mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 04:49:39 -10:00
Compare commits
1077
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db5a90c955 | ||
|
|
95f26ef625 | ||
|
|
bc7654392a | ||
|
|
760b035a3a | ||
|
|
ce2fd88c24 | ||
|
|
3d6c02ffe2 | ||
|
|
2aae150981 | ||
|
|
620afa0c1e | ||
|
|
7fdcd4abc7 | ||
|
|
18394f7074 | ||
|
|
8bde63a9ae | ||
|
|
f021e9df8a | ||
|
|
4a1d794a64 | ||
|
|
fecb9b16af | ||
|
|
7e637d5d5a | ||
|
|
ff5bc2f6a0 | ||
|
|
c08a669c2e | ||
|
|
03f6f09c93 | ||
|
|
74c2a204c7 | ||
|
|
a9ad87ea08 | ||
|
|
0a86623e9e | ||
|
|
2f957668e3 | ||
|
|
38d9a975ce | ||
|
|
f26643c43d | ||
|
|
c2cb07ded3 | ||
|
|
7a04f76a46 | ||
|
|
006d2a49b1 | ||
|
|
a281f35f1a | ||
|
|
88f7e41d8c | ||
|
|
f2998a2c69 | ||
|
|
1b0a3ea6f9 | ||
|
|
5e274a008c | ||
|
|
38be5c248c | ||
|
|
0450ef0d1a | ||
|
|
e6a2a2a7f9 | ||
|
|
bbb6a6f199 | ||
|
|
1c0b58e11b | ||
|
|
0bf0735cd9 | ||
|
|
cc3791b594 | ||
|
|
799906a921 | ||
|
|
043e3fab79 | ||
|
|
2e34c29215 | ||
|
|
96228d6e98 | ||
|
|
dc4daafd61 | ||
|
|
4b37796628 | ||
|
|
45a434a60a | ||
|
|
488ec8d5a8 | ||
|
|
b1460eb3fa | ||
|
|
671fe21a75 | ||
|
|
d6606ad642 | ||
|
|
d9b2b428a0 | ||
|
|
e87fcfaf28 | ||
|
|
65d1b7f99a | ||
|
|
712337a2da | ||
|
|
b9169cc425 | ||
|
|
b7a0124a9b | ||
|
|
27925607b8 | ||
|
|
38d8f17990 | ||
|
|
5143855863 | ||
|
|
648a1d009d | ||
|
|
df531fc595 | ||
|
|
5802f718f6 | ||
|
|
7d62d741b9 | ||
|
|
45258aabb4 | ||
|
|
db34b4d53c | ||
|
|
7c2077baf2 | ||
|
|
eef7623e9f | ||
|
|
529ac05034 | ||
|
|
6ac8559630 | ||
|
|
2626e7862b | ||
|
|
b3cd35258c | ||
|
|
0fb12b89eb | ||
|
|
c082babd9c | ||
|
|
d5f3be091c | ||
|
|
790227a2bf | ||
|
|
803f08f969 | ||
|
|
f2c40a2669 | ||
|
|
63756c00af | ||
|
|
2147571dff | ||
|
|
bb9c76103b | ||
|
|
857e61f638 | ||
|
|
58053a02b2 | ||
|
|
e8ea8733d0 | ||
|
|
184bbb52bb | ||
|
|
b00410ab01 | ||
|
|
525d8e34d0 | ||
|
|
4cdf10b399 | ||
|
|
c652d5a84c | ||
|
|
1a356834b4 | ||
|
|
3f48f7c4ad | ||
|
|
3e8a9d9738 | ||
|
|
592eefb60f | ||
|
|
373218d7d9 | ||
|
|
1bdd6c3c4c | ||
|
|
1313434e11 | ||
|
|
bf996313dc | ||
|
|
2eb5a3ecde | ||
|
|
1aee2401e5 | ||
|
|
f8203e9da3 | ||
|
|
b24bcbcc62 | ||
|
|
0b8c1b6853 | ||
|
|
6ae6c550a7 | ||
|
|
9c521d04d8 | ||
|
|
c6c9945e50 | ||
|
|
8dfeca4ac3 | ||
|
|
bb4898cb04 | ||
|
|
6e38656658 | ||
|
|
e72dd4c2ca | ||
|
|
be8725c6c6 | ||
|
|
15c921223b | ||
|
|
ec241fcab3 | ||
|
|
0e00ab670c | ||
|
|
1f9a2ca4ce | ||
|
|
0d697672dc | ||
|
|
1fe62ea8d1 | ||
|
|
687694c732 | ||
|
|
9093af9b95 | ||
|
|
3b0dca6cd9 | ||
|
|
817b7dc975 | ||
|
|
d4d7c8dbd2 | ||
|
|
bb89553b0a | ||
|
|
e4acd15a1e | ||
|
|
d16f46fb1c | ||
|
|
77ad3ba0aa | ||
|
|
da31995331 | ||
|
|
25d326567e | ||
|
|
03696d07ca | ||
|
|
0528538a6f | ||
|
|
3a48613a2d | ||
|
|
a7b795e965 | ||
|
|
99875810c6 | ||
|
|
13420121dd | ||
|
|
26c5152d4a | ||
|
|
5066e498a3 | ||
|
|
4bf806c485 | ||
|
|
2403f13483 | ||
|
|
8e98cddd6e | ||
|
|
30cabc4174 | ||
|
|
8a3b36d921 | ||
|
|
b74824f793 | ||
|
|
6a26ca5061 | ||
|
|
9b78fad1c5 | ||
|
|
d34570ae90 | ||
|
|
a0f4c4d2b3 | ||
|
|
63990c54a9 | ||
|
|
6593565165 | ||
|
|
af93922ba5 | ||
|
|
daeb1a7940 | ||
|
|
f56cbc59f1 | ||
|
|
79418a073d | ||
|
|
ce2e165510 | ||
|
|
e9ee311709 | ||
|
|
7576d4f2fe | ||
|
|
866b06ca35 | ||
|
|
f4d7b45e4d | ||
|
|
d23e4b8e87 | ||
|
|
f3d15f8ddc | ||
|
|
c9fe191d31 | ||
|
|
bad255fffb | ||
|
|
be260ef74c | ||
|
|
0ac3d52261 | ||
|
|
f7df03c654 | ||
|
|
a7e1a27e36 | ||
|
|
d83de47ef2 | ||
|
|
59435abfb2 | ||
|
|
ab319a631c | ||
|
|
7c2950480e | ||
|
|
a80bc26bfc | ||
|
|
ead3c62d23 | ||
|
|
5cd502fb79 | ||
|
|
905d777e18 | ||
|
|
66deb83980 | ||
|
|
de3e382180 | ||
|
|
0190fda7ee | ||
|
|
9651dc1598 | ||
|
|
743cf779bf | ||
|
|
bf13ce54a8 | ||
|
|
fcd3264fad | ||
|
|
e33419c48d | ||
|
|
a73df5bcb4 | ||
|
|
4e707fc8e9 | ||
|
|
2e7057ed8d | ||
|
|
ba9285e09a | ||
|
|
138eddfbd2 | ||
|
|
66be185d0c | ||
|
|
0c355efaa2 | ||
|
|
89a6e2aa7d | ||
|
|
84033d901c | ||
|
|
4b49123070 | ||
|
|
213bcbc80b | ||
|
|
0da34f0bc8 | ||
|
|
8fcf385e7e | ||
|
|
4f4722ccad | ||
|
|
7d94561ea5 | ||
|
|
248cec7cf9 | ||
|
|
e987d1cd7b | ||
|
|
f1aa29551b | ||
|
|
76734fb5ed | ||
|
|
fb0a62c400 | ||
|
|
1403301b65 | ||
|
|
1d1eb5ec4d | ||
|
|
7283412880 | ||
|
|
1d2ca8eb5a | ||
|
|
130ddb41f1 | ||
|
|
9462241c0b | ||
|
|
14bba9aea1 | ||
|
|
c7b43b0e0e | ||
|
|
1355c484fe | ||
|
|
1866c6adb5 | ||
|
|
a11517984e | ||
|
|
f207d2d12c | ||
|
|
4970252e9f | ||
|
|
d789e9b33a | ||
|
|
292f7d3b03 | ||
|
|
3bfc37172a | ||
|
|
2bb1c10557 | ||
|
|
40fac5dd5f | ||
|
|
2a33e374c2 | ||
|
|
d48d00d946 | ||
|
|
562875130c | ||
|
|
4401101fea | ||
|
|
509f887f6c | ||
|
|
266079997a | ||
|
|
f4a3903478 | ||
|
|
f4202df450 | ||
|
|
e619c0c3d3 | ||
|
|
ff0b79b6be | ||
|
|
701d20c112 | ||
|
|
9a45c9fd05 | ||
|
|
146102e82c | ||
|
|
be2c18d608 | ||
|
|
c9644cdcae | ||
|
|
d088e895f8 | ||
|
|
f1a9b2639b | ||
|
|
a1690dcb90 | ||
|
|
2c4088efdd | ||
|
|
da3725a3ac | ||
|
|
81b7460e57 | ||
|
|
c9a1127764 | ||
|
|
6eb9ae2aec | ||
|
|
d3d9ee3092 | ||
|
|
f66fc92859 | ||
|
|
94cbc350a4 | ||
|
|
550e9ec5b2 | ||
|
|
de3463958d | ||
|
|
03d7845124 | ||
|
|
661dceb0d8 | ||
|
|
202686dab6 | ||
|
|
b8da1106eb | ||
|
|
43f7921121 | ||
|
|
f4669db41c | ||
|
|
b3df3364e4 | ||
|
|
b6a76b788d | ||
|
|
e21b07662e | ||
|
|
9b4b0b552b | ||
|
|
bdab7a0c55 | ||
|
|
e269cdab6e | ||
|
|
edc76bcb40 | ||
|
|
cbde5a8e85 | ||
|
|
7fcfc35820 | ||
|
|
f852421d76 | ||
|
|
2321311725 | ||
|
|
38cd1bff86 | ||
|
|
71ee9501f9 | ||
|
|
221670589e | ||
|
|
9a47a664f7 | ||
|
|
7b7b19b71b | ||
|
|
666b9a5751 | ||
|
|
733e1adcba | ||
|
|
8421d8d8e6 | ||
|
|
63ed4c8254 | ||
|
|
3124c55642 | ||
|
|
485eb16fe3 | ||
|
|
a493f07333 | ||
|
|
366c1a9d0b | ||
|
|
0594a487c8 | ||
|
|
f8733eab72 | ||
|
|
8dcc4a24e9 | ||
|
|
bf4d7a3114 | ||
|
|
5e8a4f754d | ||
|
|
d0a537ff82 | ||
|
|
e7c98d6d23 | ||
|
|
36e7598ceb | ||
|
|
0672bd94e9 | ||
|
|
c7792cd781 | ||
|
|
252392b26a | ||
|
|
65677542cb | ||
|
|
691bbca2b2 | ||
|
|
cd95b143a0 | ||
|
|
a360a1f5f1 | ||
|
|
d1119b2353 | ||
|
|
c37e1b1c96 | ||
|
|
fd6ca9dde9 | ||
|
|
fbb3a8f6a5 | ||
|
|
0e63d64647 | ||
|
|
de50f693ae | ||
|
|
6e9b31cb5a | ||
|
|
e316c28258 | ||
|
|
1ef528af5f | ||
|
|
e536413259 | ||
|
|
ccbe7efcbe | ||
|
|
1fcf51bd92 | ||
|
|
b9938b854f | ||
|
|
ad06cb1c5b | ||
|
|
b62a7fbe3d | ||
|
|
4011a0800d | ||
|
|
8f7c6a0ed8 | ||
|
|
9e719440c9 | ||
|
|
6692540cbf | ||
|
|
668fc18d5c | ||
|
|
a101e3cf77 | ||
|
|
dcce4a6538 | ||
|
|
7ce3217f17 | ||
|
|
33a1b1f8ca | ||
|
|
a29a97f39a | ||
|
|
8d40d7467e | ||
|
|
eb57482c1a | ||
|
|
50f083043b | ||
|
|
d02bd6ca04 | ||
|
|
e543c1aea2 | ||
|
|
22962afcde | ||
|
|
1f9c9a3673 | ||
|
|
f3922f35e8 | ||
|
|
bb5bfad828 | ||
|
|
18ac8425ee | ||
|
|
f6167bb89a | ||
|
|
c8ceb289ba | ||
|
|
9ea64627ab | ||
|
|
6e9ca36481 | ||
|
|
90dbdc4236 | ||
|
|
3a35f7ebe7 | ||
|
|
05f190b36c | ||
|
|
0924a392aa | ||
|
|
21db833dee | ||
|
|
86011f2669 | ||
|
|
2bd143e093 | ||
|
|
79d3077071 | ||
|
|
aacd14e1df | ||
|
|
43afcd5ea6 | ||
|
|
b98544d862 | ||
|
|
7867dc77bd | ||
|
|
426c227b68 | ||
|
|
612bdcf4df | ||
|
|
0d712d6fc0 | ||
|
|
62fa0c081b | ||
|
|
8035a2b32a | ||
|
|
f7f2c58746 | ||
|
|
7bf0fd137d | ||
|
|
6d818f1e3b | ||
|
|
e23b5533aa | ||
|
|
6b79571edc | ||
|
|
27f022b2f2 | ||
|
|
4578fbc900 | ||
|
|
bfde2144a2 | ||
|
|
1787f4457b | ||
|
|
be14c34f7d | ||
|
|
da66bd65da | ||
|
|
dc7aa86147 | ||
|
|
4bf743765c | ||
|
|
b4e3ebe085 | ||
|
|
ada432a1f3 | ||
|
|
25d796afe4 | ||
|
|
1a034031d1 | ||
|
|
23098666e2 | ||
|
|
5490751167 | ||
|
|
4bc9cf0846 | ||
|
|
dd9248fc22 | ||
|
|
c2ed03ca59 | ||
|
|
7491a82d74 | ||
|
|
2f0c0f1d6f | ||
|
|
3b231b375f | ||
|
|
07fb5bec0e | ||
|
|
e51815a933 | ||
|
|
ea6e503ea1 | ||
|
|
a381ecc607 | ||
|
|
125e47d749 | ||
|
|
d280800bce | ||
|
|
a1c9b108ed | ||
|
|
d7a06c893f | ||
|
|
3aa672c855 | ||
|
|
8acbe82aa0 | ||
|
|
5227e2e0c4 | ||
|
|
95baa85750 | ||
|
|
fb1ffd8413 | ||
|
|
f43732c5da | ||
|
|
8dbe0e7b8a | ||
|
|
3ad66b988d | ||
|
|
969759426a | ||
|
|
224503391f | ||
|
|
0edc6267aa | ||
|
|
def75287eb | ||
|
|
c427014fc2 | ||
|
|
99d140fb83 | ||
|
|
808e5bedd9 | ||
|
|
6dfd1ed0b8 | ||
|
|
0d1d6fdf44 | ||
|
|
369b90a156 | ||
|
|
7bb6a8ae86 | ||
|
|
7afb00e976 | ||
|
|
c4fe9e664f | ||
|
|
eda9f16294 | ||
|
|
f7dddc35d1 | ||
|
|
b8806e958d | ||
|
|
40cf32133f | ||
|
|
691ec74406 | ||
|
|
359886fee1 | ||
|
|
9b86d2f16d | ||
|
|
260f15624b | ||
|
|
6de870766a | ||
|
|
072e802863 | ||
|
|
2ca9d6672c | ||
|
|
7281e8d127 | ||
|
|
a730f30435 | ||
|
|
cd5f044217 | ||
|
|
8b90cda3f4 | ||
|
|
6b2ced4643 | ||
|
|
5ee051c55f | ||
|
|
ecc452088c | ||
|
|
841ae430c0 | ||
|
|
3f7ffdb6a0 | ||
|
|
737717fe3f | ||
|
|
a463ac19cf | ||
|
|
9d0ee6ab0d | ||
|
|
703269aa71 | ||
|
|
b7a0170cd1 | ||
|
|
6f263365af | ||
|
|
6435843c24 | ||
|
|
22ee5d5c15 | ||
|
|
5fadb12b0f | ||
|
|
e94c515ab8 | ||
|
|
d83ddeed0f | ||
|
|
3556d41b44 | ||
|
|
f2df96b4bb | ||
|
|
9eeb3307d0 | ||
|
|
a406b43876 | ||
|
|
c86802e9c1 | ||
|
|
5b4065bd53 | ||
|
|
5fd439fb60 | ||
|
|
2043f836ed | ||
|
|
4a3c7fc9a9 | ||
|
|
e0e3f7e7ac | ||
|
|
542d9741c4 | ||
|
|
68eef5949b | ||
|
|
7958670868 | ||
|
|
226ed40cec | ||
|
|
d454a74716 | ||
|
|
4ff96abd9e | ||
|
|
5bc1200731 | ||
|
|
b23dff91e7 | ||
|
|
3af831e0b7 | ||
|
|
bcae459b56 | ||
|
|
ff7d85a60f | ||
|
|
267fcfc6f8 | ||
|
|
8587bf768b | ||
|
|
535ff9f99a | ||
|
|
422ccaa514 | ||
|
|
a3e27f566f | ||
|
|
9ecb451efe | ||
|
|
e3d2c02f99 | ||
|
|
13170a235e | ||
|
|
5406445ed4 | ||
|
|
301b9453b6 | ||
|
|
cd32c2ce42 | ||
|
|
7b1b1113da | ||
|
|
1f32834d9d | ||
|
|
bee0742aa2 | ||
|
|
d336d395db | ||
|
|
1953bd9c49 | ||
|
|
e27cbe9517 | ||
|
|
4b5d4320f8 | ||
|
|
ed7f3e6880 | ||
|
|
980d2c2bcc | ||
|
|
17dfa0ddb9 | ||
|
|
5f511e34e3 | ||
|
|
31c8739ecd | ||
|
|
8e23c32b8c | ||
|
|
b628b665cf | ||
|
|
7a367b10ad | ||
|
|
09c885c4af | ||
|
|
9ac6060abd | ||
|
|
a34f37fa8d | ||
|
|
7645704ac2 | ||
|
|
b25e76cb65 | ||
|
|
a9cfd27455 | ||
|
|
110f609dea | ||
|
|
ba3ac66958 | ||
|
|
274366c8ad | ||
|
|
df285b7ae1 | ||
|
|
7eec846b3d | ||
|
|
25a9f6abe2 | ||
|
|
f0737f1b87 | ||
|
|
dbefa6d333 | ||
|
|
54c0680b2a | ||
|
|
058cec3d2c | ||
|
|
a73cc9bfce | ||
|
|
245ac3f6b3 | ||
|
|
ee6159c685 | ||
|
|
68f9d90629 | ||
|
|
2523218fdc | ||
|
|
b323760659 | ||
|
|
5a93f78933 | ||
|
|
e99341d79f | ||
|
|
54a188d46a | ||
|
|
f686046a1d | ||
|
|
61f8e0370b | ||
|
|
397125fc6e | ||
|
|
6f458d5398 | ||
|
|
1223808a14 | ||
|
|
19c4c6edba | ||
|
|
bfeb86f017 | ||
|
|
e7ded2b4cd | ||
|
|
b2d1da6701 | ||
|
|
d0086c31b8 | ||
|
|
d9786f8aae | ||
|
|
fe916eb7ce | ||
|
|
a476897963 | ||
|
|
e404f32c7b | ||
|
|
77a2f5345f | ||
|
|
41efb57879 | ||
|
|
729aa2f6f7 | ||
|
|
346ce5c975 | ||
|
|
d1d64a0afb | ||
|
|
94cd6cf8bb | ||
|
|
9b09818b49 | ||
|
|
1ab0d74939 | ||
|
|
474db9e184 | ||
|
|
36cb7a62d6 | ||
|
|
cb1f1e9c0b | ||
|
|
9dc291569f | ||
|
|
5da1a075ad | ||
|
|
ad05ce147e | ||
|
|
9a227de872 | ||
|
|
d4ca441449 | ||
|
|
4ea99eb461 | ||
|
|
e01dabeb59 | ||
|
|
27e80a3fff | ||
|
|
3ab8cb097c | ||
|
|
3721f8165d | ||
|
|
f94119d722 | ||
|
|
5e78054a66 | ||
|
|
cfe64748a4 | ||
|
|
7a281781e3 | ||
|
|
a859192587 | ||
|
|
fa49d05e0c | ||
|
|
d8ff77f57f | ||
|
|
fdc8c246f5 | ||
|
|
395aadba6b | ||
|
|
1625d86ad7 | ||
|
|
187d24c2f4 | ||
|
|
47ac8a56a0 | ||
|
|
72ccbff147 | ||
|
|
9960d4bc9f | ||
|
|
2334138b99 | ||
|
|
a0b7134b9b | ||
|
|
b20efdec80 | ||
|
|
b546dcf949 | ||
|
|
15329b9564 | ||
|
|
94bd1af5cd | ||
|
|
367f48cf2f | ||
|
|
eff00035fa | ||
|
|
ba2c2f03fb | ||
|
|
309bf0b3ea | ||
|
|
b62c49ec81 | ||
|
|
e34c82d7d1 | ||
|
|
67e00da79b | ||
|
|
8528bfe750 | ||
|
|
37c344a127 | ||
|
|
b5b922cbf0 | ||
|
|
1cbeae2cd9 | ||
|
|
4292303018 | ||
|
|
3ebdc51c48 | ||
|
|
6e8ab64523 | ||
|
|
1b04d9f22c | ||
|
|
4013cf6046 | ||
|
|
26df8e9a45 | ||
|
|
bb3e3eadfc | ||
|
|
b5e215a85c | ||
|
|
da4eeb3582 | ||
|
|
dc578c2479 | ||
|
|
3522f3be91 | ||
|
|
bd52d75ab9 | ||
|
|
a54dc0ded7 | ||
|
|
c076cd11f1 | ||
|
|
b42c7af847 | ||
|
|
5893ef836c | ||
|
|
9eeb7e7983 | ||
|
|
71fa18927c | ||
|
|
ae89ed2b9d | ||
|
|
24a4c0df6a | ||
|
|
a5f90ddcc1 | ||
|
|
3fe94fc3f4 | ||
|
|
f89d437506 | ||
|
|
86a8c1c6f5 | ||
|
|
f72fb68615 | ||
|
|
3447b76736 | ||
|
|
7dd52a4214 | ||
|
|
8671b9e2f7 | ||
|
|
b861989fb6 | ||
|
|
1c8a272eca | ||
|
|
221b0dc7ee | ||
|
|
0a5cf6ad9d | ||
|
|
2cb12b8ff7 | ||
|
|
9f173e8cd9 | ||
|
|
6588daaca5 | ||
|
|
9cd648a206 | ||
|
|
44c797f65b | ||
|
|
46b9c27dfe | ||
|
|
33e3b13d43 | ||
|
|
8351d4f623 | ||
|
|
e0443739bd | ||
|
|
80a206151c | ||
|
|
64a592d0d5 | ||
|
|
c30559a63a | ||
|
|
245cec5a34 | ||
|
|
ddedc1bd8e | ||
|
|
6b71812e7b | ||
|
|
844e9affea | ||
|
|
b69cdc08ee | ||
|
|
69d56172b0 | ||
|
|
9d2a89f778 | ||
|
|
adcc19085d | ||
|
|
faddde8307 | ||
|
|
0355d2b8d1 | ||
|
|
21f42ce47b | ||
|
|
574b1e6197 | ||
|
|
34e57d301a | ||
|
|
dc83e4f14a | ||
|
|
3c837b7e9a | ||
|
|
c7b77a5b24 | ||
|
|
5a58ff46f2 | ||
|
|
4145717363 | ||
|
|
eca583074a | ||
|
|
723bdcb9f1 | ||
|
|
cb4fe955ea | ||
|
|
ed83ed79ec | ||
|
|
02669338e8 | ||
|
|
6e86a3a035 | ||
|
|
4f8344c91e | ||
|
|
643d18c6f8 | ||
|
|
8dc481d034 | ||
|
|
3ba2193d3f | ||
|
|
8693fa37eb | ||
|
|
3764146957 | ||
|
|
50c923d397 | ||
|
|
617c903cbd | ||
|
|
b6903fbdf4 | ||
|
|
dc751a9c5d | ||
|
|
dff0b2acb4 | ||
|
|
ea10ac157f | ||
|
|
173a3d23e8 | ||
|
|
98e20c0979 | ||
|
|
db02a829aa | ||
|
|
cfe92a4d32 | ||
|
|
7f9a10a9a0 | ||
|
|
925e2e53f4 | ||
|
|
0e7f24bcac | ||
|
|
b2d85b8e2f | ||
|
|
e23409f5f8 | ||
|
|
381e45f483 | ||
|
|
2d2db58905 | ||
|
|
2b3da41a6d | ||
|
|
9da948be56 | ||
|
|
79454fb6c4 | ||
|
|
10ed12182c | ||
|
|
6038076bf0 | ||
|
|
40c8cbbb25 | ||
|
|
bd7429c353 | ||
|
|
faf130adb3 | ||
|
|
f7fef072df | ||
|
|
0da6a4a64c | ||
|
|
f542fea96e | ||
|
|
742326e42e | ||
|
|
e25a6517fc | ||
|
|
be0c78dc72 | ||
|
|
ef681affbf | ||
|
|
729e448fe5 | ||
|
|
96ae3d0608 | ||
|
|
55ed0a08f6 | ||
|
|
3a2ac5ab5f | ||
|
|
435676a67d | ||
|
|
c017ef9b8a | ||
|
|
4fbe3b7131 | ||
|
|
e071603ac0 | ||
|
|
87a4ae1e41 | ||
|
|
c738941ccf | ||
|
|
5c25bb9bcb | ||
|
|
e0bc6d0ed7 | ||
|
|
e6792ab441 | ||
|
|
ec706a6a87 | ||
|
|
5d0127a764 | ||
|
|
91c15e6f48 | ||
|
|
a9fc7bab8a | ||
|
|
042c85d213 | ||
|
|
bb3d59ecbe | ||
|
|
d1c57391cf | ||
|
|
5d6c34c2ab | ||
|
|
5986b7143f | ||
|
|
5d447951b4 | ||
|
|
f149c36b44 | ||
|
|
34b6cf74ab | ||
|
|
bc33f90e32 | ||
|
|
bb47531c55 | ||
|
|
aed90493ec | ||
|
|
d54c3e51e3 | ||
|
|
a215bea0d0 | ||
|
|
ec23f6bd0e | ||
|
|
d93d56e1c9 | ||
|
|
d2265325e9 | ||
|
|
2bb22a2153 | ||
|
|
018c22eee1 | ||
|
|
6ef60c67ca | ||
|
|
982e8d7f85 | ||
|
|
8affd53cf6 | ||
|
|
eeaf894b15 | ||
|
|
b546d897ae | ||
|
|
d8aea4ad30 | ||
|
|
829692b7bd | ||
|
|
855935d4eb | ||
|
|
f83efb54c0 | ||
|
|
3ca26587eb | ||
|
|
3e2bb36d4b | ||
|
|
02bd62ff3c | ||
|
|
e1e0239914 | ||
|
|
17ad0e09dd | ||
|
|
e621dbe997 | ||
|
|
ea5c328c13 | ||
|
|
8c0bc25303 | ||
|
|
6b0a3b7606 | ||
|
|
9afe76b5d2 | ||
|
|
ad27664ebc | ||
|
|
2fe182a4b1 | ||
|
|
60c2718b91 | ||
|
|
15d9b9b3db | ||
|
|
a0c787aa83 | ||
|
|
d00003e199 | ||
|
|
991d0ee2d6 | ||
|
|
ee27abf693 | ||
|
|
6bcd2f730c | ||
|
|
c8d78816b0 | ||
|
|
3eee74a31c | ||
|
|
941d5f7ec3 | ||
|
|
b53f3fc803 | ||
|
|
d1f0b9343f | ||
|
|
0b2d4768f3 | ||
|
|
42fc9891e3 | ||
|
|
0cde26dd6e | ||
|
|
7804f7fff5 | ||
|
|
832cec27ad | ||
|
|
31acb115c2 | ||
|
|
f9591b3a92 | ||
|
|
21f92194f1 | ||
|
|
c605451460 | ||
|
|
2acdc65875 | ||
|
|
b7de2fd644 | ||
|
|
a226a81d80 | ||
|
|
eb39532f7c | ||
|
|
1478ace3e0 | ||
|
|
7edc5bf842 | ||
|
|
b8dc7d643d | ||
|
|
883ed32796 | ||
|
|
f3dfc85c0f | ||
|
|
bfd261a1d3 | ||
|
|
e32ea7b694 | ||
|
|
7ef70f6d4d | ||
|
|
1b1afbf8d7 | ||
|
|
bfdf05469b | ||
|
|
aee48373ab | ||
|
|
a2f1638a99 | ||
|
|
762cf4cb88 | ||
|
|
705287c8d4 | ||
|
|
e2aac31912 | ||
|
|
a9f5a11813 | ||
|
|
b8728ed828 | ||
|
|
de1110650f | ||
|
|
b3295e5a2d | ||
|
|
a6c1b1b04a | ||
|
|
b5fdf52e8c | ||
|
|
c43f5bdd58 | ||
|
|
dc7fc774b8 | ||
|
|
dad16f76c4 | ||
|
|
d10c59f6cc | ||
|
|
3bd2fc9a56 | ||
|
|
fabff58d09 | ||
|
|
2fd3bf091d | ||
|
|
b4442d3423 | ||
|
|
cf4cae7264 | ||
|
|
ebea1b1240 | ||
|
|
54341acb9b | ||
|
|
07fd188064 | ||
|
|
0cbe06884b | ||
|
|
c1d3e5a2ad | ||
|
|
2bcedc34cc | ||
|
|
16892c3e46 | ||
|
|
5c88b75b94 | ||
|
|
987c705bc9 | ||
|
|
b89cbbd530 | ||
|
|
d3383d9d87 | ||
|
|
4f6d9c36a8 | ||
|
|
a36157f582 | ||
|
|
3837455004 | ||
|
|
808f7a88c6 | ||
|
|
79702273d5 | ||
|
|
d06018bcad | ||
|
|
ac87cde80d | ||
|
|
06d9e02c34 | ||
|
|
40233ae05f | ||
|
|
57192065d6 | ||
|
|
d2031a476a | ||
|
|
c60ea2d4a7 | ||
|
|
6843d48358 | ||
|
|
066b251052 | ||
|
|
4596600627 | ||
|
|
ea262f90c0 | ||
|
|
02e84f212a | ||
|
|
a1d92afebf | ||
|
|
a20f3ca030 | ||
|
|
e132fcf74c | ||
|
|
7a4df25fc5 | ||
|
|
08dfcc8b74 | ||
|
|
0def45b381 | ||
|
|
be6a2b9196 | ||
|
|
f7413be1d8 | ||
|
|
02233fc439 | ||
|
|
febd8cd2ad | ||
|
|
bf7125724d | ||
|
|
efce98db47 | ||
|
|
0c8564f085 | ||
|
|
45abdefc07 | ||
|
|
73c612034b | ||
|
|
1ae9aaab21 | ||
|
|
3a46ed66ba | ||
|
|
f98806b034 | ||
|
|
1812efa209 | ||
|
|
2966757e62 | ||
|
|
bc3aad374e | ||
|
|
dcfea6f141 | ||
|
|
c5d192524e | ||
|
|
7a47cc0521 | ||
|
|
a33cc0f6c4 | ||
|
|
af4ec4facc | ||
|
|
d897643217 | ||
|
|
5688ba8637 | ||
|
|
6631975e45 | ||
|
|
fa2b135bb1 | ||
|
|
1ce9d46822 | ||
|
|
7f4d78f44a | ||
|
|
10f484a504 | ||
|
|
f0c8c9ad74 | ||
|
|
79579eda94 | ||
|
|
f7b9896294 | ||
|
|
be8ec82649 | ||
|
|
b72b7688f9 | ||
|
|
c2e01864d5 | ||
|
|
7a4d4466fd | ||
|
|
ec75cac4d9 | ||
|
|
b6c0e8b562 | ||
|
|
8d0570846b | ||
|
|
93d0624b3e | ||
|
|
563445466e | ||
|
|
b7e9d4c9cb | ||
|
|
348fb5ffb4 | ||
|
|
6d08a90106 | ||
|
|
92ed875e69 | ||
|
|
d754c2cb50 | ||
|
|
b760c5dec8 | ||
|
|
9c9b06a1b1 | ||
|
|
30da49be81 | ||
|
|
c2d0eafc36 | ||
|
|
e3c7f81412 | ||
|
|
2b155c7a30 | ||
|
|
df69993a84 | ||
|
|
3fb5bf1f5f | ||
|
|
6823e24350 | ||
|
|
305a7f6630 | ||
|
|
14a98e1470 | ||
|
|
4ba6191e0c | ||
|
|
cb5bf05424 | ||
|
|
b4f633767e | ||
|
|
15db3b17bc | ||
|
|
1dc701270f | ||
|
|
41b10e4d40 | ||
|
|
ba2c37a1fe | ||
|
|
aa997dd9ed | ||
|
|
6dbfba2c9f | ||
|
|
9748de5ec1 | ||
|
|
a0a523223c | ||
|
|
0765c7be95 | ||
|
|
73f8e57961 | ||
|
|
743d8dd666 | ||
|
|
8fbf22a055 | ||
|
|
7b410b2116 | ||
|
|
8fed4437ee | ||
|
|
ad25418f92 | ||
|
|
5972457ad5 | ||
|
|
35876bc17e | ||
|
|
f2d0bfdb31 | ||
|
|
6350a67e73 | ||
|
|
46fa212db6 | ||
|
|
d0d65cd30c | ||
|
|
cb0e9ce601 | ||
|
|
13bc0362c8 | ||
|
|
bfad425738 | ||
|
|
5749b856df | ||
|
|
f67814aaae | ||
|
|
24daea79f3 | ||
|
|
0f013f920b | ||
|
|
0811c7037b | ||
|
|
f13a5b3736 | ||
|
|
04a5778235 | ||
|
|
5a941c1d59 | ||
|
|
d0c3c7db21 | ||
|
|
be678c2f54 | ||
|
|
9586f21780 | ||
|
|
ed5a5861f7 | ||
|
|
16180306ad | ||
|
|
865045a231 | ||
|
|
e387038cc3 | ||
|
|
0b54c741a6 | ||
|
|
baa34f1ffe | ||
|
|
89b33ebbc5 | ||
|
|
53e6edf8bb | ||
|
|
0220ad0563 | ||
|
|
910521bdfe | ||
|
|
7003e5caa2 | ||
|
|
8efe146300 | ||
|
|
52b7a3d198 | ||
|
|
a14fb35713 | ||
|
|
2d0dc7798d | ||
|
|
8242e3b94b | ||
|
|
16cb6b3f2f | ||
|
|
8c9be400a6 | ||
|
|
7974a682ef | ||
|
|
41af098d19 | ||
|
|
4c95370f74 | ||
|
|
a6730a997c | ||
|
|
c5b84d9406 | ||
|
|
d2f5a12d5f | ||
|
|
6f6e839bbf | ||
|
|
065524fd4b | ||
|
|
c84cb7ab64 | ||
|
|
587ed4e41f | ||
|
|
8b8daece46 | ||
|
|
d73d46feb2 | ||
|
|
a881b339cc | ||
|
|
1f90be0a86 | ||
|
|
4ce02ce291 | ||
|
|
7d83ece711 | ||
|
|
9ee1a6eb23 | ||
|
|
f258554304 | ||
|
|
994048eb24 | ||
|
|
0af3197a90 | ||
|
|
e5824b41bb | ||
|
|
679c3606c5 | ||
|
|
acbab034cc | ||
|
|
45306da4fe | ||
|
|
f09c7b3ba5 | ||
|
|
964f495238 | ||
|
|
865f7e725c | ||
|
|
6a550a6701 | ||
|
|
ad2531efcc | ||
|
|
8af06b9e78 | ||
|
|
b6eef2e8f2 | ||
|
|
344e231058 | ||
|
|
2feeb34629 | ||
|
|
9d28ba568c | ||
|
|
1b6ed75d73 | ||
|
|
4cf7ab3474 | ||
|
|
b7045f1756 | ||
|
|
bd4b9cb0d7 | ||
|
|
926e10584c | ||
|
|
defab61664 | ||
|
|
7dc971a6f2 | ||
|
|
e0a6ca9abd | ||
|
|
210a9a8309 | ||
|
|
613fad21c9 | ||
|
|
91497d5056 | ||
|
|
6b3e50dade | ||
|
|
e796a4fe00 | ||
|
|
03f01604d9 | ||
|
|
1547526057 | ||
|
|
7602b88756 | ||
|
|
4812ff529d | ||
|
|
fe42c7bdff | ||
|
|
f706d6c0a0 | ||
|
|
16b9225533 | ||
|
|
9a7500de36 | ||
|
|
64d9b6fb74 | ||
|
|
b40f5a15b2 | ||
|
|
52a5c356cf | ||
|
|
e71dba4207 | ||
|
|
3b42ee42ca | ||
|
|
b270c44ede | ||
|
|
6cf6f8a6fe | ||
|
|
c273496c1e | ||
|
|
8933aaff38 | ||
|
|
a3de0db735 | ||
|
|
0dcb60f805 | ||
|
|
1bc7732b6e | ||
|
|
2a64abfe92 | ||
|
|
d1e81be2aa | ||
|
|
e285641ac6 | ||
|
|
d3b1ad4328 | ||
|
|
914f0e13e3 | ||
|
|
df68da3dd6 | ||
|
|
0219e65b00 | ||
|
|
cc171a6344 | ||
|
|
7d066a1c45 | ||
|
|
accb842ffa | ||
|
|
6677fcabae | ||
|
|
171d36bf7f | ||
|
|
9018ddf0d5 | ||
|
|
d847236dd2 | ||
|
|
bb6b010487 | ||
|
|
0ee3d099ab | ||
|
|
9aa48579b0 | ||
|
|
bb28d0b859 | ||
|
|
2ef3a935e4 | ||
|
|
233fa38890 | ||
|
|
97adef1d87 | ||
|
|
e91d6ed17b | ||
|
|
f6c86464aa | ||
|
|
dd0af0e07c | ||
|
|
24031db712 | ||
|
|
d82b02a54a | ||
|
|
a21876127d | ||
|
|
f64de84e7c | ||
|
|
feadc0bd69 | ||
|
|
bb6917ab3b | ||
|
|
1252d794db | ||
|
|
58fcbde152 | ||
|
|
b3970798e1 | ||
|
|
da34e25bc3 | ||
|
|
7fc75c0d6c | ||
|
|
859978fd84 | ||
|
|
7781d9fcda | ||
|
|
03e876f65b | ||
|
|
9480869e0a | ||
|
|
481e82303c | ||
|
|
689ac56bc8 | ||
|
|
c80f787d34 | ||
|
|
861a9c9c4a | ||
|
|
d2d1d8f996 | ||
|
|
46530b78b7 | ||
|
|
c5469982c8 | ||
|
|
db64a212d6 | ||
|
|
0a07b7e0ad | ||
|
|
cf3b5e8085 | ||
|
|
833d181700 | ||
|
|
dfc716d91a | ||
|
|
8dd6a27418 | ||
|
|
691ae8752e | ||
|
|
14b4fd3465 | ||
|
|
fc6a1402c3 | ||
|
|
275f96d80c | ||
|
|
850d706df2 | ||
|
|
b06c8e72e1 | ||
|
|
b1fd9ffffb | ||
|
|
e2c264cec4 | ||
|
|
3f889137d7 | ||
|
|
19f1e6b4ee | ||
|
|
7e692ebca6 | ||
|
|
0067a57f8f | ||
|
|
e028162dc2 | ||
|
|
9b26439dd3 | ||
|
|
1431270287 | ||
|
|
06e74fa976 | ||
|
|
318fde51d7 | ||
|
|
15daaf2633 | ||
|
|
d253302fc9 | ||
|
|
560eb31e4f | ||
|
|
493df37287 | ||
|
|
32298b89fd | ||
|
|
d6ee515873 | ||
|
|
bc09f0672b | ||
|
|
17d36156cb | ||
|
|
99450fa643 | ||
|
|
71ac62e395 |
No files matched your search
@@ -6,7 +6,7 @@ on:
|
||||
- 'nightly_*'
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.9
|
||||
QT_VERSION: 5.12.12
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
@@ -15,41 +15,17 @@ 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-1ff82e8
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ${{ github.workspace }}/../Qt
|
||||
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
|
||||
# - name: Install Qt
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# seriously, what the fuck why do i have to do this
|
||||
- name: Add curl to the container
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt -y install curl jq
|
||||
- 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 }}
|
||||
COMPILER: gcc-5
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -69,7 +45,7 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
@@ -85,12 +61,12 @@ jobs:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v1
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
@@ -188,7 +164,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -208,12 +184,12 @@ jobs:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v1
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -239,7 +215,7 @@ jobs:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64]
|
||||
arch: [x86_64, arm64]
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
@@ -281,6 +257,7 @@ jobs:
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -289,21 +266,39 @@ jobs:
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Sign builds
|
||||
working-directory: ./build/bin
|
||||
run: |
|
||||
# make sure OpenAL framework is signed
|
||||
find . -name OpenAL -type f | while read xx; do codesign --force -s - $xx; done
|
||||
find . -name OpenAL.framework -type d | while read xx; do codesign --force -s - $xx; done
|
||||
# make sure dylibs are signed
|
||||
find . -name \*.dylib -type f | while read xx; do codesign --force -s - $xx; done
|
||||
# sign binaries
|
||||
find . -perm +111 -type f | grep MacOS | while read xx; do codesign --force -s - $xx; done
|
||||
# sign apps
|
||||
find . -name \*.app -maxdepth 1 | while read xx; do codesign --force -s - $xx; done
|
||||
- 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 }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build.tar
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
@@ -312,17 +307,24 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release-${{ matrix.arch }}.tgz
|
||||
tar -xvzf macos-build-FastDebug-${{ matrix.arch }}.tgz
|
||||
- name: Create Distribution package
|
||||
working-directory: ./builds
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
- name: Upload result package
|
||||
working-directory: ./builds
|
||||
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
- 'release_*'
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.9
|
||||
QT_VERSION: 5.12.12
|
||||
|
||||
jobs:
|
||||
create_release:
|
||||
@@ -44,68 +44,19 @@ 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-1ff82e8
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
# uses: actions/cache@v1
|
||||
# cache the Qt directory so we don't have to reinstall it every time
|
||||
# cache.inputs:
|
||||
# path - A list of files, directories, and wildcard patterns to cache and restore. See @actions/glob for supported patterns.
|
||||
# key - An explicit key for restoring and saving the cache
|
||||
# restore-keys - An ordered list of keys to use for restoring the cache if no cache hit occurred for key
|
||||
# cache.outputs:
|
||||
# cache-hit true when an exact match was found for the key, false otherwise.
|
||||
# with:
|
||||
# path: ${{ github.workspace }}/../Qt
|
||||
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
|
||||
# - name: Install Qt
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# installs Qt in the action workflow
|
||||
# install-qt-action.inputs:
|
||||
# version desired qt version to install
|
||||
# host Host platform of Qt, default to platform used by runs-on
|
||||
# target target platform of Qt, default to desktop
|
||||
# arch target architecture of Qt, only used for windows or android builds
|
||||
# dir root dir Qt will be installed to
|
||||
# install-deps if true, auto-install dependencies on linux. Default true
|
||||
# modules whitespace delimited list string of additional addon modules to install
|
||||
# archives whitespace delimited list string of Qt archives to install
|
||||
# cached if true, Don't download Qt but set ENVARs; use with cache.outputs.cache-hit
|
||||
# setup-python Set to false to skip using setup-python to find/download a valid python version
|
||||
# set-env if true, set ENVARs; default = false
|
||||
# aqtversion version of aqtinstall to use; default = 2.0.0
|
||||
# py7zrversion version of py7zr to use; default = 0.16.1
|
||||
# extra additional arguments to pass to aqinstall
|
||||
# ENVARS set:
|
||||
# Qt5_DIR / Qt6_DIR
|
||||
# Qt bin dir appended to PATH
|
||||
# QT_PLUGIN_PATH, QML2_IMPORT_PATH, PKG_CONFIG_PATH, LD_LIBRARY_PATH
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
- name: Add curl to the container
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt -y install curl jq
|
||||
- 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
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: gcc-5
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -125,7 +76,7 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
# Upload the url file for use with other runners
|
||||
# upload-artifact.inputs:
|
||||
# if-no-files-found=warn What to do if path fails to find any files.
|
||||
@@ -149,15 +100,16 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
# Grab the release builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
# Grab the debug builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
@@ -168,7 +120,7 @@ jobs:
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
|
||||
- name: Upload result package
|
||||
# Stash the result to artifact filespace
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
@@ -195,6 +147,7 @@ jobs:
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
ref: '${{ github.ref }}'
|
||||
# - name: Cache Qt
|
||||
# # Cache Qt
|
||||
# id: cache-qt-win
|
||||
@@ -267,7 +220,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -289,15 +242,15 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -312,13 +265,13 @@ jobs:
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
|
||||
|
||||
- name: Upload result package
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
|
||||
- name: Upload debug package
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.debug_name }}
|
||||
path: ${{ steps.generate_package.outputs.debug_path }}
|
||||
@@ -337,7 +290,7 @@ jobs:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64]
|
||||
arch: [x86_64, arm64]
|
||||
name: Mac
|
||||
needs: create_release
|
||||
runs-on: macos-latest
|
||||
@@ -361,6 +314,7 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
@@ -373,6 +327,7 @@ jobs:
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -381,21 +336,39 @@ jobs:
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Sign builds
|
||||
working-directory: ./build/bin
|
||||
run: |
|
||||
# make sure OpenAL framework is signed
|
||||
find . -name OpenAL -type f | while read xx; do codesign --force -s - $xx; done
|
||||
find . -name OpenAL.framework -type d | while read xx; do codesign --force -s - $xx; done
|
||||
# make sure dylibs are signed
|
||||
find . -name \*.dylib -type f | while read xx; do codesign --force -s - $xx; done
|
||||
# sign binaries
|
||||
find . -perm +111 -type f | grep MacOS | while read xx; do codesign --force -s - $xx; done
|
||||
# sign apps
|
||||
find . -name \*.app -maxdepth 1 | while read xx; do codesign --force -s - $xx; done
|
||||
- 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 }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build.tar
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
@@ -404,21 +377,28 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release-${{ matrix.arch }}.tgz
|
||||
tar -xvzf macos-build-FastDebug-${{ matrix.arch }}.tgz
|
||||
- name: Create Distribution package
|
||||
id: generate_package
|
||||
working-directory: ./builds
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
- name: Upload result package
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
name: Publish Standalone docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'nightly_*'
|
||||
- 'release_*'
|
||||
|
||||
jobs:
|
||||
build_images:
|
||||
if: github.repository == 'scp-fs2open/fs2open.github.com'
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
include:
|
||||
- configuration: FastDebug
|
||||
tag_suffix: -debug
|
||||
- configuration: Release
|
||||
tag_suffix: ""
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Add curl to the container
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt -y install curl jq
|
||||
- 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: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Docker meta
|
||||
id: docker_meta
|
||||
uses: crazy-max/ghaction-docker-meta@v1
|
||||
with:
|
||||
images: ghcr.io/scp-fs2open/standalone_server
|
||||
tag-latest: false
|
||||
|
||||
- name: Login to GitHub Docker Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.CR_PAT }}
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/standalone/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.docker_meta.outputs.tags }}${{ matrix.tag_suffix }}
|
||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||
build-args: |
|
||||
build_type=${{ matrix.configuration }}
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
- 'test/*'
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.9
|
||||
QT_VERSION: 5.12.12
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
@@ -15,26 +15,8 @@ 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-1ff82e8
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ${{ github.workspace }}/../Qt
|
||||
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
|
||||
# - name: Install Qt
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
- name: Add curl to the container
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt -y install curl jq
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -45,16 +27,11 @@ 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 }}
|
||||
COMPILER: gcc-5
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -74,7 +51,7 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linux-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/install/*.AppImage
|
||||
@@ -91,12 +68,12 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v1
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: linux-FastDebug
|
||||
path: builds
|
||||
@@ -200,7 +177,7 @@ jobs:
|
||||
shell: bash
|
||||
run: ./bin/$CONFIGURATION/unittests --gtest_shuffle
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: ${{ github.workspace }}/build/install/*
|
||||
@@ -221,12 +198,12 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v1
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
|
||||
path: builds
|
||||
@@ -252,7 +229,7 @@ jobs:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64]
|
||||
arch: [x86_64, arm64]
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
@@ -293,6 +270,7 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -301,21 +279,39 @@ jobs:
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Sign builds
|
||||
working-directory: ./build/bin
|
||||
run: |
|
||||
# make sure OpenAL framework is signed
|
||||
find . -name OpenAL -type f | while read xx; do codesign --force -s - $xx; done
|
||||
find . -name OpenAL.framework -type d | while read xx; do codesign --force -s - $xx; done
|
||||
# make sure dylibs are signed
|
||||
find . -name \*.dylib -type f | while read xx; do codesign --force -s - $xx; done
|
||||
# sign binaries
|
||||
find . -perm +111 -type f | grep MacOS | while read xx; do codesign --force -s - $xx; done
|
||||
# sign apps
|
||||
find . -name \*.app -maxdepth 1 | while read xx; do codesign --force -s - $xx; done
|
||||
- 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 }}-${{ matrix.arch }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build.tar
|
||||
name: mac-${{ matrix.configuration }}-${{ matrix.arch }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}-${{ matrix.arch }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
@@ -324,17 +320,24 @@ jobs:
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-Release
|
||||
name: mac-Release-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mac-FastDebug
|
||||
name: mac-FastDebug-${{ matrix.arch }}
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release-${{ matrix.arch }}.tgz
|
||||
tar -xvzf macos-build-FastDebug-${{ matrix.arch }}.tgz
|
||||
- name: Create Distribution package
|
||||
working-directory: ./builds
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
- name: Upload result package
|
||||
working-directory: ./builds
|
||||
|
||||
@@ -6,42 +6,27 @@ on:
|
||||
- master
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.9
|
||||
QT_VERSION: 5.12.12
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [gcc-5, gcc-10]
|
||||
compiler: [gcc-9, gcc-13, clang-16]
|
||||
cmake_options: [""]
|
||||
include:
|
||||
# Also include configurations that check if the code compiles without the graphics backends
|
||||
- configuration: Debug
|
||||
compiler: gcc-10
|
||||
compiler: gcc-13
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
- configuration: Release
|
||||
compiler: gcc-10
|
||||
compiler: gcc-13
|
||||
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-1ff82e8
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ${{ github.workspace }}/../Qt
|
||||
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
|
||||
# - name: Install Qt
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -50,13 +35,22 @@ jobs:
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
|
||||
- name: Configure ccache
|
||||
run: |
|
||||
ccache --set-config=sloppiness=pch_defines,time_macros
|
||||
ccache -p
|
||||
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
CCACHE_PATH: /usr/local/bin/ccache
|
||||
ENABLE_QTFRED: ON
|
||||
Qt5_DIR: /qt/${{ env.QT_VERSION }}/gcc_64/lib/cmake/Qt5
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
|
||||
- name: Show CCache statistics
|
||||
run: ccache --show-stats
|
||||
@@ -3,45 +3,27 @@ name: Check a pull request
|
||||
on: [pull_request]
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.9
|
||||
QT_VERSION: 5.12.12
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [gcc-5, gcc-10, clang-9]
|
||||
compiler: [gcc-9, gcc-13, clang-16]
|
||||
cmake_options: [""]
|
||||
include:
|
||||
# Also include configurations that check if the code compiles without the graphics backends
|
||||
- configuration: Debug
|
||||
compiler: gcc-10
|
||||
compiler: gcc-13
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
- configuration: Release
|
||||
compiler: gcc-10
|
||||
compiler: gcc-13
|
||||
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-1ff82e8
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ${{ github.workspace }}/../Qt
|
||||
# key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
|
||||
# - name: Install Qt
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
- name: Add curl to the container
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt -y install curl jq
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -51,17 +33,18 @@ 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
|
||||
save: false # Caches are created by a separate job and only restored for PRs
|
||||
verbose: 1
|
||||
- name: Configure ccache
|
||||
run: ccache --set-config=sloppiness=pch_defines,time_macros
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
CCACHE_PATH: /usr/local/bin/ccache
|
||||
ENABLE_QTFRED: ON
|
||||
Qt5_DIR: /qt/${{ env.QT_VERSION }}/gcc_64/lib/cmake/Qt5
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -72,6 +55,8 @@ jobs:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Show CCache statistics
|
||||
run: ccache --show-stats
|
||||
- name: Run Clang Tidy
|
||||
# Clang-tidy reuses the precompiled headers so this only makes sense for the clang compilers
|
||||
if: startsWith(matrix.compiler, 'clang-')
|
||||
@@ -186,7 +171,7 @@ jobs:
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64]
|
||||
arch: [x86_64, arm64]
|
||||
cmake_options: [""]
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
@@ -214,7 +199,8 @@ jobs:
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
|
||||
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}-${{ matrix.arch }}
|
||||
save: false # Caches are created by a separate job and only restored for PRs
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
@@ -227,6 +213,7 @@ jobs:
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -235,6 +222,7 @@ jobs:
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Run Clang Tidy
|
||||
@@ -245,4 +233,4 @@ jobs:
|
||||
if: startsWith(matrix.compiler, 'clang-')
|
||||
uses: asarium/clang-tidy-action@v1
|
||||
with:
|
||||
fixesFile: clang-fixes.yaml
|
||||
fixesFile: clang-fixes.yaml
|
||||
@@ -0,0 +1,69 @@
|
||||
name: Weekly Coverity Scan for Freespace Open
|
||||
# adapted from code by "albert-github" on the doxygen repository
|
||||
# many thanks for figuring this out first so it could be less painful for us!
|
||||
|
||||
# keep this from running on everyone's fork
|
||||
# if: github.ref == 'refs/heads/master'
|
||||
|
||||
#This mode is for testing
|
||||
#on: [push, pull_request]
|
||||
|
||||
# In production, push on a specific schedule
|
||||
on:
|
||||
schedule:
|
||||
- cron: "57 18 * * *" # Run once per a week on Friday morning (4 AM EST), to avoid Coverity's submission limits
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.12
|
||||
coverity_email: [email protected]
|
||||
coverity_token: ${{ secrets.COVERITY_TOKEN }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build FSO With Coverity Wrapper
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
|
||||
# pipe results of wget to a log file because it's very verbose and rarely fails
|
||||
- name: Install Coverity
|
||||
run: |
|
||||
wget -o wgetlog.txt -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=${{ env.coverity_token }}&project=scp-fs2open/fs2open.github.com" -O coverity_tool.tgz
|
||||
mkdir cov-scan
|
||||
tar ax -f coverity_tool.tgz --strip-components=1 -C cov-scan
|
||||
|
||||
- name: Setup Environment
|
||||
run: |
|
||||
echo "$(pwd)/cov-scan/bin" >> $GITHUB_PATH
|
||||
echo "NPROC=$(getconf _NPROCESSORS_ONLN)" >> $GITHUB_ENV
|
||||
|
||||
- name: Configure CMake for FSO
|
||||
env:
|
||||
CONFIGURATION: FastDebug
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
|
||||
- name: Build FSO with Coverity Wrapper
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
run: cov-build --dir cov-int ninja -k 20 all
|
||||
|
||||
- name: Compress Results
|
||||
working-directory: ./build
|
||||
run: tar zcf cov-scan.tgz cov-int
|
||||
|
||||
#Comment this out when testing to keep from running into upload limits
|
||||
- name: Upload to Coverity
|
||||
run: |
|
||||
cd build
|
||||
curl --form token=${{ env.coverity_token }} --form email=${{ env.coverity_email }} --form [email protected] --form version="$(git rev-parse HEAD)" --form description="Automatic GHA scan" 'https://scan.coverity.com/builds?project=scp-fs2open/fs2open.github.com'
|
||||
@@ -250,6 +250,7 @@ documentation/doxygen/*
|
||||
projects/*
|
||||
/.vs
|
||||
CMakeSettings.json
|
||||
CMakePresets.json
|
||||
|
||||
# Weird files created by Linux
|
||||
.fuse_hidden*
|
||||
|
||||
-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
-14
@@ -47,20 +47,6 @@ endif()
|
||||
|
||||
PROJECT(FS2_Open LANGUAGES ${FSO_LANGUAGES})
|
||||
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
# Currently only GCC support ccache properly without generating additional warnings
|
||||
# Enable ccache on Mac even for clang
|
||||
if(CCACHE_PROGRAM AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR APPLE))
|
||||
if(NOT CMAKE_C_COMPILER_LAUNCHER)
|
||||
message(STATUS "Using ccache for C compilation: ${CCACHE_PROGRAM}")
|
||||
SET(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
|
||||
endif()
|
||||
if(NOT CMAKE_CXX_COMPILER_LAUNCHER)
|
||||
message(STATUS "Using ccache for C++ compilation: ${CCACHE_PROGRAM}")
|
||||
SET(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
IF(CMAKE_CROSSCOMPILING)
|
||||
SET(IMPORT_EXE_DIR "IMPORT_EXE_DIR-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to binary directory of a cmake build for the real OS")
|
||||
INCLUDE(${IMPORT_EXE_DIR}/ImportExecutables.cmake)
|
||||
@@ -141,6 +127,8 @@ OPTION(FSO_BUILD_WITH_OPENGL_DEBUG "Enables debug option for OpenGL" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_OPENXR_DEBUG "Enables debug option for OpenXR" OFF)
|
||||
|
||||
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
|
||||
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
|
||||
MARK_AS_ADVANCED(FORCE FSO_USE_OPENALSOFT)
|
||||
@@ -154,6 +142,7 @@ 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)
|
||||
mark_as_advanced(FORCE FSO_BUILD_WITH_OPENXR_DEBUG)
|
||||
|
||||
# Include cotire file from https://github.com/sakra/cotire/
|
||||
include(cotire)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
+23
-13
@@ -1,17 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ "$COMPILER" = "gcc-5" ]; then
|
||||
export CC=gcc-5
|
||||
export CXX=g++-5
|
||||
if [ "$COMPILER" = "gcc-9" ]; then
|
||||
export CC=gcc-9
|
||||
export CXX=g++-9
|
||||
fi
|
||||
if [ "$COMPILER" = "gcc-10" ]; then
|
||||
export CC=gcc-10
|
||||
export CXX=g++-10
|
||||
if [ "$COMPILER" = "gcc-13" ]; then
|
||||
export CC=gcc-13
|
||||
export CXX=g++-13
|
||||
fi
|
||||
if [ "$COMPILER" = "clang-9" ]; then
|
||||
# Work around bug in clang that uses the wrong installation directory: https://bugs.llvm.org/show_bug.cgi?id=47460
|
||||
export CC=$(readlink -f $(which clang-9))
|
||||
export CXX=$(readlink -f $(which clang++-9))
|
||||
if [ "$COMPILER" = "clang-16" ]; then
|
||||
export CC=clang-16
|
||||
export CXX=clang++-16
|
||||
fi
|
||||
|
||||
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH
|
||||
@@ -22,7 +21,7 @@ if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
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
|
||||
@@ -30,6 +29,13 @@ 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
|
||||
|
||||
if [ ! "$CCACHE_PATH" = "" ]; then
|
||||
echo "Using ccache at $CCACHE_PATH"
|
||||
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_C_COMPILER_LAUNCHER=$CCACHE_PATH -DCMAKE_CXX_COMPILER_LAUNCHER=$CCACHE_PATH"
|
||||
fi
|
||||
|
||||
mkdir build
|
||||
@@ -42,7 +48,11 @@ export LD_LIBRARY_PATH
|
||||
if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
brew install ninja
|
||||
fi
|
||||
|
||||
# CMAKE_JOB_POOLS and CMAKE_JOB_POOL_LINK ensure that when using ninja, link operations are done sequentially
|
||||
# we have some build rules that do not play nice with parallel invocation and that fixes these issues
|
||||
|
||||
cmake -G Ninja -DFSO_FATAL_WARNINGS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON $CMAKE_OPTIONS $PLATFORM_CMAKE_OPTIONS \
|
||||
-DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DCMAKE_BUILD_TYPE=$CONFIGURATION \
|
||||
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=OFF \
|
||||
-DSHADERS_ENABLE_COMPILATION=ON ..
|
||||
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=${ENABLE_QTFRED:-OFF} \
|
||||
-DSHADERS_ENABLE_COMPILATION=ON -DCMAKE_JOB_POOLS=link=1 -DCMAKE_JOB_POOL_LINK=link ..
|
||||
@@ -26,11 +26,11 @@ elif [ "$OS" = "Windows" ]; then
|
||||
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-$ARCH.tar.gz" *.app
|
||||
|
||||
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
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-Mac-$ARCH.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-Mac-$ARCH.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Mac-$ARCH.tar.gz")" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Invalid OS: $OS"
|
||||
fi
|
||||
@@ -5,6 +5,13 @@ HERE=$(dirname "$SCRIPT")
|
||||
|
||||
export LD_LIBRARY_PATH=$(pwd)/bin/lib:$LD_LIBRARY_PATH
|
||||
|
||||
# if on mac and building for architecture that doesn't match host
|
||||
# then unittests will fail so we just need to skip it (for now)
|
||||
if [ "$RUNNER_OS" = "macOS" ] && [ "$ARCH" != "$(uname -m)" ]; then
|
||||
echo "Skipping tests due to architecture mismatch!"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$CONFIGURATION" = "Debug"] && [[ "$RUNNER_OS" != "macOS" ]] ; then
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$HERE/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
|
||||
@@ -15,7 +15,7 @@ if [ "$UPLOAD_TYPE" = "nightly" ]; then
|
||||
any_success=true
|
||||
fi
|
||||
|
||||
if SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly"; then
|
||||
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
|
||||
|
||||
@@ -24,7 +24,7 @@ if [ "$UPLOAD_TYPE" = "nightly" ]; then
|
||||
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
|
||||
|
||||
+7
-3
@@ -19,7 +19,7 @@
|
||||
# HLP_API:
|
||||
# HLP_KEY:
|
||||
|
||||
# LINUX_RESULT: bool, if the linux builds were sucessfully uploaded
|
||||
# LINUX_RESULT: bool, if the linux builds were successfully uploaded
|
||||
# WINDOWS_RESULT: bool, if the windows builds were successfully uploaded
|
||||
|
||||
import sys
|
||||
@@ -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))
|
||||
|
||||
+9
-5
@@ -8,7 +8,8 @@ from file_list import ReleaseFile
|
||||
from util import retry_multi, GLOBAL_TIMEOUT
|
||||
|
||||
LINUX_KEY = "Linux"
|
||||
MACOSX_KEY = "Mac"
|
||||
MACOSX_X64_KEY = "Mac-x86_64"
|
||||
MACOSX_ARM64_KEY = "Mac-arm64"
|
||||
WIN32_SSE2_KEY = "Win32-SSE2"
|
||||
WIN64_SSE2_KEY = "Win64-SSE2"
|
||||
WIN32_AVX_KEY = "Win32-AVX"
|
||||
@@ -34,7 +35,8 @@ metadata = {
|
||||
|
||||
platforms = {
|
||||
LINUX_KEY: 'linux',
|
||||
MACOSX_KEY: 'macosx',
|
||||
MACOSX_X64_KEY: 'macosx',
|
||||
MACOSX_ARM64_KEY: 'macosx',
|
||||
WIN32_SSE2_KEY: 'windows',
|
||||
WIN64_SSE2_KEY: 'windows',
|
||||
WIN32_AVX_KEY: 'windows',
|
||||
@@ -43,7 +45,8 @@ platforms = {
|
||||
|
||||
envs = {
|
||||
LINUX_KEY: 'linux && x86_64', # Linux only has 64bit builds
|
||||
MACOSX_KEY: 'macosx',
|
||||
MACOSX_X64_KEY: 'macosx && x86_64',
|
||||
MACOSX_ARM64_KEY: 'macosx && arm64',
|
||||
WIN32_SSE2_KEY: 'windows',
|
||||
WIN64_SSE2_KEY: 'windows && x86_64',
|
||||
WIN32_AVX_KEY: 'windows && avx',
|
||||
@@ -135,7 +138,7 @@ def render_nebula_release(version, stability, files, config):
|
||||
'label': label,
|
||||
'properties': props,
|
||||
})
|
||||
elif group == MACOSX_KEY and fn.startswith(os.path.basename(fn) + '.app/'):
|
||||
elif group.startswith('Mac') and fn.startswith(os.path.basename(fn) + '.app/'):
|
||||
if 'qtfred' in fn:
|
||||
if '-FASTDBG' in fn:
|
||||
label = 'QtFRED Debug'
|
||||
@@ -148,7 +151,8 @@ def render_nebula_release(version, stability, files, config):
|
||||
label = None
|
||||
|
||||
props = {
|
||||
"x64": True, # All Mac builds are 64-bit
|
||||
"arm64": "arm64" in fn,
|
||||
"x64": "x64" in fn,
|
||||
"sse2": True, # There are no forced options on mac but 64-bit always implies SSE2 so we set that here
|
||||
"avx": False,
|
||||
"avx2": False,
|
||||
|
||||
+19
-11
@@ -7,22 +7,22 @@ PLACEHOLDER
|
||||
[b]Deprecations:[/b]
|
||||
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.
|
||||
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. Any features listed under Deprecations 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=98682.0]23.0.0 Release Thread[/url][/size]
|
||||
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=99015.0]23.2.1 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.
|
||||
[b]All platforms: [/b] For every day use, we recommend [url=https://knossosnet.github.io/Knossos-Release-Page/]Knossos.NET[/url], an integrated solution for downloading and launching mods.
|
||||
|
||||
[hidden=Alternative Launchers]
|
||||
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)
|
||||
Cross-platform: [url=https://www.hard-light.net/forums/index.php?topic=89162]wxLauncher 0.12.x Test Build[/url] (legacy project for a unified launcher)
|
||||
[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)}
|
||||
@@ -41,10 +41,10 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
|
||||
|
||||
[b]What are those SSE, SSE2 and AVX builds I keep seeing everywhere?[/b]
|
||||
[url=https://www.hard-light.net/forums/index.php?topic=65628.0]Your answer is in this topic.[/url]
|
||||
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!
|
||||
Don't want to deal with that? Use [url=https://knossosnet.github.io/Knossos-Release-Page/]Knossos.NET[/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,22 @@ 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+[/size]
|
||||
[b]Intel (64-bit):[/b] ${build(groups["Mac"].subFiles["x86_64"])}
|
||||
[b]Apple Silicon:[/b] ${build(groups["Mac"].subFiles["arm64"])}
|
||||
|
||||
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,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
|
||||
@@ -7,3 +7,9 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
else()
|
||||
set(IS_64BIT FALSE)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
else()
|
||||
set(IS_ARM64 FALSE)
|
||||
endif()
|
||||
@@ -22,6 +22,14 @@ SET(LIBRAY_DESTINATION "../Frameworks")
|
||||
|
||||
set(PLATFORM_MAC TRUE CACHE INTERNAL "" FORCE)
|
||||
|
||||
# Maybe override arm64 setting if we are compiling for different architecture
|
||||
# If not specified, or if it's a universal build, then this should do nothing
|
||||
if(CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
|
||||
set(IS_ARM64 TRUE)
|
||||
elseif(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
|
||||
set(IS_ARM64 FALSE)
|
||||
endif()
|
||||
|
||||
# Generate and don't strip debug symbols
|
||||
# These settings don't seem to generate debug symbols for code and Freespace2
|
||||
# so those settings are set manually in code and Freespace2's CMakeLists.txt files
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#cmakedefine SCP_HAVE_STD_MAX_ALIGN_T
|
||||
|
||||
#cmakedefine01 IS_64BIT
|
||||
#cmakedefine01 IS_ARM64
|
||||
|
||||
#cmakedefine01 SCP_HAVE_STRCASECMP
|
||||
#cmakedefine01 SCP_HAVE_STRNCASECMP
|
||||
|
||||
@@ -83,20 +83,41 @@ if(SUPPORTS_SHIFT_NEGATIVE_VALUE)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-shift-negative-value")
|
||||
endif()
|
||||
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
|
||||
# Check if there is a user-set optimisation flag
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" CXX_OPT_FLAG ${CXX_BASE_FLAGS})
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-Og -g -Wshadow")
|
||||
# If no user-set opt flag, set -O2 and -Og
|
||||
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O2")
|
||||
set(CXX_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
||||
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
||||
endif()
|
||||
if ("${C_OPT_FLAG}" STREQUAL "")
|
||||
set(C_OPT_FLAG_RELEASE "-O2")
|
||||
set(C_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
||||
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
|
||||
endif()
|
||||
|
||||
# Always use the base flags and add our compiler flags at the bacl
|
||||
set(CXX_FLAGS_RELEASE "${CXX_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-parameter")
|
||||
set(C_FLAGS_RELEASE "${C_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-parameter")
|
||||
|
||||
set(CXX_FLAGS_DEBUG "${CXX_OPT_FLAG_DEBUG} -g -Wshadow")
|
||||
set(C_FLAGS_DEBUG "${C_OPT_FLAG_DEBUG} -g -Wshadow")
|
||||
|
||||
# Always use the base flags and add our compiler flags at the back
|
||||
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
set(CMAKE_C_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
|
||||
set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${CXX_FLAGS_RELEASE})
|
||||
set(CMAKE_C_FLAGS_RELEASE ${C_FLAGS_RELEASE})
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG ${CXX_FLAGS_DEBUG})
|
||||
set(CMAKE_C_FLAGS_DEBUG ${C_FLAGS_DEBUG})
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "")
|
||||
|
||||
|
||||
@@ -113,19 +113,41 @@ if(SUPPORTS_STRINGOP_TRUNCATION)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-overflow")
|
||||
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")
|
||||
# Check if there is a user-set optimisation flag
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" CXX_OPT_FLAG ${CXX_BASE_FLAGS})
|
||||
string(REGEX MATCH "-O[a-zA-Z|0-9]+" C_OPT_FLAG ${C_BASE_FLAGS})
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-Og -g -Wshadow")
|
||||
# If no user-set opt flag, set -O2 and -Og
|
||||
if ("${CXX_OPT_FLAG}" STREQUAL "")
|
||||
set(CXX_OPT_FLAG_RELEASE "-O2")
|
||||
set(CXX_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(CXX_OPT_FLAG_RELEASE "${CXX_OPT_FLAG}")
|
||||
set(CXX_OPT_FLAG_DEBUG "${CXX_OPT_FLAG}")
|
||||
endif()
|
||||
if ("${C_OPT_FLAG}" STREQUAL "")
|
||||
set(C_OPT_FLAG_RELEASE "-O2")
|
||||
set(C_OPT_FLAG_DEBUG "-Og")
|
||||
else()
|
||||
set(C_OPT_FLAG_RELEASE "${C_OPT_FLAG}")
|
||||
set(C_OPT_FLAG_DEBUG "${C_OPT_FLAG}")
|
||||
endif()
|
||||
|
||||
set(CXX_FLAGS_RELEASE "${CXX_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
|
||||
set(C_FLAGS_RELEASE "${C_OPT_FLAG_RELEASE} -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
|
||||
|
||||
set(CXX_FLAGS_DEBUG "${CXX_OPT_FLAG_DEBUG} -g -Wshadow")
|
||||
set(C_FLAGS_DEBUG "${C_OPT_FLAG_DEBUG} -g -Wshadow")
|
||||
|
||||
# Always use the base flags and add our compiler flags at the back
|
||||
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
set(CMAKE_C_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${CXX_FLAGS_RELEASE})
|
||||
set(CMAKE_C_FLAGS_RELEASE ${C_FLAGS_RELEASE})
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
|
||||
set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
|
||||
set(CMAKE_CXX_FLAGS_DEBUG ${CXX_FLAGS_DEBUG})
|
||||
set(CMAKE_C_FLAGS_DEBUG ${C_FLAGS_DEBUG})
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${LINKER_FLAGS}")
|
||||
|
||||
|
||||
+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)
|
||||
|
||||
+4
-2
@@ -6,7 +6,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
include("${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
endif()
|
||||
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 23)
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 24)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 1)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 0)
|
||||
|
||||
@@ -35,7 +35,9 @@ ELSE()
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_VERSION_MAJOR}_${FSO_VERSION_MINOR}_${FSO_VERSION_BUILD}_${FSO_VERSION_REVISION_STR}")
|
||||
ENDIF()
|
||||
|
||||
IF(IS_64BIT)
|
||||
IF(IS_ARM64)
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_arm64")
|
||||
ELSEIF(IS_64BIT)
|
||||
# This is a 64-bit builds
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_x64")
|
||||
ENDIF()
|
||||
|
||||
@@ -25,6 +25,10 @@ if (FSO_BUILD_WITH_OPENGL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FSO_BUILD_WITH_OPENXR_DEBUG)
|
||||
add_definitions(-DFS_OPENXR_DEBUG)
|
||||
endif()
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC openal)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${LUA_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${PNG_LIBS})
|
||||
@@ -75,6 +79,17 @@ target_link_libraries(code PUBLIC hidapi::hidapi)
|
||||
|
||||
target_link_libraries(code PUBLIC imgui)
|
||||
|
||||
IF(NOT APPLE)
|
||||
target_link_libraries(code PUBLIC OpenXR::openxr_loader)
|
||||
target_include_directories(code PUBLIC OpenXR::Headers)
|
||||
ENDIF()
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
# On Linux, we need to access X11 window data.
|
||||
# On Windows, SDL already provides everything, so no need to do anything
|
||||
find_package(X11)
|
||||
target_link_libraries(code PUBLIC ${X11_LIBRARIES})
|
||||
ENDIF()
|
||||
|
||||
# Headers for standalone "gui" on UNIX
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${MONGOOSE_LIBS})
|
||||
|
||||
@@ -47,7 +47,7 @@ ProgramInstance::ProgramInstance(const actions::Program* program) : _program(pro
|
||||
|
||||
ProgramState ProgramInstance::step()
|
||||
{
|
||||
if (!_locals.host.IsValid()) {
|
||||
if (!_locals.host.isValid()) {
|
||||
return ProgramState::Done;
|
||||
}
|
||||
|
||||
|
||||
+14
-23
@@ -56,12 +56,6 @@ extern const int Num_ai_flag_names;
|
||||
#define AIDO_DOCK_NOW 2 // Immediately move into dock position. For ships that start mission docked.
|
||||
#define AIDO_UNDOCK 3 // Set goal of undocking with object.
|
||||
|
||||
// Submodes for seeking safety.
|
||||
#define AISS_1 41 // Pick a spot to fly to.
|
||||
#define AISS_2 42 // Flying to spot.
|
||||
#define AISS_3 43 // Gotten near spot, fly about there.
|
||||
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2
|
||||
|
||||
// Flags to ai_turn_towards_vector().
|
||||
#define AITTV_FAST (1<<0) // Turn fast, not slowed down based on skill level.
|
||||
#define AITTV_VIA_SEXP (1<<1) // Goober5000 - via sexp
|
||||
@@ -93,7 +87,7 @@ extern const int Num_ai_flag_names;
|
||||
#define AIM_BAY_DEPART 18 // Departing to a fighter bay, following path to do so
|
||||
#define AIM_SENTRYGUN 19 // AI mode for sentry guns only (floating turrets)
|
||||
#define AIM_WARP_OUT 20 // Commence warp out sequence. Point in legal direction. Then call John's code.
|
||||
#define AIM_FLY_TO_SHIP 21 // [Kazan] Fly to a ship, doesn't matter if it's hostile or friendly -- for Autopilot usage
|
||||
#define AIM_FLY_TO_SHIP 21 // Rendezvous with a ship. Like stay-near, but non-perpetual.
|
||||
#define AIM_LUA 22 // Generic Lua-based AI mode
|
||||
|
||||
#define MAX_AI_BEHAVIORS 23 // Number of AIM_xxxx types
|
||||
@@ -186,6 +180,12 @@ typedef struct ai_class {
|
||||
#define AIS_UNDOCK_3 33
|
||||
#define AIS_UNDOCK_4 34
|
||||
|
||||
// Submodes for seeking safety.
|
||||
#define AISS_1 41 // Pick a spot to fly to.
|
||||
#define AISS_2 42 // Flying to spot.
|
||||
#define AISS_3 43 // Gotten near spot, fly about there.
|
||||
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2. (Not implemented.)
|
||||
|
||||
// Submodes for Guard behavior
|
||||
#define AIS_GUARD_PATROL 101
|
||||
#define AIS_GUARD_ATTACK 102
|
||||
@@ -240,7 +240,6 @@ typedef struct ai_info {
|
||||
flagset<AI::AI_Flags> ai_flags; // Special flags for AI behavior.
|
||||
int shipnum; // Ship using this slot, -1 means none.
|
||||
|
||||
int behavior; // AI behavior; vestigial field from early development of FS1
|
||||
int mode;
|
||||
int previous_mode;
|
||||
int mode_time; // timestamp at which current mode elapses.
|
||||
@@ -278,7 +277,7 @@ typedef struct ai_info {
|
||||
|
||||
// Probably become obsolete, to be replaced by path_start, path_cur, etc.
|
||||
waypoint_list *wp_list; // waypoint list being followed
|
||||
size_t wp_index; // waypoint index in list
|
||||
int wp_index; // waypoint index in list
|
||||
int wp_flags; // waypoint flags, see WPF_xxxx
|
||||
int waypoint_speed_cap; // -1 no cap, otherwise cap - changed to int by Goober5000
|
||||
|
||||
@@ -308,6 +307,7 @@ typedef struct ai_info {
|
||||
fix submode_start_time; // time at which we entered the current submode
|
||||
int submode_parm0; // parameter specific to current submode
|
||||
int submode_parm1; // SUSHI: Another optional parameter
|
||||
float submode_float0; // Goober5000: a float parameter
|
||||
fix next_predict_pos_time; // Next time to predict position.
|
||||
|
||||
int next_dynamic_path_check_time; //ETP: Time of next path check in ai_new_maybe_reposition_attack_subsys
|
||||
@@ -373,11 +373,6 @@ typedef struct ai_info {
|
||||
float ai_turret_max_aim_update_delay;
|
||||
flagset<AI::Profile_Flags> ai_profile_flags; //Holds AI_Profiles flags (possibly overriden by AI class) that actually apply to AI
|
||||
|
||||
|
||||
union {
|
||||
float stay_near_distance; // Distance to stay within for AIM_STAY_NEAR mode.
|
||||
};
|
||||
|
||||
ship_subsys* targeted_subsys; // Targeted subobject on current target. NULL if none;
|
||||
ship_subsys* last_subsys_target; // last known subsystem target
|
||||
int targeted_subsys_parent; // Parent objnum of subobject, not necessarily targeted
|
||||
@@ -538,11 +533,11 @@ extern void ai_ignore_wing(object *ignorer, int wingnum);
|
||||
extern void ai_dock_with_object(object *docker, int docker_index, object *dockee, int dockee_index, int dock_type);
|
||||
extern void ai_stay_still(object *still_objp, vec3d *view_pos);
|
||||
extern void ai_do_default_behavior(object *obj);
|
||||
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags);
|
||||
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags, int start_index);
|
||||
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
|
||||
extern void ai_ship_destroy(int shipnum);
|
||||
extern vec3d ai_get_acc_limit(vec3d* vel_limit, const object* objp);
|
||||
extern void ai_turn_towards_vector(vec3d *dest, object *objp, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = nullptr, vec3d* turnrate_mod = nullptr);
|
||||
extern void ai_turn_towards_vector(const vec3d *dest, object *objp, const vec3d *slide_vec, const vec3d *rel_pos, float bank_override, int flags, const vec3d *rvec = nullptr, const vec3d* turnrate_mod = nullptr);
|
||||
extern void init_ai_object(int objnum);
|
||||
extern void ai_init(void); // Call this one to parse ai.tbl.
|
||||
extern void ai_level_init(void); // Call before each level to reset AI
|
||||
@@ -565,7 +560,7 @@ extern void ai_attack_wing(object *attacker, int wingnum);
|
||||
extern void ai_deathroll_start(object *ship_obj);
|
||||
extern int set_target_objnum(ai_info *aip, int objnum);
|
||||
extern void ai_form_on_wing(object *objp, object *goal_objp);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist, int additional_data);
|
||||
extern ship_subsys *set_targeted_subsys(ai_info *aip, ship_subsys *new_subsys, int parent_objnum);
|
||||
extern void ai_rearm_repair( object *objp, int docker_index, object *goal_objp, int dockee_index );
|
||||
extern void ai_add_rearm_goal( object *requester_objp, object *support_objp );
|
||||
@@ -602,8 +597,8 @@ extern void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, v
|
||||
extern int is_instructor(object *objp);
|
||||
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -1);
|
||||
|
||||
float ai_get_weapon_speed(ship_weapon *swp);
|
||||
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, vec3d *gun_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
|
||||
float ai_get_weapon_speed(const ship_weapon *swp);
|
||||
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, const vec3d *gun_pos, const object *pobjp, const vec3d *enemy_pos, const vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
|
||||
|
||||
// function to change rearm status for ai ships (called from sexpression code)
|
||||
extern void ai_set_rearm_status( int team, int new_status );
|
||||
@@ -625,10 +620,6 @@ int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float ra
|
||||
// moved to header file by Goober5000
|
||||
void ai_announce_ship_dying(object *dying_objp);
|
||||
|
||||
// added by kazan
|
||||
void ai_start_fly_to_ship(object *objp, int shipnum);
|
||||
void ai_fly_to_ship();
|
||||
|
||||
//Moved declaration here for player ship -WMC
|
||||
void ai_process_subobjects(int objnum);
|
||||
|
||||
|
||||
+5
-1
@@ -47,6 +47,7 @@ namespace AI {
|
||||
Depart_sound_played,// Goober5000 - replacement for AL's hack ;)
|
||||
Target_own_team, // this attack goal is allowed to target friendlies
|
||||
Afterburn_hard, // afterburn as hard as possible to the goal
|
||||
Waypoints_in_reverse, // decrement instead of increment
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
@@ -122,7 +123,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,
|
||||
@@ -156,6 +157,9 @@ namespace AI {
|
||||
Whackable_debris,
|
||||
Whackable_asteroids,
|
||||
Dynamic_goals_afterburn_hard,
|
||||
Player_orders_afterburn_hard,
|
||||
Hudsquadmsg_tactical_disarm_disable,
|
||||
Align_to_target_when_guarding_still,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
+16
-5
@@ -258,7 +258,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
if (optional_string("$Glide Attack Percent:")) {
|
||||
parse_float_list(profile->glide_attack_percent, NUM_SKILL_LEVELS);
|
||||
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
|
||||
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
|
||||
//While we're at it, verify the range
|
||||
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
|
||||
if (profile->glide_attack_percent[i] < 0.0f || profile->glide_attack_percent[i] > 100.0f) {
|
||||
@@ -271,7 +271,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
if (optional_string("$Circle Strafe Percent:")) {
|
||||
parse_float_list(profile->circle_strafe_percent, NUM_SKILL_LEVELS);
|
||||
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
|
||||
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
|
||||
//While we're at it, verify the range
|
||||
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
|
||||
if (profile->circle_strafe_percent[i] < 0.0f || profile->circle_strafe_percent[i] > 100.0f) {
|
||||
@@ -284,7 +284,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
if (optional_string("$Glide Strafe Percent:")) {
|
||||
parse_float_list(profile->glide_strafe_percent, NUM_SKILL_LEVELS);
|
||||
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
|
||||
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
|
||||
//While we're at it, verify the range
|
||||
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
|
||||
if (profile->glide_strafe_percent[i] < 0.0f || profile->glide_strafe_percent[i] > 100.0f) {
|
||||
@@ -297,7 +297,7 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
if (optional_string("$Random Sidethrust Percent:")) {
|
||||
parse_float_list(profile->random_sidethrust_percent, NUM_SKILL_LEVELS);
|
||||
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
|
||||
//Percent is nice for modders, but here in the code we want it between 0 and 1.0
|
||||
//While we're at it, verify the range
|
||||
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
|
||||
if (profile->random_sidethrust_percent[i] < 0.0f || profile->random_sidethrust_percent[i] > 100.0f) {
|
||||
@@ -552,7 +552,9 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
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, "$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);
|
||||
|
||||
@@ -623,6 +625,12 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$dynamic goals afterburn hard:", AI::Profile_Flags::Dynamic_goals_afterburn_hard);
|
||||
|
||||
set_flag(profile, "$player orders afterburn hard:", AI::Profile_Flags::Player_orders_afterburn_hard);
|
||||
|
||||
set_flag(profile, "$hud squad messages use tactical disarm/disable:", AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
|
||||
|
||||
set_flag(profile, "$align to target when guarding stationary ship:", AI::Profile_Flags::Align_to_target_when_guarding_still);
|
||||
|
||||
// if we've been through once already and are at the same place, force a move
|
||||
if (saved_Mp && (saved_Mp == Mp))
|
||||
{
|
||||
@@ -812,4 +820,7 @@ void ai_profile_t::reset()
|
||||
if (mod_supports_version(23, 2, 0)) {
|
||||
flags.set(AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
|
||||
}
|
||||
if (mod_supports_version(23, 4, 0)) {
|
||||
flags.set(AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
|
||||
}
|
||||
}
|
||||
+12
-13
@@ -76,7 +76,7 @@ extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d
|
||||
// If truly_random flag set (haha), then generate a pretty random number. Otherwise, generate a static rand which
|
||||
// tends to not change from frame to frame.
|
||||
// Try four times and choose nearest point to increase chance of getting a good point.
|
||||
void ai_bpap(object *objp, vec3d *attacker_objp_pos, vec3d *attacker_objp_fvec, vec3d *attack_point, vec3d *local_attack_point, float fov, float weapon_travel_dist, vec3d *surface_normal, ship_subsys *ss)
|
||||
void ai_bpap(const object *objp, const vec3d *attacker_objp_pos, const vec3d *attacker_objp_fvec, vec3d *attack_point, vec3d *local_attack_point, float fov, float weapon_travel_dist, vec3d *surface_normal, const ship_subsys *ss)
|
||||
{
|
||||
float nearest_dist;
|
||||
vec3d result_point, best_point;
|
||||
@@ -193,7 +193,7 @@ done_1:
|
||||
//
|
||||
// Note: Default value for fov is 1.0f 1.0f means don't use fov parameter.
|
||||
// If fov != 1.0f, try up to four times to find a point that's in the field of view.
|
||||
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float fov, float weapon_travel_dist)
|
||||
void ai_big_pick_attack_point_turret(const object *objp, ship_subsys *ssp, const vec3d *gpos, const vec3d *gvec, vec3d *attack_point, float fov, float weapon_travel_dist)
|
||||
{
|
||||
if (!timestamp_elapsed(ssp->turret_pick_big_attack_point_timestamp)) {
|
||||
vec3d result_point;
|
||||
@@ -213,7 +213,7 @@ void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos
|
||||
// Note: Default value for fov is 1.0f 1.0f means don't use fov parameter.
|
||||
// If fov != 1.0f, try up to four times to find a point that's in the field of view.
|
||||
// Note, attacker_objp can be a ship or a weapon.
|
||||
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov)
|
||||
void ai_big_pick_attack_point(const object *objp, const object *attacker_objp, vec3d *attack_point, float fov)
|
||||
{
|
||||
Assert(objp->instance > -1);
|
||||
Assert(objp->type == OBJ_SHIP);
|
||||
@@ -411,7 +411,7 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check)
|
||||
}
|
||||
}
|
||||
|
||||
if ( ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 1) ) {
|
||||
if ( ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, true) ) {
|
||||
subsys_in_sight = 1;
|
||||
}
|
||||
}
|
||||
@@ -535,18 +535,18 @@ 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);
|
||||
get_subsystem_pos(&gsubpos, target_objp, aip->targeted_subsys);
|
||||
|
||||
// you're in sight! shoot it!
|
||||
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 0))
|
||||
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, false))
|
||||
return false;
|
||||
|
||||
// not in sight, gotta get there
|
||||
vec3d* good_pos = nullptr;
|
||||
vec3d world_goal_pos;
|
||||
// For performance reasons we only recheck once a second, otherwise we reuse the last found target.
|
||||
if (timestamp_elapsed(aip->next_dynamic_path_check_time)) {
|
||||
vec3d tgt2pl = Pl_objp->pos - target_objp->pos;
|
||||
@@ -568,7 +568,6 @@ bool ai_new_maybe_reposition_attack_subsys() {
|
||||
vm_rot_point_around_line(&goal_pos, &tgt2pl, angle2goal, &vmd_zero_vector, &cross);
|
||||
|
||||
// then scale in (or out) towards our subsys
|
||||
vec3d world_goal_pos;
|
||||
float new_radius = ((subsys_dist - pl_dist) * (angle2goal / angle2subsys)) + pl_dist;
|
||||
vm_vec_copy_scale(&world_goal_pos, &goal_pos, new_radius / pl_dist);
|
||||
world_goal_pos += target_objp->pos;
|
||||
@@ -914,13 +913,13 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
}
|
||||
|
||||
if (tswp->num_secondary_banks > 0) {
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP))) {
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL))) {
|
||||
bool valid_secondary = ai_choose_secondary_weapon(Pl_objp, aip, En_objp);
|
||||
int current_bank = tswp->current_secondary_bank;
|
||||
if (current_bank > -1 && valid_secondary) {
|
||||
weapon_info *swip = &Weapon_info[tswp->secondary_bank_weapons[current_bank]];
|
||||
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
// If ship is protected and very low on hits, don't fire missiles.
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (En_objp->hull_strength > 10*swip->damage)) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Unload_secondaries]) {
|
||||
@@ -1035,7 +1034,7 @@ void ai_big_chase()
|
||||
ai_big_pick_attack_point(En_objp, Pl_objp, &enemy_pos, 0.8f);
|
||||
|
||||
weapon_info* wip = ai_get_weapon(&shipp->weapons);
|
||||
bool ballistic_aiming = !IS_VEC_NULL(&The_mission.gravity) && wip->gravity_const != 0.0f;
|
||||
bool ballistic_aiming = !IS_VEC_NULL(&The_mission.gravity) && wip && wip->gravity_const != 0.0f;
|
||||
bool valid_ballistic_trajectory = true;
|
||||
|
||||
if (!ballistic_aiming) {
|
||||
@@ -1842,7 +1841,7 @@ void ai_big_strafe()
|
||||
|
||||
/*
|
||||
if ( aip->goal_objnum != aip->target_objnum ) {
|
||||
Int3(); // what is going on here? - Get Alan
|
||||
UNREACHABLE("The goal objnum does not match the target objnum in ai_big_strafe(), please report to the SCP!"); // what is going on here? - Get Alan
|
||||
aip->mode = AIM_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
+2
-2
@@ -24,8 +24,8 @@ void ai_big_subsys_path_cleanup(ai_info *aip);
|
||||
void ai_big_strafe();
|
||||
int ai_big_maybe_enter_strafe_mode(const object *objp, int weapon_objnum);
|
||||
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp);
|
||||
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov=1.0f);
|
||||
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
|
||||
void ai_big_pick_attack_point(const object *objp, const object *attacker_objp, vec3d *attack_point, float fov=1.0f);
|
||||
void ai_big_pick_attack_point_turret(const object *objp, ship_subsys *ssp, const vec3d *gpos, const vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
|
||||
|
||||
// default distance for following subsystem path points --wookieejedi
|
||||
// the value is 5 because that was the original value specified in ai_big_maybe_follow_subsys_path()
|
||||
|
||||
+399
-290
File diff suppressed because it is too large.
Load diff
+205
-166
@@ -51,6 +51,8 @@ struct ship_registry_entry;
|
||||
// Goober5000 - okay, this seems really stupid. If any ship in the mission is assigned a goal
|
||||
// in PURGE_GOALS_ALL_SHIPS, *every* other ship will have certain goals purged. So I added
|
||||
// PURGE_GOALS_ONE_SHIP for goals which should only purge other goals in the one ship.
|
||||
// Goober5000 - note that the new disable and disarm goals (AI_GOAL_DISABLE_SHIP_TACTICAL and
|
||||
// AI_GOAL_DISARM_SHIP_TACTICAL) do not purge ANY goals, not even the ones in the one ship
|
||||
#define PURGE_GOALS_ALL_SHIPS (AI_GOAL_IGNORE | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)
|
||||
#define PURGE_GOALS_ONE_SHIP (AI_GOAL_IGNORE_NEW)
|
||||
|
||||
@@ -75,7 +77,9 @@ ai_goal_list Ai_goal_names[] =
|
||||
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
|
||||
{ "Guard ship", AI_GOAL_GUARD, 0 },
|
||||
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
|
||||
{ "Disable ship (tactical)",AI_GOAL_DISABLE_SHIP_TACTICAL, 0 },
|
||||
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
|
||||
{ "Disarm ship (tactical)", AI_GOAL_DISARM_SHIP_TACTICAL, 0 },
|
||||
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
|
||||
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
|
||||
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
|
||||
@@ -120,8 +124,10 @@ const char *Ai_goal_text(int goal, int submode)
|
||||
case AI_GOAL_GUARD_WING:
|
||||
return XSTR( "guard ", 480);
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
return XSTR( "disable ", 481);
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
return XSTR( "disarm ", 482);
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
return XSTR( "evade ", 483);
|
||||
@@ -208,7 +214,7 @@ void ai_maybe_add_form_goal(wing* wingp)
|
||||
int wingnum;
|
||||
if (Netgame.type_flags & NG_TYPE_TEAM) {
|
||||
const ship_registry_entry* ship_regp = ship_registry_get(Ships[wingp->ship_index[j]].ship_name);
|
||||
wingnum = TVT_wings[ship_regp->p_objp->team];
|
||||
wingnum = TVT_wings[ship_regp->p_objp()->team];
|
||||
ai_add_ship_goal_player(AIG_TYPE_PLAYER_SHIP, AI_GOAL_FORM_ON_WING, -1, Ships[Wings[wingnum].ship_index[Wings[wingnum].special_ship]].ship_name, aip);
|
||||
} else {
|
||||
wingnum = Starting_wings[0];
|
||||
@@ -481,10 +487,12 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
// these goals cannot be associated to wings, but can to a ship in a wing. So, we should find out
|
||||
// if the ship is in a wing so we can purge goals which might operate on that wing
|
||||
ship_index = ship_name_lookup(name);
|
||||
if ( ship_index == -1 ) {
|
||||
Int3(); // get allender -- this is sort of odd
|
||||
return;
|
||||
|
||||
Assertion(ship_index > -1, "Found a bad ship_index of %d in ai_goal_purge_invalid_goals, please report to the SCP!", ship_index); // get allender -- this is sort of odd
|
||||
if ( ship_index < 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wingnum = Ships[ship_index].wingnum;
|
||||
|
||||
purge_goal = goal_list;
|
||||
@@ -528,11 +536,12 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
// ignore goals should get rid of any kind of attack goal
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
|
||||
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
|
||||
purge_goal->flags.set(AI::Goal_Flags::Purge);
|
||||
break;
|
||||
|
||||
// disarm/disable goals should remove attacks from certain ships types
|
||||
// (but not tactical disarm/disable)
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS) ) {
|
||||
@@ -549,12 +558,17 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
}
|
||||
|
||||
// grab the ship type of the ship that is being disarmed/disabled
|
||||
ship_type_info *crippled_ships_type = &Ship_types[Ship_info[Ships[ship_index].ship_info_index].class_type];
|
||||
int crippled_ship_type = Ship_info[Ships[ship_index].ship_info_index].class_type;
|
||||
|
||||
// work through all the ship types which to see if the class matching our ai ship must ignore the ship
|
||||
if (ai_ship_type < 0 || crippled_ship_type < 0)
|
||||
break;
|
||||
|
||||
ship_type_info *crippled_ship_type_info = &Ship_types[crippled_ship_type];
|
||||
|
||||
// work through all the ship types to see if the class matching our ai ship must ignore the ship
|
||||
// being disarmed/disabled
|
||||
for ( j=0 ; j < (int)crippled_ships_type->ai_cripple_ignores.size(); j++) {
|
||||
if (crippled_ships_type->ai_cripple_ignores[j] == ai_ship_type) {
|
||||
for ( j=0 ; j < (int)crippled_ship_type_info->ai_cripple_ignores.size(); j++) {
|
||||
if (crippled_ship_type_info->ai_cripple_ignores[j] == ai_ship_type) {
|
||||
purge_goal->flags.set(AI::Goal_Flags::Purge);
|
||||
}
|
||||
}
|
||||
@@ -714,7 +728,7 @@ void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
|
||||
// from the mission goals (i.e. those goals which come from events) in that we don't
|
||||
// use sexpressions for goals from the player...so we enumerate all the parameters
|
||||
|
||||
void ai_add_goal_sub_player(int type, int mode, int submode, char *target_name, ai_goal *aigp, const ai_lua_parameters& lua_target )
|
||||
void ai_add_goal_sub_player(int type, int mode, int submode, const char *target_name, ai_goal *aigp, const ai_lua_parameters& lua_target )
|
||||
{
|
||||
Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
|
||||
|
||||
@@ -737,6 +751,9 @@ void ai_add_goal_sub_player(int type, int mode, int submode, char *target_name,
|
||||
if ( target_name != NULL )
|
||||
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
|
||||
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Player_orders_afterburn_hard])
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
|
||||
|
||||
// special case certain orders from player so that ships continue to do the right thing
|
||||
|
||||
@@ -801,7 +818,7 @@ int ai_goal_num(ai_goal *goals)
|
||||
}
|
||||
|
||||
|
||||
void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, char *target_name, ai_goal *aigp )
|
||||
void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, const char *target_name, ai_goal *aigp )
|
||||
{
|
||||
Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
|
||||
|
||||
@@ -818,7 +835,7 @@ void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, ch
|
||||
aigp->priority = priority;
|
||||
}
|
||||
|
||||
void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipname, ai_info *aip)
|
||||
void ai_add_ship_goal_scripting(int mode, int submode, int priority, const char *shipname, ai_info *aip)
|
||||
{
|
||||
int empty_index;
|
||||
ai_goal *aigp;
|
||||
@@ -842,7 +859,7 @@ void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipn
|
||||
// is issued to ship or wing (from player), mode is AI_GOAL_*. submode is the submode the
|
||||
// ship should go into. shipname is the object of the action. aip is the ai_info pointer
|
||||
// of the ship receiving the order
|
||||
void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip, const ai_lua_parameters& lua_target)
|
||||
void ai_add_ship_goal_player( int type, int mode, int submode, const char *shipname, ai_info *aip, const ai_lua_parameters& lua_target)
|
||||
{
|
||||
int empty_index;
|
||||
ai_goal *aigp;
|
||||
@@ -863,7 +880,7 @@ void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, a
|
||||
|
||||
// adds a goal from the player to the given wing (which in turn will add it to the proper
|
||||
// ships in the wing
|
||||
void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum, const ai_lua_parameters& lua_target)
|
||||
void ai_add_wing_goal_player( int type, int mode, int submode, const char *shipname, int wingnum, const ai_lua_parameters& lua_target)
|
||||
{
|
||||
int i, empty_index;
|
||||
wing *wingp = &Wings[wingnum];
|
||||
@@ -887,7 +904,7 @@ void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, i
|
||||
|
||||
|
||||
// common routine to add a sexpression mission goal to the appropriate goal structure.
|
||||
void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char *actor_name )
|
||||
void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, const char *actor_name )
|
||||
{
|
||||
int node, dummy, op;
|
||||
|
||||
@@ -901,22 +918,30 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
switch (op) {
|
||||
|
||||
case OP_AI_WAYPOINTS_ONCE:
|
||||
case OP_AI_WAYPOINTS: {
|
||||
case OP_AI_WAYPOINTS:
|
||||
{
|
||||
int ref_type;
|
||||
bool is_nan, is_nan_forever;
|
||||
|
||||
ref_type = Sexp_nodes[CDR(node)].subtype;
|
||||
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;
|
||||
Assertion(ref_type == SEXP_ATOM_STRING || ref_type == SEXP_ATOM_CONTAINER_DATA, "Found a bad ref_type in ai_add_goal_sub_sexp of %d. Please report to the SCP!", ref_type);
|
||||
|
||||
// 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;
|
||||
|
||||
} else
|
||||
Int3();
|
||||
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
aigp->ai_mode = AI_GOAL_WAYPOINTS;
|
||||
if ( op == OP_AI_WAYPOINTS_ONCE )
|
||||
aigp->ai_mode = AI_GOAL_WAYPOINTS_ONCE;
|
||||
if (CDDDDR(node) < 0)
|
||||
aigp->int_data = 0; // handle optional node separately because we don't subtract 1 here
|
||||
else
|
||||
aigp->int_data = eval_num(CDDDDR(node), is_nan, is_nan_forever) - 1;
|
||||
if (is_sexp_true(CDDDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Waypoints_in_reverse);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -931,14 +956,16 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
break;
|
||||
|
||||
case OP_AI_DISABLE_SHIP:
|
||||
aigp->ai_mode = AI_GOAL_DISABLE_SHIP;
|
||||
case OP_AI_DISABLE_SHIP_TACTICAL:
|
||||
aigp->ai_mode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->ai_submode = -SUBSYSTEM_ENGINE;
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
break;
|
||||
|
||||
case OP_AI_DISARM_SHIP:
|
||||
aigp->ai_mode = AI_GOAL_DISARM_SHIP;
|
||||
case OP_AI_DISARM_SHIP_TACTICAL:
|
||||
aigp->ai_mode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->ai_submode = -SUBSYSTEM_TURRET;
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
@@ -976,9 +1003,9 @@ 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->has_shipp())
|
||||
{
|
||||
auto target_aip = &Ai_info[ship_entry->shipp->ai_index];
|
||||
auto target_aip = &Ai_info[ship_entry->shipp()->ai_index];
|
||||
target_aip->ai_flags.set(AI::AI_Flags::Awaiting_repair);
|
||||
Assertion(aip != nullptr, "Must provide aip if assigning a rearm goal!");
|
||||
ai_goal_fixup_dockpoints( aip, aigp );
|
||||
@@ -1022,15 +1049,32 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
aigp->ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
|
||||
break;
|
||||
|
||||
case OP_AI_FLY_TO_SHIP:
|
||||
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)) );
|
||||
|
||||
// distance from ship
|
||||
if ( CDDDR(node) < 0 )
|
||||
aigp->float_data = 300.0f;
|
||||
else
|
||||
aigp->float_data = i2fl(atoi( CTEXT(CDDDR(node)) ));
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
aigp->float_data = i2fl(eval_num(CDDDR(node), is_nan, is_nan_forever));
|
||||
|
||||
// (the CDDDDR argument is whether to afterburn, and is handled at the end of the function, so don't handle it here)
|
||||
|
||||
// whether to "escort" the ship
|
||||
if ( CDDDDDR(node) >= 0 )
|
||||
aigp->int_data = is_sexp_true(CDDDDDR(node)) ? 1 : 0;
|
||||
|
||||
if (op == OP_AI_FLY_TO_SHIP)
|
||||
aigp->ai_mode = AI_GOAL_FLY_TO_SHIP;
|
||||
else
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_AI_FORM_ON_WING:
|
||||
aigp->priority = 99;
|
||||
@@ -1046,7 +1090,6 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
case OP_AI_EVADE_SHIP:
|
||||
case OP_AI_IGNORE:
|
||||
case OP_AI_IGNORE_NEW:
|
||||
case OP_AI_FLY_TO_SHIP:
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
|
||||
@@ -1073,14 +1116,10 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
aigp->ai_mode = AI_GOAL_CHASE_WING;
|
||||
} else if (op == OP_AI_CHASE_SHIP_CLASS) {
|
||||
aigp->ai_mode = AI_GOAL_CHASE_SHIP_CLASS;
|
||||
} else if ( op == OP_AI_STAY_NEAR_SHIP ) {
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
} else if ( op == OP_AI_IGNORE ) {
|
||||
aigp->ai_mode = AI_GOAL_IGNORE;
|
||||
} else if ( op == OP_AI_IGNORE_NEW ) {
|
||||
aigp->ai_mode = AI_GOAL_IGNORE_NEW;
|
||||
} else if ( op == OP_AI_FLY_TO_SHIP ) {
|
||||
aigp->ai_mode = AI_GOAL_FLY_TO_SHIP;
|
||||
} else
|
||||
UNREACHABLE("Coding error: unhandled AI goal in ai_add_goal_sub_sexp!");
|
||||
|
||||
@@ -1117,39 +1156,42 @@ 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 ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS
|
||||
|| op == OP_AI_DISABLE_SHIP || op == OP_AI_DISABLE_SHIP_TACTICAL || op == OP_AI_DISARM_SHIP || op == OP_AI_DISARM_SHIP_TACTICAL ) {
|
||||
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 ((CDDR(node) != -1) && is_sexp_true(CDDR(node)))
|
||||
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 ((CDDDR(node) != -1) && is_sexp_true(CDDDR(node)))
|
||||
op == OP_AI_WAYPOINTS_ONCE) {
|
||||
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_DISABLE_SHIP_TACTICAL ||
|
||||
op == OP_AI_DISARM_SHIP ||
|
||||
op == OP_AI_STAY_NEAR_SHIP) {
|
||||
if ((CDDDDR(node) != -1) && is_sexp_true(CDDDDR(node)))
|
||||
op == OP_AI_DISARM_SHIP_TACTICAL ||
|
||||
op == OP_AI_STAY_NEAR_SHIP ||
|
||||
op == OP_AI_FLY_TO_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 ((CDDDDDR(node) != -1) && is_sexp_true(CDDDDDR(node)))
|
||||
if (is_sexp_true(CDDDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
|
||||
@@ -1219,11 +1261,13 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
priority = ( CDR( CDR( CDR(node) ) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( CDR( node ) ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_DISABLE_SHIP:
|
||||
goalmode = AI_GOAL_DISABLE_SHIP;
|
||||
case OP_AI_DISABLE_SHIP_TACTICAL:
|
||||
goalmode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_DISARM_SHIP:
|
||||
goalmode = AI_GOAL_DISABLE_SHIP;
|
||||
case OP_AI_DISARM_SHIP_TACTICAL:
|
||||
goalmode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_WARP_OUT:
|
||||
@@ -1253,11 +1297,8 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_PLAY_DEAD:
|
||||
goalmode = AI_GOAL_PLAY_DEAD;
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_PLAY_DEAD_PERSISTENT:
|
||||
goalmode = AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
goalmode = (op == OP_AI_PLAY_DEAD) ? AI_GOAL_PLAY_DEAD : AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_KEEP_SAFE_DISTANCE:
|
||||
@@ -1299,12 +1340,9 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
goalmode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
break;
|
||||
case OP_AI_IGNORE:
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_IGNORE;
|
||||
break;
|
||||
case OP_AI_IGNORE_NEW:
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_IGNORE_NEW;
|
||||
goalmode = (op == OP_AI_IGNORE) ? AI_GOAL_IGNORE : AI_GOAL_IGNORE_NEW;
|
||||
break;
|
||||
case OP_AI_FORM_ON_WING:
|
||||
priority = 99;
|
||||
@@ -1427,15 +1465,8 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*
|
||||
int gindex;
|
||||
ai_goal *aigp;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Goober5000 - none of the goals act on the actor, as in ai_add_goal_sub_sexp
|
||||
if (!strcmp(name, Ships[aip->shipnum].ship_name))
|
||||
{
|
||||
// not good
|
||||
Int3();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
Assertion(strcmp(name, Ships[aip->shipnum].ship_name) != 0, "The goals apply to the actor in ai_add_goal_ship_internal for ship %s, please report to the SCP!", name);
|
||||
|
||||
// find an empty slot to put this goal in.
|
||||
gindex = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
|
||||
@@ -1486,7 +1517,7 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*
|
||||
break;
|
||||
|
||||
default:
|
||||
Int3(); // unsupported internal goal -- see Mike K or Mark A.
|
||||
UNREACHABLE("unsupported internal goal of %d found in ai_add_goal_ship_internal. Please report to the SCP", goal_type); // see Mike K or Mark A.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1526,13 +1557,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
{
|
||||
int status;
|
||||
ai_achievability return_val;
|
||||
ai_info *aip;
|
||||
int index = -1, sindex = -1;
|
||||
int modelnum = -1;
|
||||
|
||||
auto objp = &Objects[objnum];
|
||||
Assert( objp->instance != -1 );
|
||||
aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
auto shipp = &Ships[objp->instance];
|
||||
auto aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
// these orders are always achievable.
|
||||
if ( (aigp->ai_mode == AI_GOAL_KEEP_SAFE_DISTANCE)
|
||||
@@ -1543,11 +1572,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
if (aigp->ai_mode == AI_GOAL_LUA)
|
||||
return ai_lua_is_achievable(aigp, objnum);
|
||||
|
||||
auto target_ship_entry = aigp->target_name == nullptr ? nullptr : ship_registry_get(aigp->target_name);
|
||||
|
||||
// warp (depart) only achievable if there's somewhere to depart to
|
||||
if (aigp->ai_mode == AI_GOAL_WARP)
|
||||
{
|
||||
ship *shipp = &Ships[objp->instance];
|
||||
|
||||
// always valid if has working subspace drive, not disabled, and not limited by subsystem strength
|
||||
if ( ship_can_warp_full_check(shipp) )
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
@@ -1566,9 +1595,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// if the wing target is valid then be sure to set the override bit so that it always
|
||||
// gets executed next
|
||||
if ( aigp->ai_mode == AI_GOAL_FORM_ON_WING ) {
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
if (sindex < 0)
|
||||
if (!target_ship_entry || !target_ship_entry->has_shipp())
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
aigp->flags.set(AI::Goal_Flags::Goal_override);
|
||||
@@ -1625,11 +1652,10 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
|
||||
// destroyed when shipnum is valid
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
// can't determine the status of this goal if ship not valid
|
||||
// or we haven't found a valid subsystem index yet
|
||||
if ( (sindex == -1) || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
|
||||
if ( !target_ship_entry || !target_ship_entry->has_shipp() || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
@@ -1638,46 +1664,46 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// as 0 so we can continue. (The subsystem name must be turned into an index into the ship's subsystems
|
||||
// for this goal to be valid).
|
||||
Assert ( aigp->ai_submode >= 0 );
|
||||
ssp = ship_get_indexed_subsys( &Ships[sindex], aigp->ai_submode );
|
||||
ssp = ship_get_indexed_subsys( target_ship_entry->shipp(), aigp->ai_submode );
|
||||
if (ssp != NULL) {
|
||||
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
|
||||
status = (ssp->current_hits <= 0.0f) ? 1 : 0;
|
||||
} else {
|
||||
// not supposed to ever happen, but could if there is a mismatch between the table and model subsystems
|
||||
nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, Ships[sindex].ship_name));
|
||||
nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, target_ship_entry->shipp()->ship_name));
|
||||
status = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
{
|
||||
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
|
||||
// destroyed when shipnum is valid
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
// can't determine the status of this goal if ship not valid
|
||||
if (sindex < 0) {
|
||||
if (!target_ship_entry || !target_ship_entry->has_shipp()) {
|
||||
status = 0;
|
||||
} else {
|
||||
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
|
||||
status = (Ships[sindex].subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
status = (target_ship_entry->shipp()->subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
{
|
||||
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
|
||||
// destroyed when shipnum is valid
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
// can't determine the status of this goal if ship not valid
|
||||
if (sindex < 0) {
|
||||
if (!target_ship_entry || !target_ship_entry->has_shipp()) {
|
||||
status = 0;
|
||||
} else {
|
||||
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
|
||||
status = (Ships[sindex].subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
status = (target_ship_entry->shipp()->subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1696,22 +1722,23 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// MWA -- 4/22/98. Check for the ship actually being in the mission before
|
||||
// checking departure and destroyed. In multiplayer, since ships can respawn,
|
||||
// they get log entries for being destroyed even though they have respawned.
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
if ( sindex < 0 ) {
|
||||
status = mission_log_get_time( LOG_SHIP_DEPARTED, aigp->target_name, NULL, NULL);
|
||||
if ( !status ) {
|
||||
status = mission_log_get_time( LOG_SHIP_DESTROYED, aigp->target_name, NULL, NULL);
|
||||
if ( !status ) {
|
||||
status = mission_log_get_time( LOG_SELF_DESTRUCTED, aigp->target_name, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if ( status )
|
||||
return_val = ai_achievability::NOT_ACHIEVABLE;
|
||||
// Goober5000 - update this to use ship registry status with similar logic
|
||||
if (target_ship_entry && target_ship_entry->status == ShipStatus::EXITED) {
|
||||
status = 1;
|
||||
return_val = ai_achievability::NOT_ACHIEVABLE;
|
||||
} else {
|
||||
status = 0;
|
||||
}
|
||||
|
||||
// fly-to-ship can potentially be determined
|
||||
if (aigp->ai_mode == AI_GOAL_FLY_TO_SHIP && target_ship_entry && target_ship_entry->has_objp()) {
|
||||
auto dist = vm_vec_dist(&target_ship_entry->objp()->pos, &objp->pos);
|
||||
if (dist < aigp->float_data) {
|
||||
return_val = ai_achievability::SATISFIED;
|
||||
status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1749,7 +1776,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;
|
||||
}
|
||||
@@ -1764,12 +1791,12 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// the if statement.
|
||||
if ( (aigp->ai_mode == AI_GOAL_CHASE_WING) || (aigp->ai_mode == AI_GOAL_GUARD_WING) )
|
||||
{
|
||||
sindex = wing_name_lookup( aigp->target_name );
|
||||
int wingnum = wing_name_lookup( aigp->target_name );
|
||||
|
||||
if (sindex < 0)
|
||||
if (wingnum < 0)
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
wing *wingp = &Wings[sindex];
|
||||
wing *wingp = &Wings[wingnum];
|
||||
|
||||
if ( wingp->flags[Ship::Wing_Flags::Gone] )
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
@@ -1786,24 +1813,22 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ship_entry = ship_registry_get(aigp->target_name);
|
||||
|
||||
if (!ship_entry)
|
||||
if (!target_ship_entry)
|
||||
{
|
||||
status = SHIP_STATUS_UNKNOWN;
|
||||
}
|
||||
// goal ship is currently in mission
|
||||
else if (ship_entry->status == ShipStatus::PRESENT)
|
||||
else if (target_ship_entry->status == ShipStatus::PRESENT || target_ship_entry->status == ShipStatus::DEATH_ROLL)
|
||||
{
|
||||
status = SHIP_STATUS_ARRIVED;
|
||||
}
|
||||
// goal ship is still on the arrival list
|
||||
else if (ship_entry->status == ShipStatus::NOT_YET_PRESENT)
|
||||
else if (target_ship_entry->status == ShipStatus::NOT_YET_PRESENT)
|
||||
{
|
||||
status = SHIP_STATUS_NOT_ARRIVED;
|
||||
}
|
||||
// goal ship has left the area
|
||||
else if (ship_entry->status == ShipStatus::EXITED)
|
||||
else if (target_ship_entry->status == ShipStatus::EXITED)
|
||||
{
|
||||
status = SHIP_STATUS_GONE;
|
||||
}
|
||||
@@ -1814,16 +1839,21 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
if (status == SHIP_STATUS_UNKNOWN)
|
||||
{
|
||||
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", Ships[objp->instance].ship_name, aigp->target_name));
|
||||
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", shipp->ship_name, aigp->target_name));
|
||||
}
|
||||
}
|
||||
|
||||
// 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 ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP || aigp->ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL))
|
||||
{
|
||||
// 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;
|
||||
if (target_ship_entry && target_ship_entry->has_shipp()) {
|
||||
// if the ship has no turrets, we can't disarm it!
|
||||
if (target_ship_entry->shipp()->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
|
||||
@@ -1845,37 +1875,36 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// this goal will get removed.
|
||||
if ( (aigp->ai_mode == AI_GOAL_DOCK) && (status == SHIP_STATUS_ARRIVED) ) {
|
||||
if (!(aigp->flags[AI::Goal_Flags::Docker_index_valid])) {
|
||||
modelnum = Ship_info[Ships[objp->instance].ship_info_index].model_num;
|
||||
int modelnum = Ship_info[shipp->ship_info_index].model_num;
|
||||
Assert( modelnum >= 0 );
|
||||
index = model_find_dock_name_index(modelnum, aigp->docker.name);
|
||||
aigp->docker.index = index;
|
||||
aigp->docker.index = model_find_dock_name_index(modelnum, aigp->docker.name);
|
||||
aigp->flags.set(AI::Goal_Flags::Docker_index_valid);
|
||||
}
|
||||
|
||||
if (!(aigp->flags[AI::Goal_Flags::Dockee_index_valid])) {
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
if ( sindex != -1 ) {
|
||||
modelnum = Ship_info[Ships[sindex].ship_info_index].model_num;
|
||||
index = model_find_dock_name_index(modelnum, aigp->dockee.name);
|
||||
aigp->dockee.index = index;
|
||||
if (target_ship_entry && target_ship_entry->has_shipp()) {
|
||||
int modelnum = Ship_info[target_ship_entry->shipp()->ship_info_index].model_num;
|
||||
aigp->dockee.index = model_find_dock_name_index(modelnum, aigp->dockee.name);
|
||||
aigp->flags.set(AI::Goal_Flags::Dockee_index_valid);
|
||||
} else
|
||||
aigp->dockee.index = -1; // this will force code into if statement below making goal not achievable.
|
||||
}
|
||||
|
||||
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!", shipp->ship_name); // for now, allender wants to know about these things!!!!
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
// if ship is disabled, don't know if it can dock or not
|
||||
if ( Ships[objp->instance].flags[Ship::Ship_Flags::Disabled] )
|
||||
if ( shipp->flags[Ship::Ship_Flags::Disabled] )
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
// we must also determine if we're prevented from docking for any reason
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
Assert( sindex >= 0 );
|
||||
object *goal_objp = &Objects[Ships[sindex].objnum];
|
||||
if (!target_ship_entry || !target_ship_entry->has_shipp()) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
auto goal_objp = target_ship_entry->objp();
|
||||
|
||||
// if the ship that I am supposed to dock with is docked with something else, then I need to put my goal on hold
|
||||
// [MK, 4/23/98: With Mark, we believe this fixes the problem of Comet refusing to warp out after docking with Omega.
|
||||
@@ -1924,9 +1953,14 @@ 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;
|
||||
if ( target_ship_entry && target_ship_entry->has_objp() ) {
|
||||
// only put it on hold if it's someone other than the guy we're undocking from right now!!
|
||||
if (aip->goal_objnum != target_ship_entry->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) ) {
|
||||
@@ -1934,23 +1968,21 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// have fixed up the subsystem name (of the subsystem to destroy) into an index into
|
||||
// the ship's subsystem list
|
||||
if ( aigp->flags[AI::Goal_Flags::Subsys_needs_fixup] ) {
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
if ( sindex != -1 ) {
|
||||
aigp->ai_submode = ship_find_subsys( &Ships[sindex], aigp->docker.name );
|
||||
if ( target_ship_entry && target_ship_entry->has_shipp() ) {
|
||||
aigp->ai_submode = ship_find_subsys( target_ship_entry->shipp(), 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
|
||||
}
|
||||
}
|
||||
} else if ( ((aigp->ai_mode == AI_GOAL_IGNORE) || (aigp->ai_mode == AI_GOAL_IGNORE_NEW)) && (status == SHIP_STATUS_ARRIVED) ) {
|
||||
object *ignored;
|
||||
|
||||
// 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
|
||||
ignored = &Objects[Ships[sindex].objnum];
|
||||
if (!target_ship_entry || !target_ship_entry->has_objp()) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
auto ignored = target_ship_entry->objp();
|
||||
|
||||
ai_ignore_object(objp, ignored, (aigp->ai_mode == AI_GOAL_IGNORE_NEW));
|
||||
|
||||
@@ -1966,7 +1998,9 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
case AI_GOAL_GUARD:
|
||||
case AI_GOAL_GUARD_WING:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
@@ -1983,7 +2017,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, shipp->ship_name); // get allender -- bad logic
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1995,31 +2029,29 @@ 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", shipp->ship_name, aigp->target_name); // get Allender. this shouldn't happen!!!
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
if ( status == SHIP_STATUS_GONE )
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
if ( sindex < 0 ) {
|
||||
Int3();
|
||||
if ( !target_ship_entry || !target_ship_entry->has_shipp() ) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
// if desitnation currently being repaired, then goal is stil active
|
||||
if ( Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
|
||||
// if destination currently being repaired, then goal is still active
|
||||
if ( Ai_info[target_ship_entry->shipp()->ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
|
||||
// if the destination ship is dying or departing (but not completed yet), the mark goal as
|
||||
// not achievable.
|
||||
if ( Ships[sindex].is_dying_or_departing())
|
||||
if ( target_ship_entry->shipp()->is_dying_or_departing())
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
// if the destination object is no longer awaiting repair, then remove the item
|
||||
if ( !(Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
|
||||
if ( !(Ai_info[target_ship_entry->shipp()->ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
// not repairing anything means that he can do this goal!!!
|
||||
@@ -2034,14 +2066,14 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// if he is repairing something, he can satisfy his repair goal (his goal_objnum)
|
||||
// return GOAL_NOT_KNOWN which is kind of a hack which puts the goal on hold until it can be
|
||||
// satisfied.
|
||||
if ( aip->goal_objnum != Ships[sindex].objnum )
|
||||
if ( aip->goal_objnum != target_ship_entry->objnum )
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
|
||||
default:
|
||||
Int3(); // invalid case in switch:
|
||||
UNREACHABLE("Unhandled AI goal %d", aigp->ai_mode); // invalid case in switch:
|
||||
}
|
||||
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
@@ -2308,19 +2340,14 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
case AI_GOAL_WAYPOINTS: // do nothing for waypoints
|
||||
case AI_GOAL_WAYPOINTS_ONCE: {
|
||||
int flags = 0;
|
||||
|
||||
if ( current_goal->ai_mode == AI_GOAL_WAYPOINTS)
|
||||
if (current_goal->ai_mode == AI_GOAL_WAYPOINTS)
|
||||
flags |= WPF_REPEAT;
|
||||
ai_start_waypoints(objp, current_goal->wp_list, flags);
|
||||
if (current_goal->flags[AI::Goal_Flags::Waypoints_in_reverse])
|
||||
flags |= WPF_BACKTRACK;
|
||||
ai_start_waypoints(objp, current_goal->wp_list, flags, current_goal->int_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
|
||||
ai_start_fly_to_ship(objp, shipnum);
|
||||
break;
|
||||
|
||||
case AI_GOAL_DOCK: {
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
|
||||
@@ -2395,22 +2422,27 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
break;
|
||||
|
||||
|
||||
// when destroying a subsystem, we can destroy a specific instance of a subsystem
|
||||
// or all instances of a type of subsystem (i.e. a specific engine or all engines).
|
||||
// the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
|
||||
// instances of a specific type
|
||||
// when destroying a subsystem, we can destroy a specific instance of a subsystem
|
||||
// or all instances of a type of subsystem (i.e. a specific engine or all engines).
|
||||
// the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
|
||||
// instances of a specific type
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP: {
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL: {
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
ai_attack_object( objp, other_obj);
|
||||
ai_set_attack_subsystem( objp, current_goal->ai_submode ); // submode stored the subsystem type
|
||||
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM) {
|
||||
|
||||
// don't protect-ship for tactical goals
|
||||
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM && current_goal->ai_mode != AI_GOAL_DISABLE_SHIP_TACTICAL && current_goal->ai_mode != AI_GOAL_DISARM_SHIP_TACTICAL) {
|
||||
if (aip->target_objnum != -1) {
|
||||
int class_type = Ship_info[Ships[shipnum].ship_info_index].class_type;
|
||||
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
|
||||
if (Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
|
||||
if (class_type >= 0 && Ship_types[class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
|
||||
Objects[aip->target_objnum].flags.set(Object::Object_Flags::Protected);
|
||||
}
|
||||
} else // Just in case this ship had been protected, unprotect it.
|
||||
@@ -2488,14 +2520,17 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
|
||||
// labels for support ship commands
|
||||
|
||||
case AI_GOAL_STAY_NEAR_SHIP: {
|
||||
case AI_GOAL_STAY_NEAR_SHIP:
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
{
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
float dist = current_goal->float_data; // How far away to stay from ship. Should be set in SEXP?
|
||||
ai_do_stay_near(objp, other_obj, dist);
|
||||
int additional_data = current_goal->int_data; // Whether to target a particular point as if escorting
|
||||
ai_do_stay_near(objp, other_obj, dist, additional_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case AI_GOAL_KEEP_SAFE_DISTANCE:
|
||||
// todo MK: hook to keep support ship at a safe distance
|
||||
@@ -2516,7 +2551,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
break;
|
||||
|
||||
default:
|
||||
Int3();
|
||||
UNREACHABLE("unsupported goal of %d found in ai_process_mission_orders. Please report to the SCP", current_goal->ai_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2543,7 +2578,9 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_GUARD:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
@@ -2617,7 +2654,9 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_GUARD:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
|
||||
+9
-7
@@ -73,15 +73,17 @@ struct ai_info;
|
||||
#define AI_GOAL_FLY_TO_SHIP (1<<23) // 0x00800000
|
||||
#define AI_GOAL_IGNORE_NEW (1<<24) // 0x01000000
|
||||
#define AI_GOAL_CHASE_SHIP_CLASS (1<<25) // 0x02000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x03000000
|
||||
#define AI_GOAL_LUA (1<<27) // 0x04000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x04000000
|
||||
#define AI_GOAL_LUA (1<<27) // 0x08000000
|
||||
#define AI_GOAL_DISARM_SHIP_TACTICAL (1<<28) // 0x10000000
|
||||
#define AI_GOAL_DISABLE_SHIP_TACTICAL (1<<29) // 0x20000000
|
||||
|
||||
// now the masks for ship types
|
||||
|
||||
// Goober5000: added AI_GOAL_STAY_NEAR_SHIP and AI_GOAL_KEEP_SAFE_DISTANCE as valid for fighters
|
||||
//WMC - Don't need these anymore. Whee!
|
||||
/*
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_BOMBER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_STEALTH ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
@@ -166,17 +168,17 @@ extern void ai_process_mission_orders( int objnum, ai_info *aip );
|
||||
extern int ai_goal_num(ai_goal *goals);
|
||||
|
||||
// adds goals to ships/wing through sexpressions
|
||||
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipname, ai_info *aip);
|
||||
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, const char *shipname, ai_info *aip);
|
||||
extern void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip );
|
||||
extern void ai_add_wing_goal_sexp( int sexp, int type, wing *wingp );
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char *actor_name);
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, const char *actor_name);
|
||||
|
||||
extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp );
|
||||
extern void ai_remove_wing_goal_sexp( int sexp, wing *wingp );
|
||||
|
||||
// adds goals to ships/sings through player orders
|
||||
extern void ai_add_ship_goal_player(int type, int mode, int submode, char* shipname, ai_info* aip, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_wing_goal_player(int type, int mode, int submode, char* shipname, int wingnum, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_ship_goal_player(int type, int mode, int submode, const char* shipname, ai_info* aip, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
extern void ai_add_wing_goal_player(int type, int mode, int submode, const char* shipname, int wingnum, const ai_lua_parameters& lua_target = { object_ship_wing_point_team(), luacpp::LuaValueList{} });
|
||||
|
||||
extern void ai_remove_ship_goal( ai_info *aip, int index );
|
||||
extern void ai_clear_ship_goals( ai_info *aip );
|
||||
|
||||
@@ -14,24 +14,24 @@
|
||||
#include "weapon/weapon.h"
|
||||
|
||||
//Returns true if the specified object is a stealth ship, false if not
|
||||
bool is_object_stealth_ship(object* objp);
|
||||
bool is_object_stealth_ship(const object* objp);
|
||||
|
||||
//Number of live turrets on the object attacking
|
||||
int num_turrets_attacking(object *turret_parent, int target_objnum);
|
||||
int num_turrets_attacking(const object *turret_parent, int target_objnum);
|
||||
|
||||
//Determine whether an object is targetable within a nebula (checks for stealth)
|
||||
int object_is_targetable(object *target, ship *viewer);
|
||||
bool object_is_targetable(const object *target, const ship *viewer);
|
||||
|
||||
//Returns the number of enemy fighters within threshold of pos.
|
||||
int num_nearby_fighters(int enemy_team_mask, vec3d *pos, float threshold);
|
||||
int num_nearby_fighters(int enemy_team_mask, const vec3d *pos, float threshold);
|
||||
|
||||
//Returns true if OK for *aip to fire its current weapon at its current target.
|
||||
int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip, int secondary_bank, ship_subsys* turret);
|
||||
bool check_ok_to_fire(int objnum, int target_objnum, const weapon_info *wip, int secondary_bank, const vec3d *firing_pos_global);
|
||||
|
||||
//Returns true if *aip has a line of sight to its current target.
|
||||
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, ship_subsys* turret);
|
||||
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, const vec3d *firing_pos_global);
|
||||
|
||||
//Does all the stuff needed to aim and fire a turret.
|
||||
void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss);
|
||||
void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss);
|
||||
|
||||
#endif
|
||||
+169
-6
@@ -18,9 +18,9 @@ void ai_lua_add_mode(int sexp_op, const ai_mode_lua& mode) {
|
||||
}
|
||||
|
||||
bool ai_lua_add_order(int sexp_op, player_order_lua order) {
|
||||
Player_orders.emplace_back(vm_strdup(order.parseText.c_str()), vm_strdup(order.displayText.c_str()), -1, sexp_op);
|
||||
Player_orders.emplace_back(order.parseText, order.displayText, -1, sexp_op);
|
||||
Player_orders.back().localize();
|
||||
|
||||
|
||||
Lua_player_orders.emplace(sexp_op, std::move(order));
|
||||
|
||||
return true;
|
||||
@@ -48,6 +48,140 @@ const player_order_lua* ai_lua_find_player_order(int sexp_op) {
|
||||
return &aiLuaOrder->second;
|
||||
}
|
||||
|
||||
int ai_lua_get_num_general_orders() {
|
||||
int count = 0;
|
||||
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
if (order.second.generalOrder) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only)
|
||||
{
|
||||
SCP_vector<SCP_string> list;
|
||||
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
const SCP_string &cat = order.second.category;
|
||||
|
||||
// If it's not a general order then move on
|
||||
if (!order.second.generalOrder) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the order is not enabled then move on
|
||||
if (enabled_only && !order.second.cur_enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Assertion((cat.length() > 0), "Lua general orders category name must be longer than 0 characters!");
|
||||
|
||||
for (size_t i = 0; i <= list.size(); i++) {
|
||||
|
||||
// reached the end of the list, so add it
|
||||
if (i == list.size()) {
|
||||
list.push_back(cat);
|
||||
break;
|
||||
}
|
||||
|
||||
// if it's already in the list then don't add it
|
||||
if (cat == list[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// Provides a list of general orders for mission saving. You can only get one kind
|
||||
// of list at a time. If onlyEnabled and onlyValid are both true, for example, you will get
|
||||
// a list of onlyEnabled orders. If you need a list of enabled orders that are also valid, you'll
|
||||
// need to get both lists separately and compare.
|
||||
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled, bool onlyValid, const SCP_string& category)
|
||||
{
|
||||
SCP_vector<SCP_string> list;
|
||||
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
if (order.second.generalOrder) {
|
||||
bool add = false;
|
||||
|
||||
// All general orders
|
||||
if (!onlyEnabled && !onlyValid && category.empty()) {
|
||||
add = true;
|
||||
} else {
|
||||
|
||||
// Only enabled orders
|
||||
if (onlyEnabled && order.second.cur_enabled) {
|
||||
add = true;
|
||||
|
||||
// Only valid orders
|
||||
} else if (onlyValid && order.second.cur_valid) {
|
||||
add = true;
|
||||
|
||||
// Only orders that match the category requested
|
||||
} else if ((!category.empty()) && (order.second.category == category)) {
|
||||
add = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (add) {
|
||||
list.push_back(order.second.parseText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int ai_lua_find_general_order_id(const SCP_string& name) {
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
if (order.second.parseText == name) {
|
||||
return order.first;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ai_lua_enable_general_order(int sexp_op, bool enable) {
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return;
|
||||
else
|
||||
aiLuaOrder->second.cur_enabled = enable;
|
||||
}
|
||||
|
||||
void ai_lua_validate_general_order(int sexp_op, bool validity)
|
||||
{
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return;
|
||||
else
|
||||
aiLuaOrder->second.cur_valid = validity;
|
||||
}
|
||||
|
||||
void ai_lua_reset_general_orders() {
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
ai_lua_enable_general_order(order.first, false);
|
||||
ai_lua_validate_general_order(order.first, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool ai_lua_is_general_order(int sexp_op) {
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return false;
|
||||
|
||||
return aiLuaOrder->second.generalOrder;
|
||||
}
|
||||
|
||||
void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua_ai, ai_info* aip) {
|
||||
if (!action.isValid()) {
|
||||
Error(LOCATION,
|
||||
@@ -56,7 +190,11 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
|
||||
}
|
||||
|
||||
luacpp::LuaValueList luaParameters;
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
|
||||
if (aip->shipnum >= 0){
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
|
||||
} else {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h())));
|
||||
}
|
||||
if (lua_ai.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target.target)));
|
||||
}
|
||||
@@ -67,8 +205,13 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
|
||||
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
|
||||
if (retVals[0].getValue<bool>())
|
||||
ai_mission_goal_complete(aip);
|
||||
if (retVals[0].getValue<bool>()) {
|
||||
|
||||
// If we don't have a ship then it's a general order and we have nothing else to do
|
||||
if (aip->shipnum >= 0) {
|
||||
ai_mission_goal_complete(aip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +246,26 @@ void ai_lua_start(ai_goal* aigp, object* objp){
|
||||
run_ai_lua_action(action, lua_ai, aip);
|
||||
}
|
||||
|
||||
// For sending general orders that don't run on a ship.
|
||||
// Essentially just runs arbitrary lua script when the command is called
|
||||
void ai_lua_start_general(int lua_sexp_id, int target_objnum)
|
||||
{
|
||||
//Create a dummy aip to pass the target data
|
||||
ai_info aip;
|
||||
aip.shipnum = -1;
|
||||
|
||||
if (target_objnum >= 0 && Objects[target_objnum].type == OBJ_SHIP) {
|
||||
aip.lua_ai_target = {object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]), {}};
|
||||
}
|
||||
|
||||
const auto& lua_ai = ai_lua_find_mode(lua_sexp_id);
|
||||
|
||||
const auto& lua_ai_sexp = lua_ai->sexp;
|
||||
const auto& action = lua_ai_sexp.getActionEnter();
|
||||
|
||||
run_ai_lua_action(action, *lua_ai, &aip);
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_target_intrinsic(int sexp_op, int target_objnum, ship* self) {
|
||||
ship* target = &Ships[Objects[target_objnum].instance];
|
||||
|
||||
@@ -226,7 +389,7 @@ ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum){
|
||||
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::USERDATA) {
|
||||
scripting::api::enum_h enumData;
|
||||
retVals[0].getValue(scripting::api::l_Enum.Get(&enumData));
|
||||
if (!enumData.IsValid()) {
|
||||
if (!enumData.isValid()) {
|
||||
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ struct player_order_lua {
|
||||
int ai_message = MESSAGE_YESSIR;
|
||||
SCP_string parseText = "";
|
||||
SCP_string displayText = "";
|
||||
bool generalOrder = false;
|
||||
SCP_string category = "";
|
||||
bool cur_enabled = false;
|
||||
bool cur_valid = false;
|
||||
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;
|
||||
};
|
||||
@@ -29,8 +33,17 @@ bool ai_lua_add_order(int sexp_op, player_order_lua order);
|
||||
bool ai_lua_has_mode(int sexp_op);
|
||||
const ai_mode_lua* ai_lua_find_mode(int sexp_op);
|
||||
const player_order_lua* ai_lua_find_player_order(int sexp_op);
|
||||
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only = true);
|
||||
int ai_lua_get_num_general_orders();
|
||||
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled = false, bool onlyValid = false, const SCP_string& category = "");
|
||||
int ai_lua_find_general_order_id(const SCP_string& name);
|
||||
void ai_lua_enable_general_order(int sexp_op, bool enable);
|
||||
void ai_lua_validate_general_order(int sexp_op, bool validity);
|
||||
void ai_lua_reset_general_orders();
|
||||
bool ai_lua_is_general_order(int sexp_op);
|
||||
void ai_lua(ai_info* aip);
|
||||
void ai_lua_start(ai_goal* aigp, object* objp);
|
||||
void ai_lua_start_general(int lua_sexp_id, int target_objnum);
|
||||
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);
|
||||
+179
-244
@@ -72,29 +72,29 @@ const char* Turret_valid_types[NUM_TURRET_TYPES] = {
|
||||
};
|
||||
|
||||
typedef struct eval_enemy_obj_struct {
|
||||
int turret_parent_objnum; // parent of turret
|
||||
float weapon_travel_dist; // max targeting range of turret weapon
|
||||
int enemy_team_mask;
|
||||
int weapon_system_ok; // is the weapon subsystem of turret ship ok
|
||||
int eeo_flags;
|
||||
int turret_parent_objnum = -1; // parent of turret
|
||||
float weapon_travel_dist = 0.0f; // max targeting range of turret weapon
|
||||
int enemy_team_mask = 0;
|
||||
bool weapon_system_ok = false; // is the weapon subsystem of turret ship ok
|
||||
int eeo_flags = 0;
|
||||
|
||||
vec3d *tpos;
|
||||
vec3d *tvec;
|
||||
ship_subsys *turret_subsys;
|
||||
int current_enemy;
|
||||
const vec3d *tpos = nullptr;
|
||||
const vec3d *tvec = nullptr;
|
||||
const ship_subsys *turret_subsys = nullptr;
|
||||
int current_enemy = -1;
|
||||
|
||||
|
||||
float nearest_attacker_dist; // nearest ship
|
||||
int nearest_attacker_objnum;
|
||||
float nearest_attacker_dist = 99999.0f; // nearest ship
|
||||
int nearest_attacker_objnum = -1;
|
||||
|
||||
float nearest_homing_bomb_dist; // nearest homing bomb
|
||||
int nearest_homing_bomb_objnum;
|
||||
float nearest_homing_bomb_dist = 99999.0f; // nearest homing bomb
|
||||
int nearest_homing_bomb_objnum = -1;
|
||||
|
||||
float nearest_bomb_dist; // nearest non-homing bomb
|
||||
int nearest_bomb_objnum;
|
||||
float nearest_bomb_dist = 99999.0f; // nearest non-homing bomb
|
||||
int nearest_bomb_objnum = -1;
|
||||
|
||||
float nearest_dist; // nearest ship attacking this turret
|
||||
int nearest_objnum;
|
||||
float nearest_dist = 99999.0f; // nearest ship attacking this turret
|
||||
int nearest_objnum = -1;
|
||||
} eval_enemy_obj_struct;
|
||||
|
||||
// the current world orientation of the turret matrix, corresponding to its fvec and uvec defined in the model
|
||||
@@ -118,9 +118,9 @@ void turret_instance_find_world_orient(matrix* out_mat, int model_instance_num,
|
||||
* @param tpos Turret initial position
|
||||
* @param dist Distance from turret to center point of object
|
||||
*
|
||||
* @return 1 if objp is in fov of the specified turret. Otherwise return 0.
|
||||
* @return true if objp is in fov of the specified turret. Otherwise return false.
|
||||
*/
|
||||
bool object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, float dist)
|
||||
bool object_in_turret_fov(const object *objp, const ship_subsys *ss, const vec3d *tvec, const vec3d *tpos, float dist)
|
||||
{
|
||||
vec3d v2e;
|
||||
float size_mod;
|
||||
@@ -175,9 +175,9 @@ bool object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpo
|
||||
* @param bomb_objp Bomb specified
|
||||
* @param ship_objp Ship specified
|
||||
*
|
||||
* @return 1 if bomb_objp is headed towards ship_objp
|
||||
* @return true if bomb_objp is headed towards ship_objp
|
||||
*/
|
||||
int bomb_headed_towards_ship(object *bomb_objp, object *ship_objp)
|
||||
bool bomb_headed_towards_ship(const object *bomb_objp, const object *ship_objp)
|
||||
{
|
||||
float dot;
|
||||
vec3d bomb_to_ship_vector;
|
||||
@@ -185,11 +185,7 @@ int bomb_headed_towards_ship(object *bomb_objp, object *ship_objp)
|
||||
vm_vec_normalized_dir(&bomb_to_ship_vector, &ship_objp->pos, &bomb_objp->pos);
|
||||
dot = vm_vec_dot(&bomb_objp->orient.vec.fvec, &bomb_to_ship_vector);
|
||||
|
||||
if ( dot > 0 ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ( dot > 0 );
|
||||
}
|
||||
|
||||
// Set active weapon for turret
|
||||
@@ -201,7 +197,7 @@ int bomb_headed_towards_ship(object *bomb_objp, object *ship_objp)
|
||||
* @note All non-negative return values are expressed in what I like to call "widx"s.
|
||||
* @return -1 if unable to find a weapon for the target at all.
|
||||
*/
|
||||
int turret_select_best_weapon(ship_subsys *turret, object * /*target*/)
|
||||
int turret_select_best_weapon(const ship_subsys *turret, const object * /*target*/)
|
||||
{
|
||||
//TODO: Fill this out with extraodinary gun-picking algorithms
|
||||
if(turret->weapons.num_primary_banks > 0)
|
||||
@@ -215,7 +211,7 @@ int turret_select_best_weapon(ship_subsys *turret, object * /*target*/)
|
||||
/**
|
||||
* Returns true if all weapons in swp have the specified flag
|
||||
*/
|
||||
bool all_turret_weapons_have_flags(ship_weapon *swp, flagset<Weapon::Info_Flags> flags)
|
||||
bool all_turret_weapons_have_flags(const ship_weapon *swp, flagset<Weapon::Info_Flags> flags)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < swp->num_primary_banks; i++)
|
||||
@@ -232,7 +228,7 @@ bool all_turret_weapons_have_flags(ship_weapon *swp, flagset<Weapon::Info_Flags>
|
||||
return true;
|
||||
}
|
||||
|
||||
bool all_turret_weapons_have_flags(ship_weapon *swp, Weapon::Info_Flags flags)
|
||||
bool all_turret_weapons_have_flags(const ship_weapon *swp, Weapon::Info_Flags flags)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < swp->num_primary_banks; i++)
|
||||
@@ -253,7 +249,7 @@ bool all_turret_weapons_have_flags(ship_weapon *swp, Weapon::Info_Flags flags)
|
||||
* Returns true if any of the weapons in swp have flags
|
||||
*
|
||||
*/
|
||||
bool turret_weapon_has_flags(ship_weapon *swp, Weapon::Info_Flags flags)
|
||||
bool turret_weapon_has_flags(const ship_weapon *swp, Weapon::Info_Flags flags)
|
||||
{
|
||||
Assert(swp != NULL);
|
||||
|
||||
@@ -279,7 +275,7 @@ bool turret_weapon_has_flags(ship_weapon *swp, Weapon::Info_Flags flags)
|
||||
/**
|
||||
* Just gloms all the flags from all the weapons into one variable. More efficient if all you need to do is test for the existence of a flag.
|
||||
*/
|
||||
flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(ship_weapon *swp)
|
||||
flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(const ship_weapon *swp)
|
||||
{
|
||||
Assert(swp != NULL);
|
||||
|
||||
@@ -307,7 +303,7 @@ flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(ship_weapon *swp)
|
||||
* @note It might be a little faster to optimize based on WP_LASER should only appear in primaries
|
||||
* and WP_MISSILE in secondaries. but in the interest of future coding I leave it like this.
|
||||
*/
|
||||
bool turret_weapon_has_subtype(ship_weapon *swp, int subtype)
|
||||
bool turret_weapon_has_subtype(const ship_weapon *swp, int subtype)
|
||||
{
|
||||
Assert(swp != NULL);
|
||||
|
||||
@@ -335,7 +331,7 @@ bool turret_weapon_has_subtype(ship_weapon *swp, int subtype)
|
||||
*
|
||||
* @return a pointer to the Weapon_info for weapon_num
|
||||
*/
|
||||
weapon_info *get_turret_weapon_wip(ship_weapon *swp, int weapon_num)
|
||||
const weapon_info *get_turret_weapon_wip(const ship_weapon *swp, int weapon_num)
|
||||
{
|
||||
Assert(weapon_num < MAX_SHIP_WEAPONS);
|
||||
Assert(weapon_num >= 0);
|
||||
@@ -352,7 +348,7 @@ weapon_info *get_turret_weapon_wip(ship_weapon *swp, int weapon_num)
|
||||
return &Weapon_info[wi_index];
|
||||
}
|
||||
|
||||
int get_turret_weapon_next_fire_stamp(ship_weapon *swp, int weapon_num)
|
||||
int get_turret_weapon_next_fire_stamp(const ship_weapon *swp, int weapon_num)
|
||||
{
|
||||
Assert(weapon_num < MAX_SHIP_WEAPONS);
|
||||
Assert(weapon_num >= 0);
|
||||
@@ -379,7 +375,7 @@ void set_turret_weapon_next_fire_stamp(ship_weapon *swp, int weapon_num, int del
|
||||
*
|
||||
* @todo This function is kinda slow
|
||||
*/
|
||||
float longest_turret_weapon_range(ship_weapon *swp)
|
||||
float longest_turret_weapon_range(const ship_weapon *swp)
|
||||
{
|
||||
float longest_range_so_far = 0.0f;
|
||||
float weapon_range;
|
||||
@@ -492,7 +488,7 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
|
||||
{
|
||||
object *turret_parent_obj = &Objects[eeo->turret_parent_objnum];
|
||||
ship *shipp;
|
||||
ship_subsys *ss = eeo->turret_subsys;
|
||||
auto ss = eeo->turret_subsys;
|
||||
float dist, dist_comp;
|
||||
bool turret_has_no_target = false;
|
||||
|
||||
@@ -770,12 +766,10 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
|
||||
* @param laser_flag
|
||||
* @param missile_flag
|
||||
*/
|
||||
int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subsys, int enemy_team_mask, vec3d *tpos, vec3d *tvec, int current_enemy, bool big_only_flag, bool small_only_flag, bool tagged_only_flag, bool beam_flag, bool flak_flag, bool laser_flag, bool missile_flag)
|
||||
int get_nearest_turret_objnum(int turret_parent_objnum, const ship_subsys *turret_subsys, int enemy_team_mask, const vec3d *tpos, const vec3d *tvec, int current_enemy, bool big_only_flag, bool small_only_flag, bool tagged_only_flag, bool beam_flag, bool flak_flag, bool laser_flag, bool missile_flag)
|
||||
{
|
||||
//float weapon_travel_dist;
|
||||
int weapon_system_ok;
|
||||
eval_enemy_obj_struct eeo;
|
||||
ship_weapon *swp = &turret_subsys->weapons;
|
||||
auto swp = &turret_subsys->weapons;
|
||||
|
||||
// list of stuff to go thru
|
||||
ship_obj *so;
|
||||
@@ -788,10 +782,7 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
// weapon_travel_dist=wip->lssm_lock_range;
|
||||
|
||||
// Set flag based on strength of weapons subsystem. If weapons subsystem is destroyed, don't let turrets fire at bombs
|
||||
weapon_system_ok = 0;
|
||||
if ( ship_get_subsystem_strength( &Ships[Objects[turret_parent_objnum].instance], SUBSYSTEM_WEAPONS ) > 0 ) {
|
||||
weapon_system_ok = 1;
|
||||
}
|
||||
bool weapon_system_ok = !ship_subsystems_blown(&Ships[Objects[turret_parent_objnum].instance], SUBSYSTEM_WEAPONS);
|
||||
|
||||
// Initialize eeo struct.
|
||||
eeo.turret_parent_objnum = turret_parent_objnum;
|
||||
@@ -823,18 +814,6 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
eeo.tvec = tvec;
|
||||
eeo.turret_subsys = turret_subsys;
|
||||
|
||||
eeo.nearest_attacker_dist = 99999.0f;
|
||||
eeo.nearest_attacker_objnum = -1;
|
||||
|
||||
eeo.nearest_homing_bomb_dist = 99999.0f;
|
||||
eeo.nearest_homing_bomb_objnum = -1;
|
||||
|
||||
eeo.nearest_bomb_dist = 99999.0f;
|
||||
eeo.nearest_bomb_objnum = -1;
|
||||
|
||||
eeo.nearest_dist = 99999.0f;
|
||||
eeo.nearest_objnum = -1;
|
||||
|
||||
// here goes the new targeting priority setting
|
||||
int n_tgt_priorities;
|
||||
int priority_weapon_idx = -1;
|
||||
@@ -1064,7 +1043,7 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
break;
|
||||
|
||||
default:
|
||||
Int3(); //Means invalid number passed.
|
||||
UNREACHABLE("Invalid target type of %d sent to get_nearest_turret_objnum. Please report to the SCP!", turret_subsys->turret_targeting_order[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1084,7 +1063,7 @@ DCF_BOOL(use_parent_target, Use_parent_target)
|
||||
* @param tvec Forward vector of turret (world coords)
|
||||
* @param current_enemy Objnum of current turret target
|
||||
*/
|
||||
int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d *tvec, int current_enemy)
|
||||
int find_turret_enemy(const ship_subsys *turret_subsys, int objnum, const vec3d *tpos, const vec3d *tvec, int current_enemy)
|
||||
{
|
||||
int enemy_team_mask, enemy_objnum;
|
||||
ship_info *sip;
|
||||
@@ -1104,7 +1083,7 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
|
||||
ai_info *aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
|
||||
sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
|
||||
|
||||
if ((Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
|
||||
if ((sip->class_type >= 0) && (Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
|
||||
int target_objnum = aip->target_objnum;
|
||||
|
||||
if (Objects[target_objnum].signature == aip->target_signature) {
|
||||
@@ -1171,9 +1150,9 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
|
||||
Assert( !((Objects[enemy_objnum].flags[Object::Object_Flags::Flak_protected]) && flak_flag) );
|
||||
Assert( !((Objects[enemy_objnum].flags[Object::Object_Flags::Laser_protected]) && laser_flag) );
|
||||
Assert( !((Objects[enemy_objnum].flags[Object::Object_Flags::Missile_protected]) && missile_flag) );
|
||||
Assertion(!Objects[enemy_objnum].flags[Object::Object_Flags::Protected], "find_turret_enemy selected an object of type %d %s that is protected, please report to the SCP!", Objects[enemy_objnum].type, Objects[enemy_objnum].type == OBJ_SHIP ? Ships[Objects[enemy_objnum].instance].ship_name : "");
|
||||
|
||||
if ( Objects[enemy_objnum].flags[Object::Object_Flags::Protected] ) {
|
||||
Int3();
|
||||
enemy_objnum = aip->target_objnum;
|
||||
}
|
||||
}
|
||||
@@ -1205,8 +1184,6 @@ void ship_get_global_turret_info(const object *objp, const model_subsystem *tp,
|
||||
model_instance_local_to_global_dir(gvec, &tp->turret_norm, model_instance_num, tp->subobj_num, &objp->orient, true);
|
||||
}
|
||||
|
||||
void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss);
|
||||
|
||||
/**
|
||||
* Given an object and a turret on that object, return the actual firing point of the gun and its normal.
|
||||
*
|
||||
@@ -1217,86 +1194,44 @@ void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss);
|
||||
* @param objp Pointer to object
|
||||
* @param ssp Pointer to turret subsystem
|
||||
* @param gpos Absolute position of gun firing point
|
||||
* @param avg_origin Use virtual gun pos corresponding to the average of the firing points
|
||||
* @param gvec Vector from *gpos to *targetp
|
||||
* @param use_angles Use current angles
|
||||
* @param targetp Pointer to target object
|
||||
* @param targetp Absolute position of target object
|
||||
*/
|
||||
void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, int use_angles, vec3d *targetp)
|
||||
void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp, vec3d *gpos, bool avg_origin, vec3d *gvec, bool use_angles, const vec3d *targetp)
|
||||
{
|
||||
vec3d * gun_pos;
|
||||
vec3d *gun_pos;
|
||||
model_subsystem *tp = ssp->system_info;
|
||||
polymodel_instance *pmi = model_get_instance(Ships[objp->instance].model_instance_num);
|
||||
polymodel *pm = model_get(pmi->model_num);
|
||||
|
||||
gun_pos = &tp->turret_firing_point[ssp->turret_next_fire_pos % tp->turret_num_firing_points];
|
||||
vec3d avg_gun_pos;
|
||||
if (avg_origin) {
|
||||
vm_vec_avg_n(&avg_gun_pos, tp->turret_num_firing_points, tp->turret_firing_point);
|
||||
gun_pos = &avg_gun_pos;
|
||||
} else {
|
||||
gun_pos = &tp->turret_firing_point[ssp->turret_next_fire_pos % tp->turret_num_firing_points];
|
||||
}
|
||||
|
||||
model_instance_local_to_global_point(gpos, gun_pos, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
|
||||
|
||||
// we might not need to calculate this
|
||||
if (!gvec)
|
||||
return;
|
||||
|
||||
if (use_angles) {
|
||||
model_instance_local_to_global_dir(gvec, &tp->turret_norm, pm, pmi, tp->turret_gun_sobj, &objp->orient);
|
||||
} else if (tp->flags[Model::Subsystem_Flags::Share_fire_direction]) {
|
||||
vec3d avg, tmp_pos, tmp_target, enemy_point, turret_norm;
|
||||
vm_vec_avg_n(&avg, tp->turret_num_firing_points, tp->turret_firing_point);
|
||||
|
||||
model_instance_local_to_global_point(&tmp_pos, &avg, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
|
||||
|
||||
if (targetp == nullptr) {
|
||||
ship* shipp = &Ships[Objects[ssp->parent_objnum].instance];
|
||||
Assertion(ssp->turret_enemy_objnum >= 0, "The turret enemy object number %d for %s on ship name %s is invalid.", ssp->turret_enemy_objnum, ssp->sub_name, shipp->ship_name);
|
||||
object *lep = &Objects[ssp->turret_enemy_objnum];
|
||||
|
||||
int best_weapon_tidx = turret_select_best_weapon(ssp, lep);
|
||||
|
||||
//This turret doesn't have any good weapons
|
||||
if (best_weapon_tidx < 0)
|
||||
return;
|
||||
|
||||
weapon_info *wip = get_turret_weapon_wip(&ssp->weapons, best_weapon_tidx);
|
||||
|
||||
float weapon_system_strength = ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS);
|
||||
|
||||
turret_ai_update_aim(&Ai_info[shipp->ai_index], &Objects[ssp->turret_enemy_objnum], ssp);
|
||||
|
||||
if ((ssp->targeted_subsys != nullptr) && !(ssp->flags[Ship::Subsystem_Flags::No_SS_targeting])) {
|
||||
vm_vec_unrotate(&enemy_point, &ssp->targeted_subsys->system_info->pnt, &Objects[ssp->turret_enemy_objnum].orient);
|
||||
vm_vec_add2(&enemy_point, &ssp->last_aim_enemy_pos);
|
||||
} else {
|
||||
if ((lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge())) {
|
||||
// the turret norm here is from the perspective of the base submodel, not the gun submodel
|
||||
model_instance_local_to_global_dir(&turret_norm, &tp->turret_norm, pm, pmi, pm->submodel[tp->subobj_num].parent, &objp->orient);
|
||||
ai_big_pick_attack_point_turret(lep, ssp, &tmp_pos, &turret_norm, &enemy_point, MIN(wip->max_speed * wip->lifetime, wip->weapon_range), tp->turret_fov);
|
||||
}
|
||||
else {
|
||||
enemy_point = ssp->last_aim_enemy_pos;
|
||||
}
|
||||
}
|
||||
|
||||
vec3d target_moving_direction = ssp->last_aim_enemy_vel;
|
||||
|
||||
//Try to guess where the enemy will be, and store that spot in predicted_enemy_pos
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Use_additive_weapon_velocity]) {
|
||||
vm_vec_scale_sub2(&target_moving_direction, &objp->phys_info.vel, wip->vel_inherit_amount);
|
||||
}
|
||||
|
||||
set_predicted_enemy_pos_turret(&tmp_target, &tmp_pos, objp, &enemy_point, &target_moving_direction, wip->max_speed, ssp->turret_time_enemy_in_range * (weapon_system_strength + 1.0f) / 2.0f);
|
||||
} else {
|
||||
tmp_target = *targetp;
|
||||
}
|
||||
|
||||
vm_vec_normalized_dir(gvec, &tmp_target, &tmp_pos);
|
||||
} else {
|
||||
//vector gun_pos2;
|
||||
//vm_vec_add(&gun_pos2, gpos, gun_pos);
|
||||
Assertion(targetp != nullptr, "The targetp parameter must not be null here!");
|
||||
vm_vec_normalized_dir(gvec, targetp, gpos);
|
||||
}
|
||||
|
||||
// per firingpoint based changes go here for turrets
|
||||
}
|
||||
|
||||
/**
|
||||
* Update turret aiming data based on max turret aim update delay
|
||||
*/
|
||||
void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss)
|
||||
void turret_ai_update_aim(const ai_info *aip, const object *En_Objp, ship_subsys *ss)
|
||||
{
|
||||
if (Missiontime >= ss->next_aim_pos_time)
|
||||
{
|
||||
@@ -1311,26 +1246,15 @@ void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rotate a turret towards an enemy.
|
||||
*
|
||||
* Some obscure model thing only John Slagel knows about.
|
||||
* Sets predicted enemy position.
|
||||
* Sets predicted enemy position. Previously done at the beginning of aifft_rotate_turret.
|
||||
* If the turret (*ss) has a subsystem targeted, the subsystem is used as the predicted point.
|
||||
*
|
||||
* @return TRUE if caller should use angles in subsequent rotations.
|
||||
*/
|
||||
int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep, vec3d *predicted_enemy_pos, vec3d *gvec)
|
||||
void aifft_update_predicted_enemy_pos(const object *objp, const ship *shipp, ship_subsys *ss, const vec3d *global_gun_pos, const vec3d *global_gun_vec, const object *lep, vec3d *predicted_enemy_pos)
|
||||
{
|
||||
int ret_val __UNUSED = 0; // to be used in future, see comment @ end of function
|
||||
auto pmi = model_get_instance(shipp->model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
if (ss->turret_enemy_objnum != -1) {
|
||||
model_subsystem *tp = ss->system_info;
|
||||
vec3d gun_pos, gun_vec, target_vel;
|
||||
//float weapon_speed;
|
||||
vec3d target_vel;
|
||||
float weapon_system_strength;
|
||||
//HACK HACK HACK -WMC
|
||||
//This should use the best weapon variable
|
||||
@@ -1339,15 +1263,13 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
|
||||
//This turret doesn't have any good weapons
|
||||
if (best_weapon_tidx < 0)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
weapon_info *wip = get_turret_weapon_wip(&ss->weapons, best_weapon_tidx);
|
||||
auto wip = get_turret_weapon_wip(&ss->weapons, best_weapon_tidx);
|
||||
|
||||
// weapon_system_strength scales time enemy in range in 0..1. So, the lower this is, the worse the aiming will be.
|
||||
weapon_system_strength = ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS);
|
||||
|
||||
ship_get_global_turret_info(objp, tp, &gun_pos, &gun_vec);
|
||||
|
||||
//Update "known" position and velocity of target. Only matters if max_aim_update_delay is set.
|
||||
turret_ai_update_aim(&Ai_info[shipp->ai_index], &Objects[ss->turret_enemy_objnum], ss);
|
||||
|
||||
@@ -1361,7 +1283,7 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
}
|
||||
} else {
|
||||
if ((lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge())) {
|
||||
ai_big_pick_attack_point_turret(lep, ss, &gun_pos, &gun_vec, &enemy_point, tp->turret_fov, MIN(wip->max_speed * wip->lifetime, wip->weapon_range));
|
||||
ai_big_pick_attack_point_turret(lep, ss, global_gun_pos, global_gun_vec, &enemy_point, tp->turret_fov, MIN(wip->max_speed * wip->lifetime, wip->weapon_range));
|
||||
} else {
|
||||
enemy_point = ss->last_aim_enemy_pos;
|
||||
}
|
||||
@@ -1374,24 +1296,13 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
vm_vec_scale_sub2(&target_vel, &objp->phys_info.vel, wip->vel_inherit_amount);
|
||||
}
|
||||
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_distant_firepoint] || Always_use_distant_firepoints) {
|
||||
//The firing point of this turret is so far away from the its center that we should consider this for firing calculations
|
||||
//This will do the enemy position prediction based on their relative position and speed to the firing point, not the turret center.
|
||||
vec3d temp;
|
||||
ship_get_global_turret_gun_info(objp, ss, &gun_pos, &temp, 1, nullptr);
|
||||
}
|
||||
|
||||
if (IS_VEC_NULL(&The_mission.gravity) || wip->gravity_const == 0.0f)
|
||||
set_predicted_enemy_pos_turret(predicted_enemy_pos, &gun_pos, objp, &enemy_point, &target_vel, wip->max_speed, ss->turret_time_enemy_in_range * (weapon_system_strength + 1.0f)/2.0f);
|
||||
set_predicted_enemy_pos_turret(predicted_enemy_pos, global_gun_pos, objp, &enemy_point, &target_vel, wip->max_speed, ss->turret_time_enemy_in_range * (weapon_system_strength + 1.0f)/2.0f);
|
||||
else {
|
||||
vec3d shoot_vec;
|
||||
if (physics_lead_ballistic_trajectory(&gun_pos, &enemy_point, &target_vel, wip->max_speed, &The_mission.gravity, &shoot_vec)) {
|
||||
*predicted_enemy_pos = gun_pos + shoot_vec * 1000.0f;
|
||||
} else {
|
||||
if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
|
||||
}
|
||||
return ret_val;
|
||||
vec3d gravity_vec = The_mission.gravity * wip->gravity_const;
|
||||
if (physics_lead_ballistic_trajectory(global_gun_pos, &enemy_point, &target_vel, wip->max_speed, &gravity_vec, &shoot_vec)) {
|
||||
*predicted_enemy_pos = *global_gun_pos + shoot_vec * 1000.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1403,36 +1314,54 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
// Add to predicted_enemy_pos value in .45 to 1.5x radius of enemy ship, so will often miss, but not by a huge amount.
|
||||
vm_vec_scale_add2(predicted_enemy_pos, &rand_vec, (1.0f - weapon_system_strength)*1.5f * lep->radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate a turret towards an enemy.
|
||||
*
|
||||
* Some obscure model thing only John Slagel knows about.
|
||||
*
|
||||
* @return TRUE if caller should use angles in subsequent rotations.
|
||||
*/
|
||||
bool aifft_rotate_turret(const object *objp, const ship *shipp, ship_subsys *ss, const vec3d *global_gun_pos, const vec3d *global_gun_vec, const vec3d *predicted_enemy_pos)
|
||||
{
|
||||
bool ret_val __UNUSED = false; // to be used in future, see comment @ end of function
|
||||
auto pmi = model_get_instance(shipp->model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
if (ss->turret_enemy_objnum != -1) {
|
||||
model_subsystem *tp = ss->system_info;
|
||||
|
||||
//Get the normalized dir between the turret and the predicted enemy position.
|
||||
//If the dot product is smaller than or equal to the turret's FOV, try and point the gun at it.
|
||||
vec3d v2e;
|
||||
vm_vec_normalized_dir(&v2e, predicted_enemy_pos, &gun_pos);
|
||||
vm_vec_normalized_dir(&v2e, predicted_enemy_pos, global_gun_pos);
|
||||
|
||||
bool in_fov;
|
||||
|
||||
in_fov = turret_fov_test(ss, gvec, &v2e);
|
||||
in_fov = turret_fov_test(ss, global_gun_vec, &v2e);
|
||||
|
||||
if (in_fov) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos);
|
||||
} else if ((tp->flags[Model::Subsystem_Flags::Turret_reset_idle]) &&(timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
|
||||
}
|
||||
} else if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, nullptr);
|
||||
}
|
||||
|
||||
// by default "ret_val" should be set to 1 for multi-part turrets, and 0 for single-part turrets
|
||||
// but we need to keep retail behavior by default, which means always returning 0 unless a special
|
||||
// by default "ret_val" should be set to true for multi-part turrets, and false for single-part turrets
|
||||
// but we need to keep retail behavior by default, which means always returning false unless a special
|
||||
// flag is used. the "ret_val" stuff is here is needed/wanted at a later date however.
|
||||
//return ret_val;
|
||||
|
||||
// return 0 by default (to preserve retail behavior) but allow for a per-subsystem option
|
||||
// return false by default (to preserve retail behavior) but allow for a per-subsystem option
|
||||
// for using the turret normals for firing
|
||||
if (ss->system_info->flags[Model::Subsystem_Flags::Fire_on_normal])
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1440,7 +1369,7 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
*
|
||||
* @return Dot product of vector from point abs_gunposp to *enemy_subsysp, if hittable
|
||||
*/
|
||||
float aifft_compute_turret_dot(object *objp, object *enemy_objp, vec3d *abs_gunposp, ship_subsys *turret_subsysp, ship_subsys *enemy_subsysp)
|
||||
float aifft_compute_turret_dot(const object *objp, const object *enemy_objp, const vec3d *abs_gunposp, const ship_subsys *turret_subsysp, const ship_subsys *enemy_subsysp)
|
||||
{
|
||||
float dot_out;
|
||||
vec3d subobj_pos, vector_out;
|
||||
@@ -1448,7 +1377,7 @@ float aifft_compute_turret_dot(object *objp, object *enemy_objp, vec3d *abs_gunp
|
||||
vm_vec_unrotate(&subobj_pos, &enemy_subsysp->system_info->pnt, &enemy_objp->orient);
|
||||
vm_vec_add2(&subobj_pos, &enemy_objp->pos);
|
||||
|
||||
if (ship_subsystem_in_sight(enemy_objp, enemy_subsysp, abs_gunposp, &subobj_pos, 1, &dot_out, &vector_out)) {
|
||||
if (ship_subsystem_in_sight(enemy_objp, enemy_subsysp, abs_gunposp, &subobj_pos, true, &dot_out, &vector_out)) {
|
||||
vec3d turret_norm;
|
||||
|
||||
model_instance_local_to_global_dir(&turret_norm, &turret_subsysp->system_info->turret_norm, Ships[objp->instance].model_instance_num, turret_subsysp->system_info->subobj_num, &objp->orient, true);
|
||||
@@ -1502,7 +1431,7 @@ DCF(mf, "Adjusts the maximum number of tries an AI may do when trying to pick a
|
||||
*
|
||||
* @return Dot product from turret to subsystem in *dot_out
|
||||
*/
|
||||
ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *enemy_objp, float *dot_out)
|
||||
ship_subsys *aifft_find_turret_subsys(const object *objp, const ship_subsys *ssp, const vec3d *global_gun_pos, const object *enemy_objp, float *dot_out)
|
||||
{
|
||||
ship *eshipp, *shipp;
|
||||
ship_info *esip;
|
||||
@@ -1519,10 +1448,6 @@ ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *en
|
||||
float best_dot = 0.0f;
|
||||
*dot_out = best_dot;
|
||||
|
||||
// Compute absolute gun position.
|
||||
vec3d abs_gun_pos;
|
||||
ship_get_global_turret_info(objp, ssp->system_info, &abs_gun_pos, nullptr);
|
||||
|
||||
// Only pick a turret to attack on large ships.
|
||||
if (!esip->is_big_or_huge())
|
||||
return best_subsysp;
|
||||
@@ -1578,7 +1503,7 @@ ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *en
|
||||
if(stride <= 0){
|
||||
stride = 1;
|
||||
}
|
||||
int offset = (int)frand_range(0.0f, (float)(aifft_list_size % stride));
|
||||
int offset = Random::next((aifft_list_size % stride) + 1); // returns an offset in [0, size % stride] inclusive
|
||||
int idx;
|
||||
float dot_fov_modifier = 0.0f;
|
||||
|
||||
@@ -1588,7 +1513,7 @@ ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *en
|
||||
}
|
||||
|
||||
for(idx=offset; idx<aifft_list_size; idx+=stride){
|
||||
dot = aifft_compute_turret_dot(objp, enemy_objp, &abs_gun_pos, ssp, aifft_list[idx]);
|
||||
dot = aifft_compute_turret_dot(objp, enemy_objp, global_gun_pos, ssp, aifft_list[idx]);
|
||||
|
||||
if ((dot - dot_fov_modifier)* aifft_rank[idx] > best_dot) {
|
||||
best_dot = (dot - dot_fov_modifier)*aifft_rank[idx];
|
||||
@@ -1603,34 +1528,17 @@ ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *en
|
||||
}
|
||||
|
||||
/**
|
||||
* @return !0 if the specified target should scan for a new target, otherwise return 0
|
||||
* @return true if the specified target should scan for a new target, otherwise return false
|
||||
*/
|
||||
int turret_should_pick_new_target(ship_subsys *turret)
|
||||
bool turret_should_pick_new_target(ship_subsys *turret)
|
||||
{
|
||||
// int target_type;
|
||||
|
||||
if ( timestamp_elapsed(turret->turret_next_enemy_check_stamp) ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
if ( turret->turret_enemy_objnum == -1 ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
target_type = Objects[turret->turret_enemy_objnum].type;
|
||||
if ( (target_type != OBJ_SHIP) && (target_type != OBJ_ASTEROID) ) {
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
|
||||
return timestamp_elapsed(turret->turret_next_enemy_check_stamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the next fire timestamp for a turret, based on weapon type and ai class
|
||||
*/
|
||||
void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsys *turret, ai_info *aip)
|
||||
void turret_set_next_fire_timestamp(int weapon_num, const weapon_info *wip, ship_subsys *turret, const ai_info *aip)
|
||||
{
|
||||
Assert(weapon_num < MAX_SHIP_WEAPONS);
|
||||
float wait = 1000.0f;
|
||||
@@ -1743,13 +1651,13 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
|
||||
/**
|
||||
* Decide if a turret should launch an aspect seeking missile
|
||||
*/
|
||||
int turret_should_fire_aspect(ship_subsys *turret, weapon_info *wip, bool in_sight)
|
||||
bool turret_should_fire_aspect(const ship_subsys *turret, const weapon_info *wip, bool in_sight)
|
||||
{
|
||||
if ( in_sight && (turret->turret_time_enemy_in_range >= MIN(wip->min_lock_time,AICODE_TURRET_MAX_TIME_IN_RANGE)) ) {
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1771,9 +1679,9 @@ 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 play_sound = true)
|
||||
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, const vec3d *orig_firing_pos, const vec3d *orig_firing_vec, const vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f, bool play_sound = true)
|
||||
{
|
||||
matrix turret_orient;
|
||||
matrix firing_orient;
|
||||
int weapon_objnum;
|
||||
ai_info *parent_aip;
|
||||
ship *parent_ship;
|
||||
@@ -1835,16 +1743,21 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (check_ok_to_fire(parent_objnum, turret->turret_enemy_objnum, wip, -1, turret)) {
|
||||
if (check_ok_to_fire(parent_objnum, turret->turret_enemy_objnum, wip, -1, orig_firing_pos)) {
|
||||
auto turret_enemy_objp = (turret->turret_enemy_objnum >= 0) ? &Objects[turret->turret_enemy_objnum] : nullptr;
|
||||
|
||||
ship_weapon* swp = &turret->weapons;
|
||||
turret->turret_last_fire_direction = *firing_vec;
|
||||
turret->turret_last_fire_direction = *orig_firing_vec;
|
||||
|
||||
if (turret->turret_inaccuracy > 0.0f)
|
||||
vm_vec_random_cone(firing_vec, firing_vec, turret->turret_inaccuracy);
|
||||
const vec3d *firing_vec = orig_firing_vec;
|
||||
vec3d firing_vec_buf;
|
||||
|
||||
vm_vector_2_matrix(&turret_orient, firing_vec, nullptr, nullptr);
|
||||
if (turret->turret_inaccuracy > 0.0f) {
|
||||
vm_vec_random_cone(&firing_vec_buf, firing_vec, turret->turret_inaccuracy);
|
||||
firing_vec = &firing_vec_buf;
|
||||
}
|
||||
|
||||
vm_vector_2_matrix(&firing_orient, firing_vec, nullptr, nullptr);
|
||||
|
||||
// grab and set some burst data before turret_set_next_fire_timestamp wipes it
|
||||
int old_burst_seed = swp->burst_seed[weapon_num];
|
||||
@@ -2023,11 +1936,15 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec3d firing_pos_buf;
|
||||
const vec3d *firing_pos = &firing_pos_buf;
|
||||
|
||||
// zookeeper - Firepoints should cycle normally between shots,
|
||||
// so we need to get the position info separately for each shot
|
||||
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, turret_pos, firing_vec, 1, nullptr);
|
||||
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, &firing_pos_buf, false, nullptr, true, nullptr);
|
||||
|
||||
weapon_objnum = weapon_create( turret_pos, &turret_orient, turret_weapon_class, parent_objnum, -1, 1, 0,0.0f, turret);
|
||||
weapon_objnum = weapon_create(firing_pos, &firing_orient, turret_weapon_class, parent_objnum, -1, 1, 0, 0.0f, turret);
|
||||
weapon_set_tracking_info(weapon_objnum, parent_objnum, turret->turret_enemy_objnum, 1, turret->targeted_subsys);
|
||||
|
||||
//nprintf(("AI", "Turret_time_enemy_in_range = %7.3f\n", ss->turret_time_enemy_in_range));
|
||||
@@ -2059,7 +1976,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
if(predicted_pos != NULL)
|
||||
{
|
||||
// pick a firing range so that it detonates properly
|
||||
flak_pick_range(objp, turret_pos, predicted_pos, ship_get_subsystem_strength(parent_ship, SUBSYSTEM_WEAPONS));
|
||||
flak_pick_range(objp, firing_pos, predicted_pos, ship_get_subsystem_strength(parent_ship, SUBSYSTEM_WEAPONS));
|
||||
|
||||
// determine what that range was
|
||||
flak_range = flak_get_range(objp);
|
||||
@@ -2072,7 +1989,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
|
||||
// do mflash if the weapon has it
|
||||
if (wip->muzzle_flash >= 0) {
|
||||
mflash_create(turret_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
|
||||
mflash_create(firing_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
|
||||
}
|
||||
|
||||
// in multiplayer (and the master), then send a turret fired packet.
|
||||
@@ -2091,7 +2008,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
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 );
|
||||
snd_play_3d( gamesnd_get_game_sound(wip->launch_snd), firing_pos, &View_position );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2123,7 +2040,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
{
|
||||
int weapon_objnum;
|
||||
matrix turret_orient;
|
||||
matrix firing_orient;
|
||||
vec3d turret_pos, turret_fvec;
|
||||
|
||||
// parent not alive, quick out.
|
||||
@@ -2136,7 +2053,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
tsi->turret->turret_next_fire_pos = tsi->weapon_num;
|
||||
|
||||
// change firing point
|
||||
ship_get_global_turret_gun_info(&Objects[tsi->parent_objnum], tsi->turret, &turret_pos, &turret_fvec, 1, NULL);
|
||||
ship_get_global_turret_gun_info(&Objects[tsi->parent_objnum], tsi->turret, &turret_pos, false, &turret_fvec, true, nullptr);
|
||||
tsi->turret->turret_next_fire_pos++;
|
||||
|
||||
//check if this really is a swarm. If not, how the hell did it get here?
|
||||
@@ -2151,11 +2068,11 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
turret_fvec = tsi->turret->turret_last_fire_direction;
|
||||
}
|
||||
|
||||
// make turret_orient from turret_fvec -- turret->turret_last_fire_direction
|
||||
vm_vector_2_matrix(&turret_orient, &turret_fvec, NULL, NULL);
|
||||
// make firing_orient from turret_fvec -- turret->turret_last_fire_direction
|
||||
vm_vector_2_matrix(&firing_orient, &turret_fvec, NULL, NULL);
|
||||
|
||||
// create weapon and homing info
|
||||
weapon_objnum = weapon_create(&turret_pos, &turret_orient, tsi->weapon_class, tsi->parent_objnum, -1, 1, 0, 0.0f, tsi->turret);
|
||||
weapon_objnum = weapon_create(&turret_pos, &firing_orient, tsi->weapon_class, tsi->parent_objnum, -1, 1, 0, 0.0f, tsi->turret);
|
||||
weapon_set_tracking_info(weapon_objnum, tsi->parent_objnum, tsi->target_objnum, 1, tsi->target_subsys);
|
||||
|
||||
// do other cool stuff if weapon is created.
|
||||
@@ -2214,7 +2131,7 @@ int Num_turrets_fired = 0;
|
||||
* all turret movement and resetting when idle
|
||||
*/
|
||||
extern int Nebula_sec_range;
|
||||
void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
void ai_turret_execute_behavior(const ship *shipp, ship_subsys *ss)
|
||||
{
|
||||
float weapon_firing_range;
|
||||
float weapon_min_range; // *Weapon minimum firing range -Et1
|
||||
@@ -2298,12 +2215,21 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
objp = &Objects[shipp->objnum];
|
||||
Assert(objp->type == OBJ_SHIP);
|
||||
|
||||
// Use the turret info for all guns, not one gun in particular.
|
||||
vec3d gvec, gpos;
|
||||
ship_get_global_turret_info(objp, tp, &gpos, &gvec);
|
||||
vec3d global_gun_pos, global_gun_vec;
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_distant_firepoint] || Always_use_distant_firepoints) {
|
||||
//The firing point of this turret is so far away from the its center that we should consider this for firing calculations
|
||||
//This will do the enemy position prediction based on their relative position and speed to the firing point, not the turret center.
|
||||
ship_get_global_turret_gun_info(objp, ss, &global_gun_pos, false, &global_gun_vec, true, nullptr);
|
||||
} else {
|
||||
// Use the turret info for all guns, not one gun in particular.
|
||||
ship_get_global_turret_info(objp, tp, &global_gun_pos, &global_gun_vec);
|
||||
}
|
||||
|
||||
// Update predicted enemy position. This used to be done in aifft_rotate_turret
|
||||
aifft_update_predicted_enemy_pos(objp, shipp, ss, &global_gun_pos, &global_gun_vec, lep, &predicted_enemy_pos);
|
||||
|
||||
// Rotate the turret even if time hasn't elapsed, since it needs to turn to face its target.
|
||||
int use_angles = aifft_rotate_turret(objp, shipp, ss, lep, &predicted_enemy_pos, &gvec);
|
||||
bool use_angles = aifft_rotate_turret(objp, shipp, ss, &global_gun_pos, &global_gun_vec, &predicted_enemy_pos);
|
||||
|
||||
// Multiplayer clients are now able to try to track their targets and also reset to their idle positions.
|
||||
// But everything after this point is turret firing, so we need to bail here.
|
||||
@@ -2327,18 +2253,20 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
float dist_to_enemy = 0.0f;
|
||||
if (lep) {
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Turrets_ignore_target_radius])
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &gpos));
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos));
|
||||
else
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &gpos) - lep->radius);
|
||||
dist_to_enemy = MAX(0, vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &global_gun_pos) - lep->radius);
|
||||
}
|
||||
|
||||
// count the number of enemies, in case we have a spawning weapon
|
||||
int num_ships_nearby = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &gpos, 1500.0f);
|
||||
int num_ships_nearby = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &global_gun_pos, 1500.0f);
|
||||
|
||||
// some flags considering there may be different weapon types on this turret
|
||||
bool we_did_non_spawning_logic = false;
|
||||
bool tentative_return = false;
|
||||
|
||||
float turret_barrel_length = -1.0f;
|
||||
|
||||
//WMC - go through all valid weapons. Fire spawns if there are any.
|
||||
int valid_weapons[MAX_SHIP_WEAPONS];
|
||||
int num_valid = 0;
|
||||
@@ -2370,7 +2298,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
if ( (wip->wi_flags[Weapon::Info_Flags::Spawn]) && !(wip->wi_flags[Weapon::Info_Flags::Smart_spawn]) )
|
||||
{
|
||||
if (( num_ships_nearby >= 3 ) || ((num_ships_nearby >= 2) && (frand() < 0.1f))) {
|
||||
turret_fire_weapon(i, ss, parent_objnum, &gpos, &ss->turret_last_fire_direction);
|
||||
turret_fire_weapon(i, ss, parent_objnum, &global_gun_pos, &ss->turret_last_fire_direction);
|
||||
} else {
|
||||
// Regardless of firing rate, don't check whether should fire for awhile.
|
||||
if (tp->flags[Model::Subsystem_Flags::Use_multiple_guns])
|
||||
@@ -2418,10 +2346,16 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
// If the barrel of this turret is long, we shouldn't try to fire if the enemy is under the gun.
|
||||
// Note that this isn't the same thing as min_range, which is unrelated to barrel length.
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_distant_firepoint] || Always_use_distant_firepoints) {
|
||||
vec3d fpoint, fvec;
|
||||
ship_get_global_turret_gun_info(objp, ss, &fpoint, &fvec, use_angles, &predicted_enemy_pos);
|
||||
auto barrel_length = vm_vec_dist(&fpoint, &gpos);
|
||||
if (dist_to_enemy < barrel_length) continue;
|
||||
if (turret_barrel_length < 0.0f) {
|
||||
if (tp->turret_gun_sobj >= 0) {
|
||||
auto pm = model_get(tp->model_num);
|
||||
auto submodel = &pm->submodel[tp->turret_gun_sobj];
|
||||
turret_barrel_length = 2 * submodel->rad;
|
||||
} else {
|
||||
turret_barrel_length = 0.0f;
|
||||
}
|
||||
}
|
||||
if (dist_to_enemy < turret_barrel_length) continue;
|
||||
}
|
||||
|
||||
// Don't try to fire beyond weapon_limit_range (or within min range)
|
||||
@@ -2539,7 +2473,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
// Maybe pick a new enemy, unless targeting has been taken over by scripting
|
||||
if ( turret_should_pick_new_target(ss) && !ss->scripting_target_override && !(ss->flags[Ship::Subsystem_Flags::Forced_target])) {
|
||||
Num_find_turret_enemy++;
|
||||
int objnum = find_turret_enemy(ss, parent_objnum, &gpos, &gvec, ss->turret_enemy_objnum);
|
||||
int objnum = find_turret_enemy(ss, parent_objnum, &global_gun_pos, &global_gun_vec, ss->turret_enemy_objnum);
|
||||
|
||||
if (objnum >= 0) {
|
||||
if (ss->turret_enemy_objnum == -1) {
|
||||
@@ -2561,7 +2495,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
float dot = 1.0f;
|
||||
lep = &Objects[ss->turret_enemy_objnum];
|
||||
if (( lep->type == OBJ_SHIP ) && !(ss->flags[Ship::Subsystem_Flags::No_SS_targeting])) {
|
||||
ss->targeted_subsys = aifft_find_turret_subsys(objp, ss, lep, &dot);
|
||||
ss->targeted_subsys = aifft_find_turret_subsys(objp, ss, &global_gun_pos, lep, &dot);
|
||||
}
|
||||
// recheck in 2-3 seconds
|
||||
ss->turret_next_enemy_check_stamp = timestamp((int)((MAX(dot, 0.5f) * The_mission.ai_profile->turret_target_recheck_time) + (The_mission.ai_profile->turret_target_recheck_time / 2.0f)));
|
||||
@@ -2602,14 +2536,15 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
return;
|
||||
}
|
||||
|
||||
if ( lep == nullptr ){
|
||||
return;
|
||||
}
|
||||
//This can't happen. See above code
|
||||
//if ( lep == nullptr ){
|
||||
// return;
|
||||
//}
|
||||
|
||||
//This can't happen. See above code
|
||||
//Assert(ss->turret_enemy_objnum != -1);
|
||||
|
||||
bool in_fov = turret_fov_test(ss, &gvec, &v2e);
|
||||
bool in_fov = turret_fov_test(ss, &global_gun_vec, &v2e);
|
||||
bool something_was_ok_to_fire = false;
|
||||
|
||||
// the only reason predicted_enemy_pos might be zero, while everything else is valid is if
|
||||
@@ -2664,13 +2599,13 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
|
||||
// We're ready to fire... now get down to specifics, like where is the
|
||||
// actual gun point and normal, not just the one for whole turret.
|
||||
ship_get_global_turret_gun_info(objp, ss, &gpos, &gvec, use_angles, &predicted_enemy_pos);
|
||||
ship_get_global_turret_gun_info(objp, ss, &global_gun_pos, false, &global_gun_vec, use_angles, &predicted_enemy_pos);
|
||||
|
||||
// Fire in the direction the turret is facing, not right at the target regardless of turret dir.
|
||||
// [Yet this retail comment precedes the calculation of vector-to-enemy...]
|
||||
vm_vec_sub(&v2e, &predicted_enemy_pos, &gpos);
|
||||
vm_vec_sub(&v2e, &predicted_enemy_pos, &global_gun_pos);
|
||||
dist_to_enemy = vm_vec_normalize(&v2e);
|
||||
float dot = vm_vec_dot(&v2e, &gvec);
|
||||
float dot = vm_vec_dot(&v2e, &global_gun_vec);
|
||||
|
||||
// (flak jitter moved to after we obtain shoot_vector below)
|
||||
|
||||
@@ -2735,7 +2670,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
// Check if turret should fire and enemy's engines are
|
||||
// in line of sight
|
||||
if (turret_should_fire_aspect(ss, wip, in_sight) &&
|
||||
ship_get_closest_subsys_in_sight(&Ships[lep->signature], SUBSYSTEM_ENGINE, &gpos))
|
||||
ship_get_closest_subsys_in_sight(&Ships[lep->signature], SUBSYSTEM_ENGINE, &global_gun_pos))
|
||||
{
|
||||
ok_to_fire = true;
|
||||
}
|
||||
@@ -2745,14 +2680,14 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
if ( ok_to_fire && (tp->flags[Model::Subsystem_Flags::Turret_hull_check]) ) {
|
||||
int model_num = Ship_info[shipp->ship_info_index].model_num;
|
||||
vec3d end;
|
||||
vm_vec_scale_add(&end, &gpos, &gvec, model_get_radius(model_num));
|
||||
vm_vec_scale_add(&end, &global_gun_pos, &global_gun_vec, model_get_radius(model_num));
|
||||
|
||||
mc_info hull_check;
|
||||
hull_check.model_instance_num = shipp->model_instance_num;
|
||||
hull_check.model_num = model_num;
|
||||
hull_check.orient = &objp->orient;
|
||||
hull_check.pos = &objp->pos;
|
||||
hull_check.p0 = &gpos;
|
||||
hull_check.p0 = &global_gun_pos;
|
||||
hull_check.p1 = &end;
|
||||
hull_check.flags = MC_CHECK_MODEL | MC_CHECK_RAY;
|
||||
|
||||
@@ -2792,7 +2727,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
// (Despite the retail comment above, retail actually fired toward the enemy; v2e = vector-to-enemy)
|
||||
vec3d shoot_vector = v2e;
|
||||
if (tp->flags[Model::Subsystem_Flags::Fire_on_normal])
|
||||
shoot_vector = gvec;
|
||||
shoot_vector = global_gun_vec;
|
||||
|
||||
// if the weapon is a flak gun, add some jitter to its aim so it fires in a "cone"
|
||||
// to make a cool visual effect and make them less lethal
|
||||
@@ -2800,7 +2735,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, 100.0f, play_sound);
|
||||
turret_fire_weapon(valid_weapons[valid_index], ss, parent_objnum, &global_gun_pos, &shoot_vector, &predicted_enemy_pos, 100.0f, play_sound);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2869,7 +2804,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
}
|
||||
}
|
||||
|
||||
bool turret_std_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
|
||||
bool turret_std_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *v2e, float size_mod)
|
||||
{
|
||||
model_subsystem *tp = ss->system_info;
|
||||
float dot = vm_vec_dot(v2e, gvec);
|
||||
@@ -2879,7 +2814,7 @@ bool turret_std_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
|
||||
return false;
|
||||
}
|
||||
|
||||
bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
|
||||
bool turret_adv_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *v2e, float size_mod)
|
||||
{
|
||||
model_subsystem *tp = ss->system_info;
|
||||
float dot = vm_vec_dot(v2e, gvec);
|
||||
@@ -2905,7 +2840,7 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
|
||||
return false;
|
||||
}
|
||||
|
||||
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
|
||||
bool turret_fov_test(const ship_subsys *ss, const vec3d *gvec, const vec3d *v2e, float size_mod)
|
||||
{
|
||||
bool in_fov = false;
|
||||
if (ss->system_info->turret_base_fov > -1.0f)
|
||||
|
||||
@@ -670,7 +670,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
|
||||
* @param file_mapped Whether to use memory-mapped file or not.
|
||||
*
|
||||
* @details Memory-mapped files will page in the animation from disk as it is needed, but performance is not as good.
|
||||
* @return Pointer to anim that is loaded if sucess, NULL if failure.
|
||||
* @return Pointer to anim that is loaded if success, NULL if failure.
|
||||
*/
|
||||
anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
|
||||
{
|
||||
|
||||
@@ -22,19 +22,19 @@ anim_instance *init_anim_instance(anim *ptr, int bpp)
|
||||
{
|
||||
anim_instance *inst;
|
||||
|
||||
Assertion(ptr, "Bad pointer in init_anim_instance(), please report to the SCP!");
|
||||
if (!ptr) {
|
||||
Int3();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( ptr->flags & ANF_STREAMED ) {
|
||||
Assertion(ptr->file_offset > -1, "Bad file offset of %d in init_anim_instance(), please report to the SCP!", ptr->file_offset);
|
||||
if ( ptr->file_offset < 0 ) {
|
||||
Int3();
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
Assertion(ptr->data, "Bad data in init_anim_instance(), please report to the SCP!");
|
||||
if ( !ptr->data ) {
|
||||
Int3();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-11
@@ -401,12 +401,12 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
vec3d rotvel;
|
||||
if ( Game_mode & GM_NORMAL ) {
|
||||
vm_vec_rand_vec_quick(&rotvel);
|
||||
vm_vec_scale(&rotvel, frand()/4.0f + 0.1f);
|
||||
vm_vec_scale(&rotvel, asip->rotational_vel_multiplier * (frand()/4.0f + 0.1f));
|
||||
objp->phys_info.rotvel = rotvel;
|
||||
vm_vec_rand_vec_quick(&objp->phys_info.vel);
|
||||
} else {
|
||||
static_randvec( rand_base++, &rotvel );
|
||||
vm_vec_scale(&rotvel, static_randf(rand_base++)/4.0f + 0.1f);
|
||||
vm_vec_scale(&rotvel, asip->rotational_vel_multiplier * (static_randf(rand_base++)/4.0f + 0.1f));
|
||||
objp->phys_info.rotvel = rotvel;
|
||||
static_randvec( rand_base++, &objp->phys_info.vel );
|
||||
}
|
||||
@@ -1030,7 +1030,7 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
|
||||
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 (dot > cos(g3_get_hfov(Proj_fov))) {
|
||||
if (range_override) {
|
||||
return true;
|
||||
} else {
|
||||
@@ -1049,6 +1049,7 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
|
||||
*/
|
||||
static void maybe_throw_asteroid()
|
||||
{
|
||||
Assertion(Asteroid_field.num_used_field_debris_types > 0, "maybe_throw_asteroid() called while num_used_field_debris_types was 0; this should never happen, get a coder!");
|
||||
|
||||
for (asteroid_target& target : Asteroid_targets) {
|
||||
if (!timestamp_elapsed(target.throw_stamp))
|
||||
@@ -1332,10 +1333,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
mc.flags = (MC_CHECK_MODEL | MC_CHECK_SPHERELINE);
|
||||
|
||||
// copy important data
|
||||
int copy_flags = mc.flags; // make a copy of start end positions of sphere in big ship RF
|
||||
vec3d copy_p0, copy_p1;
|
||||
copy_p0 = *mc.p0;
|
||||
copy_p1 = *mc.p1;
|
||||
int orig_flags = mc.flags; // make a copy of start end positions of sphere in big ship RF
|
||||
vec3d orig_p0 = *mc.p0;
|
||||
vec3d orig_p1 = *mc.p1;
|
||||
|
||||
// first test against the sphere - if this fails then don't do any submodel tests
|
||||
mc.flags = MC_ONLY_SPHERE | MC_CHECK_SPHERELINE;
|
||||
@@ -1361,7 +1361,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
}
|
||||
|
||||
// Only check single submodel now, since children of moving submodels are handled as moving as well
|
||||
mc.flags = copy_flags | MC_SUBMODEL;
|
||||
mc.flags = orig_flags | MC_SUBMODEL;
|
||||
|
||||
// check each submodel in turn
|
||||
for (auto submodel: submodel_vector) {
|
||||
@@ -1406,9 +1406,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
}
|
||||
|
||||
// Now complete base model collision checks that do not take into account rotating submodels.
|
||||
mc.flags = copy_flags;
|
||||
*mc.p0 = copy_p0;
|
||||
*mc.p1 = copy_p1;
|
||||
mc.flags = orig_flags;
|
||||
mc.p0 = &orig_p0;
|
||||
mc.p1 = &orig_p1;
|
||||
mc.orient = &heavy_obj->orient;
|
||||
|
||||
// usual ship_ship collision test
|
||||
@@ -2239,6 +2239,10 @@ static void asteroid_parse_section()
|
||||
stuff_float(&asteroid_p->max_speed);
|
||||
}
|
||||
|
||||
if (optional_string("$Rotational Velocity Multiplier:")) {
|
||||
stuff_float(&asteroid_p->rotational_vel_multiplier);
|
||||
}
|
||||
|
||||
if(optional_string("$Damage Type:")) {
|
||||
char buf[NAME_LENGTH];
|
||||
stuff_string(buf, F_NAME, NAME_LENGTH);
|
||||
@@ -2581,6 +2585,11 @@ void asteroid_frame()
|
||||
return;
|
||||
}
|
||||
|
||||
// If no asteroid types are defined for the field, abort.
|
||||
if (Asteroid_field.num_used_field_debris_types <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If there are no explicit targets, fall back to default retail targeting behavior
|
||||
if (Asteroid_field.target_names.empty()) {
|
||||
int objnum = set_asteroid_throw_objnum();
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
int num_detail_levels; // number of detail levels for this ship
|
||||
int detail_distance[MAX_ASTEROID_DETAIL_LEVELS]; // distance to change detail levels at
|
||||
float max_speed; // cap on speed for asteroid
|
||||
float rotational_vel_multiplier; // rotational velocity multiplier for asteroid --wookieejedi
|
||||
int damage_type_idx; //Damage type of the asteroid
|
||||
int damage_type_idx_sav; // stored value from table used to reset damage_type_idx
|
||||
float inner_rad; // radius within which maximum area effect damage is applied
|
||||
@@ -80,7 +81,8 @@ public:
|
||||
float gravity_const; // multiplier for mission gravity
|
||||
|
||||
asteroid_info( )
|
||||
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0), damage_type_idx(0),
|
||||
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0),
|
||||
rotational_vel_multiplier(1), damage_type_idx(0),
|
||||
damage_type_idx_sav( -1 ), inner_rad( 0 ), outer_rad( 0 ),
|
||||
damage( 0 ), blast( 0 ), initial_asteroid_strength( 0 ),
|
||||
fireball_radius_multiplier( -1 ), spawn_weight( 1 ), gravity_const( 0 )
|
||||
|
||||
@@ -869,7 +869,7 @@ void EndAutoPilot()
|
||||
Assert( CurrentNav >= 0 );
|
||||
|
||||
int goal = 0;
|
||||
char *goal_name = NULL;
|
||||
const char *goal_name = NULL;
|
||||
|
||||
if (Navs[CurrentNav].flags & NP_WAYPOINT)
|
||||
{
|
||||
@@ -1023,7 +1023,7 @@ void nav_warp(bool prewarp=false)
|
||||
|
||||
// retime collision pairs
|
||||
if (Objects[Ships[i].objnum].flags[Object::Object_Flags::Collides])
|
||||
obj_collide_retime_cached_pairs(&Objects[Ships[i].objnum]);
|
||||
obj_collide_obj_cache_stale(&Objects[Ships[i].objnum]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,6 +425,7 @@ DCF(bm_used, "Shows BmpMan Slot Usage") {
|
||||
|
||||
SCP_stringstream text;
|
||||
text << "BmpMan Used Slots\n";
|
||||
text << " " << std::dec << std::setw(4) << std::setfill('0') << none << ", NONE\n";
|
||||
text << " " << std::dec << std::setw(4) << std::setfill('0') << pcx << ", PCX\n";
|
||||
text << " " << std::dec << std::setw(4) << std::setfill('0') << user << ", User\n";
|
||||
text << " " << std::dec << std::setw(4) << std::setfill('0') << tga << ", TGA\n";
|
||||
@@ -598,7 +599,7 @@ int bm_create_3d(int bpp, int w, int h, int d, void* data) {
|
||||
|
||||
// make sure that we have valid data
|
||||
if (data == nullptr) {
|
||||
UNREACHABLE("No valid data recieved for 3D Bitmap creation!");
|
||||
UNREACHABLE("No valid data received for 3D Bitmap creation!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -2602,7 +2603,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);
|
||||
|
||||
+106
-34
@@ -14,8 +14,8 @@
|
||||
#include "ship/ship.h" //compute_slew_matrix
|
||||
|
||||
//*************************IMPORTANT GLOBALS*************************
|
||||
float VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
|
||||
float COCKPIT_ZOOM_DEFAULT = 0.75f;
|
||||
fov_t VIEWER_ZOOM_DEFAULT = DEFAULT_FOV;
|
||||
fov_t COCKPIT_ZOOM_DEFAULT = DEFAULT_FOV;
|
||||
float Sexp_fov = 0.0f;
|
||||
warp_camera Warp_camera;
|
||||
|
||||
@@ -27,6 +27,36 @@ SCP_vector<camera*> Cameras;
|
||||
camid Current_camera;
|
||||
camid Main_camera;
|
||||
|
||||
asymmetric_fov operator* (const asymmetric_fov& left, const float& right) {
|
||||
return asymmetric_fov{ left.left * right, left.right * right, left.up * right, left.down * right };
|
||||
}
|
||||
asymmetric_fov operator+ (const asymmetric_fov& left, const float& right) {
|
||||
float ar = (left.up - left.down) / (left.right - left.left);
|
||||
return asymmetric_fov{ left.left - right * 0.5f, left.right + right * 0.5f, left.up + right * 0.5f * ar, left.down - right * 0.5f * ar };
|
||||
}
|
||||
asymmetric_fov operator- (const asymmetric_fov& left, const float& right) {
|
||||
float ar = (left.up - left.down) / (left.right - left.left);
|
||||
return asymmetric_fov{ left.left + right * 0.5f, left.right - right * 0.5f, left.up - right * 0.5f * ar, left.down + right * 0.5f * ar };
|
||||
}
|
||||
|
||||
#define APPLY_TO_FOV_T(op, name) \
|
||||
struct apply_##name##_to_fov { \
|
||||
float r; \
|
||||
template<typename T> \
|
||||
fov_t operator()(const T& l) { \
|
||||
return fov_t(l op r); \
|
||||
} \
|
||||
}; \
|
||||
fov_t operator op (const fov_t& zoom, const float& scale) { \
|
||||
return mpark::visit(apply_##name##_to_fov{scale}, zoom); \
|
||||
}
|
||||
APPLY_TO_FOV_T(*, mul)
|
||||
APPLY_TO_FOV_T(+, add)
|
||||
APPLY_TO_FOV_T(-, sub)
|
||||
|
||||
// Used to set the default value for in-game options
|
||||
static constexpr float fov_default = DEFAULT_FOV;
|
||||
|
||||
static SCP_string fov_display(float val)
|
||||
{
|
||||
auto degrees = fl_degrees(val);
|
||||
@@ -34,15 +64,57 @@ static SCP_string fov_display(float val)
|
||||
sprintf(out, u8"%.1f\u00B0", degrees);
|
||||
return out;
|
||||
}
|
||||
auto FovOption = options::OptionBuilder<float>("Graphics.FOV", "Field Of View", "The vertical field of view.")
|
||||
.category("Graphics")
|
||||
.range(0.436332f, 1.5708f)
|
||||
.bind_to(&VIEWER_ZOOM_DEFAULT)
|
||||
.display(fov_display)
|
||||
.default_val(0.75f)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(60)
|
||||
.finish();
|
||||
auto FovOption = options::OptionBuilder<float>("Graphics.FOV",
|
||||
std::pair<const char*, int>{"Field Of View", 1703},
|
||||
std::pair<const char*, int>{"The vertical field of view", 1704})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.range(0.436332f, 1.5708f)
|
||||
.change_listener([](const float& val, bool) {
|
||||
VIEWER_ZOOM_DEFAULT = val;
|
||||
return true;
|
||||
})
|
||||
.display(fov_display)
|
||||
.default_val(fov_default)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(60)
|
||||
.finish();
|
||||
|
||||
bool Use_cockpit_fov = false;
|
||||
|
||||
auto CockpitFOVToggleOption = options::OptionBuilder<bool>("Graphics.CockpitFOVToggle",
|
||||
std::pair<const char*, int>{"Cockpit FOV Toggle", 1838},
|
||||
std::pair<const char*, int>{"Whether or not to use a different FOV for cockpit rendering from normal rendering", 1839})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.default_val(false)
|
||||
.change_listener([](bool val, bool) {
|
||||
if (!val) {
|
||||
COCKPIT_ZOOM_DEFAULT = VIEWER_ZOOM_DEFAULT;
|
||||
}
|
||||
return true; // This option will always persist so we never return false
|
||||
})
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Use_cockpit_fov)
|
||||
.importance(61)
|
||||
.finish();
|
||||
|
||||
auto CockpitFovOption = options::OptionBuilder<float>("Graphics.CockpitFOV",
|
||||
std::pair<const char*, int>{"Cockpit Field Of View", 1840},
|
||||
std::pair<const char*, int>{"The vertical field of view for cockpit rendering. Only works if cockpits are active and cockpit FOV toggle is turned on.", 1841})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.range(0.436332f, 1.5708f)
|
||||
.change_listener([](const float& val, bool) {
|
||||
if (Use_cockpit_fov){
|
||||
COCKPIT_ZOOM_DEFAULT = val;
|
||||
} else {
|
||||
COCKPIT_ZOOM_DEFAULT = VIEWER_ZOOM_DEFAULT;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.display(fov_display)
|
||||
.default_val(fov_default)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(62)
|
||||
.finish();
|
||||
|
||||
//*************************CLASS: camera*************************
|
||||
//This is where the camera class begins! :D
|
||||
@@ -85,7 +157,7 @@ void camera::reset()
|
||||
func_custom_orientation = NULL;
|
||||
|
||||
fov.clear();
|
||||
fov.set(VIEWER_ZOOM_DEFAULT);
|
||||
fov.set(g3_get_hfov(VIEWER_ZOOM_DEFAULT));
|
||||
|
||||
pos_x.clear();
|
||||
pos_y.clear();
|
||||
@@ -104,7 +176,7 @@ void camera::set_name(const char *in_name)
|
||||
strncpy(name, in_name, NAME_LENGTH-1);
|
||||
}
|
||||
|
||||
void camera::set_fov(float in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
|
||||
void camera::set_fov(fov_t in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
|
||||
{
|
||||
if(in_fov_time == 0.0f && in_fov_acceleration_time == 0.0f && in_fov_deceleration_time == 0.0f)
|
||||
{
|
||||
@@ -114,26 +186,23 @@ void camera::set_fov(float in_fov, float in_fov_time, float in_fov_acceleration_
|
||||
}
|
||||
|
||||
flags &= ~CAM_STATIONARY_FOV;
|
||||
if(in_fov <= 0.0f)
|
||||
if(g3_get_hfov(in_fov) <= 0.0f)
|
||||
{
|
||||
fov.setVD(in_fov_time, in_fov_acceleration_time, 0.0f);
|
||||
}
|
||||
|
||||
fov.setAVD(in_fov, in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
|
||||
fov.setAVD(g3_get_hfov(in_fov), in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
|
||||
}
|
||||
|
||||
void camera::set_object_host(object *objp, int n_object_host_submodel)
|
||||
{
|
||||
if(objp == NULL)
|
||||
object_host = object_h();
|
||||
|
||||
object_host = object_h(objp);
|
||||
object_host_submodel = n_object_host_submodel;
|
||||
set_custom_position_function(NULL);
|
||||
set_custom_orientation_function(NULL);
|
||||
if(n_object_host_submodel > 0)
|
||||
{
|
||||
if(objp->type == OBJ_SHIP)
|
||||
if(objp != nullptr && objp->type == OBJ_SHIP)
|
||||
{
|
||||
ship_subsys* ssp = GET_FIRST(&Ships[objp->instance].subsys_list);
|
||||
while ( ssp != END_OF_LIST( &Ships[objp->instance].subsys_list ) )
|
||||
@@ -272,7 +341,7 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
|
||||
|
||||
// if we have a host, we need the difference between the camera's current orient and the orient we want
|
||||
// if not, we will later set the absolute orientation, rather than the orientation relative to the host
|
||||
if (object_host.IsValid())
|
||||
if (object_host.isValid())
|
||||
{
|
||||
vm_transpose(orient);
|
||||
temp_matrix = temp_matrix * *orient;
|
||||
@@ -295,7 +364,7 @@ void camera::do_frame(float /*in_frametime*/)
|
||||
|
||||
object *camera::get_object_host()
|
||||
{
|
||||
if(object_host.IsValid())
|
||||
if(object_host.isValid())
|
||||
return object_host.objp;
|
||||
else
|
||||
return NULL;
|
||||
@@ -308,7 +377,7 @@ int camera::get_object_host_submodel()
|
||||
|
||||
object *camera::get_object_target()
|
||||
{
|
||||
if(object_target.IsValid())
|
||||
if(object_target.isValid())
|
||||
return object_target.objp;
|
||||
else
|
||||
return NULL;
|
||||
@@ -319,11 +388,14 @@ int camera::get_object_target_submodel()
|
||||
return object_target_submodel;
|
||||
}
|
||||
|
||||
float camera::get_fov()
|
||||
fov_t camera::get_fov()
|
||||
{
|
||||
if(!(flags & CAM_STATIONARY_FOV))
|
||||
{
|
||||
fov.get(&c_fov, NULL);
|
||||
float fov_now;
|
||||
fov.get(&fov_now, nullptr);
|
||||
return fov_now;
|
||||
//TODO enable moving asymmetric fov
|
||||
}
|
||||
|
||||
return c_fov;
|
||||
@@ -341,7 +413,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
bool use_host_orient = false;
|
||||
|
||||
//POSITION
|
||||
if(!(flags & CAM_STATIONARY_POS) || object_host.IsValid())
|
||||
if(!(flags & CAM_STATIONARY_POS) || object_host.isValid())
|
||||
{
|
||||
c_pos = vmd_zero_vector;
|
||||
|
||||
@@ -350,7 +422,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
pos_y.get(&pt.xyz.y, NULL);
|
||||
pos_z.get(&pt.xyz.z, NULL);
|
||||
|
||||
if(object_host.IsValid())
|
||||
if(object_host.isValid())
|
||||
{
|
||||
object *objp = object_host.objp;
|
||||
int model_num = object_get_model(objp);
|
||||
@@ -412,9 +484,9 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
if(orientation != NULL)
|
||||
{
|
||||
bool target_set = false;
|
||||
if(!(flags & CAM_STATIONARY_ORI) || object_target.IsValid() || object_host.IsValid())
|
||||
if(!(flags & CAM_STATIONARY_ORI) || object_target.isValid() || object_host.isValid())
|
||||
{
|
||||
if(object_target.IsValid())
|
||||
if(object_target.isValid())
|
||||
{
|
||||
object *target_objp = object_target.objp;
|
||||
int model_num = object_get_model(target_objp);
|
||||
@@ -449,7 +521,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
vm_vector_2_matrix(&c_ori, &targetvec, NULL, NULL);
|
||||
target_set = true;
|
||||
}
|
||||
else if(object_host.IsValid())
|
||||
else if(object_host.isValid())
|
||||
{
|
||||
if(eyep)
|
||||
{
|
||||
@@ -722,7 +794,7 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
|
||||
//Get text size
|
||||
for(int i = 0; i < num_text_lines; i++)
|
||||
{
|
||||
gr_get_string_size(&w, &h, text_line_ptrs[i], text_line_lens[i]);
|
||||
gr_get_string_size(&w, &h, text_line_ptrs[i], static_cast<size_t>(text_line_lens[i]));
|
||||
|
||||
if(w > tw)
|
||||
tw = w;
|
||||
@@ -979,7 +1051,7 @@ int camid::getSignature()
|
||||
return sig;
|
||||
}
|
||||
|
||||
bool camid::isValid()
|
||||
bool camid::isValid() const
|
||||
{
|
||||
if(idx >= Cameras.size())
|
||||
return false;
|
||||
@@ -1171,7 +1243,7 @@ vec3d normal_cache;
|
||||
void get_turret_cam_pos(camera *cam, vec3d *pos)
|
||||
{
|
||||
object_h obj(cam->get_object_host());
|
||||
if(!obj.IsValid())
|
||||
if(!obj.isValid())
|
||||
return;
|
||||
ship* shipp = &Ships[cam->get_object_host()->instance];
|
||||
ship_subsys* ssp = GET_FIRST(&shipp->subsys_list);
|
||||
@@ -1179,7 +1251,7 @@ void get_turret_cam_pos(camera *cam, vec3d *pos)
|
||||
{
|
||||
if(ssp->system_info->subobj_num == cam->get_object_host_submodel())
|
||||
{
|
||||
ship_get_global_turret_gun_info(cam->get_object_host(), ssp, pos, &normal_cache, 1, NULL);
|
||||
ship_get_global_turret_gun_info(cam->get_object_host(), ssp, pos, true, &normal_cache, true, nullptr);
|
||||
vec3d offset = vmd_zero_vector;
|
||||
offset.xyz.x = 0.0001f;
|
||||
vm_vec_add2(pos, &offset); // prevent beam turrets from crashing with a nullvec
|
||||
@@ -1192,7 +1264,7 @@ void get_turret_cam_pos(camera *cam, vec3d *pos)
|
||||
void get_turret_cam_orient(camera *cam, matrix *ori)
|
||||
{
|
||||
object_h obj(cam->get_object_host());
|
||||
if(!obj.IsValid())
|
||||
if(!obj.isValid())
|
||||
return;
|
||||
vm_vector_2_matrix(ori, &normal_cache, vm_vec_same(&normal_cache, &cam->get_object_host()->orient.vec.uvec)?NULL:&cam->get_object_host()->orient.vec.uvec, NULL);
|
||||
}
|
||||
|
||||
+20
-5
@@ -10,6 +10,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <mpark/variant.hpp>
|
||||
|
||||
#define CAM_STATIONARY_FOV (1<<0)
|
||||
#define CAM_STATIONARY_ORI (1<<1)
|
||||
#define CAM_STATIONARY_POS (1<<2)
|
||||
@@ -18,6 +20,19 @@
|
||||
#define EXTERN_CAM_BBOX_CONSTANT_PADDING 5.0f
|
||||
#define EXTERN_CAM_BBOX_MULTIPLIER_PADDING 1.5f
|
||||
|
||||
#define DEFAULT_FOV 0.75f;
|
||||
|
||||
struct asymmetric_fov {
|
||||
float left, right, up, down;
|
||||
friend asymmetric_fov operator* (const asymmetric_fov&, const float&);
|
||||
friend asymmetric_fov operator+ (const asymmetric_fov&, const float&);
|
||||
friend asymmetric_fov operator- (const asymmetric_fov&, const float&);
|
||||
};
|
||||
using fov_t = mpark::variant<float, asymmetric_fov>;
|
||||
fov_t operator* (const fov_t&, const float&);
|
||||
fov_t operator+ (const fov_t&, const float&);
|
||||
fov_t operator- (const fov_t&, const float&);
|
||||
|
||||
class camera
|
||||
{
|
||||
protected:
|
||||
@@ -41,7 +56,7 @@ protected:
|
||||
avd_movement ori[9];
|
||||
|
||||
//Cache stuff
|
||||
float c_fov;
|
||||
fov_t c_fov;
|
||||
vec3d c_pos;
|
||||
matrix c_ori;
|
||||
public:
|
||||
@@ -59,7 +74,7 @@ public:
|
||||
void set_custom_position_function(void (*n_func_custom_position)(camera *cam, vec3d *pos));
|
||||
void set_custom_orientation_function(void (*n_func_custom_orientation)(camera *cam, matrix *ori));
|
||||
|
||||
void set_fov(float in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
|
||||
void set_fov(fov_t in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
|
||||
|
||||
void set_position(vec3d *in_position = NULL, float in_translation_time = 0.0f, float in_translation_acceleration_time = 0.0f, float in_translation_deceleration_time = 0.0f, float in_end_velocity = 0.0f);
|
||||
|
||||
@@ -74,7 +89,7 @@ public:
|
||||
int get_object_host_submodel();
|
||||
object *get_object_target();
|
||||
int get_object_target_submodel();
|
||||
float get_fov();
|
||||
fov_t get_fov();
|
||||
void get_info(vec3d *position, matrix *orientation, bool apply_camera_orientation = true);
|
||||
|
||||
//Is
|
||||
@@ -155,8 +170,8 @@ public:
|
||||
|
||||
//Some global stuff
|
||||
extern SCP_vector<subtitle> Subtitles;
|
||||
extern float VIEWER_ZOOM_DEFAULT;
|
||||
extern float COCKPIT_ZOOM_DEFAULT;
|
||||
extern fov_t VIEWER_ZOOM_DEFAULT;
|
||||
extern fov_t COCKPIT_ZOOM_DEFAULT;
|
||||
extern float Sexp_fov;
|
||||
|
||||
//Helpful functions
|
||||
|
||||
+20
-18
@@ -91,12 +91,10 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#define CFILE_STACK_MAX 8
|
||||
|
||||
int cfile_inited = 0;
|
||||
static int Cfile_stack_pos = 0;
|
||||
|
||||
static char Cfile_stack[CFILE_STACK_MAX][CFILE_ROOT_DIRECTORY_LEN];
|
||||
static SCP_vector<SCP_string> Cfile_stack;
|
||||
|
||||
std::array<CFILE, MAX_CFILE_BLOCKS> Cfile_block_list;
|
||||
|
||||
@@ -330,17 +328,16 @@ int cfile_push_chdir(int type)
|
||||
|
||||
_getcwd(OriginalDirectory, CFILE_ROOT_DIRECTORY_LEN - 1);
|
||||
|
||||
Assert(Cfile_stack_pos < CFILE_STACK_MAX);
|
||||
|
||||
if (Cfile_stack_pos >= CFILE_STACK_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy_s(Cfile_stack[Cfile_stack_pos++], OriginalDirectory);
|
||||
|
||||
cf_create_default_path_string(dir, type, NULL);
|
||||
|
||||
return _cfile_chdir(dir.c_str(), OriginalDirectory);
|
||||
int rc = _cfile_chdir(dir.c_str(), OriginalDirectory);
|
||||
|
||||
// if success then push the original directory on to the stack
|
||||
if (rc == 0) {
|
||||
Cfile_stack.push_back(OriginalDirectory);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,13 +360,16 @@ int cfile_chdir(const char *dir)
|
||||
|
||||
int cfile_pop_dir()
|
||||
{
|
||||
Assert(Cfile_stack_pos);
|
||||
|
||||
if ( !Cfile_stack_pos )
|
||||
if (Cfile_stack.empty())
|
||||
return -1;
|
||||
|
||||
Cfile_stack_pos--;
|
||||
return cfile_chdir(Cfile_stack[Cfile_stack_pos]);
|
||||
int rc = cfile_chdir(Cfile_stack.back().c_str());
|
||||
|
||||
Assertion(rc == 0, "Failed to chdir() to previous directory (%s)!", Cfile_stack.back().c_str());
|
||||
|
||||
Cfile_stack.pop_back();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// flush (delete all files in) the passed directory (by type), return the # of files deleted
|
||||
@@ -438,7 +438,7 @@ int cfile_flush_dir(int dir_type)
|
||||
// filename = name of filename or filepath to process
|
||||
// ext = extension to add. Must start with the period
|
||||
// Returns: new filename or filepath with extension.
|
||||
char *cf_add_ext(const char *filename, const char *ext)
|
||||
const char *cf_add_ext(const char *filename, const char *ext)
|
||||
{
|
||||
static char path[MAX_PATH_LEN];
|
||||
|
||||
@@ -681,6 +681,8 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
} else {
|
||||
// Path type given?
|
||||
Assert( dir_type != CF_TYPE_ANY );
|
||||
if (dir_type == CF_TYPE_ANY)
|
||||
return NULL;
|
||||
|
||||
// Create the directory if necessary
|
||||
cf_create_directory(dir_type, location_flags);
|
||||
|
||||
+1
-1
@@ -171,7 +171,7 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
|
||||
void cfile_close();
|
||||
|
||||
// add an extension to a filename if it doesn't already have it
|
||||
char *cf_add_ext(const char *filename, const char *ext);
|
||||
const char *cf_add_ext(const char *filename, const char *ext);
|
||||
|
||||
// return filename of a CFILE you called cfopen() successfully on.
|
||||
const char *cf_get_filename(const CFILE *cfile);
|
||||
|
||||
@@ -1172,7 +1172,7 @@ void cf_build_file_list()
|
||||
}
|
||||
|
||||
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());
|
||||
SIZE_T_ARG " file(s) detected, including:\n%s", count, shadowed.c_str());
|
||||
}
|
||||
|
||||
critical_shadowed.clear();
|
||||
|
||||
@@ -82,7 +82,7 @@ void SpawnShipCheat::runCheat() {
|
||||
if (ptr->system_info->type == SUBSYSTEM_TURRET)
|
||||
{
|
||||
ptr->weapons.flags.set(Ship::Weapon_Flags::Beam_Free);
|
||||
ptr->turret_next_fire_stamp = timestamp((int)frand_range(50.0f, 4000.0f));
|
||||
ptr->turret_next_fire_stamp = timestamp(Random::next(50, 4000));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+160
-73
@@ -15,6 +15,7 @@
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "globalincs/version.h"
|
||||
#include "graphics/openxr.h"
|
||||
#include "graphics/shadows.h"
|
||||
#include "hud/hudconfig.h"
|
||||
#include "io/joy.h"
|
||||
@@ -39,6 +40,7 @@
|
||||
#ifdef SCP_UNIX
|
||||
#include "osapi/osapi.h"
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
@@ -188,6 +190,7 @@ Flag exe_params[] =
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-window", "Run in window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-window", },
|
||||
{ "-fullscreen_window", "Run in fullscreen window", false, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
|
||||
{ "-capture_mouse", "Capture the mouse within the window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-capture_mouse", },
|
||||
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
|
||||
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
|
||||
{ "-nomotiondebris", "Disable motion debris", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
|
||||
@@ -195,6 +198,8 @@ Flag exe_params[] =
|
||||
{ "-warp_flash", "Enable flash upon warp", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-warp_flash", },
|
||||
{ "-no_ap_interrupt", "Disable interrupting autopilot", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ap_interrupt", },
|
||||
{ "-no_screenshake", "Disable screen shaking", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_screenshake", },
|
||||
{ "-vr", "Enable Virtual Reality Mode", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-vr", },
|
||||
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
|
||||
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-nosound", "Disable all sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nosound", },
|
||||
@@ -218,6 +223,7 @@ Flag exe_params[] =
|
||||
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-no_set_gamma", "Disable setting of gamma", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_set_gamma", },
|
||||
{ "-no_ingame_options", "Disable using ingame options", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ingame_options", },
|
||||
{ "-nomovies", "Disable video playback", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomovies", },
|
||||
{ "-noparseerrors", "Disable parsing errors", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noparseerrors", },
|
||||
{ "-loadallweps", "Load all weapons, even those not used", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-loadallweps", },
|
||||
@@ -263,7 +269,6 @@ Flag exe_params[] =
|
||||
{ "-verify_vps", "Spew VP CRCs to vp_crcs.txt", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-verify_vps", },
|
||||
{ "-reparse_mainhall", "Reparse mainhall.tbl when loading halls", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-reparse_mainhall", },
|
||||
{ "-noninteractive", "Disables interactive dialogs", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noninteractive", },
|
||||
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
|
||||
{ "-benchmark_mode", "Puts the game into benchmark mode", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-benchmark_mode", },
|
||||
{ "-profile_frame_time","Profile frame time", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_time", },
|
||||
{ "-profile_write_file", "Write profiling information to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_write_file", },
|
||||
@@ -406,7 +411,9 @@ cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3
|
||||
cmdline_parm use_warp_flash("-warp_flash", nullptr, AT_NONE); // Cmdline_warp_flash
|
||||
cmdline_parm allow_autpilot_interrupt("-no_ap_interrupt", nullptr, AT_NONE);
|
||||
cmdline_parm stretch_menu("-stretch_menu", nullptr, AT_NONE); // Cmdline_stretch_menu
|
||||
cmdline_parm capture_mouse("-capture_mouse", nullptr, AT_NONE); // Cmdline_capture_mouse
|
||||
cmdline_parm no_screenshake("-no_screenshake", nullptr, AT_NONE); // Cmdline_no_screenshake
|
||||
cmdline_parm vr("-vr", nullptr, AT_NONE);
|
||||
cmdline_parm deadzone("-deadzone",
|
||||
"Sets the joystick deadzone. Integer value from 0 to 100 as a percentage of the joystick's range (100% would make the stick do nothing). Disables deadzone slider in the in-game Options menu.", AT_INT); //Cmdline_deadzone
|
||||
|
||||
@@ -414,8 +421,10 @@ int Cmdline_ship_choice_3d = 0;
|
||||
int Cmdline_weapon_choice_3d = 0;
|
||||
int Cmdline_autopilot_interruptable = 1;
|
||||
int Cmdline_stretch_menu = 0;
|
||||
bool Cmdline_capture_mouse = false;
|
||||
int Cmdline_no_screenshake = 0;
|
||||
int Cmdline_deadzone = -1;
|
||||
bool Cmdline_enable_vr = false;
|
||||
|
||||
// Audio related
|
||||
cmdline_parm voice_recognition_arg("-voicer", NULL, AT_NONE); // Cmdline_voice_recognition
|
||||
@@ -453,6 +462,7 @@ SCP_string Cmdline_lang;
|
||||
cmdline_parm loadallweapons_arg("-loadallweps", NULL, AT_NONE); // Cmdline_load_all_weapons
|
||||
cmdline_parm nomovies_arg("-nomovies", NULL, AT_NONE); // Cmdline_nomovies -- Allows video streaming
|
||||
cmdline_parm no_set_gamma_arg("-no_set_gamma", NULL, AT_NONE); // Cmdline_no_set_gamma
|
||||
cmdline_parm no_ingame_options_arg("-no_ingame_options", NULL, AT_NONE); // Cmdline_no_ingame_options
|
||||
cmdline_parm no_fbo_arg("-disable_fbo", NULL, AT_NONE); // Cmdline_no_fbo
|
||||
cmdline_parm no_pbo_arg("-disable_pbo", NULL, AT_NONE); // Cmdline_no_pbo
|
||||
cmdline_parm mipmap_arg("-mipmap", NULL, AT_NONE); // Cmdline_mipmap
|
||||
@@ -476,6 +486,7 @@ cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
|
||||
int Cmdline_load_all_weapons = 0;
|
||||
int Cmdline_nomovies = 0;
|
||||
int Cmdline_no_set_gamma = 0;
|
||||
bool Cmdline_no_ingame_options = false;
|
||||
int Cmdline_no_fbo = 0;
|
||||
int Cmdline_no_pbo = 0;
|
||||
int Cmdline_ati_color_swap = 0;
|
||||
@@ -510,7 +521,9 @@ cmdline_parm stats_arg("-stats", NULL, AT_NONE); // Cmdline_show_stats
|
||||
cmdline_parm save_render_targets_arg("-save_render_target", NULL, AT_NONE); // Cmdline_save_render_targets
|
||||
cmdline_parm window_arg("-window", NULL, AT_NONE); // Cmdline_window
|
||||
cmdline_parm fullscreen_window_arg("-fullscreen_window", "Fullscreen/borderless window (Windows only)", AT_NONE);
|
||||
cmdline_parm res_arg("-res", "Resolution, formatted like 1600x900", AT_STRING);
|
||||
cmdline_parm deprecated_res_arg("-res", "Deprecated, resolution, formatted like 1600x900", AT_STRING);
|
||||
cmdline_parm render_res_arg("-render_res", "Resolution, formatted like 1600x900", AT_STRING);
|
||||
cmdline_parm window_res_arg("-window_res", "Window resolution, formatted like 1600x900.", AT_STRING);
|
||||
cmdline_parm center_res_arg("-center_res", "Resolution of center monitor, formatted like 1600x900", AT_STRING);
|
||||
cmdline_parm verify_vps_arg("-verify_vps", NULL, AT_NONE); // Cmdline_verify_vps -- spew VP crcs to vp_crcs.txt
|
||||
cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_fso.cfg files", AT_NONE);
|
||||
@@ -548,6 +561,7 @@ int Cmdline_show_stats = 0;
|
||||
int Cmdline_save_render_targets = 0;
|
||||
int Cmdline_window = 0;
|
||||
int Cmdline_fullscreen_window = 0;
|
||||
tl::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res = tl::nullopt;
|
||||
char *Cmdline_res = 0;
|
||||
char *Cmdline_center_res = 0;
|
||||
int Cmdline_verify_vps = 0;
|
||||
@@ -835,7 +849,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");
|
||||
|
||||
@@ -1195,93 +1209,133 @@ bool cmdline_parm::has_param() {
|
||||
}
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
// Return a vector with all filesystem names of "parent/dir" relative to parent.
|
||||
// dir must not contain a slash.
|
||||
static SCP_vector<SCP_string> unix_get_single_dir_names(const SCP_string& parent, const SCP_string& dir)
|
||||
extern void normalize_directory_separators(SCP_string &str);
|
||||
|
||||
static SCP_string get_real_mod_path(const char *mod)
|
||||
{
|
||||
SCP_vector<SCP_string> ret;
|
||||
DIR *dirp;
|
||||
SCP_string fullpath;
|
||||
SCP_string mod_path = mod;
|
||||
|
||||
DIR *dp;
|
||||
if ((dp = opendir(parent.c_str())) == NULL) {
|
||||
Warning(LOCATION, "Can't open directory '%s' when searching mod paths. Ignoring. errno=%d", parent.c_str(), errno);
|
||||
return ret;
|
||||
normalize_directory_separators(mod_path);
|
||||
|
||||
fullpath = SCP_string(".") + DIR_SEPARATOR_STR;
|
||||
fullpath += mod_path;
|
||||
|
||||
// check if path already exists
|
||||
dirp = opendir(fullpath.c_str());
|
||||
|
||||
if (dirp) {
|
||||
// found it, return unchanged
|
||||
closedir(dirp);
|
||||
|
||||
return mod_path;
|
||||
}
|
||||
|
||||
dirent *dirp;
|
||||
while ((dirp = readdir(dp)) != NULL) {
|
||||
if (!stricmp(dirp->d_name, dir.c_str())) {
|
||||
ret.push_back(dirp->d_name);
|
||||
// not found, check for a difference in case
|
||||
SCP_string new_mod_path;
|
||||
SCP_string part;
|
||||
struct dirent *dir;
|
||||
SCP_string::size_type separator;
|
||||
SCP_string::size_type offset = 0;
|
||||
|
||||
fullpath = SCP_string(".") + DIR_SEPARATOR_STR;
|
||||
|
||||
do {
|
||||
separator = mod_path.find(DIR_SEPARATOR_CHAR, offset);
|
||||
|
||||
if (separator != SCP_string::npos) {
|
||||
part = mod_path.substr(offset, separator-offset);
|
||||
offset += separator-offset + 1;
|
||||
} else {
|
||||
part = mod_path.substr(offset);
|
||||
offset += part.length();
|
||||
}
|
||||
}
|
||||
(void)closedir(dp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
dirp = opendir(fullpath.c_str());
|
||||
|
||||
// Return a vector with all filesystem names of "parent/dir" relative to parent.
|
||||
// Recurses to deal with slashes in dir.
|
||||
static SCP_vector<SCP_string> unix_get_dir_names(const SCP_string& parent, const SCP_string& dir)
|
||||
{
|
||||
size_t slash = dir.find_first_of("/\\");
|
||||
|
||||
// no subdirectories, no need to recurse
|
||||
if (slash == std::string::npos) {
|
||||
return unix_get_single_dir_names(parent, dir);
|
||||
}
|
||||
|
||||
// get the names of the first component of dir
|
||||
SCP_vector<SCP_string> this_dir_names = unix_get_single_dir_names(parent, dir.substr(0, slash));
|
||||
|
||||
SCP_string rest = dir.substr(slash + 1);
|
||||
|
||||
SCP_vector<SCP_string> ret;
|
||||
|
||||
// search for the rest of dir in each of these
|
||||
SCP_vector<SCP_string>::iterator ii, end = this_dir_names.end();
|
||||
for (ii = this_dir_names.begin(); ii != end; ++ii) {
|
||||
SCP_string this_dir_path = parent + "/" + *ii;
|
||||
SCP_vector<SCP_string> mod_path = unix_get_dir_names(this_dir_path, rest);
|
||||
|
||||
// add all found paths relative to parent
|
||||
SCP_vector<SCP_string>::iterator ii2, end2 = mod_path.end();
|
||||
for (ii2 = mod_path.begin(); ii2 != end2; ++ii2) {
|
||||
ret.push_back(*ii + "/" + *ii2);
|
||||
if ( !dirp ) {
|
||||
break;
|
||||
}
|
||||
|
||||
while ((dir = readdir(dirp)) != nullptr) {
|
||||
if (stricmp(dir->d_name, part.c_str())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SCP_string fn = fullpath + dir->d_name;
|
||||
|
||||
// make sure it accessible and a directory
|
||||
struct stat buf;
|
||||
|
||||
if (stat(fn.c_str(), &buf) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !S_ISDIR(buf.st_mode) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !new_mod_path.empty() ) {
|
||||
new_mod_path += DIR_SEPARATOR_STR;
|
||||
}
|
||||
|
||||
new_mod_path += dir->d_name;
|
||||
|
||||
fullpath += dir->d_name;
|
||||
fullpath += DIR_SEPARATOR_STR;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (dirp) {
|
||||
closedir(dirp);
|
||||
}
|
||||
} while (offset < mod_path.length());
|
||||
|
||||
// Append anything left from mod_path onto the new path. This will catch trailing separators
|
||||
// as well as mod folders which don't exist so that the mod string remains unchanged except
|
||||
// for the directory name case.
|
||||
if (new_mod_path.length() != mod_path.length()) {
|
||||
new_mod_path += mod_path.substr(new_mod_path.length());
|
||||
}
|
||||
|
||||
return ret;
|
||||
return new_mod_path;
|
||||
}
|
||||
|
||||
// For case sensitive filesystems (e.g. Linux/BSD) perform case-insensitive dir matches.
|
||||
//
|
||||
// NOTE: Aside from change in case no alterations should be made to the modlist. Missing
|
||||
// mod folders should be left in place and no errors or warnings should be generated.
|
||||
// There should be no difference between Windows and non-Windows modlist handling.
|
||||
static void handle_unix_modlist(char **modlist, size_t *len)
|
||||
{
|
||||
// search filesystem for given paths
|
||||
SCP_vector<SCP_string> mod_paths;
|
||||
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ","))
|
||||
{
|
||||
SCP_vector<SCP_string> this_mod_paths = unix_get_dir_names(".", cur_mod);
|
||||
// Ignore non-existing mods for unit tests
|
||||
if (!running_unittests && this_mod_paths.empty()) {
|
||||
ReleaseWarning(LOCATION, "Can't find mod '%s'. Ignoring.", cur_mod);
|
||||
}
|
||||
mod_paths.insert(mod_paths.end(), this_mod_paths.begin(), this_mod_paths.end());
|
||||
|
||||
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ",")) {
|
||||
SCP_string path = get_real_mod_path(cur_mod);
|
||||
mod_paths.push_back(path);
|
||||
}
|
||||
|
||||
// create new char[] to replace modlist
|
||||
size_t total_len = 0;
|
||||
SCP_vector<SCP_string>::iterator ii, end = mod_paths.end();
|
||||
for (ii = mod_paths.begin(); ii != end; ++ii) {
|
||||
total_len += ii->length() + 1;
|
||||
|
||||
for (auto &path : mod_paths) {
|
||||
total_len += path.length() + 1;
|
||||
}
|
||||
|
||||
char *new_modlist = new char[total_len + 1];
|
||||
memset(new_modlist, 0, total_len + 1);
|
||||
end = mod_paths.end();
|
||||
for (ii = mod_paths.begin(); ii != end; ++ii) {
|
||||
strcat_s(new_modlist, total_len + 1, ii->c_str());
|
||||
strcat_s(new_modlist, total_len + 1, ","); // replace later with NUL
|
||||
|
||||
for (auto &path : mod_paths) {
|
||||
strcat_s(new_modlist, total_len + 1, path.c_str());
|
||||
strcat_s(new_modlist, total_len + 1, ",");
|
||||
}
|
||||
|
||||
// remove trailing comma
|
||||
new_modlist[total_len-1] = '\0';
|
||||
|
||||
// make the rest of the modlist manipulation unaware that anything happened here
|
||||
delete [] *modlist;
|
||||
*modlist = new_modlist;
|
||||
@@ -1646,7 +1700,7 @@ bool SetCmdlineParams()
|
||||
|
||||
// be sure that this string fits in our limits
|
||||
if ( strlen(Cmdline_game_password) >= MAX_PASSWD_LEN ) {
|
||||
ReleaseWarning(LOCATION, "Multi game password is longer than max of %d charaters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
|
||||
ReleaseWarning(LOCATION, "Multi game password is longer than max of %d characters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
|
||||
Cmdline_game_password[MAX_PASSWD_LEN-1] = '\0';
|
||||
}
|
||||
}
|
||||
@@ -1710,31 +1764,48 @@ bool SetCmdlineParams()
|
||||
// d3d windowed
|
||||
if(window_arg.found()) {
|
||||
// We need to set both values since we don't know if we are going to use the new config system
|
||||
options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "0");
|
||||
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "0");
|
||||
Cmdline_window = 1;
|
||||
}
|
||||
|
||||
if ( fullscreen_window_arg.found( ) )
|
||||
{
|
||||
options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "1");
|
||||
//options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "1");
|
||||
Cmdline_fullscreen_window = 1;
|
||||
Cmdline_window = 0; /* Make sure no-one sets both */
|
||||
}
|
||||
|
||||
if(res_arg.found()){
|
||||
Cmdline_res = res_arg.str();
|
||||
if(render_res_arg.found() || deprecated_res_arg.found()){
|
||||
if (render_res_arg.found()) {
|
||||
Cmdline_res = render_res_arg.str();
|
||||
}
|
||||
else {
|
||||
Cmdline_res = deprecated_res_arg.str();
|
||||
mprintf(("Deprecated -res argument. Use -render_res instead...\n"));
|
||||
}
|
||||
|
||||
int width = 0;
|
||||
/*int width = 0;
|
||||
int height = 0;
|
||||
|
||||
if ( sscanf(Cmdline_res, "%dx%d", &width, &height) == 2 ) {
|
||||
if (sscanf(Cmdline_res, "%dx%d", &width, &height) == 2) {
|
||||
SCP_string override;
|
||||
sprintf(override, "{\"width\":%d,\"height\":%d}", width, height);
|
||||
options::OptionsManager::instance()->setOverride("Graphics.Resolution", override);
|
||||
} else {
|
||||
mprintf(("Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".\n", Cmdline_res));
|
||||
Warning(LOCATION, "Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".\n", Cmdline_res);
|
||||
}*/
|
||||
}
|
||||
if(window_res_arg.found()){
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
if ( sscanf(window_res_arg.str(), "%dx%d", &width, &height) == 2 ) {
|
||||
Cmdline_window_res.emplace(static_cast<uint16_t>(width), static_cast<uint16_t>(height));
|
||||
} else {
|
||||
Warning(LOCATION, "Failed to parse -window_res parameter \"%s\". Must be in format \"<width>x<height>\".\n", window_res_arg.str());
|
||||
}
|
||||
}
|
||||
|
||||
if(center_res_arg.found()){
|
||||
Cmdline_center_res = center_res_arg.str();
|
||||
}
|
||||
@@ -1769,7 +1840,7 @@ bool SetCmdlineParams()
|
||||
if(mod_arg.found() ) {
|
||||
Cmdline_mod = mod_arg.str();
|
||||
|
||||
// strip off blank space it it's there
|
||||
// strip off blank space if it's there
|
||||
if ( Cmdline_mod[strlen(Cmdline_mod)-1] == ' ' ) {
|
||||
Cmdline_mod[strlen(Cmdline_mod)-1] = '\0';
|
||||
}
|
||||
@@ -1829,7 +1900,7 @@ bool SetCmdlineParams()
|
||||
if (val > 0.1) {
|
||||
VIEWER_ZOOM_DEFAULT = val;
|
||||
} else {
|
||||
VIEWER_ZOOM_DEFAULT = 0.75f;
|
||||
VIEWER_ZOOM_DEFAULT = DEFAULT_FOV;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1843,6 +1914,14 @@ bool SetCmdlineParams()
|
||||
}
|
||||
}
|
||||
|
||||
if (vr.found()) {
|
||||
Cmdline_enable_vr = true;
|
||||
if (fov_arg.found() || fov_cockpit_arg.found()) {
|
||||
Warning(LOCATION, "FoV Command line settings found. VR-Mode will override these with the HMD's native FoV...");
|
||||
}
|
||||
openxr_prepare();
|
||||
}
|
||||
|
||||
if (orb_radar.found())
|
||||
{
|
||||
Cmdline_orb_radar = 1;
|
||||
@@ -1871,6 +1950,10 @@ bool SetCmdlineParams()
|
||||
if ( stretch_menu.found() ) {
|
||||
Cmdline_stretch_menu = 1;
|
||||
}
|
||||
|
||||
if ( capture_mouse.found() ) {
|
||||
Cmdline_capture_mouse = true;
|
||||
}
|
||||
// new lighting lines
|
||||
if ( ambient_power_arg.found() )
|
||||
Cmdline_ambient_power = ambient_power_arg.get_float();
|
||||
@@ -1894,6 +1977,10 @@ bool SetCmdlineParams()
|
||||
Cmdline_no_set_gamma = 1;
|
||||
}
|
||||
|
||||
if (no_ingame_options_arg.found()) {
|
||||
Cmdline_no_ingame_options = true;
|
||||
}
|
||||
|
||||
if(no_vsync_arg.found() )
|
||||
{
|
||||
Gr_enable_vsync = false;
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
* source.
|
||||
*
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FS_CMDLINE_HEADER_FILE
|
||||
#define FS_CMDLINE_HEADER_FILE
|
||||
|
||||
#include <tl/optional.hpp>
|
||||
|
||||
int parse_cmdline(int argc, char *argv[]);
|
||||
|
||||
@@ -46,6 +47,7 @@ extern int Cmdline_use_last_pilot;
|
||||
extern int Cmdline_window;
|
||||
extern int Cmdline_fullscreen_window;
|
||||
extern char *Cmdline_res;
|
||||
extern tl::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res;
|
||||
extern char *Cmdline_center_res;
|
||||
|
||||
|
||||
@@ -86,8 +88,10 @@ extern int Cmdline_ship_choice_3d;
|
||||
extern int Cmdline_weapon_choice_3d;
|
||||
extern int Cmdline_autopilot_interruptable;
|
||||
extern int Cmdline_stretch_menu;
|
||||
extern bool Cmdline_capture_mouse;
|
||||
extern int Cmdline_no_screenshake;
|
||||
extern int Cmdline_deadzone;
|
||||
extern bool Cmdline_enable_vr;
|
||||
|
||||
// Audio related
|
||||
extern int Cmdline_voice_recognition;
|
||||
@@ -110,6 +114,7 @@ extern SCP_string Cmdline_lang;
|
||||
extern int Cmdline_load_all_weapons;
|
||||
extern int Cmdline_nomovies; // WMC Toggles movie playing support
|
||||
extern int Cmdline_no_set_gamma;
|
||||
extern bool Cmdline_no_ingame_options;
|
||||
extern int Cmdline_no_fbo;
|
||||
extern int Cmdline_no_pbo;
|
||||
extern int Cmdline_mipmap;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -923,8 +923,8 @@ bool control_config_do_reset(bool cycle, bool API_Access)
|
||||
|
||||
// first, determine how many bindings need to be changed
|
||||
for (size_t e = 0; e < Control_config.size(); ++e) {
|
||||
auto item = Control_config[e];
|
||||
auto default_item = default_bindings[e];
|
||||
const auto& item = Control_config[e];
|
||||
const auto& default_item = default_bindings[e];
|
||||
|
||||
if (item.disabled) {
|
||||
// skip
|
||||
@@ -1359,9 +1359,6 @@ bool control_config_accept(bool API_Access)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
|
||||
|
||||
if (!API_Access) {
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
|
||||
@@ -1630,7 +1627,7 @@ void control_config_close(bool API_Access)
|
||||
Ui_window.destroy();
|
||||
common_free_interface_palette(); // restore game palette
|
||||
}
|
||||
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
|
||||
|
||||
game_flush();
|
||||
|
||||
if (Game_mode & GM_MULTIPLAYER) {
|
||||
@@ -2536,6 +2533,10 @@ void control_config_do_frame(float frametime)
|
||||
if (List_buttons[i].pressed()) {
|
||||
// Select the pressed line
|
||||
Selected_line = i + Scroll_offset;
|
||||
|
||||
// Cyborg - Quick assertion for Coverity 1093701. Not likely to happen, but we check for a negative Selected Line later.
|
||||
Assertion(Selected_line > -1, "control_config_do_frame() has somehow managed to get a negative Selected_line index of %d. Please get an SCP member.", Selected_line);
|
||||
|
||||
Selected_item = selItem::None;
|
||||
List_buttons[i].get_mouse_pos(&x, &y);
|
||||
|
||||
|
||||
@@ -947,7 +947,7 @@ int check_control(int id, int key = -1);
|
||||
void control_get_axes_readings(int *axis_v, float frame_time);
|
||||
|
||||
/**
|
||||
* @brief Markes the given control (by IoActionId) as used
|
||||
* @brief Marks the given control (by IoActionId) as used
|
||||
*
|
||||
* @details Updates the ::used timestamp, triggers a script hook, and marks ::continous_ongoing as true
|
||||
*/
|
||||
|
||||
@@ -45,27 +45,31 @@ int Failed_key_index;
|
||||
// Joystick configuration
|
||||
int Joy_dead_zone_size = 10;
|
||||
|
||||
auto DeadZoneOption =
|
||||
options::OptionBuilder<int>("Input.JoystickDeadZone", "Deadzone", "The deadzone of the selected joystick.")
|
||||
.category("Input")
|
||||
.range(0, 45)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(10)
|
||||
.bind_to(&Joy_dead_zone_size)
|
||||
.importance(1)
|
||||
.finish();
|
||||
auto DeadZoneOption = options::OptionBuilder<int>("Input.JoystickDeadZone",
|
||||
std::pair<const char*, int>{"Deadzone", 1377},
|
||||
std::pair<const char*, int>{"The deadzone used for all joysticks", 1744})
|
||||
.category(std::make_pair("Input", 1827))
|
||||
.range(0, 45)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(10)
|
||||
.bind_to(&Joy_dead_zone_size)
|
||||
.importance(1)
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
int Joy_sensitivity = 9;
|
||||
|
||||
auto SensitivityOption =
|
||||
options::OptionBuilder<int>("Input.JoystickSensitivity", "Sensitivity", "The sentitivity of the selected joystick.")
|
||||
.category("Input")
|
||||
.range(0, 9)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(9)
|
||||
.bind_to(&Joy_sensitivity)
|
||||
.importance(2)
|
||||
.finish();
|
||||
auto SensitivityOption = options::OptionBuilder<int>("Input.JoystickSensitivity",
|
||||
std::pair<const char*, int>{"Sensitivity", 1745},
|
||||
std::pair<const char*, int>{"The sensitivity used for all joysticks", 1746})
|
||||
.category(std::make_pair("Input", 1827))
|
||||
.range(0, 9)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(9)
|
||||
.bind_to(&Joy_sensitivity)
|
||||
.importance(2)
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
//! arrays which hold the key mappings. The array index represents a key-independent action.
|
||||
//! please use SPACES for aligning the fields of this array
|
||||
@@ -158,8 +162,8 @@ void control_config_common_init_bindings() {
|
||||
// flight controls (flight modes)
|
||||
(BANK_WHEN_PRESSED, -1, -1, SHIP_TAB, 1, "Bank When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(AFTERBURNER, KEY_TAB, 5, SHIP_TAB, 1, "Afterburner", CC_TYPE_CONTINUOUS)
|
||||
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 0, "Glide When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 0, "Toggle Gliding", CC_TYPE_TRIGGER)
|
||||
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 1774, "Glide When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 1775, "Toggle Gliding", CC_TYPE_TRIGGER)
|
||||
|
||||
// flight controls (axes)
|
||||
(JOY_HEADING_AXIS, JOY_X_AXIS, MOUSE_X_AXIS, SHIP_TAB, 1016, "Turn (Yaw) Axis", CC_TYPE_AXIS_REL)
|
||||
@@ -173,7 +177,7 @@ void control_config_common_init_bindings() {
|
||||
(FIRE_SECONDARY, KEY_SPACEBAR, 1, WEAPON_TAB, 1, "Fire Secondary Weapon", CC_TYPE_CONTINUOUS)
|
||||
(CYCLE_NEXT_PRIMARY, KEY_PERIOD, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Forward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PREV_PRIMARY, KEY_COMMA, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Backward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PRIMARY_WEAPON_SEQUENCE, KEY_O, -1, WEAPON_TAB, 0, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PRIMARY_WEAPON_SEQUENCE, KEY_O, -1, WEAPON_TAB, 1776, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(CYCLE_SECONDARY, KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Forward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_NUM_MISSLES, KEY_SHIFTED | KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(LAUNCH_COUNTERMEASURE, KEY_X, 3, WEAPON_TAB, 1, "Launch Countermeasure", CC_TYPE_TRIGGER)
|
||||
@@ -209,8 +213,8 @@ void control_config_common_init_bindings() {
|
||||
(PADLOCK_DOWN, -1, 32, COMPUTER_TAB, 1, "View Rear", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_LEFT, -1, 34, COMPUTER_TAB, 1, "View Left", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_RIGHT, -1, 35, COMPUTER_TAB, 1, "View Right", CC_TYPE_CONTINUOUS)
|
||||
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 0, "Top-Down View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 0, "Target Padlock View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 1777, "Top-Down View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 1778, "Target Padlock View", CC_TYPE_TRIGGER)
|
||||
|
||||
(RADAR_RANGE_CYCLE, KEY_RAPOSTRO, -1, COMPUTER_TAB, 1, "Cycle Radar Range", CC_TYPE_TRIGGER)
|
||||
(SQUADMSG_MENU, KEY_C, -1, COMPUTER_TAB, 1, "Communications Menu", CC_TYPE_TRIGGER)
|
||||
@@ -235,8 +239,8 @@ void control_config_common_init_bindings() {
|
||||
|
||||
// Navigation and Autopilot
|
||||
(SHOW_NAVMAP, -1, -1, NO_TAB, 1, "Show Nav Map", CC_TYPE_TRIGGER, true)
|
||||
(AUTO_PILOT_TOGGLE, KEY_ALTED | KEY_A, -1, COMPUTER_TAB, 0, "Toggle Auto Pilot", CC_TYPE_TRIGGER)
|
||||
(NAV_CYCLE, KEY_ALTED | KEY_N, -1, COMPUTER_TAB, 0, "Cycle Nav Points", CC_TYPE_TRIGGER)
|
||||
(AUTO_PILOT_TOGGLE, KEY_ALTED | KEY_A, -1, COMPUTER_TAB, 1779, "Toggle Auto Pilot", CC_TYPE_TRIGGER)
|
||||
(NAV_CYCLE, KEY_ALTED | KEY_N, -1, COMPUTER_TAB, 1780, "Cycle Nav Points", CC_TYPE_TRIGGER)
|
||||
|
||||
// Escort
|
||||
(ADD_REMOVE_ESCORT, KEY_ALTED | KEY_E, -1, COMPUTER_TAB, 1, "Add or Remove Escort", CC_TYPE_TRIGGER)
|
||||
@@ -258,15 +262,15 @@ void control_config_common_init_bindings() {
|
||||
// HUD
|
||||
(TOGGLE_HUD, KEY_SHIFTED | KEY_O, -1, COMPUTER_TAB, 1, "Toggle HUD", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_HUD_CONTRAST, KEY_L, -1, COMPUTER_TAB, 1, "Toggle High HUD Contrast", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 0, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 1781, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
|
||||
(HUD_TARGETBOX_TOGGLE_WIREFRAME, KEY_ALTED | KEY_SHIFTED | KEY_Q, -1, COMPUTER_TAB, 1, "Toggle HUD Wireframe Target View", CC_TYPE_TRIGGER)
|
||||
|
||||
// Custom Controls
|
||||
(CUSTOM_CONTROL_1, KEY_ALTED | KEY_SHIFTED | KEY_1, -1, COMPUTER_TAB, 0, "Custom Control 1", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_2, KEY_ALTED | KEY_SHIFTED | KEY_2, -1, COMPUTER_TAB, 0, "Custom Control 2", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_3, KEY_ALTED | KEY_SHIFTED | KEY_3, -1, COMPUTER_TAB, 0, "Custom Control 3", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_4, KEY_ALTED | KEY_SHIFTED | KEY_4, -1, COMPUTER_TAB, 0, "Custom Control 4", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_5, KEY_ALTED | KEY_SHIFTED | KEY_5, -1, COMPUTER_TAB, 0, "Custom Control 5", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_1, KEY_ALTED | KEY_SHIFTED | KEY_1, -1, COMPUTER_TAB, 1784, "Custom Control 1", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_2, KEY_ALTED | KEY_SHIFTED | KEY_2, -1, COMPUTER_TAB, 1785, "Custom Control 2", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_3, KEY_ALTED | KEY_SHIFTED | KEY_3, -1, COMPUTER_TAB, 1786, "Custom Control 3", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_4, KEY_ALTED | KEY_SHIFTED | KEY_4, -1, COMPUTER_TAB, 1787, "Custom Control 4", CC_TYPE_TRIGGER, true)
|
||||
(CUSTOM_CONTROL_5, KEY_ALTED | KEY_SHIFTED | KEY_5, -1, COMPUTER_TAB, 1788, "Custom Control 5", CC_TYPE_TRIGGER, true)
|
||||
.end(); // Builder
|
||||
|
||||
// init default preset
|
||||
@@ -449,7 +453,7 @@ const char* Joy_button_text_french_u[] = {
|
||||
"Bouton 13", "Bouton 14", "Bouton 15", "Bouton 16", "Bouton 17", "Bouton 18",
|
||||
"Bouton 19", "Bouton 20", "Bouton 21", "Bouton 22", "Bouton 23", "Bouton 24",
|
||||
"Bouton 25", "Bouton 26", "Bouton 27", "Bouton 28", "Bouton 29", "Bouton 30",
|
||||
"Bouton 31", "Bouton 32", "Chapeau Arri\xc3\xa8""re", "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
"Bouton 31", "Bouton 32", ("Chapeau Arri\xc3\xa8""re"), "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
};
|
||||
|
||||
const char* Joy_button_text_polish_u[] = {
|
||||
@@ -458,7 +462,7 @@ const char* Joy_button_text_polish_u[] = {
|
||||
"Przyc.13", "Przyc.14", "Przyc.15", "Przyc.16", "Przyc.17", "Przyc.18",
|
||||
"Przyc.19", "Przyc.20", "Przyc.21", "Przyc.22", "Przyc.23", "Przyc.24",
|
||||
"Przyc.25", "Przyc.26", "Przyc.27", "Przyc.28", "Przyc.29", "Przyc.30",
|
||||
"Przyc.31", "Przyc.32", "Hat Ty\xc5\x82", "Hat Prz\xc3\xb3""d", "Hat Lewo", "Hat Prawo"
|
||||
"Przyc.31", "Przyc.32", "Hat Ty\xc5\x82", ("Hat Prz\xc3\xb3""d"), "Hat Lewo", "Hat Prawo"
|
||||
};
|
||||
|
||||
const char* Joy_button_text_english_u[] = {
|
||||
@@ -799,6 +803,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(); });
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -52,6 +52,7 @@ struct MovieProperties {
|
||||
FrameSize size;
|
||||
|
||||
float fps = -1.0f;
|
||||
float duration = 0.0f;
|
||||
|
||||
FramePixelFormat pixelFormat = FramePixelFormat::Invalid;
|
||||
};
|
||||
@@ -108,7 +109,7 @@ class Decoder {
|
||||
* @note A implementation should initialize the datastructures required for decoding here.
|
||||
*
|
||||
* @param fileName The name of the file that should be opened
|
||||
* @return @c true if the initialization was successfull, @c false otherwise
|
||||
* @return @c true if the initialization was successful, @c false otherwise
|
||||
*/
|
||||
virtual bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) = 0;
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
extern int Cmdline_nomovies;
|
||||
|
||||
bool Movie_active = false;
|
||||
|
||||
|
||||
const char* Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
|
||||
"ViewFootage",
|
||||
@@ -60,6 +62,18 @@ static cutscene_info *get_cutscene_pointer(char *cutscene_filename)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_cutscene_index_by_name(const char* name)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(Cutscenes.size()); i++) {
|
||||
if (!stricmp(name, Cutscenes[i].name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find anything.
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void cutscene_info_init(cutscene_info *csni)
|
||||
{
|
||||
csni->filename[0] = '\0';
|
||||
@@ -222,7 +236,6 @@ void cutscene_mark_viewable(const char* filename)
|
||||
|
||||
// change to lower case
|
||||
strlwr(file);
|
||||
int i = 0;
|
||||
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut)
|
||||
{
|
||||
// change the cutscene file name to lower case
|
||||
@@ -235,7 +248,6 @@ void cutscene_mark_viewable(const char* filename)
|
||||
cut->flags.set(Cutscene::Cutscene_Flags::Viewable);
|
||||
return;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
Warning(LOCATION, "Could not find cutscene '%s' in listing; cannot mark it viewable...", filename);
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct cutscene_info
|
||||
|
||||
extern SCP_vector<cutscene_info> Cutscenes;
|
||||
|
||||
extern bool Movie_active;
|
||||
|
||||
// initializa table data
|
||||
void cutscene_init();
|
||||
|
||||
@@ -48,4 +50,6 @@ void cutscenes_screen_do_frame();
|
||||
|
||||
void cutscene_mark_viewable(const char* filename);
|
||||
|
||||
int get_cutscene_index_by_name(const char* name);
|
||||
|
||||
#endif
|
||||
@@ -503,6 +503,7 @@ MovieProperties FFMPEGDecoder::getProperties() const
|
||||
props.size.height = static_cast<size_t>(m_status->videoCodecPars.height);
|
||||
|
||||
props.fps = static_cast<float>(getFrameRate(m_status->videoStream, m_status->videoCodecCtx));
|
||||
props.duration = static_cast<float>(m_status->videoStream->duration * av_q2d(m_status->videoStream->time_base));
|
||||
|
||||
props.pixelFormat = getPixelFormat(getConversionFormat(m_status->videoCodecPars.pixel_format));
|
||||
|
||||
|
||||
+11
-3
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,6 +278,7 @@ bool play(const char* name) {
|
||||
// clear the screen and hide the mouse cursor
|
||||
io::mouse::CursorManager::get()->pushStatus();
|
||||
io::mouse::CursorManager::get()->showCursor(false);
|
||||
Movie_active = true;
|
||||
gr_reset_clip();
|
||||
gr_set_color(255, 255, 255);
|
||||
gr_set_clear_color(0, 0, 0);
|
||||
@@ -299,6 +305,8 @@ bool play(const char* name) {
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
|
||||
}
|
||||
|
||||
Movie_active = false;
|
||||
|
||||
// show the mouse cursor again
|
||||
io::mouse::CursorManager::get()->popStatus();
|
||||
|
||||
|
||||
+10
-11
@@ -501,11 +501,11 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
}
|
||||
else if (vaporize) {
|
||||
db->model_num = Debris_vaporize_model;
|
||||
db->submodel_num = Random::next(Debris_num_submodels);
|
||||
db->submodel_num = (Debris_num_submodels <= 0 ? 0 : Random::next(Debris_num_submodels));
|
||||
}
|
||||
else {
|
||||
db->model_num = Debris_model;
|
||||
db->submodel_num = Random::next(Debris_num_submodels);
|
||||
db->submodel_num = (Debris_num_submodels <= 0 ? 0 : Random::next(Debris_num_submodels));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -644,7 +644,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ
|
||||
if (spark_timeout >= 0) {
|
||||
db->fire_timeout = _timestamp(spark_timeout);
|
||||
} else if (parent_objnum >= 0) {
|
||||
float t = 1000*Objects[parent_objnum].radius/3 + Random::next(fl2i(1000*3*Objects[parent_objnum].radius));
|
||||
float t = 1000*Objects[parent_objnum].radius/3 + (fl2i(1000*3*Objects[parent_objnum].radius) == 0 ? 0 : Random::next(fl2i(1000*3*Objects[parent_objnum].radius)));
|
||||
db->fire_timeout = _timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
|
||||
} else {
|
||||
db->fire_timeout = TIMESTAMP::immediate();
|
||||
@@ -926,10 +926,9 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
mc.flags = (MC_CHECK_MODEL | MC_CHECK_SPHERELINE);
|
||||
|
||||
// copy important data
|
||||
int copy_flags = mc.flags; // make a copy of start end positions of sphere in big ship RF
|
||||
vec3d copy_p0, copy_p1;
|
||||
copy_p0 = *mc.p0;
|
||||
copy_p1 = *mc.p1;
|
||||
int orig_flags = mc.flags; // make a copy of start end positions of sphere in big ship RF
|
||||
vec3d orig_p0 = *mc.p0;
|
||||
vec3d orig_p1 = *mc.p1;
|
||||
|
||||
// first test against the sphere - if this fails then don't do any submodel tests
|
||||
mc.flags = MC_ONLY_SPHERE | MC_CHECK_SPHERELINE;
|
||||
@@ -955,7 +954,7 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
}
|
||||
|
||||
// Only check single submodel now, since children of moving submodels are handled as moving as well
|
||||
mc.flags = copy_flags | MC_SUBMODEL;
|
||||
mc.flags = orig_flags | MC_SUBMODEL;
|
||||
|
||||
if (Ship_info[Ships[pship_obj->instance].ship_info_index].collision_lod > -1) {
|
||||
mc.lod = Ship_info[Ships[pship_obj->instance].ship_info_index].collision_lod;
|
||||
@@ -1005,9 +1004,9 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
|
||||
}
|
||||
|
||||
// Now complete base model collision checks that do not take into account rotating submodels.
|
||||
mc.flags = copy_flags;
|
||||
*mc.p0 = copy_p0;
|
||||
*mc.p1 = copy_p1;
|
||||
mc.flags = orig_flags;
|
||||
mc.p0 = &orig_p0;
|
||||
mc.p1 = &orig_p1;
|
||||
mc.orient = &heavy_obj->orient;
|
||||
|
||||
// usual ship_ship collision test
|
||||
|
||||
@@ -220,8 +220,8 @@ struct Decal {
|
||||
vm_vec_make(&scale, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
if (!object.IsValid()) {
|
||||
bool isValid() const {
|
||||
if (!object.isValid()) {
|
||||
return false;
|
||||
}
|
||||
if (object.objp->flags[Object::Object_Flags::Should_be_dead]) {
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
* half-rate linear filtering on GCN.
|
||||
*
|
||||
* If SMAA is applied to 64-bit color buffers, switching to point filtering
|
||||
* when accesing them will increase the performance. Search for
|
||||
* when accessing them will increase the performance. Search for
|
||||
* 'SMAASamplePoint' to see which textures may benefit from point
|
||||
* filtering, and where (which is basically the color input in the edge
|
||||
* detection and resolve passes).
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
|
||||
#ifdef COPY_ARRAY
|
||||
uniform sampler2DArray tex;
|
||||
#else
|
||||
uniform sampler2D tex;
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef COPY_ARRAY
|
||||
fragOut0 = texture(tex, vec3(fragTexCoord.xy, 0));
|
||||
#else
|
||||
fragOut0 = texture(tex, fragTexCoord.xy);
|
||||
#endif
|
||||
}
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
#include "shadows.sdr" //! #include "shadows.sdr"
|
||||
|
||||
in vec3 beamVec;
|
||||
in vec3 lightPosition;
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D ColorBuffer;
|
||||
@@ -26,6 +24,13 @@ layout (std140) uniform globalDeferredData {
|
||||
|
||||
float invScreenWidth;
|
||||
float invScreenHeight;
|
||||
|
||||
float nearPlane;
|
||||
};
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
layout (std140) uniform lightData {
|
||||
@@ -63,23 +68,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);
|
||||
// this chunk is unnecessary if sourceRadius= 0.0, but let's avoid a branch.
|
||||
// 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 +99,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 +119,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.
|
||||
// this chunk is unnecessary 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 +140,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 +161,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
}
|
||||
}
|
||||
attenuation *= attenuation;
|
||||
lightDir = normalize(lightDir);
|
||||
lightDirOut = normalize(lightDirOut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +170,7 @@ void main()
|
||||
vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
|
||||
vec3 position = texture(PositionBuffer, screenPos).xyz;
|
||||
|
||||
if(abs(dot(position, position)) < 0.1)
|
||||
if(abs(dot(position, position)) < nearPlane * nearPlane)
|
||||
discard;
|
||||
|
||||
vec3 diffColor = texture(ColorBuffer, screenPos).rgb;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
// Iteratively optimised points to give low discrepancy distribution on arbritrary hemisphere.
|
||||
// Iteratively optimised points to give low discrepancy distribution on arbitrary hemisphere.
|
||||
const vec3 points[128] = vec3[128](
|
||||
vec3(-0.2268, 0.6185, 0.7523),
|
||||
vec3( 0.9958, -0.0871, -0.0277),
|
||||
|
||||
@@ -33,7 +33,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
|
||||
|
||||
// NOTE - we're intentionally using UE4's reflectance model as modellers are using tools designed for common engines.
|
||||
|
||||
// Cook-Torrance BRDF Model (Specular Reflection) = Distibution * Fresnel * Geometry / (4*dotNV*dotNL)
|
||||
// Cook-Torrance BRDF Model (Specular Reflection) = Distribution * Fresnel * Geometry / (4*dotNV*dotNL)
|
||||
|
||||
// Distribution Term - Trowbridge-Reitz GGX
|
||||
|
||||
@@ -49,7 +49,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
|
||||
// Smith's method:
|
||||
// Microsurfaces block light rays coming in from the light
|
||||
// AND block light rays reflecting to the camera.
|
||||
// Hence, model both seperately and multiply.
|
||||
// Hence, model both separately and multiply.
|
||||
float g1vNL = GeometrySchlickGGX(dotNL, k);
|
||||
float g1vNV = GeometrySchlickGGX(dotNV, k);
|
||||
float geometry = g1vNL * g1vNV;
|
||||
|
||||
@@ -118,10 +118,13 @@ uniform sampler2DArray sMiscmap;
|
||||
uniform sampler2DArray shadow_map;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
#ifndef FLAG_SHADOW_MAP
|
||||
out vec4 fragOut1;
|
||||
out vec4 fragOut2;
|
||||
out vec4 fragOut3;
|
||||
out vec4 fragOut4;
|
||||
#endif
|
||||
|
||||
vec3 FresnelLazarovEnv(vec3 specColor, vec3 view, vec3 normal, float gloss)
|
||||
{
|
||||
@@ -185,10 +188,9 @@ 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
|
||||
|
||||
return;
|
||||
#else
|
||||
vec3 eyeDir = vec3(normalize(-vertIn.position).xyz);
|
||||
vec2 texCoord = vertIn.texCoord.xy;
|
||||
|
||||
@@ -263,6 +265,9 @@ void main()
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
|
||||
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
|
||||
specColor *= alphaMult;
|
||||
}
|
||||
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'.
|
||||
@@ -397,6 +402,11 @@ void main()
|
||||
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
|
||||
}
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
|
||||
//Since this is emissive, we need to premultiply it for intensity, and apply alpha to not replace existing emissive
|
||||
emissiveColor *= alphaMult;
|
||||
}
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
|
||||
vec3 finalFogColor = fogColor.rgb;
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
@@ -453,4 +463,5 @@ void main()
|
||||
fragOut3 = vec4(specColor.rgb, fresnelFactor);
|
||||
fragOut4 = emissiveColor;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -5,7 +5,6 @@ out vec4 fragOut2;
|
||||
out vec4 fragOut3;
|
||||
out vec4 fragOut4;
|
||||
out vec4 fragOut5;
|
||||
out float gl_FragDepth;
|
||||
|
||||
uniform sampler2DMS texColor;
|
||||
uniform sampler2DMS texPos;
|
||||
|
||||
@@ -37,7 +37,6 @@ vec3 Uncharted2ToneMapping(vec3 hdr_color) // John Hable's filmic
|
||||
hdr_color = ((hdr_color * (A * hdr_color + C * B) + D * E) / (hdr_color * (A * hdr_color + B) + D * F)) - E / F;
|
||||
float white = ((W * (A * W + C * B) + D * E) / (W * (A * W + B) + D * F)) - E / F;
|
||||
hdr_color /= white;
|
||||
hdr_color = linear_to_srgb(hdr_color); // return from linear color space to SRGB color space
|
||||
|
||||
return hdr_color;
|
||||
}
|
||||
@@ -65,7 +64,6 @@ vec3 aces(vec3 hdr_color)
|
||||
hdr_color = aces_input * hdr_color;
|
||||
hdr_color = rtt_and_odt_fit(hdr_color);
|
||||
hdr_color = aces_output * hdr_color;
|
||||
hdr_color = linear_to_srgb(hdr_color);
|
||||
return hdr_color;
|
||||
}
|
||||
|
||||
@@ -79,7 +77,6 @@ vec3 aces_approx(vec3 hdr_color) // also filmic, higher contrast then Uncharted2
|
||||
hdr_color *= 0.6f;
|
||||
|
||||
hdr_color = clamp((hdr_color*(a*hdr_color+b))/(hdr_color*(c*hdr_color+d)+e), 0.0f, 1.0f);
|
||||
hdr_color = linear_to_srgb(hdr_color); // return from linear color space to SRGB color space
|
||||
return hdr_color;
|
||||
}
|
||||
|
||||
@@ -96,7 +93,6 @@ vec3 rhj_lumaToneMapping(vec3 hdr_color) // reinhard_jodie
|
||||
float luma = dot(hdr_color, vec3(0.2126, 0.7152, 0.0722)); //dot products are a bit more expensive
|
||||
float toneMappedLuma = luma / (1.0 + luma);
|
||||
hdr_color *= toneMappedLuma / luma;
|
||||
hdr_color = linear_to_srgb(hdr_color); // return from linear color space to SRGB color space
|
||||
return hdr_color;
|
||||
}
|
||||
|
||||
@@ -105,14 +101,12 @@ vec3 reinhard_extended(vec3 hdr_color)
|
||||
float max_white = 1.0;
|
||||
vec3 numerator = hdr_color * (1.0f + (hdr_color / vec3(max_white * max_white)));
|
||||
hdr_color = numerator / (1.0f + hdr_color);
|
||||
hdr_color = linear_to_srgb(hdr_color); // return from linear color space to SRGB color space
|
||||
return hdr_color;
|
||||
}
|
||||
|
||||
vec3 linearToneMapping(vec3 hdr_color)
|
||||
{
|
||||
hdr_color = clamp(hdr_color, 0., 1.);
|
||||
hdr_color = linear_to_srgb(hdr_color); // return from linear color space to SRGB color space
|
||||
return hdr_color;
|
||||
}
|
||||
|
||||
@@ -155,7 +149,7 @@ vec3 PPC_RGB( vec3 color ) {
|
||||
funswitch(color.g),
|
||||
funswitch(color.b));
|
||||
|
||||
return linear_to_srgb(color);
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +168,7 @@ vec3 PPC( vec3 color ) {
|
||||
else {
|
||||
luma_tone = sh_offsetY;
|
||||
}
|
||||
return linear_to_srgb(color * luma_tone / luma);
|
||||
return color * luma_tone / luma;
|
||||
}
|
||||
|
||||
|
||||
@@ -213,5 +207,9 @@ void main()
|
||||
break;
|
||||
|
||||
}
|
||||
#ifdef LINEAR_OUT
|
||||
fragOut0 = vec4(color.rgb, 1.0);
|
||||
#else
|
||||
fragOut0 = vec4(linear_to_srgb(color.rgb), 1.0);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,714 @@
|
||||
-- Module options:
|
||||
local always_try_using_lpeg = true
|
||||
local register_global_module_table = false
|
||||
local global_module_name = 'json'
|
||||
|
||||
--[==[
|
||||
|
||||
David Kolf's JSON module for Lua 5.1/5.2
|
||||
|
||||
Version 2.5
|
||||
|
||||
|
||||
For the documentation see the corresponding readme.txt or visit
|
||||
<http://dkolf.de/src/dkjson-lua.fsl/>.
|
||||
|
||||
You can contact the author by sending an e-mail to 'david' at the
|
||||
domain 'dkolf.de'.
|
||||
|
||||
|
||||
Copyright (C) 2010-2014 David Heiko Kolf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--]==]
|
||||
|
||||
-- global dependencies:
|
||||
local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
|
||||
pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
|
||||
local error, require, pcall, select = error, require, pcall, select
|
||||
local floor, huge = math.floor, math.huge
|
||||
local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
|
||||
string.rep, string.gsub, string.sub, string.byte, string.char,
|
||||
string.find, string.len, string.format
|
||||
local strmatch = string.match
|
||||
local concat = table.concat
|
||||
|
||||
local json = { version = "dkjson 2.5" }
|
||||
|
||||
if register_global_module_table then
|
||||
_G[global_module_name] = json
|
||||
end
|
||||
|
||||
local _ENV = nil -- blocking globals in Lua 5.2
|
||||
|
||||
pcall (function()
|
||||
-- Enable access to blocked metatables.
|
||||
-- Don't worry, this module doesn't change anything in them.
|
||||
local debmeta = require "debug".getmetatable
|
||||
if debmeta then getmetatable = debmeta end
|
||||
end)
|
||||
|
||||
json.null = setmetatable ({}, {
|
||||
__tojson = function () return "null" end
|
||||
})
|
||||
|
||||
local function isarray (tbl)
|
||||
local max, n, arraylen = 0, 0, 0
|
||||
for k,v in pairs (tbl) do
|
||||
if k == 'n' and type(v) == 'number' then
|
||||
arraylen = v
|
||||
if v > max then
|
||||
max = v
|
||||
end
|
||||
else
|
||||
if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
|
||||
return false
|
||||
end
|
||||
if k > max then
|
||||
max = k
|
||||
end
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
if max > 10 and max > arraylen and max > n * 2 then
|
||||
return false -- don't create an array with too many holes
|
||||
end
|
||||
return true, max
|
||||
end
|
||||
|
||||
local escapecodes = {
|
||||
["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
|
||||
["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
|
||||
}
|
||||
|
||||
local function escapeutf8 (uchar)
|
||||
local value = escapecodes[uchar]
|
||||
if value then
|
||||
return value
|
||||
end
|
||||
local a, b, c, d = strbyte (uchar, 1, 4)
|
||||
a, b, c, d = a or 0, b or 0, c or 0, d or 0
|
||||
if a <= 0x7f then
|
||||
value = a
|
||||
elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
|
||||
value = (a - 0xc0) * 0x40 + b - 0x80
|
||||
elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
|
||||
value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
|
||||
elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
|
||||
value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
|
||||
else
|
||||
return ""
|
||||
end
|
||||
if value <= 0xffff then
|
||||
return strformat ("\\u%.4x", value)
|
||||
elseif value <= 0x10ffff then
|
||||
-- encode as UTF-16 surrogate pair
|
||||
value = value - 0x10000
|
||||
local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
|
||||
return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
local function fsub (str, pattern, repl)
|
||||
-- gsub always builds a new string in a buffer, even when no match
|
||||
-- exists. First using find should be more efficient when most strings
|
||||
-- don't contain the pattern.
|
||||
if strfind (str, pattern) then
|
||||
return gsub (str, pattern, repl)
|
||||
else
|
||||
return str
|
||||
end
|
||||
end
|
||||
|
||||
local function quotestring (value)
|
||||
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
|
||||
value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
|
||||
if strfind (value, "[\194\216\220\225\226\239]") then
|
||||
value = fsub (value, "\194[\128-\159\173]", escapeutf8)
|
||||
value = fsub (value, "\216[\128-\132]", escapeutf8)
|
||||
value = fsub (value, "\220\143", escapeutf8)
|
||||
value = fsub (value, "\225\158[\180\181]", escapeutf8)
|
||||
value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
|
||||
value = fsub (value, "\226\129[\160-\175]", escapeutf8)
|
||||
value = fsub (value, "\239\187\191", escapeutf8)
|
||||
value = fsub (value, "\239\191[\176-\191]", escapeutf8)
|
||||
end
|
||||
return "\"" .. value .. "\""
|
||||
end
|
||||
json.quotestring = quotestring
|
||||
|
||||
local function replace(str, o, n)
|
||||
local i, j = strfind (str, o, 1, true)
|
||||
if i then
|
||||
return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
|
||||
else
|
||||
return str
|
||||
end
|
||||
end
|
||||
|
||||
-- locale independent num2str and str2num functions
|
||||
local decpoint, numfilter
|
||||
|
||||
local function updatedecpoint ()
|
||||
decpoint = strmatch(tostring(0.5), "([^05+])")
|
||||
-- build a filter that can be used to remove group separators
|
||||
numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
|
||||
end
|
||||
|
||||
updatedecpoint()
|
||||
|
||||
local function num2str (num)
|
||||
return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
|
||||
end
|
||||
|
||||
local function str2num (str)
|
||||
local num = tonumber(replace(str, ".", decpoint))
|
||||
if not num then
|
||||
updatedecpoint()
|
||||
num = tonumber(replace(str, ".", decpoint))
|
||||
end
|
||||
return num
|
||||
end
|
||||
|
||||
local function addnewline2 (level, buffer, buflen)
|
||||
buffer[buflen+1] = "\n"
|
||||
buffer[buflen+2] = strrep (" ", level)
|
||||
buflen = buflen + 2
|
||||
return buflen
|
||||
end
|
||||
|
||||
function json.addnewline (state)
|
||||
if state.indent then
|
||||
state.bufferlen = addnewline2 (state.level or 0,
|
||||
state.buffer, state.bufferlen or #(state.buffer))
|
||||
end
|
||||
end
|
||||
|
||||
local encode2 -- forward declaration
|
||||
|
||||
local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
local kt = type (key)
|
||||
if kt ~= 'string' and kt ~= 'number' then
|
||||
return nil, "type '" .. kt .. "' is not supported as a key by JSON."
|
||||
end
|
||||
if prev then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = ","
|
||||
end
|
||||
if indent then
|
||||
buflen = addnewline2 (level, buffer, buflen)
|
||||
end
|
||||
buffer[buflen+1] = quotestring (key)
|
||||
buffer[buflen+2] = ":"
|
||||
return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
|
||||
end
|
||||
|
||||
local function appendcustom(res, buffer, state)
|
||||
local buflen = state.bufferlen
|
||||
if type (res) == 'string' then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = res
|
||||
end
|
||||
return buflen
|
||||
end
|
||||
|
||||
local function exception(reason, value, state, buffer, buflen, defaultmessage)
|
||||
defaultmessage = defaultmessage or reason
|
||||
local handler = state.exception
|
||||
if not handler then
|
||||
return nil, defaultmessage
|
||||
else
|
||||
state.bufferlen = buflen
|
||||
local ret, msg = handler (reason, value, state, defaultmessage)
|
||||
if not ret then return nil, msg or defaultmessage end
|
||||
return appendcustom(ret, buffer, state)
|
||||
end
|
||||
end
|
||||
|
||||
function json.encodeexception(reason, value, state, defaultmessage)
|
||||
return quotestring("<" .. defaultmessage .. ">")
|
||||
end
|
||||
|
||||
encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
local valtype = type (value)
|
||||
local valmeta = getmetatable (value)
|
||||
valmeta = type (valmeta) == 'table' and valmeta -- only tables
|
||||
local valtojson = valmeta and valmeta.__tojson
|
||||
if valtojson then
|
||||
if tables[value] then
|
||||
return exception('reference cycle', value, state, buffer, buflen)
|
||||
end
|
||||
tables[value] = true
|
||||
state.bufferlen = buflen
|
||||
local ret, msg = valtojson (value, state)
|
||||
if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
|
||||
tables[value] = nil
|
||||
buflen = appendcustom(ret, buffer, state)
|
||||
elseif value == nil then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "null"
|
||||
elseif valtype == 'number' then
|
||||
local s
|
||||
if value ~= value or value >= huge or -value >= huge then
|
||||
-- This is the behaviour of the original JSON implementation.
|
||||
s = "null"
|
||||
else
|
||||
s = num2str (value)
|
||||
end
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = s
|
||||
elseif valtype == 'boolean' then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = value and "true" or "false"
|
||||
elseif valtype == 'string' then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = quotestring (value)
|
||||
elseif valtype == 'table' then
|
||||
if tables[value] then
|
||||
return exception('reference cycle', value, state, buffer, buflen)
|
||||
end
|
||||
tables[value] = true
|
||||
level = level + 1
|
||||
local isa, n = isarray (value)
|
||||
if n == 0 and valmeta and valmeta.__jsontype == 'object' then
|
||||
isa = false
|
||||
end
|
||||
local msg
|
||||
if isa then -- JSON array
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "["
|
||||
for i = 1, n do
|
||||
buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
|
||||
if not buflen then return nil, msg end
|
||||
if i < n then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = ","
|
||||
end
|
||||
end
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "]"
|
||||
else -- JSON object
|
||||
local prev = false
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "{"
|
||||
local order = valmeta and valmeta.__jsonorder or globalorder
|
||||
if order then
|
||||
local used = {}
|
||||
n = #order
|
||||
for i = 1, n do
|
||||
local k = order[i]
|
||||
local v = value[k]
|
||||
if v then
|
||||
used[k] = true
|
||||
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
prev = true -- add a seperator before the next element
|
||||
end
|
||||
end
|
||||
for k,v in pairs (value) do
|
||||
if not used[k] then
|
||||
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
if not buflen then return nil, msg end
|
||||
prev = true -- add a seperator before the next element
|
||||
end
|
||||
end
|
||||
else -- unordered
|
||||
for k,v in pairs (value) do
|
||||
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
if not buflen then return nil, msg end
|
||||
prev = true -- add a seperator before the next element
|
||||
end
|
||||
end
|
||||
if indent then
|
||||
buflen = addnewline2 (level - 1, buffer, buflen)
|
||||
end
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "}"
|
||||
end
|
||||
tables[value] = nil
|
||||
else
|
||||
return exception ('unsupported type', value, state, buffer, buflen,
|
||||
"type '" .. valtype .. "' is not supported by JSON.")
|
||||
end
|
||||
return buflen
|
||||
end
|
||||
|
||||
function json.encode (value, state)
|
||||
state = state or {}
|
||||
local oldbuffer = state.buffer
|
||||
local buffer = oldbuffer or {}
|
||||
state.buffer = buffer
|
||||
updatedecpoint()
|
||||
local ret, msg = encode2 (value, state.indent, state.level or 0,
|
||||
buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
|
||||
if not ret then
|
||||
error (msg, 2)
|
||||
elseif oldbuffer == buffer then
|
||||
state.bufferlen = ret
|
||||
return true
|
||||
else
|
||||
state.bufferlen = nil
|
||||
state.buffer = nil
|
||||
return concat (buffer)
|
||||
end
|
||||
end
|
||||
|
||||
local function loc (str, where)
|
||||
local line, pos, linepos = 1, 1, 0
|
||||
while true do
|
||||
pos = strfind (str, "\n", pos, true)
|
||||
if pos and pos < where then
|
||||
line = line + 1
|
||||
linepos = pos
|
||||
pos = pos + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
return "line " .. line .. ", column " .. (where - linepos)
|
||||
end
|
||||
|
||||
local function unterminated (str, what, where)
|
||||
return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
|
||||
end
|
||||
|
||||
local function scanwhite (str, pos)
|
||||
while true do
|
||||
pos = strfind (str, "%S", pos)
|
||||
if not pos then return nil end
|
||||
local sub2 = strsub (str, pos, pos + 1)
|
||||
if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
|
||||
-- UTF-8 Byte Order Mark
|
||||
pos = pos + 3
|
||||
elseif sub2 == "//" then
|
||||
pos = strfind (str, "[\n\r]", pos + 2)
|
||||
if not pos then return nil end
|
||||
elseif sub2 == "/*" then
|
||||
pos = strfind (str, "*/", pos + 2)
|
||||
if not pos then return nil end
|
||||
pos = pos + 2
|
||||
else
|
||||
return pos
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local escapechars = {
|
||||
["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
|
||||
["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
|
||||
}
|
||||
|
||||
local function unichar (value)
|
||||
if value < 0 then
|
||||
return nil
|
||||
elseif value <= 0x007f then
|
||||
return strchar (value)
|
||||
elseif value <= 0x07ff then
|
||||
return strchar (0xc0 + floor(value/0x40),
|
||||
0x80 + (floor(value) % 0x40))
|
||||
elseif value <= 0xffff then
|
||||
return strchar (0xe0 + floor(value/0x1000),
|
||||
0x80 + (floor(value/0x40) % 0x40),
|
||||
0x80 + (floor(value) % 0x40))
|
||||
elseif value <= 0x10ffff then
|
||||
return strchar (0xf0 + floor(value/0x40000),
|
||||
0x80 + (floor(value/0x1000) % 0x40),
|
||||
0x80 + (floor(value/0x40) % 0x40),
|
||||
0x80 + (floor(value) % 0x40))
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function scanstring (str, pos)
|
||||
local lastpos = pos + 1
|
||||
local buffer, n = {}, 0
|
||||
while true do
|
||||
local nextpos = strfind (str, "[\"\\]", lastpos)
|
||||
if not nextpos then
|
||||
return unterminated (str, "string", pos)
|
||||
end
|
||||
if nextpos > lastpos then
|
||||
n = n + 1
|
||||
buffer[n] = strsub (str, lastpos, nextpos - 1)
|
||||
end
|
||||
if strsub (str, nextpos, nextpos) == "\"" then
|
||||
lastpos = nextpos + 1
|
||||
break
|
||||
else
|
||||
local escchar = strsub (str, nextpos + 1, nextpos + 1)
|
||||
local value
|
||||
if escchar == "u" then
|
||||
value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
|
||||
if value then
|
||||
local value2
|
||||
if 0xD800 <= value and value <= 0xDBff then
|
||||
-- we have the high surrogate of UTF-16. Check if there is a
|
||||
-- low surrogate escaped nearby to combine them.
|
||||
if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
|
||||
value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
|
||||
if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
|
||||
value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
|
||||
else
|
||||
value2 = nil -- in case it was out of range for a low surrogate
|
||||
end
|
||||
end
|
||||
end
|
||||
value = value and unichar (value)
|
||||
if value then
|
||||
if value2 then
|
||||
lastpos = nextpos + 12
|
||||
else
|
||||
lastpos = nextpos + 6
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not value then
|
||||
value = escapechars[escchar] or escchar
|
||||
lastpos = nextpos + 2
|
||||
end
|
||||
n = n + 1
|
||||
buffer[n] = value
|
||||
end
|
||||
end
|
||||
if n == 1 then
|
||||
return buffer[1], lastpos
|
||||
elseif n > 1 then
|
||||
return concat (buffer), lastpos
|
||||
else
|
||||
return "", lastpos
|
||||
end
|
||||
end
|
||||
|
||||
local scanvalue -- forward declaration
|
||||
|
||||
local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
|
||||
local len = strlen (str)
|
||||
local tbl, n = {}, 0
|
||||
local pos = startpos + 1
|
||||
if what == 'object' then
|
||||
setmetatable (tbl, objectmeta)
|
||||
else
|
||||
setmetatable (tbl, arraymeta)
|
||||
end
|
||||
while true do
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
local char = strsub (str, pos, pos)
|
||||
if char == closechar then
|
||||
return tbl, pos + 1
|
||||
end
|
||||
local val1, err
|
||||
val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||
if err then return nil, pos, err end
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
char = strsub (str, pos, pos)
|
||||
if char == ":" then
|
||||
if val1 == nil then
|
||||
return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
|
||||
end
|
||||
pos = scanwhite (str, pos + 1)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
local val2
|
||||
val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||
if err then return nil, pos, err end
|
||||
tbl[val1] = val2
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
char = strsub (str, pos, pos)
|
||||
else
|
||||
n = n + 1
|
||||
tbl[n] = val1
|
||||
end
|
||||
if char == "," then
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
|
||||
pos = pos or 1
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then
|
||||
return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
|
||||
end
|
||||
local char = strsub (str, pos, pos)
|
||||
if char == "{" then
|
||||
return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
|
||||
elseif char == "[" then
|
||||
return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
|
||||
elseif char == "\"" then
|
||||
return scanstring (str, pos)
|
||||
else
|
||||
local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
|
||||
if pstart then
|
||||
local number = str2num (strsub (str, pstart, pend))
|
||||
if number then
|
||||
return number, pend + 1
|
||||
end
|
||||
end
|
||||
pstart, pend = strfind (str, "^%a%w*", pos)
|
||||
if pstart then
|
||||
local name = strsub (str, pstart, pend)
|
||||
if name == "true" then
|
||||
return true, pend + 1
|
||||
elseif name == "false" then
|
||||
return false, pend + 1
|
||||
elseif name == "null" then
|
||||
return nullval, pend + 1
|
||||
end
|
||||
end
|
||||
return nil, pos, "no valid JSON value at " .. loc (str, pos)
|
||||
end
|
||||
end
|
||||
|
||||
local function optionalmetatables(...)
|
||||
if select("#", ...) > 0 then
|
||||
return ...
|
||||
else
|
||||
return {__jsontype = 'object'}, {__jsontype = 'array'}
|
||||
end
|
||||
end
|
||||
|
||||
function json.decode (str, pos, nullval, ...)
|
||||
local objectmeta, arraymeta = optionalmetatables(...)
|
||||
return scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||
end
|
||||
|
||||
function json.use_lpeg ()
|
||||
local g = require ("lpeg")
|
||||
|
||||
if g.version() == "0.11" then
|
||||
error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
|
||||
end
|
||||
|
||||
local pegmatch = g.match
|
||||
local P, S, R = g.P, g.S, g.R
|
||||
|
||||
local function ErrorCall (str, pos, msg, state)
|
||||
if not state.msg then
|
||||
state.msg = msg .. " at " .. loc (str, pos)
|
||||
state.pos = pos
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function Err (msg)
|
||||
return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
|
||||
end
|
||||
|
||||
local SingleLineComment = P"//" * (1 - S"\n\r")^0
|
||||
local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
|
||||
local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
|
||||
|
||||
local PlainChar = 1 - S"\"\\\n\r"
|
||||
local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
|
||||
local HexDigit = R("09", "af", "AF")
|
||||
local function UTF16Surrogate (match, pos, high, low)
|
||||
high, low = tonumber (high, 16), tonumber (low, 16)
|
||||
if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
|
||||
return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
local function UTF16BMP (hex)
|
||||
return unichar (tonumber (hex, 16))
|
||||
end
|
||||
local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
|
||||
local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
|
||||
local Char = UnicodeEscape + EscapeSequence + PlainChar
|
||||
local String = P"\"" * g.Cs (Char ^ 0) * (P"\"" + Err "unterminated string")
|
||||
local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
|
||||
local Fractal = P"." * R"09"^0
|
||||
local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
|
||||
local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
|
||||
local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
|
||||
local SimpleValue = Number + String + Constant
|
||||
local ArrayContent, ObjectContent
|
||||
|
||||
-- The functions parsearray and parseobject parse only a single value/pair
|
||||
-- at a time and store them directly to avoid hitting the LPeg limits.
|
||||
local function parsearray (str, pos, nullval, state)
|
||||
local obj, cont
|
||||
local npos
|
||||
local t, nt = {}, 0
|
||||
repeat
|
||||
obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
|
||||
if not npos then break end
|
||||
pos = npos
|
||||
nt = nt + 1
|
||||
t[nt] = obj
|
||||
until cont == 'last'
|
||||
return pos, setmetatable (t, state.arraymeta)
|
||||
end
|
||||
|
||||
local function parseobject (str, pos, nullval, state)
|
||||
local obj, key, cont
|
||||
local npos
|
||||
local t = {}
|
||||
repeat
|
||||
key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
|
||||
if not npos then break end
|
||||
pos = npos
|
||||
t[key] = obj
|
||||
until cont == 'last'
|
||||
return pos, setmetatable (t, state.objectmeta)
|
||||
end
|
||||
|
||||
local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) * Space * (P"]" + Err "']' expected")
|
||||
local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) * Space * (P"}" + Err "'}' expected")
|
||||
local Value = Space * (Array + Object + SimpleValue)
|
||||
local ExpectedValue = Value + Space * Err "value expected"
|
||||
ArrayContent = Value * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
|
||||
local Pair = g.Cg (Space * String * Space * (P":" + Err "colon expected") * ExpectedValue)
|
||||
ObjectContent = Pair * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
|
||||
local DecodeValue = ExpectedValue * g.Cp ()
|
||||
|
||||
function json.decode (str, pos, nullval, ...)
|
||||
local state = {}
|
||||
state.objectmeta, state.arraymeta = optionalmetatables(...)
|
||||
local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
|
||||
if state.msg then
|
||||
return nil, state.pos, state.msg
|
||||
else
|
||||
return obj, retpos
|
||||
end
|
||||
end
|
||||
|
||||
-- use this function only once:
|
||||
json.use_lpeg = function () return json end
|
||||
|
||||
json.using_lpeg = true
|
||||
|
||||
return json -- so you can get the module using json = require "dkjson".use_lpeg()
|
||||
end
|
||||
|
||||
if always_try_using_lpeg then
|
||||
pcall (json.use_lpeg)
|
||||
end
|
||||
|
||||
return json
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
#Ship types
|
||||
#Ship types
|
||||
|
||||
$Name: Navbuoy
|
||||
$Max Debris Speed: 200
|
||||
$FF Multiplier: 1.0
|
||||
@@ -11,7 +11,8 @@ $AI:
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Sentry Gun
|
||||
$Counts for Alone: YES
|
||||
$On Hotkey List: YES
|
||||
@@ -31,7 +32,8 @@ $AI:
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Escape Pod
|
||||
$Praise Destruction: YES
|
||||
$On Hotkey List: YES
|
||||
@@ -49,7 +51,8 @@ $AI:
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Cargo
|
||||
$Scannable: YES
|
||||
$Max Debris Speed: 200
|
||||
@@ -62,7 +65,8 @@ $Fog:
|
||||
+Compl dist: 500.0
|
||||
$AI:
|
||||
+Passive docks: ( "cargo" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Support
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -88,7 +92,8 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Active docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
;;WMC - Stealth ships always have another type, so this isn't used
|
||||
$Name: Stealth
|
||||
$Counts for Alone: YES
|
||||
@@ -113,7 +118,8 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Fighter
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -140,7 +146,8 @@ $AI:
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Bomber
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -167,8 +174,9 @@ $AI:
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
|
||||
$Name: Fighter/bomber
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -194,7 +202,8 @@ $AI:
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Transport
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -204,6 +213,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 2.0
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -222,7 +232,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Freighter
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -233,6 +244,7 @@ $Scannable: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 1.75
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -252,7 +264,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: AWACS
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -262,6 +275,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 0.8
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -280,7 +294,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Gas Miner
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -290,6 +305,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 1.0
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -308,7 +324,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Cruiser
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -318,6 +335,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 0.9
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -336,7 +354,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Corvette
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -346,6 +365,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 0.3333
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -364,7 +384,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Capital
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -393,7 +414,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Super Cap
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -420,7 +442,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Drydock
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -445,7 +468,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Knossos Device
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -468,5 +492,6 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
#End
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
#End
|
||||
@@ -311,7 +311,7 @@ static char* GetFilePart(char *source)
|
||||
SCP_string safe_string;
|
||||
|
||||
// Entry point into the main exception handling routine. This routine is put into an except()
|
||||
// statment at the beginning of a thread and is called anytime that there is a program exception
|
||||
// statement at the beginning of a thread and is called anytime that there is a program exception
|
||||
// The data is stored in a file called ErrorLog.txt in the data directory.
|
||||
//
|
||||
// data: pointer to the exception data
|
||||
|
||||
+37
-30
@@ -48,44 +48,51 @@ bool fireballs_parsed = false;
|
||||
|
||||
bool Fireball_use_3d_warp = false;
|
||||
|
||||
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)
|
||||
.bind_to(&Fireball_use_3d_warp)
|
||||
.importance(65)
|
||||
.finish();
|
||||
static auto WarpOption __UNUSED = options::OptionBuilder<bool>("Graphics.3dWarp",
|
||||
std::pair<const char*, int>{"3D Warp", 1770},
|
||||
std::pair<const char*, int>{"Use a 3D model for warp effects", 1771})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Fireball_use_3d_warp)
|
||||
.importance(65)
|
||||
.finish();
|
||||
|
||||
/**
|
||||
* Play warp in sound for warp effect
|
||||
*/
|
||||
void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
|
||||
{
|
||||
gamesnd_id sound_index;
|
||||
float range_multiplier = 1.0f;
|
||||
object *fireball_objp;
|
||||
|
||||
Assert((fb != NULL) && (fb->objnum >= 0));
|
||||
if((fb == NULL) || (fb->objnum < 0)){
|
||||
return;
|
||||
}
|
||||
fireball_objp = &Objects[fb->objnum];
|
||||
auto fireball_objp = &Objects[fb->objnum];
|
||||
auto sound_index = gamesnd_id(GameSounds::WARP_IN);
|
||||
|
||||
sound_index = gamesnd_id(GameSounds::WARP_IN);
|
||||
|
||||
if(fb->warp_open_sound_index.isValid()) {
|
||||
if (fb->warp_open_sound_index.isValid()) {
|
||||
sound_index = fb->warp_open_sound_index;
|
||||
} else if ((ship_class >= 0) && (ship_class < ship_info_size())) {
|
||||
if ( Ship_info[ship_class].is_huge_ship() ) {
|
||||
sound_index = gamesnd_id(GameSounds::CAPITAL_WARP_IN);
|
||||
fb->flags |= FBF_WARP_CAPITAL_SIZE;
|
||||
} else if ( Ship_info[ship_class].is_big_ship() ) {
|
||||
range_multiplier = 6.0f;
|
||||
fb->flags |= FBF_WARP_CRUISER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, range_multiplier); // play warp sound effect
|
||||
if (ship_class >= 0 && ship_class < ship_info_size()) {
|
||||
if (Ship_info[ship_class].is_huge_ship()) {
|
||||
fb->flags |= FBF_WARP_CAPITAL_SIZE;
|
||||
} else if (Ship_info[ship_class].is_big_ship()) {
|
||||
fb->flags |= FBF_WARP_CRUISER_SIZE;
|
||||
}
|
||||
|
||||
// originally 6.0 for SIF_BIG_SHIP and 1.0 for everything else
|
||||
if (Ship_info[ship_class].class_type >= 0)
|
||||
fb->warp_sound_range_multiplier = Ship_types[Ship_info[ship_class].class_type].warp_sound_range_multiplier;
|
||||
else
|
||||
fb->warp_sound_range_multiplier = 1.0f;
|
||||
}
|
||||
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, fb->warp_sound_range_multiplier); // play warp sound effect
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,15 +100,14 @@ void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
|
||||
*/
|
||||
void fireball_play_warphole_close_sound(fireball *fb)
|
||||
{
|
||||
gamesnd_id sound_index;
|
||||
Assert((fb != NULL) && (fb->objnum >= 0));
|
||||
if((fb == NULL) || (fb->objnum < 0)){
|
||||
return;
|
||||
}
|
||||
auto fireball_objp = &Objects[fb->objnum];
|
||||
auto sound_index = gamesnd_id(GameSounds::WARP_OUT);
|
||||
|
||||
object *fireball_objp;
|
||||
|
||||
fireball_objp = &Objects[fb->objnum];
|
||||
|
||||
sound_index = gamesnd_id(GameSounds::WARP_OUT);
|
||||
|
||||
if ( fb->warp_close_sound_index.isValid() ) {
|
||||
if (fb->warp_close_sound_index.isValid()) {
|
||||
sound_index = fb->warp_close_sound_index;
|
||||
} else if ( fb->flags & FBF_WARP_CAPITAL_SIZE ) {
|
||||
sound_index = gamesnd_id(GameSounds::CAPITAL_WARP_OUT);
|
||||
@@ -109,7 +115,7 @@ void fireball_play_warphole_close_sound(fireball *fb)
|
||||
return;
|
||||
}
|
||||
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius); // play warp sound effect
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0F, SND_PRIORITY_SINGLE_INSTANCE, NULL, fb->warp_sound_range_multiplier); // play warp sound effect
|
||||
}
|
||||
|
||||
static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fireball_index)
|
||||
@@ -845,6 +851,7 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
|
||||
new_fireball->warp_close_sound_index = warp_close_sound;
|
||||
new_fireball->warp_open_duration = (warp_open_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_open_duration;
|
||||
new_fireball->warp_close_duration = (warp_close_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_close_duration;
|
||||
new_fireball->warp_sound_range_multiplier = 1.0f;
|
||||
|
||||
matrix orient;
|
||||
if(orient_override != NULL){
|
||||
@@ -1045,7 +1052,7 @@ float fireball_wormhole_intensity(fireball *fb)
|
||||
rad = (float)pow((fb->total_time - t) / fb->warp_close_duration, 0.4f);
|
||||
}
|
||||
return rad;
|
||||
}
|
||||
}
|
||||
|
||||
extern void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, bool warp_3d, int warp_glow_bitmap, int warp_ball_bitmap, int warp_model_id);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -94,6 +92,9 @@ typedef struct fireball {
|
||||
gamesnd_id warp_close_sound_index;
|
||||
float warp_open_duration;
|
||||
float warp_close_duration;
|
||||
|
||||
// the sound multiplier is based on the ship class, but we lose that while the warp is closing
|
||||
float warp_sound_range_multiplier;
|
||||
} fireball;
|
||||
// end move
|
||||
|
||||
|
||||
@@ -24,13 +24,15 @@
|
||||
|
||||
bool Fireball_warp_flash = false;
|
||||
|
||||
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)
|
||||
.bind_to_once(&Fireball_warp_flash)
|
||||
.importance(65)
|
||||
.finish();
|
||||
static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.WarpFlash",
|
||||
std::pair<const char*, int>{"Warp Flash", 1768},
|
||||
std::pair<const char*, int>{"Show flash upon warp open or close", 1769})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to_once(&Fireball_warp_flash)
|
||||
.importance(65)
|
||||
.finish();
|
||||
|
||||
void warpin_batch_draw_face( int texture, vertex *v1, vertex *v2, vertex *v3 )
|
||||
{
|
||||
|
||||
@@ -499,7 +499,7 @@ void help_overlay_blit(int overlay_id, int resolution_index)
|
||||
font::set_font(help_overlaylist[overlay_id].fontlist.at(resolution_index));
|
||||
for (idx = 0; idx < textcount; idx++) {
|
||||
gr_set_color_fast(&Color_black);
|
||||
gr_get_string_size(&width, &height, help_overlaylist[overlay_id].textlist.at(0).at(idx).string, (int)strlen(help_overlaylist[overlay_id].textlist.at(0).at(idx).string));
|
||||
gr_get_string_size(&width, &height, help_overlaylist[overlay_id].textlist.at(0).at(idx).string, strlen(help_overlaylist[overlay_id].textlist.at(0).at(idx).string));
|
||||
gr_rect(help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).x_coord-2*HELP_PADDING, help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).y_coord-3*HELP_PADDING, width+4*HELP_PADDING, height+4*HELP_PADDING, GR_RESIZE_MENU);
|
||||
gr_set_color_fast(&Color_bright_white);
|
||||
gr_printf_menu(help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).x_coord, help_overlaylist[overlay_id].textlist.at(resolution_index).at(idx).y_coord,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "globalincs/alphacolors.h"
|
||||
#include "io/key.h"
|
||||
#include "mission/missionmessage.h"
|
||||
#include "missionui/missionscreencommon.h"
|
||||
#include "sound/audiostr.h"
|
||||
#include "ui/ui.h"
|
||||
@@ -516,8 +517,7 @@ void gameplay_help_leave()
|
||||
// unpause all game sounds
|
||||
weapon_unpause_sounds();
|
||||
audiostream_unpause_all();
|
||||
|
||||
Help_text.clear();
|
||||
message_resume_all();
|
||||
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
game_flush();
|
||||
@@ -633,6 +633,7 @@ void gameplay_help_do_frame(float /*frametime*/)
|
||||
// make sure game sounds are paused
|
||||
weapon_pause_sounds();
|
||||
audiostream_pause_all();
|
||||
message_pause_all();
|
||||
|
||||
k = Ui_window.process() & ~KEY_DEBUGGED;
|
||||
gameplay_help_process_key(k);
|
||||
|
||||
@@ -113,7 +113,9 @@ const char *GS_event_text[] =
|
||||
"GS_EVENT_LAB",
|
||||
"GS_EVENT_PXO_HELP",
|
||||
"GS_EVENT_FICTION_VIEWER", // 65
|
||||
"GS_EVENT_SCRIPTING"
|
||||
"GS_EVENT_SCRIPTING",
|
||||
"GS_EVENT_SCRIPTING_MISSION",
|
||||
"GS_EVENT_INGAME_OPTIONS"
|
||||
};
|
||||
//XSTR:ON
|
||||
|
||||
@@ -176,7 +178,9 @@ const char *GS_state_text[] =
|
||||
"GS_STATE_PXO_HELP", // 50
|
||||
"GS_STATE_START_GAME",
|
||||
"GS_STATE_FICTION_VIEWER",
|
||||
"GS_STATE_SCRIPTING"
|
||||
"GS_STATE_SCRIPTING",
|
||||
"GS_STATE_SCRIPTING_MISSION",
|
||||
"GS_STATE_INGAME_OPTIONS"
|
||||
};
|
||||
//XSTR:ON
|
||||
|
||||
|
||||
@@ -89,6 +89,8 @@ enum GS_EVENT {
|
||||
GS_EVENT_PXO_HELP,
|
||||
GS_EVENT_FICTION_VIEWER,
|
||||
GS_EVENT_SCRIPTING,
|
||||
GS_EVENT_SCRIPTING_MISSION,
|
||||
GS_EVENT_INGAME_OPTIONS,
|
||||
|
||||
GS_NUM_EVENTS // Last one++
|
||||
};
|
||||
@@ -159,6 +161,8 @@ enum GS_STATE {
|
||||
GS_STATE_START_GAME,
|
||||
GS_STATE_FICTION_VIEWER,
|
||||
GS_STATE_SCRIPTING,
|
||||
GS_STATE_SCRIPTING_MISSION,
|
||||
GS_STATE_INGAME_OPTIONS,
|
||||
|
||||
GS_NUM_STATES // Last one++
|
||||
};
|
||||
|
||||
+101
-48
@@ -45,13 +45,16 @@ static bool music_volume_change_listener(float new_val, bool /*initial*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
.change_listener(music_volume_change_listener)
|
||||
.importance(1)
|
||||
.finish();
|
||||
static auto MusicVolumeOption __UNUSED = options::OptionBuilder<float>("Audio.Music",
|
||||
std::pair<const char*, int>{"Music", 1371},
|
||||
std::pair<const char*, int>{"Volume used for playing music", 1760})
|
||||
.category(std::make_pair("Audio", 1826))
|
||||
.default_val(Default_music_volume)
|
||||
.range(0.0f, 1.0f)
|
||||
.change_listener(music_volume_change_listener)
|
||||
.importance(1)
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
typedef struct tagSNDPATTERN {
|
||||
int default_next_pattern; // Needed so the next_pattern member can be reset
|
||||
@@ -257,6 +260,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 +305,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, "Soundtrack file %s was not found. The soundtrack '%s' will not be used.", filename, 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 +471,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 +605,14 @@ 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)
|
||||
{
|
||||
Pattern_timer_id = TIMESTAMP::never(); // update the timestamp as if a soundtrack did start
|
||||
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 +625,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 +705,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
|
||||
}
|
||||
|
||||
@@ -908,11 +971,13 @@ int event_music_friendly_arrival()
|
||||
// overlay
|
||||
if (Soundtracks[Current_soundtrack_num].flags & EMF_ALLIED_ARRIVAL_OVERLAY)
|
||||
{
|
||||
// Goober5000 - I didn't touch this part... for some reason, FS2 only has one
|
||||
// Goober5000 - This is how retail did it. For some reason, FS2 only has one
|
||||
// arrival music pattern, and this is it
|
||||
Assert(Patterns[SONG_AARV_1].handle >= 0 );
|
||||
audiostream_play(Patterns[SONG_AARV_1].handle, (Master_event_music_volume * aav_music_volume), 0); // no looping
|
||||
audiostream_set_sample_cutoff(Patterns[SONG_AARV_1].handle, fl2i(Patterns[SONG_AARV_1].num_measures * Patterns[SONG_AARV_1].samples_per_measure) );
|
||||
if (Patterns[SONG_AARV_1].handle >= 0)
|
||||
{
|
||||
audiostream_play(Patterns[SONG_AARV_1].handle, (Master_event_music_volume * aav_music_volume), 0); // no looping
|
||||
audiostream_set_sample_cutoff(Patterns[SONG_AARV_1].handle, fl2i(Patterns[SONG_AARV_1].num_measures * Patterns[SONG_AARV_1].samples_per_measure));
|
||||
}
|
||||
}
|
||||
// don't overlay
|
||||
else
|
||||
@@ -1166,9 +1231,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 +1346,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 +1624,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 +1643,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 +1676,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 +1687,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 +1698,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 +1723,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 +1743,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
|
||||
|
||||
@@ -319,7 +319,7 @@ enum class InterfaceSounds {
|
||||
MIN_INTERFACE_SOUNDS =70 //!< MIN_INTERFACE_SOUNDS
|
||||
};
|
||||
|
||||
// These two id types are defined as sublcasses so that type safe implicit conversions are possible from the predefined
|
||||
// These two id types are defined as subclasses so that type safe implicit conversions are possible from the predefined
|
||||
// sound enum values
|
||||
|
||||
struct gamesnd_id_tag{};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -177,8 +191,8 @@ class flagset {
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool any_set() { return values.any(); }
|
||||
bool none_set() { return values.none(); }
|
||||
bool any_set() const { return values.any(); }
|
||||
bool none_set() const { return values.none(); }
|
||||
|
||||
void from_u64(std::uint64_t num) { values = (unsigned long) num; }
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
#define MAX_POLYGON_MODELS 300
|
||||
|
||||
// object.h
|
||||
//If this value exceeds 2^16-1, this will break collision pair caching as is. Proceed with caution.
|
||||
#define MAX_OBJECTS 5000 //Increased from 3500 to 5000 in 2022
|
||||
|
||||
// from weapon.h (and beam.h)
|
||||
|
||||
@@ -288,7 +288,7 @@ constexpr bool LoggingEnabled = false;
|
||||
// Disabling this functionality is dangerous, crazy values can run rampant unchecked, and the longer it's disabled
|
||||
// the more likely you are to have problems getting it working again.
|
||||
#if defined(NDEBUG)
|
||||
# define Assert(expr) do { ASSUME(expr); } while (false)
|
||||
# define Assert(expr) do { ASSUME(expr); (void)sizeof(expr); } while (false)
|
||||
#else
|
||||
# define Assert(expr) do {\
|
||||
if (!(expr)) {\
|
||||
@@ -442,7 +442,7 @@ public:
|
||||
class camera *getCamera();
|
||||
size_t getIndex();
|
||||
int getSignature();
|
||||
bool isValid();
|
||||
bool isValid() const;
|
||||
};
|
||||
|
||||
#include "globalincs/vmallocator.h"
|
||||
@@ -453,7 +453,7 @@ public:
|
||||
// - is not "none"
|
||||
// - is not "<none>"
|
||||
inline bool VALID_FNAME(const char* x) {
|
||||
return strlen((x)) && stricmp((x), "none") != 0 && stricmp((x), "<none>") != 0;
|
||||
return (x[0] != '\0') && stricmp(x, "none") != 0 && stricmp(x, "<none>") != 0;
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the specified string may be a valid file name
|
||||
|
||||
Loaded 100 of 972 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user