mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-13 06:21:29 -10:00
Compare commits
981
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
504108603d | ||
|
|
1ae9aaab21 | ||
|
|
3a46ed66ba | ||
|
|
1812efa209 | ||
|
|
2966757e62 | ||
|
|
bc3aad374e | ||
|
|
c5d192524e | ||
|
|
7a47cc0521 | ||
|
|
a33cc0f6c4 | ||
|
|
af4ec4facc | ||
|
|
d897643217 | ||
|
|
6631975e45 | ||
|
|
fa2b135bb1 | ||
|
|
7f4d78f44a | ||
|
|
10f484a504 | ||
|
|
f0c8c9ad74 | ||
|
|
79579eda94 | ||
|
|
be8ec82649 | ||
|
|
b72b7688f9 | ||
|
|
c2e01864d5 | ||
|
|
7a4d4466fd | ||
|
|
ec75cac4d9 | ||
|
|
b6c0e8b562 | ||
|
|
8d0570846b | ||
|
|
93d0624b3e | ||
|
|
563445466e | ||
|
|
b7e9d4c9cb | ||
|
|
348fb5ffb4 | ||
|
|
d754c2cb50 | ||
|
|
b760c5dec8 | ||
|
|
9c9b06a1b1 | ||
|
|
30da49be81 | ||
|
|
c2d0eafc36 | ||
|
|
e3c7f81412 | ||
|
|
2b155c7a30 | ||
|
|
df69993a84 | ||
|
|
3fb5bf1f5f | ||
|
|
6823e24350 | ||
|
|
305a7f6630 | ||
|
|
4ba6191e0c | ||
|
|
b4f633767e | ||
|
|
6dbfba2c9f | ||
|
|
9748de5ec1 | ||
|
|
0765c7be95 | ||
|
|
73f8e57961 | ||
|
|
743d8dd666 | ||
|
|
7b410b2116 | ||
|
|
8fed4437ee | ||
|
|
ad25418f92 | ||
|
|
5972457ad5 | ||
|
|
35876bc17e | ||
|
|
46fa212db6 | ||
|
|
d0d65cd30c | ||
|
|
cb0e9ce601 | ||
|
|
13bc0362c8 | ||
|
|
5749b856df | ||
|
|
f67814aaae | ||
|
|
24daea79f3 | ||
|
|
0f013f920b | ||
|
|
d0c3c7db21 | ||
|
|
be678c2f54 | ||
|
|
16180306ad | ||
|
|
865045a231 | ||
|
|
0b54c741a6 | ||
|
|
baa34f1ffe | ||
|
|
0220ad0563 | ||
|
|
910521bdfe | ||
|
|
7003e5caa2 | ||
|
|
8efe146300 | ||
|
|
a14fb35713 | ||
|
|
2d0dc7798d | ||
|
|
8242e3b94b | ||
|
|
16cb6b3f2f | ||
|
|
8c9be400a6 | ||
|
|
7974a682ef | ||
|
|
41af098d19 | ||
|
|
4c95370f74 | ||
|
|
a6730a997c | ||
|
|
c5b84d9406 | ||
|
|
d2f5a12d5f | ||
|
|
6f6e839bbf | ||
|
|
065524fd4b | ||
|
|
c84cb7ab64 | ||
|
|
587ed4e41f | ||
|
|
d73d46feb2 | ||
|
|
a881b339cc | ||
|
|
1f90be0a86 | ||
|
|
4ce02ce291 | ||
|
|
7d83ece711 | ||
|
|
9ee1a6eb23 | ||
|
|
f258554304 | ||
|
|
994048eb24 | ||
|
|
0af3197a90 | ||
|
|
e5824b41bb | ||
|
|
679c3606c5 | ||
|
|
acbab034cc | ||
|
|
45306da4fe | ||
|
|
f09c7b3ba5 | ||
|
|
964f495238 | ||
|
|
865f7e725c | ||
|
|
6a550a6701 | ||
|
|
ad2531efcc | ||
|
|
8af06b9e78 | ||
|
|
b6eef2e8f2 | ||
|
|
2feeb34629 | ||
|
|
9d28ba568c | ||
|
|
1b6ed75d73 | ||
|
|
4cf7ab3474 | ||
|
|
bd4b9cb0d7 | ||
|
|
926e10584c | ||
|
|
defab61664 | ||
|
|
7dc971a6f2 | ||
|
|
e0a6ca9abd | ||
|
|
613fad21c9 | ||
|
|
91497d5056 | ||
|
|
e796a4fe00 | ||
|
|
03f01604d9 | ||
|
|
1547526057 | ||
|
|
7602b88756 | ||
|
|
4812ff529d | ||
|
|
fe42c7bdff | ||
|
|
f706d6c0a0 | ||
|
|
16b9225533 | ||
|
|
64d9b6fb74 | ||
|
|
b40f5a15b2 | ||
|
|
52a5c356cf | ||
|
|
b270c44ede | ||
|
|
6cf6f8a6fe | ||
|
|
c273496c1e | ||
|
|
8933aaff38 | ||
|
|
a3de0db735 | ||
|
|
0dcb60f805 | ||
|
|
1bc7732b6e | ||
|
|
2a64abfe92 | ||
|
|
d1e81be2aa | ||
|
|
e285641ac6 | ||
|
|
d3b1ad4328 | ||
|
|
914f0e13e3 | ||
|
|
df68da3dd6 | ||
|
|
0219e65b00 | ||
|
|
cc171a6344 | ||
|
|
7d066a1c45 | ||
|
|
6677fcabae | ||
|
|
171d36bf7f | ||
|
|
9018ddf0d5 | ||
|
|
d847236dd2 | ||
|
|
0ee3d099ab | ||
|
|
9aa48579b0 | ||
|
|
bb28d0b859 | ||
|
|
2ef3a935e4 | ||
|
|
233fa38890 | ||
|
|
e91d6ed17b | ||
|
|
f6c86464aa | ||
|
|
dd0af0e07c | ||
|
|
24031db712 | ||
|
|
d82b02a54a | ||
|
|
a21876127d | ||
|
|
f64de84e7c | ||
|
|
feadc0bd69 | ||
|
|
1252d794db | ||
|
|
58fcbde152 | ||
|
|
b3970798e1 | ||
|
|
da34e25bc3 | ||
|
|
7fc75c0d6c | ||
|
|
859978fd84 | ||
|
|
7781d9fcda | ||
|
|
03e876f65b | ||
|
|
9480869e0a | ||
|
|
481e82303c | ||
|
|
689ac56bc8 | ||
|
|
c5469982c8 | ||
|
|
db64a212d6 | ||
|
|
0a07b7e0ad | ||
|
|
833d181700 | ||
|
|
dfc716d91a | ||
|
|
8dd6a27418 | ||
|
|
691ae8752e | ||
|
|
14b4fd3465 | ||
|
|
fc6a1402c3 | ||
|
|
275f96d80c | ||
|
|
850d706df2 | ||
|
|
b06c8e72e1 | ||
|
|
b1fd9ffffb | ||
|
|
e2c264cec4 | ||
|
|
3f889137d7 | ||
|
|
19f1e6b4ee | ||
|
|
7e692ebca6 | ||
|
|
0067a57f8f | ||
|
|
e028162dc2 | ||
|
|
9b26439dd3 | ||
|
|
1431270287 | ||
|
|
06e74fa976 | ||
|
|
318fde51d7 | ||
|
|
d253302fc9 | ||
|
|
560eb31e4f | ||
|
|
493df37287 | ||
|
|
32298b89fd | ||
|
|
d6ee515873 | ||
|
|
bc09f0672b | ||
|
|
859534a75c | ||
|
|
5f8234d1cd | ||
|
|
03e0904398 | ||
|
|
99170a3a70 | ||
|
|
9b72fb6592 | ||
|
|
ed6adeb281 | ||
|
|
7c13df5881 | ||
|
|
c6a98ad228 | ||
|
|
927567ffed | ||
|
|
5ebf530a30 | ||
|
|
b32b54a737 | ||
|
|
447ed95878 | ||
|
|
1ddf247fd5 | ||
|
|
7f05f775af | ||
|
|
6cfc54499d | ||
|
|
4fa5c0d3e7 | ||
|
|
8c237626a5 | ||
|
|
41312265d5 | ||
|
|
ee42e767a5 | ||
|
|
f6b445ed2e | ||
|
|
126c2e27f7 | ||
|
|
f4aa5c079f | ||
|
|
4f9e1360a5 | ||
|
|
d839f9f3c9 | ||
|
|
9d10066da7 | ||
|
|
d42f3f79ac | ||
|
|
32982351dc | ||
|
|
bcb9e48586 | ||
|
|
df323423dd | ||
|
|
26abf577cc | ||
|
|
7c0827aaa2 | ||
|
|
4845f6837d | ||
|
|
15e7fb16d1 | ||
|
|
60f3aa59d6 | ||
|
|
8562dde955 | ||
|
|
85f915f352 | ||
|
|
23f6b39597 | ||
|
|
c7bc0a7263 | ||
|
|
3ae178e125 | ||
|
|
e7cb174684 | ||
|
|
aef5a022a8 | ||
|
|
fe77cbee3c | ||
|
|
ab5e016dbb | ||
|
|
91e7bea55e | ||
|
|
c72b8b0cf4 | ||
|
|
c07389ce6b | ||
|
|
f07e3322e9 | ||
|
|
8e242b4c40 | ||
|
|
9bd3b00b49 | ||
|
|
46b886df2c | ||
|
|
87ad9d99c4 | ||
|
|
1a946beed1 | ||
|
|
720d938a3a | ||
|
|
ab63301d22 | ||
|
|
f1bed594f8 | ||
|
|
8a44ff160f | ||
|
|
ee74f86c5e | ||
|
|
68d216d973 | ||
|
|
d7d9f10208 | ||
|
|
cc567edaf7 | ||
|
|
fd6b670a04 | ||
|
|
b24594acb8 | ||
|
|
af84b91619 | ||
|
|
e28e681d08 | ||
|
|
b223665c3d | ||
|
|
303e482047 | ||
|
|
8fc28b01ea | ||
|
|
278355cac0 | ||
|
|
9bd10e55c6 | ||
|
|
a10c733122 | ||
|
|
a06573b15e | ||
|
|
4ff90d3716 | ||
|
|
01b96de318 | ||
|
|
eb959cd0bf | ||
|
|
46dee9ff0c | ||
|
|
579ce220ab | ||
|
|
09ae954d8e | ||
|
|
4c43f22a7a | ||
|
|
9967ed5150 | ||
|
|
ff2ec6a2ab | ||
|
|
9b0846c897 | ||
|
|
2ed78ab1a8 | ||
|
|
5373ceb650 | ||
|
|
8e7a93698b | ||
|
|
b3532e71cc | ||
|
|
bee289cfa9 | ||
|
|
5bf35ef048 | ||
|
|
16e0e3d6c4 | ||
|
|
59a5d2642c | ||
|
|
346bbb61a2 | ||
|
|
2ba173d208 | ||
|
|
f4b6a4af61 | ||
|
|
f8220ccd60 | ||
|
|
be29fc9eaa | ||
|
|
4d25b34c1b | ||
|
|
b32e7b35f7 | ||
|
|
b837c4fa7a | ||
|
|
7443fed890 | ||
|
|
d4beb69328 | ||
|
|
d6f3fc76f9 | ||
|
|
3e0c7f0721 | ||
|
|
d0409ee7be | ||
|
|
04ad198bb1 | ||
|
|
ca66b41a9e | ||
|
|
38c04d0ab3 | ||
|
|
d784f18a52 | ||
|
|
d87cd04aad | ||
|
|
aec4977e6e | ||
|
|
c7ad3592a6 | ||
|
|
1fe528b86d | ||
|
|
34663c68bd | ||
|
|
29e77013ab | ||
|
|
3ec4480c13 | ||
|
|
562dd95da3 | ||
|
|
2b1cd53db9 | ||
|
|
be8c3ebb2f | ||
|
|
b0b05b35fd | ||
|
|
7beb28b4f6 | ||
|
|
a094eb00c8 | ||
|
|
6ccde7b01d | ||
|
|
62b70e74ca | ||
|
|
89ffbb5a34 | ||
|
|
4c7e9f6585 | ||
|
|
78b957982b | ||
|
|
8aa5a22f5d | ||
|
|
26cfc8d017 | ||
|
|
5ed0a9161c | ||
|
|
6f8c8e802a | ||
|
|
712a70444b | ||
|
|
eaf57bddf3 | ||
|
|
29f82cb5d7 | ||
|
|
7846e593a0 | ||
|
|
ff3be1a4e3 | ||
|
|
25348edff2 | ||
|
|
0bdcd3c2f4 | ||
|
|
13a990a98f | ||
|
|
18ba984f3e | ||
|
|
488db515ce | ||
|
|
3f8e3360f9 | ||
|
|
61579f746c | ||
|
|
02a40ae905 | ||
|
|
04a9de69ea | ||
|
|
1457bb0c7f | ||
|
|
275c7ffe66 | ||
|
|
e120bb90b6 | ||
|
|
10ce1ac625 | ||
|
|
baada08eca | ||
|
|
996a2002e6 | ||
|
|
5a1ac87802 | ||
|
|
9e5894512c | ||
|
|
e5301b7595 | ||
|
|
ae91e4af1b | ||
|
|
b77902309a | ||
|
|
09a1485a7b | ||
|
|
63df812d79 | ||
|
|
4dc6fd417f | ||
|
|
f15c5188c3 | ||
|
|
b8dacdd898 | ||
|
|
b97430e5a0 | ||
|
|
64c27d8186 | ||
|
|
d43cf1018d | ||
|
|
e7048f6940 | ||
|
|
ef1933ec1b | ||
|
|
2a74c93313 | ||
|
|
143c52d252 | ||
|
|
53ba2e792a | ||
|
|
06df0a8a4d | ||
|
|
28747bb1b7 | ||
|
|
f2987aa749 | ||
|
|
938eacdee9 | ||
|
|
898c0c1945 | ||
|
|
6234c97f4f | ||
|
|
8dd4a05cd1 | ||
|
|
6e561761d1 | ||
|
|
b3f237b8c1 | ||
|
|
587d5af8ca | ||
|
|
0cc28cf8fc | ||
|
|
5c9b309293 | ||
|
|
c19f05a9d9 | ||
|
|
ab4d1fb779 | ||
|
|
13e1f28c4a | ||
|
|
bce1e7c2d9 | ||
|
|
2f654c496c | ||
|
|
1feef8ff2a | ||
|
|
fa0878b6b3 | ||
|
|
21d1ffd3bd | ||
|
|
237fea6cbf | ||
|
|
95649dafa1 | ||
|
|
427873a345 | ||
|
|
4a53ff742d | ||
|
|
581c834353 | ||
|
|
58f3e8fb06 | ||
|
|
d7a2bba630 | ||
|
|
0d6791ff1d | ||
|
|
9be559622e | ||
|
|
31b23d8c50 | ||
|
|
56f010a231 | ||
|
|
f0322a12f2 | ||
|
|
f62e437dbd | ||
|
|
41e338e8ab | ||
|
|
6ce1f5276a | ||
|
|
623f887495 | ||
|
|
3f6eae0836 | ||
|
|
0bffa82422 | ||
|
|
d203d2915f | ||
|
|
64af9e520c | ||
|
|
77c7aee8f4 | ||
|
|
eafab41823 | ||
|
|
bbb7599512 | ||
|
|
522e1aa360 | ||
|
|
57f9455f6c | ||
|
|
a8035fec36 | ||
|
|
9b337b714b | ||
|
|
f5a08bb694 | ||
|
|
da7d9f28b9 | ||
|
|
4bbc9f3eb3 | ||
|
|
7c4b9272d5 | ||
|
|
051d85d05c | ||
|
|
b487969e5f | ||
|
|
86a81bfb9c | ||
|
|
d7c22b126c | ||
|
|
108def6224 | ||
|
|
ff296f8f98 | ||
|
|
4106414858 | ||
|
|
9c5b4dfb49 | ||
|
|
1083f34ffc | ||
|
|
3c30257816 | ||
|
|
023a7d3e68 | ||
|
|
f32b575f0c | ||
|
|
1525f829b7 | ||
|
|
a932dc94c0 | ||
|
|
55a92a32de | ||
|
|
0c8a6c6f97 | ||
|
|
5e3f8e4792 | ||
|
|
7018a560b9 | ||
|
|
bcc964d0fa | ||
|
|
8fbe2c244a | ||
|
|
c6a2dcdfa9 | ||
|
|
d28db605a9 | ||
|
|
67428f506c | ||
|
|
0ff15cfe16 | ||
|
|
4ee4f51ee2 | ||
|
|
4da52ca23b | ||
|
|
1d52bc5876 | ||
|
|
689dca1f3f | ||
|
|
bb53f7ee68 | ||
|
|
78d9562661 | ||
|
|
b7d1270439 | ||
|
|
257ba70d70 | ||
|
|
10e5875289 | ||
|
|
64de96f6ce | ||
|
|
ac9636733f | ||
|
|
a2df152323 | ||
|
|
fbca88d36d | ||
|
|
e01a5359ac | ||
|
|
e2b205ffaa | ||
|
|
1388866ddd | ||
|
|
7e9e8bcb62 | ||
|
|
deded57112 | ||
|
|
599a1893c3 | ||
|
|
dbff592f94 | ||
|
|
9c00070154 | ||
|
|
203b738f79 | ||
|
|
b016163bf3 | ||
|
|
884d47611f | ||
|
|
a786e2d541 | ||
|
|
dc2370393e | ||
|
|
0dd4daf2eb | ||
|
|
949141c611 | ||
|
|
14689265ce | ||
|
|
837ac8d08e | ||
|
|
6cac2af8e4 | ||
|
|
80004f2996 | ||
|
|
e3cd5c819f | ||
|
|
39273db918 | ||
|
|
cd36ce336f | ||
|
|
dcdade36a3 | ||
|
|
cbbd197cd3 | ||
|
|
5d4cd31a79 | ||
|
|
835285248e | ||
|
|
682cffa610 | ||
|
|
4753d0f761 | ||
|
|
85bcfd56e8 | ||
|
|
af88697348 | ||
|
|
633f138afe | ||
|
|
d7ebb8f062 | ||
|
|
272d6261c4 | ||
|
|
2a492e00c2 | ||
|
|
c816a65c63 | ||
|
|
8d762d3fbe | ||
|
|
fec9603a09 | ||
|
|
78cb768546 | ||
|
|
de057e421e | ||
|
|
9308318199 | ||
|
|
17b34508e9 | ||
|
|
bcf0ab1957 | ||
|
|
18a679052b | ||
|
|
d516ab3c23 | ||
|
|
dceea0d7a5 | ||
|
|
1fdf8b1756 | ||
|
|
d76c733d66 | ||
|
|
c92d383b69 | ||
|
|
7c6e27e83d | ||
|
|
f2eca9ca3f | ||
|
|
31e891df0d | ||
|
|
98f1777040 | ||
|
|
af41dbae37 | ||
|
|
242c7184b8 | ||
|
|
2f28dc2f1e | ||
|
|
88166d58bc | ||
|
|
51c55550f0 | ||
|
|
9caa9c4c7c | ||
|
|
fbf0db09a7 | ||
|
|
6afb160ebd | ||
|
|
6752a7f196 | ||
|
|
2cb9b94f61 | ||
|
|
6f7c949e16 | ||
|
|
5b411f4041 | ||
|
|
91acdfbc23 | ||
|
|
29ea809790 | ||
|
|
7540c79993 | ||
|
|
eed50619ca | ||
|
|
685f641696 | ||
|
|
32cfb59a9e | ||
|
|
75a14625cf | ||
|
|
56869f10a5 | ||
|
|
482d4a19a8 | ||
|
|
2baf97b07a | ||
|
|
27d9e412cb | ||
|
|
6e51c7cc05 | ||
|
|
638745cb16 | ||
|
|
900abcf680 | ||
|
|
b74937d74f | ||
|
|
2c42f425dc | ||
|
|
fd82ff70f1 | ||
|
|
1b5b902bdd | ||
|
|
730eddc73a | ||
|
|
39b24a5789 | ||
|
|
43bd4d95fa | ||
|
|
7a5c145436 | ||
|
|
95f5839b5f | ||
|
|
8d1171ae88 | ||
|
|
11987590af | ||
|
|
629857adfb | ||
|
|
29c644c10c | ||
|
|
2bb705eca0 | ||
|
|
b1033732f1 | ||
|
|
39d5fc36f7 | ||
|
|
ede86efa99 | ||
|
|
8b63f9528d | ||
|
|
08471e8749 | ||
|
|
465190b154 | ||
|
|
3c498e65ec | ||
|
|
aa91e93aa6 | ||
|
|
3e24e21e4d | ||
|
|
6d142428c3 | ||
|
|
92f140c080 | ||
|
|
03555ebce4 | ||
|
|
0d3922d483 | ||
|
|
0f88965aed | ||
|
|
a65813b292 | ||
|
|
8236a87d25 | ||
|
|
e105b57a26 | ||
|
|
482034a383 | ||
|
|
5e255dd8d1 | ||
|
|
55a89dc13d | ||
|
|
7205808e76 | ||
|
|
0b2c356fe8 | ||
|
|
199fca289c | ||
|
|
c1260fc533 | ||
|
|
f9c9474b0c | ||
|
|
625a77bdb1 | ||
|
|
1d9fa9719c | ||
|
|
bc2218a87b | ||
|
|
b2e56dc408 | ||
|
|
8cd8e9b0ff | ||
|
|
2392a6cc7d | ||
|
|
c8fd2af450 | ||
|
|
46d1386690 | ||
|
|
7b288deb62 | ||
|
|
5be591a345 | ||
|
|
5cc0404efc | ||
|
|
ece792d35b | ||
|
|
7893f0e3c5 | ||
|
|
c2a61c7d86 | ||
|
|
a918212fe6 | ||
|
|
e561b9e915 | ||
|
|
9d41b1bb1e | ||
|
|
b3502ba413 | ||
|
|
3917890981 | ||
|
|
a150dc8255 | ||
|
|
aa4c3840f4 | ||
|
|
65f96cbf42 | ||
|
|
e664849346 | ||
|
|
c7a5f87b1b | ||
|
|
b265124459 | ||
|
|
89f10a5495 | ||
|
|
2f4bea8b21 | ||
|
|
473f907a40 | ||
|
|
8af5d4cf93 | ||
|
|
58fd88a113 | ||
|
|
b50456c244 | ||
|
|
97fde4d149 | ||
|
|
5b06f84771 | ||
|
|
e194e84c27 | ||
|
|
e103eaeb45 | ||
|
|
8153e32351 | ||
|
|
fd66eb7550 | ||
|
|
02805be745 | ||
|
|
f8f61e8b62 | ||
|
|
cfba7ec067 | ||
|
|
5e285e42bc | ||
|
|
975b31dc91 | ||
|
|
7a24e0e4c6 | ||
|
|
259828316d | ||
|
|
3a3d2c4438 | ||
|
|
4af5bf405f | ||
|
|
7827cb4835 | ||
|
|
db8292be03 | ||
|
|
1b1a8983ee | ||
|
|
5e9dd9aef5 | ||
|
|
c342a22507 | ||
|
|
15b1ed8822 | ||
|
|
a0e94eca92 | ||
|
|
6720115b95 | ||
|
|
c3d6d72941 | ||
|
|
0428fa221f | ||
|
|
7f83dd8ddb | ||
|
|
dd1641fd15 | ||
|
|
53b1dc690a | ||
|
|
5392a0d9fe | ||
|
|
2f0e2f591f | ||
|
|
cc1e26dd25 | ||
|
|
14b37add71 | ||
|
|
e1f071036f | ||
|
|
6b0f49cf3b | ||
|
|
9d57ca14de | ||
|
|
2298c3fb31 | ||
|
|
8f697dd03a | ||
|
|
6eeeb788dc | ||
|
|
a60512cfa4 | ||
|
|
2fd24ecf29 | ||
|
|
9cdbf4b5ed | ||
|
|
d2e57becd3 | ||
|
|
305fa3c6eb | ||
|
|
7a2caea6ea | ||
|
|
0fc8fcfad3 | ||
|
|
dbe731782a | ||
|
|
6bc6b0f1e2 | ||
|
|
6eee49a868 | ||
|
|
b6f0e8e4e8 | ||
|
|
1a5c39154d | ||
|
|
b373ad2df4 | ||
|
|
39c5336847 | ||
|
|
9cfc6f4b07 | ||
|
|
9190d90536 | ||
|
|
50fee8eb8a | ||
|
|
7f44bd1969 | ||
|
|
03e3bdb40a | ||
|
|
c127b2b982 | ||
|
|
15d078aad2 | ||
|
|
92fc993597 | ||
|
|
88dd1f843b | ||
|
|
084085a53f | ||
|
|
eb81b50c55 | ||
|
|
6e91356f47 | ||
|
|
9dbf5df152 | ||
|
|
c2c02470d1 | ||
|
|
e78fbfb9be | ||
|
|
756f0a9732 | ||
|
|
68ad0c826b | ||
|
|
f02ff33311 | ||
|
|
98268b139c | ||
|
|
5b175673ed | ||
|
|
1dc4a210b7 | ||
|
|
eaed502d62 | ||
|
|
267921b443 | ||
|
|
439f59e1f2 | ||
|
|
ce8724a653 | ||
|
|
ed78597635 | ||
|
|
af41185acb | ||
|
|
61247bf3e2 | ||
|
|
c83b4b5838 | ||
|
|
f6ffe4e399 | ||
|
|
18b48214a2 | ||
|
|
ddc5c7ac8b | ||
|
|
9d0629f657 | ||
|
|
7d0743d5ed | ||
|
|
9e24469928 | ||
|
|
4483d5051b | ||
|
|
4e9309a154 | ||
|
|
439c22b528 | ||
|
|
e3be23ac7f | ||
|
|
39c71d3a7b | ||
|
|
b2fe7a94ae | ||
|
|
b7353b2027 | ||
|
|
bef3f33f6a | ||
|
|
d0f051847c | ||
|
|
153d3effaa | ||
|
|
96f0c66722 | ||
|
|
bdea153270 | ||
|
|
13e28a3102 | ||
|
|
b089dabadc | ||
|
|
a20dd3bea9 | ||
|
|
5dc8b04dab | ||
|
|
00995f5516 | ||
|
|
8846e043fb | ||
|
|
89c6d330f8 | ||
|
|
42db9f2e7b | ||
|
|
35f4dab373 | ||
|
|
2ed504eb82 | ||
|
|
5074a939ed | ||
|
|
ec4222b412 | ||
|
|
901dfe310b | ||
|
|
5f6f4c11b2 | ||
|
|
2de1441bf1 | ||
|
|
e1de3b6ac4 | ||
|
|
6960fe58c8 | ||
|
|
4b6a791b02 | ||
|
|
801b693e63 | ||
|
|
0ab3a85289 | ||
|
|
faf8fb2ecc | ||
|
|
0fbc422ca0 | ||
|
|
c835481e6d | ||
|
|
4deaecece9 | ||
|
|
1387c46b67 | ||
|
|
acd4486fc1 | ||
|
|
b7343690de | ||
|
|
7d39df9871 | ||
|
|
4ab8d35b8b | ||
|
|
3e7e3bfb4d | ||
|
|
42a16b4c7d | ||
|
|
7ea7953cd7 | ||
|
|
0bb898ae2e | ||
|
|
c6831d8b30 | ||
|
|
68aec1edef | ||
|
|
072fee459b | ||
|
|
d85d854646 | ||
|
|
23c5355bc7 | ||
|
|
eba379330e | ||
|
|
f75f08f7ba | ||
|
|
0357df1e7d | ||
|
|
7a5c6df202 | ||
|
|
628ac80f2c | ||
|
|
ea58a760ff | ||
|
|
5e79d94bad | ||
|
|
2f4059b7fd | ||
|
|
b030148c21 | ||
|
|
754c351498 | ||
|
|
f45a6fb58c | ||
|
|
6e25fbb50f | ||
|
|
db5a37c178 | ||
|
|
b68e424213 | ||
|
|
af428ca6b9 | ||
|
|
731b5d53c5 | ||
|
|
3042846e62 | ||
|
|
8d27682126 | ||
|
|
9f20cb1921 | ||
|
|
8b75bbbb0d | ||
|
|
9220b48592 | ||
|
|
f7f2b5f025 | ||
|
|
2531a31b1e | ||
|
|
8d406c2167 | ||
|
|
0813a7f416 | ||
|
|
9a1badf444 | ||
|
|
5df51711fe | ||
|
|
7ec27f147f | ||
|
|
e972cdc2cf | ||
|
|
f220075bbe | ||
|
|
730c84308e | ||
|
|
badde3ad96 | ||
|
|
1371dc3a08 | ||
|
|
0c5342b875 | ||
|
|
4c3024e5fc | ||
|
|
bbb7539fb6 | ||
|
|
a9a110e8fa | ||
|
|
a71dbbab6a | ||
|
|
3e8be9c8a3 | ||
|
|
b2270e4714 | ||
|
|
5410b3ef46 | ||
|
|
5344b45c47 | ||
|
|
2bdf6c21f2 | ||
|
|
5b2bd80609 | ||
|
|
8063fc3863 | ||
|
|
9ac262579d | ||
|
|
4924f56613 | ||
|
|
dbc2cb1c27 | ||
|
|
076ad7770b | ||
|
|
3c942fc409 | ||
|
|
5f48e55990 | ||
|
|
aaee1e5a32 | ||
|
|
ce274209c1 | ||
|
|
7be49e67d1 | ||
|
|
8731ad1448 | ||
|
|
a5f634885b | ||
|
|
fe4d93393b | ||
|
|
9de6beb4c2 | ||
|
|
4485efe484 | ||
|
|
12a0a8642e | ||
|
|
e246616fac | ||
|
|
d3701166af | ||
|
|
e1db2ca59a | ||
|
|
063a567fe4 | ||
|
|
c32c655350 | ||
|
|
91d274cd6d | ||
|
|
08742f36e8 | ||
|
|
24571d099e | ||
|
|
f29c48965e | ||
|
|
fbb209ef6b | ||
|
|
7cc9f72cac | ||
|
|
6f7f9c2f48 | ||
|
|
d398ce25fb | ||
|
|
3c59687d75 | ||
|
|
ef3af0e254 | ||
|
|
40807000ad | ||
|
|
de5a422fc0 | ||
|
|
4b86f32b21 | ||
|
|
09b6552908 | ||
|
|
de3e158b73 | ||
|
|
a0c0766146 | ||
|
|
05790db5e7 | ||
|
|
d28833e92a | ||
|
|
60e5ba9541 | ||
|
|
705d4a519f | ||
|
|
950fbf1a13 | ||
|
|
dd0b099d9b | ||
|
|
ca6f25f5af | ||
|
|
09215672a1 | ||
|
|
1076493ceb | ||
|
|
28a1e2a3d4 | ||
|
|
280d8c8c8a | ||
|
|
58e7d50b1c | ||
|
|
1c4db98bc5 | ||
|
|
214c6e3d5c | ||
|
|
eaa063ba65 | ||
|
|
002ab4885e | ||
|
|
58175aa386 | ||
|
|
0e70c4918a | ||
|
|
0d75790a6a | ||
|
|
85e11ecd6d | ||
|
|
3651239a6b | ||
|
|
041a390660 | ||
|
|
6bc1bff0ab | ||
|
|
de1215f64e | ||
|
|
d101227721 | ||
|
|
13b7f626a9 | ||
|
|
0e375e2e0d | ||
|
|
a360245857 | ||
|
|
d0e26adc20 | ||
|
|
289266d959 | ||
|
|
4f36c6a781 | ||
|
|
4a8991703f | ||
|
|
34232bd5d8 | ||
|
|
7eca7febcb | ||
|
|
0ad91aaf3d | ||
|
|
e83609b121 | ||
|
|
1d93e9bff6 | ||
|
|
a568f514a3 | ||
|
|
ed8a511fe9 | ||
|
|
3c723c9ea9 | ||
|
|
e9be428cd1 | ||
|
|
8360bae5af | ||
|
|
6162c475a0 | ||
|
|
9419f24184 | ||
|
|
236b648b11 | ||
|
|
414c630d04 | ||
|
|
d7bbecfa16 | ||
|
|
d2e1e2b5de | ||
|
|
11f2635abd | ||
|
|
df8268368a | ||
|
|
6b097be0a6 | ||
|
|
9980c3f5c5 | ||
|
|
bd1a288cd9 | ||
|
|
eca7db0315 | ||
|
|
be4d7acb6a | ||
|
|
02e5cc4353 | ||
|
|
481c0a490b | ||
|
|
2a5b930941 | ||
|
|
2881482182 | ||
|
|
661732a45b | ||
|
|
856997326b | ||
|
|
d52c2da8b5 | ||
|
|
c6a1639a82 | ||
|
|
a0181e715d | ||
|
|
dbbd6b7705 | ||
|
|
ae135b4922 | ||
|
|
9c167b279d | ||
|
|
1884e4c4d1 | ||
|
|
8cf7796809 | ||
|
|
3b3a45d2d8 | ||
|
|
9f1c00c581 | ||
|
|
87a051a933 | ||
|
|
7022ba191a | ||
|
|
8d672bddb3 | ||
|
|
dc281a56f8 | ||
|
|
7b0a8eff9e | ||
|
|
d722f50f8b | ||
|
|
ddeb40aa61 | ||
|
|
db68e30862 | ||
|
|
a1fc0907cf | ||
|
|
2c5f52a28d | ||
|
|
3d5ae71fc6 | ||
|
|
5d0fadba19 | ||
|
|
2eb6410de8 | ||
|
|
401a26623a | ||
|
|
9336d7264f | ||
|
|
ec3ad17fa2 | ||
|
|
d9a9cb5f9d | ||
|
|
0a7ff1bc1a | ||
|
|
e5f80a160a | ||
|
|
e3a153ef5b | ||
|
|
ccf86293ce | ||
|
|
f142780b95 | ||
|
|
48f99e36b0 | ||
|
|
8bf51ff858 | ||
|
|
84cb7fddba | ||
|
|
566d15dfec | ||
|
|
0d82ca5be2 | ||
|
|
4857f320ad | ||
|
|
636f6933be | ||
|
|
a8483c5a8a | ||
|
|
5eb4c35572 | ||
|
|
15752d1729 | ||
|
|
413842c84a | ||
|
|
e41bde6dad | ||
|
|
e37ca8fd8e | ||
|
|
e2099271c6 | ||
|
|
19817f4cda | ||
|
|
c41e5c9d7f | ||
|
|
b08109c2fe | ||
|
|
30b484b276 | ||
|
|
2989034394 | ||
|
|
eec2ce1713 | ||
|
|
439f633364 | ||
|
|
458d2f5e12 | ||
|
|
2f361340fc | ||
|
|
41d65630f8 | ||
|
|
5e57094f8e | ||
|
|
ae9b604f44 | ||
|
|
8db39a6c61 | ||
|
|
ec84c7183e | ||
|
|
16a5b1ccc7 | ||
|
|
856726d000 | ||
|
|
dd2c5a22a4 | ||
|
|
b97129da86 | ||
|
|
a7badba0d8 | ||
|
|
93a1f3e6b4 | ||
|
|
b19399021d | ||
|
|
c95fe1c9d1 | ||
|
|
f405496791 | ||
|
|
33b63e5b6c | ||
|
|
b64bd789b6 | ||
|
|
9011319e2f | ||
|
|
3fd825b1de | ||
|
|
b21d380240 | ||
|
|
c2e8ba9fa6 | ||
|
|
61fb9c5dd1 | ||
|
|
f7ecb85df6 | ||
|
|
144ae46ccc | ||
|
|
1a81682472 | ||
|
|
3349c99a0a | ||
|
|
6e2723a313 | ||
|
|
9241c49f32 | ||
|
|
80fc7a5cbf | ||
|
|
ca982fa1ae | ||
|
|
20fc9d629c | ||
|
|
881f47670c | ||
|
|
54a64cb91e | ||
|
|
232eb2a099 | ||
|
|
fc65df048f | ||
|
|
f2cfac14b3 | ||
|
|
5cbe64c793 | ||
|
|
e2b9a5a1a2 | ||
|
|
da83c3aa41 | ||
|
|
30237c8988 | ||
|
|
ca23d30c99 | ||
|
|
53e30ba771 | ||
|
|
c4f84ea9f5 | ||
|
|
7acd4c6491 | ||
|
|
04c136f59e | ||
|
|
3768473270 | ||
|
|
52427a7ec3 |
No files matched your search
@@ -1,14 +1,6 @@
|
||||
|
||||
cmake/ @asarium
|
||||
|
||||
ci/ @asarium @z64555
|
||||
|
||||
code/executor/ @asarium
|
||||
|
||||
code/scpui/ @asarium
|
||||
|
||||
code/scripting/ @asarium
|
||||
|
||||
code/controlconfig/ @z64555
|
||||
|
||||
code/model/modelanimation*.* @bmagnu
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
@@ -31,11 +31,16 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -133,7 +138,12 @@ jobs:
|
||||
# arch: win64_msvc2017_64
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -144,11 +154,19 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
env:
|
||||
@@ -235,12 +253,17 @@ jobs:
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Set up test version
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -264,13 +287,15 @@ jobs:
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Package build result
|
||||
working-directory: ./build
|
||||
run: cd bin && tar -cvzf macos-build.tar *.app
|
||||
working-directory: ./build/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build.tar
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
@@ -293,6 +318,11 @@ jobs:
|
||||
with:
|
||||
name: mac-FastDebug
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release.tgz
|
||||
tar -xvzf macos-build-FastDebug.tgz
|
||||
- name: Create Distribution package
|
||||
working-directory: ./builds
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
name: Linux
|
||||
needs: create_release # Don't run this job until create_release is done and successful
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
@@ -87,12 +87,17 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
# checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -213,7 +218,12 @@ jobs:
|
||||
# arch: win64_msvc2017_64
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -224,11 +234,19 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
env:
|
||||
@@ -334,12 +352,17 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -357,13 +380,15 @@ jobs:
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Package build result
|
||||
working-directory: ./build
|
||||
run: cd bin && tar -cvzf macos-build.tar *.app
|
||||
working-directory: ./build/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build.tar
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
@@ -386,6 +411,11 @@ jobs:
|
||||
with:
|
||||
name: mac-FastDebug
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release.tgz
|
||||
tar -xvzf macos-build-FastDebug.tgz
|
||||
- name: Create Distribution package
|
||||
id: generate_package
|
||||
working-directory: ./builds
|
||||
|
||||
@@ -24,6 +24,12 @@ jobs:
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
@@ -31,7 +31,6 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -42,6 +41,12 @@ jobs:
|
||||
[[ "${{ github.ref }}" =~ ^refs\/heads\/test\/(.*)$ ]]
|
||||
# Override the revision string so that the builds are named correctly
|
||||
echo "set(FSO_VERSION_REVISION_STR ${BASH_REMATCH[1]})" > "version_override.cmake"
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -146,7 +151,12 @@ jobs:
|
||||
# arch: win64_msvc2017_64
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -157,11 +167,19 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
env:
|
||||
@@ -249,12 +267,17 @@ jobs:
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Set up test version
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -277,13 +300,15 @@ jobs:
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Package build result
|
||||
working-directory: ./build
|
||||
run: cd bin && tar -cvzf macos-build.tar *.app
|
||||
working-directory: ./build/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build.tar
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
@@ -306,6 +331,11 @@ jobs:
|
||||
with:
|
||||
name: mac-FastDebug
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release.tgz
|
||||
tar -xvzf macos-build-FastDebug.tgz
|
||||
- name: Create Distribution package
|
||||
working-directory: ./builds
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
@@ -38,7 +38,6 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -48,7 +47,12 @@ jobs:
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
|
||||
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -113,7 +117,12 @@ jobs:
|
||||
# arch: win64_msvc2017_64
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -125,12 +134,23 @@ jobs:
|
||||
cd build
|
||||
|
||||
if [ "$COMPILER" = "MinGW" ]; then
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFSO_BUILD_FRED2="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFSO_BUILD_FRED2="OFF" -DFSO_BUILD_WITH_VULKAN="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFSO_BUILD_FRED2="OFF" -DCMAKE_BUILD_TYPE=$CONFIGURATION -G "Ninja" ..
|
||||
fi
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
if [ "$ARCHITECTURE" = "Win32" ]; then
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -DFSO_BUILD_WITH_VULKAN="OFF" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
fi
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -182,7 +202,6 @@ jobs:
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -192,7 +211,12 @@ jobs:
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
|
||||
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
@@ -217,4 +241,4 @@ jobs:
|
||||
if: startsWith(matrix.compiler, 'clang-')
|
||||
uses: asarium/clang-tidy-action@v1
|
||||
with:
|
||||
fixesFile: clang-fixes.yaml
|
||||
fixesFile: clang-fixes.yaml
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
language: bash
|
||||
sudo: required
|
||||
dist: xenial
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/cmake-3.8
|
||||
- $HOME/.ccache
|
||||
- $HOME/curl_cache
|
||||
addons:
|
||||
apt:
|
||||
packages: &global_deps
|
||||
- ninja-build
|
||||
- libopenal-dev
|
||||
- libreadline6-dev
|
||||
- libpng12-dev
|
||||
- libjpeg62-dev
|
||||
- liblua5.1-0-dev
|
||||
- libjansson-dev
|
||||
- libsdl2-dev
|
||||
- libfreetype6-dev
|
||||
- qt57base
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "scp-fs2open/fs2open.github.com"
|
||||
notification_email: [email protected]
|
||||
build_command: "ci/travis/script.sh"
|
||||
# must match TRAVIS_BRANCH check below
|
||||
branch_pattern: coverity_scan
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
# also note that fork's don't get access to secure keys
|
||||
# you have to test using a branch in the main repo
|
||||
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
|
||||
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
|
||||
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
|
||||
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
|
||||
# These declarations set DATACORDER_USER and DATACORDER_PASSWORD
|
||||
- secure: "dpBH/dDN3bmU/NFlh+2v9isNx9wX0ocoRy+W+kBXRH32sosUGp26REhMqgVRpBNP5oxPBU8ic5bEogxAYWCB+0xUygBbkxAwyMPgoA34s0OXdTCY/ofw14ni8qqV2Ffy7fQJbP/jkMURyiMHx3kBTxNv3YjxKJqLnOuOMlQLpT8="
|
||||
- secure: "tLMRBD1Ufp5iKNwlqPDVbbuczgusaXNoBJyAnPATpJq2YwlkW4j3PqP9rW5vd85+52xam2EOP20w9PoBR5J6FLdiXRu4Lf7yCEhSHFAgowVqQj8QcJpPlyXr90bM4emFGrGqpdxVwxyQ5AFhKwLuEZKsI14GYLN+UMEwpNCMing="
|
||||
deploy:
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: "q619+eQTe7lv8UVphK4OIzU8Jw84KBbVkuprN2sWIubRcV3IbZr2+WahJoUMt+nyhiy3YjDYtstO2ZgkxupwnZgwGUBVIiD1c4SPuyy+HTjNMOtiVsEUHT2hf+xPAemWpTlK5HcwhMmHAOh6rt6dEj57QOg0gcmGiwD/tCbEriA="
|
||||
skip_cleanup: true
|
||||
file_glob: true
|
||||
file: "/tmp/builds/*"
|
||||
on:
|
||||
condition: '"$RELEASE_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: script
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: '"$NIGHTLY_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: $TEST_BUILD = true
|
||||
all_branches: true
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# note that gcc Debug MUST be 1st for Coverity
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-9 CXX=g++-9
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- g++-9
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-9
|
||||
script:
|
||||
- ./ci/travis/script.sh
|
||||
- ./ci/travis/clang_tidy.sh
|
||||
- os: osx
|
||||
env: CONFIGURATION="Debug"
|
||||
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-9 CXX=g++-9
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- g++-9
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-9
|
||||
script:
|
||||
- ./ci/travis/script.sh
|
||||
- ./ci/travis/clang_tidy.sh
|
||||
- os: osx
|
||||
env: CONFIGURATION="Release"
|
||||
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
# There is a GCC compiler bug with MinGW that causes compilation failures on Windows at the moment
|
||||
allow_failures:
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
fast_finish: true
|
||||
|
||||
before_install:
|
||||
# ugly hack; if running a coverity scan abort all except the 1st build
|
||||
# see note re gcc compiler above needing to be 1st
|
||||
# also note that branch_pattern & the TRAVIS_BRANCH check must match
|
||||
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
|
||||
# build process
|
||||
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
|
||||
- source "./ci/travis/check_release.sh"
|
||||
- "./ci/travis/before_install.sh"
|
||||
install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then export PATH="/c/Program Files/CMake/bin":$PATH; fi
|
||||
- "./ci/travis/install.sh"
|
||||
- export PATH=$HOME/cmake-3.6/bin:$PATH
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
|
||||
- "./ci/travis/before_script.sh"
|
||||
script:
|
||||
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
|
||||
+3
-1
@@ -137,8 +137,9 @@ option(FSO_RELEASE_LOGGING "Enable logging output for release builds" OFF)
|
||||
OPTION(FSO_BUILD_WITH_FFMPEG "Enable the usage of FFmpeg for sound and custscenes" ON)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_OPENGL "Enable compilation of the OpenGL renderer" ON)
|
||||
OPTION(FSO_BUILD_WITH_OPENGL_DEBUG "Enables debug option for OpenGL" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" ON)
|
||||
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" OFF)
|
||||
|
||||
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
|
||||
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
|
||||
@@ -151,6 +152,7 @@ mark_as_advanced(FORCE ENABLE_COTIRE)
|
||||
mark_as_advanced(FORCE FSO_RELEASE_LOGGING)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_FFMPEG)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENGL_DEBUG)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_VULKAN)
|
||||
|
||||
# Include cotire file from https://github.com/sakra/cotire/
|
||||
|
||||
+179
@@ -3,6 +3,185 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [23.2.0] - 2023-06-16
|
||||
### Changes
|
||||
|
||||
<details><summary> <b>Big Feature: MSAA</b> </summary>
|
||||
|
||||
> The return of a long forgotten feature, with optimizations and improvements
|
||||
> Noticeable reduction to artifacts caused by subpixel geometry and glinting.
|
||||
</details>
|
||||
|
||||
<details><summary> <b>Big Feature: SCPUI</b> </summary>
|
||||
|
||||
> A modernized approach to defining menus in FS
|
||||
> Tired of having your Menus in FSO be at a resolution of potato? Use SCPUI to have them rendered from Fake-HTML to the actual screensize as opposed to a prebuilt graphics!
|
||||
> Tired of being limited to whatever people in the SCP hardcoded in for buttons? Use SCPUI to define buttons and all other manner of shenanigans as Lua-code just as you like.
|
||||
> Tired of needing to replace a bajillion interface graphics to reskin FSO? Use SCPUI, and especially Mjn's existing collection of Lua, CSS, Fake-HTML and images, and you only need to replace about 250 graphics.
|
||||
</details>
|
||||
|
||||
<details><summary> <b>Big Feature: Localized Volumetric Nebulae</b> </summary>
|
||||
|
||||
> Allows specifying a POF as the "hull" of a nebula, which will be rendered using ray marching
|
||||
> Further details can be found on the [GitHub Pull Request](https://github.com/scp-fs2open/fs2open.github.com/pull/5231)
|
||||
> Note: As this is a new feature, many improvements and optimizations remain to be made
|
||||
> Adapted from Andrew Schneider's 2015 SIGGRAPH talk "The real-time volumetric cloudscapes of Horizon: Zero Dawn"
|
||||
</details>
|
||||
|
||||
<details><summary>Game: </summary>
|
||||
|
||||
- Per bank autoaim
|
||||
</details>
|
||||
|
||||
<details><summary>Animation: </summary>
|
||||
|
||||
- Fix CTD on bad legacy animation data
|
||||
- Add proper time wrapping for Animations
|
||||
- Actually handle a mssing `Fade_anim` properly
|
||||
</details>
|
||||
|
||||
<details><summary>Controls: </summary>
|
||||
|
||||
- Organize and map additional keys to librocket
|
||||
- Catch when SDL fails to open a joystick that is enumerated by the OS
|
||||
</details>
|
||||
|
||||
<details><summary>FRED: </summary>
|
||||
|
||||
- Add SpaceMouse support
|
||||
- Add pre-parse enums support
|
||||
- Add music player to FRED
|
||||
- Enhanced SEXP comments
|
||||
- FRED Dialog for Volumetrics
|
||||
- QoL improvements to Object Editor
|
||||
- Add FRED support for the "required weapon" feature
|
||||
- SEXP Tree search and filter
|
||||
</details>
|
||||
|
||||
<details><summary>QtFRED: </summary>
|
||||
|
||||
- Campaign Editor
|
||||
- Add SpaceMouse support
|
||||
- Make 'player starts in chase view' a toggle
|
||||
</details>
|
||||
|
||||
<details><summary>Graphics: </summary>
|
||||
|
||||
- "The other great shader flag removal effort"
|
||||
- Enhance handling of motion debris
|
||||
- Expose texture filtering as a built-in option
|
||||
- Improved particle culling and performance
|
||||
- Optimized trail renderer
|
||||
- Beam Particles
|
||||
- Multiple lighting profiles
|
||||
- Use volume particles for poofs
|
||||
- Optimize for simple trails
|
||||
- Kink shamed the laser bitmaps
|
||||
</details>
|
||||
|
||||
<details><summary>HUD: </summary>
|
||||
|
||||
- Flag to apply HUD shudder to chase view
|
||||
- Add missing HUD gauges
|
||||
- Explicitly do not split lines when making the message log
|
||||
</details>
|
||||
|
||||
<details><summary>Localization: </summary>
|
||||
|
||||
- Add some XSTR entries
|
||||
</details>
|
||||
|
||||
<details><summary>Modding: </summary>
|
||||
|
||||
- Mapify built-in strings
|
||||
- Allow `gameplay_profiles.tbl` to be an alias of `ai_profiles.tbl`
|
||||
- Modular rank table
|
||||
- Toggle auto-assigning personas
|
||||
- Add some parameters for corkscrew starting angle
|
||||
- Add clip planes to `game_settings.tbl`
|
||||
- Add `+Use ship` as a Template
|
||||
- Modular messages table
|
||||
- Add arbitrary curves support
|
||||
- Traitor overrides
|
||||
- Add support for loose lz4 compressed files
|
||||
- Add per-species warp effects
|
||||
</details>
|
||||
|
||||
<details><summary>Models: </summary>
|
||||
|
||||
- Fix submodel sanity check
|
||||
- Fix techroom modelnum references
|
||||
- Adjust movement sanity checks to account for more situations
|
||||
- Modular POF Features 2
|
||||
- Add fov values to .pof models
|
||||
- Add a Translation Moveable
|
||||
- Remove model octants
|
||||
- Fix glowpoints on animated submodels
|
||||
- Update type_flags when dock name changes
|
||||
- Add additional checks for Animation List handling of nonexistent polymodel instances
|
||||
- Virtual POFs: Modify Subsystems
|
||||
- Validate chunk size to avoid alignment crash and add align skip flag
|
||||
</details>
|
||||
|
||||
<details><summary>Multiplayer: </summary>
|
||||
|
||||
- Generic Lua Multiplayer RPC
|
||||
</details>
|
||||
|
||||
<details><summary>Performance: </summary>
|
||||
|
||||
- Increase sound update rate
|
||||
- Add `line of sight` as an optional AI override
|
||||
</details>
|
||||
|
||||
<details><summary>SEXPs: </summary>
|
||||
|
||||
- `turret-fired-since`, returns `true` if the specified turret has fired in the last `N` milliseconds
|
||||
- `is-ship-emp-active`, returns `true` if the specified ship or list of ships is currently under an EMP effect
|
||||
- `turret-has-primary` and `turret-has-secondary`, returns `true` if the specified turret contains the specified weapon
|
||||
- `has-armor-type`, returns `true` if the specified ship or subsystem has the specified armor type
|
||||
- `OPF_ANY_HUD_GAUGE` and `OPF_EVENT_NAME`, new Lua SEXP parameters
|
||||
- Enhance Dynamic SEXPs with parent parameters
|
||||
- Add "afterburn hard" AI goal flag
|
||||
</details>
|
||||
|
||||
<details><summary>Scripting: </summary>
|
||||
|
||||
- Add option to deprecate hooks
|
||||
- Get audiostream duration in float seconds
|
||||
- Lua method to check if the game has focus
|
||||
- `On warp complete` hook
|
||||
- Allow Lua to set the Discord presence to custom strings
|
||||
- Add virtvars for goal satisfaction and score
|
||||
- Allow scripts to read and add LuaEnums
|
||||
- Funcs and virtvars for SCPUI pause screen
|
||||
- Expose pausing weapon sounds
|
||||
- Make collision_group_id accessible to parse objects
|
||||
- Pass shortcut key character to Lua as a hook variable
|
||||
- Lua method to free all loaded models
|
||||
- `On Asteroid Created` hook
|
||||
- SCPUI methods required for handling closeup briefing icons
|
||||
- Expose some Nebula settings to Lua
|
||||
- SCPUI mission log
|
||||
- SCPUI APIsfor the Game Help UI, medals access, and control config
|
||||
- Force expand wings instead of toggle for SCPUI
|
||||
- Add misc. validity checks
|
||||
- Convert hotkey types to enum
|
||||
- Finalize SCPUI API
|
||||
- Blocking `On Frame` executor
|
||||
- SCPUI Hud Config API
|
||||
- Configurable restriction for ships that accept Lua player orders
|
||||
- Add `ship::isPlayer()`
|
||||
- Lua access to default countermeasures class
|
||||
- Flag to check if a ship or weapon class is player allowed
|
||||
- Add hooks for comm menu opening/closing
|
||||
</details>
|
||||
|
||||
<details><summary>Technical: </summary>
|
||||
|
||||
- Improve CFLAGS handling
|
||||
</details>
|
||||
|
||||
## [22.2.0] - 2022-08-06
|
||||
|
||||
```
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
FreeSpace2 *S*ource *C*ode *P*roject
|
||||
==
|
||||
[](https://travis-ci.org/scp-fs2open/fs2open.github.com)
|
||||
[](https://ci.appveyor.com/project/SirKnightly/fs2open-github-com/branch/master)
|
||||
[](https://scan.coverity.com/projects/870)
|
||||
|
||||
Building
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
version: 1.0.0.{build}
|
||||
image: Visual Studio 2015
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
clone_depth: 10
|
||||
environment:
|
||||
matrix:
|
||||
- BuildID: 0
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
PlatformToolset: v140
|
||||
QT_DIR: C:\Qt\5.9\msvc2015
|
||||
- BuildID: 1
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
|
||||
PlatformToolset: v140
|
||||
QT_DIR: C:\Qt\5.9\msvc2015_64
|
||||
before_build:
|
||||
- git submodule update --init --recursive
|
||||
build_script:
|
||||
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/build.ps1
|
||||
test_script:
|
||||
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/test.ps1
|
||||
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
auth_token:
|
||||
secure: h55Scpy+3vmo1Yb7WlSIGA4d9DRnsbzUYc2LYsQdByQHZHbqrqjBpicH0D2FFLEO
|
||||
on:
|
||||
ReleaseBuild: true # deploy on release push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: sftp
|
||||
host: scp.indiegames.us
|
||||
username:
|
||||
secure: SFivQZfatqWHXK1ijYK3GQ==
|
||||
password:
|
||||
secure: q6Zk/412o1ri+NEya1dl1Q==
|
||||
folder: public_html/builds/nightly/$(VersionName)
|
||||
on:
|
||||
NightlyBuild: true # deploy on nightly push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: sftp
|
||||
host: porphyrion.feralhosting.com
|
||||
username:
|
||||
secure: 36+bVD8eJgI0BVbi7TZ4zQ==
|
||||
password:
|
||||
secure: CrzmDVca8AGG08iWPA1gOD4Ge06+wJ3rcBagBGclwYQ=
|
||||
folder: www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly/$(VersionName)
|
||||
on:
|
||||
NightlyBuild: true # deploy on nightly push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: sftp
|
||||
host: porphyrion.feralhosting.com
|
||||
username:
|
||||
secure: 36+bVD8eJgI0BVbi7TZ4zQ==
|
||||
password:
|
||||
secure: CrzmDVca8AGG08iWPA1gOD4Ge06+wJ3rcBagBGclwYQ=
|
||||
folder: www/datacorder.porphyrion.feralhosting.com/public_html/builds/test/$(VersionName)
|
||||
on:
|
||||
TestBuild: true # deploy on test build push only
|
||||
@@ -1,164 +0,0 @@
|
||||
|
||||
class BuildConfig {
|
||||
[string]$Generator
|
||||
[string]$PackageType
|
||||
[string]$Toolset
|
||||
[string]$SimdType
|
||||
[string]$QtDir
|
||||
[Bool]$SourcePackage
|
||||
}
|
||||
|
||||
$NightlyConfigurations = @(
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015 Win64";
|
||||
# PackageType="Win64";
|
||||
# Toolset="v140";
|
||||
# SimdType="SSE2";
|
||||
# QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
# SourcePackage=$false;
|
||||
# },
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015";
|
||||
# PackageType="Win32";
|
||||
# Toolset="v140";
|
||||
# SimdType="SSE2";
|
||||
# QtDir="C:\Qt\5.9\msvc2015";
|
||||
# SourcePackage=$false;
|
||||
# }
|
||||
)
|
||||
$ReleaseConfigurations = @(
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015";
|
||||
# PackageType="Win32";
|
||||
# Toolset="v140";
|
||||
# SimdType="SSE2";
|
||||
# QtDir="C:\Qt\5.9\msvc2015";
|
||||
# SourcePackage=$true;
|
||||
# }
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015";
|
||||
# PackageType="Win32-AVX";
|
||||
# Toolset="v140";
|
||||
# SimdType="AVX";
|
||||
# QtDir="C:\Qt\5.9\msvc2015";
|
||||
# SourcePackage=$false;
|
||||
# }
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015 Win64";
|
||||
# PackageType="Win64";
|
||||
# Toolset="v140";
|
||||
# SimdType="SSE2";
|
||||
# QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
# SourcePackage=$false;
|
||||
# }
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015 Win64";
|
||||
# PackageType="Win64-AVX";
|
||||
# Toolset="v140";
|
||||
# SimdType="AVX";
|
||||
# QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
# SourcePackage=$false;
|
||||
# }
|
||||
)
|
||||
|
||||
$BuildConfigurations = $null
|
||||
|
||||
# Default values
|
||||
$ReleaseBuild = $false
|
||||
$NightlyBuild = $false
|
||||
$TestBuild = $false
|
||||
|
||||
# Set to true to test either the release or the nightly part of this script
|
||||
$ReleaseTest = $false
|
||||
$NightlyTest = $false
|
||||
$TestBuildTest = $false
|
||||
|
||||
if ($ReleaseTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)"))) {
|
||||
# Tag matches
|
||||
$ReleaseBuild = $true
|
||||
$PackageName = "fs2_open_$($matches[1])"
|
||||
$BuildConfigurations = $ReleaseConfigurations
|
||||
}
|
||||
|
||||
if ($NightlyTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)"))) {
|
||||
# Tag matches
|
||||
$NightlyBuild = $true
|
||||
$PackageName = "nightly_$($matches[1])"
|
||||
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
|
||||
$BuildConfigurations = $NightlyConfigurations
|
||||
}
|
||||
|
||||
if ($TestBuildTest -Or ([System.Convert]::ToInt32($env:APPVEYOR_PULL_REQUEST_NUMBER) -le 0 -And ("$env:APPVEYOR_REPO_BRANCH" -match "^test\/(.*)"))) {
|
||||
# Tag matches
|
||||
$TestBuild = $true
|
||||
$PackageName = "test_$($matches[1])"
|
||||
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
|
||||
$BuildConfigurations = $NightlyConfigurations
|
||||
|
||||
# Override the revision string so that the builds are named correctly
|
||||
[System.IO.File]::WriteAllLines("$env:APPVEYOR_BUILD_FOLDER/version_override.cmake", "set(FSO_VERSION_REVISION_STR $env:VersionName)")
|
||||
}
|
||||
|
||||
# Multiply by 2 so that we can add 0 or 1 for debug or release Configs
|
||||
$buildID = [convert]::ToInt32($env:BuildID) * 2
|
||||
if ($Env:Configuration -eq "Release") {
|
||||
$buildID = $buildID + 1
|
||||
}
|
||||
|
||||
$DeployBuild = $false
|
||||
if ($ReleaseBuild -Or $NightlyBuild -Or $TestBuild) {
|
||||
$DeployBuild = $true
|
||||
}
|
||||
|
||||
Set-AppveyorBuildVariable 'ReleaseBuild' "$ReleaseBuild"
|
||||
Set-AppveyorBuildVariable 'NightlyBuild' "$NightlyBuild"
|
||||
Set-AppveyorBuildVariable 'TestBuild' "$TestBuild"
|
||||
|
||||
New-Item build -type directory
|
||||
Set-Location -Path build
|
||||
|
||||
if ($DeployBuild) {
|
||||
# Release build
|
||||
if ($buildID -ge $BuildConfigurations.Length) {
|
||||
# Not needed
|
||||
exit 0
|
||||
}
|
||||
|
||||
$buildConfig = $BuildConfigurations[$buildID]
|
||||
|
||||
if ($buildConfig.SourcePackage -eq $True) {
|
||||
7z a -xr'!.git' "$($PackageName)-source-Win.zip" "$env:APPVEYOR_BUILD_FOLDER"
|
||||
Push-AppveyorArtifact "$($PackageName)-source-Win.zip"
|
||||
}
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
|
||||
-DQT5_INSTALL_ROOT="$($buildConfig.QtDir)" -DFSO_BUILD_QTFRED=OFF `
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" `
|
||||
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
|
||||
|
||||
$Configs = @("Release", "FastDebug")
|
||||
foreach ($config in $Configs) {
|
||||
cmake --build . --config "$config" --target INSTALL -- /verbosity:minimal
|
||||
if (! ($?)) {
|
||||
Add-AppveyorMessage "A release build failed!"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
7z a -xr'!*.pdb' "$($PackageName)-builds-$($buildConfig.PackageType).zip" "$env:APPVEYOR_BUILD_FOLDER/../install/*"
|
||||
Push-AppveyorArtifact "$($PackageName)-builds-$($buildConfig.PackageType).zip"
|
||||
|
||||
7z a "$($PackageName)-debug-$($buildConfig.PackageType).7z" "$env:APPVEYOR_BUILD_FOLDER/../install/*.pdb"
|
||||
Push-AppveyorArtifact "$($PackageName)-debug-$($buildConfig.PackageType).7z"
|
||||
} else {
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
|
||||
-DFSO_BUILD_QTFRED=OFF -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="ON" `
|
||||
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
|
||||
|
||||
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
|
||||
|
||||
if (! ($?)) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild) -Or [System.Convert]::ToBoolean($env:TestBuild)) {
|
||||
# Skip tests for deployment
|
||||
exit 0
|
||||
} else {
|
||||
write "Running unit tests..."
|
||||
# Run unit tests
|
||||
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
|
||||
|
||||
if (! ($?)) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,11 @@ LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH
|
||||
if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
CXXFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
|
||||
CFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
|
||||
PLATFORM_CMAKE_OPTIONS=""
|
||||
# TODO: Vulkan support is disabled on MacOS due to issues with the test suite not linking correctly
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_WITH_VULKAN=OFF"
|
||||
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
|
||||
else
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas -static-libstdc++"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON"
|
||||
fi
|
||||
@@ -29,6 +30,8 @@ fi
|
||||
CMAKE_OPTIONS="$JOB_CMAKE_OPTIONS"
|
||||
if [[ "$COMPILER" =~ ^clang.*$ ]]; then
|
||||
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=ON"
|
||||
# force clang to silently allow -static-libstdc++ flag
|
||||
CXXFLAGS="$CXXFLAGS -Qunused-arguments"
|
||||
fi
|
||||
|
||||
mkdir build
|
||||
|
||||
@@ -10,27 +10,27 @@ source $HERE/dist_functions.sh
|
||||
if [ "$OS" = "Linux" ]; then
|
||||
tar -cvzf "$(get_package_name)-builds-Linux.tar.gz" *
|
||||
|
||||
echo "::set-output name=package_path::$(pwd)/$(get_package_name)-builds-Linux.tar.gz"
|
||||
echo "::set-output name=package_name::$(get_package_name)-builds-Linux.tar.gz"
|
||||
echo "::set-output name=package_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Linux.tar.gz")"
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-Linux.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-Linux.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Linux.tar.gz")" >> $GITHUB_OUTPUT
|
||||
elif [ "$OS" = "Windows" ]; then
|
||||
7z a -xr'!*.pdb' "$(get_package_name)-builds-$ARCH-$SIMD.zip" "*"
|
||||
|
||||
echo "::set-output name=package_path::$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip"
|
||||
echo "::set-output name=package_name::$(get_package_name)-builds-$ARCH-$SIMD.zip"
|
||||
echo "::set-output name=package_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip")"
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-$ARCH-$SIMD.zip" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-$ARCH-$SIMD.zip")" >> $GITHUB_OUTPUT
|
||||
|
||||
7z a "$(get_package_name)-debug-$ARCH-$SIMD.7z" "*.pdb"
|
||||
|
||||
echo "::set-output name=debug_path::$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z"
|
||||
echo "::set-output name=debug_name::$(get_package_name)-debug-$ARCH-$SIMD.7z"
|
||||
echo "::set-output name=debug_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z")"
|
||||
echo "debug_path=$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z" >> $GITHUB_OUTPUT
|
||||
echo "debug_name=$(get_package_name)-debug-$ARCH-$SIMD.7z" >> $GITHUB_OUTPUT
|
||||
echo "debug_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z")" >> $GITHUB_OUTPUT
|
||||
elif [ "$OS" = "Mac" ]; then
|
||||
tar -cvzf "$(get_package_name)-builds-Mac.tar.gz" *
|
||||
tar -cvzf "$(get_package_name)-builds-Mac.tar.gz" *.app
|
||||
|
||||
echo "::set-output name=package_path::$(pwd)/$(get_package_name)-builds-Mac.tar.gz"
|
||||
echo "::set-output name=package_name::$(get_package_name)-builds-Mac.tar.gz"
|
||||
echo "::set-output name=package_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Mac.tar.gz")"
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-Mac.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-Mac.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Mac.tar.gz")" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Invalid OS: $OS"
|
||||
fi
|
||||
@@ -10,11 +10,21 @@ HERE=$(dirname "$SCRIPT")
|
||||
source $HERE/dist_functions.sh
|
||||
|
||||
if [ "$UPLOAD_TYPE" = "nightly" ]; then
|
||||
SSHPASS=$INDIEGAMES_SSHPASS upload_files_to_sftp "$INDIEGAMES_USER@scp.indiegames.us" "public_html/builds/nightly"
|
||||
any_success=false
|
||||
if SSHPASS=$INDIEGAMES_SSHPASS upload_files_to_sftp "$INDIEGAMES_USER@scp.indiegames.us" "public_html/builds/nightly"; then
|
||||
any_success=true
|
||||
fi
|
||||
|
||||
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly"
|
||||
if SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@perses.feralhosting.com" "www/datacorder.perses.feralhosting.com/public_html/builds/nightly"; then
|
||||
any_success=true
|
||||
fi
|
||||
|
||||
if [ "$any_success" = "false" ]; then
|
||||
echo "All uploads failed"
|
||||
exit 1
|
||||
fi
|
||||
elif [ "$UPLOAD_TYPE" = "test" ]; then
|
||||
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/test"
|
||||
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@perses.feralhosting.com" "www/datacorder.perses.feralhosting.com/public_html/builds/test"
|
||||
else
|
||||
echo "Unknown upload type $UPLOAD_TYPE"
|
||||
exit 1
|
||||
|
||||
+6
-2
@@ -137,8 +137,8 @@ def main():
|
||||
"pass": os.environ["INDIEGAMES_SSHPASS"],
|
||||
"path": "public_html/builds/{type}/{version}/",
|
||||
"mirrors": (
|
||||
"https://porphyrion.feralhosting.com/datacorder/builds/{type}/{version}/{file}",
|
||||
"http://scp.indiegames.us/builds/{type}/{version}/{file}",
|
||||
"https://perses.feralhosting.com/datacorder/builds/{type}/{version}/{file}",
|
||||
"https://scp.indiegames.us/builds/{type}/{version}/{file}",
|
||||
),
|
||||
},
|
||||
"nebula": {
|
||||
@@ -260,6 +260,10 @@ def main():
|
||||
if "Linux" not in groups.keys():
|
||||
print("ERROR: No Linux builds were detected!")
|
||||
sys.exit(1)
|
||||
|
||||
if "Mac" not in groups.keys():
|
||||
print("ERROR: No Mac builds were detected!")
|
||||
sys.exit(1)
|
||||
|
||||
# z64: What dose this do???
|
||||
# print(installer.render_installer_config(version, groups, config))
|
||||
|
||||
+14
-7
@@ -9,7 +9,7 @@ PLACEHOLDER
|
||||
|
||||
Deprecations are a mechanism in FSO where a certain feature or aspect of the engine has changed or is no longer supported. Since this would normally break existing mods we have the mod table feature "[tt]$Target Version:[/tt]" with which a mod can specify what version of FSO it was developed with. The features listed above will be removed or changed when the target version of a mod is at least the version released in this post.
|
||||
|
||||
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=98360.0]22.2.0 Release Thread[/url][/size]
|
||||
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=98682.0]23.0.0 Release Thread[/url][/size]
|
||||
|
||||
Launchers, if you don't have one already:
|
||||
[b]All platforms: [/b] For every day use, we recommend [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url], an integrated solution for downloading and launching mods.
|
||||
@@ -18,11 +18,11 @@ Launchers, if you don't have one already:
|
||||
Cross-platform: [url=https://www.hard-light.net/forums/index.php?topic=89162]wxLauncher 0.12.x Test Build[/url] (ongoing project for a unified launcher, you should upgrade to the latest RC/test build if you have not yet)
|
||||
[b]Important:[/b] For best compatibility with FSO 3.8 and later you should use at least wxLauncher 0.12.
|
||||
|
||||
Windows: [url=http://scp.fsmods.net/builds/Launcher55g.zip]Launcher 5.5g[/url] ([url=http://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=https://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
|
||||
Windows: [url=http://scp.fsmods.net/builds/Launcher55g.zip]Launcher 5.5g[/url] ([url=https://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=https://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
|
||||
OS X: Soulstorm's [url=https://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
|
||||
Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=https://www.hard-light.net/wiki/index.php/Fs2_open_on_Linux/Graphics_Settings]by hand[/url] or whatever you can figure out.[/hidden]
|
||||
|
||||
[img]http://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
|
||||
[img]https://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
|
||||
[size=8pt]Compiled using GitHub Actions on Windows Server 2019 (10.0.17763), Visual Studio Enterprise 2019[/size]
|
||||
|
||||
[b]64-bit:[/b] ${build(groups["Win64"].mainFile)}
|
||||
@@ -44,7 +44,7 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
|
||||
Don't want to deal with that? Use [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url] and it will download the best build specifically for your PC!
|
||||
[/hidden]
|
||||
|
||||
[img]http://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
|
||||
[img]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
|
||||
[size=8pt]Compiled with Ubuntu 16.04 LTS 64-bit, GCC 5[/size]
|
||||
${build(groups["Linux"].mainFile)}
|
||||
|
||||
@@ -52,14 +52,21 @@ These builds use a mechanism called [url=https://appimage.org/]AppImage[/url] wh
|
||||
Alternatively, if there is a package in your software repository then you should use that. If you are the maintainer of such a package for a distribution then let us know and we will include that here.
|
||||
|
||||
|
||||
[img]http://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]OS X[/size][/color]
|
||||
[b][color=red]Not available[/color][/b] We recently lost access to our Mac CI environment which we usually used for compiling these builds so for the time being, there will be no builds for this OS.
|
||||
[img]https://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]macOS[/size][/color]
|
||||
[size=8pt]macOS 10.9+, 64-bit (Intel)[/size]
|
||||
${build(groups["Mac"].mainFile)}
|
||||
|
||||
These builds are not signed and so by default will fail to launch. To run them simply right-click on the app, click open, then click open again on the security confirmation dialog. You should only have to do this once for each app.
|
||||
If running the game through Knossos or Knossos.NET this step should not be necessary.
|
||||
|
||||
[size=8pt][color=red][b]NOTE:[/b][/color] macOS builds currently have limited support and may exhibit issues not present on other platforms.[/size]
|
||||
|
||||
|
||||
[hidden=TrackIR Users]
|
||||
[size=12pt]Important!![/size]
|
||||
An external DLL is required for FSO to use TrackIR functions. The following DLL is simply unpacked in to your main FreeSpace2 root dir.
|
||||
TrackIR is only supported on Windows.
|
||||
[url=https://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=http://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
|
||||
[url=https://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=https://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
|
||||
|
||||
Known issues:
|
||||
[list]
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Mako==1.2.2
|
||||
requests==2.26.0
|
||||
requests==2.31.0
|
||||
semantic-version==2.8.5
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$NIGHTLY_BUILD" = true ]; then
|
||||
echo "Generating bintray config..."
|
||||
sed -e "s/\$VERSION_NAME/$VERSION_NAME/" ci/bintray.template.json > ci/bintray.json
|
||||
fi
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
sudo add-apt-repository -y "ppa:msulikowski/valgrind" # For fixing a bug with valgrind 3.11 which does not recognize the rdrand instruction
|
||||
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
|
||||
sudo add-apt-repository -y 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
|
||||
|
||||
sudo apt-get -yq update
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
# Nothing to do here
|
||||
:
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
# Nothing to do here
|
||||
:
|
||||
fi
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
mkdir -p /tmp/builds
|
||||
if [ "$RELEASE_BUILD" = true ]; then
|
||||
# Package the source code in release builds
|
||||
PARENT_DIR="$(basename "$PWD")"
|
||||
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
|
||||
export CXXFLAGS
|
||||
export CFLAGS
|
||||
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
mkdir -p $config
|
||||
cd $config
|
||||
eval $CMAKE -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_BUILD_TYPE=$config -DCMAKE_INSTALL_PREFIX="/tmp/release/$config" \
|
||||
-DFSO_BUILD_APPIMAGE=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_QTFRED=OFF ../..
|
||||
cd ..
|
||||
done
|
||||
else
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=OFF ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
|
||||
else
|
||||
cmake -G "Xcode" $CMAKE_OPTIONS ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFSO_BUILD_FRED2="OFF" -G "$CMAKE_GENERATOR" ..
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "$CMAKE_GENERATOR" -T "$CMAKE_TOOLSET" ..
|
||||
fi
|
||||
fi
|
||||
@@ -1,74 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
RELEASE_BUILD=false
|
||||
NIGHTLY_BUILD=false
|
||||
TEST_BUILD=false
|
||||
|
||||
BUILD_DEPLOYMENT=false
|
||||
BUILD_CONFIGS="Release FastDebug"
|
||||
VERSION_NAME=""
|
||||
PACKAGE_NAME=""
|
||||
|
||||
RELEASE_PATTERN="^release_(.*)$"
|
||||
NIGHTLY_PATTERN="^nightly_(.*)$"
|
||||
TEST_BUILD_PATTERN="^test\/(.*)$"
|
||||
|
||||
# These are for testing
|
||||
NIGHTLY_TEST=false
|
||||
RELEASE_TEST=false
|
||||
TEST_BUILD_TEST=false
|
||||
|
||||
if [ "$RELEASE_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $RELEASE_PATTERN ]]; then
|
||||
echo "This is a release tag!";
|
||||
RELEASE_BUILD=true;
|
||||
PACKAGE_NAME="fs2_open_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
if [ "$NIGHTLY_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
|
||||
echo "This is a nightly tag!";
|
||||
NIGHTLY_BUILD=true;
|
||||
VERSION_NAME="${BASH_REMATCH[1]}";
|
||||
PACKAGE_NAME="nightly_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
if [ "$TEST_BUILD_TEST" = true ] || [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_BRANCH" =~ $TEST_BUILD_PATTERN ]]; then
|
||||
echo "This is a test build branch!";
|
||||
TEST_BUILD=true;
|
||||
if [ "$TEST_BUILD_TEST" = true ]; then
|
||||
VERSION_NAME="test";
|
||||
PACKAGE_NAME="test_test";
|
||||
else
|
||||
VERSION_NAME="${BASH_REMATCH[1]}";
|
||||
PACKAGE_NAME="test_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
|
||||
# Override the revision string so that the builds are named correctly
|
||||
echo "set(FSO_VERSION_REVISION_STR $VERSION_NAME)" > "$TRAVIS_BUILD_DIR/version_override.cmake"
|
||||
fi
|
||||
|
||||
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ] || [ "$TEST_BUILD" = true ]); then
|
||||
BUILD_DEPLOYMENT=true;
|
||||
fi
|
||||
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc-5.*$ ]])); then
|
||||
echo "Skipping non-release compiler";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
if ([[ "$CONFIGURATION" == "Debug" ]]); then
|
||||
echo "Skipping non-release configuration";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
echo "Skipping non-release platform"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
export RELEASE_BUILD
|
||||
export NIGHTLY_BUILD
|
||||
export TEST_BUILD
|
||||
export BUILD_DEPLOYMENT
|
||||
export BUILD_CONFIGS
|
||||
export VERSION_NAME
|
||||
export PACKAGE_NAME
|
||||
@@ -1,89 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -u
|
||||
|
||||
if [[ ! "$(curl -V)" == *"sftp"* ]]; then
|
||||
# Before
|
||||
echo "Before:"
|
||||
curl -V
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
|
||||
if [ -f ~/curl_cache/curl*.deb ]; then
|
||||
cd ~/curl_cache
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
else
|
||||
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
|
||||
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
|
||||
mkdir /tmp/curl
|
||||
cd /tmp/curl
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
|
||||
apt-get source curl
|
||||
sudo apt-get build-dep curl
|
||||
|
||||
cd curl-*
|
||||
export DEB_BUILD_OPTIONS="nocheck"
|
||||
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
|
||||
|
||||
cd ..
|
||||
dpkg -l | grep curl
|
||||
ls -al
|
||||
|
||||
if [ ! -d ~/curl_cache ]; then
|
||||
mkdir ~/curl_cache
|
||||
fi
|
||||
|
||||
cp libcurl3*.deb curl*.deb ~/curl_cache
|
||||
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew install libssh2
|
||||
|
||||
if [ -d ~/curl_cache/curl ]; then
|
||||
cd ~/curl_cache/curl
|
||||
sudo make install
|
||||
else
|
||||
mkdir /tmp/curl
|
||||
cd /tmp/curl
|
||||
|
||||
curl -LO "https://curl.haxx.se/download/curl-7.64.0.tar.bz2"
|
||||
tar -xjf curl-7.64.0.tar.bz2
|
||||
|
||||
cd curl-7.64.0
|
||||
./configure --disable-debug --disable-dependency-tracking --disable-silent-rules --with-libssh2 --with-darwinssl --without-ca-bundle --without-ca-path
|
||||
make -j"$(sysctl hw.logicalcpu | cut -d " " -f 2)"
|
||||
|
||||
if [ ! -d ~/curl_cache ]; then
|
||||
mkdir ~/curl_cache
|
||||
fi
|
||||
|
||||
cp -a . ~/curl_cache/curl
|
||||
sudo make install
|
||||
fi
|
||||
export PATH=/usr/local/bin:$PATH
|
||||
fi
|
||||
|
||||
# After
|
||||
echo "After:"
|
||||
curl -V
|
||||
fi
|
||||
|
||||
cd /tmp/builds
|
||||
|
||||
for file in *; do
|
||||
if [ "$TEST_BUILD" = true ]; then
|
||||
# Upload to datacorder
|
||||
curl -k "sftp://porphyrion.feralhosting.com/www/datacorder.porphyrion.feralhosting.com/public_html/builds/test/$VERSION_NAME/" --user "$DATACORDER_USER:$DATACORDER_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
else
|
||||
# Upload to indiegames
|
||||
curl -k "sftp://scp.indiegames.us/~/public_html/builds/nightly/$VERSION_NAME/" --user "$INDIEGAMES_USER:$INDIEGAMES_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
|
||||
# Upload to datacorder
|
||||
curl -k "sftp://porphyrion.feralhosting.com/~/www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly/$VERSION_NAME/" --user "$DATACORDER_USER:$DATACORDER_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
fi
|
||||
done
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
FILENAME=
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
if [ ! -d "$HOME/cmake-3.8/bin" ]; then
|
||||
# If the cache does not currently contain CMake then download and install it
|
||||
mkdir -p $HOME/cmake-3.8/
|
||||
|
||||
wget -O /tmp/cmake.tar.gz --no-check-certificate https://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz
|
||||
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake-3.8/ --strip-components=1
|
||||
fi
|
||||
export PATH=$HOME/cmake-3.8/bin:$PATH
|
||||
|
||||
cd $HOME
|
||||
|
||||
if [ "${BUILD_DEPLOYMENT}" = true ]; then
|
||||
wget -O appimagetool -c "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" # (64-bit)
|
||||
chmod a+x ./appimagetool
|
||||
|
||||
wget -O linuxdeployqt -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" # (64-bit)
|
||||
chmod a+x ./linuxdeployqt
|
||||
fi
|
||||
|
||||
sudo apt-get -yq install valgrind
|
||||
|
||||
if [[ "$CC" = "clang-9" ]]; then
|
||||
sudo apt-get -yq install clang-9 clang-tidy-9
|
||||
fi
|
||||
|
||||
if [[ "$CC" = "clang-4.0" ]]; then
|
||||
# Fix a header bug present in ubuntu...
|
||||
sudo ln -s /usr/include/libcxxabi/__cxxabi_config.h /usr/include/c++/v1/__cxxabi_config.h
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
gem install xcpretty
|
||||
|
||||
brew update
|
||||
brew outdated cmake || brew upgrade cmake
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
choco install mingw ninja
|
||||
fi
|
||||
|
||||
cmake --version
|
||||
@@ -1,68 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -ex
|
||||
mkdir -p /tmp/builds
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
cd build
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
cd "$config"
|
||||
|
||||
# Compile all targets
|
||||
ninja all
|
||||
|
||||
# Install Freespace2 targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Freespace2 -P cmake_install.cmake
|
||||
|
||||
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
|
||||
FILENAME="$(find /tmp/release/$config/fso/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
|
||||
$HOME/appimagetool -n /tmp/release/$config/fso "/tmp/release/$config/fso/$FILENAME"
|
||||
|
||||
: <<'END'
|
||||
# Install qtFRED targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=qtFRED -P cmake_install.cmake
|
||||
|
||||
PREV="$(pwd)"
|
||||
cd /tmp/release/$config/qtfred
|
||||
|
||||
unset QTDIR; unset QT_PLUGIN_PATH; unset LD_LIBRARY_PATH
|
||||
$HOME/linuxdeployqt usr/qtfred.desktop -bundle-non-qt-libs
|
||||
# Move our AppRun script to the right location
|
||||
mv usr/AppRun AppRun
|
||||
|
||||
echo "Embed newer libstdc++ for distros that don't come with it (ubuntu 14.04)";
|
||||
mkdir -p usr/optional/; mkdir -p usr/optional/libstdc++/;
|
||||
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./usr/optional/libstdc++/;
|
||||
|
||||
$HOME/appimagetool -n . "$(find /tmp/release/$config/qtfred/usr/bin -name 'qtfred_*' -type f -printf "%f\n").AppImage"
|
||||
|
||||
cd "$PREV"
|
||||
END
|
||||
|
||||
cd ..
|
||||
done
|
||||
|
||||
cp `find /tmp/release -name '*.AppImage' -print` /tmp/release
|
||||
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-Linux.tar.gz *.AppImage)
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cd build
|
||||
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
cmake --build . --config "$config" --target install | tee build.log \
|
||||
| xcpretty
|
||||
XCODE_RET=${PIPESTATUS[0]}
|
||||
if [ "$XCODE_RET" -ne "0" ]; then
|
||||
tar -cvzf build.log.tar.gz build.log
|
||||
curl --upload-file build.log.tar.gz "https://transfer.sh/build.log.tar.gz"
|
||||
exit $XCODE_RET
|
||||
fi
|
||||
done
|
||||
|
||||
ls -al /tmp/release
|
||||
|
||||
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-MacOSX.tar.gz *)
|
||||
fi
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -e
|
||||
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
ninja -k 20 all
|
||||
|
||||
if [ "$CONFIGURATION" = "Debug" ]; then
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
else
|
||||
./bin/unittests --gtest_shuffle
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
|
||||
XCODE_RET=${PIPESTATUS[0]}
|
||||
if [ "$XCODE_RET" -ne "0" ]; then
|
||||
tar -cvzf build.log.tar.gz build.log
|
||||
curl --upload-file build.log.tar.gz "https://keep.sh"
|
||||
exit $XCODE_RET
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
|
||||
cmake --build . --config "$CONFIGURATION"
|
||||
else
|
||||
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
|
||||
fi
|
||||
fi
|
||||
@@ -4,7 +4,7 @@ MESSAGE(STATUS "Doing configuration specific to Apple Clang...")
|
||||
# TODO: Actually add Mac specific flags here...
|
||||
|
||||
# Suppress specific warning
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -funroll-loops -fsigned-char -Wno-unknown-pragmas")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fsigned-char -Wno-unknown-pragmas")
|
||||
|
||||
# Omit "conversion from string literal to 'char *' is deprecated" warnings.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings")
|
||||
@@ -13,6 +13,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-char-subscripts")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-Wno-unused-variable")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Wextra -Wshadow -Wno-unused-parameter")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -Wshadow")
|
||||
@@ -33,7 +33,7 @@ set(COMPILER_FLAGS "")
|
||||
_enable_extra_compiler_warnings_flags()
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -funroll-loops -fsigned-char -Wno-unknown-pragmas")
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsigned-char -Wno-unknown-pragmas")
|
||||
|
||||
# Omit "argument unused during compilation" when clang is used with ccache.
|
||||
if(${CMAKE_CXX_COMPILER} MATCHES "ccache")
|
||||
@@ -85,7 +85,7 @@ endif()
|
||||
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
set(COMPILER_FLAGS_DEBUG "-Og -g -Wshadow")
|
||||
|
||||
# Always use the base flags and add our compiler flags at the bacl
|
||||
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
@@ -120,7 +120,7 @@ if (FSO_FATAL_WARNINGS)
|
||||
target_compile_options(compiler INTERFACE "-Werror")
|
||||
endif()
|
||||
|
||||
# Always define this to make sure that the fixed width format macros are available
|
||||
# Always define this to make sure that the fixed-width format macros are available
|
||||
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
|
||||
|
||||
@@ -45,7 +45,7 @@ endif()
|
||||
_enable_extra_compiler_warnings_flags()
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -funroll-loops -fsigned-char -Wno-unknown-pragmas")
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsigned-char -Wno-unknown-pragmas")
|
||||
|
||||
if (NOT GCC_INCREMENTAL_LINKING)
|
||||
# Place each function and data in its own section so the linker can
|
||||
@@ -115,7 +115,7 @@ endif()
|
||||
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
set(COMPILER_FLAGS_DEBUG "-Og -g -Wshadow")
|
||||
|
||||
# Always use the base flags and add our compiler flags at the back
|
||||
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
@@ -165,7 +165,7 @@ if (FSO_FATAL_WARNINGS)
|
||||
target_compile_options(compiler INTERFACE "-Werror")
|
||||
endif()
|
||||
|
||||
# Always define this to make sure that the fixed width format macros are available
|
||||
# Always define this to make sure that the fixed-width format macros are available
|
||||
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS=1)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
|
||||
|
||||
+30
-17
@@ -67,30 +67,43 @@ ENDIF(EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${FILE}\")
|
||||
ENDFUNCTION(EP_CHECK_FILE_EXISTS)
|
||||
|
||||
MACRO(COPY_FILE_TO_TARGET _target _file)
|
||||
if(UNIX)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND cp -a "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
)
|
||||
if (IS_DIRECTORY "${_file}")
|
||||
get_filename_component(_dirName "${_file}" NAME)
|
||||
if (PLATFORM_MAC AND ("${_file}" MATCHES ".framework$"))
|
||||
# This is stupid, but it preserves symlinks, unlike copy_directory_if_different.
|
||||
# Otherwise we end up creating duplicate files in the copied framework.
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND rsync -rlq "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
else()
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/${_dirName}"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
endmacro(COPY_FILE_TO_TARGET)
|
||||
|
||||
MACRO(COPY_FILES_TO_TARGET _target)
|
||||
if(UNIX)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND mkdir -p "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
|
||||
)
|
||||
endif()
|
||||
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
FOREACH(file IN LISTS TARGET_COPY_FILES)
|
||||
COPY_FILE_TO_TARGET("${_target}" "${file}")
|
||||
ENDFOREACH(file)
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
include("${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
endif()
|
||||
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 22)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 3)
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 23)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 1)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 0)
|
||||
|
||||
# A numeric revision e.g. the CI build number
|
||||
|
||||
+17
-5
@@ -20,6 +20,9 @@ TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR}/code)
|
||||
|
||||
if (FSO_BUILD_WITH_OPENGL)
|
||||
target_link_libraries(code PUBLIC OpenGL)
|
||||
if(FSO_BUILD_WITH_OPENGL_DEBUG)
|
||||
add_definitions(-DFS_OPENGL_DEBUG)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC openal)
|
||||
@@ -47,10 +50,6 @@ target_link_libraries(code PUBLIC libRocket)
|
||||
|
||||
target_link_libraries(code PUBLIC pcp)
|
||||
|
||||
if (FSO_BUILD_WITH_VULKAN)
|
||||
target_link_libraries(code PUBLIC vulkan-hpp)
|
||||
endif()
|
||||
|
||||
target_link_libraries(code PUBLIC parsers)
|
||||
|
||||
target_link_libraries(code PUBLIC mdns)
|
||||
@@ -70,6 +69,10 @@ target_link_libraries(code PUBLIC any)
|
||||
|
||||
target_link_libraries(code PUBLIC optional)
|
||||
|
||||
target_link_libraries(code PUBLIC anl)
|
||||
|
||||
target_link_libraries(code PUBLIC hidapi::hidapi)
|
||||
|
||||
target_link_libraries(code PUBLIC imgui)
|
||||
|
||||
# Headers for standalone "gui" on UNIX
|
||||
@@ -94,7 +97,16 @@ if (FSO_BUILD_WITH_OPENGL)
|
||||
target_compile_definitions(code PUBLIC WITH_OPENGL)
|
||||
endif()
|
||||
if (FSO_BUILD_WITH_VULKAN)
|
||||
target_compile_definitions(code PUBLIC WITH_VULKAN)
|
||||
find_package(Vulkan REQUIRED)
|
||||
if (Vulkan_FOUND)
|
||||
target_compile_definitions(code PUBLIC WITH_VULKAN)
|
||||
target_link_libraries(code PRIVATE Vulkan::Vulkan)
|
||||
|
||||
target_compile_definitions(code PUBLIC WITH_VULKAN VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1 VK_NO_PROTOTYPES)
|
||||
else()
|
||||
message(WARNING "FSO_BUILD_WITH_VULKAN was set, but the package was unable to be found. Forcing OFF.")
|
||||
set(FSO_BUILD_WITH_VULKAN OFF CACHE BOOL "Enable compilation of the Vulkan renderer" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(shaders.cmake)
|
||||
|
||||
@@ -34,7 +34,13 @@ typedef struct ai_flag_name {
|
||||
char flag_name[TOKEN_LENGTH];
|
||||
} ai_flag_name;
|
||||
|
||||
typedef struct ai_flag_description {
|
||||
AI::AI_Flags flag;
|
||||
SCP_string flag_desc;
|
||||
} ai_flag_description;
|
||||
|
||||
extern ai_flag_name Ai_flag_names[];
|
||||
extern ai_flag_description Ai_flag_descriptions[];
|
||||
extern const int Num_ai_flag_names;
|
||||
|
||||
// dock_orient_and_approach() modes.
|
||||
@@ -588,6 +594,8 @@ extern int ai_fire_primary_weapon(object *objp); //changed to return weather it
|
||||
extern int ai_fire_secondary_weapon(object *objp);
|
||||
extern float ai_get_weapon_dist(ship_weapon *swp);
|
||||
extern void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank_override, matrix* target_orient = nullptr, int flags = 0);
|
||||
extern bool ai_willing_to_afterburn_hard(ai_info* aip);
|
||||
extern void ai_afterburn_hard(object* objp, ai_info* aip);
|
||||
extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
|
||||
extern void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, ai_info *aip);
|
||||
|
||||
|
||||
+10
-4
@@ -45,7 +45,8 @@ namespace AI {
|
||||
Purge, // purge this goal next time we process
|
||||
Goals_purged, // this goal has already caused other goals to get purged
|
||||
Depart_sound_played,// Goober5000 - replacement for AL's hack ;)
|
||||
Target_own_team,
|
||||
Target_own_team, // this attack goal is allowed to target friendlies
|
||||
Afterburn_hard, // afterburn as hard as possible to the goal
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
@@ -121,7 +122,7 @@ namespace AI {
|
||||
Smart_shield_management,
|
||||
Smart_subsystem_targeting_for_turrets,
|
||||
Strict_turret_tagged_only_targeting,
|
||||
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in http://scp.indiegames.us/mantis/view.php?id=3198
|
||||
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in https://scp.indiegames.us/mantis/view.php?id=3198
|
||||
Turrets_ignore_target_radius,
|
||||
Use_actual_primary_range,
|
||||
Use_subsystem_path_point_radii,
|
||||
@@ -130,8 +131,9 @@ namespace AI {
|
||||
Use_only_single_fov_for_turrets,
|
||||
No_turning_directional_bias,
|
||||
Use_axial_turnrate_differences,
|
||||
all_nonshielded_ships_can_manage_ets,
|
||||
fightercraft_nonshielded_ships_can_manage_ets,
|
||||
All_nonshielded_ships_can_manage_ets,
|
||||
Fightercraft_nonshielded_ships_can_manage_ets,
|
||||
Ships_playing_dead_dont_manage_ets,
|
||||
Better_collision_avoidance,
|
||||
Require_exact_los,
|
||||
Improved_missile_avoidance,
|
||||
@@ -150,6 +152,10 @@ namespace AI {
|
||||
Fixed_removing_play_dead_order,
|
||||
Disable_bay_emerge_timeout,
|
||||
Adjusted_AI_class_autoscale,
|
||||
Carry_shield_difficulty_scaling_bug,
|
||||
Whackable_debris,
|
||||
Whackable_asteroids,
|
||||
Dynamic_goals_afterburn_hard,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
+35
-6
@@ -223,6 +223,9 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
if (optional_string("$Player Subsys Damage Factor:") || optional_string("$AI Damage Reduction to Player Subsys:"))
|
||||
parse_float_list(profile->subsys_damage_scale, NUM_SKILL_LEVELS);
|
||||
|
||||
if (optional_string("$Player Damage Inflicted Factor:"))
|
||||
parse_float_list(profile->player_damage_inflicted_scale, NUM_SKILL_LEVELS);
|
||||
|
||||
// represented in fractions of F1_0
|
||||
if (optional_string("$Predict Position Delay:"))
|
||||
{
|
||||
@@ -546,16 +549,18 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
mprintf(("Warning: \"$ships with no shields can manage ETS\" flag is deprecated in favor of \"$any ship with no shields can manage ETS\"\n"));
|
||||
bool temp;
|
||||
stuff_boolean(&temp);
|
||||
profile->flags.set(AI::Profile_Flags::all_nonshielded_ships_can_manage_ets, temp);
|
||||
profile->flags.set(AI::Profile_Flags::All_nonshielded_ships_can_manage_ets, temp);
|
||||
}
|
||||
|
||||
set_flag(profile, "$no directional bias for missile and ship turning:", AI::Profile_Flags::No_turning_directional_bias);
|
||||
|
||||
set_flag(profile, "$respect ship axial turnrate differences:", AI::Profile_Flags::Use_axial_turnrate_differences);
|
||||
|
||||
set_flag(profile, "$any ship with no shields can manage ETS:", AI::Profile_Flags::all_nonshielded_ships_can_manage_ets);
|
||||
set_flag(profile, "$any ship with no shields can manage ETS:", AI::Profile_Flags::All_nonshielded_ships_can_manage_ets);
|
||||
|
||||
set_flag(profile, "$fighters/bombers with no shields can manage ETS:", AI::Profile_Flags::fightercraft_nonshielded_ships_can_manage_ets);
|
||||
set_flag(profile, "$fighters/bombers with no shields can manage ETS:", AI::Profile_Flags::Fightercraft_nonshielded_ships_can_manage_ets);
|
||||
|
||||
set_flag(profile, "$ships playing dead don't manage ETS:", AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
|
||||
|
||||
set_flag(profile, "$better combat collision avoidance for fightercraft:", AI::Profile_Flags::Better_collision_avoidance);
|
||||
|
||||
@@ -610,6 +615,13 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$use adjusted AI class autoscale:", AI::Profile_Flags::Adjusted_AI_class_autoscale);
|
||||
|
||||
set_flag(profile, "$carry shield difficulty scaling bug:", AI::Profile_Flags::Carry_shield_difficulty_scaling_bug);
|
||||
|
||||
set_flag(profile, "$debris affected by physics whacks:", AI::Profile_Flags::Whackable_debris);
|
||||
|
||||
set_flag(profile, "$asteroids affected by physics whacks:", AI::Profile_Flags::Whackable_asteroids);
|
||||
|
||||
set_flag(profile, "$dynamic goals afterburn hard:", AI::Profile_Flags::Dynamic_goals_afterburn_hard);
|
||||
|
||||
// if we've been through once already and are at the same place, force a move
|
||||
if (saved_Mp && (saved_Mp == Mp))
|
||||
@@ -652,12 +664,21 @@ void ai_profiles_init()
|
||||
// init retail entry first
|
||||
parse_ai_profiles_tbl(NULL);
|
||||
|
||||
// Allow mission_profiles.tbl to be a alias of ai_profiles.tbl, but only load one or the other.
|
||||
// mission_profiles.tbl would be newer so assume intended, but print to the log to be sure - Mjn
|
||||
char filename[MAX_FILENAME_LEN] = "ai_profiles.tbl";
|
||||
if (cf_exists_full("mission_profiles.tbl", CF_TYPE_TABLES)) {
|
||||
mprintf(("mission_profiles.tbl was found! Using that instead of ai_profiles.tbl...\n"));
|
||||
strcpy_s(filename, "mission_profiles.tbl");
|
||||
}
|
||||
|
||||
// now parse the supplied table (if any)
|
||||
if (cf_exists_full("ai_profiles.tbl", CF_TYPE_TABLES))
|
||||
parse_ai_profiles_tbl("ai_profiles.tbl");
|
||||
if (cf_exists_full(filename, CF_TYPE_TABLES))
|
||||
parse_ai_profiles_tbl(filename);
|
||||
|
||||
// parse any modular tables
|
||||
parse_modular_table("*-aip.tbm", parse_ai_profiles_tbl);
|
||||
parse_modular_table("*-msp.tbm", parse_ai_profiles_tbl);
|
||||
|
||||
// set default if specified
|
||||
temp = ai_profile_lookup(Default_profile_name);
|
||||
@@ -711,6 +732,7 @@ void ai_profile_t::reset()
|
||||
shield_energy_scale[i] = 0;
|
||||
afterburner_recharge_scale[i] = 0;
|
||||
player_damage_scale[i] = 0;
|
||||
player_damage_inflicted_scale[i] = 0;
|
||||
|
||||
subsys_damage_scale[i] = 0;
|
||||
beam_friendly_damage_cap[i] = 0;
|
||||
@@ -760,7 +782,7 @@ void ai_profile_t::reset()
|
||||
flags.set(AI::Profile_Flags::Fix_ai_path_order_bug);
|
||||
flags.set(AI::Profile_Flags::Aspect_invulnerability_fix);
|
||||
flags.set(AI::Profile_Flags::Use_actual_primary_range);
|
||||
flags.set(AI::Profile_Flags::fightercraft_nonshielded_ships_can_manage_ets);
|
||||
flags.set(AI::Profile_Flags::Fightercraft_nonshielded_ships_can_manage_ets);
|
||||
}
|
||||
// this flag has been enabled ever since 3.7.2
|
||||
if (mod_supports_version(3, 7, 2)) {
|
||||
@@ -770,6 +792,10 @@ void ai_profile_t::reset()
|
||||
if (mod_supports_version(3, 6, 10)) {
|
||||
flags.set(AI::Profile_Flags::Reset_last_hit_target_time_for_player_hits);
|
||||
}
|
||||
// backwards compatible flag for a bug accidentally introduced during this time
|
||||
if (mod_supports_version(3, 6, 14) && !mod_supports_version(23, 1, 0)) {
|
||||
flags.set(AI::Profile_Flags::Carry_shield_difficulty_scaling_bug);
|
||||
}
|
||||
if (mod_supports_version(21, 4, 0)) {
|
||||
flags.set(AI::Profile_Flags::Fixed_ship_weapon_collision);
|
||||
}
|
||||
@@ -783,4 +809,7 @@ void ai_profile_t::reset()
|
||||
flags.set(AI::Profile_Flags::No_continuous_turn_on_attack);
|
||||
flags.set(AI::Profile_Flags::Fixed_removing_play_dead_order);
|
||||
}
|
||||
if (mod_supports_version(23, 2, 0)) {
|
||||
flags.set(AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
float shield_energy_scale[NUM_SKILL_LEVELS]; // shield energy available
|
||||
float afterburner_recharge_scale[NUM_SKILL_LEVELS]; // speed of afterburner recharge
|
||||
float player_damage_scale[NUM_SKILL_LEVELS]; // damage applied to the player
|
||||
float player_damage_inflicted_scale[NUM_SKILL_LEVELS]; // damage applied by the player
|
||||
|
||||
float subsys_damage_scale[NUM_SKILL_LEVELS]; // damage applied to a player subsystem
|
||||
float beam_friendly_damage_cap[NUM_SKILL_LEVELS]; // damage cap values for friendly beam fire
|
||||
|
||||
+49
-58
@@ -67,7 +67,6 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
|
||||
void ai_big_strafe_position();
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos);
|
||||
|
||||
extern int model_which_octant_distant_many( vec3d *pnt, int model_num,matrix *model_orient, vec3d * model_pos, polymodel **pm, int *octs);
|
||||
extern void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos);
|
||||
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal);
|
||||
|
||||
@@ -83,10 +82,9 @@ void ai_bpap(object *objp, vec3d *attacker_objp_pos, vec3d *attacker_objp_fvec,
|
||||
vec3d result_point, best_point;
|
||||
vec3d rel_point;
|
||||
int num_tries;
|
||||
model_octant *octp;
|
||||
polymodel *pm;
|
||||
int i, q, octs[4];
|
||||
int i;
|
||||
ship_info *sip = &Ship_info[Ships[objp->instance].ship_info_index];
|
||||
polymodel* pm = model_get(sip->model_num);
|
||||
model_subsystem *tp = NULL;
|
||||
if (ss != NULL)
|
||||
tp = ss->system_info;
|
||||
@@ -94,63 +92,53 @@ void ai_bpap(object *objp, vec3d *attacker_objp_pos, vec3d *attacker_objp_fvec,
|
||||
best_point = objp->pos;
|
||||
nearest_dist = weapon_travel_dist;
|
||||
|
||||
model_which_octant_distant_many(attacker_objp_pos, sip->model_num, &objp->orient, &objp->pos, &pm, octs);
|
||||
|
||||
// attempt anywhere from 16 to 4 times, more if we're closer
|
||||
num_tries = (int) (vm_vec_dist(&objp->pos, attacker_objp_pos)/objp->radius);
|
||||
|
||||
if (num_tries >= 4)
|
||||
num_tries = 1;
|
||||
else
|
||||
num_tries = 4 - num_tries;
|
||||
num_tries = (4 - num_tries) * 4;
|
||||
|
||||
// Index #0 is best one.
|
||||
if ( pm->octants[octs[0]].verts ) {
|
||||
*local_attack_point = *pm->octants[octs[0]].verts[0]; // Set just in case it doesn't get set below.
|
||||
} else {
|
||||
vm_vec_zero(local_attack_point);
|
||||
}
|
||||
vm_vec_zero(local_attack_point);
|
||||
|
||||
for (q=0; q<4; q++) {
|
||||
octp = &pm->octants[octs[q]];
|
||||
if (octp->nverts > 0) {
|
||||
auto collision_tree = model_get_bsp_collision_tree(pm->submodel[pm->detail[0]].collision_tree_index);
|
||||
|
||||
if (num_tries > octp->nverts)
|
||||
num_tries = octp->nverts;
|
||||
if (!collision_tree->poly_centers.empty()) {
|
||||
int num_polies = (int)collision_tree->poly_centers.size();
|
||||
|
||||
if (num_tries > octp->nverts)
|
||||
num_tries = octp->nverts;
|
||||
if (num_tries > num_polies)
|
||||
num_tries = num_polies;
|
||||
|
||||
for (i=0; i<num_tries; i++) {
|
||||
int index;
|
||||
float dist, dot;
|
||||
vec3d v2p;
|
||||
for (i=0; i<num_tries; i++) {
|
||||
int index;
|
||||
float dist, dot;
|
||||
vec3d v2p;
|
||||
|
||||
index = (int) (frand() * (octp->nverts));
|
||||
index = (int) (frand() * num_polies);
|
||||
|
||||
rel_point = *octp->verts[index];
|
||||
vm_vec_unrotate(&result_point, &rel_point, &objp->orient);
|
||||
vm_vec_add2(&result_point, &objp->pos);
|
||||
rel_point = collision_tree->poly_centers[index];
|
||||
vm_vec_unrotate(&result_point, &rel_point, &objp->orient);
|
||||
vm_vec_add2(&result_point, &objp->pos);
|
||||
|
||||
dist = vm_vec_normalized_dir(&v2p, &result_point, attacker_objp_pos);
|
||||
bool in_fov = false;
|
||||
dist = vm_vec_normalized_dir(&v2p, &result_point, attacker_objp_pos);
|
||||
bool in_fov = false;
|
||||
|
||||
dot = vm_vec_dot(&v2p, attacker_objp_fvec);
|
||||
if (tp == NULL) {
|
||||
if (dot > fov)
|
||||
in_fov = true;
|
||||
} else {
|
||||
in_fov = turret_fov_test(ss, attacker_objp_fvec, &v2p);
|
||||
}
|
||||
dot = vm_vec_dot(&v2p, attacker_objp_fvec);
|
||||
if (tp == NULL) {
|
||||
if (dot > fov)
|
||||
in_fov = true;
|
||||
} else {
|
||||
in_fov = turret_fov_test(ss, attacker_objp_fvec, &v2p);
|
||||
}
|
||||
|
||||
if (in_fov) {
|
||||
if (dist < nearest_dist) {
|
||||
nearest_dist = dist;
|
||||
best_point = result_point;
|
||||
*local_attack_point = rel_point;
|
||||
Assert( !vm_is_vec_nan(local_attack_point) );
|
||||
if (dot > (1.0f + fov)/2.0f) // If this point is quite good, quit searching for a better one.
|
||||
goto done_1;
|
||||
}
|
||||
if (in_fov) {
|
||||
if (dist < nearest_dist) {
|
||||
nearest_dist = dist;
|
||||
best_point = result_point;
|
||||
*local_attack_point = rel_point;
|
||||
Assert( !vm_is_vec_nan(local_attack_point) );
|
||||
if (dot > (1.0f + fov)/2.0f) // If this point is quite good, quit searching for a better one.
|
||||
goto done_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,8 +162,6 @@ done_1:
|
||||
}
|
||||
|
||||
mc_info mc;
|
||||
mc_info_init(&mc);
|
||||
|
||||
mc.model_instance_num = Ships[objp->instance].model_instance_num;
|
||||
mc.model_num = sip->model_num;
|
||||
mc.orient = &objp->orient;
|
||||
@@ -549,11 +535,11 @@ bool ai_new_maybe_reposition_attack_subsys() {
|
||||
|
||||
// get world pos of eye (stored in geye)
|
||||
ep = &(pm->view_positions[Ships[Pl_objp->instance].current_viewpoint]);
|
||||
model_local_to_global_point(&geye, &ep->pnt, pm->id, 0, &Pl_objp->orient, &Pl_objp->pos);
|
||||
model_local_to_global_point(&geye, &ep->pnt, pm, 0, &Pl_objp->orient, &Pl_objp->pos);
|
||||
|
||||
// get world pos of subsystem
|
||||
vm_vec_unrotate(&gsubpos, &aip->targeted_subsys->system_info->pnt, &En_objp->orient);
|
||||
vm_vec_add2(&gsubpos, &En_objp->pos);
|
||||
polymodel* tgt_pm = model_get(Ship_info[Ships[target_objp->instance].ship_info_index].model_num);
|
||||
model_local_to_global_point(&gsubpos, &vmd_zero_vector, tgt_pm, aip->targeted_subsys->system_info->subobj_num, &En_objp->orient, &En_objp->pos);
|
||||
|
||||
// you're in sight! shoot it!
|
||||
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 0))
|
||||
@@ -618,6 +604,7 @@ bool ai_new_maybe_reposition_attack_subsys() {
|
||||
else
|
||||
good_pos = &world_goal_pos;
|
||||
aip->next_dynamic_path_check_time = timestamp( AI_DYNAMIC_PATH_RECHECK_DELAY );
|
||||
aip->last_dynamic_path_goal = *good_pos;
|
||||
|
||||
}
|
||||
else{ //Not enough time has passed till recheck.
|
||||
@@ -631,15 +618,17 @@ bool ai_new_maybe_reposition_attack_subsys() {
|
||||
accelerate_ship(aip, subsys_distance > 200.0f ? 1.0f : subsys_distance / 200.0f);
|
||||
|
||||
if (!(Ships[Pl_objp->instance].flags[Ship::Ship_Flags::Afterburner_locked])) {
|
||||
if (subsys_distance > 300.0f) {
|
||||
if (ai_willing_to_afterburn_hard(aip) && subsys_distance > 1000.0f)
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
else if (subsys_distance > 300.0f) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 2 * F1_0;
|
||||
}
|
||||
}
|
||||
else
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
} else
|
||||
afterburners_stop(Pl_objp);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
@@ -759,7 +748,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
if (ai_new_maybe_reposition_attack_subsys())
|
||||
return;
|
||||
} else if ( ai_big_maybe_follow_subsys_path() ) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && !ai_willing_to_afterburn_hard(aip)) {
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
return;
|
||||
@@ -851,7 +840,9 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
} else {
|
||||
accelerate_ship(aip, accel);
|
||||
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
|
||||
if (ai_willing_to_afterburn_hard(aip) && accel > 0.99f && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked])) {
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
} else if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3*F1_0;
|
||||
|
||||
+253
-104
@@ -159,8 +159,8 @@ const char *Submode_text[] = {
|
||||
"STLTH_SWP",
|
||||
"BIG_APPR",
|
||||
"BIG_CIRC",
|
||||
"BIG_PARL"
|
||||
"GLIDE_ATK"
|
||||
"BIG_PARL",
|
||||
"GLIDE_ATK",
|
||||
"CIR_STRAFE"
|
||||
};
|
||||
|
||||
@@ -218,6 +218,11 @@ ai_flag_name Ai_flag_names[] = {
|
||||
{AI::AI_Flags::Free_afterburner_use, "free-afterburner-use", },
|
||||
};
|
||||
|
||||
ai_flag_description Ai_flag_descriptions[] = {
|
||||
{AI::AI_Flags::No_dynamic, "Will stop allowing the AI to pursue dynamic goals (eg: chasing ships it was not ordered to)."},
|
||||
{AI::AI_Flags::Free_afterburner_use, "Will allow AI to use afterburners when attacking a big ship, flying to a target position, guarding a ship, and flying in formation."},
|
||||
};
|
||||
|
||||
extern const int Num_ai_flag_names = sizeof(Ai_flag_names) / sizeof(ai_flag_name);
|
||||
|
||||
const char *Skill_level_names(int level, int translate)
|
||||
@@ -381,7 +386,7 @@ int is_preferred_weapon(int weapon_num, object *firer_objp, object *target_objp)
|
||||
continue;
|
||||
|
||||
auto ship_entry = &Ship_registry[hfi->ship_registry_index];
|
||||
if (ship_entry->status != ShipStatus::PRESENT)
|
||||
if (!ship_entry->objp)
|
||||
continue;
|
||||
|
||||
int signature = ship_entry->objp->signature;
|
||||
@@ -579,8 +584,9 @@ int ai_maybe_autoscale(int absolute_index)
|
||||
*/
|
||||
void init_ai_class(ai_class *aicp)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NUM_SKILL_LEVELS; i++)
|
||||
|
||||
// AI Class main attributes
|
||||
for (int i = 0; i < NUM_SKILL_LEVELS; i++)
|
||||
{
|
||||
aicp->ai_cmeasure_fire_chance[i] = FLT_MIN;
|
||||
aicp->ai_in_range_time[i] = FLT_MIN;
|
||||
@@ -605,13 +611,18 @@ void init_ai_class(ai_class *aicp)
|
||||
aicp->ai_chance_to_use_missiles_on_plr[i] = INT_MIN;
|
||||
aicp->ai_max_aim_update_delay[i] = FLT_MIN;
|
||||
aicp->ai_turret_max_aim_update_delay[i] = FLT_MIN;
|
||||
// Set the lowest values here so the table can be modular
|
||||
aicp->ai_accuracy[i] = FLT_MIN;
|
||||
aicp->ai_evasion[i] = FLT_MIN;
|
||||
aicp->ai_courage[i] = FLT_MIN;
|
||||
aicp->ai_patience[i] = FLT_MIN;
|
||||
}
|
||||
aicp->ai_profile_flags.reset();
|
||||
aicp->ai_profile_flags_set.reset();
|
||||
|
||||
//AI Class autoscale overrides
|
||||
//INT_MIN and FLT_MIN represent the "not set" state
|
||||
for (i = 0; i < NUM_SKILL_LEVELS; i++)
|
||||
for (int i = 0; i < NUM_SKILL_LEVELS; i++)
|
||||
{
|
||||
aicp->ai_aburn_use_factor[i] = INT_MIN;
|
||||
aicp->ai_shockwave_evade_chance[i] = FLT_MIN;
|
||||
@@ -639,28 +650,76 @@ void set_aic_flag(ai_class *aicp, const char *name, AI::Profile_Flags flag)
|
||||
set->remove(flag);
|
||||
}
|
||||
|
||||
static ai_class* get_ai_class_pointer(const char* class_name)
|
||||
{
|
||||
for (int i = 0; i < Num_ai_classes; i++) {
|
||||
if (!stricmp(class_name, Ai_classes[i].name)) {
|
||||
return &Ai_classes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find anything.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool class_added_in_tbm = false;
|
||||
|
||||
void parse_ai_class()
|
||||
{
|
||||
ai_class *aicp = &Ai_classes[Num_ai_classes];
|
||||
|
||||
init_ai_class(aicp);
|
||||
ai_class *aicp;
|
||||
bool create_if_not_found = true;
|
||||
char thisName[NAME_LENGTH];
|
||||
|
||||
required_string("$Name:");
|
||||
stuff_string(aicp->name, F_NAME, NAME_LENGTH);
|
||||
stuff_string(thisName, F_NAME, NAME_LENGTH);
|
||||
|
||||
Ai_class_names[Num_ai_classes] = aicp->name;
|
||||
if (optional_string("+nocreate")) {
|
||||
if (!Parsing_modular_table) {
|
||||
Warning(LOCATION, "+nocreate flag used for ai class in non-modular table\n");
|
||||
}
|
||||
create_if_not_found = false;
|
||||
}
|
||||
|
||||
required_string("$accuracy:");
|
||||
parse_float_list(aicp->ai_accuracy, NUM_SKILL_LEVELS);
|
||||
// Does this class exist already?
|
||||
// If so, load this new info into it
|
||||
aicp = get_ai_class_pointer(thisName);
|
||||
if (aicp != nullptr) {
|
||||
if (!Parsing_modular_table) {
|
||||
error_display(1, "Error: AI Class %s already exists. All class names must be unique.", thisName);
|
||||
}
|
||||
} else {
|
||||
// Don't create class if it has +nocreate and is in a modular table.
|
||||
if (!create_if_not_found && Parsing_modular_table) {
|
||||
return;
|
||||
}
|
||||
|
||||
required_string("$evasion:");
|
||||
parse_float_list(aicp->ai_evasion, NUM_SKILL_LEVELS);
|
||||
// Setup a new ai class
|
||||
aicp = &Ai_classes[Num_ai_classes];
|
||||
strcpy(aicp->name, thisName);
|
||||
|
||||
required_string("$courage:");
|
||||
parse_float_list(aicp->ai_courage, NUM_SKILL_LEVELS);
|
||||
init_ai_class(aicp);
|
||||
Ai_class_names[Num_ai_classes] = aicp->name;
|
||||
|
||||
required_string("$patience:");
|
||||
parse_float_list(aicp->ai_patience, NUM_SKILL_LEVELS);
|
||||
Num_ai_classes++;
|
||||
|
||||
if (Parsing_modular_table) {
|
||||
mprintf(("New Ai Class '%s' found in modular table\n", aicp->name));
|
||||
class_added_in_tbm = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (optional_string("$accuracy:"))
|
||||
parse_float_list(aicp->ai_accuracy, NUM_SKILL_LEVELS);
|
||||
|
||||
if (optional_string("$evasion:"))
|
||||
parse_float_list(aicp->ai_evasion, NUM_SKILL_LEVELS);
|
||||
|
||||
if (optional_string("$courage:"))
|
||||
parse_float_list(aicp->ai_courage, NUM_SKILL_LEVELS);
|
||||
|
||||
if (optional_string("$patience:"))
|
||||
parse_float_list(aicp->ai_patience, NUM_SKILL_LEVELS);
|
||||
|
||||
if (optional_string("$Afterburner Use Factor:"))
|
||||
parse_int_list(aicp->ai_aburn_use_factor, NUM_SKILL_LEVELS);
|
||||
@@ -819,6 +878,8 @@ void parse_ai_class()
|
||||
set_aic_flag(aicp, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
|
||||
|
||||
set_aic_flag(aicp, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
|
||||
|
||||
set_aic_flag(aicp, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
|
||||
}
|
||||
|
||||
void reset_ai_class_names()
|
||||
@@ -833,28 +894,18 @@ void reset_ai_class_names()
|
||||
}
|
||||
|
||||
#define AI_CLASS_INCREMENT 10
|
||||
void parse_aitbl()
|
||||
void parse_aitbl(const char* filename)
|
||||
{
|
||||
try {
|
||||
read_file_text("ai.tbl", CF_TYPE_TABLES);
|
||||
read_file_text(filename, CF_TYPE_TABLES);
|
||||
reset_parse();
|
||||
|
||||
//Just in case parse_aitbl is called twice
|
||||
free_ai_stuff();
|
||||
|
||||
Num_ai_classes = 0;
|
||||
Num_alloced_ai_classes = AI_CLASS_INCREMENT;
|
||||
Ai_classes = (ai_class*) vm_malloc(Num_alloced_ai_classes * sizeof(ai_class));
|
||||
Ai_class_names = (char**) vm_malloc(Num_alloced_ai_classes * sizeof(char*));
|
||||
|
||||
required_string("#AI Classes");
|
||||
|
||||
while (required_string_either("#End", "$Name:")) {
|
||||
|
||||
parse_ai_class();
|
||||
|
||||
Num_ai_classes++;
|
||||
|
||||
if(Num_ai_classes >= Num_alloced_ai_classes)
|
||||
{
|
||||
Num_alloced_ai_classes += AI_CLASS_INCREMENT;
|
||||
@@ -868,11 +919,10 @@ void parse_aitbl()
|
||||
}
|
||||
}
|
||||
|
||||
atexit(free_ai_stuff);
|
||||
}
|
||||
catch (const parse::ParseException& e)
|
||||
{
|
||||
mprintf(("TABLES: Unable to parse 'ai.tbl'! Error message = %s.\n", e.what()));
|
||||
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -888,14 +938,38 @@ void ai_init()
|
||||
{
|
||||
if ( !ai_inited ) {
|
||||
// Do the first time initialization stuff here
|
||||
try
|
||||
{
|
||||
parse_aitbl();
|
||||
free_ai_stuff();
|
||||
|
||||
Num_ai_classes = 0;
|
||||
Num_alloced_ai_classes = AI_CLASS_INCREMENT;
|
||||
Ai_classes = (ai_class*)vm_malloc(Num_alloced_ai_classes * sizeof(ai_class));
|
||||
Ai_class_names = (char**)vm_malloc(Num_alloced_ai_classes * sizeof(char*));
|
||||
|
||||
parse_aitbl("ai.tbl");
|
||||
|
||||
parse_modular_table("*-aic.tbm", parse_aitbl);
|
||||
|
||||
if (class_added_in_tbm) {
|
||||
mprintf(("One or more Ai Classes were added in a modular table. This may affect "
|
||||
"ai autoscaling. If that's not desired then use a tbl instead of a tbm!\n"));
|
||||
}
|
||||
catch (const parse::ParseException& e)
|
||||
{
|
||||
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "ai.tbl", e.what()));
|
||||
|
||||
// autoscaling is meaningless if only one AI class has it, and will produce either ineffectual or
|
||||
// divide-by-zero math expressions if $use adjusted AI class autoscale: is enabled
|
||||
int num_autoscaled_classes = 0;
|
||||
int autoscaled_class_index = -1;
|
||||
for (int i = 0; i < Num_ai_classes; ++i) {
|
||||
if (Ai_classes[i].ai_class_autoscale) {
|
||||
num_autoscaled_classes++;
|
||||
autoscaled_class_index = i;
|
||||
}
|
||||
}
|
||||
if (num_autoscaled_classes == 1) {
|
||||
Warning(LOCATION, "Autoscaling is meaningless when only one AI class has autoscaling enabled. Turning off autoscaling for %s.", Ai_classes[autoscaled_class_index].name);
|
||||
Ai_classes[autoscaled_class_index].ai_class_autoscale = false;
|
||||
}
|
||||
|
||||
atexit(free_ai_stuff);
|
||||
|
||||
ai_inited = 1;
|
||||
}
|
||||
@@ -1308,6 +1382,15 @@ void ai_turn_towards_vector(vec3d* dest, object* objp, vec3d* slide_vec, vec3d*
|
||||
acc_limit.xyz.z *= 0.2f;
|
||||
}
|
||||
|
||||
// finally, maybe override the limits based on some ship flags
|
||||
if (objp->type == OBJ_SHIP) {
|
||||
ship_info* sip = &Ship_info[Ships[objp->instance].ship_info_index];
|
||||
if (sip->flags[Ship::Info_Flags::Dont_clamp_max_velocity])
|
||||
vel_limit = vm_vec_new(200.0f, 200.0f, 200.0f); // 200 rad/s should be enough to get anywhere within a 1/60th of a second
|
||||
if (sip->flags[Ship::Info_Flags::Instantaneous_acceleration])
|
||||
acc_limit = vm_vec_new(12000.0f, 12000.0f, 12000.0f); // enough to get to 200 rad/s in 1/60th of a second
|
||||
}
|
||||
|
||||
src = objp->pos;
|
||||
|
||||
if (rel_pos != NULL) {
|
||||
@@ -1576,7 +1659,7 @@ void set_accel_for_target_speed(object *objp, float tspeed)
|
||||
|
||||
aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
|
||||
max_speed = Ships[objp->instance].current_max_speed;
|
||||
max_speed = objp->phys_info.max_vel.xyz.z;
|
||||
|
||||
if (max_speed > 0.0f) {
|
||||
AI_ci.forward = tspeed/max_speed;
|
||||
@@ -1887,7 +1970,7 @@ int num_enemies_attacking(int objnum)
|
||||
/**
|
||||
* Scan all the ships in *objp's wing. Return the lowest maximum speed of a ship in the wing.
|
||||
*
|
||||
* Current maximum speed (based on energy settings) is shipp->current_max_speed
|
||||
* Current maximum speed (based on energy settings) is objp->phys_info.max_vel.xyz.z
|
||||
*/
|
||||
float get_wing_lowest_max_speed(object *objp)
|
||||
{
|
||||
@@ -1902,7 +1985,7 @@ float get_wing_lowest_max_speed(object *objp)
|
||||
shipp = &Ships[objp->instance];
|
||||
wingnum = shipp->wingnum;
|
||||
|
||||
lowest_max_speed = shipp->current_max_speed;
|
||||
lowest_max_speed = objp->phys_info.max_vel.xyz.z;
|
||||
|
||||
if ( wingnum == -1 )
|
||||
return lowest_max_speed;
|
||||
@@ -1920,13 +2003,13 @@ float get_wing_lowest_max_speed(object *objp)
|
||||
if ((oaip->mode == AIM_WAYPOINTS) && (oshipp->wingnum == wingnum)) {
|
||||
// Note: If a ship in the wing has a super low max speed, probably its engines are disabled. So, fly along and
|
||||
// ignore the poor guy.
|
||||
float cur_max = oshipp->current_max_speed;
|
||||
float cur_max = o->phys_info.max_vel.xyz.z;
|
||||
|
||||
if (object_is_docked(o)) {
|
||||
cur_max *= o->phys_info.mass / dock_calc_total_docked_mass(o);
|
||||
}
|
||||
|
||||
if ((oshipp->current_max_speed > 5.0f) && (cur_max < lowest_max_speed)) {
|
||||
if ((o->phys_info.max_vel.xyz.z > 5.0f) && (cur_max < lowest_max_speed)) {
|
||||
lowest_max_speed = cur_max;
|
||||
}
|
||||
}
|
||||
@@ -1958,14 +2041,16 @@ float get_wing_lowest_av_ab_speed(object *objp)
|
||||
|
||||
wingnum = shipp->wingnum;
|
||||
|
||||
if (((shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(sip->flags[Ship::Info_Flags::Afterburner])) || (shipp->current_max_speed < 5.0f) || (objp->phys_info.afterburner_max_vel.xyz.z <= shipp->current_max_speed) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
lowest_max_av_ab_speed = shipp->current_max_speed;
|
||||
if (((shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(sip->flags[Ship::Info_Flags::Afterburner])) || (objp->phys_info.max_vel.xyz.z < 5.0f) ||
|
||||
(objp->phys_info.afterburner_max_vel.xyz.z <= objp->phys_info.max_vel.xyz.z) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use]
|
||||
|| aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
lowest_max_av_ab_speed = objp->phys_info.max_vel.xyz.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
recharge_scale = Energy_levels[shipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level];
|
||||
recharge_scale = sip->afterburner_recover_rate * recharge_scale / (sip->afterburner_burn_rate + sip->afterburner_recover_rate * recharge_scale);
|
||||
lowest_max_av_ab_speed = recharge_scale * (objp->phys_info.afterburner_max_vel.xyz.z - shipp->current_max_speed) + shipp->current_max_speed;
|
||||
lowest_max_av_ab_speed = recharge_scale * (objp->phys_info.afterburner_max_vel.xyz.z - objp->phys_info.max_vel.xyz.z) + objp->phys_info.max_vel.xyz.z;
|
||||
}
|
||||
|
||||
|
||||
@@ -1986,14 +2071,14 @@ float get_wing_lowest_av_ab_speed(object *objp)
|
||||
if ((oaip->mode == AIM_WAYPOINTS) && (oshipp->wingnum == wingnum) && (oaip->ai_flags[AI::AI_Flags::Formation_object, AI::AI_Flags::Formation_wing])) {
|
||||
|
||||
float cur_max;
|
||||
if ((oshipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(osip->flags[Ship::Info_Flags::Afterburner]) || (o->phys_info.afterburner_max_vel.xyz.z <= oshipp->current_max_speed) || !(oaip->ai_flags[AI::AI_Flags::Free_afterburner_use] || oaip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
cur_max = oshipp->current_max_speed;
|
||||
if ((oshipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(osip->flags[Ship::Info_Flags::Afterburner]) || (o->phys_info.afterburner_max_vel.xyz.z <= o->phys_info.max_vel.xyz.z) || !(oaip->ai_flags[AI::AI_Flags::Free_afterburner_use] || oaip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
cur_max = o->phys_info.max_vel.xyz.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
recharge_scale = Energy_levels[shipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level];
|
||||
recharge_scale = osip->afterburner_recover_rate * recharge_scale / (osip->afterburner_burn_rate + osip->afterburner_recover_rate * recharge_scale);
|
||||
cur_max = recharge_scale * (o->phys_info.afterburner_max_vel.xyz.z - oshipp->current_max_speed) + oshipp->current_max_speed;
|
||||
cur_max = recharge_scale * (o->phys_info.afterburner_max_vel.xyz.z - o->phys_info.max_vel.xyz.z) + o->phys_info.max_vel.xyz.z;
|
||||
}
|
||||
|
||||
if (object_is_docked(o)) {
|
||||
@@ -2001,7 +2086,7 @@ float get_wing_lowest_av_ab_speed(object *objp)
|
||||
}
|
||||
// Note: If a ship in the wing has a super low max speed, probably its engines are disabled. So, fly along and
|
||||
// ignore the poor guy.
|
||||
if ((oshipp->current_max_speed > 5.0f) && (cur_max < lowest_max_av_ab_speed)) {
|
||||
if ((o->phys_info.max_vel.xyz.z > 5.0f) && (cur_max < lowest_max_av_ab_speed)) {
|
||||
lowest_max_av_ab_speed = cur_max;
|
||||
}
|
||||
}
|
||||
@@ -3268,6 +3353,8 @@ void ai_do_objects_undocked_stuff( object *docker, object *dockee )
|
||||
dockee_aip->support_ship_objnum = -1;
|
||||
docker_aip->support_ship_signature = -1;
|
||||
dockee_aip->support_ship_signature = -1;
|
||||
// clear out points for docker
|
||||
docker_aip->path_start = -1;
|
||||
}
|
||||
|
||||
// unlink the two objects
|
||||
@@ -3365,7 +3452,7 @@ void ai_dock_with_object(object *docker, int docker_index, object *dockee, int d
|
||||
// make sure we have a path
|
||||
if (path_num < 0)
|
||||
{
|
||||
Error(LOCATION, "Cannot find a dock path for ship %s, dock index %d. Aborting dock.\n", Ships[dockee->instance].ship_name, dockee_index);
|
||||
Warning(LOCATION, "Cannot find a dock path for ship %s, dock index %d. Aborting dock.\n", Ships[dockee->instance].ship_name, dockee_index);
|
||||
ai_mission_goal_complete(aip);
|
||||
return;
|
||||
}
|
||||
@@ -3674,6 +3761,33 @@ void ai_update_aim(ai_info *aip)
|
||||
}
|
||||
}
|
||||
|
||||
// returns if the currently active goal trying to afterburn hard
|
||||
bool ai_willing_to_afterburn_hard(ai_info* aip) {
|
||||
return aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC ?
|
||||
The_mission.ai_profile->flags[AI::Profile_Flags::Dynamic_goals_afterburn_hard] :
|
||||
aip->goals[aip->active_goal].flags[AI::Goal_Flags::Afterburn_hard];
|
||||
}
|
||||
|
||||
// pedal to the metal!!1!
|
||||
void ai_afterburn_hard(object* objp, ai_info* aip) {
|
||||
ship* shipp = &Ships[objp->instance];
|
||||
|
||||
if (!(objp->phys_info.flags & PF_AFTERBURNER_ON)) {
|
||||
if (shipp->afterburner_fuel > Ship_info[shipp->ship_info_index].afterburner_fuel_capacity * 0.3) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 5 * F1_0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (shipp->afterburner_fuel > 0.0f) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 5 * F1_0;
|
||||
}
|
||||
}
|
||||
|
||||
accelerate_ship(aip, 1.0f);
|
||||
};
|
||||
|
||||
// Given an ai_info struct, by reading current goal and path information,
|
||||
// extract base path information and return in pmp and pmpv.
|
||||
// Return true if found, else return false.
|
||||
@@ -3824,6 +3938,9 @@ void set_accel_for_docking(object *objp, ai_info *aip, float dot, float dot_to_n
|
||||
} else {
|
||||
change_acceleration(aip, -1.0f); // -1.0f means subtract off flFrametime from acceleration value in 0.0..1.0
|
||||
}
|
||||
} else if (max_allowed_speed <= 0.0f && ai_willing_to_afterburn_hard(aip) && dist_to_goal > 1000.0f && dot > 0.99f) {
|
||||
// BOOK IT
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
} else {
|
||||
float max_bay_speed = sip->max_speed;
|
||||
|
||||
@@ -4615,7 +4732,11 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
|
||||
ab_allowed = false;
|
||||
}
|
||||
|
||||
if (!(sip->flags[Ship::Info_Flags::Afterburner]) || (shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
if (!(sip->flags[Ship::Info_Flags::Afterburner]) || (shipp->flags[Ship::Ship_Flags::Afterburner_locked]) ||
|
||||
!(aip->ai_flags[AI::AI_Flags::Free_afterburner_use] ||
|
||||
aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use] ||
|
||||
ai_willing_to_afterburn_hard(aip)))
|
||||
{
|
||||
ab_allowed = false;
|
||||
}
|
||||
|
||||
@@ -4624,13 +4745,13 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
|
||||
float max_allowed_ab_speed = 10000.1f;
|
||||
float self_ab_speed = 10000.0f;
|
||||
|
||||
if (shipp->wingnum != -1) {
|
||||
if (shipp->wingnum != -1 && !ai_willing_to_afterburn_hard(aip)) {
|
||||
max_allowed_speed = 0.9f * get_wing_lowest_max_speed(Pl_objp);
|
||||
max_allowed_ab_speed = 0.95f * get_wing_lowest_av_ab_speed(Pl_objp);
|
||||
if (ab_allowed) {
|
||||
float self_ab_scale = Energy_levels[shipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level];
|
||||
self_ab_scale = sip->afterburner_recover_rate * self_ab_scale / (sip->afterburner_burn_rate + sip->afterburner_recover_rate * self_ab_scale);
|
||||
self_ab_speed = 0.95f * (self_ab_scale * (Pl_objp->phys_info.afterburner_max_vel.xyz.z - shipp->current_max_speed) + shipp->current_max_speed);
|
||||
self_ab_speed = 0.95f * (self_ab_scale * (Pl_objp->phys_info.afterburner_max_vel.xyz.z - Pl_objp->phys_info.max_vel.xyz.z) + Pl_objp->phys_info.max_vel.xyz.z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4642,7 +4763,7 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
|
||||
|
||||
if ((self_ab_speed < 5.0f) || (max_allowed_ab_speed < 5.0f)){ // || ((shipp->wingnum != -1) && (dist_to_goal / max_allowed_ab_speed < 5.0f))){
|
||||
ab_allowed = false;
|
||||
} else if (max_allowed_ab_speed < shipp->current_max_speed) {
|
||||
} else if (max_allowed_ab_speed < Pl_objp->phys_info.max_vel.xyz.z) {
|
||||
if (max_allowed_speed < max_allowed_ab_speed) {
|
||||
max_allowed_speed = max_allowed_ab_speed;
|
||||
} else {
|
||||
@@ -4681,16 +4802,16 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
|
||||
}
|
||||
|
||||
if (!(Pl_objp->phys_info.flags & PF_AFTERBURNER_ON )) {
|
||||
if (aip->prev_accel * shipp->current_max_speed > max_allowed_ab_speed) {
|
||||
accelerate_ship(aip, max_allowed_ab_speed / shipp->current_max_speed);
|
||||
if (aip->prev_accel * Pl_objp->phys_info.max_vel.xyz.z > max_allowed_ab_speed) {
|
||||
accelerate_ship(aip, max_allowed_ab_speed / Pl_objp->phys_info.max_vel.xyz.z);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Pl_objp->phys_info.flags & PF_AFTERBURNER_ON ) {
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
if (aip->prev_accel * shipp->current_max_speed > max_allowed_speed) {
|
||||
accelerate_ship(aip, max_allowed_speed / shipp->current_max_speed);
|
||||
if (aip->prev_accel * Pl_objp->phys_info.max_vel.xyz.z > max_allowed_speed) {
|
||||
accelerate_ship(aip, max_allowed_speed / Pl_objp->phys_info.max_vel.xyz.z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7198,8 +7319,10 @@ void attack_set_accel(ai_info *aip, ship_info *sip, float dist_to_enemy, float d
|
||||
optimal_range = wip->optimum_range;
|
||||
|
||||
if (dist_to_enemy > optimal_range + vm_vec_mag_quick(&En_objp->phys_info.vel) * dot_from_enemy + Pl_objp->phys_info.speed * speed_ratio) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
if (dist_to_enemy > optimal_range + 600.0f) {
|
||||
if (dist_to_enemy > optimal_range + 600.0f) {
|
||||
if (ai_willing_to_afterburn_hard(aip)) {
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
} else if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
if (!( Pl_objp->phys_info.flags & PF_AFTERBURNER_ON )) {
|
||||
float percent_left;
|
||||
ship_info *sip_local;
|
||||
@@ -7274,8 +7397,10 @@ static void get_behind_ship(ai_info *aip)
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
dot = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
|
||||
|
||||
if (dot > 0.25f) {
|
||||
|
||||
if (ai_willing_to_afterburn_hard(aip) && dot > 0.9f && vm_vec_dist(&Pl_objp->pos, &En_objp->pos) > 1000.0f) {
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
} else if (dot > 0.25f) {
|
||||
accelerate_ship(aip, 1.0f);
|
||||
} else {
|
||||
accelerate_ship(aip, (dot + 1.0f)/2.0f);
|
||||
@@ -7300,11 +7425,9 @@ int avoid_player(object *objp, vec3d *goal_pos)
|
||||
// If so, stuff *collision_point.
|
||||
int will_collide_pp(vec3d *p0, vec3d *p1, float radius, object *big_objp, vec3d *collision_point)
|
||||
{
|
||||
mc_info mc;
|
||||
mc_info_init(&mc);
|
||||
|
||||
polymodel *pm = model_get(Ship_info[Ships[big_objp->instance].ship_info_index].model_num);
|
||||
|
||||
mc_info mc;
|
||||
mc.model_instance_num = -1;
|
||||
mc.model_num = pm->id; // Fill in the model to check
|
||||
mc.orient = &big_objp->orient; // The object's orient
|
||||
@@ -7494,6 +7617,10 @@ int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d
|
||||
float dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
|
||||
float d2 = (1.0f + dot) * (1.0f + dot);
|
||||
accelerate_ship(aip, d2/4.0f);
|
||||
|
||||
if (ai_willing_to_afterburn_hard(aip) && dot > 0.99f)
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -8493,6 +8620,10 @@ void ai_cruiser_chase()
|
||||
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
|
||||
float dot = vm_vec_dot_to_point(&Pl_objp->orient.vec.fvec, &Pl_objp->pos, &En_objp->pos);
|
||||
if (ai_willing_to_afterburn_hard(aip) && dot > 0.99f)
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
}
|
||||
|
||||
// really track down and chase
|
||||
@@ -10543,16 +10674,25 @@ void ai_big_guard()
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (cur_guard_rad > 1.1f * max_guard_dist)) {
|
||||
|
||||
bool free_ab_use = aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use];
|
||||
if (!(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) &&
|
||||
(free_ab_use || ai_willing_to_afterburn_hard(aip)) &&
|
||||
(cur_guard_rad > 1.1f * max_guard_dist))
|
||||
{
|
||||
vec3d v2g;
|
||||
float dot_to_goal_point;
|
||||
|
||||
vm_vec_normalized_dir(&v2g, &goal_pt, &Pl_objp->pos);
|
||||
dot_to_goal_point = vm_vec_dot(&v2g, &Pl_objp->orient.vec.fvec);
|
||||
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip) && dot_to_goal_point > 0.75f) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3*F1_0;
|
||||
if (dot_to_goal_point > 0.75f) {
|
||||
if (ai_willing_to_afterburn_hard(aip))
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
else if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3 * F1_0;
|
||||
}
|
||||
}
|
||||
} else if (Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) {
|
||||
afterburners_stop(Pl_objp);
|
||||
@@ -10666,8 +10806,14 @@ void ai_guard()
|
||||
compute_desired_rvec(&rvec, &goal_point, &Pl_objp->pos);
|
||||
ai_turn_towards_vector(&goal_point, Pl_objp, nullptr, nullptr, 0.0f, 0, &rvec);
|
||||
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel_scale * (0.25f + dist_to_goal_point/700.0f) > 0.8f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
bool free_ab_use = aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use];
|
||||
if (!(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) &&
|
||||
(free_ab_use || ai_willing_to_afterburn_hard(aip)) &&
|
||||
(accel_scale * (0.25f + dist_to_goal_point/700.0f) > 0.8f))
|
||||
{
|
||||
if (ai_willing_to_afterburn_hard(aip))
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
else if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3*F1_0;
|
||||
}
|
||||
@@ -10877,10 +11023,10 @@ void ai_do_objects_repairing_stuff( object *repaired_objp, object *repair_objp,
|
||||
// send appropriate messages here
|
||||
if (Game_mode & GM_NORMAL || MULTIPLAYER_MASTER) {
|
||||
if ( how == REPAIR_INFO_KILLED ){
|
||||
message_send_builtin_to_player( MESSAGE_SUPPORT_KILLED, NULL, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_SOON, 0, 0, p_index, p_team );
|
||||
message_send_builtin(MESSAGE_SUPPORT_KILLED, nullptr, nullptr, p_index, p_team);
|
||||
} else {
|
||||
if ( repair_objp ){
|
||||
message_send_builtin_to_player( MESSAGE_REPAIR_ABORTED, &Ships[repair_objp->instance], MESSAGE_PRIORITY_NORMAL, MESSAGE_TIME_SOON, 0, 0, p_index, p_team );
|
||||
message_send_builtin(MESSAGE_REPAIR_ABORTED, &Ships[repair_objp->instance], nullptr, p_index, p_team);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10902,7 +11048,7 @@ void ai_do_objects_repairing_stuff( object *repaired_objp, object *repair_objp,
|
||||
hud_support_view_stop();
|
||||
|
||||
if (Game_mode & GM_NORMAL || MULTIPLAYER_MASTER) {
|
||||
message_send_builtin_to_player(MESSAGE_REPAIR_DONE, &Ships[repair_objp->instance], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, p_index, p_team);
|
||||
message_send_builtin(MESSAGE_REPAIR_DONE, &Ships[repair_objp->instance], nullptr, p_index, p_team);
|
||||
}
|
||||
}
|
||||
stamp = timestamp((int) ((30 + 10*frand()) * 1000));
|
||||
@@ -11251,6 +11397,10 @@ void ai_stay_near()
|
||||
if (dist > max_dist) {
|
||||
turn_towards_point(Pl_objp, &goal_pos, NULL, 0.0f);
|
||||
accelerate_ship(aip, dist / max_dist - 0.8f);
|
||||
|
||||
float dot = vm_vec_dot_to_point(&Pl_objp->orient.vec.fvec, &Pl_objp->pos, &goal_pos);
|
||||
if (ai_willing_to_afterburn_hard(aip) && dot > 0.99f && dist - max_dist > 700.0f)
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12461,7 +12611,8 @@ int ai_formation()
|
||||
|
||||
ship_info *sip = &Ship_info[shipp->ship_info_index];
|
||||
bool ab_allowed = false;
|
||||
if ((sip->flags[Ship::Info_Flags::Afterburner]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
if ((sip->flags[Ship::Info_Flags::Afterburner]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) &&
|
||||
((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) || ai_willing_to_afterburn_hard(aip))) {
|
||||
ab_allowed = true;
|
||||
} else {
|
||||
if (Pl_objp->phys_info.flags & PF_AFTERBURNER_ON)
|
||||
@@ -12490,13 +12641,13 @@ int ai_formation()
|
||||
} else if (dist_to_goal > 200.0f) {
|
||||
if (dot_to_goal > -0.5f) {
|
||||
turn_towards_point(Pl_objp, &goal_point, nullptr, 0.0f, leader_orient, AITTV_SLOW_BANK_ACCEL);
|
||||
float range_speed = shipp->current_max_speed - leader_speed;
|
||||
float range_speed = Pl_objp->phys_info.max_vel.xyz.z - leader_speed;
|
||||
if (range_speed > 0.0f) {
|
||||
set_accel_for_target_speed(Pl_objp, leader_speed + range_speed * (dist_to_goal+100.0f)/500.0f);
|
||||
if (Pl_objp->phys_info.flags & PF_AFTERBURNER_ON)
|
||||
afterburners_stop(Pl_objp);
|
||||
} else {
|
||||
set_accel_for_target_speed(Pl_objp, shipp->current_max_speed);
|
||||
set_accel_for_target_speed(Pl_objp, Pl_objp->phys_info.max_vel.xyz.z);
|
||||
if (ab_allowed) {
|
||||
if (!(Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && (dot_to_goal > 0.4f)) {
|
||||
float percent_left = 100.0f * shipp->afterburner_fuel / sip->afterburner_fuel_capacity;
|
||||
@@ -12536,13 +12687,13 @@ int ai_formation()
|
||||
} else if (dist_to_goal > 75.0f) {
|
||||
turn_towards_point(Pl_objp, &future_goal_point_2, nullptr, 0.0f, leader_orient, AITTV_SLOW_BANK_ACCEL);
|
||||
float delta_speed;
|
||||
float range_speed = shipp->current_max_speed - leader_speed;
|
||||
float range_speed = Pl_objp->phys_info.max_vel.xyz.z - leader_speed;
|
||||
if (range_speed > 0.0f) {
|
||||
delta_speed = dist_to_goal_2/500.0f * range_speed;
|
||||
if (Pl_objp->phys_info.flags & PF_AFTERBURNER_ON)
|
||||
afterburners_stop(Pl_objp);
|
||||
} else {
|
||||
delta_speed = shipp->current_max_speed - leader_speed;
|
||||
delta_speed = Pl_objp->phys_info.max_vel.xyz.z - leader_speed;
|
||||
if (ab_allowed) {
|
||||
if (!(Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && (dot_to_goal > 0.6f)) {
|
||||
float percent_left = 100.0f * shipp->afterburner_fuel / sip->afterburner_fuel_capacity;
|
||||
@@ -12607,7 +12758,7 @@ int ai_formation()
|
||||
set_accel_for_target_speed(Pl_objp, leader_speed + 1.5f * dot_to_goal - 1.0f);
|
||||
}
|
||||
|
||||
float range_speed = shipp->current_max_speed - leader_speed;
|
||||
float range_speed = Pl_objp->phys_info.max_vel.xyz.z - leader_speed;
|
||||
if (range_speed > 0.0f) {
|
||||
if (Pl_objp->phys_info.flags & PF_AFTERBURNER_ON)
|
||||
afterburners_stop(Pl_objp);
|
||||
@@ -12635,7 +12786,7 @@ int ai_formation()
|
||||
// Goober5000 7/5/2006 changed to leader_speed from 0.0f
|
||||
set_accel_for_target_speed(Pl_objp, leader_speed);
|
||||
|
||||
float range_speed = shipp->current_max_speed - leader_speed;
|
||||
float range_speed = Pl_objp->phys_info.max_vel.xyz.z - leader_speed;
|
||||
if (range_speed > 0.0f) {
|
||||
if (Pl_objp->phys_info.flags & PF_AFTERBURNER_ON)
|
||||
afterburners_stop(Pl_objp);
|
||||
@@ -12836,10 +12987,10 @@ void ai_maybe_launch_cmeasure(object *objp, ai_info *aip)
|
||||
// check if modder wants to use custom fail delay, or default
|
||||
if (cmeasure->cmeasure_failure_delay_multiplier_ai >= 0) {
|
||||
// use firewait as delay
|
||||
fail_delay = cmeasure->cmeasure_firewait * cmeasure->cmeasure_failure_delay_multiplier_ai;
|
||||
fail_delay = static_cast<int> (cmeasure->cmeasure_firewait * cmeasure->cmeasure_failure_delay_multiplier_ai);
|
||||
} else {
|
||||
// use default to wait firwait + additional delay to decrease chance of firing very soon.
|
||||
fail_delay = cmeasure->cmeasure_firewait + (int) (fire_chance*2000);
|
||||
fail_delay = cmeasure->cmeasure_firewait + static_cast<int> (fire_chance * 2000);
|
||||
}
|
||||
shipp->cmeasure_fire_stamp = timestamp(fail_delay);
|
||||
return;
|
||||
@@ -12848,7 +12999,7 @@ void ai_maybe_launch_cmeasure(object *objp, ai_info *aip)
|
||||
if (weapon_objp->type == OBJ_WEAPON) {
|
||||
if (weapon_objp->instance >= 0) {
|
||||
ship_launch_countermeasure(objp);
|
||||
shipp->cmeasure_fire_stamp = timestamp(cmeasure->cmeasure_firewait * cmeasure->cmeasure_sucess_delay_multiplier_ai);
|
||||
shipp->cmeasure_fire_stamp = timestamp(static_cast<int> (cmeasure->cmeasure_firewait * cmeasure->cmeasure_success_delay_multiplier_ai));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -13748,7 +13899,7 @@ void ai_execute_behavior(ai_info *aip)
|
||||
ship *shipp = &Ships[aip->shipnum];
|
||||
ship_info *sip = &Ship_info[shipp->ship_info_index];
|
||||
|
||||
if (strnicmp(shipp->ship_name, INSTRUCTOR_SHIP_NAME, strlen(INSTRUCTOR_SHIP_NAME)) != 0) {
|
||||
if (!is_instructor(&Objects[shipp->objnum])) {
|
||||
if (sip->is_big_or_huge()) {
|
||||
aip->mode = AIM_NONE;
|
||||
} else {
|
||||
@@ -14581,6 +14732,11 @@ int ai_need_new_target(object *pl_objp, int target_objnum)
|
||||
if ( Ships[objp->instance].flags[Ship::Ship_Flags::Dying] ) {
|
||||
return 1;
|
||||
} else if (Ships[objp->instance].team == Ships[pl_objp->instance].team) {
|
||||
// Goober5000 - targeting the same team is allowed it if attacks itself
|
||||
if (iff_x_attacks_y(Ships[pl_objp->instance].team, Ships[pl_objp->instance].team)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Goober5000 - targeting the same team is allowed if pl_objp is going bonkers
|
||||
ai_info *pl_aip = &Ai_info[Ships[pl_objp->instance].ai_index];
|
||||
if (pl_aip->active_goal != AI_GOAL_NONE && pl_aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) {
|
||||
@@ -15045,9 +15201,6 @@ void ai_process( object * obj, int ai_index, float frametime )
|
||||
|
||||
ai_frame(OBJ_INDEX(obj));
|
||||
|
||||
// the ships maximum velocity now depends on the energy flowing to engines
|
||||
obj->phys_info.max_vel.xyz.z = shipp->current_max_speed;
|
||||
|
||||
// In certain circumstances, the AI says don't fly in the normal way.
|
||||
// One circumstance is in docking and undocking, when the ship is moving
|
||||
// under thruster control.
|
||||
@@ -15408,9 +15561,9 @@ void process_friendly_hit_message( int message, object *objp )
|
||||
|
||||
if ( index >= 0 )
|
||||
{
|
||||
message_send_builtin_to_player( message, &Ships[index], MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_ANYTIME, 0, 0, -1, -1 );
|
||||
message_send_builtin(message, &Ships[index], nullptr, -1, -1);
|
||||
} else {
|
||||
message_send_builtin_to_player( message, NULL, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_ANYTIME, 0, 0, -1, -1 );
|
||||
message_send_builtin(message, nullptr, nullptr, -1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15519,7 +15672,7 @@ void maybe_process_friendly_hit(object *objp_hitter, object *objp_hit, object *o
|
||||
if (is_instructor(objp_hit)) {
|
||||
// it's not nice to hit your instructor
|
||||
if (pp->friendly_damage > FRIENDLY_DAMAGE_THRESHOLD) {
|
||||
message_send_builtin_to_player( MESSAGE_INSTRUCTOR_ATTACK, NULL, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, -1, -1);
|
||||
message_send_builtin(MESSAGE_INSTRUCTOR_ATTACK, nullptr, nullptr, -1, -1);
|
||||
pp->last_warning_message_time = Missiontime;
|
||||
ship_set_subsystem_strength( Player_ship, SUBSYSTEM_WEAPONS, 0.0f);
|
||||
|
||||
@@ -15531,7 +15684,7 @@ void maybe_process_friendly_hit(object *objp_hitter, object *objp_hit, object *o
|
||||
} else if (Missiontime - pp->last_warning_message_time > F1_0*4) {
|
||||
// warning every 4 sec
|
||||
// use NULL as the message sender here since it is the Terran Command persona
|
||||
message_send_builtin_to_player( MESSAGE_INSTRUCTOR_HIT, NULL, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, -1, -1);
|
||||
message_send_builtin(MESSAGE_INSTRUCTOR_HIT, nullptr, nullptr, -1, -1);
|
||||
pp->last_warning_message_time = Missiontime;
|
||||
}
|
||||
|
||||
@@ -15761,10 +15914,10 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
|
||||
// Added OBJ_BEAM for traitor detection - FUBAR
|
||||
if ((hit_objp->type == OBJ_WEAPON) || (hit_objp->type == OBJ_BEAM)) {
|
||||
if(hit_objp->parent < 0){
|
||||
if (hit_objp->parent < 0) {
|
||||
return;
|
||||
}
|
||||
if ( hit_objp->parent_sig != Objects[hit_objp->parent].signature ){
|
||||
if (hit_objp->parent_sig != Objects[hit_objp->parent].signature) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -15812,7 +15965,8 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
|
||||
maybe_process_friendly_hit(objp_hitter, objp_ship, hit_objp); // Deal with player's friendly fire.
|
||||
|
||||
ship_maybe_ask_for_help(shipp);
|
||||
ship* attacker = &Ships[objp_hitter->instance];
|
||||
ship_maybe_ask_for_help(shipp, attacker);
|
||||
} else if (hit_objp->type == OBJ_SHIP) {
|
||||
if (shipp->team == Ships[hit_objp->instance].team) // Don't have AI react to collisions between teammates.
|
||||
return;
|
||||
@@ -15934,22 +16088,19 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case AIM_FLY_TO_SHIP:
|
||||
case AIM_WAYPOINTS:
|
||||
if (sip->is_fighter_bomber())
|
||||
break;
|
||||
else
|
||||
return;
|
||||
break;
|
||||
return;
|
||||
case AIM_SAFETY:
|
||||
if ((aip->submode != AISS_1) || (Missiontime - aip->submode_start_time > i2f(1))) {
|
||||
aip->submode = AISS_1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
case AIM_WARP_OUT:
|
||||
return;
|
||||
break;
|
||||
case AIM_LUA:
|
||||
return;
|
||||
default:
|
||||
@@ -16465,8 +16616,6 @@ bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*
|
||||
}
|
||||
|
||||
mc_info hull_check;
|
||||
mc_info_init(&hull_check);
|
||||
|
||||
hull_check.model_instance_num = model_instance_num;
|
||||
hull_check.model_num = model_num;
|
||||
hull_check.orient = &objp->orient;
|
||||
|
||||
+92
-40
@@ -13,6 +13,7 @@
|
||||
#include "ai/aigoals.h"
|
||||
#include "ai/ailua.h"
|
||||
#include "globalincs/linklist.h"
|
||||
#include "globalincs/utility.h"
|
||||
#include "mission/missionlog.h"
|
||||
#include "mission/missionparse.h"
|
||||
#include "network/multi.h"
|
||||
@@ -904,7 +905,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
int ref_type;
|
||||
|
||||
ref_type = Sexp_nodes[CDR(node)].subtype;
|
||||
if (ref_type == SEXP_ATOM_STRING) { // referenced by name
|
||||
if (ref_type == SEXP_ATOM_STRING || ref_type == SEXP_ATOM_CONTAINER_DATA) { // referenced by name
|
||||
// save the waypoint path name -- the list will get resolved when the goal is checked
|
||||
// for achievability.
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
|
||||
@@ -975,7 +976,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
// this goal needs some extra setup
|
||||
// if this doesn't work, the goal will be immediately removed
|
||||
auto ship_entry = ship_registry_get(aigp->target_name);
|
||||
if (ship_entry->status == ShipStatus::PRESENT)
|
||||
if (ship_entry && ship_entry->shipp)
|
||||
{
|
||||
auto target_aip = &Ai_info[ship_entry->shipp->ai_index];
|
||||
target_aip->ai_flags.set(AI::AI_Flags::Awaiting_repair);
|
||||
@@ -1022,14 +1023,18 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
break;
|
||||
|
||||
case OP_AI_STAY_NEAR_SHIP:
|
||||
{
|
||||
bool is_nan, is_nan_forever;
|
||||
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->priority = atoi( CTEXT(CDDR(node)) );
|
||||
if ( CDDDR(node) < 0 )
|
||||
aigp->float_data = 300.0f;
|
||||
else
|
||||
aigp->float_data = i2fl(atoi( CTEXT(CDDDR(node)) ));
|
||||
aigp->float_data = i2fl(eval_num(CDDDR(node), is_nan, is_nan_forever));
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_AI_FORM_ON_WING:
|
||||
aigp->priority = 99;
|
||||
@@ -1117,14 +1122,41 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
|
||||
// Goober5000 - we now have an extra optional chase argument to allow chasing our own team
|
||||
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS || op == OP_AI_DISABLE_SHIP || op == OP_AI_DISARM_SHIP ) {
|
||||
if ((CDDDR(node) != -1) && is_sexp_true(CDDDR(node)))
|
||||
if (is_sexp_true(CDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Target_own_team);
|
||||
}
|
||||
if ( op == OP_AI_DESTROY_SUBSYS ) {
|
||||
if ((CDDDDR(node) != -1) && is_sexp_true(CDDDDR(node)))
|
||||
if (is_sexp_true(CDDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Target_own_team);
|
||||
}
|
||||
|
||||
// maybe get the afterburn hard flag
|
||||
if (op == OP_AI_CHASE_ANY) {
|
||||
if (is_sexp_true(CDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
if (op == OP_AI_GUARD ||
|
||||
op == OP_AI_GUARD_WING ||
|
||||
op == OP_AI_WAYPOINTS ||
|
||||
op == OP_AI_WAYPOINTS_ONCE ||
|
||||
op == OP_AI_FLY_TO_SHIP) {
|
||||
if (is_sexp_true(CDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
if (op == OP_AI_CHASE ||
|
||||
op == OP_AI_CHASE_WING ||
|
||||
op == OP_AI_CHASE_SHIP_CLASS ||
|
||||
op == OP_AI_DISABLE_SHIP ||
|
||||
op == OP_AI_DISARM_SHIP ||
|
||||
op == OP_AI_STAY_NEAR_SHIP) {
|
||||
if (is_sexp_true(CDDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
if (op == OP_AI_DESTROY_SUBSYS || op == OP_AI_DOCK) {
|
||||
if (is_sexp_true(CDDDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
|
||||
// Goober5000 - since none of the goals act on the actor,
|
||||
// don't assign the goal if the actor's goal target is itself
|
||||
if (aigp->target_name != NULL && !strcmp(aigp->target_name, actor_name))
|
||||
@@ -1721,7 +1753,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
|
||||
default:
|
||||
Int3();
|
||||
UNREACHABLE("Unhandled AI goal %d", aigp->ai_mode);
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
@@ -1765,7 +1797,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
status = SHIP_STATUS_UNKNOWN;
|
||||
}
|
||||
// goal ship is currently in mission
|
||||
else if (ship_entry->status == ShipStatus::PRESENT)
|
||||
else if (ship_entry->status == ShipStatus::PRESENT || ship_entry->status == ShipStatus::DEATH_ROLL)
|
||||
{
|
||||
status = SHIP_STATUS_ARRIVED;
|
||||
}
|
||||
@@ -1793,9 +1825,16 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// Goober5000 - before doing anything else, check if this is a disarm goal for an arrived ship...
|
||||
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP))
|
||||
{
|
||||
// if the ship has no turrets, we can't disarm it!
|
||||
if (Ships[ship_name_lookup(aigp->target_name)].subsys_info[SUBSYSTEM_TURRET].type_count == 0)
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
if ( sindex >= 0 ) {
|
||||
// if the ship has no turrets, we can't disarm it!
|
||||
if (Ships[sindex].subsys_info[SUBSYSTEM_TURRET].type_count == 0)
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
} else {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
}
|
||||
|
||||
// if the goal is an ignore/disable/disarm goal, then
|
||||
@@ -1836,7 +1875,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
|
||||
if ( (aigp->dockee.index == -1) || (aigp->docker.index == -1) ) {
|
||||
Int3(); // for now, allender wants to know about these things!!!!
|
||||
Warning(LOCATION, "Cannot determine docking information for %s!", Ships[objp->instance].ship_name); // for now, allender wants to know about these things!!!!
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
@@ -1846,7 +1885,10 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
// we must also determine if we're prevented from docking for any reason
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
Assert( sindex >= 0 );
|
||||
if (sindex < 0) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
object *goal_objp = &Objects[Ships[sindex].objnum];
|
||||
|
||||
// if the ship that I am supposed to dock with is docked with something else, then I need to put my goal on hold
|
||||
@@ -1896,9 +1938,16 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// might happen too, so err on the safe side. (Yay for emergent paragraph justification!)
|
||||
if ((aip->mode == AIM_DOCK) && (aip->submode >= AIS_UNDOCK_0))
|
||||
{
|
||||
// only put it on hold if it's someone other than the guy we're undocking from right now!!
|
||||
if (aip->goal_objnum != Ships[ship_name_lookup(aigp->target_name)].objnum)
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
if ( sindex >= 0 ) {
|
||||
// only put it on hold if it's someone other than the guy we're undocking from right now!!
|
||||
if (aip->goal_objnum != Ships[sindex].objnum)
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
} else {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
}
|
||||
|
||||
} else if ( (aigp->ai_mode == AI_GOAL_DESTROY_SUBSYSTEM) && (status == SHIP_STATUS_ARRIVED) ) {
|
||||
@@ -1912,7 +1961,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
aigp->ai_submode = ship_find_subsys( &Ships[sindex], aigp->docker.name );
|
||||
aigp->flags.remove(AI::Goal_Flags::Subsys_needs_fixup);
|
||||
} else {
|
||||
Int3();
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
}
|
||||
@@ -1921,7 +1970,10 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
// for ignoring a ship, call the ai_ignore object function, then declare the goal satisfied
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
Assert( sindex != -1 ); // should be true because of above status
|
||||
if (sindex < 0) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
ignored = &Objects[Ships[sindex].objnum];
|
||||
|
||||
ai_ignore_object(objp, ignored, (aigp->ai_mode == AI_GOAL_IGNORE_NEW));
|
||||
@@ -1955,7 +2007,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
else if ( status == SHIP_STATUS_UNKNOWN )
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
Int3(); // get allender -- bad logic
|
||||
UNREACHABLE("Invalid status variable %d for ship %s; get Allender or a SCP member", status, Ships[objp->instance].ship_name); // get allender -- bad logic
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1967,7 +2019,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// short circuit a couple of cases. Ship not arrived shouldn't happen. Ship gone means
|
||||
// we mark the goal as not achievable.
|
||||
if ( status == SHIP_STATUS_NOT_ARRIVED ) {
|
||||
Int3(); // get Allender. this shouldn't happen!!!
|
||||
UNREACHABLE("Ship %s cannot rearm a target %s that hasn't arrived; get Allender or a SCP member", Ships[objp->instance].ship_name, aigp->target_name); // get Allender. this shouldn't happen!!!
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
@@ -1975,9 +2027,8 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
if ( sindex < 0 ) {
|
||||
Int3();
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
@@ -2013,7 +2064,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
|
||||
default:
|
||||
Int3(); // invalid case in switch:
|
||||
UNREACHABLE("Unhandled AI goal %d", aigp->ai_mode); // invalid case in switch:
|
||||
}
|
||||
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
@@ -2124,11 +2175,11 @@ void validate_mission_goals(int objnum, ai_info *aip)
|
||||
if ( (aip->goals[0].ai_mode != AI_GOAL_NONE) && (aip->goals[0].flags[AI::Goal_Flags::Goal_on_hold]) )
|
||||
aip->mode = AIM_NONE;
|
||||
|
||||
// if the active goal is a rearm/repair goal, the put all other valid goals (which are not repair goals)
|
||||
// on hold
|
||||
if ( (aip->goals[0].ai_mode == AI_GOAL_REARM_REPAIR) && object_is_docked(&Objects[objnum]) ) {
|
||||
// if the active goal is a rearm/repair or undock goal,
|
||||
// then put all other valid goals (which are not rearm/repair or undock goals) on hold
|
||||
if ( (aip->goals[0].ai_mode == AI_GOAL_REARM_REPAIR || aip->goals[0].ai_mode == AI_GOAL_UNDOCK) && object_is_docked(&Objects[objnum]) ) {
|
||||
for ( i = 1; i < MAX_AI_GOALS; i++ ) {
|
||||
if ( (aip->goals[i].ai_mode == AI_GOAL_NONE) || (aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR) )
|
||||
if ( aip->goals[i].ai_mode == AI_GOAL_NONE || aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR || aip->goals[i].ai_mode == AI_GOAL_UNDOCK )
|
||||
continue;
|
||||
aip->goals[i].flags.set(AI::Goal_Flags::Goal_on_hold);
|
||||
}
|
||||
@@ -2496,7 +2547,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
ai_formation_object_recalculate_slotnums(old_form_objnum);
|
||||
}
|
||||
|
||||
void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, const char *new_name)
|
||||
void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *old_name, const char *new_name)
|
||||
{
|
||||
int i, mode, flag, dummy;
|
||||
|
||||
@@ -2506,8 +2557,8 @@ void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, c
|
||||
flag = 0;
|
||||
switch (type)
|
||||
{
|
||||
case REF_TYPE_SHIP:
|
||||
case REF_TYPE_PLAYER:
|
||||
case sexp_ref_type::SHIP:
|
||||
case sexp_ref_type::PLAYER:
|
||||
switch (mode)
|
||||
{
|
||||
case AI_GOAL_CHASE:
|
||||
@@ -2524,7 +2575,7 @@ void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, c
|
||||
}
|
||||
break;
|
||||
|
||||
case REF_TYPE_WING:
|
||||
case sexp_ref_type::WING:
|
||||
switch (mode)
|
||||
{
|
||||
case AI_GOAL_CHASE_WING:
|
||||
@@ -2533,7 +2584,7 @@ void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, c
|
||||
}
|
||||
break;
|
||||
|
||||
case REF_TYPE_WAYPOINT:
|
||||
case sexp_ref_type::WAYPOINT:
|
||||
switch (mode)
|
||||
{
|
||||
case AI_GOAL_WAYPOINTS:
|
||||
@@ -2542,7 +2593,7 @@ void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, c
|
||||
}
|
||||
break;
|
||||
|
||||
case REF_TYPE_PATH:
|
||||
case sexp_ref_type::WAYPOINT_PATH:
|
||||
switch (mode)
|
||||
{
|
||||
case AI_GOAL_WAYPOINTS:
|
||||
@@ -2553,7 +2604,7 @@ void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, c
|
||||
break;
|
||||
|
||||
default:
|
||||
Warning(LOCATION, "unhandled FRED reference type %d in ai_update_goal_references", type);
|
||||
Warning(LOCATION, "unhandled FRED reference type %d in ai_update_goal_references", static_cast<int>(type));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2570,7 +2621,7 @@ void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, c
|
||||
}
|
||||
}
|
||||
|
||||
int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name)
|
||||
bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char *name)
|
||||
{
|
||||
int i, mode, flag;
|
||||
|
||||
@@ -2580,7 +2631,8 @@ int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name)
|
||||
flag = 0;
|
||||
switch (type)
|
||||
{
|
||||
case REF_TYPE_SHIP:
|
||||
case sexp_ref_type::SHIP:
|
||||
case sexp_ref_type::PLAYER:
|
||||
switch (mode)
|
||||
{
|
||||
case AI_GOAL_CHASE:
|
||||
@@ -2597,7 +2649,7 @@ int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name)
|
||||
}
|
||||
break;
|
||||
|
||||
case REF_TYPE_WING:
|
||||
case sexp_ref_type::WING:
|
||||
switch (mode)
|
||||
{
|
||||
case AI_GOAL_CHASE_WING:
|
||||
@@ -2606,7 +2658,7 @@ int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name)
|
||||
}
|
||||
break;
|
||||
|
||||
case REF_TYPE_WAYPOINT:
|
||||
case sexp_ref_type::WAYPOINT:
|
||||
switch (mode)
|
||||
{
|
||||
case AI_GOAL_WAYPOINTS:
|
||||
@@ -2615,7 +2667,7 @@ int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name)
|
||||
}
|
||||
break;
|
||||
|
||||
case REF_TYPE_PATH:
|
||||
case sexp_ref_type::WAYPOINT_PATH:
|
||||
switch (mode)
|
||||
{
|
||||
case AI_GOAL_WAYPOINTS:
|
||||
@@ -2628,11 +2680,11 @@ int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name)
|
||||
if (flag) // is this a valid goal to parse for this conversion?
|
||||
{
|
||||
if (!stricmp(goals[i].target_name, name))
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
char *ai_add_dock_name(const char *str)
|
||||
|
||||
+2
-2
@@ -187,8 +187,8 @@ extern void ai_copy_mission_wing_goal( ai_goal *aigp, ai_info *aip );
|
||||
extern void ai_mission_goal_complete( ai_info *aip );
|
||||
extern void ai_mission_wing_goal_complete( int wingnum, ai_goal *remove_goalp );
|
||||
|
||||
extern void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, const char *new_name);
|
||||
extern int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name);
|
||||
extern void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *old_name, const char *new_name);
|
||||
extern bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char *name);
|
||||
extern char *ai_add_dock_name(const char *str);
|
||||
|
||||
extern int ai_query_goal_valid( int ship, int ai_goal_type );
|
||||
|
||||
@@ -186,6 +186,24 @@ bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t o
|
||||
return ai_lua_is_valid_target_lua(mode, target_objnum, self);
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_ship(int sexp_op, bool isWing, ship* self)
|
||||
{
|
||||
const player_order_lua& order = *ai_lua_find_player_order(sexp_op);
|
||||
|
||||
switch (order.shipRestrictions) {
|
||||
case player_order_lua::ship_restrictions::ANY:
|
||||
return true;
|
||||
case player_order_lua::ship_restrictions::WING:
|
||||
return isWing;
|
||||
case player_order_lua::ship_restrictions::IN_PLAYER_WING:
|
||||
return self->wingnum != -1 && Ships[Player_obj->instance].wingnum == self->wingnum;
|
||||
case player_order_lua::ship_restrictions::PLAYER_WING:
|
||||
return isWing && self->wingnum != -1 && Ships[Player_obj->instance].wingnum == self->wingnum;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum){
|
||||
const auto& lua_ai = Lua_ai_modes.at(aigp->ai_submode);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ struct player_order_lua {
|
||||
SCP_string parseText = "";
|
||||
SCP_string displayText = "";
|
||||
enum class target_restrictions : int { TARGET_ALLIES, TARGET_ALL, TARGET_OWN, TARGET_ENEMIES, TARGET_SAME_WING, TARGET_PLAYER_WING, TARGET_ALL_CAPS, TARGET_ALLIED_CAPS, TARGET_ENEMY_CAPS, TARGET_NOT_SELF } targetRestrictions = target_restrictions::TARGET_ALL;
|
||||
enum class ship_restrictions : int { ANY, WING, IN_PLAYER_WING, PLAYER_WING } shipRestrictions = ship_restrictions::ANY;
|
||||
};
|
||||
|
||||
|
||||
@@ -31,4 +32,5 @@ const player_order_lua* ai_lua_find_player_order(int sexp_op);
|
||||
void ai_lua(ai_info* aip);
|
||||
void ai_lua_start(ai_goal* aigp, object* objp);
|
||||
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order);
|
||||
bool ai_lua_is_valid_ship(int sexp_op, bool isWing, ship* self);
|
||||
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum);
|
||||
+24
-5
@@ -58,11 +58,19 @@ const char *Turret_target_order_names[NUM_TURRET_ORDER_TYPES] = {
|
||||
#define EEOF_BIG_ONLY (1<<0) // turret fires only at big and huge ships
|
||||
#define EEOF_SMALL_ONLY (1<<1) // turret fires only at small ships
|
||||
#define EEOF_TAGGED_ONLY (1<<2) // turret fires only at tagged ships
|
||||
|
||||
#define EEOF_BEAM (1<<3) // turret is a beam
|
||||
#define EEOF_FLAK (1<<4) // turret is flak
|
||||
#define EEOF_LASER (1<<5) // turret is a laser
|
||||
#define EEOF_MISSILE (1<<6) // turret is a missile
|
||||
|
||||
const char* Turret_valid_types[NUM_TURRET_TYPES] = {
|
||||
"Beam",
|
||||
"Flak",
|
||||
"Laser",
|
||||
"Missile",
|
||||
};
|
||||
|
||||
typedef struct eval_enemy_obj_struct {
|
||||
int turret_parent_objnum; // parent of turret
|
||||
float weapon_travel_dist; // max targeting range of turret weapon
|
||||
@@ -1763,7 +1771,7 @@ void turret_update_enemy_in_range(ship_subsys *turret, float seconds)
|
||||
/**
|
||||
* Fire a weapon from a turret
|
||||
*/
|
||||
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, vec3d *turret_pos, vec3d *firing_vec, vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f)
|
||||
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, vec3d *turret_pos, vec3d *firing_vec, vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f, bool play_sound = true)
|
||||
{
|
||||
matrix turret_orient;
|
||||
int weapon_objnum;
|
||||
@@ -1887,6 +1895,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
|
||||
parent_ship->last_fired_turret = turret;
|
||||
turret->last_fired_weapon_info_index = turret_weapon_class;
|
||||
turret->turret_last_fired = _timestamp();
|
||||
|
||||
if (scripting::hooks::OnTurretFired->isActive()) {
|
||||
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, SCP_vector<int>{ turret_weapon_class }, true },
|
||||
@@ -2029,6 +2038,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
|
||||
parent_ship->last_fired_turret = turret;
|
||||
turret->last_fired_weapon_info_index = wp->weapon_info_index;
|
||||
turret->turret_last_fired = _timestamp();
|
||||
|
||||
wp->target_num = turret->turret_enemy_objnum;
|
||||
// AL 1-6-97: Store pointer to turret subsystem
|
||||
@@ -2078,7 +2088,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
}
|
||||
}
|
||||
|
||||
if ( wip->launch_snd.isValid() ) {
|
||||
if ( play_sound && wip->launch_snd.isValid() ) {
|
||||
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
|
||||
if ( parent_objnum != OBJ_INDEX(Player_obj) || (turret->flags[Ship::Subsystem_Flags::Play_sound_for_player]) ) {
|
||||
snd_play_3d( gamesnd_get_game_sound(wip->launch_snd), turret_pos, &View_position );
|
||||
@@ -2155,6 +2165,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
|
||||
Ships[Objects[tsi->parent_objnum].instance].last_fired_turret = tsi->turret;
|
||||
tsi->turret->last_fired_weapon_info_index = tsi->weapon_class;
|
||||
tsi->turret->turret_last_fired = _timestamp();
|
||||
|
||||
if (scripting::hooks::OnTurretFired->isActive()) {
|
||||
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{
|
||||
@@ -2617,6 +2628,8 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
number_of_firings = num_valid;
|
||||
}
|
||||
|
||||
auto sound_played = gamesnd_id();
|
||||
|
||||
for (int i = 0; i < number_of_firings; ++i)
|
||||
{
|
||||
int valid_index;
|
||||
@@ -2626,6 +2639,13 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
valid_index = i;
|
||||
auto wip = get_turret_weapon_wip(&ss->weapons, valid_weapons[valid_index]);
|
||||
|
||||
bool play_sound = false;
|
||||
|
||||
if (sound_played != wip->launch_snd) {
|
||||
sound_played = wip->launch_snd;
|
||||
play_sound = true;
|
||||
}
|
||||
|
||||
// Forces the firing turret to retain the firingpoints of their weapons:
|
||||
// if the turret has multiple banks, the first bank will only fire from the first firepoint,
|
||||
// the second bank only from the second firepoint, and so on.
|
||||
@@ -2728,7 +2748,6 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
vm_vec_scale_add(&end, &gpos, &gvec, model_get_radius(model_num));
|
||||
|
||||
mc_info hull_check;
|
||||
mc_info_init(&hull_check);
|
||||
hull_check.model_instance_num = shipp->model_instance_num;
|
||||
hull_check.model_num = model_num;
|
||||
hull_check.orient = &objp->orient;
|
||||
@@ -2781,7 +2800,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
flak_jitter_aim(&shoot_vector, dist_to_enemy, ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS), wip);
|
||||
}
|
||||
|
||||
turret_fire_weapon(valid_weapons[valid_index], ss, parent_objnum, &gpos, &shoot_vector, &predicted_enemy_pos);
|
||||
turret_fire_weapon(valid_weapons[valid_index], ss, parent_objnum, &gpos, &shoot_vector, &predicted_enemy_pos, 100.0f, play_sound);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2889,7 +2908,7 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
|
||||
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
|
||||
{
|
||||
bool in_fov = false;
|
||||
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_base_restricted_fov])
|
||||
if (ss->system_info->turret_base_fov > -1.0f)
|
||||
in_fov = turret_adv_fov_test(ss, gvec, v2e, size_mod);
|
||||
else
|
||||
in_fov = turret_std_fov_test(ss, gvec, v2e, size_mod);
|
||||
|
||||
+166
-94
@@ -265,7 +265,7 @@ static void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
|
||||
/**
|
||||
* Create a single asteroid
|
||||
*/
|
||||
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype)
|
||||
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype, bool check_visibility)
|
||||
{
|
||||
int n, objnum;
|
||||
matrix orient;
|
||||
@@ -356,6 +356,13 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
angs.h = static_randf( rand_base++ ) * PI2;
|
||||
}
|
||||
|
||||
// If the generated asteroid position is within the player view then abort
|
||||
// I'm unsure how Eyepoint is handled for multiplayer, so this may need to move up into the SP
|
||||
// only section - Mjn
|
||||
if (check_visibility && asteroid_is_within_view(&pos, -1.0f, true)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vm_angles_2_matrix(&orient, &angs);
|
||||
flagset<Object::Object_Flags> asteroid_default_flagset;
|
||||
asteroid_default_flagset += Object::Object_Flags::Renders;
|
||||
@@ -437,6 +444,12 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
// ensure vel is valid
|
||||
Assert( !vm_is_vec_nan(&objp->phys_info.vel) );
|
||||
|
||||
if (scripting::hooks::OnAsteroidCreated->isActive()) {
|
||||
scripting::hooks::OnAsteroidCreated->run(
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Asteroid", 'o', objp)));
|
||||
}
|
||||
|
||||
return objp;
|
||||
}
|
||||
|
||||
@@ -691,11 +704,29 @@ void asteroid_create_asteroid_field(int num_asteroids, int field_type, int aster
|
||||
|
||||
Asteroid_field.num_initial_asteroids = num_asteroids;
|
||||
|
||||
if (field_type == 0) {
|
||||
Asteroid_field.field_type = FT_PASSIVE;
|
||||
} else {
|
||||
Asteroid_field.field_type = FT_ACTIVE;
|
||||
switch (field_type) {
|
||||
case 0:
|
||||
Asteroid_field.field_type = FT_PASSIVE;
|
||||
Asteroid_field.enhanced_visibility_checks = false;
|
||||
break;
|
||||
case 1:
|
||||
Asteroid_field.field_type = FT_ACTIVE;
|
||||
Asteroid_field.enhanced_visibility_checks = false;
|
||||
break;
|
||||
case 2:
|
||||
Asteroid_field.field_type = FT_PASSIVE;
|
||||
Asteroid_field.enhanced_visibility_checks = true;
|
||||
break;
|
||||
case 3:
|
||||
Asteroid_field.field_type = FT_ACTIVE;
|
||||
Asteroid_field.enhanced_visibility_checks = true;
|
||||
break;
|
||||
default: //Any other number will just give default behavior
|
||||
Asteroid_field.field_type = FT_PASSIVE;
|
||||
Asteroid_field.enhanced_visibility_checks = false;
|
||||
break;
|
||||
}
|
||||
|
||||
vm_vec_rand_vec_quick(&Asteroid_field.vel);
|
||||
vm_vec_scale(&Asteroid_field.vel, (float)asteroid_speed);
|
||||
Asteroid_field.speed = (float)asteroid_speed;
|
||||
@@ -746,7 +777,7 @@ void asteroid_create_asteroid_field(int num_asteroids, int field_type, int aster
|
||||
}
|
||||
|
||||
// will replace any existing asteroid or debris field with a debris field
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max)
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max, bool enhanced)
|
||||
{
|
||||
remove_all_asteroids();
|
||||
|
||||
@@ -754,6 +785,8 @@ void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int deb
|
||||
|
||||
Asteroid_field.field_type = FT_PASSIVE;
|
||||
|
||||
Asteroid_field.enhanced_visibility_checks = enhanced;
|
||||
|
||||
vm_vec_rand_vec_quick(&Asteroid_field.vel);
|
||||
vm_vec_scale(&Asteroid_field.vel, (float)asteroid_speed);
|
||||
Asteroid_field.speed = (float)asteroid_speed;
|
||||
@@ -883,37 +916,37 @@ static int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an asteroid from one end of the asteroid field to the other
|
||||
* Generates a potential new position for an asteroid that might wrap
|
||||
* from one end of the asteroid field to the other
|
||||
*/
|
||||
static void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
|
||||
static void asteroid_wrap_pos(vec3d *pos, asteroid_field *asfieldp)
|
||||
{
|
||||
if (objp->pos.xyz.x < asfieldp->min_bound.xyz.x) {
|
||||
objp->pos.xyz.x = asfieldp->max_bound.xyz.x + (objp->pos.xyz.x - asfieldp->min_bound.xyz.x);
|
||||
if (pos->xyz.x < asfieldp->min_bound.xyz.x) {
|
||||
pos->xyz.x = asfieldp->max_bound.xyz.x + (pos->xyz.x - asfieldp->min_bound.xyz.x);
|
||||
}
|
||||
|
||||
if (objp->pos.xyz.y < asfieldp->min_bound.xyz.y) {
|
||||
objp->pos.xyz.y = asfieldp->max_bound.xyz.y + (objp->pos.xyz.y - asfieldp->min_bound.xyz.y);
|
||||
}
|
||||
|
||||
if (objp->pos.xyz.z < asfieldp->min_bound.xyz.z) {
|
||||
objp->pos.xyz.z = asfieldp->max_bound.xyz.z + (objp->pos.xyz.z - asfieldp->min_bound.xyz.z);
|
||||
if (pos->xyz.y < asfieldp->min_bound.xyz.y) {
|
||||
pos->xyz.y = asfieldp->max_bound.xyz.y + (pos->xyz.y - asfieldp->min_bound.xyz.y);
|
||||
}
|
||||
|
||||
if (objp->pos.xyz.x > asfieldp->max_bound.xyz.x) {
|
||||
objp->pos.xyz.x = asfieldp->min_bound.xyz.x + (objp->pos.xyz.x - asfieldp->max_bound.xyz.x);
|
||||
if (pos->xyz.z < asfieldp->min_bound.xyz.z) {
|
||||
pos->xyz.z = asfieldp->max_bound.xyz.z + (pos->xyz.z - asfieldp->min_bound.xyz.z);
|
||||
}
|
||||
|
||||
if (objp->pos.xyz.y > asfieldp->max_bound.xyz.y) {
|
||||
objp->pos.xyz.y = asfieldp->min_bound.xyz.y + (objp->pos.xyz.y - asfieldp->max_bound.xyz.y);
|
||||
if (pos->xyz.x > asfieldp->max_bound.xyz.x) {
|
||||
pos->xyz.x = asfieldp->min_bound.xyz.x + (pos->xyz.x - asfieldp->max_bound.xyz.x);
|
||||
}
|
||||
|
||||
if (objp->pos.xyz.z > asfieldp->max_bound.xyz.z) {
|
||||
objp->pos.xyz.z = asfieldp->min_bound.xyz.z + (objp->pos.xyz.z - asfieldp->max_bound.xyz.z);
|
||||
if (pos->xyz.y > asfieldp->max_bound.xyz.y) {
|
||||
pos->xyz.y = asfieldp->min_bound.xyz.y + (pos->xyz.y - asfieldp->max_bound.xyz.y);
|
||||
}
|
||||
|
||||
if (pos->xyz.z > asfieldp->max_bound.xyz.z) {
|
||||
pos->xyz.z = asfieldp->min_bound.xyz.z + (pos->xyz.z - asfieldp->max_bound.xyz.z);
|
||||
}
|
||||
|
||||
// wrap on inner bound, check all 3 axes as needed, use of rand ok for multiplayer with send_asteroid_throw()
|
||||
inner_bound_pos_fixup(asfieldp, &objp->pos);
|
||||
|
||||
inner_bound_pos_fixup(asfieldp, pos);
|
||||
}
|
||||
|
||||
|
||||
@@ -960,7 +993,8 @@ static void asteroid_aim_at_target(object *objp, object *asteroid_objp, float de
|
||||
vm_vec_add2(&rand_vec, &objp->orient.vec.rvec);
|
||||
vm_vec_normalize(&rand_vec);
|
||||
|
||||
speed = Asteroid_info[0].max_speed * (frand()/2.0f + 0.5f);
|
||||
auto asp = &Asteroids[asteroid_objp->instance];
|
||||
speed = Asteroid_info[asp->asteroid_type].max_speed * (frand()/2.0f + 0.5f);
|
||||
|
||||
vm_vec_copy_scale(&asteroid_objp->phys_info.vel, &rand_vec, -speed);
|
||||
asteroid_objp->phys_info.desired_vel = asteroid_objp->phys_info.vel;
|
||||
@@ -983,6 +1017,32 @@ static void sanitize_asteroid_targets_list() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an asteroid will be within the player's view
|
||||
*
|
||||
**/
|
||||
bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
|
||||
{
|
||||
vec3d vec_to_asteroid;
|
||||
|
||||
// Distance and view cone for the position in relation to the player
|
||||
float dist = vm_vec_normalized_dir(&vec_to_asteroid, pos, &Eye_position);
|
||||
float dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
|
||||
|
||||
// if asteroid is within view or far enough away then wrap
|
||||
if (dot > cos(Proj_fov)) {
|
||||
if (range_override) {
|
||||
return true;
|
||||
} else {
|
||||
if (dist < range) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call once per frame to maybe throw some asteroids at one or more ships.
|
||||
*
|
||||
@@ -1023,7 +1083,7 @@ static void maybe_throw_asteroid()
|
||||
if (subtype < 0)
|
||||
return;
|
||||
|
||||
object *objp = asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
|
||||
object *objp = asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype, Asteroid_field.enhanced_visibility_checks);
|
||||
if (objp != nullptr) {
|
||||
asteroid_aim_at_target(target_objp, objp, ASTEROID_MIN_COLLIDE_TIME + frand() * 20.0f);
|
||||
|
||||
@@ -1074,7 +1134,7 @@ void asteroid_delete( object * obj )
|
||||
}
|
||||
|
||||
/**
|
||||
* See if we should reposition the asteroid.
|
||||
* See if we should reposition the asteroid.
|
||||
* Only reposition if oustide the bounding volume and the player isn't looking towards the asteroid.
|
||||
*/
|
||||
static void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
|
||||
@@ -1084,61 +1144,74 @@ static void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
|
||||
return;
|
||||
}
|
||||
|
||||
if ( asteroid_should_wrap(objp, asfieldp) ) {
|
||||
vec3d vec_to_asteroid, old_asteroid_pos, old_vel;
|
||||
float dot, dist;
|
||||
if (asteroid_should_wrap(objp, asfieldp)) {
|
||||
|
||||
old_asteroid_pos = objp->pos;
|
||||
old_vel = objp->phys_info.vel;
|
||||
// Generate a possible new position if we do end up wrapping, but don't move the asteroid yet
|
||||
vec3d new_pos = objp->pos;
|
||||
asteroid_wrap_pos(&new_pos, asfieldp);
|
||||
|
||||
// don't wrap asteroid if it is a target of some ship
|
||||
if ( !asteroid_is_targeted(objp) ) {
|
||||
bool wrap = false;
|
||||
bool reverse = false;
|
||||
|
||||
// only wrap if player won't see asteroid disappear/reverse direction
|
||||
dist = vm_vec_normalized_dir(&vec_to_asteroid, &objp->pos, &Eye_position);
|
||||
dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
|
||||
|
||||
if ( (dot < 0.7f) || (dist > asfieldp->bound_rad) ) {
|
||||
if (Num_asteroids > MAX_ASTEROIDS-10) {
|
||||
objp->flags.set(Object::Object_Flags::Should_be_dead);
|
||||
} else {
|
||||
// check to ensure player won't see asteroid appear either
|
||||
asteroid_wrap_pos(objp, asfieldp);
|
||||
asteroid* astp = &Asteroids[objp->instance];
|
||||
// If asteroid is targeted then we cannot wrap because they player would see it and say "SHENANIGANS!"
|
||||
// So we bail
|
||||
if (asteroid_is_targeted(objp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (asfieldp->field_type == FT_ACTIVE) {
|
||||
// this doesnt count as a thrown asteroid anymore
|
||||
for (asteroid_target& target : Asteroid_targets)
|
||||
if (target.objnum == astp->target_objnum)
|
||||
target.incoming_asteroids--;
|
||||
// if asteroid is not within view...
|
||||
if (!asteroid_is_within_view(&objp->pos, asfieldp->bound_rad, asfieldp->enhanced_visibility_checks)) {
|
||||
|
||||
astp->target_objnum = -1;
|
||||
}
|
||||
// if asteroid new position is within view then reverse velocity, otherwise wrap
|
||||
if (asteroid_is_within_view(&new_pos, (asfieldp->bound_rad * 1.3f), asfieldp->enhanced_visibility_checks)) {
|
||||
|
||||
dist = vm_vec_normalized_dir(&vec_to_asteroid, &objp->pos, &Eye_position);
|
||||
dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
|
||||
|
||||
//probably don't reverse direction if there's gravity involved
|
||||
if (IS_VEC_NULL(&The_mission.gravity)) {
|
||||
if ((dot > 0.7f) && (dist < (asfieldp->bound_rad * 1.3f))) {
|
||||
// player would see asteroid pop out other side, so reverse velocity instead of wrapping
|
||||
objp->pos = old_asteroid_pos;
|
||||
vm_vec_copy_scale(&objp->phys_info.vel, &old_vel, -1.0f);
|
||||
objp->phys_info.desired_vel = objp->phys_info.vel;
|
||||
Asteroids[objp->instance].target_objnum = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// update last pos (after vel is known)
|
||||
vm_vec_scale_add(&objp->last_pos, &objp->pos, &objp->phys_info.vel, -flFrametime);
|
||||
|
||||
asteroid_update_collide(objp);
|
||||
|
||||
if (asfieldp->field_type == FT_ACTIVE) {
|
||||
if (MULTIPLAYER_MASTER)
|
||||
send_asteroid_throw(objp);
|
||||
}
|
||||
// if the mission has gravity, then we can't reverse. So make sure gravity is null
|
||||
if (IS_VEC_NULL(&The_mission.gravity)) {
|
||||
reverse = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
wrap = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// we can wrap, but we have too many asteroids, so destroy this one instead
|
||||
if (wrap && (Num_asteroids > MAX_ASTEROIDS - 10)) {
|
||||
objp->flags.set(Object::Object_Flags::Should_be_dead);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reverse instead of wrap!
|
||||
if (reverse) {
|
||||
vm_vec_copy_scale(&objp->phys_info.vel, &objp->phys_info.vel, -1.0f);
|
||||
objp->phys_info.desired_vel = objp->phys_info.vel;
|
||||
Asteroids[objp->instance].target_objnum = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// We can wrap, so wrap!
|
||||
if (wrap) {
|
||||
objp->pos = new_pos;
|
||||
asteroid *astp = &Asteroids[objp->instance];
|
||||
|
||||
if (asfieldp->field_type == FT_ACTIVE) {
|
||||
// this doesnt count as a thrown asteroid anymore
|
||||
for (asteroid_target &target : Asteroid_targets)
|
||||
if (target.objnum == astp->target_objnum)
|
||||
target.incoming_asteroids--;
|
||||
|
||||
astp->target_objnum = -1;
|
||||
}
|
||||
|
||||
// update last pos (after vel is known)
|
||||
vm_vec_scale_add(&objp->last_pos, &objp->pos, &objp->phys_info.vel, -flFrametime);
|
||||
|
||||
asteroid_update_collide(objp);
|
||||
|
||||
if (asfieldp->field_type == FT_ACTIVE) {
|
||||
if (MULTIPLAYER_MASTER)
|
||||
send_asteroid_throw(objp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1166,7 +1239,6 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
}
|
||||
|
||||
mc_info mc;
|
||||
mc_info_init(&mc);
|
||||
int num, asteroid_subtype;
|
||||
|
||||
Assert( pasteroid->type == OBJ_ASTEROID );
|
||||
@@ -1601,7 +1673,7 @@ static void asteroid_do_area_effect(object *asteroid_objp)
|
||||
continue;
|
||||
|
||||
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage, asip->damage_type_idx);
|
||||
weapon_area_apply_blast(NULL, ship_objp, &asteroid_objp->pos, blast, 0);
|
||||
weapon_area_apply_blast(nullptr, ship_objp, &asteroid_objp->pos, blast, false);
|
||||
} // end for
|
||||
}
|
||||
|
||||
@@ -1613,7 +1685,7 @@ static void asteroid_do_area_effect(object *asteroid_objp)
|
||||
* @param hitpos world position asteroid was hit, can be NULL if hit by area effect
|
||||
* @param damage amount of damage to apply to asteroid
|
||||
*/
|
||||
void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, float damage )
|
||||
void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, float damage, vec3d* force )
|
||||
{
|
||||
float explosion_life;
|
||||
asteroid *asp;
|
||||
@@ -1625,7 +1697,13 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
|
||||
}
|
||||
|
||||
if ( MULTIPLAYER_MASTER ){
|
||||
send_asteroid_hit( pasteroid_obj, other_obj, hitpos, damage );
|
||||
send_asteroid_hit( pasteroid_obj, other_obj, hitpos, damage, force );
|
||||
}
|
||||
|
||||
if (hitpos && force && The_mission.ai_profile->flags[AI::Profile_Flags::Whackable_asteroids]) {
|
||||
vec3d rel_hit_pos = *hitpos - pasteroid_obj->pos;
|
||||
physics_calculate_and_apply_whack(force, &rel_hit_pos, &pasteroid_obj->phys_info, &pasteroid_obj->orient, &pasteroid_obj->phys_info.I_body_inv);
|
||||
pasteroid_obj->phys_info.desired_vel = pasteroid_obj->phys_info.vel;
|
||||
}
|
||||
|
||||
pasteroid_obj->hull_strength -= damage;
|
||||
@@ -1885,7 +1963,6 @@ static void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_i
|
||||
static int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
|
||||
{
|
||||
mc_info mc;
|
||||
mc_info_init(&mc);
|
||||
|
||||
asteroid_test_collide(pasteroid_obj, escort_objp, &mc);
|
||||
|
||||
@@ -2015,7 +2092,6 @@ float asteroid_time_to_impact(object *asteroid_objp)
|
||||
float time=-1.0f, total_dist, speed;
|
||||
asteroid *asp;
|
||||
mc_info mc;
|
||||
mc_info_init(&mc);
|
||||
|
||||
asp = &Asteroids[asteroid_objp->instance];
|
||||
|
||||
@@ -2037,17 +2113,6 @@ float asteroid_time_to_impact(object *asteroid_objp)
|
||||
return time;
|
||||
}
|
||||
|
||||
int get_asteroid_position(const char* name)
|
||||
{
|
||||
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
|
||||
if (!stricmp(name, Asteroid_info[i].name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static SCP_string setup_display_name(SCP_string name)
|
||||
{
|
||||
|
||||
@@ -2118,7 +2183,7 @@ static void asteroid_parse_section()
|
||||
asteroid_t.name);
|
||||
}
|
||||
} else {
|
||||
// Don't create poof if it has +nocreate and is in a modular table.
|
||||
// Don't create asteroid if it has +nocreate and is in a modular table.
|
||||
if (!create_if_not_found && Parsing_modular_table) {
|
||||
if (!skip_to_start_of_string_either("$Name:", "#end")) {
|
||||
error_display(1, "Missing [#end] or [$Name] after asteroid %s", asteroid_t.name);
|
||||
@@ -2349,7 +2414,7 @@ static void asteroid_parse_tbl(const char* filename)
|
||||
}
|
||||
|
||||
// Gets the index of an asteroid by name from Asteroid_info
|
||||
static int get_asteroid_index(const char* asteroid_name)
|
||||
int get_asteroid_index(const char* asteroid_name)
|
||||
{
|
||||
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
|
||||
if (!stricmp(asteroid_name, Asteroid_info[i].name)) {
|
||||
@@ -2461,6 +2526,10 @@ void asteroid_init()
|
||||
// parse any modular tables
|
||||
parse_modular_table("*-ast.tbm", asteroid_parse_tbl);
|
||||
|
||||
//No asteroids defined. Bail!
|
||||
if (asteroid_list.empty())
|
||||
return;
|
||||
|
||||
// now verify the asteroids were found and put them in the correct order
|
||||
verify_asteroid_list();
|
||||
|
||||
@@ -2616,6 +2685,9 @@ void asteroid_target_closest_danger()
|
||||
|
||||
void asteroid_page_in()
|
||||
{
|
||||
if (Asteroid_info.empty())
|
||||
return;
|
||||
|
||||
if (Asteroid_field.num_initial_asteroids > 0 ) {
|
||||
int i, j, k;
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ typedef struct asteroid_field {
|
||||
debris_genre_t debris_genre; // type of debris (ship or asteroid) [generic type]
|
||||
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]; // one of the debris type defines above
|
||||
int num_used_field_debris_types; // how many of the above are used
|
||||
bool enhanced_visibility_checks; // if true then range checks are overridden for spawning and wrapping asteroids in the field
|
||||
|
||||
SCP_vector<SCP_string> target_names; // default retail behavior is to just throw at the first big ship in the field
|
||||
} asteroid_field;
|
||||
@@ -158,24 +159,28 @@ extern vec3d Asteroid_icon_closeup_position; // closeup position for asteroid f
|
||||
extern float Asteroid_icon_closeup_zoom; // zoom position for asteroid field briefing icon rendering
|
||||
|
||||
void asteroid_init();
|
||||
bool asteroid_is_within_view(vec3d *pos, float range, bool range_override = false);
|
||||
void asteroid_level_init();
|
||||
void asteroid_level_close();
|
||||
void asteroid_create_all();
|
||||
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, bool brown, bool blue, bool orange, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> targets);
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max);
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max, bool enhanced);
|
||||
void asteroid_render(object* obj, model_draw_list* scene);
|
||||
void asteroid_delete( object *asteroid_objp );
|
||||
void asteroid_process_pre( object *asteroid_objp );
|
||||
void asteroid_process_post( object *asteroid_objp);
|
||||
int asteroid_check_collision( object *asteroid_objp, object * other_obj, vec3d * hitpos, collision_info_struct *asteroid_hit_info=NULL, vec3d* hitnormal=NULL );
|
||||
void asteroid_hit( object *pasteroid_objp, object *other_objp, vec3d *hitpos, float damage );
|
||||
void asteroid_hit( object *pasteroid_objp, object *other_objp, vec3d *hitpos, float damage, vec3d* force );
|
||||
int asteroid_count();
|
||||
int asteroid_collide_objnum(object *asteroid_objp);
|
||||
float asteroid_time_to_impact(object *asteroid_objp);
|
||||
void asteroid_show_brackets();
|
||||
void asteroid_target_closest_danger();
|
||||
void asteroid_add_target(object* objp);
|
||||
int get_asteroid_position(const char* name);
|
||||
int get_asteroid_index(const char* asteroid_name);
|
||||
|
||||
// need to extern for keycontrol debug commands
|
||||
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype, bool check_visibility = false);
|
||||
|
||||
// need to extern for multiplayer
|
||||
void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec);
|
||||
|
||||
@@ -1011,7 +1011,7 @@ void nav_warp(bool prewarp=false)
|
||||
vm_vec_scale(&velocity, (float)Ai_info[Ships[Autopilot_flight_leader->instance].ai_index].waypoint_speed_cap);
|
||||
|
||||
// Find all ships that are supposed to autopilot with the player and move them
|
||||
// to the cinimatic location or the final destination
|
||||
// to the cinematic location or the final destination
|
||||
for (int i = 0; i < MAX_SHIPS; i++)
|
||||
{
|
||||
if (Ships[i].objnum != -1
|
||||
@@ -1020,11 +1020,12 @@ void nav_warp(bool prewarp=false)
|
||||
{
|
||||
vm_vec_add(&Objects[Ships[i].objnum].pos, &Objects[Ships[i].objnum].pos, &targetPos);
|
||||
Objects[Ships[i].objnum].phys_info.vel = velocity;
|
||||
|
||||
// retime collision pairs
|
||||
if (Objects[Ships[i].objnum].flags[Object::Object_Flags::Collides])
|
||||
obj_collide_obj_cache_stale(&Objects[Ships[i].objnum]);
|
||||
}
|
||||
}
|
||||
|
||||
// retime all collision pairs
|
||||
obj_collide_retime_cached_pairs();
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
@@ -1183,6 +1184,10 @@ void send_autopilot_msgID(int msgid)
|
||||
if (msgid < 0 || msgid >= NP_NUM_MESSAGES)
|
||||
return;
|
||||
|
||||
// bail out if message is not set
|
||||
if (NavMsgs[msgid].message[0] == '\0')
|
||||
return;
|
||||
|
||||
send_autopilot_msg(NavMsgs[msgid].message, NavMsgs[msgid].filename);
|
||||
}
|
||||
// ********************************************************************************************
|
||||
@@ -1222,6 +1227,15 @@ void NavSystem_Init()
|
||||
for (int i = 0; i < MAX_NAVPOINTS; i++)
|
||||
Navs[i].clear();
|
||||
|
||||
//Initialize all these as empty strings so we can detect and bail out later -Mjn
|
||||
for (int i = 0; i < NP_NUM_MESSAGES; i++)
|
||||
NavMsgs[i].message[0] = '\0';
|
||||
|
||||
//Set defaults here before parsing
|
||||
NavLinkDistance = 1000;
|
||||
AutopilotMinEnemyDistance = 5000;
|
||||
AutopilotMinAsteroidDistance = 1000;
|
||||
LockWeaponsDuringAutopilot = false;
|
||||
AutoPilotEngaged = false;
|
||||
CurrentNav = -1;
|
||||
audio_handle = -1;
|
||||
@@ -1229,10 +1243,9 @@ void NavSystem_Init()
|
||||
UseCutsceneBars = true;
|
||||
|
||||
// defaults... can be tabled or bound to mission later
|
||||
if (cf_exists_full("autopilot.tbl", CF_TYPE_TABLES))
|
||||
parse_autopilot_table("autopilot.tbl");
|
||||
else
|
||||
parse_autopilot_table(NULL);
|
||||
parse_autopilot_table("autopilot.tbl");
|
||||
|
||||
parse_modular_table("*-aplt.tbm", parse_autopilot_table);
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
@@ -1243,10 +1256,16 @@ void parse_autopilot_table(const char *filename)
|
||||
|
||||
try
|
||||
{
|
||||
if (filename == NULL)
|
||||
read_file_text_from_default(defaults_get_file("autopilot.tbl"));
|
||||
else
|
||||
|
||||
if (!Parsing_modular_table) {
|
||||
// if table doesn't exist, use the default table
|
||||
if (cf_exists_full(filename, CF_TYPE_TABLES))
|
||||
read_file_text(filename, CF_TYPE_TABLES);
|
||||
else
|
||||
read_file_text_from_default(defaults_get_file("autopilot.tbl"));
|
||||
} else {
|
||||
read_file_text(filename, CF_TYPE_TABLES);
|
||||
}
|
||||
|
||||
reset_parse();
|
||||
|
||||
@@ -1254,23 +1273,17 @@ void parse_autopilot_table(const char *filename)
|
||||
required_string("#Autopilot");
|
||||
|
||||
// autopilot link distance
|
||||
required_string("$Link Distance:");
|
||||
stuff_int(&NavLinkDistance);
|
||||
if (optional_string("$Link Distance:"))
|
||||
stuff_int(&NavLinkDistance);
|
||||
|
||||
if (optional_string("$Interrupt autopilot if enemy within distance:"))
|
||||
stuff_int(&AutopilotMinEnemyDistance);
|
||||
else
|
||||
AutopilotMinEnemyDistance = 5000;
|
||||
|
||||
if (optional_string("$Interrupt autopilot if asteroid within distance:"))
|
||||
stuff_int(&AutopilotMinAsteroidDistance);
|
||||
else
|
||||
AutopilotMinAsteroidDistance = 1000;
|
||||
|
||||
if (optional_string("$Lock Weapons During Autopilot:"))
|
||||
stuff_boolean(&LockWeaponsDuringAutopilot);
|
||||
else
|
||||
LockWeaponsDuringAutopilot = false;
|
||||
|
||||
// optional no cutscene bars
|
||||
if (optional_string("+No_Cutscene_Bars"))
|
||||
@@ -1285,13 +1298,14 @@ void parse_autopilot_table(const char *filename)
|
||||
"$Support Present:", "$Support Working:" };
|
||||
for (int i = 0; i < NP_NUM_MESSAGES; i++)
|
||||
{
|
||||
required_string(msg_tags[i]);
|
||||
if (optional_string(msg_tags[i])) {
|
||||
|
||||
required_string("+Msg:");
|
||||
stuff_string(NavMsgs[i].message, F_MESSAGE, 256);
|
||||
required_string("+Msg:");
|
||||
stuff_string(NavMsgs[i].message, F_MESSAGE, 256);
|
||||
|
||||
required_string("+Snd File:");
|
||||
stuff_string(NavMsgs[i].filename, F_NAME, 256);
|
||||
required_string("+Snd File:");
|
||||
stuff_string(NavMsgs[i].filename, F_NAME, 256);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort fla
|
||||
void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags );
|
||||
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert = true );
|
||||
|
||||
const size_t BM_BLOCK_SIZE = 4096;
|
||||
|
||||
|
||||
+100
-10
@@ -585,6 +585,59 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
|
||||
return n;
|
||||
}
|
||||
|
||||
int bm_create_3d(int bpp, int w, int h, int d, void* data) {
|
||||
Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
|
||||
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int n = find_block_of(1);
|
||||
|
||||
// Out of bitmap slots
|
||||
if (n == -1)
|
||||
return -1;
|
||||
|
||||
// make sure that we have valid data
|
||||
if (data == nullptr) {
|
||||
UNREACHABLE("No valid data recieved for 3D Bitmap creation!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto entry = bm_get_entry(n);
|
||||
|
||||
memset(entry, 0, sizeof(bitmap_entry));
|
||||
|
||||
sprintf_safe(entry->filename, "TMP%dx%dx%d+%d", w, h, d, bpp);
|
||||
entry->type = BM_TYPE_3D;
|
||||
entry->comp_type = BM_TYPE_NONE;
|
||||
|
||||
entry->bm.w = (short)w;
|
||||
entry->bm.h = (short)h;
|
||||
entry->bm.d = (short)d;
|
||||
entry->bm.rowsize = (short)w;
|
||||
entry->bm.bpp = (ubyte)bpp;
|
||||
entry->bm.true_bpp = (ubyte)bpp;
|
||||
entry->bm.flags = (ubyte)BMP_TEX_XPARENT;
|
||||
entry->bm.data = 0;
|
||||
entry->bm.palette = nullptr;
|
||||
|
||||
entry->info.user.bpp = (ubyte)bpp;
|
||||
entry->info.user.data = data;
|
||||
entry->info.user.flags = (ubyte)BMP_TEX_XPARENT;
|
||||
|
||||
entry->signature = Bm_next_signature++;
|
||||
|
||||
entry->handle = n;
|
||||
entry->mem_taken = (w * h * d * (bpp >> 3));
|
||||
|
||||
entry->load_count++;
|
||||
|
||||
bm_update_memory_used(n, (int)entry->mem_taken);
|
||||
|
||||
gr_bm_create(bm_get_slot(n));
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void bm_convert_format(bitmap *bmp, ushort flags) {
|
||||
int idx;
|
||||
|
||||
@@ -628,7 +681,7 @@ void bm_free_data(bitmap_slot* bs, bool release)
|
||||
|
||||
// Don't free up memory for user defined bitmaps, since
|
||||
// BmpMan isn't the one in charge of allocating/deallocing them.
|
||||
if (be->type==BM_TYPE_USER) {
|
||||
if (be->type == BM_TYPE_USER || be->type == BM_TYPE_3D) {
|
||||
#ifdef BMPMAN_NDEBUG
|
||||
if ( be->data_size != 0 )
|
||||
bm_texture_ram -= be->data_size;
|
||||
@@ -684,7 +737,7 @@ void bm_free_data_fast(int handle)
|
||||
|
||||
// Don't free up memory for user defined bitmaps, since
|
||||
// BmpMan isn't the one in charge of allocating/deallocing them.
|
||||
if (be->type == BM_TYPE_USER) {
|
||||
if (be->type == BM_TYPE_USER || be->type == BM_TYPE_3D) {
|
||||
#ifdef BMPMAN_NDEBUG
|
||||
if ( be->data_size != 0 )
|
||||
bm_texture_ram -= be->data_size;
|
||||
@@ -892,6 +945,27 @@ int bm_get_info(int handle, int *w, int * h, ushort* flags, int *nframes, int *f
|
||||
}
|
||||
}
|
||||
|
||||
int bm_get_depth(int handle, int* depth) {
|
||||
bitmap* bmp;
|
||||
|
||||
if (!bm_inited) return -1;
|
||||
|
||||
auto entry = bm_get_entry(handle);
|
||||
|
||||
Assertion(entry->handle == handle, "Invalid bitmap handle %d passed to bm_get_info().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
|
||||
|
||||
if (entry->type != BM_TYPE_3D) {
|
||||
*depth = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bmp = &(entry->bm);
|
||||
|
||||
*depth = bmp->d;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int bm_get_num_mipmaps(int num) {
|
||||
auto entry = bm_get_entry(num);
|
||||
|
||||
@@ -1407,6 +1481,10 @@ static int bm_load_image_data(int handle, int bpp, ushort flags, bool nodebug)
|
||||
bm_lock_user(handle, bs, bmp, true_bpp, flags);
|
||||
break;
|
||||
|
||||
case BM_TYPE_3D:
|
||||
bm_lock_user(handle, bs, bmp, true_bpp, flags, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", c_type);
|
||||
return -1;
|
||||
@@ -1517,10 +1595,13 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
// MAX_FILENAME_LEN-10 == 5 character frame designator plus '.' plus 3 letter ext plus NULL terminator
|
||||
// we only check for -5 here since the filename should already have the extension on it, and it must have passed the previous check
|
||||
if (strlen(filename) > MAX_FILENAME_LEN - 5) {
|
||||
Warning(LOCATION, "Passed filename, '%s', is too long to support an extension and frames!!\n\nMaximum length for an ANI/EFF/APNG, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 10);
|
||||
if (img_cfp != nullptr)
|
||||
cfclose(img_cfp);
|
||||
return -1;
|
||||
// Don't check PNGs yet, because a PNG could be a regular non-animated image
|
||||
if (type != BM_TYPE_PNG) {
|
||||
Warning(LOCATION, "Passed filename, '%s', is too long to support an extension and frames!!\n\nMaximum length for an ANI/EFF/APNG, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 10);
|
||||
if (img_cfp != nullptr)
|
||||
cfclose(img_cfp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// it's an effect file, any readable image type with eff being txt
|
||||
@@ -1604,6 +1685,14 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now do the same filename length check that was deferred for PNGs above
|
||||
if (strlen(filename) > MAX_FILENAME_LEN - 5) {
|
||||
Warning(LOCATION, "Passed filename, '%s', is too long to support an extension and frames!!\n\nMaximum length for an ANI/EFF/APNG, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 10);
|
||||
if (img_cfp != nullptr)
|
||||
cfclose(img_cfp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Warning(LOCATION, "Unsupported image type: %i", type);
|
||||
@@ -2388,7 +2477,7 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags
|
||||
bm_convert_format(bmp, flags);
|
||||
}
|
||||
|
||||
void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags) {
|
||||
void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert) {
|
||||
auto be = &bs->entry;
|
||||
|
||||
// Unload any existing data
|
||||
@@ -2428,7 +2517,8 @@ void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort
|
||||
break;
|
||||
}
|
||||
|
||||
bm_convert_format(bmp, flags);
|
||||
if (convert)
|
||||
bm_convert_format(bmp, flags);
|
||||
}
|
||||
|
||||
int bm_make_render_target(int width, int height, int flags) {
|
||||
@@ -2512,7 +2602,7 @@ void *bm_malloc(int n, size_t size) {
|
||||
void bm_page_in_aabitmap(int handle, int nframes) {
|
||||
int i;
|
||||
|
||||
if (handle == -1)
|
||||
if (handle < 0)
|
||||
return;
|
||||
|
||||
Assert(bm_get_entry(handle)->handle == handle);
|
||||
@@ -3131,7 +3221,7 @@ int bm_unload_fast(int handle, int clear_render_targets) {
|
||||
return -1; // Already been released
|
||||
}
|
||||
|
||||
if (be->type == BM_TYPE_USER) {
|
||||
if (be->type == BM_TYPE_USER || be->type == BM_TYPE_3D) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
+27
-1
@@ -79,7 +79,9 @@ enum BM_TYPE
|
||||
BM_TYPE_CUBEMAP_DDS, //!< generic DDS cubemap (uncompressed cubemap surface)
|
||||
BM_TYPE_CUBEMAP_DXT1, //!< 24-bit cubemap (compressed cubemap surface)
|
||||
BM_TYPE_CUBEMAP_DXT3, //!< 32-bit cubemap (compressed cubemap surface)
|
||||
BM_TYPE_CUBEMAP_DXT5 //!< 32-bit cubemap (compressed cubemap surface)
|
||||
BM_TYPE_CUBEMAP_DXT5, //!< 32-bit cubemap (compressed cubemap surface)
|
||||
|
||||
BM_TYPE_3D //!< 3D in-memory
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -90,6 +92,7 @@ struct bitmap
|
||||
{
|
||||
short w; //!< Width, in number of pixels
|
||||
short h; //!< Height, in number of pixels
|
||||
short d; //!< Depth, in number of pixels
|
||||
short rowsize; //!< What you need to add to go to next row
|
||||
int bpp; //!< Requested bitdepth of each pixel. ( 7, 8, 15, 16, 24, 32)
|
||||
int true_bpp; //!< The image's actual bitdepth
|
||||
@@ -217,6 +220,19 @@ int bm_load_duplicate(const char *filename);
|
||||
*/
|
||||
int bm_create(int bpp, int w, int h, void *data = NULL, int flags = 0);
|
||||
|
||||
/**
|
||||
* Loads a 3D bitmap which exists somewhere in the RAM.
|
||||
*
|
||||
* @param bpp The bitdepth of the bitmap
|
||||
* @param w The width of the bitmap
|
||||
* @param h The height of the bitmap
|
||||
* @param d The depth of the bitmap
|
||||
* @param[in] data The bitmap's data glob
|
||||
*
|
||||
* @note The used RAM cannot be freed until bm_release is called on the created bitmap
|
||||
*/
|
||||
int bm_create_3d(int bpp, int w, int h, int d, void* data = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Unloads a bitmap's data, but not the bitmap info
|
||||
*
|
||||
@@ -373,6 +389,16 @@ int bm_is_valid(int handle);
|
||||
*/
|
||||
int bm_get_info(int handle, int *w = nullptr, int * h = nullptr, ushort* flags = nullptr, int *nframes = nullptr, int *fps = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Gets 3D info on the bitmap indexed by handle.
|
||||
*
|
||||
* @param[out] depth If non-null, gets the depth
|
||||
*
|
||||
* @returns The handle on success
|
||||
* @returns -1 on failure
|
||||
*/
|
||||
int bm_get_depth(int handle, int* depth);
|
||||
|
||||
/**
|
||||
* @brief Gets the filename of the bitmap indexed by handle
|
||||
*
|
||||
|
||||
@@ -775,9 +775,10 @@ int is_ext_in_list( const char *ext_list, const char *ext )
|
||||
// Run a basic test for indexed files that may be shadowed
|
||||
#ifndef NDEBUG
|
||||
#define ENABLE_SHADOW_CHECK 1
|
||||
SCP_vector<SCP_string> critical_shadowed;
|
||||
#endif
|
||||
|
||||
static void check_file_shadows(const int root_index __UNUSED, const int pathtype __UNUSED, const SCP_string &name __UNUSED, const SCP_string sub_path __UNUSED)
|
||||
static void check_file_shadows(const int root_index __UNUSED, const int pathtype __UNUSED, const SCP_string &name __UNUSED, const SCP_string &sub_path __UNUSED, const char *real_name = nullptr)
|
||||
{
|
||||
#if ENABLE_SHADOW_CHECK
|
||||
if ( !cf_should_scan_subdirs(pathtype) ) {
|
||||
@@ -786,11 +787,12 @@ static void check_file_shadows(const int root_index __UNUSED, const int pathtype
|
||||
|
||||
SCP_string curfile, newfile;
|
||||
|
||||
const bool critical = ((pathtype == CF_TYPE_TABLES) || (pathtype == CF_TYPE_MISSIONS));
|
||||
const auto root = cf_get_root(root_index);
|
||||
|
||||
newfile = root->path + ((root->roottype == CF_ROOTTYPE_PACK) ? "::" : "");
|
||||
newfile += cf_get_root_pathtype(root, pathtype) + DIR_SEPARATOR_CHAR;
|
||||
newfile += sub_path + name;
|
||||
newfile += sub_path + (real_name ? real_name : name);
|
||||
|
||||
for (uint i = 0; i < Num_files; ++i) {
|
||||
const auto f = cf_get_file(i);
|
||||
@@ -815,14 +817,23 @@ static void check_file_shadows(const int root_index __UNUSED, const int pathtype
|
||||
continue;
|
||||
}
|
||||
|
||||
curfile = r->path + ((r->roottype == CF_ROOTTYPE_PACK) ? "::" : "");
|
||||
curfile += cf_get_root_pathtype(r, pathtype) + DIR_SEPARATOR_CHAR;
|
||||
curfile += f->sub_path + f->name_ext;
|
||||
if (r->roottype == CF_ROOTTYPE_PATH) {
|
||||
curfile = f->real_name;
|
||||
} else {
|
||||
curfile = r->path + ((r->roottype == CF_ROOTTYPE_PACK) ? "::" : "");
|
||||
curfile += cf_get_root_pathtype(r, pathtype) + DIR_SEPARATOR_CHAR;
|
||||
curfile += f->sub_path + f->name_ext;
|
||||
}
|
||||
|
||||
// this log message occurs in the middle of an existing line, hence the extra new lines
|
||||
mprintf(("\nWARNING! A file being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
|
||||
mprintf(("\nWARNING! A %sfile being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
|
||||
critical ? "critical " : "",
|
||||
newfile.c_str(), curfile.c_str()));
|
||||
|
||||
if (critical) {
|
||||
critical_shadowed.push_back(name);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -886,12 +897,18 @@ void cf_search_root_path(int root_index)
|
||||
|
||||
for (auto &file : files) {
|
||||
auto ext_idx = file.name.rfind('.');
|
||||
auto orig_name = file.name;
|
||||
|
||||
if ( ext_idx != SCP_string::npos && SCP_string_lcase_equal_to()(file.name.substr(ext_idx), SCP_string(".lz41")) ) {
|
||||
file.name = file.name.erase(ext_idx, file.name.length());
|
||||
ext_idx = file.name.rfind('.');
|
||||
}
|
||||
|
||||
if ( ext_idx == SCP_string::npos || !is_ext_in_list(Pathtypes[i].extensions, file.name.substr(ext_idx+1).c_str()) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
check_file_shadows(root_index, i, file.name, file.sub_path);
|
||||
check_file_shadows(root_index, i, file.name, file.sub_path, orig_name.c_str());
|
||||
|
||||
cf_file *cfile = cf_create_file();
|
||||
|
||||
@@ -901,7 +918,7 @@ void cf_search_root_path(int root_index)
|
||||
cfile->write_time = file.m_time;
|
||||
cfile->size = static_cast<int>(file.size);
|
||||
cfile->pack_offset = 0;
|
||||
cfile->real_name = search_path + DIR_SEPARATOR_STR + file.sub_path + file.name;
|
||||
cfile->real_name = search_path + DIR_SEPARATOR_STR + file.sub_path + orig_name;
|
||||
cfile->sub_path = file.sub_path;
|
||||
|
||||
++num_files;
|
||||
@@ -1143,6 +1160,24 @@ void cf_build_file_list()
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// if some special/critical files might be shadowed then make sure the user knows about it
|
||||
if ( !critical_shadowed.empty() && !running_unittests ) {
|
||||
SCP_string shadowed;
|
||||
const auto count = critical_shadowed.size();
|
||||
|
||||
// only report a few of the files so that the warning dialog doesn't get freakishly large
|
||||
for (size_t j = 0; (j < 5) && (j < count); ++j) {
|
||||
shadowed += critical_shadowed[j] + '\n';
|
||||
}
|
||||
|
||||
Warning(LOCATION, "Some critical files might be shadowed! Please check the debug log for details.\n\n"
|
||||
"%lu file(s) detected, including:\n%s", count, shadowed.c_str());
|
||||
}
|
||||
|
||||
critical_shadowed.clear();
|
||||
critical_shadowed.shrink_to_fit();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,11 @@ bool CustomCheat::canUseCheat() {
|
||||
|
||||
void CustomCheat::runCheat() {
|
||||
if (!canUseCheat()) return;
|
||||
HUD_printf("%s", cheatMsg.c_str());
|
||||
|
||||
//Only try to send the message if we actually have one to send and are in a mission
|
||||
if (!cheatMsg.empty() && (Game_mode & GM_IN_MISSION))
|
||||
HUD_printf("%s", cheatMsg.c_str());
|
||||
|
||||
scripting::hooks::OnCheat->run(scripting::hook_param_list(scripting::hook_param("Cheat", 's', cheatCode)));
|
||||
CheatUsed = cheatCode;
|
||||
}
|
||||
@@ -108,8 +112,9 @@ void parse_cheat_table(const char* filename) {
|
||||
code = code.substr(0, CHEAT_BUFFER_LEN);
|
||||
}
|
||||
|
||||
required_string("+Message:");
|
||||
stuff_string(msg, F_MESSAGE);
|
||||
if (optional_string("+Message:")) {
|
||||
stuff_string(msg, F_MESSAGE);
|
||||
}
|
||||
|
||||
if (optional_string("+RequireCheats:")) {
|
||||
stuff_boolean(&requireCheats);
|
||||
|
||||
@@ -235,6 +235,7 @@ Flag exe_params[] =
|
||||
{ "-prefer_ipv4", "Prefer IPv4 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv4", },
|
||||
{ "-prefer_ipv6", "Prefer IPv6 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv6", },
|
||||
{ "-log_multi_packet", "Log multi packet types ", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-log_multi_packet",},
|
||||
{ "-no_bsp_align", "Disable pof BSP data alignment", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_bsp_align", },
|
||||
#ifdef WIN32
|
||||
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fix_registry", },
|
||||
#endif
|
||||
@@ -273,6 +274,7 @@ Flag exe_params[] =
|
||||
{ "-slow_frames_ok", "Don't adjust timestamps for slow frames", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-slow_frames_ok", },
|
||||
{ "-imgui_debug", "Show imgui debug/demo window in the lab", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-imgui_debug", },
|
||||
{ "-luadev", "Make lua errors non-fatal", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-luadev", },
|
||||
{"-vulkan", "Use vulkan render backend", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-vulkan", },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -329,7 +331,6 @@ int Cmdline_use_last_pilot = 0;
|
||||
// Graphics related
|
||||
cmdline_parm fov_arg("-fov", "Vertical field-of-view factor", AT_FLOAT); // Cmdline_fov -- comand line FOV -Bobboau
|
||||
cmdline_parm fov_cockpit_arg("-fov_cockpit", "Vertical field-of-view factor for Cockpits", AT_FLOAT);
|
||||
cmdline_parm clip_dist_arg("-clipdist", "Changes the distance from the viewpoint for the near-clipping plane", AT_FLOAT); // Cmdline_clip_dist
|
||||
cmdline_parm ambient_power_arg("-ambient", "Multiplies the brightness of all ambient light", AT_FLOAT);
|
||||
cmdline_parm light_power_arg("-light", "Multiplies the brightness of all light", AT_FLOAT);
|
||||
cmdline_parm emissive_power_arg("-emissive", "Multiplies the brightness of all ambient light", AT_FLOAT);
|
||||
@@ -351,6 +352,7 @@ cmdline_parm deprecated_fxaa_arg("-fxaa", nullptr, AT_NONE);
|
||||
cmdline_parm deprecated_fxaa_preset_arg("-fxaa_preset", "FXAA quality (0-2), requires post-processing and -fxaa", AT_INT);
|
||||
cmdline_parm deprecated_smaa_arg("-smaa", nullptr, AT_NONE);
|
||||
cmdline_parm deprecated_smaa_preset_arg("-smaa_preset", "SMAA quality (0-3), requires post-processing and -smaa", AT_INT);
|
||||
cmdline_parm msaa_enabled_arg("-msaa", nullptr, AT_INT);
|
||||
cmdline_parm fb_explosions_arg("-fb_explosions", NULL, AT_NONE);
|
||||
cmdline_parm fb_thrusters_arg("-fb_thrusters", NULL, AT_NONE);
|
||||
cmdline_parm flightshaftsoff_arg("-nolightshafts", NULL, AT_NONE);
|
||||
@@ -360,7 +362,6 @@ cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline
|
||||
cmdline_parm deferred_lighting_cockpit_arg("-deferred_cockpit", nullptr, AT_NONE);
|
||||
cmdline_parm anisotropy_level_arg("-anisotropic_filter", NULL, AT_INT);
|
||||
|
||||
float Cmdline_clip_dist = Default_min_draw_distance;
|
||||
float Cmdline_ambient_power = 1.0f;
|
||||
float Cmdline_emissive_power = 0.0f;
|
||||
float Cmdline_light_power = 1.0f;
|
||||
@@ -379,6 +380,7 @@ bool Cmdline_force_lightshaft_off = false;
|
||||
int Cmdline_no_deferred_lighting = 0;
|
||||
bool Cmdline_deferred_lighting_cockpit = false;
|
||||
int Cmdline_aniso_level = 0;
|
||||
int Cmdline_msaa_enabled = 0;
|
||||
|
||||
// Game Speed related
|
||||
cmdline_parm no_fpscap("-no_fps_capping", "Don't limit frames-per-second", AT_NONE); // Cmdline_NoFPSCap
|
||||
@@ -442,8 +444,10 @@ char *Cmdline_gateway_ip = nullptr;
|
||||
// Launcher related options
|
||||
cmdline_parm portable_mode("-portable_mode", NULL, AT_NONE);
|
||||
cmdline_parm joy_info("-joy_info", "Outputs SDL joystick info", AT_NONE);
|
||||
cmdline_parm lang_arg("-language", "Language name as defined in strings.tbl", AT_STRING);
|
||||
|
||||
bool Cmdline_portable_mode = false;
|
||||
SCP_string Cmdline_lang;
|
||||
|
||||
// Troubleshooting
|
||||
cmdline_parm loadallweapons_arg("-loadallweps", NULL, AT_NONE); // Cmdline_load_all_weapons
|
||||
@@ -464,6 +468,7 @@ cmdline_parm noshadercache_arg("-noshadercache", NULL, AT_NONE);
|
||||
cmdline_parm prefer_ipv4_arg("-prefer_ipv4", nullptr, AT_NONE);
|
||||
cmdline_parm prefer_ipv6_arg("-prefer_ipv6", nullptr, AT_NONE);
|
||||
cmdline_parm log_multi_packet_arg("-log_multi_packet", nullptr, AT_NONE);
|
||||
cmdline_parm no_bsp_align_arg("-no_bsp_align", nullptr, AT_NONE);
|
||||
#ifdef WIN32
|
||||
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
|
||||
#endif
|
||||
@@ -485,6 +490,7 @@ bool Cmdline_noshadercache = false;
|
||||
bool Cmdline_prefer_ipv4 = false;
|
||||
bool Cmdline_prefer_ipv6 = false;
|
||||
bool Cmdline_dump_packet_type = false;
|
||||
bool Cmdline_no_bsp_align = false;
|
||||
#ifdef WIN32
|
||||
bool Cmdline_alternate_registry_path = false;
|
||||
#endif
|
||||
@@ -525,6 +531,7 @@ cmdline_parm fixed_seed_rand("-seed", nullptr, AT_INT); // Cmdline_rng_seed,Cmdl
|
||||
cmdline_parm luadev_arg("-luadev", "Make lua errors non-fatal", AT_NONE); // Cmdline_lua_devmode
|
||||
cmdline_parm override_arg("-override_data", "Enable override directory", AT_NONE); // Cmdline_override_data
|
||||
cmdline_parm imgui_debug_arg("-imgui_debug", nullptr, AT_NONE);
|
||||
cmdline_parm vulkan("-vulkan", nullptr, AT_NONE);
|
||||
|
||||
char *Cmdline_start_mission = NULL;
|
||||
int Cmdline_dis_collisions = 0;
|
||||
@@ -560,6 +567,7 @@ bool Cmdline_slow_frames_ok = false;
|
||||
bool Cmdline_lua_devmode = false;
|
||||
bool Cmdline_override_data = false;
|
||||
bool Cmdline_show_imgui_debug = false;
|
||||
bool Cmdline_vulkan = false;
|
||||
|
||||
// Other
|
||||
cmdline_parm get_flags_arg(GET_FLAGS_STRING, "Output the launcher flags file", AT_STRING);
|
||||
@@ -827,7 +835,7 @@ void os_validate_parms(int argc, char *argv[])
|
||||
// if we got a -help, --help, -h, or -? then show the help text, otherwise show unknown option
|
||||
if (!stricmp(token, "-help") || !stricmp(token, "--help") || !stricmp(token, "-h") || !stricmp(token, "-?")) {
|
||||
printf("FreeSpace 2 Open, version %s\n", FS_VERSION_FULL);
|
||||
printf("Website: http://scp.indiegames.us\n");
|
||||
printf("Website: https://scp.indiegames.us\n");
|
||||
printf("Github (bug reporting): https://github.com/scp-fs2open/fs2open.github.com/issues\n\n");
|
||||
printf("Usage: fs2_open [options]\n");
|
||||
|
||||
@@ -1835,10 +1843,6 @@ bool SetCmdlineParams()
|
||||
}
|
||||
}
|
||||
|
||||
if( clip_dist_arg.found() ) {
|
||||
Min_draw_distance = Cmdline_clip_dist = clip_dist_arg.get_float();
|
||||
}
|
||||
|
||||
if (orb_radar.found())
|
||||
{
|
||||
Cmdline_orb_radar = 1;
|
||||
@@ -1933,6 +1937,21 @@ bool SetCmdlineParams()
|
||||
}
|
||||
}
|
||||
|
||||
if (msaa_enabled_arg.found()) {
|
||||
Cmdline_msaa_enabled = msaa_enabled_arg.get_int();
|
||||
switch (Cmdline_msaa_enabled) {
|
||||
case 0:
|
||||
case 4:
|
||||
case 8:
|
||||
case 16:
|
||||
break;
|
||||
default:
|
||||
Warning(LOCATION, "Requested illegal MSAA sample count %d. Allowed are: 0, 4, 8, 16. Setting to 0.", Cmdline_msaa_enabled);
|
||||
Cmdline_msaa_enabled = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( glow_arg.found() )
|
||||
Cmdline_glow = 0;
|
||||
|
||||
@@ -2000,6 +2019,15 @@ bool SetCmdlineParams()
|
||||
{
|
||||
Cmdline_portable_mode = true;
|
||||
}
|
||||
|
||||
if (lang_arg.found())
|
||||
{
|
||||
Cmdline_lang = lang_arg.str();
|
||||
}
|
||||
|
||||
if (no_bsp_align_arg.found()) {
|
||||
Cmdline_no_bsp_align = true;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
if (fix_registry.found()) {
|
||||
@@ -2200,6 +2228,10 @@ bool SetCmdlineParams()
|
||||
Cmdline_show_video_info = true;
|
||||
}
|
||||
|
||||
if (vulkan.found()) {
|
||||
Cmdline_vulkan = true;
|
||||
}
|
||||
|
||||
//Deprecated flags - CommanderDJ
|
||||
if (deprecated_no_emissive_arg.found()) {
|
||||
Cmdline_emissive = 0;
|
||||
|
||||
@@ -52,7 +52,6 @@ extern char *Cmdline_center_res;
|
||||
// FSO OPTIONS -------------------------------------------------
|
||||
|
||||
// Graphics related
|
||||
extern float Cmdline_clip_dist;
|
||||
extern float Cmdline_ambient_power;
|
||||
extern float Cmdline_emissive_power;
|
||||
extern float Cmdline_light_power;
|
||||
@@ -70,6 +69,7 @@ extern int Cmdline_no_deferred_lighting;
|
||||
extern bool Cmdline_deferred_lighting_cockpit;
|
||||
extern int Cmdline_emissive;
|
||||
extern int Cmdline_aniso_level;
|
||||
extern int Cmdline_msaa_enabled;
|
||||
|
||||
// Game Speed related
|
||||
extern int Cmdline_NoFPSCap;
|
||||
@@ -104,6 +104,7 @@ extern char *Cmdline_gateway_ip;
|
||||
|
||||
// Launcher related options
|
||||
extern bool Cmdline_portable_mode;
|
||||
extern SCP_string Cmdline_lang;
|
||||
|
||||
// Troubleshooting
|
||||
extern int Cmdline_load_all_weapons;
|
||||
@@ -156,6 +157,7 @@ extern bool Cmdline_slow_frames_ok;
|
||||
extern bool Cmdline_lua_devmode;
|
||||
extern bool Cmdline_override_data;
|
||||
extern bool Cmdline_show_imgui_debug;
|
||||
extern bool Cmdline_vulkan;
|
||||
|
||||
enum class WeaponSpewType { NONE = 0, STANDARD, ALL };
|
||||
extern WeaponSpewType Cmdline_spew_weapon_stats;
|
||||
|
||||
@@ -51,6 +51,14 @@ void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand)
|
||||
|
||||
objp->phys_info.max_vel.xyz.z = -25.0f;
|
||||
vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
|
||||
|
||||
// if this cmeasure has a single segment trail, let the trail know since we just changed the velocity
|
||||
// yeah this is hacky but that's what this function gets for CHANGING the velocity on objects with a ""CONSTANT VELOCITY""
|
||||
weapon* wp = &Weapons[objp->instance];
|
||||
if (wp->trail_ptr && wp->trail_ptr->single_segment) {
|
||||
wp->trail_ptr->vel[0] = objp->phys_info.vel;
|
||||
wp->trail_ptr->vel[1] = objp->phys_info.vel;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -433,6 +433,26 @@ private:
|
||||
short btn = -1; //!< The button, key combo, or axis that's bound.
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct cc_line
|
||||
* @brief Defines an interactable line to display control names and their bindings
|
||||
*/
|
||||
struct cc_line {
|
||||
const char* label;
|
||||
int cc_index; // index into Control_config of item
|
||||
int y; // Y coordinate of line
|
||||
int kx, kw, jx, jw; // x start and width of keyboard and joystick bound text
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct conflict
|
||||
* @brief Defines an conflict between bindings
|
||||
*/
|
||||
struct conflict {
|
||||
int first = -1; // index of other control in conflict with this one
|
||||
int second = -1; // index of other control in conflict with this one
|
||||
};
|
||||
|
||||
/*!
|
||||
* A pair of bindings.
|
||||
* @note Please don't set the bindings directly, use ::take() instead.
|
||||
@@ -641,6 +661,15 @@ private:
|
||||
SCP_vector<CCI>& ControlConfig;
|
||||
};
|
||||
|
||||
enum class selItem : int {
|
||||
selItem_REND, // Must be first to allow cycling
|
||||
|
||||
None,
|
||||
Primary,
|
||||
Secondary,
|
||||
|
||||
selItem_END // Must be last to allow cycling
|
||||
};
|
||||
|
||||
extern int Failed_key_index;
|
||||
|
||||
@@ -649,6 +678,9 @@ extern int Joy_sensitivity;
|
||||
|
||||
extern int Control_config_overlay_id;
|
||||
|
||||
extern SCP_vector<cc_line> Cc_lines; //!< Stores the keyboard details for the UI
|
||||
extern SCP_vector<conflict> Conflicts; //!< Stores conflict data for the keybinds
|
||||
|
||||
extern SCP_vector<CCI> Control_config; //!< Stores the keyboard configuration
|
||||
extern SCP_vector<CC_preset> Control_config_presets; // tabled control presets; pointers to config_item arrays
|
||||
extern const char **Joy_button_text; // String table of button labels. XSTR'd on init.
|
||||
@@ -689,7 +721,7 @@ void control_config_common_close();
|
||||
/*!
|
||||
* @brief init config menu
|
||||
*/
|
||||
void control_config_init();
|
||||
void control_config_init(bool API_Access = false);
|
||||
|
||||
/*!
|
||||
* @brief do a frame of the config menu
|
||||
@@ -699,12 +731,73 @@ void control_config_do_frame(float frametime);
|
||||
/*!
|
||||
* @brief close config menu
|
||||
*/
|
||||
void control_config_close();
|
||||
void control_config_close(bool API_Access = false);
|
||||
|
||||
/*!
|
||||
* @brief setup for binding a control
|
||||
*/
|
||||
void control_config_do_bind(bool API_Access = false);
|
||||
|
||||
/*!
|
||||
* @brief setup for searching a control
|
||||
*/
|
||||
void control_config_do_search(bool API_Access = false);
|
||||
|
||||
/**
|
||||
* @brief Unbinds the selected control
|
||||
*/
|
||||
bool control_config_remove_binding(int ctrl, selItem item, bool API_Access = false);
|
||||
|
||||
/**
|
||||
* @brief Clears all conflicting control bindings, except the selected control
|
||||
*/
|
||||
bool control_config_clear_other(int ctrl, bool API_Access = false);
|
||||
|
||||
/**
|
||||
* @brief Unbinds ALL controls
|
||||
* TODO: unbind axes and reset inversion
|
||||
*/
|
||||
bool control_config_clear_all(bool API_Access = false);
|
||||
|
||||
/**
|
||||
* @brief Reverts all bindings to their preset. If already default, cycle to the next presets.
|
||||
*/
|
||||
bool control_config_do_reset(bool cycle = true, bool API_Access = false);
|
||||
|
||||
/**
|
||||
* @brief Toggles a modifier on or off for a control binding
|
||||
*/
|
||||
bool control_config_toggle_modifier(int bit, int ctrl, bool API_Access = false);
|
||||
|
||||
/**
|
||||
* @brief Toggles inversion for the selected axis control
|
||||
*/
|
||||
bool control_config_toggle_invert(int ctrl, selItem item, bool API_Access = false);
|
||||
|
||||
/*!
|
||||
* @brief Performs a single undo opration, reverting the most recent change to bindings, if any
|
||||
*/
|
||||
void control_config_do_undo(bool API_Access = false);
|
||||
|
||||
/*!
|
||||
*@brief Runs every frame to check for input and binds the input if appropriate
|
||||
*/
|
||||
int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access = false);
|
||||
|
||||
/*!
|
||||
*@brief Runs every frame to check for input. Returns the index of the item the key is bound to or -1 if nothing.
|
||||
*/
|
||||
int control_config_search_key_on_frame(bool API_Access = false);
|
||||
|
||||
/*!
|
||||
* Does a cursory conflict check, then accepts changes to the bindings, if any, and request the menu to close.
|
||||
*/
|
||||
bool control_config_accept(bool API_Access = false);
|
||||
|
||||
/*!
|
||||
* @brief Cancel configuration of controls, revert any changes, return to previous menu/game state
|
||||
*/
|
||||
void control_config_cancel_exit();
|
||||
void control_config_cancel_exit(bool API_Access = false);
|
||||
|
||||
/*!
|
||||
* @brief Copies all bindings within preset into Control_config
|
||||
@@ -735,6 +828,30 @@ bool control_config_use_preset_by_name(const SCP_string &name);
|
||||
|
||||
SCP_vector<CC_preset>::iterator control_config_get_current_preset(bool invert_agnostic = false);
|
||||
|
||||
/*!
|
||||
* @brief Deletes the preset
|
||||
*
|
||||
* @returns TRUE if successful
|
||||
* @returns FALSE if the preset is default or currently selected
|
||||
*/
|
||||
bool control_config_delete_preset(CC_preset preset);
|
||||
|
||||
/*!
|
||||
* @brief Clones a preset
|
||||
*
|
||||
* @returns TRUE if successful
|
||||
* @returns FALSE if the preset already exists with that name
|
||||
*/
|
||||
bool control_config_clone_preset(CC_preset preset, SCP_string name);
|
||||
|
||||
/*!
|
||||
* @brief Saves a preset with the current controls
|
||||
*
|
||||
* @returns TRUE if successful
|
||||
* @returns FALSE if the preset already exists with that name
|
||||
*/
|
||||
bool control_config_create_new_preset(SCP_string name);
|
||||
|
||||
/*!
|
||||
* Returns the IoActionId (index within Control_config[]) of a control bound to the given key
|
||||
*
|
||||
|
||||
@@ -643,7 +643,9 @@ const char *translate_key(char *key)
|
||||
|
||||
if (!first.empty() && !second.empty()) {
|
||||
strcpy_s(text, first.textify().c_str());
|
||||
strcat_s(text, " or ");
|
||||
strcat_s(text, " ");
|
||||
strcat_s(text, XSTR("or", 1672));
|
||||
strcat_s(text, " ");
|
||||
strcat_s(text, second.textify().c_str());
|
||||
|
||||
} else if (!first.empty()) {
|
||||
@@ -653,7 +655,7 @@ const char *translate_key(char *key)
|
||||
strcpy_s(text, second.textify().c_str());
|
||||
|
||||
} else {
|
||||
strcpy_s(text, "None");
|
||||
strcpy_s(text, XSTR("None", 1673));
|
||||
}
|
||||
|
||||
return text;
|
||||
@@ -664,7 +666,7 @@ const char *textify_scancode(int code)
|
||||
static char text[BTN_MSG_LEN];
|
||||
|
||||
if (code < 0)
|
||||
return "None";
|
||||
return XSTR("None", 1673);
|
||||
|
||||
int keycode = code & KEY_MASK;
|
||||
|
||||
@@ -797,6 +799,8 @@ void control_config_common_init()
|
||||
Mouse_button_text[6] = vm_strdup(XSTR("Wheel Down", 1656));
|
||||
Mouse_button_text[7] = vm_strdup(XSTR("Wheel Left", 1657));
|
||||
Mouse_button_text[8] = vm_strdup(XSTR("Wheel Right", 1658));
|
||||
|
||||
Script_system.OnStateDestroy.add([](lua_State*) -> void { Lua_hooks.clear(); });
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -35,7 +35,7 @@ Section lookupSectionValue(const char* name) {
|
||||
return Section::Invalid;
|
||||
}
|
||||
|
||||
void load_preset_files() {
|
||||
void load_preset_files(SCP_string clone) {
|
||||
SCP_vector<SCP_string> filelist;
|
||||
cf_get_file_list(filelist, CF_TYPE_PLAYER_BINDS, NOX("*.json"), CF_SORT_NAME, nullptr,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
@@ -128,7 +128,8 @@ void load_preset_files() {
|
||||
// Done with the file
|
||||
auto it = preset_find_duplicate(preset);
|
||||
|
||||
if (it == Control_config_presets.end()) {
|
||||
// If we just cloned the file, then allow the duplicate. Just this once.
|
||||
if ((clone == preset.name) || (it == Control_config_presets.end())) {
|
||||
Control_config_presets.push_back(preset);
|
||||
|
||||
} else if ((it->name != preset.name) || (it->type != Preset_t::pst)) {
|
||||
@@ -147,6 +148,31 @@ bool preset_file_exists(SCP_string name) {
|
||||
return cf_exists(name.c_str(), CF_TYPE_PLAYER_BINDS) != 0;
|
||||
}
|
||||
|
||||
bool delete_preset_file(CC_preset preset) {
|
||||
|
||||
// can't remove the default preset!
|
||||
if (preset.name == "default") {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = control_config_get_current_preset();
|
||||
|
||||
// can't remove the currently loaded preset either!
|
||||
if (preset.name == it->name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SCP_string filename = preset.name + ".json";
|
||||
|
||||
cf_delete(filename.c_str(), CF_TYPE_PLAYER_BINDS, CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
|
||||
// Reload the presets from file.
|
||||
Control_config_presets.resize(1);
|
||||
load_preset_files();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool save_preset_file(CC_preset preset, bool overwrite) {
|
||||
// Must have a name
|
||||
if (preset.name.empty()) {
|
||||
|
||||
@@ -209,12 +209,24 @@ private:
|
||||
*/
|
||||
bool save_preset_file(CC_preset preset, bool overwrite);
|
||||
|
||||
/**
|
||||
* @brief Deletes the given preset to file.
|
||||
* @param[in] preset The preset to delete
|
||||
*
|
||||
* @returns True if successful, or
|
||||
* @returns False Preset is default, or
|
||||
* @returns False Preset file is the currently selected preset
|
||||
*/
|
||||
bool delete_preset_file(CC_preset preset);
|
||||
|
||||
/**
|
||||
* @brief Loads in all preset .json files from 'players/presets'
|
||||
* @details If a preset file is unique, it is loaded into the game and available for use by the player. However, if
|
||||
* a preset is a duplicate of another preset, it is ignored, and the player is warned of it
|
||||
*
|
||||
* @param[in] clone Used to check if we just cloned a particular preset and allows just that clone in without warning
|
||||
*/
|
||||
void load_preset_files();
|
||||
void load_preset_files(SCP_string clone = "");
|
||||
|
||||
/**
|
||||
* @brief Checks if the given preset is a duplicate within Control_config_presets vector
|
||||
|
||||
@@ -175,6 +175,9 @@ void parse_cutscene_table(const char* filename)
|
||||
if (flag)
|
||||
csnp->flags.set(Cutscene::Cutscene_Flags::Never_viewable);
|
||||
}
|
||||
if (optional_string("$Custom data:")) {
|
||||
parse_string_map(csnp->custom_data, "$end_custom_data", "+Val:");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ typedef struct cutscene_info
|
||||
char name[NAME_LENGTH];
|
||||
char* description;
|
||||
flagset<Cutscene::Cutscene_Flags> flags;
|
||||
SCP_map<SCP_string, SCP_string> custom_data;
|
||||
} cutscene_info;
|
||||
|
||||
extern SCP_vector<cutscene_info> Cutscenes;
|
||||
|
||||
@@ -174,10 +174,15 @@ void determine_display_positions(Player* player, PlaybackState* state) {
|
||||
void initialize_player_state(Player* player, PlaybackState* state) {
|
||||
determine_display_positions(player, state);
|
||||
|
||||
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
|
||||
if (!Movie_subtitle_font.empty()) {
|
||||
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
|
||||
|
||||
if (state->subtitle_font < 0) {
|
||||
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
|
||||
if (state->subtitle_font < 0) {
|
||||
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
|
||||
}
|
||||
}
|
||||
else if (font::FontManager::numberOfFonts() > 0) {
|
||||
state->subtitle_font = 0; // if not explicitly specified, default to the first available font
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
-19
@@ -251,10 +251,10 @@ void debris_process_post(object * obj, float frame_time)
|
||||
|
||||
int n, n_arcs = Random::next(1, 3); // Create 1-3 sparks
|
||||
|
||||
vec3d v1, v2, v3, v4;
|
||||
|
||||
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v1, &v2);
|
||||
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v3, &v4);
|
||||
vec3d v1 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
vec3d v2 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
vec3d v3 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
vec3d v4 = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
|
||||
n = 0;
|
||||
|
||||
@@ -327,11 +327,7 @@ void debris_process_post(object * obj, float frame_time)
|
||||
// Maybe move a vertex.... 20% of the time maybe?
|
||||
int mr = Random::next();
|
||||
if ( mr < Random::MAX_VALUE/5 ) {
|
||||
vec3d v1, v2;
|
||||
|
||||
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v1, &v2);
|
||||
|
||||
db->arc_pts[i][mr % 2] = v1;
|
||||
db->arc_pts[i][mr % 2] = submodel_get_random_point(db->model_num, db->submodel_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,7 +359,7 @@ int debris_find_oldest()
|
||||
}
|
||||
|
||||
#define DEBRIS_ROTVEL_SCALE 5.0f
|
||||
void calc_debris_physics_properties( physics_info *pi, vec3d *min, vec3d *max );
|
||||
void calc_debris_physics_properties( physics_info *pi, vec3d *min, vec3d *max, float density );
|
||||
|
||||
MONITOR(NumSmallDebris)
|
||||
MONITOR(NumHullDebris)
|
||||
@@ -378,8 +374,9 @@ MONITOR(NumHullDebris)
|
||||
* @param exp_center Explosion center in global coordinates
|
||||
* @param hull_flag Whether this debris is a chunk of a ship's hull (as opposed to shrapnel)
|
||||
* @param exp_force Explosion force, used to assign velocity to pieces. 1.0f assigns velocity like before. 2.0f assigns twice as much to non-inherited part of velocity
|
||||
* @param source_subsys The subsystem this debris came from, if any
|
||||
*/
|
||||
object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force)
|
||||
object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force, ship_subsys* source_subsys)
|
||||
{
|
||||
int parent_objnum;
|
||||
object *obj;
|
||||
@@ -397,7 +394,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
obj = debris_create_only(parent_objnum, shipp->ship_info_index, shipp->alt_type_index, shipp->team, -1.0f, -1, model_num, submodel_num, pos, nullptr, hull_flag, vaporize, shipp->debris_damage_type_idx);
|
||||
if (obj != nullptr)
|
||||
{
|
||||
debris_create_set_velocity(&Debris[obj->instance], shipp, exp_center, exp_force);
|
||||
debris_create_set_velocity(&Debris[obj->instance], shipp, exp_center, exp_force, source_subsys);
|
||||
debris_create_fire_hook(obj, source_obj);
|
||||
}
|
||||
|
||||
@@ -669,7 +666,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
return obj;
|
||||
}
|
||||
|
||||
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force)
|
||||
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force, ship_subsys* source_subsys)
|
||||
{
|
||||
auto obj = &Objects[db->objnum];
|
||||
auto source_obj = (source_shipp == nullptr) ? nullptr : &Objects[source_shipp->objnum];
|
||||
@@ -690,7 +687,8 @@ void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_cente
|
||||
vec3d *min, *max;
|
||||
min = &pm->submodel[db->submodel_num].min;
|
||||
max = &pm->submodel[db->submodel_num].max;
|
||||
calc_debris_physics_properties( &obj->phys_info, min, max );
|
||||
float density = source_subsys != nullptr ? source_subsys->system_info->density : Ship_info[source_shipp->ship_info_index].debris_density;
|
||||
calc_debris_physics_properties( &obj->phys_info, min, max, density);
|
||||
}
|
||||
else {
|
||||
scale = exp_force * i2fl(Random::next(10, 29)); // for radial_vel away from blast center (non-hull)
|
||||
@@ -773,7 +771,7 @@ void debris_create_fire_hook(object *obj, object *source_obj)
|
||||
* Alas, poor debris_obj got whacked. Fortunately, we know who did it, where and how hard, so we
|
||||
* can do something about it.
|
||||
*/
|
||||
void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float damage)
|
||||
void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float damage, vec3d* force)
|
||||
{
|
||||
debris *debris_p = &Debris[debris_obj->instance];
|
||||
|
||||
@@ -813,6 +811,11 @@ void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float
|
||||
damage = 0.0f;
|
||||
}
|
||||
|
||||
if (hitpos && force && The_mission.ai_profile->flags[AI::Profile_Flags::Whackable_debris]) {
|
||||
vec3d rel_hit_pos = *hitpos - debris_obj->pos;
|
||||
physics_calculate_and_apply_whack(force, &rel_hit_pos, &debris_obj->phys_info, &debris_obj->orient, &debris_obj->phys_info.I_body_inv);
|
||||
}
|
||||
|
||||
debris_obj->hull_strength -= damage;
|
||||
|
||||
if (debris_obj->hull_strength < 0.0f) {
|
||||
@@ -833,7 +836,6 @@ void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float
|
||||
int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, collision_info_struct *debris_hit_info, vec3d* hitNormal)
|
||||
{
|
||||
mc_info mc;
|
||||
mc_info_init(&mc);
|
||||
|
||||
Assert( pdebris->type == OBJ_DEBRIS );
|
||||
|
||||
@@ -873,7 +875,7 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
|
||||
weapon *wp = &Weapons[other_obj->instance];
|
||||
wp->collisionInfo = new mc_info; // The weapon will free this memory later
|
||||
memcpy(wp->collisionInfo, &mc, sizeof(mc_info));
|
||||
*wp->collisionInfo = mc;
|
||||
|
||||
return mc.num_hits;
|
||||
}
|
||||
@@ -1115,7 +1117,7 @@ int debris_get_team(object *objp)
|
||||
/**
|
||||
* Fills in debris physics properties when created, specifically mass and moment of inertia
|
||||
*/
|
||||
void calc_debris_physics_properties( physics_info *pi, vec3d *mins, vec3d *maxs )
|
||||
void calc_debris_physics_properties( physics_info *pi, vec3d *mins, vec3d *maxs, float density )
|
||||
{
|
||||
float dx, dy, dz, mass;
|
||||
dx = maxs->xyz.x - mins->xyz.x;
|
||||
@@ -1124,7 +1126,7 @@ void calc_debris_physics_properties( physics_info *pi, vec3d *mins, vec3d *maxs
|
||||
|
||||
// John, with new bspgen, just set pi->mass = mass
|
||||
mass = 0.12f * dx * dy * dz;
|
||||
pi->mass = (float) pow(mass, 0.6666667f) * 4.65f;
|
||||
pi->mass = (float) pow(mass, 0.6666667f) * 4.65f * density;
|
||||
|
||||
pi->I_body_inv.vec.rvec.xyz.x = 12.0f / (pi->mass * (dy*dy + dz*dz));
|
||||
pi->I_body_inv.vec.rvec.xyz.y = 0.0f;
|
||||
|
||||
@@ -71,19 +71,19 @@ void debris_delete( object * obj );
|
||||
void debris_process_post( object * obj, float frame_time);
|
||||
|
||||
// Create debris, set velocity, and fire scripting hook
|
||||
object *debris_create( object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force );
|
||||
object *debris_create( object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force, ship_subsys* source_subsys = nullptr );
|
||||
|
||||
// Create debris but don't do anything else
|
||||
object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_type_index, int team, float hull_strength, int spark_timeout, int model_num, int submodel_num, vec3d *pos, matrix *orient, bool hull_flag, bool vaporize, int damage_type_idx);
|
||||
|
||||
// Set velocity after debris creation
|
||||
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force);
|
||||
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force, ship_subsys* source_subsys = nullptr);
|
||||
|
||||
// Fire scripting hook after debris creation
|
||||
void debris_create_fire_hook(object *obj, object *source_obj);
|
||||
|
||||
int debris_check_collision( object * obj, object * other_obj, vec3d * hitpos, collision_info_struct *debris_hit_info=NULL, vec3d* hitnormal = NULL );
|
||||
void debris_hit( object * debris_obj, object * other_obj, vec3d * hitpos, float damage );
|
||||
void debris_hit( object * debris_obj, object * other_obj, vec3d * hitpos, float damage, vec3d* force );
|
||||
int debris_get_team(object *objp);
|
||||
|
||||
void debris_add_to_hull_list(debris *db);
|
||||
|
||||
@@ -72,7 +72,10 @@ $Player Damage Factor: 0.25, 0.5, 0.65, 0.85, 1
|
||||
|
||||
;; factor applied to subsystem damage suffered by the player
|
||||
;; (in addition to Player Damage Factor)
|
||||
$Player Subsys Damage Factor: 0.2, 0.4, 0.6, 0.8, 1
|
||||
$Player Subsys Damage Factor: 0.2, 0.4, 0.6, 0.8, 1
|
||||
|
||||
;; factor applied to damage inflicted by the player
|
||||
$Player Damage Inflicted Factor: 1, 1, 1, 1, 1
|
||||
|
||||
;; measure of time (in F1_0 units) after which the AI will recalculate
|
||||
;; the position of its target
|
||||
|
||||
@@ -15,7 +15,8 @@ layout (std140) uniform genericData {
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 baseColor = texture(baseMap, fragTexCoord.xyz);
|
||||
float y = fragTexCoord.y / fragTexCoord.w;
|
||||
vec4 baseColor = texture(baseMap, vec3(fragTexCoord.x, y, fragTexCoord.z));
|
||||
|
||||
baseColor.rgb = srgb_to_linear(baseColor.rgb);
|
||||
vec4 blendColor = vec4(srgb_to_linear(fragColor.rgb), fragColor.a);
|
||||
|
||||
@@ -17,7 +17,7 @@ layout (std140) uniform genericData {
|
||||
|
||||
void main()
|
||||
{
|
||||
fragTexCoord = vec4(vertTexCoord.xyz, 0.0);
|
||||
fragColor = vertColor * color;
|
||||
gl_Position = projMatrix * modelViewMatrix * vertPosition;
|
||||
fragTexCoord = vertTexCoord;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragOut0 = texture(tex, fragTexCoord.xy);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ out vec4 fragOut1;
|
||||
out vec4 fragOut2;
|
||||
out vec4 fragOut3;
|
||||
out vec4 fragOut4;
|
||||
out vec4 fragOut5;
|
||||
void main()
|
||||
{
|
||||
fragOut0 = vec4(0.0, 0.0, 0.0, 1.0); // color
|
||||
@@ -10,4 +11,5 @@ void main()
|
||||
fragOut2 = vec4(0.0, 0.0, 0.0, 1.0); // normal
|
||||
fragOut3 = vec4(0.0, 0.0, 0.0, 0.0); // specular
|
||||
fragOut4 = vec4(0.0, 0.0, 0.0, 1.0); // emissive
|
||||
fragOut5 = vec4(0.0, 0.0, 0.0, 1.0); // composite
|
||||
}
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
#include "shadows.sdr" //! #include "shadows.sdr"
|
||||
|
||||
in vec3 beamVec;
|
||||
in vec3 lightPosition;
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D ColorBuffer;
|
||||
@@ -28,6 +26,11 @@ layout (std140) uniform globalDeferredData {
|
||||
float invScreenHeight;
|
||||
};
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
layout (std140) uniform lightData {
|
||||
vec3 diffuseLightColor;
|
||||
float coneAngle;
|
||||
@@ -63,23 +66,24 @@ vec3 ExpandLightSize(in vec3 lightDir, in vec3 reflectDir) {
|
||||
vec3 centerToRay = max(dot(lightDir, reflectDir),sourceRadius) * reflectDir - lightDir;
|
||||
return lightDir + centerToRay * clamp(sourceRadius/length(centerToRay), 0.0, 1.0);
|
||||
}
|
||||
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDir, out float attenuation, out float area_normalisation)
|
||||
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDirOut, out float attenuation, out float area_normalisation)
|
||||
{
|
||||
if (lightType == LT_DIRECTIONAL) {
|
||||
lightDir = normalize(lightPosition);
|
||||
lightDirOut = normalize(lightDir);
|
||||
attenuation = 1.0;
|
||||
area_normalisation = 1.0;
|
||||
} else {
|
||||
vec3 lightPosition = modelViewMatrix[3].xyz;
|
||||
// Positional light source
|
||||
if (lightType == LT_POINT) {
|
||||
lightDir = lightPosition - position.xyz;
|
||||
float dist = length(lightDir);
|
||||
lightDirOut = lightPosition - position.xyz;
|
||||
float dist = length(lightDirOut);
|
||||
|
||||
// this chunk is unneccessary if sourceRadius= 0.0, but let's avoid a branch.
|
||||
// given a sphere of radius sourceRadius centered at lightDir,
|
||||
// move lightDir towards the ray defined by reflectDir
|
||||
lightDir = ExpandLightSize(lightDir, reflectDir);
|
||||
dist = length(lightDir);
|
||||
// given a sphere of radius sourceRadius centered at lightDirOut,
|
||||
// move lightDirOut towards the ray defined by reflectDir
|
||||
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
|
||||
dist = length(lightDirOut);
|
||||
// Energy conservation term
|
||||
float alpha_adjust = clamp(alpha + (sourceRadius/(2*dist)), 0.0, 1.0);
|
||||
area_normalisation = alpha/alpha_adjust;
|
||||
@@ -93,7 +97,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
}
|
||||
else if (lightType == LT_TUBE) { // Tube light
|
||||
|
||||
vec3 beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
|
||||
vec3 beamDir = normalize(beamVec);
|
||||
//The actual 'lighting element' is shorter than the light volume cylinder
|
||||
//To compensate the light is moved forward along the beam one radius and the length shortened
|
||||
@@ -113,15 +117,15 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
vec3 r = d - a_t * dot(d, a_t) - c * dot(d,c);
|
||||
float neardist = dot(r, r)/dot(b_t, r);
|
||||
// Move along the beam by the distance we calculated
|
||||
lightDir = sourceDir - beamDir * clamp(neardist, 0.0, beamLength);
|
||||
lightDirOut = sourceDir - beamDir * clamp(neardist, 0.0, beamLength);
|
||||
// Somebody with a symbolic expression simplifier or a wrinklier brain than me
|
||||
// should figure out how to optimise these calcs - qaz
|
||||
|
||||
|
||||
// this chunk is unneccessary if sourceRadius = 0.0, but let's avoid a branch.
|
||||
// Same principle as in LT_POINT, treat chosen location as a spherelight.
|
||||
lightDir = ExpandLightSize(lightDir, reflectDir);
|
||||
float dist = length(lightDir);
|
||||
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
|
||||
float dist = length(lightDirOut);
|
||||
// Energy conservation term
|
||||
float alpha_adjust = min(alpha + (sourceRadius/(2*dist)), 1.0);
|
||||
area_normalisation = alpha/alpha_adjust;
|
||||
@@ -134,9 +138,9 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
}
|
||||
else if (lightType == LT_CONE) {
|
||||
lightDir = lightPosition - position.xyz;
|
||||
float coneDot = dot(normalize(-lightDir), coneDir);
|
||||
float dist = length(lightDir);
|
||||
lightDirOut = lightPosition - position.xyz;
|
||||
float coneDot = dot(normalize(-lightDirOut), coneDir);
|
||||
float dist = length(lightDirOut);
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
area_normalisation = 1.0;
|
||||
|
||||
@@ -155,7 +159,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
}
|
||||
}
|
||||
attenuation *= attenuation;
|
||||
lightDir = normalize(lightDir);
|
||||
lightDirOut = normalize(lightDirOut);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,17 +27,11 @@ layout (std140) uniform lightData {
|
||||
float sourceRadius;
|
||||
};
|
||||
|
||||
out vec3 lightPosition;
|
||||
out vec3 beamVec;
|
||||
void main()
|
||||
{
|
||||
if (lightType == LT_DIRECTIONAL) {
|
||||
gl_Position = vec4(vertPosition.xyz, 1.0);
|
||||
lightPosition = lightDir;
|
||||
} else {
|
||||
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
|
||||
lightPosition = modelViewMatrix[3].xyz;
|
||||
if(lightType == LT_TUBE)
|
||||
beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,14 @@
|
||||
#include "shadows.sdr" //! #include "shadows.sdr"
|
||||
#include "lighting.sdr" //! #include "lighting.sdr"
|
||||
#include "gamma.sdr" //! #include "gamma.sdr"
|
||||
#include "model_shader_flags.h"
|
||||
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
#define LT_DIRECTIONAL 0
|
||||
#define LT_POINT 1
|
||||
#define LT_TUBE 2
|
||||
#define LT_TUBE 2
|
||||
|
||||
struct model_light {
|
||||
vec4 position;
|
||||
|
||||
@@ -54,21 +56,14 @@ layout (std140) uniform modelData {
|
||||
int blend_alpha;
|
||||
|
||||
vec3 emissionFactor;
|
||||
bool overrideDiffuse_;
|
||||
|
||||
vec3 diffuseClr_;
|
||||
bool overrideGlow_;
|
||||
|
||||
vec3 glowClr_;
|
||||
bool overrideSpec_;
|
||||
|
||||
vec3 specClr_;
|
||||
bool alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
bool alpha_spec_;
|
||||
int effect_num;
|
||||
int sBasemapIndex;
|
||||
|
||||
|
||||
vec4 fogColor;
|
||||
|
||||
@@ -88,8 +83,6 @@ layout (std140) uniform modelData {
|
||||
float middist;
|
||||
float fardist;
|
||||
|
||||
vec2 normalAlphaMinMax_;
|
||||
int sBasemapIndex;
|
||||
int sGlowmapIndex;
|
||||
|
||||
int sSpecmapIndex;
|
||||
@@ -98,58 +91,31 @@ layout (std140) uniform modelData {
|
||||
int sMiscmapIndex;
|
||||
|
||||
float alphaMult;
|
||||
|
||||
int flags;
|
||||
};
|
||||
|
||||
in VertexOutput {
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vec3 envReflect;
|
||||
#endif
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#ifdef FLAG_FOG
|
||||
mat3 tangentMatrix;
|
||||
float fogDist;
|
||||
#endif
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
#ifdef FLAG_SHADOWS
|
||||
vec4 shadowUV[4];
|
||||
vec4 shadowPos;
|
||||
#endif
|
||||
} vertIn;
|
||||
|
||||
#ifdef FLAG_DIFFUSE_MAP
|
||||
uniform sampler2DArray sBasemap;
|
||||
#endif
|
||||
#ifdef FLAG_GLOW_MAP
|
||||
uniform sampler2DArray sGlowmap;
|
||||
#endif
|
||||
#ifdef FLAG_SPEC_MAP
|
||||
uniform sampler2DArray sSpecmap;
|
||||
#endif
|
||||
#ifdef FLAG_ENV_MAP
|
||||
uniform samplerCube sEnvmap;
|
||||
uniform samplerCube sIrrmap;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
uniform sampler2DArray sNormalmap;
|
||||
#endif
|
||||
#ifdef FLAG_AMBIENT_MAP
|
||||
uniform sampler2DArray sAmbientmap;
|
||||
#endif
|
||||
#ifdef FLAG_ANIMATED
|
||||
uniform sampler2D sFramebuffer;
|
||||
#endif
|
||||
#ifdef FLAG_TEAMCOLOR
|
||||
vec4 teamMask;
|
||||
#endif
|
||||
#ifdef FLAG_MISC_MAP
|
||||
uniform sampler2DArray sMiscmap;
|
||||
#endif
|
||||
#ifdef FLAG_SHADOWS
|
||||
uniform sampler2DArray shadow_map;
|
||||
#endif
|
||||
|
||||
out vec4 fragOut0;
|
||||
out vec4 fragOut1;
|
||||
@@ -216,81 +182,73 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
// need depth and depth squared for variance shadow maps
|
||||
fragOut0 = vec4(vertIn.position.z, vertIn.position.z * vertIn.position.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
|
||||
if (true) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
// need depth and depth squared for variance shadow maps
|
||||
fragOut0 = vec4(vertIn.position.z, vertIn.position.z * vertIn.position.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
|
||||
if (true) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
vec3 eyeDir = vec3(normalize(-vertIn.position).xyz);
|
||||
vec2 texCoord = vertIn.texCoord.xy;
|
||||
|
||||
// setup our baseline values for base, emissive, fresnel, gloss, AO and normal
|
||||
// default specular value is set below, as it depends on the diffuse color
|
||||
|
||||
vec4 baseColor = color;
|
||||
vec4 specColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
vec4 emissiveColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
float fresnelFactor = 0.0;
|
||||
float glossData = defaultGloss;
|
||||
vec2 aoFactors = vec2(1.0, 1.0);
|
||||
#ifdef FLAG_AMBIENT_MAP
|
||||
// red channel is ambient occlusion factor which only affects ambient lighting.
|
||||
// green is cavity occlusion factor which only affects diffuse and specular lighting.
|
||||
aoFactors = texture(sAmbientmap, vec3(texCoord, float(sAmbientmapIndex))).xy;
|
||||
#endif
|
||||
vec3 unitNormal = normalize(vertIn.normal);
|
||||
vec3 normal = unitNormal;
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
// Normal map - convert from DXT5nm
|
||||
vec2 normalSample;
|
||||
normal.rg = normalSample = (texture(sNormalmap, vec3(texCoord, float(sNormalmapIndex))).ag * 2.0) - 1.0;
|
||||
normal.b = clamp(sqrt(1.0 - dot(normal.rg, normal.rg)), 0.0001, 1.0);
|
||||
normal = vertIn.tangentMatrix * normal;
|
||||
float norm = length(normal);
|
||||
// prevent breaking of normal maps
|
||||
if (norm > 0.0)
|
||||
normal /= norm;
|
||||
else
|
||||
normal = unitNormal;
|
||||
#endif
|
||||
|
||||
#ifdef FLAG_ANIMATED
|
||||
vec2 distort = vec2(cos(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005),sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*cos(vertIn.position.y*vertIn.position.w*0.005))*0.03;
|
||||
#endif
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_AMBIENT)) {
|
||||
// red channel is ambient occlusion factor which only affects ambient lighting.
|
||||
// green is cavity occlusion factor which only affects diffuse and specular lighting.
|
||||
aoFactors = texture(sAmbientmap, vec3(texCoord, float(sAmbientmapIndex))).xy;
|
||||
}
|
||||
|
||||
#ifdef FLAG_DIFFUSE_MAP
|
||||
vec2 diffuseTexCoord = texCoord;
|
||||
#ifdef FLAG_ANIMATED
|
||||
if (effect_num == 2) {
|
||||
diffuseTexCoord = texCoord + distort*(1.0-anim_timer);
|
||||
}
|
||||
#endif
|
||||
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
|
||||
// Normal map - convert from DXT5nm
|
||||
vec2 normalSample;
|
||||
normal.rg = normalSample = (texture(sNormalmap, vec3(texCoord, float(sNormalmapIndex))).ag * 2.0) - 1.0;
|
||||
normal.b = clamp(sqrt(1.0 - dot(normal.rg, normal.rg)), 0.0001, 1.0);
|
||||
normal = vertIn.tangentMatrix * normal;
|
||||
float norm = length(normal);
|
||||
// prevent breaking of normal maps
|
||||
if (norm > 0.0)
|
||||
normal /= norm;
|
||||
else
|
||||
normal = unitNormal;
|
||||
}
|
||||
|
||||
#ifdef FLAG_ALPHA_MULT
|
||||
baseColor.a *= alphaMult;
|
||||
#endif
|
||||
vec2 distort = vec2(0.0, 0.0);
|
||||
|
||||
if ( blend_alpha == 0 && baseColor.a < 0.95 ) discard; // if alpha blending is not on, discard transparent pixels
|
||||
// premultiply alpha if blend_alpha is 1. assume that our blend function is srcColor + (1-Alpha)*destColor.
|
||||
// if blend_alpha is 2, assume blend func is additive and don't modify color
|
||||
if(blend_alpha == 1) baseColor.rgb = baseColor.rgb * baseColor.a;
|
||||
#endif
|
||||
specColor = vec4(baseColor.rgb * SPEC_FACTOR_NO_SPEC_MAP, glossData);
|
||||
#ifdef FLAG_HDR
|
||||
baseColor.rgb = srgb_to_linear(baseColor.rgb);
|
||||
#endif
|
||||
#ifdef FLAG_SPEC_MAP
|
||||
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
|
||||
if(alphaGloss) glossData = specColor.a;
|
||||
if(gammaSpec) {
|
||||
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
|
||||
fresnelFactor = 1.0;
|
||||
if (effect_num >= 0) {
|
||||
distort = vec2(cos(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005),sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*cos(vertIn.position.y*vertIn.position.w*0.005))*0.03;
|
||||
}
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
|
||||
vec2 diffuseTexCoord = texCoord;
|
||||
if (effect_num == 2) {
|
||||
diffuseTexCoord = texCoord + distort*(1.0-anim_timer);
|
||||
}
|
||||
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
baseColor.rgb = srgb_to_linear(baseColor.rgb);
|
||||
}
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
|
||||
baseColor.a *= alphaMult;
|
||||
}
|
||||
|
||||
if ( blend_alpha == 0 && baseColor.a < 0.95 ) discard; // if alpha blending is not on, discard transparent pixels
|
||||
// premultiply alpha if blend_alpha is 1. assume that our blend function is srcColor + (1-Alpha)*destColor.
|
||||
// if blend_alpha is 2, assume blend func is additive and don't modify color
|
||||
if(blend_alpha == 1) baseColor.rgb = baseColor.rgb * baseColor.a;
|
||||
}
|
||||
#ifdef FLAG_HDR
|
||||
specColor.rgb = srgb_to_linear(specColor.rgb);
|
||||
#endif
|
||||
#endif
|
||||
baseColor.rgb *= aoFactors.y;
|
||||
specColor.rgb *= aoFactors.y;
|
||||
|
||||
// Anti-glint "trick" based on Valve's "Advanced VR Rendering" talk at GDC2015:
|
||||
// http://media.steampowered.com/apps/valve/2015/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf Page 43
|
||||
@@ -300,176 +258,199 @@ void main()
|
||||
float glossGeo = 1.0f - pow(clamp(max(dot(normDx,normDx), dot(normDy,normDy)),0.0,1.0),0.33);
|
||||
glossData = min(glossData, glossGeo);
|
||||
|
||||
#ifdef FLAG_MISC_MAP
|
||||
#ifdef FLAG_TEAMCOLOR
|
||||
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
|
||||
|
||||
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
|
||||
//at this point is vec3(0.5). To get accurate results, we subtract 0.5 from the team colors
|
||||
vec3 color_offset = vec3(-0.5) * (teamMask.x + teamMask.y);
|
||||
|
||||
vec3 team_color = base_color * teamMask.x + stripe_color * teamMask.y + color_offset;
|
||||
vec3 team_color_glow = (base_color * teamMask.b) + (stripe_color * teamMask.a);
|
||||
|
||||
#ifdef FLAG_HDR
|
||||
baseColor.rgb = linear_to_srgb(baseColor.rgb);
|
||||
specColor.rgb = linear_to_srgb(specColor.rgb);
|
||||
#endif
|
||||
|
||||
baseColor.rgb += team_color;
|
||||
baseColor.rgb = max(baseColor.rgb, vec3(0.0)); // We need to make sure that nothing here ever goes negative
|
||||
specColor.rgb += team_color;
|
||||
specColor.rgb = max(specColor.rgb, vec3(0.03));
|
||||
|
||||
#ifdef FLAG_HDR
|
||||
baseColor.rgb = srgb_to_linear(baseColor.rgb);
|
||||
specColor.rgb = srgb_to_linear(specColor.rgb);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
// Now that we have a base color and min gloss value, compute the spec color
|
||||
vec4 specColor = vec4(baseColor.rgb * SPEC_FACTOR_NO_SPEC_MAP, glossData);
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
|
||||
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
|
||||
if(alphaGloss) glossData = specColor.a;
|
||||
if(gammaSpec) {
|
||||
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
|
||||
fresnelFactor = 1.0;
|
||||
}
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
specColor.rgb = srgb_to_linear(specColor.rgb);
|
||||
}
|
||||
}
|
||||
|
||||
baseColor.rgb *= aoFactors.y;
|
||||
specColor.rgb *= aoFactors.y;
|
||||
|
||||
vec4 teamMask = vec4(0.0);
|
||||
vec3 team_color_glow = vec3(0.0);
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_MISC)) {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TEAMCOLOR)) {
|
||||
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
|
||||
|
||||
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
|
||||
//at this point is vec3(0.5). To get accurate results, we subtract 0.5 from the team colors
|
||||
vec3 color_offset = vec3(-0.5) * (teamMask.x + teamMask.y);
|
||||
|
||||
vec3 team_color = base_color * teamMask.x + stripe_color * teamMask.y + color_offset;
|
||||
team_color_glow = (base_color * teamMask.b) + (stripe_color * teamMask.a);
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
baseColor.rgb = linear_to_srgb(baseColor.rgb);
|
||||
specColor.rgb = linear_to_srgb(specColor.rgb);
|
||||
}
|
||||
|
||||
baseColor.rgb += team_color;
|
||||
baseColor.rgb = max(baseColor.rgb, vec3(0.0)); // We need to make sure that nothing here ever goes negative
|
||||
specColor.rgb += team_color;
|
||||
specColor.rgb = max(specColor.rgb, vec3(0.03));
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
baseColor.rgb = srgb_to_linear(baseColor.rgb);
|
||||
specColor.rgb = srgb_to_linear(specColor.rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
|
||||
#ifdef FLAG_DEFERRED
|
||||
#ifdef FLAG_LIGHT
|
||||
// Ambient lighting still needs to be done since that counts as an "emissive" color
|
||||
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactors.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior
|
||||
emissiveColor.rgb += baseColor.rgb * lightAmbient;
|
||||
#else
|
||||
#ifdef FLAG_SPEC_MAP
|
||||
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
|
||||
#endif
|
||||
// If there is no lighting then we copy the color data so far into the
|
||||
emissiveColor.rgb += baseColor.rgb;
|
||||
#endif
|
||||
#else
|
||||
#ifdef FLAG_LIGHT
|
||||
float shadow = 1.0;
|
||||
#ifdef FLAG_SHADOWS
|
||||
shadow = getShadowValue(shadow_map, -vertIn.position.z, vertIn.shadowPos.z, vertIn.shadowUV, fardist, middist, neardist, veryneardist);
|
||||
#endif
|
||||
baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x);
|
||||
#else
|
||||
#ifdef FLAG_SPEC_MAP
|
||||
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_ENV_MAP
|
||||
#ifdef FLAG_LIGHT
|
||||
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
|
||||
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
|
||||
// to determine the mip bias.
|
||||
// We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
|
||||
// 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2)
|
||||
// so let s = (2/alpha^2 - 2)
|
||||
// 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1)
|
||||
|
||||
const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes
|
||||
const float REZ_BIAS = log2(ENV_REZ * sqrt(3));
|
||||
|
||||
float roughness = clamp(1.0f - glossData, 0.0f, 1.0f);
|
||||
float alpha = roughness * roughness;
|
||||
float alphaSqr = alpha * alpha;
|
||||
float rough_bias = 0.5 * log2(2/alphaSqr - 1);
|
||||
float mip_bias = REZ_BIAS - rough_bias;
|
||||
|
||||
// Sample light, using mip bias to blur it.
|
||||
vec3 light_dir = reflect(-eyeDir, normal);
|
||||
vec3 env_light_dir = vec3(envMatrix * vec4(light_dir, 0.0));
|
||||
vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias));
|
||||
|
||||
vec3 halfVec = normal;
|
||||
|
||||
// Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture
|
||||
// or properly calculating IBL levels.
|
||||
// Fresnel calculation as with standard lights.
|
||||
|
||||
vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a);
|
||||
|
||||
// Pseudo-IBL, so use k_IBL
|
||||
float k = alpha * alpha/ 2.0f;
|
||||
|
||||
float NdotL = max(dot(light_dir, normal),0);
|
||||
|
||||
float g1vNL = GeometrySchlickGGX(NdotL, k);
|
||||
vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL;
|
||||
|
||||
vec3 kD = vec3(1.0)-fresnel;
|
||||
kD *= (vec3(1.0) - specColor.rgb);
|
||||
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb);
|
||||
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x;
|
||||
emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_GLOW_MAP
|
||||
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
|
||||
#ifdef FLAG_MISC_MAP
|
||||
#ifdef FLAG_TEAMCOLOR
|
||||
float glowColorLuminance = dot(glowColor, vec3(0.299, 0.587, 0.114));
|
||||
glowColor = team_glow_enabled ? mix(max(team_color_glow, vec3(0.0)), glowColor, clamp(glowColorLuminance - teamMask.b - teamMask.a, 0.0, 1.0)) : glowColor;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_HDR
|
||||
glowColor = srgb_to_linear(glowColor) * GLOW_MAP_SRGB_MULTIPLIER;
|
||||
#endif
|
||||
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
|
||||
#endif
|
||||
|
||||
#ifdef FLAG_FOG
|
||||
vec3 finalFogColor = fogColor.rgb;
|
||||
#ifdef FLAG_HDR
|
||||
finalFogColor = srgb_to_linear(finalFogColor);
|
||||
#endif
|
||||
#ifdef FLAG_DIFFUSE_MAP
|
||||
if(blend_alpha == 1) finalFogColor *= baseColor.a;
|
||||
#endif
|
||||
// This code will only be used by the forward renderer so we apply the fog effect to both the emissive and the base
|
||||
// color.
|
||||
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, vertIn.fogDist);
|
||||
emissiveColor.rgb = vec3(0.0); // Zero the emissive color since it has already been added by the previous line
|
||||
specColor.rgb *= vertIn.fogDist;
|
||||
#endif
|
||||
|
||||
#ifdef FLAG_DIFFUSE_MAP
|
||||
if(desaturate == 1) {
|
||||
baseColor.rgb = color.rgb * dot(vec3(1.0), baseColor.rgb) * 0.3333333;
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED)) {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
|
||||
// Ambient lighting still needs to be done since that counts as an "emissive" color
|
||||
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactors.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior
|
||||
emissiveColor.rgb += baseColor.rgb * lightAmbient;
|
||||
} else {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
|
||||
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
|
||||
}
|
||||
// If there is no lighting then we copy the color data so far into the
|
||||
emissiveColor.rgb += baseColor.rgb;
|
||||
}
|
||||
} else {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
|
||||
float shadow = 1.0;
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
|
||||
shadow = getShadowValue(shadow_map, -vertIn.position.z, vertIn.shadowPos.z, vertIn.shadowUV, fardist, middist, neardist, veryneardist);
|
||||
}
|
||||
baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x);
|
||||
} else {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
|
||||
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
|
||||
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
|
||||
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
|
||||
// to determine the mip bias.
|
||||
// We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
|
||||
// 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2)
|
||||
// so let s = (2/alpha^2 - 2)
|
||||
// 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1)
|
||||
|
||||
const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes
|
||||
const float REZ_BIAS = log2(ENV_REZ * sqrt(3));
|
||||
|
||||
float roughness = clamp(1.0f - glossData, 0.0f, 1.0f);
|
||||
float alpha = roughness * roughness;
|
||||
float alphaSqr = alpha * alpha;
|
||||
float rough_bias = 0.5 * log2(2/alphaSqr - 1);
|
||||
float mip_bias = REZ_BIAS - rough_bias;
|
||||
|
||||
// Sample light, using mip bias to blur it.
|
||||
vec3 light_dir = reflect(-eyeDir, normal);
|
||||
vec3 env_light_dir = vec3(envMatrix * vec4(light_dir, 0.0));
|
||||
vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias));
|
||||
|
||||
vec3 halfVec = normal;
|
||||
|
||||
// Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture
|
||||
// or properly calculating IBL levels.
|
||||
// Fresnel calculation as with standard lights.
|
||||
|
||||
vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a);
|
||||
|
||||
// Pseudo-IBL, so use k_IBL
|
||||
float k = alpha * alpha/ 2.0f;
|
||||
|
||||
float NdotL = max(dot(light_dir, normal),0);
|
||||
|
||||
float g1vNL = GeometrySchlickGGX(NdotL, k);
|
||||
vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL;
|
||||
|
||||
vec3 kD = vec3(1.0)-fresnel;
|
||||
kD *= (vec3(1.0) - specColor.rgb);
|
||||
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb);
|
||||
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x;
|
||||
emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a;
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_GLOW)) {
|
||||
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_MISC)) {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TEAMCOLOR)) {
|
||||
float glowColorLuminance = dot(glowColor, vec3(0.299, 0.587, 0.114));
|
||||
glowColor = team_glow_enabled ? mix(max(team_color_glow, vec3(0.0)), glowColor, clamp(glowColorLuminance - teamMask.b - teamMask.a, 0.0, 1.0)) : glowColor;
|
||||
}
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
glowColor = srgb_to_linear(glowColor) * GLOW_MAP_SRGB_MULTIPLIER;
|
||||
}
|
||||
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
|
||||
}
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
|
||||
vec3 finalFogColor = fogColor.rgb;
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
finalFogColor = srgb_to_linear(finalFogColor);
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
|
||||
if(blend_alpha == 1) finalFogColor *= baseColor.a;
|
||||
}
|
||||
// This code will only be used by the forward renderer so we apply the fog effect to both the emissive and the base
|
||||
// color.
|
||||
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, vertIn.fogDist);
|
||||
emissiveColor.rgb = vec3(0.0); // Zero the emissive color since it has already been added by the previous line
|
||||
specColor.rgb *= vertIn.fogDist;
|
||||
}
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
|
||||
if(desaturate == 1) {
|
||||
baseColor.rgb = color.rgb * dot(vec3(1.0), baseColor.rgb) * 0.3333333;
|
||||
}
|
||||
}
|
||||
|
||||
if (effect_num == 0) {
|
||||
float shinefactor = 1.0/(1.0 + pow(abs((fract(abs(texCoord.x))-anim_timer) * 1000.0), 2.0)) * 1000.0;
|
||||
emissiveColor.rgb += vec3(shinefactor);
|
||||
baseColor.a = baseColor.a * clamp(shinefactor * (fract(abs(texCoord.x))-anim_timer) * -10000.0,0.0,1.0);
|
||||
} else if (effect_num == 1) {
|
||||
float shinefactor = 1.0/(1.0 + pow(abs(vertIn.position.y-anim_timer), 2.0));
|
||||
emissiveColor.rgb += vec3(shinefactor);
|
||||
if (!(FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT))) {
|
||||
// ATI Wireframe fix *grumble*
|
||||
baseColor.a = clamp((vertIn.position.y-anim_timer) * 10000.0,0.0,1.0);
|
||||
}
|
||||
} else if (effect_num == 2) {
|
||||
vec2 screenPos = gl_FragCoord.xy * vec2(vpwidth,vpheight);
|
||||
baseColor.a = baseColor.a;
|
||||
float cloak_interp = (sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005)*0.5)-0.5;
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
|
||||
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
|
||||
} else {
|
||||
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*vertIn.normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
|
||||
}
|
||||
}
|
||||
|
||||
if (!(FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED))) {
|
||||
// emissive colors won't be added later when we are using forward rendering so we need to do that here
|
||||
baseColor.rgb += emissiveColor.rgb;
|
||||
}
|
||||
#endif
|
||||
#ifdef FLAG_ANIMATED
|
||||
if (effect_num == 0) {
|
||||
float shinefactor = 1.0/(1.0 + pow(abs((fract(abs(texCoord.x))-anim_timer) * 1000.0), 2.0)) * 1000.0;
|
||||
emissiveColor.rgb += vec3(shinefactor);
|
||||
baseColor.a = baseColor.a * clamp(shinefactor * (fract(abs(texCoord.x))-anim_timer) * -10000.0,0.0,1.0);
|
||||
}
|
||||
if (effect_num == 1) {
|
||||
float shinefactor = 1.0/(1.0 + pow(abs(vertIn.position.y-anim_timer), 2.0));
|
||||
emissiveColor.rgb += vec3(shinefactor);
|
||||
#ifndef FLAG_LIGHT
|
||||
// ATI Wireframe fix *grumble*
|
||||
baseColor.a = clamp((vertIn.position.y-anim_timer) * 10000.0,0.0,1.0);
|
||||
#endif
|
||||
}
|
||||
if (effect_num == 2) {
|
||||
vec2 screenPos = gl_FragCoord.xy * vec2(vpwidth,vpheight);
|
||||
baseColor.a = baseColor.a;
|
||||
float cloak_interp = (sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005)*0.5)-0.5;
|
||||
#ifdef FLAG_LIGHT
|
||||
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
|
||||
#else
|
||||
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*vertIn.normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifndef FLAG_DEFERRED
|
||||
// emissive colors won't be added later when we are using forward rendering so we need to do that here
|
||||
baseColor.rgb += emissiveColor.rgb;
|
||||
#endif
|
||||
|
||||
fragOut0 = baseColor;
|
||||
#ifdef FLAG_DEFERRED
|
||||
fragOut1 = vec4(vertIn.position.xyz, 1.0);
|
||||
fragOut2 = vec4(normal, glossData);
|
||||
fragOut3 = vec4(specColor.rgb, fresnelFactor);
|
||||
fragOut4 = emissiveColor;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED)) {
|
||||
fragOut1 = vec4(vertIn.position.xyz, 1.0);
|
||||
fragOut2 = vec4(normal, glossData);
|
||||
fragOut3 = vec4(specColor.rgb, fresnelFactor);
|
||||
fragOut4 = emissiveColor;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
#extension GL_ARB_gpu_shader5: enable
|
||||
|
||||
#include "model_shader_flags.h"
|
||||
|
||||
#ifdef FLAG_THICK_OUTLINE
|
||||
layout (triangles) in;
|
||||
// For every triangle line we generate 2 triangles which can be done with 4 vertices so in total we will need 12 vertices
|
||||
layout (triangle_strip, max_vertices = 12) out;
|
||||
#else
|
||||
#elif defined(FLAG_SHADOW_MAP)
|
||||
layout (triangles) in;
|
||||
layout (triangle_strip, max_vertices = 3) out;
|
||||
#endif
|
||||
@@ -61,21 +63,13 @@ layout (std140) uniform modelData {
|
||||
int blend_alpha;
|
||||
|
||||
vec3 emissionFactor;
|
||||
bool overrideDiffuse_;
|
||||
|
||||
vec3 diffuseClr_;
|
||||
bool overrideGlow_;
|
||||
|
||||
vec3 glowClr_;
|
||||
bool overrideSpec_;
|
||||
|
||||
vec3 specClr_;
|
||||
bool alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
bool alpha_spec_;
|
||||
int effect_num;
|
||||
int sBasemapIndex;
|
||||
|
||||
vec4 fogColor;
|
||||
|
||||
@@ -95,8 +89,6 @@ layout (std140) uniform modelData {
|
||||
float middist;
|
||||
float fardist;
|
||||
|
||||
vec2 normalAlphaMinMax_;
|
||||
int sBasemapIndex;
|
||||
int sGlowmapIndex;
|
||||
|
||||
int sSpecmapIndex;
|
||||
@@ -105,160 +97,146 @@ layout (std140) uniform modelData {
|
||||
int sMiscmapIndex;
|
||||
|
||||
float alphaMult;
|
||||
|
||||
int flags;
|
||||
};
|
||||
|
||||
in VertexOutput {
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vec3 envReflect;
|
||||
#endif
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#ifdef FLAG_FOG
|
||||
mat3 tangentMatrix;
|
||||
float fogDist;
|
||||
#endif
|
||||
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
float instance;
|
||||
#endif
|
||||
#ifdef FLAG_TRANSFORM
|
||||
float clipModel;
|
||||
#endif
|
||||
#else
|
||||
vec4 position;
|
||||
#endif
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
#ifdef FLAG_SHADOWS
|
||||
vec4 shadowUV[4];
|
||||
vec4 shadowPos;
|
||||
#endif
|
||||
} vertIn[];
|
||||
|
||||
out VertexOutput {
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vec3 envReflect;
|
||||
#endif
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#ifdef FLAG_FOG
|
||||
mat3 tangentMatrix;
|
||||
float fogDist;
|
||||
#endif
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
#ifdef FLAG_SHADOWS
|
||||
vec4 shadowUV[4];
|
||||
vec4 shadowPos;
|
||||
#endif
|
||||
} vertOut;
|
||||
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
void main(void)
|
||||
{
|
||||
#ifdef GL_ARB_gpu_shader5
|
||||
int instanceID = gl_InvocationID;
|
||||
#else
|
||||
int instanceID = int(vertIn[0].instance);
|
||||
#endif
|
||||
for(int vert = 0; vert < gl_in.length(); vert++)
|
||||
void main(void)
|
||||
{
|
||||
#ifdef FLAG_TRANSFORM
|
||||
if (vertIn[vert].clipModel > 0.9) {
|
||||
// If the model was clipped in the vertex shader then we do not apply the shadow projection matrix here
|
||||
gl_Position = gl_in[vert].gl_Position;
|
||||
} else {
|
||||
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
|
||||
}
|
||||
#else
|
||||
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
|
||||
#endif
|
||||
if(gl_Position.z < -1.0)
|
||||
#ifdef GL_ARB_gpu_shader5
|
||||
int instanceID = gl_InvocationID;
|
||||
#else
|
||||
int instanceID = int(vertIn[0].instance);
|
||||
#endif
|
||||
for(int vert = 0; vert < gl_in.length(); vert++)
|
||||
{
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
|
||||
if (vertIn[vert].clipModel > 0.9) {
|
||||
// If the model was clipped in the vertex shader then we do not apply the shadow projection matrix here
|
||||
gl_Position = gl_in[vert].gl_Position;
|
||||
} else {
|
||||
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
|
||||
}
|
||||
} else {
|
||||
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
|
||||
}
|
||||
if(gl_Position.z < -1.0)
|
||||
gl_Position.z = -1.0;
|
||||
|
||||
vertOut.position = gl_in[vert].gl_Position;
|
||||
vertOut.normal = vertIn[vert].normal;
|
||||
vertOut.texCoord = vertIn[vert].texCoord;
|
||||
|
||||
gl_Layer = instanceID;
|
||||
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
|
||||
#endif
|
||||
#ifdef FLAG_FOG
|
||||
vertOut.fogDist = vertIn[vert].fogDist;
|
||||
#endif
|
||||
#ifdef FLAG_SHADOWS
|
||||
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
|
||||
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
|
||||
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
|
||||
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
|
||||
vertOut.shadowPos = vertIn[vert].shadowPos;
|
||||
#endif
|
||||
#if defined(FLAG_CLIP)
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
#endif
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
#elif defined(FLAG_THICK_OUTLINE)
|
||||
const vec2 pixelOffsetDir[4] = vec2[](
|
||||
vec2(0.0, 1.0),
|
||||
vec2(1.0, 1.0),
|
||||
vec2(1.0, -1.0),
|
||||
vec2(0.0, -1.0)
|
||||
);
|
||||
void main(void)
|
||||
{
|
||||
for(int vert = 0; vert < gl_in.length(); vert++)
|
||||
{
|
||||
int nextVert = (vert + 1) % gl_in.length();
|
||||
vec4 clip = gl_in[vert].gl_Position;
|
||||
vec4 diff = gl_in[nextVert].gl_Position - clip; // vector from vert to the next vertex in the list
|
||||
vec2 normal = normalize(vec2(diff.y, -diff.x)); // Computing the normal of a 2D vector is actually rather simple...
|
||||
for (int lineVert = 0; lineVert < 4; ++lineVert)
|
||||
{
|
||||
// This is the pixel offset along the normal axis
|
||||
vec2 yOffPixel = pixelOffsetDir[lineVert].y * normal * (outlineWidth / 2.0);
|
||||
// This is the offset of the vertex along the vector between this vertex and the next one in the triangle
|
||||
vec2 xOff = pixelOffsetDir[lineVert].x * diff.xy;
|
||||
|
||||
// This is the final offset in clip space
|
||||
vec2 finalOffset = xOff + yOffPixel * vec2(vpwidth, vpheight) * clip.w;
|
||||
|
||||
gl_Position = vec4(clip.xyz + vec3(finalOffset, 0.0), clip.w);
|
||||
vertOut.position = vertIn[vert].position;
|
||||
vertOut.position = gl_in[vert].gl_Position;
|
||||
vertOut.normal = vertIn[vert].normal;
|
||||
vertOut.texCoord = vertIn[vert].texCoord;
|
||||
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
|
||||
#endif
|
||||
#ifdef FLAG_FOG
|
||||
vertOut.fogDist = vertIn[vert].fogDist;
|
||||
#endif
|
||||
#ifdef FLAG_SHADOWS
|
||||
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
|
||||
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
|
||||
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
|
||||
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
|
||||
vertOut.shadowPos = vertIn[vert].shadowPos;
|
||||
#endif
|
||||
#if defined(FLAG_CLIP)
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
#endif
|
||||
gl_Layer = instanceID;
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
|
||||
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
|
||||
vertOut.fogDist = vertIn[vert].fogDist;
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
|
||||
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
|
||||
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
|
||||
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
|
||||
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
|
||||
vertOut.shadowPos = vertIn[vert].shadowPos;
|
||||
}
|
||||
if (use_clip_plane) {
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
}
|
||||
EmitVertex();
|
||||
}
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
#elif defined(FLAG_THICK_OUTLINE)
|
||||
const vec2 pixelOffsetDir[4] = vec2[](
|
||||
vec2(0.0, 1.0),
|
||||
vec2(1.0, 1.0),
|
||||
vec2(1.0, -1.0),
|
||||
vec2(0.0, -1.0)
|
||||
);
|
||||
|
||||
void main(void)
|
||||
{
|
||||
for(int vert = 0; vert < gl_in.length(); vert++)
|
||||
{
|
||||
int nextVert = (vert + 1) % gl_in.length();
|
||||
vec4 clip = gl_in[vert].gl_Position;
|
||||
vec4 diff = gl_in[nextVert].gl_Position - clip; // vector from vert to the next vertex in the list
|
||||
vec2 normal = normalize(vec2(diff.y, -diff.x)); // Computing the normal of a 2D vector is actually rather simple...
|
||||
for (int lineVert = 0; lineVert < 4; ++lineVert)
|
||||
{
|
||||
// This is the pixel offset along the normal axis
|
||||
vec2 yOffPixel = pixelOffsetDir[lineVert].y * normal * (outlineWidth / 2.0);
|
||||
// This is the offset of the vertex along the vector between this vertex and the next one in the triangle
|
||||
vec2 xOff = pixelOffsetDir[lineVert].x * diff.xy;
|
||||
|
||||
// This is the final offset in clip space
|
||||
vec2 finalOffset = xOff + yOffPixel * vec2(vpwidth, vpheight) * clip.w;
|
||||
|
||||
gl_Position = vec4(clip.xyz + vec3(finalOffset, 0.0), clip.w);
|
||||
vertOut.position = vertIn[vert].position;
|
||||
vertOut.normal = vertIn[vert].normal;
|
||||
vertOut.texCoord = vertIn[vert].texCoord;
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
|
||||
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
|
||||
vertOut.fogDist = vertIn[vert].fogDist;
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
|
||||
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
|
||||
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
|
||||
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
|
||||
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
|
||||
vertOut.shadowPos = vertIn[vert].shadowPos;
|
||||
}
|
||||
if (use_clip_plane) {
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
}
|
||||
EmitVertex();
|
||||
}
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -2,6 +2,7 @@
|
||||
#extension GL_ARB_gpu_shader5: enable
|
||||
|
||||
#include "shadows.sdr"
|
||||
#include "model_shader_flags.h"
|
||||
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
@@ -56,21 +57,13 @@ layout (std140) uniform modelData {
|
||||
int blend_alpha;
|
||||
|
||||
vec3 emissionFactor;
|
||||
bool overrideDiffuse_;
|
||||
|
||||
vec3 diffuseClr_;
|
||||
bool overrideGlow_;
|
||||
|
||||
vec3 glowClr_;
|
||||
bool overrideSpec_;
|
||||
|
||||
vec3 specClr_;
|
||||
bool alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
bool alpha_spec_;
|
||||
int effect_num;
|
||||
int sBasemapIndex;
|
||||
|
||||
vec4 fogColor;
|
||||
|
||||
@@ -90,8 +83,6 @@ layout (std140) uniform modelData {
|
||||
float middist;
|
||||
float fardist;
|
||||
|
||||
vec2 normalAlphaMinMax_;
|
||||
int sBasemapIndex;
|
||||
int sGlowmapIndex;
|
||||
|
||||
int sSpecmapIndex;
|
||||
@@ -100,41 +91,32 @@ layout (std140) uniform modelData {
|
||||
int sMiscmapIndex;
|
||||
|
||||
float alphaMult;
|
||||
|
||||
int flags;
|
||||
};
|
||||
|
||||
#ifdef FLAG_TRANSFORM
|
||||
uniform samplerBuffer transform_tex;
|
||||
#endif
|
||||
|
||||
out VertexOutput {
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vec3 envReflect;
|
||||
#endif
|
||||
mat3 tangentMatrix;
|
||||
#ifdef FLAG_FOG
|
||||
mat3 tangentMatrix;
|
||||
float fogDist;
|
||||
#endif
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
float instance;
|
||||
#endif
|
||||
#ifdef FLAG_TRANSFORM
|
||||
// This flag is needed to let the geometry shader know that it doesn't need to apply the
|
||||
// shadow projection to gl_Position
|
||||
float clipModel;
|
||||
#endif
|
||||
#else
|
||||
vec4 position;
|
||||
#endif
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
#ifdef FLAG_SHADOWS
|
||||
vec4 shadowUV[4];
|
||||
vec4 shadowPos;
|
||||
#endif
|
||||
} vertOut;
|
||||
|
||||
#ifdef FLAG_TRANSFORM
|
||||
#define TEXELS_PER_MATRIX 4
|
||||
void getModelTransform(inout mat4 transform, out bool invisible, int id, int matrix_offset)
|
||||
{
|
||||
@@ -145,7 +127,7 @@ void getModelTransform(inout mat4 transform, out bool invisible, int id, int mat
|
||||
invisible = transform[3].w >= 0.9;
|
||||
transform[3].w = 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position;
|
||||
@@ -153,76 +135,77 @@ void main()
|
||||
vec4 texCoord;
|
||||
mat4 orient = mat4(1.0);
|
||||
mat4 scale = mat4(1.0);
|
||||
#ifdef FLAG_TRANSFORM
|
||||
bool clipModel;
|
||||
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
|
||||
#endif
|
||||
bool clipModel = false;
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
|
||||
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
|
||||
}
|
||||
texCoord = textureMatrix * vertTexCoord;
|
||||
vec4 vertex = vertPosition;
|
||||
#ifdef FLAG_THRUSTER
|
||||
if(vertex.z < -1.5) {
|
||||
vertex.z *= thruster_scale;
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_THRUSTER)) {
|
||||
if(vertex.z < -1.5) {
|
||||
vertex.z *= thruster_scale;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Transform the normal into eye space and normalize the result.
|
||||
// Transform the normal into eye space and normalize the result.
|
||||
normal = normalize(mat3(modelViewMatrix) * mat3(orient) * vertNormal);
|
||||
position = modelViewMatrix * orient * vertex;
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
gl_Position = position;
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
#ifdef APPLE
|
||||
vertOut.instance = float(gl_InstanceIDARB);
|
||||
#else
|
||||
vertOut.instance = float(gl_InstanceID);
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
gl_Position = projMatrix * position;
|
||||
#endif
|
||||
#ifdef FLAG_SHADOWS
|
||||
vec4 shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
|
||||
vertOut.shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
|
||||
vertOut.shadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, shadowPos);
|
||||
vertOut.shadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, shadowPos);
|
||||
vertOut.shadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, shadowPos);
|
||||
vertOut.shadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, shadowPos);
|
||||
#endif
|
||||
|
||||
// Setup stuff for normal maps and envmaps
|
||||
vec3 t = normalize(mat3(modelViewMatrix) * mat3(orient) * vertTangent.xyz);
|
||||
vec3 b = cross(normal, t) * vertTangent.w;
|
||||
vertOut.tangentMatrix = mat3(t, b, normal);
|
||||
|
||||
#ifdef FLAG_ENV_MAP
|
||||
// Environment mapping reflection vector.
|
||||
vec3 envReflect = reflect(normalize(position.xyz), normal);
|
||||
vertOut.envReflect = vec3(envMatrix * vec4(envReflect, 0.0));
|
||||
#endif
|
||||
#ifdef FLAG_FOG
|
||||
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
|
||||
#endif
|
||||
#ifdef FLAG_TRANSFORM
|
||||
if (clipModel) {
|
||||
// Clip this model by moving all vertices outside the clip volume
|
||||
gl_Position = vec4(vec3(-2.0), 1.0);
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
gl_Position = position;
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
#ifdef APPLE
|
||||
vertOut.instance = float(gl_InstanceIDARB);
|
||||
#else
|
||||
vertOut.instance = float(gl_InstanceID);
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
gl_Position = projMatrix * position;
|
||||
#endif
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
|
||||
vec4 shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
|
||||
vertOut.shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
|
||||
vertOut.shadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, shadowPos);
|
||||
vertOut.shadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, shadowPos);
|
||||
vertOut.shadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, shadowPos);
|
||||
vertOut.shadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, shadowPos);
|
||||
}
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
vertOut.clipModel = clipModel ? 1.0 : 0.0;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_CLIP
|
||||
|
||||
// Setup stuff for normal maps and envmaps
|
||||
vec3 t = normalize(mat3(modelViewMatrix) * mat3(orient) * vertTangent.xyz);
|
||||
vec3 b = cross(normal, t) * vertTangent.w;
|
||||
vertOut.tangentMatrix = mat3(t, b, normal);
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
|
||||
// Environment mapping reflection vector.
|
||||
vec3 envReflect = reflect(normalize(position.xyz), normal);
|
||||
vertOut.envReflect = vec3(envMatrix * vec4(envReflect, 0.0));
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
|
||||
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
|
||||
if (clipModel) {
|
||||
// Clip this model by moving all vertices outside the clip volume
|
||||
gl_Position = vec4(vec3(-2.0), 1.0);
|
||||
}
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
vertOut.clipModel = clipModel ? 1.0 : 0.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(use_clip_plane) {
|
||||
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
|
||||
} else {
|
||||
gl_ClipDistance[0] = 1.0;
|
||||
}
|
||||
#endif
|
||||
#ifndef FLAG_SHADOW_MAP
|
||||
vertOut.position = position;
|
||||
vertOut.normal = normal;
|
||||
vertOut.texCoord = texCoord;
|
||||
#else
|
||||
vertOut.normal = normal;
|
||||
vertOut.texCoord = texCoord;
|
||||
#endif
|
||||
|
||||
#ifndef FLAG_SHADOW_MAP
|
||||
vertOut.position = position;
|
||||
vertOut.normal = normal;
|
||||
vertOut.texCoord = texCoord;
|
||||
#else
|
||||
vertOut.normal = normal;
|
||||
vertOut.texCoord = texCoord;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#define MODEL_SDR_FLAG_LIGHT (1 << 0)
|
||||
#define MODEL_SDR_FLAG_DEFERRED (1 << 1)
|
||||
#define MODEL_SDR_FLAG_HDR (1 << 2)
|
||||
#define MODEL_SDR_FLAG_DIFFUSE (1 << 3)
|
||||
#define MODEL_SDR_FLAG_GLOW (1 << 4)
|
||||
#define MODEL_SDR_FLAG_SPEC (1 << 5)
|
||||
#define MODEL_SDR_FLAG_ENV (1 << 6)
|
||||
#define MODEL_SDR_FLAG_NORMAL (1 << 7)
|
||||
#define MODEL_SDR_FLAG_AMBIENT (1 << 8)
|
||||
#define MODEL_SDR_FLAG_MISC (1 << 9)
|
||||
#define MODEL_SDR_FLAG_TEAMCOLOR (1 << 10)
|
||||
#define MODEL_SDR_FLAG_FOG (1 << 11)
|
||||
#define MODEL_SDR_FLAG_TRANSFORM (1 << 12)
|
||||
#define MODEL_SDR_FLAG_SHADOWS (1 << 13)
|
||||
#define MODEL_SDR_FLAG_THRUSTER (1 << 14)
|
||||
#define MODEL_SDR_FLAG_ALPHA_MULT (1 << 15)
|
||||
|
||||
|
||||
#define FLAG_ACTIVE(flag) (flags & flag) != 0
|
||||
@@ -0,0 +1,198 @@
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
out vec4 fragOut1;
|
||||
out vec4 fragOut2;
|
||||
out vec4 fragOut3;
|
||||
out vec4 fragOut4;
|
||||
out vec4 fragOut5;
|
||||
out float gl_FragDepth;
|
||||
|
||||
uniform sampler2DMS texColor;
|
||||
uniform sampler2DMS texPos;
|
||||
uniform sampler2DMS texNormal;
|
||||
uniform sampler2DMS texSpecular;
|
||||
uniform sampler2DMS texEmissive;
|
||||
uniform sampler2DMS texDepth;
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
int samples;
|
||||
float fov;
|
||||
};
|
||||
|
||||
const float voxelDepth = 2.5f;
|
||||
const float voxelDepthFalloff = 2.5f;
|
||||
|
||||
#define SORT(a, b) if (a > b) { float t = dists[a]; dists[a] = dists[b]; dists[b] = t; }
|
||||
|
||||
//The following sorting networks for median calculation are NOT complete. Calculations that don't affect the
|
||||
//median entry are removed, and thus, while the median element is correct, the rest of the array is NOT fully sorted
|
||||
|
||||
#ifdef SAMPLES_4
|
||||
|
||||
float getMedianDist(ivec2 texel) {
|
||||
float dists[4];
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
dists[i] = texelFetch(texPos, texel, i).z;
|
||||
}
|
||||
|
||||
SORT(0, 2)
|
||||
SORT(1, 3)
|
||||
SORT(0, 1)
|
||||
SORT(2, 3)
|
||||
SORT(1, 2)
|
||||
|
||||
return dists[1];
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef SAMPLES_8
|
||||
|
||||
float getMedianDist(ivec2 texel) {
|
||||
float dists[8];
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
dists[i] = texelFetch(texPos, texel, i).z;
|
||||
}
|
||||
|
||||
SORT(0, 4)
|
||||
SORT(1, 5)
|
||||
SORT(2, 6)
|
||||
SORT(3, 7)
|
||||
SORT(0, 2)
|
||||
SORT(1, 3)
|
||||
SORT(4, 6)
|
||||
SORT(5, 7)
|
||||
SORT(2, 4)
|
||||
SORT(3, 5)
|
||||
SORT(0, 1)
|
||||
SORT(2, 3)
|
||||
SORT(4, 5)
|
||||
SORT(6, 7)
|
||||
SORT(1, 4)
|
||||
SORT(3, 6)
|
||||
SORT(3, 4)
|
||||
|
||||
return dists[3];
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef SAMPLES_16
|
||||
|
||||
float getMedianDist(ivec2 texel) {
|
||||
float dists[16];
|
||||
|
||||
for(int i = 0; i < 16; i++) {
|
||||
dists[i] = texelFetch(texPos, texel, i).z;
|
||||
}
|
||||
|
||||
SORT(0, 1)
|
||||
SORT(2, 3)
|
||||
SORT(4, 5)
|
||||
SORT(6, 7)
|
||||
SORT(8, 9)
|
||||
SORT(10, 11)
|
||||
SORT(12, 13)
|
||||
SORT(14, 15)
|
||||
SORT(0, 2)
|
||||
SORT(4, 6)
|
||||
SORT(8, 10)
|
||||
SORT(12, 14)
|
||||
SORT(1, 3)
|
||||
SORT(5, 7)
|
||||
SORT(9, 11)
|
||||
SORT(13, 15)
|
||||
SORT(0, 4)
|
||||
SORT(1, 5)
|
||||
SORT(2, 6)
|
||||
SORT(3, 7)
|
||||
SORT(8, 12)
|
||||
SORT(9, 13)
|
||||
SORT(10, 14)
|
||||
SORT(11, 15)
|
||||
SORT(0, 8)
|
||||
SORT(1, 9)
|
||||
SORT(2, 10)
|
||||
SORT(3, 11)
|
||||
SORT(4, 12)
|
||||
SORT(5, 13)
|
||||
SORT(6, 14)
|
||||
SORT(7, 15)
|
||||
SORT(5, 10)
|
||||
SORT(6, 9)
|
||||
SORT(3, 12)
|
||||
SORT(13, 14)
|
||||
SORT(7, 11)
|
||||
SORT(1, 2)
|
||||
SORT(4, 8)
|
||||
SORT(7, 13)
|
||||
SORT(2, 8)
|
||||
SORT(5, 6)
|
||||
SORT(9, 10)
|
||||
SORT(3, 8)
|
||||
SORT(6, 8)
|
||||
SORT(3, 5)
|
||||
SORT(7, 9)
|
||||
SORT(5, 6)
|
||||
SORT(7, 8)
|
||||
SORT(6, 7)
|
||||
|
||||
return dists[7];
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//Fallback, do front first
|
||||
float getMedianDist(ivec2 texel) {
|
||||
float minDist = -1000000;
|
||||
for(int i = 0; i < samples; i++) {
|
||||
minDist = max(minDist, texelFetch(texPos, texel, i).z);
|
||||
}
|
||||
return minDist;
|
||||
}
|
||||
|
||||
#endif //SAMPLES_16
|
||||
#endif //SAMPLES_8
|
||||
#endif //SAMPLES_4
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 texSize = textureSize(texColor);
|
||||
ivec2 texel = ivec2(texSize * fragTexCoord.xy);
|
||||
|
||||
float texelWidthFactor = tan(fov / texSize.y);
|
||||
float dist = getMedianDist(texel);
|
||||
|
||||
float weight = 0.0f;
|
||||
vec4 color = vec4(0);
|
||||
vec4 pos = vec4(0);
|
||||
vec4 normal = vec4(0);
|
||||
vec4 specular = vec4(0);
|
||||
vec4 emissive = vec4(0);
|
||||
float depth = 0;
|
||||
|
||||
for(int i = 0; i < samples; i++) {
|
||||
vec4 localPos = texelFetch(texPos, texel, i);
|
||||
//Calculate local weight from distance Voxel, but if the distance is 0 (i.e. no model at all), set weight to 1 to allow stuff like background emissive
|
||||
float localWeight = max(step(-0.001, dist),
|
||||
smoothstep(dist + dist * texelWidthFactor * (voxelDepth + voxelDepthFalloff), dist + dist * texelWidthFactor * voxelDepth, localPos.z) *
|
||||
smoothstep(dist - dist * texelWidthFactor * voxelDepth, dist + dist * texelWidthFactor * (voxelDepth + voxelDepthFalloff), localPos.z)
|
||||
);
|
||||
|
||||
pos += localPos * localWeight;
|
||||
color += texelFetch(texColor, texel, i) * localWeight;
|
||||
normal += texelFetch(texNormal, texel, i) * localWeight;
|
||||
specular += texelFetch(texSpecular, texel, i) * localWeight;
|
||||
emissive += texelFetch(texEmissive, texel, i) * localWeight;
|
||||
depth += texelFetch(texDepth, texel, i).x * localWeight;
|
||||
weight += localWeight;
|
||||
}
|
||||
|
||||
fragOut0 = color / weight;
|
||||
fragOut1 = pos / weight;
|
||||
fragOut2 = normalize(normal);
|
||||
fragOut3 = specular / weight;
|
||||
fragOut4 = emissive / weight;
|
||||
gl_FragDepth = depth / weight;
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
|
||||
in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
layout (binding = 0) uniform sampler2D composite;
|
||||
layout (binding = 1) uniform sampler2D emissive;
|
||||
layout (binding = 2) uniform sampler2D depth;
|
||||
layout (binding = 3) uniform sampler3D volume_tex;
|
||||
#ifdef NOISE
|
||||
layout (binding = 4) uniform sampler3D noise_volume_tex;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
mat4 p_inv;
|
||||
mat4 v_inv;
|
||||
vec3 camera;
|
||||
float zNear;
|
||||
vec3 globalLightDirection;
|
||||
float zFar;
|
||||
vec3 globalLightDiffuse;
|
||||
float stepsize;
|
||||
vec3 nebPos;
|
||||
float globalstepalpha;
|
||||
vec3 nebSize;
|
||||
float alphalim;
|
||||
float emissiveSpreadFactor;
|
||||
float emissiveIntensity;
|
||||
float emissiveFalloff;
|
||||
float henyeyGreensteinCoeff;
|
||||
vec3 noiseColor;
|
||||
int directionalLightSampleSteps;
|
||||
float directionalLightStepSize;
|
||||
float noiseColorScale1;
|
||||
float noiseColorScale2;
|
||||
float noiseIntensity;
|
||||
float aspect;
|
||||
float fov;
|
||||
};
|
||||
|
||||
const float sqrt4pi_inv = inversesqrt(4.0 * 3.14159);
|
||||
const float beer_powder_norm = 3.0/2.0 * sqrt(3.0);
|
||||
|
||||
//This HG implementation assumes that the scatter vectors between which is theta both point away from the point of scatter
|
||||
float henyey_greenstein(float cosTheta) {
|
||||
float radicant = 1.0 + henyeyGreensteinCoeff * henyeyGreensteinCoeff + 2.0 * henyeyGreensteinCoeff * cosTheta;
|
||||
return sqrt4pi_inv * (1.0 - henyeyGreensteinCoeff * henyeyGreensteinCoeff) / pow(radicant, 3.0 / 2.0);
|
||||
}
|
||||
|
||||
/*
|
||||
Base idea of sampling volumetrics from multiple LOD 3D-Textures with cloud models / noise as well as the shading for the diffuse
|
||||
part of the volumetrics is adapted from Andrew Schneider's 2015 SIGGRAPH talk "The real-time volumetric cloudscapes of Horizon: Zero Dawn".
|
||||
*/
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 eyeDirection = p_inv * vec4(fragTexCoord.xy * 2.0 - 1.0, -1, 1);
|
||||
eyeDirection.w = 0;
|
||||
vec3 rayDirection = normalize((v_inv * eyeDirection).xyz);
|
||||
|
||||
vec4 color_in = texture(composite, fragTexCoord.xy);
|
||||
|
||||
vec3 lCorner = nebPos - nebSize * 0.5;
|
||||
vec3 rCorner = nebPos + nebSize * 0.5;
|
||||
|
||||
vec3 t1 = (lCorner - camera) / rayDirection;
|
||||
vec3 t2 = (rCorner - camera) / rayDirection;
|
||||
|
||||
vec3 tMin = min(t1, t2);
|
||||
vec3 tMax = max(t1, t2);
|
||||
|
||||
vec2 fragcoordAngle = (fragTexCoord.xy - 0.5) * fov;
|
||||
fragcoordAngle.x *= aspect;
|
||||
float depth = (2.0 * zNear * zFar / (zFar + zNear - (2 * texture(depth, fragTexCoord.xy).x - 1) * (zFar - zNear))) * sqrt(1.0 + tan(fragcoordAngle.x) * tan(fragcoordAngle.x) + tan(fragcoordAngle.y) * tan(fragcoordAngle.y));
|
||||
|
||||
//The t at which the ray enters the nebula cube
|
||||
float maxtMin = max(0,max(tMin.x, max(tMin.y, tMin.z)));
|
||||
//The t at which the ray leaves the nebula cube
|
||||
float mintMax = min(depth, min(tMax.x, min(tMax.y, tMax.z)));
|
||||
|
||||
//The cumulative one minus alpha value of the nebula. Corresponds to the multiplier of the current step when additively drawing to a fragment for which the steps closer to the camera are already drawn.
|
||||
float cumOMAlpha = 1;
|
||||
//The cumulative distance already travelled through the nebula.
|
||||
float cumnebdist = 0;
|
||||
//The color of the current fragment
|
||||
vec3 cumcolor = vec3(0, 0, 0);
|
||||
|
||||
//While not perfectly accurate, it's sufficient to assume all gradients for the 3d texture lookups are identical
|
||||
vec3 initialPos = (camera + rayDirection * maxtMin) / nebSize + 0.5;
|
||||
vec3 gradX = dFdx(initialPos);
|
||||
vec3 gradY = dFdy(initialPos);
|
||||
|
||||
vec3 sidestep = 1.0 / vec3(textureSize(volume_tex, 0));
|
||||
|
||||
for(float stept = maxtMin; stept < mintMax; stept += stepsize) {
|
||||
//Step setup
|
||||
vec3 position = camera + rayDirection * stept - nebPos;
|
||||
vec3 sampleposition = position / nebSize + 0.5;
|
||||
vec4 volume_sample = textureGrad(volume_tex, sampleposition, gradX, gradY);
|
||||
|
||||
#ifdef DO_EDGE_SMOOTHING
|
||||
//Average 3D texel with texels on corner, in an attempt to reduce jagged edges.
|
||||
float stepcolor_alpha = volume_sample.a;
|
||||
if(cumOMAlpha > 0.8) {
|
||||
//Draw additional samples only if we currently encounter an edge
|
||||
stepcolor_alpha = stepcolor_alpha / 2.0 + (
|
||||
textureGrad(volume_tex, sampleposition + vec3(sidestep.x, sidestep.y, sidestep.z), gradX, gradY).a +
|
||||
textureGrad(volume_tex, sampleposition + vec3(sidestep.x, sidestep.y, -sidestep.z), gradX, gradY).a +
|
||||
textureGrad(volume_tex, sampleposition + vec3(sidestep.x, -sidestep.y, sidestep.z), gradX, gradY).a +
|
||||
textureGrad(volume_tex, sampleposition + vec3(sidestep.x, -sidestep.y, -sidestep.z), gradX, gradY).a +
|
||||
textureGrad(volume_tex, sampleposition + vec3(-sidestep.x, sidestep.y, sidestep.z), gradX, gradY).a +
|
||||
textureGrad(volume_tex, sampleposition + vec3(-sidestep.x, sidestep.y, -sidestep.z), gradX, gradY).a +
|
||||
textureGrad(volume_tex, sampleposition + vec3(-sidestep.x, -sidestep.y, sidestep.z), gradX, gradY).a +
|
||||
textureGrad(volume_tex, sampleposition + vec3(-sidestep.x, -sidestep.y, -sidestep.z), gradX, gradY).a) / 16.0;
|
||||
}
|
||||
#else
|
||||
float stepcolor_alpha = volume_sample.a;
|
||||
#endif
|
||||
|
||||
float stepalpha = globalstepalpha * stepcolor_alpha;
|
||||
//All the following computations are just required if we have a stepcoloralpha that is non-zero.
|
||||
if(stepcolor_alpha > 0.01)
|
||||
{
|
||||
//Noise - Technically, we need to do edge noise here but I'm not very happy with how it turned out. The cloud needs to be "eroded" by the noise as per the SIGGRAPH talk, but it's unclear as to how that can be achieved.
|
||||
//So for now, don't do edge noise. noise_volume_tex.ba are still reserved for noise data for edge erosion.
|
||||
|
||||
//Diffuse
|
||||
#ifdef NOISE
|
||||
//Mix the actual nebula color with the noise color depending on the product of the noise channels multiplied with intensity, smooth-clamped from 0 to 1
|
||||
vec3 stepcolor_neb = mix(volume_sample.rgb, noiseColor,
|
||||
smoothstep(0, 1, (textureGrad(noise_volume_tex, position / noiseColorScale1, gradX, gradY).r + textureGrad(noise_volume_tex, position / noiseColorScale2, gradX, gradY).g) / 2.0 * noiseIntensity));
|
||||
#else
|
||||
vec3 stepcolor_neb = volume_sample.rgb;
|
||||
#endif
|
||||
vec3 stepcolor_diffuse = stepcolor_neb * henyey_greenstein(dot(rayDirection, globalLightDirection));
|
||||
float directionalLightStep = 4.0 / float(directionalLightSampleSteps);
|
||||
float directionalLightDepth = 0.1;
|
||||
//From the current position in the volumetric cloud, sample towards the sun to test whether or not the current part of the nebula is bright or not
|
||||
for(int dlstep = 1; dlstep <= directionalLightSampleSteps; dlstep++){
|
||||
//TODO Sample these in a cone towards the sun, not just a line. Also add the high-distance sample for concave nebulae
|
||||
vec3 dlsteppos = (position - globalLightDirection * (dlstep * directionalLightStepSize)) / nebSize + 0.5;
|
||||
float dlstepalpha = textureGrad(volume_tex, dlsteppos, gradX, gradY).a * step(0, dlsteppos.x) * step(dlsteppos.x, 1) * step(0, dlsteppos.y) * step(dlsteppos.y, 1) * step(0, dlsteppos.z) * step(dlsteppos.z, 1);
|
||||
directionalLightDepth += dlstepalpha * directionalLightStep;
|
||||
}
|
||||
stepcolor_diffuse *= beer_powder_norm * (1 - exp(-directionalLightDepth * 2.0)) * exp(-directionalLightDepth);
|
||||
|
||||
//Emissive
|
||||
cumnebdist += stepcolor_alpha * stepsize;
|
||||
vec3 emissive_lod = textureLod(emissive, fragTexCoord.xy, clamp(cumnebdist * emissiveSpreadFactor, 0, float(textureQueryLevels(emissive) - 1))).rgb;
|
||||
vec3 stepcolor_emissive = emissive_lod.rgb * pow(1 - globalstepalpha, (depth - stept) * emissiveFalloff) * emissiveIntensity;
|
||||
|
||||
//Step finish
|
||||
vec3 stepcolor = clamp(stepcolor_diffuse + stepcolor_emissive, 0, 1);
|
||||
float stepalpha = globalstepalpha * stepcolor_alpha;
|
||||
cumcolor += stepalpha * cumOMAlpha * stepcolor;
|
||||
}
|
||||
|
||||
cumOMAlpha *= 1.0 - stepalpha;
|
||||
|
||||
if(cumOMAlpha < alphalim)
|
||||
break;
|
||||
}
|
||||
|
||||
cumcolor += cumOMAlpha * color_in.rgb;
|
||||
|
||||
fragOut0 = vec4(cumcolor, 1);
|
||||
}
|
||||
@@ -48,7 +48,7 @@ bool fireballs_parsed = false;
|
||||
|
||||
bool Fireball_use_3d_warp = false;
|
||||
|
||||
static auto WarpOption = options::OptionBuilder<bool>("Graphics.3dWarp", "3D Warp", "Use a 3D model for warp effects")
|
||||
static auto WarpOption __UNUSED = options::OptionBuilder<bool>("Graphics.3dWarp", "3D Warp", "Use a 3D model for warp effects")
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
@@ -1069,8 +1069,8 @@ void fireball_render(object* obj, model_draw_list *scene)
|
||||
|
||||
float alpha = 1.0f;
|
||||
|
||||
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && Neb_affects_fireballs)
|
||||
alpha *= neb2_get_fog_visibility(&obj->pos,
|
||||
if (Neb_affects_fireballs)
|
||||
nebula_handle_alpha(alpha, &obj->pos,
|
||||
Neb2_fog_visibility_fireball_const + (obj->radius * Neb2_fog_visibility_fireball_scaled_factor));
|
||||
|
||||
g3_transfer_vertex(&p, &obj->pos);
|
||||
|
||||
@@ -40,8 +40,6 @@ class asteroid_info;
|
||||
|
||||
#define FIREBALL_NUM_LARGE_EXPLOSIONS 2
|
||||
|
||||
#define MAX_FIREBALLS 200
|
||||
|
||||
extern int fireball_used[MAX_FIREBALL_TYPES];
|
||||
|
||||
// all this moved here by Goober5000 because it makes more sense in the H file
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
bool Fireball_warp_flash = false;
|
||||
|
||||
static auto WarpFlashOption = options::OptionBuilder<bool>("Graphics.WarpFlash", "Warp Flash", "Show flash upon warp open or close")
|
||||
static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.WarpFlash", "Warp Flash", "Show flash upon warp open or close")
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
@@ -83,7 +83,8 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
|
||||
|
||||
g3_transfer_vertex( &verts[4], &vecs[4] );
|
||||
|
||||
float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? neb2_get_fog_visibility(&obj->pos, 1.0f) : 1.0f;
|
||||
float alpha = 1.0f;
|
||||
nebula_handle_alpha(alpha, &obj->pos, 1.0f);
|
||||
|
||||
//batch_add_bitmap(warp_glow_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT, &verts[4], 0, r, alpha);
|
||||
batching_add_bitmap(warp_glow_bitmap, &verts[4], 0, r, alpha);
|
||||
|
||||
+344
-476
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "controlconfig/controlsconfig.h"
|
||||
#include "freespace.h"
|
||||
#include "gamehelp/gameplayhelp.h"
|
||||
#include "gamesequence/gamesequence.h"
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "globalincs/alphacolors.h"
|
||||
@@ -22,33 +23,44 @@
|
||||
|
||||
|
||||
|
||||
// text positioning constats
|
||||
// text positioning constants
|
||||
#define TITLE_Y 35
|
||||
#define Y_START 70
|
||||
#define X_OFFSET_1 70
|
||||
|
||||
// pixel offset for description of key from where key binding starts
|
||||
#define KEY_DESCRIPTION_OFFSET 193
|
||||
// increased this from 193 to 250 to account for allowing multiple keys -Mjn
|
||||
#define KEY_DESCRIPTION_OFFSET 250
|
||||
|
||||
// different gameplay help pages
|
||||
enum : int {
|
||||
// The first 9 are the basic retail pages
|
||||
GP_HELP_BASIC_KEYS,
|
||||
GP_HELP_MOVEMENT_KEYS,
|
||||
GP_HELP_COMMON_TARGET_KEYS,
|
||||
GP_HELP_ADVANCED_TARGET_KEYS,
|
||||
GP_HELP_MESSAGING,
|
||||
GP_HELP_WEAPON_KEYS,
|
||||
GP_HELP_THROTTLE_AND_ETS_KEYS,
|
||||
GP_HELP_VIEW_KEYS,
|
||||
GP_HELP_MISC_KEYS,
|
||||
|
||||
// Plus one for multi only
|
||||
GP_HELP_MULTI_KEYS,
|
||||
|
||||
// Any others defined here will have unique sections within the vector
|
||||
// but will need special handling to display in the retail UI
|
||||
GP_HELP_FUNCTION_KEYS,
|
||||
|
||||
First_available_section
|
||||
};
|
||||
|
||||
#define GP_FIRST_SCREEN 0 // keep up to date
|
||||
|
||||
#define GP_HELP_BASIC_KEYS 0
|
||||
#define GP_HELP_MOVEMENT_KEYS 1
|
||||
#define GP_HELP_COMMON_TARGET_KEYS 2
|
||||
#define GP_HELP_ADVANCED_TARGET_KEYS 3
|
||||
#define GP_HELP_MESSAGING 4
|
||||
#define GP_HELP_WEAPON_KEYS 5
|
||||
#define GP_HELP_THROTTLE_AND_ETS_KEYS 6
|
||||
#define GP_HELP_VIEW_KEYS 7
|
||||
#define GP_HELP_MISC_KEYS 8
|
||||
#define GP_HELP_MULTI_KEYS 9
|
||||
|
||||
#define GP_LAST_SCREEN_SINGLE 8 // keep up to date
|
||||
#define GP_LAST_SCREEN_MULTI 9 // keep up to date
|
||||
|
||||
// set this to GP_LAST_SCREEN_SINGLE or GP_LAST_SCREEN_MULTI based upon what game mode we're in
|
||||
int Gp_last_screen;
|
||||
static int Gp_last_screen;
|
||||
|
||||
#define NUM_BUTTONS 3
|
||||
#define PREVIOUS_PAGE_BUTTON 0
|
||||
@@ -109,10 +121,11 @@ static int Gameplay_help_inited = 0;
|
||||
|
||||
static int Current_help_page;
|
||||
|
||||
SCP_vector<gameplay_help_section> Help_text;
|
||||
|
||||
void gameplay_help_blit_control_line(int x, int y, int id)
|
||||
void gameplay_help_init_control_line(int id, gameplay_help_section &thisHelp)
|
||||
{
|
||||
char buf[256];
|
||||
char buf[256];
|
||||
|
||||
auto ci = &Control_config[id];
|
||||
|
||||
@@ -121,38 +134,55 @@ void gameplay_help_blit_control_line(int x, int y, int id)
|
||||
strcpy_s(buf, ci->first.textify().c_str());
|
||||
|
||||
if (!ci->second.empty()) {
|
||||
strcat_s(buf, XSTR( ", ", 129));
|
||||
strcat_s(buf, XSTR(", ", 129));
|
||||
strcat_s(buf, ci->second.textify().c_str());
|
||||
}
|
||||
|
||||
if (ci->empty()) {
|
||||
strcpy_s(buf, XSTR( "no binding", 130));
|
||||
strcpy_s(buf, XSTR("no binding", 130));
|
||||
}
|
||||
|
||||
gr_string(x,y,buf,GR_RESIZE_MENU);
|
||||
|
||||
// gr_string(x+KEY_DESCRIPTION_OFFSET,y,ci->text,GR_RESIZE_MENU);
|
||||
gr_string(x+KEY_DESCRIPTION_OFFSET, y, XSTR(ci->text.c_str(), CONTROL_CONFIG_XSTR + id), GR_RESIZE_MENU);
|
||||
thisHelp.key.push_back(buf);
|
||||
thisHelp.text.push_back(XSTR(ci->text.c_str(), CONTROL_CONFIG_XSTR + id));
|
||||
}
|
||||
|
||||
void gameplay_help_blit_control_line_raw(int x, int y, const char *control_text, const char *control_description)
|
||||
void gameplay_help_init_control_line_raw(const char* control_text, const char* control_description, gameplay_help_section &thisHelp)
|
||||
{
|
||||
gr_string(x,y,control_text,GR_RESIZE_MENU);
|
||||
gr_string(x+KEY_DESCRIPTION_OFFSET,y,control_description,GR_RESIZE_MENU);
|
||||
thisHelp.key.push_back(control_text);
|
||||
thisHelp.text.push_back(control_description);
|
||||
}
|
||||
|
||||
// displays the given help key and text at the specified
|
||||
// x and y coordinates
|
||||
void gameplay_help_blit_help_text(int x, int y, const SCP_string *control_text, const SCP_string *control_description)
|
||||
{
|
||||
gr_string(x, y, control_text->c_str(), GR_RESIZE_MENU);
|
||||
gr_string(x + KEY_DESCRIPTION_OFFSET, y, control_description->c_str(), GR_RESIZE_MENU);
|
||||
}
|
||||
|
||||
// displays a help section header at the specified y coordinate and an x coordinate
|
||||
// calculated from the header string's length
|
||||
void gameplay_help_blit_header_text(int y_offset, const SCP_string *header)
|
||||
{
|
||||
gr_set_color_fast(&Color_bright);
|
||||
int w;
|
||||
gr_get_string_size(&w, nullptr, header->c_str());
|
||||
gr_printf_menu((gr_screen.clip_width - w) / 2, y_offset, "%s", header->c_str());
|
||||
gr_set_color_fast(&Color_normal);
|
||||
}
|
||||
|
||||
// game_play_help_set_title() will display the title for the help screen and
|
||||
// set the font for the rest of the screen
|
||||
void gameplay_help_set_title(const char *title)
|
||||
void gameplay_help_set_title(const SCP_string *title)
|
||||
{
|
||||
int sy=TITLE_Y;
|
||||
char buf[128];
|
||||
|
||||
gr_set_color_fast(&Color_bright);
|
||||
int w;
|
||||
gr_get_string_size(&w, NULL, title);
|
||||
gr_get_string_size(&w, nullptr, title->c_str());
|
||||
|
||||
gr_printf_menu((gr_screen.clip_width_unscaled - w) / 2,sy,"%s", title);
|
||||
gr_printf_menu((gr_screen.clip_width_unscaled - w) / 2,sy,"%s", title->c_str());
|
||||
|
||||
sprintf(buf, XSTR("Page %d of %d", 132), Current_help_page + 1, Gp_last_screen + 1);
|
||||
gr_get_string_size(&w, NULL, buf);
|
||||
@@ -160,6 +190,253 @@ void gameplay_help_set_title(const char *title)
|
||||
gr_set_color_fast(&Color_normal);
|
||||
}
|
||||
|
||||
// Inits all the gameplay help text and returns it
|
||||
// in a nice organized vector of help sections
|
||||
SCP_vector<gameplay_help_section> gameplay_help_init_text()
|
||||
{
|
||||
SCP_vector<gameplay_help_section> complete_help_text;
|
||||
|
||||
for (int i = 0; i < First_available_section; i++) {
|
||||
|
||||
gameplay_help_section thisHelp;
|
||||
|
||||
switch (i) {
|
||||
|
||||
case GP_HELP_BASIC_KEYS:
|
||||
thisHelp.title = XSTR("Basic Keys", 133);
|
||||
|
||||
thisHelp.header = "";
|
||||
|
||||
gameplay_help_init_control_line(END_MISSION, thisHelp);
|
||||
gameplay_help_init_control_line(FIRE_PRIMARY, thisHelp);
|
||||
gameplay_help_init_control_line(MAX_THROTTLE, thisHelp);
|
||||
gameplay_help_init_control_line(ZERO_THROTTLE, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_NEXT, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_PREV, thisHelp);
|
||||
gameplay_help_init_control_line(TOGGLE_AUTO_TARGETING, thisHelp);
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_MOVEMENT_KEYS:
|
||||
thisHelp.title = XSTR("Movement Keys", 147);
|
||||
|
||||
thisHelp.header = "";
|
||||
|
||||
gameplay_help_init_control_line(FORWARD_THRUST, thisHelp);
|
||||
gameplay_help_init_control_line(MAX_THROTTLE, thisHelp);
|
||||
gameplay_help_init_control_line(ONE_THIRD_THROTTLE, thisHelp);
|
||||
gameplay_help_init_control_line(TWO_THIRDS_THROTTLE, thisHelp);
|
||||
gameplay_help_init_control_line(MINUS_5_PERCENT_THROTTLE, thisHelp);
|
||||
gameplay_help_init_control_line(PLUS_5_PERCENT_THROTTLE, thisHelp);
|
||||
gameplay_help_init_control_line(ZERO_THROTTLE, thisHelp);
|
||||
gameplay_help_init_control_line(AFTERBURNER, thisHelp);
|
||||
gameplay_help_init_control_line(REVERSE_THRUST, thisHelp);
|
||||
gameplay_help_init_control_line(PITCH_FORWARD, thisHelp);
|
||||
gameplay_help_init_control_line(PITCH_BACK, thisHelp);
|
||||
gameplay_help_init_control_line(YAW_LEFT, thisHelp);
|
||||
gameplay_help_init_control_line(YAW_RIGHT, thisHelp);
|
||||
gameplay_help_init_control_line(BANK_LEFT, thisHelp);
|
||||
gameplay_help_init_control_line(BANK_RIGHT, thisHelp);
|
||||
gameplay_help_init_control_line(BANK_WHEN_PRESSED, thisHelp);
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_COMMON_TARGET_KEYS:
|
||||
thisHelp.title = XSTR("Basic Targeting Keys", 148);
|
||||
|
||||
thisHelp.header = "";
|
||||
|
||||
gameplay_help_init_control_line(TARGET_NEXT, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_PREV, thisHelp);
|
||||
gameplay_help_init_control_line(TOGGLE_AUTO_TARGETING, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_SHIP_IN_RETICLE, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_NEXT_CLOSEST_HOSTILE, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_PREV_CLOSEST_HOSTILE, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_NEXT_CLOSEST_FRIENDLY, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_PREV_CLOSEST_FRIENDLY, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_NEXT_SUBOBJECT, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_PREV_SUBOBJECT, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_SUBOBJECT_IN_RETICLE, thisHelp);
|
||||
gameplay_help_init_control_line(MATCH_TARGET_SPEED, thisHelp);
|
||||
gameplay_help_init_control_line(TOGGLE_AUTO_MATCH_TARGET_SPEED, thisHelp);
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_ADVANCED_TARGET_KEYS:
|
||||
thisHelp.title = XSTR("Advanced Targeting Keys", 149);
|
||||
|
||||
thisHelp.header = "";
|
||||
|
||||
gameplay_help_init_control_line(TARGET_CLOSEST_SHIP_ATTACKING_SELF, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_CLOSEST_SHIP_ATTACKING_TARGET, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_LAST_TRANMISSION_SENDER, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_TARGETS_TARGET, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_NEXT_ESCORT_SHIP, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_CLOSEST_REPAIR_SHIP, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_NEXT_UNINSPECTED_CARGO, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_PREV_UNINSPECTED_CARGO, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_NEWEST_SHIP, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_NEXT_BOMB, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_PREV_BOMB, thisHelp);
|
||||
gameplay_help_init_control_line(STOP_TARGETING_SHIP, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_NEXT_LIVE_TURRET, thisHelp);
|
||||
gameplay_help_init_control_line(TARGET_PREV_LIVE_TURRET, thisHelp);
|
||||
gameplay_help_init_control_line(STOP_TARGETING_SUBSYSTEM, thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("F5...F12", 143), XSTR("Select target assigned to that hotkey", 150), thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("Shift-F5...F12", 151), XSTR("Add/remove target from that hotkey", 152), thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("Alt-Shift-F5...F12", 153), XSTR("Clear that hotkey", 154), thisHelp);
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_MESSAGING:
|
||||
thisHelp.title = XSTR("Messaging Keys", 155);
|
||||
|
||||
thisHelp.header = "";
|
||||
|
||||
gameplay_help_init_control_line(SQUADMSG_MENU, thisHelp);
|
||||
gameplay_help_init_control_line(REARM_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line(ATTACK_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line(DISARM_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line(DISABLE_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line(CAPTURE_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line(ENGAGE_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line(FORM_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line(IGNORE_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line(PROTECT_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line(COVER_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line(WARP_MESSAGE, thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("F5...F12", 143),
|
||||
XSTR("send specified order to these target(s)", 156),
|
||||
thisHelp);
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_WEAPON_KEYS:
|
||||
thisHelp.title = XSTR("Weapon Keys", 157);
|
||||
|
||||
thisHelp.header = "";
|
||||
|
||||
gameplay_help_init_control_line(FIRE_PRIMARY, thisHelp);
|
||||
gameplay_help_init_control_line(FIRE_SECONDARY, thisHelp);
|
||||
gameplay_help_init_control_line(CYCLE_NEXT_PRIMARY, thisHelp);
|
||||
gameplay_help_init_control_line(CYCLE_PREV_PRIMARY, thisHelp);
|
||||
gameplay_help_init_control_line(CYCLE_SECONDARY, thisHelp);
|
||||
gameplay_help_init_control_line(CYCLE_NUM_MISSLES, thisHelp);
|
||||
gameplay_help_init_control_line(LAUNCH_COUNTERMEASURE, thisHelp);
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_THROTTLE_AND_ETS_KEYS:
|
||||
thisHelp.title = XSTR("Energy Management Keys", 158);
|
||||
|
||||
thisHelp.header = "";
|
||||
|
||||
gameplay_help_init_control_line(SHIELD_EQUALIZE, thisHelp);
|
||||
gameplay_help_init_control_line(SHIELD_XFER_TOP, thisHelp);
|
||||
gameplay_help_init_control_line(SHIELD_XFER_BOTTOM, thisHelp);
|
||||
gameplay_help_init_control_line(SHIELD_XFER_LEFT, thisHelp);
|
||||
gameplay_help_init_control_line(SHIELD_XFER_RIGHT, thisHelp);
|
||||
gameplay_help_init_control_line(INCREASE_WEAPON, thisHelp);
|
||||
gameplay_help_init_control_line(DECREASE_WEAPON, thisHelp);
|
||||
gameplay_help_init_control_line(INCREASE_SHIELD, thisHelp);
|
||||
gameplay_help_init_control_line(DECREASE_SHIELD, thisHelp);
|
||||
gameplay_help_init_control_line(INCREASE_ENGINE, thisHelp);
|
||||
gameplay_help_init_control_line(DECREASE_ENGINE, thisHelp);
|
||||
gameplay_help_init_control_line(ETS_EQUALIZE, thisHelp);
|
||||
/*
|
||||
gameplay_help_init_control_line(XFER_LASER, thisHelp);
|
||||
gameplay_help_init_control_line(XFER_SHIELD, thisHelp);
|
||||
*/
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_MISC_KEYS:
|
||||
thisHelp.title = XSTR("Miscellaneous Keys", 159);
|
||||
|
||||
thisHelp.header = "";
|
||||
|
||||
// ending mission
|
||||
gameplay_help_init_control_line(END_MISSION, thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("ESC", 160), XSTR("invoke abort mission popup", 161), thisHelp);
|
||||
|
||||
// time compression
|
||||
gameplay_help_init_control_line(TIME_SPEED_UP, thisHelp);
|
||||
gameplay_help_init_control_line(TIME_SLOW_DOWN, thisHelp);
|
||||
|
||||
// radar keys
|
||||
gameplay_help_init_control_line(RADAR_RANGE_CYCLE, thisHelp);
|
||||
|
||||
// escort view keys
|
||||
gameplay_help_init_control_line(ADD_REMOVE_ESCORT, thisHelp);
|
||||
gameplay_help_init_control_line(ESCORT_CLEAR, thisHelp);
|
||||
|
||||
// Pause, Print Screenshot
|
||||
gameplay_help_init_control_line_raw(XSTR("Pause", 162), XSTR("pause game", 163), thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("Print Scrn", 164), XSTR("take screen shot", 165), thisHelp);
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_VIEW_KEYS:
|
||||
thisHelp.title = XSTR("View Keys", 166);
|
||||
|
||||
thisHelp.header = "";
|
||||
|
||||
gameplay_help_init_control_line(PADLOCK_UP, thisHelp);
|
||||
gameplay_help_init_control_line(PADLOCK_DOWN, thisHelp);
|
||||
gameplay_help_init_control_line(PADLOCK_LEFT, thisHelp);
|
||||
gameplay_help_init_control_line(PADLOCK_RIGHT, thisHelp);
|
||||
gameplay_help_init_control_line(VIEW_CHASE, thisHelp);
|
||||
gameplay_help_init_control_line(VIEW_EXTERNAL, thisHelp);
|
||||
gameplay_help_init_control_line(VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK, thisHelp);
|
||||
gameplay_help_init_control_line(VIEW_SLEW, thisHelp);
|
||||
gameplay_help_init_control_line(VIEW_DIST_INCREASE, thisHelp);
|
||||
gameplay_help_init_control_line(VIEW_DIST_DECREASE, thisHelp);
|
||||
gameplay_help_init_control_line(VIEW_CENTER, thisHelp);
|
||||
gameplay_help_init_control_line(VIEW_OTHER_SHIP, thisHelp);
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_MULTI_KEYS:
|
||||
thisHelp.title = XSTR("Multiplayer Keys", 167);
|
||||
|
||||
thisHelp.header = XSTR("Ingame messaging keys (tap for text, hold for voice)", 168);
|
||||
|
||||
gameplay_help_init_control_line(MULTI_MESSAGE_ALL, thisHelp);
|
||||
gameplay_help_init_control_line(MULTI_MESSAGE_FRIENDLY, thisHelp);
|
||||
gameplay_help_init_control_line(MULTI_MESSAGE_HOSTILE, thisHelp);
|
||||
gameplay_help_init_control_line(MULTI_MESSAGE_TARGET, thisHelp);
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_FUNCTION_KEYS:
|
||||
thisHelp.title = XSTR("Function Keys", 134);
|
||||
|
||||
thisHelp.header = "";
|
||||
|
||||
gameplay_help_init_control_line_raw(XSTR("F1", 135), XSTR("context-sensitive help", 136), thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("F2", 137),
|
||||
XSTR("options screen (available anywhere in game)", 138),
|
||||
thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("F3", 139), XSTR("hotkey assignment", 140), thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("F4", 141), XSTR("HUD message scroll-back", 142), thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("F5...F12", 143), XSTR("hotkeys", 144), thisHelp);
|
||||
gameplay_help_init_control_line_raw(XSTR("Shift-Esc", 145),
|
||||
XSTR("quit FreeSpace 2 immediately", 146),
|
||||
thisHelp);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
complete_help_text.push_back(thisHelp);
|
||||
}
|
||||
|
||||
return complete_help_text;
|
||||
}
|
||||
|
||||
// called once when the gameplay help state is entered
|
||||
void gameplay_help_init()
|
||||
{
|
||||
@@ -170,6 +447,10 @@ void gameplay_help_init()
|
||||
return;
|
||||
}
|
||||
|
||||
// init all the help text
|
||||
Help_text.clear(); //Make sure the array is empty before we start.
|
||||
Help_text = gameplay_help_init_text();
|
||||
|
||||
common_set_interface_palette("InterfacePalette"); // set the interface palette
|
||||
Ui_window.create(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled, 0);
|
||||
Ui_window.set_mask_bmap(Game_help_mask_filename[gr_screen.res]);
|
||||
@@ -204,7 +485,7 @@ void gameplay_help_init()
|
||||
|
||||
Background_bitmap = bm_load(Game_help_filename[gr_screen.res]);
|
||||
|
||||
Current_help_page = GP_HELP_BASIC_KEYS;
|
||||
Current_help_page = GP_FIRST_SCREEN;
|
||||
Gameplay_help_inited = 1;
|
||||
}
|
||||
|
||||
@@ -297,456 +578,43 @@ void gameplay_help_draw_text()
|
||||
|
||||
separation = gr_get_font_height() + 3;
|
||||
|
||||
switch ( Current_help_page ) {
|
||||
gameplay_help_section thisHelp = Help_text[Current_help_page];
|
||||
|
||||
case GP_HELP_BASIC_KEYS:
|
||||
{
|
||||
gameplay_help_set_title(XSTR("Basic Keys", 133));
|
||||
x_offset = X_OFFSET_1;
|
||||
y_offset = Y_START;
|
||||
gameplay_help_set_title(&thisHelp.title);
|
||||
x_offset = X_OFFSET_1;
|
||||
y_offset = Y_START;
|
||||
|
||||
// if we have a header then display it
|
||||
if (thisHelp.header.length() > 0) {
|
||||
gameplay_help_blit_header_text(y_offset, &thisHelp.header);
|
||||
y_offset += separation;
|
||||
}
|
||||
|
||||
// blit help text for each key
|
||||
for (int i = 0; i < (int)thisHelp.key.size(); i++) {
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_help_text(x_offset, y_offset, &thisHelp.key[i], &thisHelp.text[i]);
|
||||
}
|
||||
|
||||
// Special handling of function keys to display on the same page as the basic keys
|
||||
if (Current_help_page == GP_HELP_BASIC_KEYS) {
|
||||
|
||||
y_offset += separation;
|
||||
y_offset += separation;
|
||||
|
||||
thisHelp = Help_text[GP_HELP_FUNCTION_KEYS];
|
||||
|
||||
gameplay_help_blit_header_text(y_offset, &thisHelp.title);
|
||||
|
||||
y_offset += separation;
|
||||
y_offset += separation;
|
||||
|
||||
// blit help text for each key
|
||||
for (int i = 0; i < (int)thisHelp.key.size(); i++) {
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, END_MISSION);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, FIRE_PRIMARY);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, MAX_THROTTLE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, ZERO_THROTTLE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, TARGET_NEXT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, TARGET_PREV);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, TOGGLE_AUTO_TARGETING);
|
||||
|
||||
y_offset += separation;
|
||||
y_offset += separation;
|
||||
|
||||
gr_set_color_fast(&Color_bright);
|
||||
int w;
|
||||
gr_get_string_size(&w, NULL, XSTR("Function Keys", 134));
|
||||
gr_printf_menu((gr_screen.clip_width - w) / 2, y_offset, "%s", XSTR("Function Keys", 134));
|
||||
gr_set_color_fast(&Color_normal);
|
||||
|
||||
y_offset += separation;
|
||||
y_offset += separation;
|
||||
|
||||
gameplay_help_blit_control_line_raw(x_offset, y_offset, XSTR("F1", 135), XSTR("context-sensitive help", 136));
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset, y_offset, XSTR("F2", 137), XSTR("options screen (available anywhere in game)", 138));
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset, y_offset, XSTR("F3", 139), XSTR("hotkey assignment", 140));
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset, y_offset, XSTR("F4", 141), XSTR("HUD message scroll-back", 142));
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset, y_offset, XSTR("F5...F12", 143), XSTR("hotkeys", 144));
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset, y_offset, XSTR("Shift-Esc", 145), XSTR("quit FreeSpace 2 immediately", 146));
|
||||
|
||||
break;
|
||||
gameplay_help_blit_help_text(x_offset, y_offset, &thisHelp.key[i], &thisHelp.text[i]);
|
||||
}
|
||||
case GP_HELP_MOVEMENT_KEYS:
|
||||
gameplay_help_set_title(XSTR( "Movement Keys", 147));
|
||||
x_offset=X_OFFSET_1;
|
||||
y_offset=Y_START;
|
||||
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,FORWARD_THRUST);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,MAX_THROTTLE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,ONE_THIRD_THROTTLE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TWO_THIRDS_THROTTLE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,MINUS_5_PERCENT_THROTTLE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,PLUS_5_PERCENT_THROTTLE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,ZERO_THROTTLE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,AFTERBURNER);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,REVERSE_THRUST);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,PITCH_FORWARD);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,PITCH_BACK);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,YAW_LEFT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,YAW_RIGHT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,BANK_LEFT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,BANK_RIGHT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,BANK_WHEN_PRESSED);
|
||||
break;
|
||||
|
||||
case GP_HELP_COMMON_TARGET_KEYS:
|
||||
gameplay_help_set_title(XSTR( "Basic Targeting Keys", 148));
|
||||
x_offset=X_OFFSET_1;
|
||||
y_offset=Y_START;
|
||||
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_NEXT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_PREV);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TOGGLE_AUTO_TARGETING);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_SHIP_IN_RETICLE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_NEXT_CLOSEST_HOSTILE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_PREV_CLOSEST_HOSTILE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_NEXT_CLOSEST_FRIENDLY);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_PREV_CLOSEST_FRIENDLY);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_NEXT_SUBOBJECT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_PREV_SUBOBJECT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_SUBOBJECT_IN_RETICLE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,MATCH_TARGET_SPEED);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TOGGLE_AUTO_MATCH_TARGET_SPEED);
|
||||
break;
|
||||
|
||||
case GP_HELP_ADVANCED_TARGET_KEYS:
|
||||
gameplay_help_set_title(XSTR( "Advanced Targeting Keys", 149));
|
||||
x_offset=X_OFFSET_1;
|
||||
y_offset=Y_START;
|
||||
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_CLOSEST_SHIP_ATTACKING_SELF);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_CLOSEST_SHIP_ATTACKING_TARGET);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_LAST_TRANMISSION_SENDER);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_TARGETS_TARGET);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_NEXT_ESCORT_SHIP);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_CLOSEST_REPAIR_SHIP);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_NEXT_UNINSPECTED_CARGO);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_PREV_UNINSPECTED_CARGO);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_NEWEST_SHIP);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_NEXT_BOMB);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_PREV_BOMB);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,STOP_TARGETING_SHIP);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_NEXT_LIVE_TURRET);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TARGET_PREV_LIVE_TURRET);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,STOP_TARGETING_SUBSYSTEM);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset, y_offset, XSTR( "F5...F12", 143), XSTR( "Select target assigned to that hotkey", 150));
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset, y_offset, XSTR( "Shift-F5...F12", 151), XSTR( "Add/remove target from that hotkey", 152));
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset, y_offset, XSTR( "Alt-Shift-F5...F12", 153), XSTR( "Clear that hotkey", 154));
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_MESSAGING:
|
||||
gameplay_help_set_title(XSTR( "Messaging Keys", 155));
|
||||
x_offset=X_OFFSET_1;
|
||||
y_offset=Y_START;
|
||||
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,SQUADMSG_MENU);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,REARM_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,ATTACK_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,DISARM_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,DISABLE_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,CAPTURE_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,ENGAGE_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,FORM_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,IGNORE_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,PROTECT_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,COVER_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,WARP_MESSAGE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset, y_offset, XSTR( "F5...F12", 143), XSTR( "send specified order to these target(s)", 156));
|
||||
break;
|
||||
|
||||
case GP_HELP_WEAPON_KEYS:
|
||||
gameplay_help_set_title(XSTR( "Weapon Keys", 157));
|
||||
x_offset=X_OFFSET_1;
|
||||
y_offset=Y_START;
|
||||
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,FIRE_PRIMARY);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,FIRE_SECONDARY);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,CYCLE_NEXT_PRIMARY);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,CYCLE_PREV_PRIMARY);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,CYCLE_SECONDARY);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,CYCLE_NUM_MISSLES);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,LAUNCH_COUNTERMEASURE);
|
||||
break;
|
||||
|
||||
case GP_HELP_THROTTLE_AND_ETS_KEYS:
|
||||
gameplay_help_set_title(XSTR( "Energy Management Keys", 158));
|
||||
x_offset=X_OFFSET_1;
|
||||
y_offset=Y_START;
|
||||
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,SHIELD_EQUALIZE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,SHIELD_XFER_TOP);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,SHIELD_XFER_BOTTOM);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,SHIELD_XFER_LEFT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,SHIELD_XFER_RIGHT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,INCREASE_WEAPON);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,DECREASE_WEAPON);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,INCREASE_SHIELD);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,DECREASE_SHIELD);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,INCREASE_ENGINE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,DECREASE_ENGINE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,ETS_EQUALIZE);
|
||||
/*
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,XFER_LASER);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,XFER_SHIELD);
|
||||
*/
|
||||
break;
|
||||
|
||||
case GP_HELP_MISC_KEYS:
|
||||
gameplay_help_set_title(XSTR( "Miscellaneous Keys", 159));
|
||||
x_offset=X_OFFSET_1;
|
||||
y_offset=Y_START;
|
||||
|
||||
// ending mission
|
||||
//
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,END_MISSION);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset,y_offset, XSTR( "ESC", 160), XSTR( "invoke abort mission popup", 161));
|
||||
|
||||
// time compression
|
||||
//
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TIME_SPEED_UP);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,TIME_SLOW_DOWN);
|
||||
|
||||
// radar keys
|
||||
//
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,RADAR_RANGE_CYCLE);
|
||||
|
||||
// escort view keys
|
||||
//
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,ADD_REMOVE_ESCORT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,ESCORT_CLEAR);
|
||||
|
||||
// Pause, Print Screenshot
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset,y_offset, XSTR( "Pause", 162), XSTR( "pause game", 163));
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line_raw(x_offset,y_offset, XSTR( "Print Scrn", 164), XSTR( "take screen shot", 165));
|
||||
|
||||
break;
|
||||
|
||||
case GP_HELP_VIEW_KEYS:
|
||||
gameplay_help_set_title(XSTR( "View Keys", 166));
|
||||
x_offset=X_OFFSET_1;
|
||||
y_offset=Y_START;
|
||||
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,PADLOCK_UP);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,PADLOCK_DOWN);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,PADLOCK_LEFT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,PADLOCK_RIGHT);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,VIEW_CHASE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,VIEW_EXTERNAL);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,VIEW_SLEW);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,VIEW_DIST_INCREASE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,VIEW_DIST_DECREASE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,VIEW_CENTER);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset,VIEW_OTHER_SHIP);
|
||||
break;
|
||||
|
||||
case GP_HELP_MULTI_KEYS:
|
||||
{
|
||||
gameplay_help_set_title(XSTR("Multiplayer Keys", 167));
|
||||
x_offset = X_OFFSET_1;
|
||||
y_offset = Y_START;
|
||||
|
||||
// ingame messaging
|
||||
gr_set_color_fast(&Color_bright);
|
||||
int w;
|
||||
gr_get_string_size(&w, NULL, XSTR("Ingame messaging keys (tap for text, hold for voice)", 168));
|
||||
gr_printf_menu((gr_screen.clip_width - w) / 2, y_offset, "%s", XSTR("Ingame messaging keys (tap for text, hold for voice)", 168));
|
||||
gr_set_color_fast(&Color_normal);
|
||||
|
||||
y_offset += separation;
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, MULTI_MESSAGE_ALL);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, MULTI_MESSAGE_FRIENDLY);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, MULTI_MESSAGE_HOSTILE);
|
||||
|
||||
y_offset += separation;
|
||||
gameplay_help_blit_control_line(x_offset, y_offset, MULTI_MESSAGE_TARGET);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
} // end switch
|
||||
}
|
||||
}
|
||||
|
||||
// gameplay_help_do_frame() is the function that displays help when acutally playing the game
|
||||
|
||||
@@ -12,6 +12,17 @@
|
||||
#ifndef __GAMEPLAY_HELP_H__
|
||||
#define __GAMEPLAY_HELP_H__
|
||||
|
||||
struct gameplay_help_section {
|
||||
SCP_string title;
|
||||
SCP_string header;
|
||||
SCP_vector<SCP_string> key;
|
||||
SCP_vector<SCP_string> text;
|
||||
};
|
||||
|
||||
extern SCP_vector<gameplay_help_section> Help_text;
|
||||
|
||||
SCP_vector<gameplay_help_section> gameplay_help_init_text();
|
||||
|
||||
void gameplay_help_init();
|
||||
void gameplay_help_do_frame(float frametime);
|
||||
|
||||
|
||||
+85
-40
@@ -45,7 +45,7 @@ static bool music_volume_change_listener(float new_val, bool /*initial*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto MusicVolumeOption = options::OptionBuilder<float>("Audio.Music", "Music", "Volume used for playing music")
|
||||
static auto MusicVolumeOption __UNUSED = options::OptionBuilder<float>("Audio.Music", "Music", "Volume used for playing music")
|
||||
.category("Audio")
|
||||
.default_val(Default_music_volume)
|
||||
.range(0.0f, 1.0f)
|
||||
@@ -257,6 +257,19 @@ SCP_vector<menu_music> Spooled_music;
|
||||
int Mission_music[NUM_SCORES];
|
||||
|
||||
|
||||
bool event_music_pattern_is_skippable(const SOUNDTRACK_PATTERN_INFO &pattern)
|
||||
{
|
||||
// check for blank or "none"
|
||||
if (pattern.fname[0] == '\0' || !strnicmp(pattern.fname, NOX("none.wav"), 4))
|
||||
return true;
|
||||
|
||||
// no content means this pattern isn't intended to play
|
||||
if (pattern.num_measures == 0 || pattern.samples_per_measure == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// event_music_init()
|
||||
//
|
||||
@@ -289,6 +302,51 @@ void event_music_init()
|
||||
|
||||
// look for any modular tables
|
||||
parse_modular_table(NOX("*-mus.tbm"), event_music_parse_musictbl);
|
||||
|
||||
|
||||
// now that we've parsed everything, check the validity
|
||||
for (auto &soundtrack : Soundtracks)
|
||||
{
|
||||
bool all_patterns_valid = true;
|
||||
|
||||
// Goober5000 - set the valid flag according to whether we can load all our patterns
|
||||
// (since someone may be running an enhanced music.tbl without warble_fs1 installed)
|
||||
for (int i = 0; i < soundtrack.num_patterns; i++)
|
||||
{
|
||||
auto filename = soundtrack.patterns[i].fname;
|
||||
|
||||
// some patterns aren't played for various legitimate reasons
|
||||
if (event_music_pattern_is_skippable(soundtrack.patterns[i]))
|
||||
continue;
|
||||
|
||||
// check for negative numbers (zero is allowed)
|
||||
if (soundtrack.patterns[i].num_measures < 0 || soundtrack.patterns[i].samples_per_measure < 0)
|
||||
{
|
||||
Warning(LOCATION, "Soundtrack file %s has a negative 'num_measures' or 'samples_per_measure'; this is not allowed", soundtrack.patterns[i].fname);
|
||||
all_patterns_valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// check for file with exact extension
|
||||
// (since event music specifies samples and measures, the audio format is important; so we don't want to assume any format will work)
|
||||
if (!cf_exists_full(filename, CF_TYPE_MUSIC))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// see if the file exists with a different extension
|
||||
auto res = cf_find_file_location_ext(filename, NUM_AUDIO_EXT, audio_ext_list, CF_TYPE_MUSIC);
|
||||
if (res.found)
|
||||
Warning(LOCATION, "Soundtrack file %s was not found with its specified extension, but another file %s exists in the modpack. Please update the extension and adjust audio specifications if necessary.", filename, res.name_ext.c_str());
|
||||
#endif
|
||||
|
||||
Warning(LOCATION, "One or more files in '%s' could not be loaded. The soundtrack will not be used.", soundtrack.name);
|
||||
all_patterns_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_patterns_valid)
|
||||
soundtrack.flags |= EMF_VALID;
|
||||
}
|
||||
|
||||
Event_music_inited = TRUE;
|
||||
Event_music_begun = FALSE;
|
||||
@@ -410,7 +468,7 @@ void event_music_do_frame()
|
||||
|
||||
// start off the music delayed
|
||||
if ( timestamp_elapsed(Pattern_timer_id) ) {
|
||||
Pattern_timer_id = TIMESTAMP::invalid();
|
||||
Pattern_timer_id = TIMESTAMP::never();
|
||||
Event_music_begun = TRUE;
|
||||
if ( Current_pattern != -1 && Patterns[Current_pattern].handle >= 0) {
|
||||
//WMC - removed in favor of if
|
||||
@@ -544,14 +602,11 @@ void event_music_level_start(int force_soundtrack)
|
||||
if (force_soundtrack != -1)
|
||||
Current_soundtrack_num = force_soundtrack;
|
||||
|
||||
// Check that soundtrack index is in range, except that < 0 means no soundtrack
|
||||
if (Current_soundtrack_num < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < (int)Soundtracks.size());
|
||||
|
||||
if (Current_soundtrack_num < 0 || Current_soundtrack_num > (int)Soundtracks.size())
|
||||
Assert(Current_soundtrack_num < (int)Soundtracks.size());
|
||||
if (Current_soundtrack_num >= (int)Soundtracks.size())
|
||||
return;
|
||||
|
||||
strack = &Soundtracks[Current_soundtrack_num];
|
||||
@@ -564,7 +619,7 @@ void event_music_level_start(int force_soundtrack)
|
||||
// tracks because their patterns weren't -1
|
||||
for (i = 0; i < MAX_PATTERNS; i++)
|
||||
{
|
||||
if (!strnicmp(strack->patterns[i].fname, NOX("none.wav"), 4))
|
||||
if (event_music_pattern_is_skippable(strack->patterns[i]))
|
||||
{
|
||||
Patterns[i].handle = -1;
|
||||
continue;
|
||||
@@ -644,7 +699,9 @@ void event_music_first_pattern()
|
||||
// if we really are initializing the level
|
||||
if (Missiontime == 0) {
|
||||
Pattern_timer_id = TIMESTAMP::invalid(); // don't let this start quite yet; see event_music_set_start_delay()
|
||||
} else {
|
||||
}
|
||||
// don't step on a timestamp in progress; only set it if it has elapsed at least once already
|
||||
else if (Pattern_timer_id.isNever()) {
|
||||
Pattern_timer_id = TIMESTAMP::immediate(); // start immediately
|
||||
}
|
||||
|
||||
@@ -1166,9 +1223,6 @@ void parse_soundtrack()
|
||||
int i, strack_idx = -1;
|
||||
bool nocreate = false;
|
||||
|
||||
//Start parsing soundtrack
|
||||
//required_string("#Soundtrack Start");
|
||||
|
||||
//Get the name, and do we have this track already?
|
||||
required_string("$SoundTrack Name:");
|
||||
stuff_string(namebuf, F_NAME, NAME_LENGTH);
|
||||
@@ -1284,23 +1338,6 @@ void parse_soundtrack()
|
||||
|
||||
//We're done here.
|
||||
required_string("#SoundTrack End");
|
||||
|
||||
|
||||
// Goober5000 - set the valid flag according to whether we can load all our patterns
|
||||
// (since someone may be running an enhanced music.tbl without warble_fs1 installed)
|
||||
for (i = 0; i < Soundtracks[strack_idx].num_patterns; i++)
|
||||
{
|
||||
// check for "none"
|
||||
if (!strlen(Soundtracks[strack_idx].patterns[i].fname) || !strnicmp(Soundtracks[strack_idx].patterns[i].fname, "none", 4))
|
||||
continue;
|
||||
|
||||
// check for file
|
||||
if (!cf_exists_full_ext(Soundtracks[strack_idx].patterns[i].fname, CF_TYPE_MUSIC, NUM_AUDIO_EXT, audio_ext_list))
|
||||
return;
|
||||
}
|
||||
|
||||
// made it here okay, so it's valid
|
||||
Soundtracks[strack_idx].flags |= EMF_VALID;
|
||||
}
|
||||
|
||||
void parse_menumusic()
|
||||
@@ -1579,7 +1616,7 @@ int hostile_ships_present()
|
||||
// NOTE: callers to this function are advised to allocate a 256 byte buffer
|
||||
void event_music_get_info(char *outbuf)
|
||||
{
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_soundtrack_num < 0 || Current_pattern < 0 ) {
|
||||
strcpy(outbuf,XSTR( "Event music is not playing", 213));
|
||||
}
|
||||
else {
|
||||
@@ -1598,7 +1635,7 @@ int event_music_next_soundtrack(int delta)
|
||||
{
|
||||
int new_soundtrack;
|
||||
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Soundtracks.empty() ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1631,7 +1668,7 @@ void event_sexp_change_soundtrack(const char *name)
|
||||
}
|
||||
|
||||
event_music_level_close();
|
||||
Current_soundtrack_num = -1;
|
||||
Current_soundtrack_num = -1;
|
||||
event_music_level_start(new_soundtrack);
|
||||
}
|
||||
|
||||
@@ -1642,7 +1679,7 @@ void event_sexp_change_soundtrack(const char *name)
|
||||
// NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
|
||||
void event_music_get_soundtrack_name(char *outbuf)
|
||||
{
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_soundtrack_num < 0 ) {
|
||||
strcpy(outbuf, XSTR( "Event music is not playing", 213));
|
||||
}
|
||||
else {
|
||||
@@ -1653,11 +1690,15 @@ void event_music_get_soundtrack_name(char *outbuf)
|
||||
// set the current soundtrack based on name
|
||||
void event_music_set_soundtrack(const char *name)
|
||||
{
|
||||
Current_soundtrack_num = event_music_get_soundtrack_index(name);
|
||||
int index = event_music_get_soundtrack_index(name);
|
||||
|
||||
if ( Current_soundtrack_num == -1 ) {
|
||||
if (index >= 0 && Soundtracks[index].flags & EMF_VALID)
|
||||
Current_soundtrack_num = index;
|
||||
else
|
||||
Current_soundtrack_num = -1;
|
||||
|
||||
if (Current_soundtrack_num == -1)
|
||||
mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
|
||||
}
|
||||
}
|
||||
|
||||
int event_music_get_soundtrack_index(const char *name)
|
||||
@@ -1674,7 +1715,7 @@ int event_music_get_soundtrack_index(const char *name)
|
||||
|
||||
int event_music_get_spooled_music_index(const char *name)
|
||||
{
|
||||
// find the correct index for the event music
|
||||
// find the correct index for the spooled music
|
||||
for ( int i = 0; i < (int)Spooled_music.size(); i++ ) {
|
||||
if ( !stricmp(name, Spooled_music[i].name) ) {
|
||||
return i;
|
||||
@@ -1694,8 +1735,12 @@ void event_music_set_score(int score_index, const char *name)
|
||||
{
|
||||
Assert(score_index < NUM_SCORES);
|
||||
|
||||
// find the correct index for the event music
|
||||
Mission_music[score_index] = event_music_get_spooled_music_index(name);
|
||||
int index = event_music_get_spooled_music_index(name);
|
||||
|
||||
if (index >= 0 && Spooled_music[index].flags & SMF_VALID)
|
||||
Mission_music[score_index] = index;
|
||||
else
|
||||
Mission_music[score_index] = -1;
|
||||
}
|
||||
|
||||
// reset what sort of music is to be used for this mission
|
||||
|
||||
@@ -74,15 +74,16 @@ extern SCP_vector<menu_music> Spooled_music;
|
||||
|
||||
|
||||
// event music soundtrack storage
|
||||
typedef struct tagSOUNDTRACK_PATTERN_INFO {
|
||||
char fname[MAX_FILENAME_LEN];
|
||||
float num_measures;
|
||||
int samples_per_measure;
|
||||
} SOUNDTRACK_PATTERN_INFO;
|
||||
typedef struct tagSOUNDTRACK_INFO {
|
||||
int flags;
|
||||
int num_patterns;
|
||||
char name[NAME_LENGTH];
|
||||
struct {
|
||||
char fname[MAX_FILENAME_LEN];
|
||||
float num_measures;
|
||||
int samples_per_measure;
|
||||
} patterns[MAX_PATTERNS];
|
||||
SOUNDTRACK_PATTERN_INFO patterns[MAX_PATTERNS];
|
||||
} SOUNDTRACK_INFO;
|
||||
|
||||
// Goober5000 - event music flags
|
||||
|
||||
+78
-51
@@ -1189,6 +1189,10 @@ void parse_sound_environments()
|
||||
required_string("#Sound Environments End");
|
||||
}
|
||||
|
||||
// Due to the cyclic depdendency between sounds and species, the parsing is now broken up into two stages.
|
||||
// First, just the sounds are parsed; and second, just the flyby sounds are parsed (or assigned).
|
||||
static bool Sound_table_first_stage = false;
|
||||
|
||||
void parse_sound_table(const char* filename)
|
||||
{
|
||||
try
|
||||
@@ -1199,76 +1203,94 @@ void parse_sound_table(const char* filename)
|
||||
// Parse the gameplay sounds section
|
||||
if (optional_string("#Game Sounds Start"))
|
||||
{
|
||||
while (!check_for_string("#Game Sounds End"))
|
||||
if (!Sound_table_first_stage)
|
||||
skip_to_string("#Game Sounds End");
|
||||
else
|
||||
{
|
||||
game_snd tempSound;
|
||||
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds))
|
||||
while (!check_for_string("#Game Sounds End"))
|
||||
{
|
||||
Snds.push_back(game_snd(tempSound));
|
||||
game_snd tempSound;
|
||||
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds))
|
||||
{
|
||||
Snds.push_back(game_snd(tempSound));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required_string("#Game Sounds End");
|
||||
required_string("#Game Sounds End");
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the interface sounds section
|
||||
if (optional_string("#Interface Sounds Start"))
|
||||
{
|
||||
while (!check_for_string("#Interface Sounds End"))
|
||||
if (!Sound_table_first_stage)
|
||||
skip_to_string("#Interface Sounds End");
|
||||
else
|
||||
{
|
||||
game_snd tempSound;
|
||||
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds_iface))
|
||||
while (!check_for_string("#Interface Sounds End"))
|
||||
{
|
||||
Snds_iface.push_back(game_snd(tempSound));
|
||||
Snds_iface_handle.push_back(sound_handle::invalid());
|
||||
game_snd tempSound;
|
||||
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds_iface))
|
||||
{
|
||||
Snds_iface.push_back(game_snd(tempSound));
|
||||
Snds_iface_handle.push_back(sound_handle::invalid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required_string("#Interface Sounds End");
|
||||
required_string("#Interface Sounds End");
|
||||
}
|
||||
}
|
||||
|
||||
// parse flyby sound section
|
||||
if (optional_string("#Flyby Sounds Start"))
|
||||
{
|
||||
// try parsing sounds for each species
|
||||
// Note 1: instead of going through Species_info and requiring a sound for each species,
|
||||
// we now parse the token and extract the species name from it
|
||||
// Note 2: if a species doesn't have a flyby sound, the flyby code will just not play anything
|
||||
while (!check_for_string("#Flyby Sounds End"))
|
||||
if (Sound_table_first_stage)
|
||||
skip_to_string("#Flyby Sounds End");
|
||||
else
|
||||
{
|
||||
char species_name_tag[NAME_LENGTH + 2];
|
||||
stuff_string_until(species_name_tag, ":", NAME_LENGTH + 2);
|
||||
|
||||
if (species_name_tag[0] != '$')
|
||||
// try parsing sounds for each species
|
||||
// Note 1: instead of going through Species_info and requiring a sound for each species,
|
||||
// we now parse the token and extract the species name from it
|
||||
// Note 2: if a species doesn't have a flyby sound, the flyby code will just not play anything
|
||||
while (!check_for_string("#Flyby Sounds End"))
|
||||
{
|
||||
error_display(0, "Unexpected token tag %s", species_name_tag);
|
||||
advance_to_eoln(nullptr);
|
||||
continue;
|
||||
char species_name_tag[NAME_LENGTH + 2];
|
||||
stuff_string_until(species_name_tag, ":", NAME_LENGTH + 2);
|
||||
|
||||
if (species_name_tag[0] != '$')
|
||||
{
|
||||
error_display(0, "Unexpected token tag %s", species_name_tag);
|
||||
advance_to_eoln(nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
int idx = species_info_lookup(&species_name_tag[1]);
|
||||
if (idx < 0)
|
||||
{
|
||||
mprintf(("Skipping flyby sound for unknown species %s\n", &species_name_tag[1]));
|
||||
advance_to_eoln(nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
// now we have a known species
|
||||
species_info* species = &Species_info[idx];
|
||||
strcat_s(species_name_tag, ":"); // put back the terminator to restore the entire tag
|
||||
|
||||
// parse the two sounds for it
|
||||
gamesnd_parse_line(&species->snd_flyby_fighter, ":"); // since we stuffed most of the tag, the : is all that remains on this line
|
||||
gamesnd_parse_line(&species->snd_flyby_bomber, species_name_tag); // for the subsequent line we use required_string on the whole tag
|
||||
}
|
||||
|
||||
int idx = species_info_lookup(&species_name_tag[1]);
|
||||
if (idx < 0)
|
||||
{
|
||||
mprintf(("Skipping flyby sound for unknown species %s\n", &species_name_tag[1]));
|
||||
advance_to_eoln(nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
// now we have a known species
|
||||
species_info *species = &Species_info[idx];
|
||||
strcat_s(species_name_tag, ":"); // put back the terminator to restore the entire tag
|
||||
|
||||
// parse the two sounds for it
|
||||
gamesnd_parse_line(&species->snd_flyby_fighter, ":"); // since we stuffed most of the tag, the : is all that remains on this line
|
||||
gamesnd_parse_line(&species->snd_flyby_bomber, species_name_tag); // for the subsequent line we use required_string on the whole tag
|
||||
required_string("#Flyby Sounds End");
|
||||
}
|
||||
|
||||
required_string("#Flyby Sounds End");
|
||||
}
|
||||
|
||||
if (optional_string("#Sound Environments Start"))
|
||||
{
|
||||
parse_sound_environments();
|
||||
if (!Sound_table_first_stage)
|
||||
skip_to_string("#Sound Environments End");
|
||||
else
|
||||
parse_sound_environments();
|
||||
}
|
||||
}
|
||||
catch (const parse::ParseException& e)
|
||||
@@ -1277,24 +1299,29 @@ void parse_sound_table(const char* filename)
|
||||
return;
|
||||
}
|
||||
|
||||
gamesnd_add_retail_default_enhanced_sound_data();
|
||||
if (Sound_table_first_stage)
|
||||
gamesnd_add_retail_default_enhanced_sound_data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the sounds.tbl file, and load the specified sounds.
|
||||
*/
|
||||
void gamesnd_parse_soundstbl()
|
||||
void gamesnd_parse_soundstbl(bool first_stage)
|
||||
{
|
||||
Sound_table_first_stage = first_stage;
|
||||
|
||||
parse_sound_table("sounds.tbl");
|
||||
|
||||
parse_modular_table("*-snd.tbm", parse_sound_table);
|
||||
|
||||
//Set any flyby sounds for species that use the borrowed feature
|
||||
for (size_t i = 0; i < Species_info.size(); i++) {
|
||||
if (Species_info[i].borrows_flyby_sounds_species >= 0) {
|
||||
int idx = Species_info[i].borrows_flyby_sounds_species;
|
||||
Species_info[i].snd_flyby_fighter = Species_info[idx].snd_flyby_fighter;
|
||||
Species_info[i].snd_flyby_bomber = Species_info[idx].snd_flyby_bomber;
|
||||
if (!first_stage) {
|
||||
//Set any flyby sounds for species that use the borrowed feature
|
||||
for (size_t i = 0; i < Species_info.size(); i++) {
|
||||
if (Species_info[i].borrows_flyby_sounds_species >= 0) {
|
||||
int idx = Species_info[i].borrows_flyby_sounds_species;
|
||||
Species_info[i].snd_flyby_fighter = Species_info[idx].snd_flyby_fighter;
|
||||
Species_info[i].snd_flyby_bomber = Species_info[idx].snd_flyby_bomber;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ class interface_snd_id : public util::ID<interface_snd_tag, int, -1> {
|
||||
}
|
||||
};
|
||||
|
||||
void gamesnd_parse_soundstbl(); // Loads in general game sounds from sounds.tbl
|
||||
void gamesnd_parse_soundstbl(bool first_stage); // Loads in general game sounds from sounds.tbl
|
||||
void gamesnd_close(); // close out gamesnd... only call from game_shutdown()!
|
||||
void gamesnd_load_gameplay_sounds();
|
||||
void gamesnd_unload_gameplay_sounds();
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
// clang-format on
|
||||
#include "globalincs/adjustment.h"
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
//*************************************************
|
||||
// adjustment funcs
|
||||
//*************************************************
|
||||
|
||||
/**
|
||||
* @brief Processes an input according to the user's configuration and returns the result.
|
||||
*/
|
||||
float adjustment::handle(float input) const
|
||||
{
|
||||
if (only_positive && input < 0.0f)
|
||||
input = base;
|
||||
if (has_multiplier)
|
||||
input *= multipier;
|
||||
// handling adjust after multiplier makes it possible to multiply by 0 and still adjust.
|
||||
if (has_adjust)
|
||||
input += adjust;
|
||||
if (has_minimum)
|
||||
input = MAX(input, minimum);
|
||||
if (has_maximum)
|
||||
input = MIN(input, maximum);
|
||||
return input;
|
||||
}
|
||||
|
||||
void adjustment::reset()
|
||||
{
|
||||
base = 1.0f;
|
||||
has_adjust = false;
|
||||
has_minimum = false;
|
||||
has_maximum = false;
|
||||
has_multiplier = false;
|
||||
only_positive = true;
|
||||
}
|
||||
|
||||
void adjustment::set_adjust(float in)
|
||||
{
|
||||
has_adjust = true;
|
||||
adjust = in;
|
||||
}
|
||||
|
||||
void adjustment::set_multiplier(float in)
|
||||
{
|
||||
has_multiplier = true;
|
||||
multipier = in;
|
||||
}
|
||||
|
||||
void adjustment::stack_multiplier(float in)
|
||||
{
|
||||
if (has_multiplier) {
|
||||
multipier *= in;
|
||||
} else {
|
||||
multipier = in;
|
||||
has_multiplier = true;
|
||||
}
|
||||
}
|
||||
|
||||
void adjustment::set_maximum(float in)
|
||||
{
|
||||
has_maximum = true;
|
||||
maximum = in;
|
||||
}
|
||||
|
||||
void adjustment::set_minimum(float in)
|
||||
{
|
||||
has_minimum = true;
|
||||
minimum = in;
|
||||
}
|
||||
|
||||
void adjustment::stack_minimum(float in)
|
||||
{
|
||||
if (has_minimum) {
|
||||
minimum = MAX(minimum, in);
|
||||
} else {
|
||||
minimum = in;
|
||||
has_minimum = true;
|
||||
}
|
||||
}
|
||||
bool adjustment::read_adjust(float* out) const
|
||||
{
|
||||
*out = adjust;
|
||||
return has_adjust;
|
||||
}
|
||||
bool adjustment::read_multiplier(float* out) const
|
||||
{
|
||||
*out = multipier;
|
||||
return has_multiplier;
|
||||
}
|
||||
/**
|
||||
* @brief for use during the parsing of a light profile to attempt to read in an LPV
|
||||
*
|
||||
* @param filename for error reporting primairly
|
||||
* @param valuename Text of the field
|
||||
* @param profile_name The name of the profile being parsed, for error reporting
|
||||
* @param value_target The profile object parsing into
|
||||
* @param required If false it is an error for this to not find a value.
|
||||
* @return true if a succesful parse, false otherwise
|
||||
*/
|
||||
bool adjustment::parse(const char* filename,
|
||||
const char* valuename,
|
||||
const SCP_string& profile_name,
|
||||
adjustment* value_target,
|
||||
bool required)
|
||||
{
|
||||
if (optional_string(valuename)) {
|
||||
bool parsed = true;
|
||||
int parses = 0;
|
||||
while (parsed) {
|
||||
parsed = false;
|
||||
if (parse_optional_float_into("+default:", &value_target->base)) {
|
||||
parsed = true;
|
||||
parses++;
|
||||
}
|
||||
if (parse_optional_float_into("+maximum:", &value_target->maximum)) {
|
||||
value_target->has_maximum = true;
|
||||
parsed = true;
|
||||
parses++;
|
||||
}
|
||||
if (parse_optional_float_into("+minimum:", &value_target->minimum)) {
|
||||
value_target->has_minimum = true;
|
||||
parsed = true;
|
||||
parses++;
|
||||
}
|
||||
if (parse_optional_float_into("+multiplier:", &value_target->multipier)) {
|
||||
value_target->has_multiplier = true;
|
||||
parsed = true;
|
||||
parses++;
|
||||
}
|
||||
if (parse_optional_float_into("+adjust:", &value_target->adjust)) {
|
||||
value_target->has_adjust = true;
|
||||
parsed = true;
|
||||
parses++;
|
||||
}
|
||||
}
|
||||
if (parses == 0) {
|
||||
Warning(LOCATION,
|
||||
"Adjustment config '%s' in file '%s' profile '%s' parsed but set no properties, possible "
|
||||
"malformed table.",
|
||||
valuename,
|
||||
filename,
|
||||
profile_name.c_str());
|
||||
} else if (parses > 5) {
|
||||
Warning(LOCATION,
|
||||
"Adjustment config '%s' in file '%s' section '%s' parsed too many properties, possible "
|
||||
"malformed table.",
|
||||
valuename,
|
||||
filename,
|
||||
profile_name.c_str());
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if (required) {
|
||||
Error(LOCATION,
|
||||
"Expected adjustment config value '%s' in file '%s' section '%s' not found",
|
||||
valuename,
|
||||
filename,
|
||||
profile_name.c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
adjustment::adjustment(const adjustment& rhs){
|
||||
*this = rhs;
|
||||
}
|
||||
|
||||
adjustment& adjustment::operator= (const adjustment& rhs){
|
||||
has_adjust = rhs.has_adjust;
|
||||
adjust = rhs.adjust;
|
||||
has_multiplier = rhs.has_multiplier;
|
||||
multipier = rhs.multipier;
|
||||
has_minimum = rhs.has_minimum;
|
||||
minimum = rhs.minimum;
|
||||
has_maximum = rhs.has_maximum;
|
||||
maximum = rhs.maximum;
|
||||
return *this;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// clang-format on
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include "parse/parsehi.h"
|
||||
|
||||
/**
|
||||
* @brief To hold configuration of, and handle application of, modifiers to numeric values.
|
||||
*
|
||||
* Was originally made for lighting_profiles, but was extracted into it's own thing for potential reuse.
|
||||
*/
|
||||
struct adjustment {
|
||||
float base;
|
||||
bool only_positive = true;
|
||||
|
||||
float handle(float input) const;
|
||||
void reset();
|
||||
void set_adjust(const float in);
|
||||
void set_multiplier(const float in);
|
||||
void stack_multiplier(const float in);
|
||||
void set_maximum(const float in);
|
||||
void set_minimum(const float in);
|
||||
void stack_minimum(const float in);
|
||||
|
||||
static bool parse(const char* filename,
|
||||
const char* valuename,
|
||||
const SCP_string& profile_name,
|
||||
adjustment* value_target,
|
||||
bool required = false);
|
||||
bool read_multiplier(float* out) const;
|
||||
bool read_adjust(float* out) const;
|
||||
|
||||
adjustment() = default ;
|
||||
adjustment(const adjustment& rhs);
|
||||
//adjustment(const adjustment& lhs, const adjustment& rhs, const float& fact);
|
||||
adjustment& operator= (const adjustment& rhs);
|
||||
|
||||
private:
|
||||
bool has_adjust = false;
|
||||
float adjust;
|
||||
bool has_multiplier=false;
|
||||
float multipier;
|
||||
bool has_minimum = false;
|
||||
float minimum;
|
||||
bool has_maximum = false;
|
||||
float maximum;
|
||||
};
|
||||
@@ -100,6 +100,20 @@ class flagset {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename TIter>
|
||||
flagset<T>& set_multiple_from_source(const flagset<T>& source, TIter begin, TIter end) {
|
||||
auto current = begin;
|
||||
while (current != end) {
|
||||
if (source[*current]) {
|
||||
set(*current, true);
|
||||
}
|
||||
|
||||
current = std::next(current);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
flagset<T>& remove(T idx) {
|
||||
return set(idx, false);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
// from parselo.h
|
||||
#define PATHNAME_LENGTH 192
|
||||
#define NAME_LENGTH 32
|
||||
#define SEXP_LENGTH 128
|
||||
#define DATE_LENGTH 32
|
||||
#define TIME_LENGTH 16
|
||||
#define DATE_TIME_LENGTH 48
|
||||
|
||||
@@ -99,6 +99,14 @@ struct ivec2 {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
namespace scripting {
|
||||
class ade_table_entry;
|
||||
}
|
||||
namespace luacpp {
|
||||
class LuaValue;
|
||||
}
|
||||
struct lua_State;
|
||||
|
||||
/** Represents a point in 3d space.
|
||||
|
||||
Note: this is a struct, not a class, so no member functions. */
|
||||
@@ -109,6 +117,9 @@ typedef struct vec3d {
|
||||
} xyz;
|
||||
float a1d[3];
|
||||
};
|
||||
|
||||
void serialize(lua_State* /*L*/, const scripting::ade_table_entry& /*tableEntry*/, const luacpp::LuaValue& value, ubyte* data, int& packet_size);
|
||||
void deserialize(lua_State* /*L*/, const scripting::ade_table_entry& /*tableEntry*/, char* data_ptr, ubyte* data, int& offset);
|
||||
} vec3d;
|
||||
|
||||
typedef struct vec2d {
|
||||
@@ -321,6 +332,7 @@ constexpr bool LoggingEnabled = false;
|
||||
const float PI2 = (PI*2.0f);
|
||||
// half values
|
||||
const float PI_2 = (PI/2.0f);
|
||||
const float PI_4 = (PI/4.0f);
|
||||
|
||||
|
||||
extern int Fred_running; // Is Fred running, or FreeSpace?
|
||||
|
||||
@@ -251,14 +251,14 @@ const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum"
|
||||
{ 3, "High" },
|
||||
{ 4, "Ultra" }, };
|
||||
|
||||
const auto ModelDetailOption =
|
||||
const auto ModelDetailOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.Detail", "Model Detail", "Detail level of models").importance(8).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.detail_distance = val;
|
||||
return true;
|
||||
}).finish();
|
||||
|
||||
const auto TexturesOption = options::OptionBuilder<int>("Graphics.Texture",
|
||||
const auto TexturesOption __UNUSED = options::OptionBuilder<int>("Graphics.Texture",
|
||||
"3D Hardware Textures",
|
||||
"Level of detail of textures").importance(6).category("Graphics").values(
|
||||
DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
@@ -266,7 +266,7 @@ const auto TexturesOption = options::OptionBuilder<int>("Graphics.Texture",
|
||||
return true;
|
||||
}).finish();
|
||||
|
||||
const auto ParticlesOption = options::OptionBuilder<int>("Graphics.Particles",
|
||||
const auto ParticlesOption __UNUSED = options::OptionBuilder<int>("Graphics.Particles",
|
||||
"Particles",
|
||||
"Level of detail for particles").importance(5).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
@@ -274,7 +274,7 @@ const auto ParticlesOption = options::OptionBuilder<int>("Graphics.Particles",
|
||||
return true;
|
||||
}).finish();
|
||||
|
||||
const auto SmallDebrisOption =
|
||||
const auto SmallDebrisOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.SmallDebris", "Impact Effects", "Level of detail of impact effects").category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).importance(4).change_listener([](int val,
|
||||
bool) {
|
||||
@@ -282,7 +282,7 @@ const auto SmallDebrisOption =
|
||||
return true;
|
||||
}).finish();
|
||||
|
||||
const auto ShieldEffectsOption = options::OptionBuilder<int>("Graphics.ShieldEffects",
|
||||
const auto ShieldEffectsOption __UNUSED = options::OptionBuilder<int>("Graphics.ShieldEffects",
|
||||
"Shield Hit Effects",
|
||||
"Level of detail of shield impacts").importance(3).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
@@ -290,7 +290,7 @@ const auto ShieldEffectsOption = options::OptionBuilder<int>("Graphics.ShieldEff
|
||||
return true;
|
||||
}).finish();
|
||||
|
||||
const auto StarsOption =
|
||||
const auto StarsOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.Stars", "Stars", "Number of stars in the mission").importance(2).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.num_stars = val;
|
||||
@@ -425,3 +425,71 @@ void SCP_toupper(char *str)
|
||||
for (; *str != '\0'; ++str)
|
||||
*str = SCP_toupper(*str);
|
||||
}
|
||||
|
||||
// this is a bit naive but it is good enough for the time being
|
||||
void SCP_totitle(char *str)
|
||||
{
|
||||
bool prev_alpha = false;
|
||||
|
||||
for (; *str != '\0'; ++str)
|
||||
{
|
||||
bool this_alpha = (*str >= 'a' && *str <= 'z') || (*str >= 'A' && *str <= 'Z');
|
||||
|
||||
if (this_alpha)
|
||||
{
|
||||
if (prev_alpha)
|
||||
*str = SCP_tolower(*str);
|
||||
else
|
||||
*str = SCP_toupper(*str);
|
||||
}
|
||||
|
||||
prev_alpha = this_alpha;
|
||||
}
|
||||
}
|
||||
|
||||
bool lcase_equal(const SCP_string& _Left, const SCP_string& _Right)
|
||||
{
|
||||
if (_Left.size() != _Right.size())
|
||||
return false;
|
||||
|
||||
auto l_it = _Left.cbegin();
|
||||
auto r_it = _Right.cbegin();
|
||||
|
||||
while (l_it != _Left.cend())
|
||||
{
|
||||
if (SCP_tolower(*l_it) != SCP_tolower(*r_it))
|
||||
return false;
|
||||
|
||||
++l_it;
|
||||
++r_it;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lcase_lessthan(const SCP_string& _Left, const SCP_string& _Right)
|
||||
{
|
||||
auto l_it = _Left.cbegin();
|
||||
auto r_it = _Right.cbegin();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (l_it == _Left.cend())
|
||||
return (r_it != _Right.cend());
|
||||
else if (r_it == _Right.cend())
|
||||
return false;
|
||||
|
||||
auto lch = SCP_tolower(*l_it);
|
||||
auto rch = SCP_tolower(*r_it);
|
||||
|
||||
if (lch < rch)
|
||||
return true;
|
||||
else if (lch > rch)
|
||||
return false;
|
||||
|
||||
++l_it;
|
||||
++r_it;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -194,59 +194,4 @@ int current_detail_level();
|
||||
#define safe_kill(a) if(a)vm_free(a)
|
||||
|
||||
|
||||
// Goober5000
|
||||
// A sort for use with small or almost-sorted lists. Iteration time is O(n) for a fully-sorted list.
|
||||
// This uses a type-safe version of the function prototype for stdlib's qsort, although the size is an int rather than a size_t (for the reasons that j is an int).
|
||||
// The fncompare function should return <0, 0, or >0 as the left item is less than, equal to, or greater than the right item.
|
||||
template <typename array_t, typename T>
|
||||
void insertion_sort(array_t& array_base, int array_size, int (*fncompare)(const T*, const T*))
|
||||
{
|
||||
// NOTE: j *must* be a signed type because j reaches -1 and j+1 must be 0.
|
||||
int i, j;
|
||||
T *current, *current_buf;
|
||||
|
||||
// allocate space for the element being moved
|
||||
// (Taylor says that for optimization purposes malloc/free should be used rather than vm_malloc/vm_free here)
|
||||
current_buf = new T();
|
||||
if (current_buf == nullptr)
|
||||
{
|
||||
UNREACHABLE("Malloc failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
// loop
|
||||
for (i = 1; i < array_size; i++)
|
||||
{
|
||||
// grab the current element
|
||||
// this does a lazy move/copy because if the array is mostly sorted,
|
||||
// there's no sense copying sorted items to their own places
|
||||
bool lazily_copied = false;
|
||||
current = &array_base[i];
|
||||
|
||||
// bump other elements toward the end of the array
|
||||
for (j = i - 1; (j >= 0) && (fncompare(&array_base[j], current) > 0); j--)
|
||||
{
|
||||
if (!lazily_copied)
|
||||
{
|
||||
// this may look strange but it is just copying the data
|
||||
// into the buffer, then pointing to the buffer
|
||||
*current_buf = std::move(*current);
|
||||
current = current_buf;
|
||||
lazily_copied = true;
|
||||
}
|
||||
|
||||
array_base[j + 1] = std::move(array_base[j]);
|
||||
}
|
||||
|
||||
if (lazily_copied)
|
||||
{
|
||||
// insert the current element at the correct place
|
||||
array_base[j + 1] = std::move(*current);
|
||||
}
|
||||
}
|
||||
|
||||
// free the allocated space
|
||||
delete current_buf;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,150 @@
|
||||
|
||||
#ifndef _FSO_UTILITY_H
|
||||
#define _FSO_UTILITY_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "globalincs/globals.h"
|
||||
#include "globalincs/toolchain.h"
|
||||
|
||||
|
||||
// Goober5000
|
||||
// A sort for use with small or almost-sorted lists. Iteration time is O(n) for a fully-sorted list.
|
||||
// This uses a type-safe version of the function prototype for stdlib's qsort, although the size is an int rather than a size_t (for the reasons that j is an int).
|
||||
// The fncompare function should return <0, 0, or >0 as the left item is less than, equal to, or greater than the right item.
|
||||
template <typename array_t, typename T>
|
||||
void insertion_sort(array_t& array_base, int array_size, int (*fncompare)(const T*, const T*))
|
||||
{
|
||||
// NOTE: j *must* be a signed type because j reaches -1 and j+1 must be 0.
|
||||
int i, j;
|
||||
T *current, *current_buf;
|
||||
|
||||
// allocate space for the element being moved
|
||||
// (Taylor says that for optimization purposes malloc/free should be used rather than vm_malloc/vm_free here)
|
||||
current_buf = new T();
|
||||
if (current_buf == nullptr)
|
||||
{
|
||||
UNREACHABLE("Malloc failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
// loop
|
||||
for (i = 1; i < array_size; i++)
|
||||
{
|
||||
// grab the current element
|
||||
// this does a lazy move/copy because if the array is mostly sorted,
|
||||
// there's no sense copying sorted items to their own places
|
||||
bool lazily_copied = false;
|
||||
current = &array_base[i];
|
||||
|
||||
// bump other elements toward the end of the array
|
||||
for (j = i - 1; (j >= 0) && (fncompare(&array_base[j], current) > 0); j--)
|
||||
{
|
||||
if (!lazily_copied)
|
||||
{
|
||||
// this may look strange but it is just copying the data
|
||||
// into the buffer, then pointing to the buffer
|
||||
*current_buf = std::move(*current);
|
||||
current = current_buf;
|
||||
lazily_copied = true;
|
||||
}
|
||||
|
||||
array_base[j + 1] = std::move(array_base[j]);
|
||||
}
|
||||
|
||||
if (lazily_copied)
|
||||
{
|
||||
// insert the current element at the correct place
|
||||
array_base[j + 1] = std::move(*current);
|
||||
}
|
||||
}
|
||||
|
||||
// free the allocated space
|
||||
delete current_buf;
|
||||
}
|
||||
|
||||
//
|
||||
// See https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C++
|
||||
//
|
||||
template<typename T>
|
||||
typename T::size_type GeneralizedLevenshteinDistance(const T &source,
|
||||
const T &target,
|
||||
typename T::size_type insert_cost = 1,
|
||||
typename T::size_type delete_cost = 1,
|
||||
typename T::size_type replace_cost = 1) {
|
||||
if (source.size() > target.size()) {
|
||||
return GeneralizedLevenshteinDistance(target, source, delete_cost, insert_cost, replace_cost);
|
||||
}
|
||||
|
||||
using TSizeType = typename T::size_type;
|
||||
const TSizeType min_size = source.size(), max_size = target.size();
|
||||
std::vector<TSizeType> lev_dist(min_size + 1);
|
||||
|
||||
lev_dist[0] = 0;
|
||||
for (TSizeType i = 1; i <= min_size; ++i) {
|
||||
lev_dist[i] = lev_dist[i - 1] + delete_cost;
|
||||
}
|
||||
|
||||
for (TSizeType j = 1; j <= max_size; ++j) {
|
||||
TSizeType previous_diagonal = lev_dist[0], previous_diagonal_save;
|
||||
lev_dist[0] += insert_cost;
|
||||
|
||||
for (TSizeType i = 1; i <= min_size; ++i) {
|
||||
previous_diagonal_save = lev_dist[i];
|
||||
if (source[i - 1] == target[j - 1]) {
|
||||
lev_dist[i] = previous_diagonal;
|
||||
}
|
||||
else {
|
||||
lev_dist[i] = std::min(std::min(lev_dist[i - 1] + delete_cost, lev_dist[i] + insert_cost), previous_diagonal + replace_cost);
|
||||
}
|
||||
previous_diagonal = previous_diagonal_save;
|
||||
}
|
||||
}
|
||||
|
||||
return lev_dist[min_size];
|
||||
}
|
||||
|
||||
// Lafiel
|
||||
template<typename T>
|
||||
typename T::size_type stringcost(const T& op, const T& input, typename T::size_type max_expected_length = NAME_LENGTH) {
|
||||
using TSizeType = typename T::size_type;
|
||||
|
||||
if(input.empty())
|
||||
return T::npos;
|
||||
|
||||
struct string_search_it {
|
||||
TSizeType count;
|
||||
TSizeType lastpos;
|
||||
TSizeType cost;
|
||||
};
|
||||
std::vector<string_search_it> iterators;
|
||||
|
||||
//Go through the input. If we find it split up into parts, prefer things that are least split, and within this prefer things that are closer together
|
||||
for (TSizeType i = 0; i < op.length(); i++) {
|
||||
std::vector<string_search_it> insert;
|
||||
for (auto& it : iterators) {
|
||||
if (it.count < input.length() && op[i] == input[it.count]) {
|
||||
//We found something. There may be a better match for this later, so only make a copy.
|
||||
insert.emplace_back(string_search_it{it.count + 1, i, i - it.lastpos <= 1 ? it.cost : max_expected_length + i - it.lastpos - 1});
|
||||
}
|
||||
}
|
||||
|
||||
iterators.insert(iterators.end(), insert.begin(), insert.end());
|
||||
|
||||
if (op[i] == input[0])
|
||||
iterators.emplace_back(string_search_it{1, i, i});
|
||||
}
|
||||
|
||||
auto cost = T::npos;
|
||||
|
||||
for (const auto& it : iterators) {
|
||||
//Things that are missing letters are considered worse by default
|
||||
auto localcost = (input.length() - it.count) * (max_expected_length * max_expected_length) + it.cost;
|
||||
if (localcost < cost)
|
||||
cost = localcost;
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -19,13 +19,17 @@ bool check_at_least(const version& v) {
|
||||
return get_executable_version() >= v;
|
||||
}
|
||||
|
||||
SCP_string format_version(const version& v) {
|
||||
SCP_string format_version(const version& v, bool exclude_build) {
|
||||
SCP_stringstream ss;
|
||||
|
||||
ss << v.major << "." << v.minor << "." << v.build;
|
||||
ss << v.major << "." << v.minor;
|
||||
|
||||
if (v.revision != 0) {
|
||||
ss << "." << v.revision;
|
||||
if (!exclude_build) {
|
||||
ss << "." << v.build;
|
||||
|
||||
if (v.revision != 0) {
|
||||
ss << "." << v.revision;
|
||||
}
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
|
||||
@@ -83,10 +83,11 @@ bool check_at_least(const version& v);
|
||||
|
||||
/**
|
||||
* @brief Returns the string representation of the passed version
|
||||
* @param major The version to format
|
||||
* @param v The version to format
|
||||
* @param exclude_build Whether to exclude the build and revision numbers (i.e. only print major and minor)
|
||||
* @returns A string representation of the version number
|
||||
*/
|
||||
SCP_string format_version(const version& v);
|
||||
SCP_string format_version(const version& v, bool exclude_build = false);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
|
||||
@@ -60,6 +60,10 @@ inline bool SCP_truncate(SCP_string &str, size_t c_str_size) {
|
||||
|
||||
extern void SCP_tolower(char *str);
|
||||
extern void SCP_toupper(char *str);
|
||||
extern void SCP_totitle(char *str);
|
||||
|
||||
extern bool lcase_equal(const SCP_string& _Left, const SCP_string& _Right);
|
||||
extern bool lcase_lessthan(const SCP_string& _Left, const SCP_string& _Right);
|
||||
|
||||
|
||||
template <typename T, typename U>
|
||||
@@ -77,6 +81,9 @@ using SCP_deque = std::deque<T, std::allocator<T>>;
|
||||
template <typename T>
|
||||
using SCP_set = std::set<T, std::less<T>, std::allocator<T>>;
|
||||
|
||||
template <typename T>
|
||||
using SCP_multiset = std::multiset<T, std::less<T>, std::allocator<T>>;
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
template<class T, bool>
|
||||
struct enum_hasher_util {
|
||||
@@ -124,43 +131,13 @@ struct SCP_string_lcase_hash {
|
||||
|
||||
struct SCP_string_lcase_equal_to {
|
||||
bool operator()(const SCP_string& _Left, const SCP_string& _Right) const {
|
||||
if (_Left.size() != _Right.size()) {
|
||||
return false;
|
||||
}
|
||||
auto l_it = _Left.cbegin();
|
||||
auto r_it = _Right.cbegin();
|
||||
while (l_it != _Left.cend()) {
|
||||
if (SCP_tolower(*l_it) != SCP_tolower(*r_it)) {
|
||||
return false;
|
||||
}
|
||||
++l_it;
|
||||
++r_it;
|
||||
}
|
||||
return true;
|
||||
return lcase_equal(_Left, _Right);
|
||||
}
|
||||
};
|
||||
|
||||
struct SCP_string_lcase_less_than {
|
||||
bool operator()(const SCP_string& _Left, const SCP_string& _Right) const {
|
||||
auto l_it = _Left.cbegin();
|
||||
auto r_it = _Right.cbegin();
|
||||
while (true) {
|
||||
if (l_it == _Left.cend()) {
|
||||
return (r_it != _Right.cend());
|
||||
} else if (r_it == _Right.cend()) {
|
||||
return false;
|
||||
}
|
||||
auto lch = SCP_tolower(*l_it);
|
||||
auto rch = SCP_tolower(*r_it);
|
||||
if (lch < rch) {
|
||||
return true;
|
||||
} else if (lch > rch) {
|
||||
return false;
|
||||
}
|
||||
++l_it;
|
||||
++r_it;
|
||||
}
|
||||
return true;
|
||||
return lcase_lessthan(_Left, _Right);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+34
-11
@@ -30,6 +30,7 @@
|
||||
#include "graphics/util/GPUMemoryHeap.h"
|
||||
#include "graphics/util/UniformBuffer.h"
|
||||
#include "graphics/util/UniformBufferManager.h"
|
||||
#include "graphics/shadows.h"
|
||||
#include "io/mouse.h"
|
||||
#include "libs/jansson.h"
|
||||
#include "options/Option.h"
|
||||
@@ -111,7 +112,7 @@ static bool gamma_change_listener(float new_val, bool initial)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto GammaOption =
|
||||
static auto GammaOption __UNUSED =
|
||||
options::OptionBuilder<float>("Graphics.Gamma", "Brightness", "The brighness value used for the game window")
|
||||
.category("Graphics")
|
||||
.default_val(1.0f)
|
||||
@@ -127,7 +128,7 @@ const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum"
|
||||
{ 3, "High" },
|
||||
{ 4, "Ultra" }, };
|
||||
|
||||
const auto LightingOption = options::OptionBuilder<int>("Graphics.Lighting", "Lighting", "Level of detail of the lighting")
|
||||
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting", "Lighting", "Level of detail of the lighting")
|
||||
.importance(1)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
@@ -161,7 +162,7 @@ static bool mode_change_func(os::ViewportState state, bool initial)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto WindowModeOption = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode", "Window Mode",
|
||||
static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode", "Window Mode",
|
||||
"Controls how the game window is created.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
@@ -174,7 +175,7 @@ static auto WindowModeOption = options::OptionBuilder<os::ViewportState>("Graphi
|
||||
.finish();
|
||||
|
||||
const std::shared_ptr<scripting::OverridableHook<>> OnFrameHook = scripting::OverridableHook<>::Factory(
|
||||
"On Frame", "Called every frame as the last action before showing the frame result to the user.", {}, CHA_ONFRAME);
|
||||
"On Frame", "Called every frame as the last action before showing the frame result to the user.", {}, tl::nullopt, CHA_ONFRAME);
|
||||
|
||||
// z-buffer stuff
|
||||
int gr_zbuffering = 0;
|
||||
@@ -373,7 +374,7 @@ static auto ResolutionOption =
|
||||
|
||||
bool Gr_enable_soft_particles = false;
|
||||
|
||||
static auto SoftParticlesOption = options::OptionBuilder<bool>("Graphics.SoftParticles", "Soft Particles",
|
||||
static auto SoftParticlesOption __UNUSED = options::OptionBuilder<bool>("Graphics.SoftParticles", "Soft Particles",
|
||||
"Enable or disable soft particle rendering.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
@@ -384,7 +385,7 @@ static auto SoftParticlesOption = options::OptionBuilder<bool>("Graphics.SoftPar
|
||||
|
||||
flagset<FramebufferEffects> Gr_framebuffer_effects;
|
||||
|
||||
static auto FramebufferEffectsOption =
|
||||
static auto FramebufferEffectsOption __UNUSED =
|
||||
options::OptionBuilder<flagset<FramebufferEffects>>(
|
||||
"Graphics.FramebufferEffects", "Framebuffer effects",
|
||||
"Controls which framebuffer effects will be applied to the scene.")
|
||||
@@ -402,7 +403,7 @@ static auto FramebufferEffectsOption =
|
||||
AntiAliasMode Gr_aa_mode = AntiAliasMode::None;
|
||||
AntiAliasMode Gr_aa_mode_last_frame = AntiAliasMode::None;
|
||||
|
||||
static auto AAOption = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode", "Anti Aliasing",
|
||||
static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode", "Anti Aliasing",
|
||||
"Controls the anti aliasing mode of the engine.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
@@ -419,6 +420,20 @@ static auto AAOption = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode",
|
||||
.importance(79)
|
||||
.finish();
|
||||
|
||||
extern int Cmdline_msaa_enabled;
|
||||
static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamples", "Multisample Anti Aliasing",
|
||||
"Controls whether multisample anti aliasing is enabled, and with how many samples.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{0, "Off"},
|
||||
{4, "4 Samples"},
|
||||
{8, "8 Samples"},
|
||||
{16, "16 Samples"}})
|
||||
.default_val(0)
|
||||
.bind_to(&Cmdline_msaa_enabled)
|
||||
.importance(78)
|
||||
.finish();
|
||||
|
||||
bool gr_is_fxaa_mode(AntiAliasMode mode)
|
||||
{
|
||||
return mode == AntiAliasMode::FXAA_Low || mode == AntiAliasMode::FXAA_Medium || mode == AntiAliasMode::FXAA_High;
|
||||
@@ -429,7 +444,7 @@ bool gr_is_smaa_mode(AntiAliasMode mode) {
|
||||
|
||||
bool Gr_post_processing_enabled = true;
|
||||
|
||||
static auto PostProcessOption =
|
||||
static auto PostProcessOption __UNUSED =
|
||||
options::OptionBuilder<bool>("Graphics.PostProcessing", "Post processing",
|
||||
"Controls whether post processing is enabled in the engine")
|
||||
.category("Graphics")
|
||||
@@ -441,7 +456,7 @@ static auto PostProcessOption =
|
||||
|
||||
bool Gr_enable_vsync = true;
|
||||
|
||||
static auto VSyncOption = options::OptionBuilder<bool>("Graphics.VSync", "Vertical Sync",
|
||||
static auto VSyncOption __UNUSED = options::OptionBuilder<bool>("Graphics.VSync", "Vertical Sync",
|
||||
"Controls how the engine does vertical synchronization")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
@@ -1537,6 +1552,9 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
depth = d_depth;
|
||||
}
|
||||
|
||||
if (Cmdline_vulkan)
|
||||
mode = GR_VULKAN;
|
||||
|
||||
// if we are in standalone mode then just use special defaults
|
||||
if (Is_standalone) {
|
||||
mode = GR_STUB;
|
||||
@@ -1676,6 +1694,11 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
|
||||
Gr_inited = 1;
|
||||
|
||||
if (!gr_is_capable(CAPABILITY_SHADOWS) && Shadow_quality != ShadowQuality::Disabled) {
|
||||
Warning(LOCATION, "Shadows are enabled, but the system does not fulfill the requirements. Disabling shadows...");
|
||||
Shadow_quality = ShadowQuality::Disabled;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1769,7 +1792,7 @@ void gr_set_color( int r, int g, int b )
|
||||
gr_init_color( &gr_screen.current_color, r, g, b );
|
||||
}
|
||||
|
||||
void gr_set_color_fast(color *dst)
|
||||
void gr_set_color_fast(const color *dst)
|
||||
{
|
||||
gr_screen.current_color = *dst;
|
||||
}
|
||||
@@ -2569,7 +2592,7 @@ void gr_flip(bool execute_scripting)
|
||||
|
||||
void gr_print_timestamp(int x, int y, fix timestamp, int resize_mode)
|
||||
{
|
||||
int seconds = fl2i(f2fl(timestamp));
|
||||
int seconds = f2i(timestamp);
|
||||
|
||||
// format the time information into strings
|
||||
SCP_string time;
|
||||
|
||||
Loaded 100 of 603 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user