mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 22:56:30 -10:00
Compare commits
879
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 | ||
|
|
f98806b034 | ||
|
|
dcfea6f141 | ||
|
|
5688ba8637 | ||
|
|
1ce9d46822 | ||
|
|
f7b9896294 | ||
|
|
6d08a90106 | ||
|
|
92ed875e69 | ||
|
|
14a98e1470 | ||
|
|
cb5bf05424 | ||
|
|
15db3b17bc | ||
|
|
1dc701270f | ||
|
|
41b10e4d40 | ||
|
|
ba2c37a1fe | ||
|
|
aa997dd9ed | ||
|
|
a0a523223c | ||
|
|
8fbf22a055 | ||
|
|
f2d0bfdb31 | ||
|
|
6350a67e73 | ||
|
|
bfad425738 | ||
|
|
0811c7037b | ||
|
|
f13a5b3736 | ||
|
|
04a5778235 | ||
|
|
5a941c1d59 | ||
|
|
9586f21780 | ||
|
|
ed5a5861f7 | ||
|
|
e387038cc3 | ||
|
|
89b33ebbc5 | ||
|
|
53e6edf8bb | ||
|
|
52b7a3d198 | ||
|
|
8b8daece46 | ||
|
|
344e231058 | ||
|
|
b7045f1756 | ||
|
|
210a9a8309 | ||
|
|
6b3e50dade | ||
|
|
9a7500de36 | ||
|
|
e71dba4207 | ||
|
|
3b42ee42ca | ||
|
|
accb842ffa | ||
|
|
bb6b010487 | ||
|
|
97adef1d87 | ||
|
|
bb6917ab3b | ||
|
|
c80f787d34 | ||
|
|
861a9c9c4a | ||
|
|
d2d1d8f996 | ||
|
|
46530b78b7 | ||
|
|
cf3b5e8085 | ||
|
|
15daaf2633 | ||
|
|
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,36 +15,17 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
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:
|
||||
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
|
||||
@@ -64,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
|
||||
@@ -80,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
|
||||
@@ -183,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/*
|
||||
@@ -203,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
|
||||
@@ -234,7 +215,7 @@ jobs:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64]
|
||||
arch: [x86_64, arm64]
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
@@ -276,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
|
||||
@@ -284,23 +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/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
|
||||
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-${{ matrix.configuration }}.tgz
|
||||
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
|
||||
@@ -309,22 +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.tgz
|
||||
tar -xvzf macos-build-FastDebug.tgz
|
||||
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,64 +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-3d30dc5
|
||||
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
|
||||
- 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
|
||||
@@ -121,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.
|
||||
@@ -145,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
|
||||
@@ -164,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 }}
|
||||
@@ -191,6 +147,7 @@ jobs:
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
ref: '${{ github.ref }}'
|
||||
# - name: Cache Qt
|
||||
# # Cache Qt
|
||||
# id: cache-qt-win
|
||||
@@ -263,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/*
|
||||
@@ -285,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
|
||||
@@ -308,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 }}
|
||||
@@ -333,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
|
||||
@@ -357,6 +314,7 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
@@ -369,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
|
||||
@@ -377,23 +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/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
|
||||
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-${{ matrix.configuration }}.tgz
|
||||
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
|
||||
@@ -402,26 +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.tgz
|
||||
tar -xvzf macos-build-FastDebug.tgz
|
||||
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,59 +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:
|
||||
- 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,22 +15,8 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
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:
|
||||
@@ -41,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
|
||||
@@ -70,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
|
||||
@@ -87,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
|
||||
@@ -196,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/*
|
||||
@@ -217,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
|
||||
@@ -248,7 +229,7 @@ jobs:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64]
|
||||
arch: [x86_64, arm64]
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
@@ -289,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
|
||||
@@ -297,23 +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/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
|
||||
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-${{ matrix.configuration }}.tgz
|
||||
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
|
||||
@@ -322,22 +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.tgz
|
||||
tar -xvzf macos-build-FastDebug.tgz
|
||||
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-3d30dc5
|
||||
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,41 +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-3d30dc5
|
||||
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:
|
||||
@@ -47,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
|
||||
@@ -68,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-')
|
||||
@@ -182,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
|
||||
@@ -210,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:
|
||||
@@ -223,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
|
||||
@@ -231,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
|
||||
|
||||
@@ -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*
|
||||
|
||||
+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)
|
||||
|
||||
+20
-12
@@ -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
|
||||
@@ -34,6 +33,11 @@ if [[ "$COMPILER" =~ ^clang.*$ ]]; then
|
||||
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
|
||||
cd build
|
||||
|
||||
@@ -44,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" *.app
|
||||
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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+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,
|
||||
|
||||
@@ -7,15 +7,15 @@ 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=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
|
||||
@@ -41,7 +41,7 @@ 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]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
|
||||
@@ -53,8 +53,9 @@ Alternatively, if there is a package in your software repository then you should
|
||||
|
||||
|
||||
[img]https://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]macOS[/size][/color]
|
||||
[size=8pt]macOS 10.9+, 64-bit (Intel)[/size]
|
||||
${build(groups["Mac"].mainFile)}
|
||||
[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.
|
||||
|
||||
@@ -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}")
|
||||
|
||||
|
||||
+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);
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+11
-12
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -538,15 +538,15 @@ bool ai_new_maybe_reposition_attack_subsys() {
|
||||
model_local_to_global_point(&geye, &ep->pnt, pm, 0, &Pl_objp->orient, &Pl_objp->pos);
|
||||
|
||||
// get world pos of subsystem
|
||||
polymodel* tgt_pm = model_get(Ship_info[Ships[target_objp->instance].ship_info_index].model_num);
|
||||
model_local_to_global_point(&gsubpos, &vmd_zero_vector, tgt_pm, aip->targeted_subsys->system_info->subobj_num, &En_objp->orient, &En_objp->pos);
|
||||
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()
|
||||
|
||||
+382
-285
File diff suppressed because it is too large.
Load diff
+172
-156
@@ -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 && ship_entry->shipp)
|
||||
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,17 +1049,30 @@ 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(eval_num(CDDDR(node), is_nan, is_nan_forever));
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
|
||||
// (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;
|
||||
}
|
||||
|
||||
@@ -1050,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))) );
|
||||
|
||||
@@ -1077,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!");
|
||||
|
||||
@@ -1121,7 +1156,8 @@ 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 ( 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);
|
||||
}
|
||||
@@ -1138,8 +1174,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
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) {
|
||||
op == OP_AI_WAYPOINTS_ONCE) {
|
||||
if (is_sexp_true(CDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
@@ -1147,8 +1182,11 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
@@ -1223,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:
|
||||
@@ -1257,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:
|
||||
@@ -1303,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;
|
||||
@@ -1431,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 );
|
||||
@@ -1490,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;
|
||||
}
|
||||
|
||||
@@ -1530,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)
|
||||
@@ -1547,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;
|
||||
@@ -1570,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);
|
||||
@@ -1629,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;
|
||||
}
|
||||
@@ -1642,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;
|
||||
}
|
||||
@@ -1700,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;
|
||||
}
|
||||
|
||||
@@ -1768,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;
|
||||
@@ -1790,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 || ship_entry->status == ShipStatus::DEATH_ROLL)
|
||||
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;
|
||||
}
|
||||
@@ -1818,18 +1839,16 @@ 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))
|
||||
{
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
if ( sindex >= 0 ) {
|
||||
if (target_ship_entry && target_ship_entry->has_shipp()) {
|
||||
// if the ship has no turrets, we can't disarm it!
|
||||
if (Ships[sindex].subsys_info[SUBSYSTEM_TURRET].type_count == 0)
|
||||
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);
|
||||
@@ -1856,40 +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) ) {
|
||||
Warning(LOCATION, "Cannot determine docking information for %s!", Ships[objp->instance].ship_name); // 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);
|
||||
if (sindex < 0) {
|
||||
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
|
||||
}
|
||||
object *goal_objp = &Objects[Ships[sindex].objnum];
|
||||
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.
|
||||
@@ -1938,11 +1953,9 @@ 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))
|
||||
{
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
if ( sindex >= 0 ) {
|
||||
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 != Ships[sindex].objnum)
|
||||
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);
|
||||
@@ -1955,10 +1968,8 @@ 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 {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
@@ -1966,15 +1977,12 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
}
|
||||
} 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 );
|
||||
if (sindex < 0) {
|
||||
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
|
||||
}
|
||||
ignored = &Objects[Ships[sindex].objnum];
|
||||
auto ignored = target_ship_entry->objp();
|
||||
|
||||
ai_ignore_object(objp, ignored, (aigp->ai_mode == AI_GOAL_IGNORE_NEW));
|
||||
|
||||
@@ -1990,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:
|
||||
@@ -2007,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;
|
||||
|
||||
UNREACHABLE("Invalid status variable %d for ship %s; get Allender or a SCP member", status, Ships[objp->instance].ship_name); // 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;
|
||||
}
|
||||
|
||||
@@ -2019,30 +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 ) {
|
||||
UNREACHABLE("Ship %s cannot rearm a target %s that hasn't arrived; get Allender or a SCP member", Ships[objp->instance].ship_name, aigp->target_name); // get Allender. this shouldn't happen!!!
|
||||
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 ) {
|
||||
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!!!
|
||||
@@ -2057,7 +2066,7 @@ 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;
|
||||
@@ -2331,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!!!!
|
||||
@@ -2418,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.
|
||||
@@ -2511,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
|
||||
@@ -2539,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;
|
||||
}
|
||||
|
||||
@@ -2566,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:
|
||||
@@ -2640,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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+159
-72
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -278,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);
|
||||
@@ -304,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
|
||||
}
|
||||
@@ -24,6 +24,8 @@ layout (std140) uniform globalDeferredData {
|
||||
|
||||
float invScreenWidth;
|
||||
float invScreenHeight;
|
||||
|
||||
float nearPlane;
|
||||
};
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
@@ -79,7 +81,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
lightDirOut = lightPosition - position.xyz;
|
||||
float dist = length(lightDirOut);
|
||||
|
||||
// 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.
|
||||
// given a sphere of radius sourceRadius centered at lightDirOut,
|
||||
// move lightDirOut towards the ray defined by reflectDir
|
||||
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
|
||||
@@ -122,7 +124,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
// 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.
|
||||
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
|
||||
float dist = length(lightDirOut);
|
||||
@@ -168,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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -92,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,6 +517,7 @@ void gameplay_help_leave()
|
||||
// unpause all game sounds
|
||||
weapon_unpause_sounds();
|
||||
audiostream_unpause_all();
|
||||
message_resume_all();
|
||||
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
game_flush();
|
||||
@@ -631,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++
|
||||
};
|
||||
|
||||
+20
-12
@@ -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
|
||||
@@ -338,7 +341,7 @@ void event_music_init()
|
||||
Warning(LOCATION, "Soundtrack file %s was not found with its specified extension, but another file %s exists in the modpack. Please update the extension and adjust audio specifications if necessary.", filename, res.name_ext.c_str());
|
||||
#endif
|
||||
|
||||
Warning(LOCATION, "One or more files in '%s' could not be loaded. The soundtrack will not be used.", soundtrack.name);
|
||||
Warning(LOCATION, "Soundtrack file %s was not found. The soundtrack '%s' will not be used.", filename, soundtrack.name);
|
||||
all_patterns_valid = false;
|
||||
break;
|
||||
}
|
||||
@@ -604,7 +607,10 @@ void event_music_level_start(int 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 < (int)Soundtracks.size());
|
||||
if (Current_soundtrack_num >= (int)Soundtracks.size())
|
||||
return;
|
||||
@@ -965,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
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -191,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
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "debugconsole/console.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "io/timer.h"
|
||||
#include "nebula/neb.h"
|
||||
#include "options/Option.h"
|
||||
|
||||
@@ -34,12 +33,6 @@ float Cutscene_delta_time = 1.0f;
|
||||
//How far along a change is (0 to 1)
|
||||
float Cutscene_bars_progress = 1.0f;
|
||||
|
||||
//FADEIN STUFF
|
||||
shader Viewer_shader;
|
||||
FadeType Fade_type = FI_NONE;
|
||||
int Fade_start_timestamp = 0;
|
||||
int Fade_end_timestamp = 0;
|
||||
|
||||
// The detail level. Anything below zero draws simple models earlier than it
|
||||
// should. Anything above zero draws higher detail models longer than it should.
|
||||
// -2=lowest
|
||||
@@ -245,57 +238,95 @@ detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
|
||||
// Global used to access detail levels in game and libs
|
||||
detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS - 1];
|
||||
|
||||
const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum" },
|
||||
{ 1, "Low" },
|
||||
{ 2, "Medium" },
|
||||
{ 3, "High" },
|
||||
{ 4, "Ultra" }, };
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
|
||||
{ 1, {"Low", 1161}},
|
||||
{ 2, {"Medium", 1162}},
|
||||
{ 3, {"High", 1163}},
|
||||
{ 4, {"Ultra", 1721}}};
|
||||
|
||||
const auto ModelDetailOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.Detail", "Model Detail", "Detail level of models").importance(8).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.detail_distance = val;
|
||||
return true;
|
||||
}).finish();
|
||||
const auto ModelDetailOption __UNUSED = options::OptionBuilder<int>("Graphics.Detail",
|
||||
std::pair<const char*, int>{"Model Detail", 1739},
|
||||
std::pair<const char*, int>{"Detail level of models", 1740})
|
||||
.importance(8)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.detail_distance = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
const auto TexturesOption __UNUSED = options::OptionBuilder<int>("Graphics.Texture",
|
||||
"3D Hardware Textures",
|
||||
"Level of detail of textures").importance(6).category("Graphics").values(
|
||||
DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.hardware_textures = val;
|
||||
return true;
|
||||
}).finish();
|
||||
std::pair<const char*, int>{"3D Hardware Textures", 1362},
|
||||
std::pair<const char*, int>{"Level of detail of textures", 1720})
|
||||
.importance(6)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.hardware_textures = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
const auto ParticlesOption __UNUSED = options::OptionBuilder<int>("Graphics.Particles",
|
||||
"Particles",
|
||||
"Level of detail for particles").importance(5).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.num_particles = val;
|
||||
return true;
|
||||
}).finish();
|
||||
std::pair<const char*, int>{"Particles", 1363},
|
||||
std::pair<const char*, int>{"Level of detail for particles", 1717})
|
||||
.importance(5)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.num_particles = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
const auto SmallDebrisOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.SmallDebris", "Impact Effects", "Level of detail of impact effects").category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).importance(4).change_listener([](int val,
|
||||
bool) {
|
||||
Detail.num_small_debris = val;
|
||||
return true;
|
||||
}).finish();
|
||||
const auto SmallDebrisOption __UNUSED = options::OptionBuilder<int>("Graphics.SmallDebris",
|
||||
std::pair<const char*, int>{"Impact Effects", 1364},
|
||||
std::pair<const char*, int>{"Level of detail of impact effects", 1743})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.importance(4)
|
||||
.change_listener([](int val,bool) {
|
||||
Detail.num_small_debris = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
const auto ShieldEffectsOption __UNUSED = options::OptionBuilder<int>("Graphics.ShieldEffects",
|
||||
"Shield Hit Effects",
|
||||
"Level of detail of shield impacts").importance(3).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.shield_effects = val;
|
||||
return true;
|
||||
}).finish();
|
||||
std::pair<const char*, int>{"Shield Hit Effects", 1718},
|
||||
std::pair<const char*, int>{"Level of detail of shield impacts", 1719})
|
||||
.importance(3)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.shield_effects = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
const auto StarsOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.Stars", "Stars", "Number of stars in the mission").importance(2).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.num_stars = val;
|
||||
return true;
|
||||
}).finish();
|
||||
const auto StarsOption __UNUSED = options::OptionBuilder<int>("Graphics.Stars",
|
||||
std::pair<const char*, int>{"Stars", 1366},
|
||||
std::pair<const char*, int>{"Number of stars in the mission", 1698})
|
||||
.importance(2)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.num_stars = val;
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
// Call this with:
|
||||
// 0 - lowest
|
||||
|
||||
@@ -59,19 +59,6 @@
|
||||
extern float Cutscene_bars_progress, Cutscene_delta_time;
|
||||
extern int Cutscene_bar_flags;
|
||||
|
||||
//-----Fadein stuff
|
||||
struct shader;
|
||||
extern shader Viewer_shader;
|
||||
|
||||
enum FadeType {
|
||||
FI_NONE,
|
||||
FI_FADEIN,
|
||||
FI_FADEOUT
|
||||
};
|
||||
extern FadeType Fade_type;
|
||||
extern int Fade_start_timestamp;
|
||||
extern int Fade_end_timestamp;
|
||||
|
||||
|
||||
typedef struct vei {
|
||||
angles_t angles; // Angles defining viewer location.
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define ASSUME(x)
|
||||
|
||||
#if defined(NDEBUG)
|
||||
# define Assertion(expr, msg, ...) do { } while (false)
|
||||
# define Assertion(expr, msg, ...) do { (void)sizeof(expr); } while (false)
|
||||
#else
|
||||
/*
|
||||
* NOTE: Assertion() can only use its proper functionality in compilers
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define ASSUME(x)
|
||||
|
||||
#if defined(NDEBUG)
|
||||
# define Assertion(expr, msg, ...) do {} while (false)
|
||||
# define Assertion(expr, msg, ...) do { (void)sizeof(expr); } while (false)
|
||||
#else
|
||||
/*
|
||||
* NOTE: Assertion() can only use its proper functionality in compilers
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#define ASSUME(x)
|
||||
|
||||
#if defined(NDEBUG)
|
||||
# define Assertion(expr, msg, ...) do {} while (false)
|
||||
# define Assertion(expr, msg, ...) do { (void)sizeof(expr); } while (false)
|
||||
#else
|
||||
/*
|
||||
* NOTE: Assertion() can only use its proper functionality in compilers
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#define ASSUME(x)
|
||||
|
||||
#if defined(NDEBUG)
|
||||
# define Assertion(expr, msg, ...) do { ASSUME(expr); } while (false)
|
||||
# define Assertion(expr, msg, ...) do { ASSUME(expr); (void)sizeof(expr); } while (false)
|
||||
#else
|
||||
# define Assertion(expr, msg, ...) \
|
||||
do { \
|
||||
|
||||
+48
-32
@@ -53,41 +53,10 @@ version parse_version() {
|
||||
return v;
|
||||
}
|
||||
version parse_version_inline() {
|
||||
version v;
|
||||
|
||||
SCP_string input;
|
||||
stuff_string(input, F_RAW);
|
||||
|
||||
size_t start_pos = 0;
|
||||
size_t end_pos = input.find('.');
|
||||
|
||||
v.major = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
if (end_pos == SCP_string::npos)
|
||||
return v;
|
||||
|
||||
start_pos = end_pos + 1;
|
||||
end_pos = input.find('.', start_pos);
|
||||
|
||||
v.minor = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
if (end_pos == SCP_string::npos)
|
||||
return v;
|
||||
|
||||
start_pos = end_pos + 1;
|
||||
end_pos = input.find('.', start_pos);
|
||||
|
||||
v.build = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
if (end_pos == SCP_string::npos)
|
||||
return v;
|
||||
|
||||
start_pos = end_pos + 1;
|
||||
end_pos = input.find('.', start_pos);
|
||||
|
||||
v.revision = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
return v;
|
||||
return version(std::move(input), 0);
|
||||
}
|
||||
version get_executable_version() {
|
||||
version v;
|
||||
@@ -102,6 +71,53 @@ version get_executable_version() {
|
||||
version::version(int major_in, int minor_in, int build_in, int revision_in) :
|
||||
major(major_in), minor(minor_in), build(build_in), revision(revision_in) {
|
||||
}
|
||||
|
||||
version::version(const SCP_string& semver, int missing) : major(missing), minor(missing), build(missing), revision(missing) {
|
||||
int i = 0;
|
||||
auto str = semver;
|
||||
int has_fields = 0;
|
||||
while (i <= 4) {
|
||||
size_t pos = str.find_first_of('.');
|
||||
SCP_string ver;
|
||||
if (pos != SCP_string::npos) {
|
||||
ver = str.substr(0, pos);
|
||||
str.erase(0, pos + 1);
|
||||
}
|
||||
else {
|
||||
ver = str;
|
||||
str.clear();
|
||||
}
|
||||
|
||||
if (!ver.empty() && std::find_if(ver.begin(), ver.end(), [](char c) { return !std::isdigit(c, SCP_default_locale); }) == ver.end()) {
|
||||
switch (has_fields) {
|
||||
case 0:
|
||||
major = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
case 1:
|
||||
minor = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
case 2:
|
||||
build = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
case 3:
|
||||
revision = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Version parsing broken, get a coder!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break; //Break out of the loop if the first string is not a digit.
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
bool version::isValid() const { return major != 0 || minor != 0 || build != 0 || revision != 0; }
|
||||
bool version::operator<(const version& v) const {
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ struct version {
|
||||
|
||||
version(int major, int minor = 0, int build = 0, int revision = 0);
|
||||
|
||||
version(const SCP_string& semver, int missing = -1);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
bool operator<(const version& other) const;
|
||||
|
||||
@@ -21,10 +21,20 @@ template <typename T>
|
||||
using SCP_vector = std::vector<T, std::allocator<T>>;
|
||||
|
||||
template <typename T>
|
||||
bool SCP_vector_contains(SCP_vector<T>& vector, T item) {
|
||||
bool SCP_vector_contains(const SCP_vector<T>& vector, const T& item) {
|
||||
return std::find(vector.begin(), vector.end(), item) != vector.end();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool SCP_vector_inbounds(const SCP_vector<T>& vector, int idx) {
|
||||
return ((idx >= 0) && (idx < static_cast<int>(vector.size())));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool SCP_vector_inbounds(const SCP_vector<T>& vector, size_t idx) {
|
||||
return idx < vector.size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using SCP_list = std::list<T, std::allocator<T>>;
|
||||
|
||||
|
||||
+221
-148
@@ -25,6 +25,7 @@
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "debugconsole/console.h"
|
||||
#include "executor/global_executors.h"
|
||||
#include "graphics/openxr.h"
|
||||
#include "graphics/paths/PathRenderer.h"
|
||||
#include "graphics/post_processing.h"
|
||||
#include "graphics/util/GPUMemoryHeap.h"
|
||||
@@ -112,35 +113,40 @@ static bool gamma_change_listener(float new_val, bool initial)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto GammaOption __UNUSED =
|
||||
options::OptionBuilder<float>("Graphics.Gamma", "Brightness", "The brighness value used for the game window")
|
||||
.category("Graphics")
|
||||
.default_val(1.0f)
|
||||
.enumerator(gamma_value_enumerator)
|
||||
.display(gamma_display)
|
||||
.change_listener(gamma_change_listener)
|
||||
.finish();
|
||||
static auto GammaOption __UNUSED = options::OptionBuilder<float>("Graphics.Gamma",
|
||||
std::pair<const char*, int>{"Brightness", 1375},
|
||||
std::pair<const char*, int>{"The brightness value used for the game window", 1738})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.default_val(1.0f)
|
||||
.enumerator(gamma_value_enumerator)
|
||||
.display(gamma_display)
|
||||
.change_listener(gamma_change_listener)
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
|
||||
const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum" },
|
||||
{ 1, "Low" },
|
||||
{ 2, "Medium" },
|
||||
{ 3, "High" },
|
||||
{ 4, "Ultra" }, };
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
|
||||
{ 1, {"Low", 1161}},
|
||||
{ 2, {"Medium", 1162}},
|
||||
{ 3, {"High", 1163}},
|
||||
{ 4, {"Ultra", 1721}}};
|
||||
|
||||
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting", "Lighting", "Level of detail of the lighting")
|
||||
.importance(1)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool initial) {
|
||||
Detail.lighting = val;
|
||||
if (!initial) {
|
||||
gr_recompile_all_shaders(nullptr);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting",
|
||||
std::pair<const char*, int>{"Lighting", 1367},
|
||||
std::pair<const char*, int>{"Level of detail of the lighting", 1715})
|
||||
.importance(1)
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool initial) {
|
||||
Detail.lighting = val;
|
||||
if (!initial) {
|
||||
gr_recompile_all_shaders(nullptr);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.flags({options::OptionFlags::RetailBuiltinOption})
|
||||
.finish();
|
||||
|
||||
os::ViewportState Gr_configured_window_state = os::ViewportState::Windowed;
|
||||
|
||||
@@ -162,17 +168,18 @@ static bool mode_change_func(os::ViewportState state, bool initial)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode", "Window Mode",
|
||||
"Controls how the game window is created.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.values({{os::ViewportState::Fullscreen, "Fullscreen"},
|
||||
{os::ViewportState::Borderless, "Borderless"},
|
||||
{os::ViewportState::Windowed, "Windowed"}})
|
||||
.importance(98)
|
||||
.default_val(os::ViewportState::Fullscreen)
|
||||
.change_listener(mode_change_func)
|
||||
.finish();
|
||||
static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode",
|
||||
std::pair<const char*, int>{"Window Mode", 1772},
|
||||
std::pair<const char*, int>{"Controls how the game window is created", 1773})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.values({{os::ViewportState::Fullscreen, {"Fullscreen", 1679}},
|
||||
{os::ViewportState::Borderless, {"Borderless", 1675}},
|
||||
{os::ViewportState::Windowed, {"Windowed", 1676}}})
|
||||
.importance(98)
|
||||
.default_val(os::ViewportState::Fullscreen)
|
||||
.change_listener(mode_change_func)
|
||||
.finish();
|
||||
|
||||
const std::shared_ptr<scripting::OverridableHook<>> OnFrameHook = scripting::OverridableHook<>::Factory(
|
||||
"On Frame", "Called every frame as the last action before showing the frame result to the user.", {}, tl::nullopt, CHA_ONFRAME);
|
||||
@@ -188,6 +195,7 @@ int gr_stencil_mode = 0;
|
||||
// Default clipping distances
|
||||
const float Default_min_draw_distance = 1.0f;
|
||||
const float Default_max_draw_distance = 1e10;
|
||||
float Min_draw_distance_cockpit = 0.02f;
|
||||
float Min_draw_distance = Default_min_draw_distance;
|
||||
float Max_draw_distance = Default_max_draw_distance;
|
||||
|
||||
@@ -251,18 +259,20 @@ static bool videodisplay_change(int display, bool initial)
|
||||
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display));
|
||||
return true;
|
||||
}
|
||||
static auto VideoDisplayOption =
|
||||
options::OptionBuilder<int>("Graphics.Display", "Primary display", "The display used for rendering.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(videodisplay_deserializer)
|
||||
.serializer(videodisplay_serializer)
|
||||
.enumerator(videodisplay_enumerator)
|
||||
.display(videodisplay_display)
|
||||
.default_val(0)
|
||||
.change_listener(videodisplay_change)
|
||||
.importance(99)
|
||||
.finish();
|
||||
static auto VideoDisplayOption = options::OptionBuilder<int>("Graphics.Display",
|
||||
std::pair<const char*, int>{"Primary display", 1741},
|
||||
std::pair<const char*, int>{"The display used for rendering", 1742})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(videodisplay_deserializer)
|
||||
.serializer(videodisplay_serializer)
|
||||
.enumerator(videodisplay_enumerator)
|
||||
.display(videodisplay_display)
|
||||
.flags({options::OptionFlags::ForceMultiValueSelection})
|
||||
.default_val(0)
|
||||
.change_listener(videodisplay_change)
|
||||
.importance(99)
|
||||
.finish();
|
||||
|
||||
struct ResolutionInfo {
|
||||
uint32_t width = 0;
|
||||
@@ -359,80 +369,83 @@ static bool resolution_change(const ResolutionInfo& /*info*/, bool initial)
|
||||
}
|
||||
*/
|
||||
}
|
||||
static auto ResolutionOption =
|
||||
options::OptionBuilder<ResolutionInfo>("Graphics.Resolution", "Resolution", "The rendering resolution.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(resolution_deserializer)
|
||||
.serializer(resolution_serializer)
|
||||
.enumerator(resolution_enumerator)
|
||||
.display(resolution_display)
|
||||
.default_func(resolution_default)
|
||||
.change_listener(resolution_change)
|
||||
.importance(100)
|
||||
.finish();
|
||||
static auto ResolutionOption = options::OptionBuilder<ResolutionInfo>("Graphics.Resolution",
|
||||
std::pair<const char*, int>{"Resolution", 1748},
|
||||
std::pair<const char*, int>{"The rendering resolution", 1749})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(resolution_deserializer)
|
||||
.serializer(resolution_serializer)
|
||||
.enumerator(resolution_enumerator)
|
||||
.display(resolution_display)
|
||||
.default_func(resolution_default)
|
||||
.change_listener(resolution_change)
|
||||
.importance(100)
|
||||
.finish();
|
||||
|
||||
bool Gr_enable_soft_particles = false;
|
||||
|
||||
static auto SoftParticlesOption __UNUSED = options::OptionBuilder<bool>("Graphics.SoftParticles", "Soft Particles",
|
||||
"Enable or disable soft particle rendering.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_soft_particles)
|
||||
.importance(68)
|
||||
.finish();
|
||||
static auto SoftParticlesOption __UNUSED = options::OptionBuilder<bool>("Graphics.SoftParticles",
|
||||
std::pair<const char*, int>{"Soft Particles", 1761},
|
||||
std::pair<const char*, int>{"Enable or disable soft particle rendering", 1762})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_soft_particles)
|
||||
.importance(68)
|
||||
.finish();
|
||||
|
||||
flagset<FramebufferEffects> Gr_framebuffer_effects;
|
||||
|
||||
static auto FramebufferEffectsOption __UNUSED =
|
||||
options::OptionBuilder<flagset<FramebufferEffects>>(
|
||||
"Graphics.FramebufferEffects", "Framebuffer effects",
|
||||
"Controls which framebuffer effects will be applied to the scene.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{{}, "None"},
|
||||
{{FramebufferEffects::Shockwaves}, "Shockwaves"},
|
||||
{{FramebufferEffects::Thrusters}, "Thrusters"},
|
||||
{{FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters}, "All"}})
|
||||
.default_val({FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters})
|
||||
.bind_to_once(&Gr_framebuffer_effects)
|
||||
.importance(77)
|
||||
.finish();
|
||||
static auto FramebufferEffectsOption __UNUSED = options::OptionBuilder<flagset<FramebufferEffects>>("Graphics.FramebufferEffects",
|
||||
std::pair<const char*, int>{"Framebuffer effects", 1732},
|
||||
std::pair<const char*, int>{"Controls which framebuffer effects will be applied to the scene", 1733})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{{}, {"None", 211}},
|
||||
{{FramebufferEffects::Shockwaves}, {"Shockwaves", 1688}},
|
||||
{{FramebufferEffects::Thrusters}, {"Thrusters", 1689}},
|
||||
{{FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters}, {"All", 1690}}})
|
||||
.default_val({})
|
||||
.bind_to_once(&Gr_framebuffer_effects)
|
||||
.importance(77)
|
||||
.finish();
|
||||
|
||||
AntiAliasMode Gr_aa_mode = AntiAliasMode::None;
|
||||
AntiAliasMode Gr_aa_mode_last_frame = AntiAliasMode::None;
|
||||
|
||||
static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode", "Anti Aliasing",
|
||||
"Controls the anti aliasing mode of the engine.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{AntiAliasMode::None, "None"},
|
||||
{AntiAliasMode::FXAA_Low, "FXAA Low"},
|
||||
{AntiAliasMode::FXAA_Medium, "FXAA Medium"},
|
||||
{AntiAliasMode::FXAA_High, "FXAA High"},
|
||||
{AntiAliasMode::SMAA_Low, "SMAA Low"},
|
||||
{AntiAliasMode::SMAA_Medium, "SMAA Medium"},
|
||||
{AntiAliasMode::SMAA_High, "SMAA High"},
|
||||
{AntiAliasMode::SMAA_Ultra, "SMAA Ultra"}})
|
||||
.default_val(AntiAliasMode::None)
|
||||
.bind_to(&Gr_aa_mode)
|
||||
.importance(79)
|
||||
.finish();
|
||||
static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode",
|
||||
std::pair<const char*, int>{"Anti Aliasing", 1752},
|
||||
std::pair<const char*, int>{"Controls the anti aliasing mode of the engine.", 1753})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{AntiAliasMode::None, {"None", 211}},
|
||||
{AntiAliasMode::FXAA_Low, {"FXAA Low", 1681}},
|
||||
{AntiAliasMode::FXAA_Medium, {"FXAA Medium", 1682}},
|
||||
{AntiAliasMode::FXAA_High, {"FXAA High", 1683}},
|
||||
{AntiAliasMode::SMAA_Low, {"SMAA Low", 1684}},
|
||||
{AntiAliasMode::SMAA_Medium, {"SMAA Medium", 1685}},
|
||||
{AntiAliasMode::SMAA_High, {"SMAA High", 1686}},
|
||||
{AntiAliasMode::SMAA_Ultra, {"SMAA Ultra", 1687}}})
|
||||
.default_val(AntiAliasMode::None)
|
||||
.bind_to(&Gr_aa_mode)
|
||||
.importance(79)
|
||||
.finish();
|
||||
|
||||
extern int Cmdline_msaa_enabled;
|
||||
static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamples", "Multisample Anti Aliasing",
|
||||
"Controls whether multisample anti aliasing is enabled, and with how many samples.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{0, "Off"},
|
||||
{4, "4 Samples"},
|
||||
{8, "8 Samples"},
|
||||
{16, "16 Samples"}})
|
||||
.default_val(0)
|
||||
.bind_to(&Cmdline_msaa_enabled)
|
||||
.importance(78)
|
||||
.finish();
|
||||
static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamples",
|
||||
std::pair<const char*, int>{"Multisample Anti Aliasing", 1758},
|
||||
std::pair<const char*, int>{"Controls whether multisample anti asliasing is enabled, and with how many samples", 1759})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{0, {"Off", 1693}},
|
||||
{4, {"4 Samples", 1694}},
|
||||
{8, {"8 Samples", 1695}},
|
||||
{16, {"16 Samples", 1696}}})
|
||||
.default_val(0)
|
||||
.bind_to_once(&Cmdline_msaa_enabled)
|
||||
.importance(78)
|
||||
.finish();
|
||||
|
||||
bool gr_is_fxaa_mode(AntiAliasMode mode)
|
||||
{
|
||||
@@ -444,26 +457,27 @@ bool gr_is_smaa_mode(AntiAliasMode mode) {
|
||||
|
||||
bool Gr_post_processing_enabled = true;
|
||||
|
||||
static auto PostProcessOption __UNUSED =
|
||||
options::OptionBuilder<bool>("Graphics.PostProcessing", "Post processing",
|
||||
"Controls whether post processing is enabled in the engine")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(false)
|
||||
.bind_to_once(&Gr_post_processing_enabled)
|
||||
.importance(69)
|
||||
.finish();
|
||||
static auto PostProcessOption __UNUSED = options::OptionBuilder<bool>("Graphics.PostProcessing",
|
||||
std::pair<const char*, int>{"Post processing", 1726},
|
||||
std::pair<const char*, int>{"Controls whether post processing is enabled in the engine.", 1727})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_post_processing_enabled)
|
||||
.importance(69)
|
||||
.finish();
|
||||
|
||||
bool Gr_enable_vsync = true;
|
||||
|
||||
static auto VSyncOption __UNUSED = options::OptionBuilder<bool>("Graphics.VSync", "Vertical Sync",
|
||||
"Controls how the engine does vertical synchronization")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_vsync)
|
||||
.importance(70)
|
||||
.finish();
|
||||
static auto VSyncOption __UNUSED = options::OptionBuilder<bool>("Graphics.VSync",
|
||||
std::pair<const char*, int>{"Vertical Sync", 1766},
|
||||
std::pair<const char*, int>{"Controls how the engine does vertical synchronization", 1767})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_vsync)
|
||||
.importance(70)
|
||||
.finish();
|
||||
|
||||
static std::unique_ptr<graphics::util::UniformBufferManager> UniformBufferManager;
|
||||
|
||||
@@ -694,7 +708,7 @@ bool gr_resize_screen_pos(int *x, int *y, int *w, int *h, int resize_mode)
|
||||
*/
|
||||
bool gr_unsize_screen_pos(int *x, int *y, int *w, int *h, int resize_mode)
|
||||
{
|
||||
if ( resize_mode == GR_RESIZE_NONE || (!gr_screen.custom_size && (gr_screen.rendering_to_texture == -1)) ) {
|
||||
if ( resize_mode == GR_RESIZE_NONE || resize_mode == GR_RESIZE_REPLACE || (!gr_screen.custom_size && (gr_screen.rendering_to_texture == -1)) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1015,6 +1029,9 @@ void gr_close()
|
||||
return;
|
||||
}
|
||||
|
||||
if(Cmdline_enable_vr)
|
||||
openxr_close();
|
||||
|
||||
if (Gr_original_gamma_ramp != nullptr && os::getSDLMainWindow() != nullptr) {
|
||||
SDL_SetWindowGammaRamp(os::getSDLMainWindow(), Gr_original_gamma_ramp, (Gr_original_gamma_ramp + 256),
|
||||
(Gr_original_gamma_ramp + 512));
|
||||
@@ -1246,14 +1263,38 @@ static void init_colors()
|
||||
Gr_ta_alpha.scale = 17;
|
||||
}
|
||||
|
||||
static void gr_init_function_pointers(int mode) {
|
||||
gr_screen = {};
|
||||
|
||||
switch (mode) {
|
||||
case GR_OPENGL:
|
||||
#ifdef WITH_OPENGL
|
||||
gr_opengl_init_function_pointers();
|
||||
#else
|
||||
Error(LOCATION, "OpenGL renderer was requested but that was not compiled into this build.");
|
||||
#endif
|
||||
break;
|
||||
case GR_VULKAN:
|
||||
#ifdef WITH_VULKAN
|
||||
graphics::vulkan::initialize_function_pointers();
|
||||
#else
|
||||
Error(LOCATION, "Vulkan renderer was requested but that was not compiled into this build.");
|
||||
#endif
|
||||
break;
|
||||
case GR_STUB:
|
||||
gr_stub_init_function_pointers();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Invalid graphics mode requested"); // Invalid graphics mode
|
||||
}
|
||||
}
|
||||
|
||||
static bool gr_init_sub(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int mode, int width, int height,
|
||||
int depth, float center_aspect_ratio)
|
||||
{
|
||||
int res = GR_1024;
|
||||
bool rc = false;
|
||||
|
||||
gr_screen = {};
|
||||
|
||||
float aspect_ratio = (float)width / (float)height;
|
||||
|
||||
if ( (((width == 640) && (height == 480)) || ((width == 1024) && (height == 768))) && (aspect_ratio == center_aspect_ratio) ) {
|
||||
@@ -1552,9 +1593,6 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
depth = d_depth;
|
||||
}
|
||||
|
||||
if (Cmdline_vulkan)
|
||||
mode = GR_VULKAN;
|
||||
|
||||
// if we are in standalone mode then just use special defaults
|
||||
if (Is_standalone) {
|
||||
mode = GR_STUB;
|
||||
@@ -1564,6 +1602,8 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
center_aspect_ratio = -1.0f;
|
||||
}
|
||||
|
||||
gr_init_function_pointers(mode);
|
||||
|
||||
if (gr_get_resolution_class(width, height) != GR_640) {
|
||||
// check for hi-res interface files so that we can verify our width/height is correct
|
||||
// if we don't have it then fall back to 640x480 mode instead
|
||||
@@ -1581,6 +1621,17 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
}
|
||||
}
|
||||
|
||||
if (Cmdline_enable_vr) {
|
||||
float user_ar = i2fl(width) / i2fl(height);
|
||||
float xr_ar = openxr_preinit(user_ar);
|
||||
|
||||
if (MAX(user_ar, xr_ar) / MIN(user_ar, xr_ar) > 1.05f) {
|
||||
int newWidth = fl2i(i2fl(height) * xr_ar);
|
||||
mprintf(("User specified resolution does not match OpenXR HMD aspect ratio. Adjusting width from %dpx to %dpx.", width, newWidth));
|
||||
width = newWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// These compiler macros will force windowed mode at the specified resolution if
|
||||
// built in debug mode. This helps if you run with the debugger active as the
|
||||
// game won't be switching from fullscreen to minimized every time you hit a breakpoint or
|
||||
@@ -1699,20 +1750,12 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
Shadow_quality = ShadowQuality::Disabled;
|
||||
}
|
||||
|
||||
if(Cmdline_enable_vr)
|
||||
openxr_init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void gr_force_windowed()
|
||||
{
|
||||
if ( !Gr_inited ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Os_debugger_running ) {
|
||||
os_sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
int gr_activated = 0;
|
||||
void gr_activate(int active)
|
||||
{
|
||||
@@ -1727,7 +1770,7 @@ void gr_activate(int active)
|
||||
}
|
||||
|
||||
if (active) {
|
||||
if (Cmdline_fullscreen_window || Cmdline_window) {
|
||||
if (gr_is_viewport_window()) {
|
||||
os::getMainViewport()->restore();
|
||||
} else {
|
||||
os::getMainViewport()->setState(os::ViewportState::Fullscreen);
|
||||
@@ -1737,7 +1780,7 @@ void gr_activate(int active)
|
||||
}
|
||||
|
||||
if (active) {
|
||||
if (!Cmdline_fullscreen_window && !Cmdline_window) {
|
||||
if (!gr_is_viewport_window()) {
|
||||
gr_set_gamma(Gr_gamma);
|
||||
}
|
||||
}
|
||||
@@ -2587,7 +2630,12 @@ void gr_flip(bool execute_scripting)
|
||||
uniform_buffer_managers_retire_buffers();
|
||||
|
||||
TRACE_SCOPE(tracing::PageFlip);
|
||||
gr_screen.gf_flip();
|
||||
|
||||
//Prevent a real page flip if OpenXR is on and claims that that wasn't the full image yet
|
||||
if (!gr_openxr_flip()) {
|
||||
gr_screen.gf_flip();
|
||||
gr_setup_frame();
|
||||
}
|
||||
}
|
||||
|
||||
void gr_print_timestamp(int x, int y, fix timestamp, int resize_mode)
|
||||
@@ -2911,3 +2959,28 @@ void gr_get_post_process_effect_names(SCP_vector<SCP_string>& names)
|
||||
names.push_back(eff.name);
|
||||
}
|
||||
}
|
||||
|
||||
bool gr_is_viewport_window()
|
||||
{
|
||||
if (Fred_running) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Using_in_game_options) {
|
||||
switch (Gr_configured_window_state)
|
||||
{
|
||||
case os::ViewportState::Windowed:
|
||||
case os::ViewportState::Borderless:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (Cmdline_window || Cmdline_fullscreen_window) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
+35
-4
@@ -36,6 +36,7 @@ class OverridableHook;
|
||||
|
||||
extern const float Default_min_draw_distance;
|
||||
extern const float Default_max_draw_distance;
|
||||
extern float Min_draw_distance_cockpit;
|
||||
extern float Min_draw_distance;
|
||||
extern float Max_draw_distance;
|
||||
extern int Gr_inited;
|
||||
@@ -102,7 +103,7 @@ public:
|
||||
Stack.push_back(Current_transform);
|
||||
}
|
||||
|
||||
matrix4 &get_transform()
|
||||
const matrix4 &get_transform() const
|
||||
{
|
||||
return Current_transform;
|
||||
}
|
||||
@@ -115,7 +116,7 @@ public:
|
||||
Stack.push_back(Current_transform);
|
||||
}
|
||||
|
||||
void push_and_replace(matrix4 new_transform)
|
||||
void push_and_replace(const matrix4 &new_transform)
|
||||
{
|
||||
Current_transform = new_transform;
|
||||
Stack.push_back(Current_transform);
|
||||
@@ -202,6 +203,7 @@ enum shader_type {
|
||||
SDR_TYPE_VOLUMETRIC_FOG,
|
||||
SDR_TYPE_ROCKET_UI,
|
||||
SDR_TYPE_COPY,
|
||||
SDR_TYPE_COPY_WORLD,
|
||||
SDR_TYPE_MSAA_RESOLVE,
|
||||
|
||||
SDR_TYPE_POST_PROCESS_SMAA_EDGE,
|
||||
@@ -236,6 +238,10 @@ enum shader_type {
|
||||
#define SDR_FLAG_VOLUMETRICS_DO_EDGE_SMOOTHING (1<<0)
|
||||
#define SDR_FLAG_VOLUMETRICS_NOISE (1<<1)
|
||||
|
||||
#define SDR_FLAG_COPY_FROM_ARRAY (1 << 0)
|
||||
|
||||
#define SDR_FLAG_TONEMAPPING_LINEAR_OUT (1 << 0)
|
||||
|
||||
|
||||
enum class uniform_block_type {
|
||||
Lights = 0,
|
||||
@@ -300,7 +306,7 @@ public:
|
||||
|
||||
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset);
|
||||
|
||||
size_t get_vertex_stride() { return Vertex_stride; }
|
||||
size_t get_vertex_stride() const { return Vertex_stride; }
|
||||
|
||||
bool operator==(const vertex_layout& other) const;
|
||||
|
||||
@@ -696,6 +702,8 @@ typedef struct screen {
|
||||
// switch onscreen, offscreen
|
||||
std::function<void()> gf_flip;
|
||||
|
||||
std::function<void()> gf_setup_frame;
|
||||
|
||||
// sets the clipping region
|
||||
std::function<void(int x, int y, int w, int h, int resize_mode)> gf_set_clip;
|
||||
|
||||
@@ -911,6 +919,14 @@ typedef struct screen {
|
||||
std::function<void(int x, int y, int width, int height)> gf_set_viewport;
|
||||
|
||||
std::function<void(bool set_override)> gf_override_fog;
|
||||
|
||||
//OpenXR functions
|
||||
std::function<SCP_vector<const char*>()> gf_openxr_get_extensions;
|
||||
std::function<bool()> gf_openxr_test_capabilities;
|
||||
std::function<bool()> gf_openxr_create_session;
|
||||
std::function<int64_t(const SCP_vector<int64_t>&)> gf_openxr_get_swapchain_format;
|
||||
std::function<bool()> gf_openxr_acquire_swapchain_buffers;
|
||||
std::function<bool()> gf_openxr_flip;
|
||||
} screen;
|
||||
|
||||
// handy macro
|
||||
@@ -965,6 +981,7 @@ extern screen gr_screen;
|
||||
#define GR_RESIZE_MENU 3
|
||||
#define GR_RESIZE_MENU_ZOOMED 4
|
||||
#define GR_RESIZE_MENU_NO_OFFSET 5
|
||||
#define GR_RESIZE_REPLACE 6
|
||||
|
||||
void gr_set_screen_scale(int x, int y, int zoom_x = -1, int zoom_y = -1, int max_x = gr_screen.max_w, int max_y = gr_screen.max_h, int center_x = gr_screen.center_w, int center_y = gr_screen.center_h, bool force_stretch = false);
|
||||
void gr_reset_screen_scale();
|
||||
@@ -985,7 +1002,7 @@ extern void gr_printf_menu_zoomed( int x, int y, const char * format, SCP_FORMAT
|
||||
extern void gr_printf_no_resize( int x, int y, const char * format, SCP_FORMAT_STRING ... ) SCP_FORMAT_STRING_ARGS(3, 4);
|
||||
|
||||
// Returns the size of the string in pixels in w and h
|
||||
extern void gr_get_string_size( int *w, int *h, const char * text, int len = 9999 );
|
||||
extern void gr_get_string_size( int *w, int *h, const char * text, size_t len = std::string::npos );
|
||||
|
||||
// Returns the height of the current font
|
||||
extern int gr_get_font_height();
|
||||
@@ -1010,6 +1027,10 @@ extern void gr_activate(int active);
|
||||
//#define gr_flip GR_CALL(gr_screen.gf_flip)
|
||||
void gr_flip(bool execute_scripting = true);
|
||||
|
||||
inline void gr_setup_frame() {
|
||||
gr_screen.gf_setup_frame();
|
||||
}
|
||||
|
||||
//#define gr_set_clip GR_CALL(gr_screen.gf_set_clip)
|
||||
inline void gr_set_clip(int x, int y, int w, int h, int resize_mode=GR_RESIZE_FULL)
|
||||
{
|
||||
@@ -1271,6 +1292,14 @@ inline void gr_sync_delete(gr_sync sync)
|
||||
gr_screen.gf_sync_delete(sync);
|
||||
}
|
||||
|
||||
//OpenXR
|
||||
#define gr_openxr_get_extensions GR_CALL(gr_screen.gf_openxr_get_extensions)
|
||||
#define gr_openxr_test_capabilities GR_CALL(gr_screen.gf_openxr_test_capabilities)
|
||||
#define gr_openxr_create_session GR_CALL(gr_screen.gf_openxr_create_session)
|
||||
#define gr_openxr_get_swapchain_format GR_CALL(gr_screen.gf_openxr_get_swapchain_format)
|
||||
#define gr_openxr_acquire_swapchain_buffers GR_CALL(gr_screen.gf_openxr_acquire_swapchain_buffers)
|
||||
#define gr_openxr_flip GR_CALL(gr_screen.gf_openxr_flip)
|
||||
|
||||
// color functions
|
||||
void gr_init_color(color *c, int r, int g, int b);
|
||||
void gr_init_alphacolor( color *clr, int r, int g, int b, int alpha, int type = AC_TYPE_HUD );
|
||||
@@ -1399,6 +1428,8 @@ void gr_set_gamma(float gamma);
|
||||
|
||||
void gr_get_post_process_effect_names(SCP_vector<SCP_string> &names);
|
||||
|
||||
bool gr_is_viewport_window();
|
||||
|
||||
// Include this last to make the 2D rendering function available everywhere
|
||||
#include "graphics/render.h"
|
||||
|
||||
|
||||
@@ -734,6 +734,28 @@ void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool m
|
||||
}
|
||||
}
|
||||
|
||||
void generic_anim_bitmap_set(generic_anim* ga, float frametime, const generic_extras* ge)
|
||||
{
|
||||
if ((ge != nullptr) && (ga->use_hud_color == true)) {
|
||||
Warning(LOCATION, "Monochrome generic anims can't use extra info (yet)");
|
||||
return;
|
||||
}
|
||||
|
||||
float a = 1.0f;
|
||||
if (ge != nullptr) {
|
||||
a = ge->alpha;
|
||||
}
|
||||
if (ga->type == BM_TYPE_PNG) {
|
||||
generic_anim_render_variable_frame_delay(ga, frametime, a);
|
||||
}
|
||||
else {
|
||||
generic_anim_render_fixed_frame_delay(ga, frametime, a);
|
||||
}
|
||||
|
||||
if (ga->num_frames > 0)
|
||||
ga->previous_frame = ga->current_frame;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief reset an animation back to the start
|
||||
*
|
||||
|
||||
@@ -91,5 +91,6 @@ int generic_anim_stream(generic_anim *ga, const bool cache = true);
|
||||
int generic_bitmap_load(generic_bitmap *gb);
|
||||
void generic_anim_unload(generic_anim *ga);
|
||||
void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu = false, const generic_extras *ge = nullptr);
|
||||
void generic_anim_bitmap_set(generic_anim* ga, float frametime, const generic_extras* ge = nullptr);
|
||||
void generic_anim_reset(generic_anim *ga);
|
||||
#endif
|
||||
@@ -18,6 +18,11 @@
|
||||
#include "bmpman/bm_internal.h"
|
||||
|
||||
|
||||
void gr_stub_setup_frame()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint gr_stub_lock()
|
||||
{
|
||||
return 1;
|
||||
@@ -421,7 +426,37 @@ void gr_stub_delete_query_object(int /*obj*/)
|
||||
{
|
||||
}
|
||||
|
||||
bool gr_stub_init()
|
||||
SCP_vector<const char*> gr_stub_openxr_get_extensions()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool gr_stub_openxr_test_capabilities()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gr_stub_openxr_create_session()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t gr_stub_openxr_get_swapchain_format(const SCP_vector<int64_t>& /*allowed*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool gr_stub_openxr_acquire_swapchain_buffers()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gr_stub_openxr_flip()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gr_stub_init()
|
||||
{
|
||||
if (gr_screen.res != GR_640) {
|
||||
gr_screen.res = GR_640;
|
||||
@@ -447,8 +482,13 @@ bool gr_stub_init()
|
||||
Gr_blue.mask = 0xff;
|
||||
Gr_t_blue = Gr_blue;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void gr_stub_init_function_pointers() {
|
||||
// function pointers...
|
||||
gr_screen.gf_flip = gr_stub_flip;
|
||||
gr_screen.gf_setup_frame = gr_stub_setup_frame;
|
||||
gr_screen.gf_set_clip = gr_stub_set_clip;
|
||||
gr_screen.gf_reset_clip = gr_stub_reset_clip;
|
||||
|
||||
@@ -572,5 +612,10 @@ bool gr_stub_init()
|
||||
|
||||
gr_screen.gf_override_fog = [](bool /*b*/) {};
|
||||
|
||||
return true;
|
||||
gr_screen.gf_openxr_get_extensions = gr_stub_openxr_get_extensions;
|
||||
gr_screen.gf_openxr_test_capabilities = gr_stub_openxr_test_capabilities;
|
||||
gr_screen.gf_openxr_create_session = gr_stub_openxr_create_session;
|
||||
gr_screen.gf_openxr_get_swapchain_format = gr_stub_openxr_get_swapchain_format;
|
||||
gr_screen.gf_openxr_acquire_swapchain_buffers = gr_stub_openxr_acquire_swapchain_buffers;
|
||||
gr_screen.gf_openxr_flip = gr_stub_openxr_flip;
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
|
||||
|
||||
void gr_stub_init_function_pointers();
|
||||
bool gr_stub_init();
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "io/timer.h"
|
||||
#include "lighting/lighting.h"
|
||||
#include "lighting/lighting_profiles.h"
|
||||
#include "math/bitarray.h"
|
||||
@@ -43,6 +44,12 @@ struct gr_light
|
||||
int type;
|
||||
};
|
||||
|
||||
//FADEIN STUFF
|
||||
shader Viewer_shader;
|
||||
FadeType Fade_type = FadeType::FI_NONE;
|
||||
TIMESTAMP Fade_start_timestamp = TIMESTAMP::invalid();
|
||||
TIMESTAMP Fade_end_timestamp = TIMESTAMP::invalid();
|
||||
|
||||
// Variables
|
||||
SCP_vector<gr_light> gr_lights;
|
||||
graphics::model_light gr_light_uniforms[graphics::MAX_UNIFORM_LIGHTS];
|
||||
@@ -332,8 +339,8 @@ void gr_set_ambient_light(int red, int green, int blue) {
|
||||
gr_light_ambient[3] = 1.0f;
|
||||
}
|
||||
void gr_get_ambient_light(vec3d* light_vector) {
|
||||
auto abv = ltp::current()->ambient_light_brightness;
|
||||
auto over = ltp::current()->overall_brightness;
|
||||
const auto& abv = ltp::current()->ambient_light_brightness;
|
||||
const auto& over = ltp::current()->overall_brightness;
|
||||
light_vector->xyz.x = over.handle(abv.handle(gr_light_ambient[0]));
|
||||
light_vector->xyz.y = over.handle(abv.handle(gr_light_ambient[1]));
|
||||
light_vector->xyz.z = over.handle(abv.handle(gr_light_ambient[2]));
|
||||
|
||||
@@ -5,6 +5,20 @@
|
||||
#include "lighting/lighting.h"
|
||||
#include "cmdline/cmdline.h"
|
||||
|
||||
//-----Fadein stuff
|
||||
struct shader;
|
||||
extern shader Viewer_shader;
|
||||
|
||||
enum class FadeType {
|
||||
FI_NONE = 0,
|
||||
FI_FADEIN,
|
||||
FI_FADEOUT
|
||||
};
|
||||
extern FadeType Fade_type;
|
||||
extern TIMESTAMP Fade_start_timestamp;
|
||||
extern TIMESTAMP Fade_end_timestamp;
|
||||
|
||||
|
||||
//Variables
|
||||
extern int Num_active_gr_lights;
|
||||
|
||||
@@ -13,6 +27,7 @@ extern const float gr_light_zero[4];
|
||||
extern const float gr_light_emission[4];
|
||||
extern float gr_light_ambient[4];
|
||||
|
||||
|
||||
//Functions
|
||||
void gr_set_light(light *fs_light);
|
||||
void gr_reset_lighting();
|
||||
|
||||
@@ -441,7 +441,7 @@ void material::set_color(int r, int g, int b, int a)
|
||||
Clr.xyzw.w = i2fl(a) / 255.0f;
|
||||
}
|
||||
|
||||
void material::set_color(color &clr_in)
|
||||
void material::set_color(const color &clr_in)
|
||||
{
|
||||
if ( clr_in.is_alphacolor ) {
|
||||
Clr.xyzw.x = i2fl(clr_in.red) / 255.0f;
|
||||
|
||||
Loaded 100 of 938 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user