mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 22:56:30 -10:00
Compare commits
941
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b0673b30d | ||
|
|
b92954877d | ||
|
|
3047a226a3 | ||
|
|
9974457df0 | ||
|
|
c72e214c47 | ||
|
|
7177361c82 | ||
|
|
654b0a0e42 | ||
|
|
add6a60439 | ||
|
|
5694e5c810 | ||
|
|
5c8806d040 | ||
|
|
798e47409a | ||
|
|
f8acd4f898 | ||
|
|
689467e21f | ||
|
|
b6ff2caa0a | ||
|
|
5020cf8b64 | ||
|
|
4f1d486ea3 | ||
|
|
e8c9a0a3aa | ||
|
|
2bc1247002 | ||
|
|
d8a052128e | ||
|
|
fa3631c9b9 | ||
|
|
0fcf7e0fbe | ||
|
|
d562104c0f | ||
|
|
a1dbf2e917 | ||
|
|
d55a604ca5 | ||
|
|
264a44085d | ||
|
|
da3ed275d4 | ||
|
|
44bebf17b8 | ||
|
|
0b234af925 | ||
|
|
5ca15685ef | ||
|
|
98713dadc1 | ||
|
|
b0f5a4cffb | ||
|
|
dd9faf9438 | ||
|
|
fc2cac617f | ||
|
|
96bd06fbc1 | ||
|
|
d62e38d996 | ||
|
|
d8fe4a11be | ||
|
|
1a4abd9977 | ||
|
|
aa6b1030f1 | ||
|
|
3752a54a63 | ||
|
|
a49acc92f3 | ||
|
|
5ba4e50685 | ||
|
|
24e3243289 | ||
|
|
c1987aba62 | ||
|
|
6f7bcbd0ff | ||
|
|
9a8d5cde53 | ||
|
|
efc5a370d5 | ||
|
|
4760bc7e2b | ||
|
|
a7b46dba58 | ||
|
|
cc079aedfa | ||
|
|
f3937a8f68 | ||
|
|
1f7cdca5a9 | ||
|
|
d36a95962f | ||
|
|
d2eff1f141 | ||
|
|
9ce7748c20 | ||
|
|
c74d523e18 | ||
|
|
0bc26cab24 | ||
|
|
0d56bb9999 | ||
|
|
f2fa235522 | ||
|
|
7829989478 | ||
|
|
a8e411d310 | ||
|
|
07924f078a | ||
|
|
782980844b | ||
|
|
c95865442e | ||
|
|
f484ddef06 | ||
|
|
0c687f37c1 | ||
|
|
6de5c96127 | ||
|
|
083984efec | ||
|
|
9346f67d5c | ||
|
|
d2322cb2c2 | ||
|
|
96f2a3b045 | ||
|
|
e2e14bb6df | ||
|
|
155e043bb0 | ||
|
|
ef721b3192 | ||
|
|
06ded501c8 | ||
|
|
9540caff5a | ||
|
|
3eacbc0e0b | ||
|
|
a2d4576c4f | ||
|
|
c727e40b8a | ||
|
|
78b385e41b | ||
|
|
5485efe904 | ||
|
|
85bb14898f | ||
|
|
a3bbf13da6 | ||
|
|
10d3bdda06 | ||
|
|
dd93284777 | ||
|
|
d6bb97d8f2 | ||
|
|
46293ad0fe | ||
|
|
8aa4a86e1c | ||
|
|
ca7618c993 | ||
|
|
fc21e12dfd | ||
|
|
a662f8168c | ||
|
|
c2b93549a2 | ||
|
|
32852c967e | ||
|
|
342373e2a1 | ||
|
|
1070d1dbea | ||
|
|
6cf6b3266f | ||
|
|
f464b30089 | ||
|
|
0fb6b2ae0d | ||
|
|
18c182acc8 | ||
|
|
c9291e3f1c | ||
|
|
00f0cc4847 | ||
|
|
2f8e10b8d8 | ||
|
|
0acb22456c | ||
|
|
22c8ae024e | ||
|
|
5857b569a1 | ||
|
|
9136c04a34 | ||
|
|
87926995df | ||
|
|
66becc983e | ||
|
|
47564d1505 | ||
|
|
4572aa1bc1 | ||
|
|
d36db98974 | ||
|
|
a822d2ad60 | ||
|
|
e3fc5f8bc1 | ||
|
|
386e068890 | ||
|
|
5a674a7db1 | ||
|
|
5984be99b6 | ||
|
|
84962ff33c | ||
|
|
3136e0debf | ||
|
|
7318221e6a | ||
|
|
c3477e88a7 | ||
|
|
f1f27b21b7 | ||
|
|
52455bbc62 | ||
|
|
25a4f66451 | ||
|
|
e0eb7ef3d6 | ||
|
|
2909e8fa2b | ||
|
|
a47658b336 | ||
|
|
42a88a9e3f | ||
|
|
174976d2bb | ||
|
|
911639d1b0 | ||
|
|
5366f235ca | ||
|
|
76b301b4f1 | ||
|
|
49b486a326 | ||
|
|
c39861a600 | ||
|
|
bb42302ba3 | ||
|
|
29217cc2aa | ||
|
|
385478824e | ||
|
|
b0c6d81d89 | ||
|
|
5d66f3108f | ||
|
|
922be2ff36 | ||
|
|
af1f0eaeca | ||
|
|
6b3f99eafd | ||
|
|
cb008706a4 | ||
|
|
9366963e42 | ||
|
|
7ed7b37f9a | ||
|
|
a62a9cd5e0 | ||
|
|
80b75352bf | ||
|
|
c58216f9c3 | ||
|
|
f40a018785 | ||
|
|
cf9bfb8939 | ||
|
|
74db049f85 | ||
|
|
7fde659b42 | ||
|
|
780ab89b61 | ||
|
|
afbdd39bde | ||
|
|
6e159345d8 | ||
|
|
a421d38455 | ||
|
|
c69bc1e395 | ||
|
|
e89a661210 | ||
|
|
1e834010e0 | ||
|
|
4b172c0ca9 | ||
|
|
eb3b7544b5 | ||
|
|
207540303f | ||
|
|
89ed5be8c7 | ||
|
|
57395a772a | ||
|
|
e179caa339 | ||
|
|
621593c39f | ||
|
|
da66b8c08c | ||
|
|
ffed86e8a0 | ||
|
|
719148beaa | ||
|
|
1a487473d7 | ||
|
|
eddca6bdf0 | ||
|
|
226e956fcc | ||
|
|
a88ccb69e7 | ||
|
|
10bdf5c03b | ||
|
|
12cbf9ab61 | ||
|
|
6496b97d21 | ||
|
|
721680cb60 | ||
|
|
c4cf9edd41 | ||
|
|
7f22137bc3 | ||
|
|
fd77eba855 | ||
|
|
e72e90b9cc | ||
|
|
6d070c88b7 | ||
|
|
57f529e902 | ||
|
|
a51b2750aa | ||
|
|
fce04d5907 | ||
|
|
07a21a607a | ||
|
|
3f21ba4d17 | ||
|
|
0c49b09fd7 | ||
|
|
e824caeea3 | ||
|
|
0211f44df9 | ||
|
|
823566244f | ||
|
|
0e80428d48 | ||
|
|
ab3eb196b9 | ||
|
|
bc3da4fed7 | ||
|
|
ed06a424e2 | ||
|
|
bb3b3b7b13 | ||
|
|
affb402ee7 | ||
|
|
7ac37d45c3 | ||
|
|
b3b349a2f0 | ||
|
|
2988aa8fc8 | ||
|
|
4d84e4c2a0 | ||
|
|
d9dfceb279 | ||
|
|
9dfb36962c | ||
|
|
c634e64f27 | ||
|
|
662d5f743a | ||
|
|
fb223c1dbe | ||
|
|
5bb869953e | ||
|
|
97614517a2 | ||
|
|
0a29a74bc8 | ||
|
|
7c695eebd0 | ||
|
|
8f6e6e97f5 | ||
|
|
9c9ca3bcd6 | ||
|
|
bdea3d53c0 | ||
|
|
360dcd4e1e | ||
|
|
5a9136a5c2 | ||
|
|
9fbcd71442 | ||
|
|
7e337944f0 | ||
|
|
31e55f4d12 | ||
|
|
398cf2f8c3 | ||
|
|
028ee9ec23 | ||
|
|
5b1f668e6f | ||
|
|
08626aeecf | ||
|
|
42fba1c7f2 | ||
|
|
3ed90e2b89 | ||
|
|
9e2aa0377f | ||
|
|
4106176aab | ||
|
|
ea93f29654 | ||
|
|
dbd1c027e8 | ||
|
|
77fc5150c7 | ||
|
|
027f109f9f | ||
|
|
1b744a6ae1 | ||
|
|
125e1e26bf | ||
|
|
20dcdb2904 | ||
|
|
0be895d8bd | ||
|
|
f76048b269 | ||
|
|
18150673c3 | ||
|
|
5034855d4d | ||
|
|
1d5c802a9c | ||
|
|
35380e8e24 | ||
|
|
649b513481 | ||
|
|
cb7c760255 | ||
|
|
412cd8a993 | ||
|
|
1c45a18d9b | ||
|
|
0af43628ad | ||
|
|
8d8cdd9206 | ||
|
|
23a48ed9a8 | ||
|
|
261e37d047 | ||
|
|
67d0fb3dce | ||
|
|
c40764b65c | ||
|
|
77be140a45 | ||
|
|
89fb43b83d | ||
|
|
13a08371cf | ||
|
|
732f1bdcbe | ||
|
|
8e560a0ba4 | ||
|
|
406c28d871 | ||
|
|
c9374ec6fb | ||
|
|
072e1123d9 | ||
|
|
e402af803b | ||
|
|
219bcca23a | ||
|
|
91eb48c5b8 | ||
|
|
d0fea8e14c | ||
|
|
d29ead20f6 | ||
|
|
760a91376c | ||
|
|
cf7919aef6 | ||
|
|
2b6058d6f4 | ||
|
|
7693138f56 | ||
|
|
d06e5ee627 | ||
|
|
5eddd06f44 | ||
|
|
e62c148c53 | ||
|
|
bfa498b378 | ||
|
|
ecb78479ce | ||
|
|
70b8a8e81e | ||
|
|
4e6ff9c355 | ||
|
|
2811e56d39 | ||
|
|
cd67d8ac6a | ||
|
|
735b41631d | ||
|
|
203c5a04f6 | ||
|
|
6918993994 | ||
|
|
22782333c9 | ||
|
|
727b3dc5c2 | ||
|
|
76392de698 | ||
|
|
d848adc1cf | ||
|
|
493158174a | ||
|
|
786b4b74f1 | ||
|
|
1f311adf13 | ||
|
|
bd062d155e | ||
|
|
98a3c64cc8 | ||
|
|
6255b9b154 | ||
|
|
2e42f9f215 | ||
|
|
3e57da1681 | ||
|
|
f2f53b718d | ||
|
|
dbf94acf02 | ||
|
|
8712e69130 | ||
|
|
0d27a0f086 | ||
|
|
b9896ea611 | ||
|
|
11d571ed43 | ||
|
|
206ca742ab | ||
|
|
c89bc89cdc | ||
|
|
4b26d38534 | ||
|
|
bd79cc9a7a | ||
|
|
79c3571d2f | ||
|
|
2365174b55 | ||
|
|
32b1e563bb | ||
|
|
f8de460b75 | ||
|
|
ba665bfc9d | ||
|
|
4e8203a066 | ||
|
|
bd2c50aa1d | ||
|
|
d50a599934 | ||
|
|
9d898cb585 | ||
|
|
b6d3065876 | ||
|
|
b2f5ea9065 | ||
|
|
495872e8fa | ||
|
|
760cc543b7 | ||
|
|
abec56ee05 | ||
|
|
bab0752af2 | ||
|
|
320ebd4762 | ||
|
|
48cd9b2989 | ||
|
|
e22112e0a9 | ||
|
|
e85fabf671 | ||
|
|
51f50132d2 | ||
|
|
6ef8028794 | ||
|
|
b5328a81c2 | ||
|
|
63a0c9bdb9 | ||
|
|
2b3c533d09 | ||
|
|
351aed432f | ||
|
|
3367b5739f | ||
|
|
bd50aadf5c | ||
|
|
3e87c3f54e | ||
|
|
35e6bc9df0 | ||
|
|
8ddbad645b | ||
|
|
1736c9b230 | ||
|
|
0b2dc58d5a | ||
|
|
94358c20e9 | ||
|
|
2fba619a67 | ||
|
|
2984f21999 | ||
|
|
f823a8dc62 | ||
|
|
415924bbbd | ||
|
|
e8fdfa5513 | ||
|
|
0721792b93 | ||
|
|
5ab63a8ec9 | ||
|
|
21751a8a58 | ||
|
|
d43be3eba4 | ||
|
|
e64d6a062e | ||
|
|
f3601d8178 | ||
|
|
1ba0b8dcbe | ||
|
|
26269e10bf | ||
|
|
6e1b194c38 | ||
|
|
7c26c19671 | ||
|
|
4ace4f6d5a | ||
|
|
1ec38ff71a | ||
|
|
b48d2faa80 | ||
|
|
00acefea86 | ||
|
|
cce4be4bfb | ||
|
|
f873a6fc99 | ||
|
|
2777e45a95 | ||
|
|
924013b521 | ||
|
|
b44f9f6125 | ||
|
|
aef869aa2a | ||
|
|
18d3c01576 | ||
|
|
830fed0bdc | ||
|
|
bff3d433e2 | ||
|
|
f5fe1c5d65 | ||
|
|
e371032e5e | ||
|
|
595d63c001 | ||
|
|
06fc2c81f9 | ||
|
|
8ec89751bb | ||
|
|
d85c1431a4 | ||
|
|
bd151095b3 | ||
|
|
7e8e28e6e8 | ||
|
|
e6ef239ae6 | ||
|
|
5f54188e5b | ||
|
|
a29378d245 | ||
|
|
346817f3d0 | ||
|
|
f0ecf8c2aa | ||
|
|
a86074e3cd | ||
|
|
0b9f0f25c9 | ||
|
|
7d800e48ae | ||
|
|
a00a7a7f26 | ||
|
|
874e22b8e1 | ||
|
|
18c1abb14f | ||
|
|
6cd217589b | ||
|
|
0e477367ef | ||
|
|
8a3a99ccbd | ||
|
|
291f4f68ea | ||
|
|
7a9a33d16c | ||
|
|
1b0dd83c27 | ||
|
|
b42831b981 | ||
|
|
e8bbb97f96 | ||
|
|
0a9032fc03 | ||
|
|
8bc5723d43 | ||
|
|
37022fa5c2 | ||
|
|
f4f223908c | ||
|
|
f07c4481ff | ||
|
|
e6b9ff7361 | ||
|
|
b3c900803e | ||
|
|
fdbdcec2b1 | ||
|
|
9d122616dd | ||
|
|
f8e99e6012 | ||
|
|
2116d1fe66 | ||
|
|
1cc027666e | ||
|
|
fde3589d1d | ||
|
|
2080824a20 | ||
|
|
11b37bbeae | ||
|
|
41074956a8 | ||
|
|
c63ce5de8c | ||
|
|
17e42e92cf | ||
|
|
debedf26ef | ||
|
|
90c4316a5e | ||
|
|
9782f191b9 | ||
|
|
49fb2f07c0 | ||
|
|
f24277c39e | ||
|
|
452c8370dc | ||
|
|
77179dc183 | ||
|
|
d37a446894 | ||
|
|
7a5b840338 | ||
|
|
50cd91bd86 | ||
|
|
00c8b946a4 | ||
|
|
4c6f043274 | ||
|
|
307c770c58 | ||
|
|
bd0e6bb990 | ||
|
|
0a6729b03d | ||
|
|
9e56ba43a5 | ||
|
|
f76e110c87 | ||
|
|
a8328a8ee7 | ||
|
|
6464900fa1 | ||
|
|
64bd233c49 | ||
|
|
2d4d886a6a | ||
|
|
32b059ae07 | ||
|
|
1af0a1082b | ||
|
|
f34294cf95 | ||
|
|
5d60e56614 | ||
|
|
4d581e92e8 | ||
|
|
3d515ddfb7 | ||
|
|
9161601cac | ||
|
|
09a307b17d | ||
|
|
848d133fe3 | ||
|
|
8f8a6ca527 | ||
|
|
a2af63726e | ||
|
|
8ea13a2b49 | ||
|
|
b67ae48590 | ||
|
|
3dcfa99c4a | ||
|
|
7a5a54d009 | ||
|
|
da7228cedb | ||
|
|
aa7a57ef4e | ||
|
|
c300278328 | ||
|
|
8b3dccce1c | ||
|
|
d323421817 | ||
|
|
7ab80a0162 | ||
|
|
d1b16d5269 | ||
|
|
446b50cbaf | ||
|
|
187cd35e74 | ||
|
|
e95d214143 | ||
|
|
6ae8674615 | ||
|
|
7c01485d2d | ||
|
|
3850acdd23 | ||
|
|
e3424b4350 | ||
|
|
f10e35e8dd | ||
|
|
bc6282b34b | ||
|
|
d8ad8ebc77 | ||
|
|
ab83a94eb4 | ||
|
|
663474516f | ||
|
|
0dfed6de4b | ||
|
|
d73ac59383 | ||
|
|
a47b2440d3 | ||
|
|
7d6f261221 | ||
|
|
473521f5ed | ||
|
|
f1f234b89d | ||
|
|
00d067be47 | ||
|
|
2ba9a03d9a | ||
|
|
14929db6fe | ||
|
|
6ce8963e13 | ||
|
|
364741ef8f | ||
|
|
209cb7cba8 | ||
|
|
02aed5fde4 | ||
|
|
8694c042f7 | ||
|
|
3f86fbc7ad | ||
|
|
fded868f8c | ||
|
|
f1a7a98639 | ||
|
|
ec8354957d | ||
|
|
afeca7cc8f | ||
|
|
f0542553d6 | ||
|
|
cfefaef385 | ||
|
|
90638ce534 | ||
|
|
36b0fa046b | ||
|
|
c1d687f560 | ||
|
|
94f99c35f9 | ||
|
|
61ceeff893 | ||
|
|
ae3bbd2959 | ||
|
|
0702a38e1c | ||
|
|
064d3a7549 | ||
|
|
e32e01eb50 | ||
|
|
c661ae4590 | ||
|
|
7a654b7e7b | ||
|
|
d902c7612b | ||
|
|
979d305afe | ||
|
|
f14acf9fc1 | ||
|
|
c2895ba8a4 | ||
|
|
419c56d012 | ||
|
|
e30931b6d2 | ||
|
|
20653ece8e | ||
|
|
77476edd73 | ||
|
|
e69f2b3fec | ||
|
|
1e61964055 | ||
|
|
f5c83fbb40 | ||
|
|
7819d8262d | ||
|
|
1edf63c617 | ||
|
|
b2ab98a979 | ||
|
|
1b9ab28d29 | ||
|
|
c5cbd2297c | ||
|
|
678922472a | ||
|
|
c9972f678a | ||
|
|
ef850ad302 | ||
|
|
4d620bb3c7 | ||
|
|
e963cfda93 | ||
|
|
4fa9a43e0e | ||
|
|
a9ec68ced6 | ||
|
|
92a1a2c441 | ||
|
|
384e228347 | ||
|
|
35ee34b86a | ||
|
|
2149a0e1ee | ||
|
|
5979d29463 | ||
|
|
e369cf98d3 | ||
|
|
08b7fc68b7 | ||
|
|
44d042edb8 | ||
|
|
8edb25c235 | ||
|
|
f641f0283e | ||
|
|
b76294e528 | ||
|
|
e86bbb0138 | ||
|
|
af4b23b7c4 | ||
|
|
f0068b13a0 | ||
|
|
2e3ff7410c | ||
|
|
ac57537f94 | ||
|
|
1794ba87b3 | ||
|
|
03a9c24330 | ||
|
|
e2dbfca1c3 | ||
|
|
00746f1f92 | ||
|
|
11ec3b64c6 | ||
|
|
eb3c8a25fb | ||
|
|
6cad66c7e7 | ||
|
|
b69ac0cdd3 | ||
|
|
7d854c96c4 | ||
|
|
b572ef45eb | ||
|
|
ac27124243 | ||
|
|
0152b7829a | ||
|
|
7d0393d565 | ||
|
|
76c54a1016 | ||
|
|
1e7ee8b345 | ||
|
|
367e19b751 | ||
|
|
d0241d060c | ||
|
|
ad9bf0af71 | ||
|
|
4f8cf06e57 | ||
|
|
8ef408c746 | ||
|
|
075bbe7e3b | ||
|
|
0a6558eea9 | ||
|
|
19a7814e50 | ||
|
|
44802949da | ||
|
|
d186aefa92 | ||
|
|
7c3e07ab7b | ||
|
|
b49f70fbc3 | ||
|
|
fed039fd54 | ||
|
|
2b1e08431c | ||
|
|
b0e8f260bb | ||
|
|
f7d84dfe76 | ||
|
|
601a41bb60 | ||
|
|
5f183832e1 | ||
|
|
c7b1092a96 | ||
|
|
764c996361 | ||
|
|
2f5ccc5b1a | ||
|
|
3a171493b0 | ||
|
|
655fe8d7f1 | ||
|
|
0c2a6a4f28 | ||
|
|
3d700589c5 | ||
|
|
33f24f1b4d | ||
|
|
5e3f72229c | ||
|
|
544234743e | ||
|
|
fdb5506d41 | ||
|
|
7ff6da8b8b | ||
|
|
ce4563867d | ||
|
|
9c71a3a1a0 | ||
|
|
eddda373d3 | ||
|
|
86f458f01a | ||
|
|
7926366ee6 | ||
|
|
710d7a614c | ||
|
|
a379411d7a | ||
|
|
35abc3e3f5 | ||
|
|
a89ba892a2 | ||
|
|
d1ba57bc23 | ||
|
|
931cfdebb0 | ||
|
|
f7b19553c8 | ||
|
|
6579719a04 | ||
|
|
68f03b5328 | ||
|
|
7fea61f618 | ||
|
|
91d8031c32 | ||
|
|
7b3705ad61 | ||
|
|
9a2a85198a | ||
|
|
cbd3d7da24 | ||
|
|
54f030ae6c | ||
|
|
be31334212 | ||
|
|
41dd60d111 | ||
|
|
e88b898839 | ||
|
|
94fe34f619 | ||
|
|
56803e7c9f | ||
|
|
7a8b8d5fdc | ||
|
|
782600ba7a | ||
|
|
36972b35f5 | ||
|
|
cc027a91fc | ||
|
|
222a75f3e6 | ||
|
|
5823c5f4b5 | ||
|
|
4c16c95b9b | ||
|
|
ac82d8349c | ||
|
|
2f0a15da28 | ||
|
|
0d78538a91 | ||
|
|
1e0845ca5e | ||
|
|
6d204a7bc5 | ||
|
|
622c99fa2f | ||
|
|
aafa386f22 | ||
|
|
29f1280df7 | ||
|
|
5593bd168d | ||
|
|
b14db41126 | ||
|
|
85c1ae1f4b | ||
|
|
ad817795e2 | ||
|
|
2a8ee1f80b | ||
|
|
1b82c101f6 | ||
|
|
7d42bf08a6 | ||
|
|
8d8cf0a41c | ||
|
|
ef496f08e0 | ||
|
|
47b5bc6b64 | ||
|
|
3f3ff4f685 | ||
|
|
dc320d0768 | ||
|
|
c9ca58f504 | ||
|
|
cf8f90e93d | ||
|
|
06fc8c73a5 | ||
|
|
d92496ee02 | ||
|
|
c13e262bb8 | ||
|
|
8d93276423 | ||
|
|
69915a1364 | ||
|
|
179f0c0f47 | ||
|
|
5254a5867d | ||
|
|
2a4b5b0dee | ||
|
|
fea116ea82 | ||
|
|
b6bc5175da | ||
|
|
02ebdd50d0 | ||
|
|
c5800b722d | ||
|
|
0eb5197ecd | ||
|
|
cf0a785029 | ||
|
|
a9a9c89c98 | ||
|
|
f9424a1b88 | ||
|
|
b0467d0697 | ||
|
|
d93e6cf752 | ||
|
|
e00635d430 | ||
|
|
413e817733 | ||
|
|
e37427a24b | ||
|
|
30d534fe32 | ||
|
|
b77b820aa2 | ||
|
|
ce9dd1eaf3 | ||
|
|
6c83a72403 | ||
|
|
54b6efcf25 | ||
|
|
925aa44ebb | ||
|
|
f0f23b5fd0 | ||
|
|
7d77b8ebc0 | ||
|
|
6f0f3a10eb | ||
|
|
f011e59d61 | ||
|
|
d718c76906 | ||
|
|
895d4dce1a | ||
|
|
e146a24f9e | ||
|
|
c66f90b46d | ||
|
|
d4ad137251 | ||
|
|
1e695cf807 | ||
|
|
850f2904dc | ||
|
|
086e386b75 | ||
|
|
452f554193 | ||
|
|
15dc0aba77 | ||
|
|
9cccab3f18 | ||
|
|
36a714b93f | ||
|
|
70609bb3b9 | ||
|
|
10a47781a0 | ||
|
|
ff55a39dd4 | ||
|
|
ae57ea7158 | ||
|
|
ef85e94e40 | ||
|
|
258e735af2 | ||
|
|
19f193f533 | ||
|
|
d5eca2fab1 | ||
|
|
f932c2da6a | ||
|
|
14f94eb34f | ||
|
|
4be8851c16 | ||
|
|
5e4abb30a3 | ||
|
|
f2dd37fab3 | ||
|
|
974981520d | ||
|
|
46bd9ecae8 | ||
|
|
9fcf17b9e6 | ||
|
|
9056a9c89b | ||
|
|
0480fa69d9 | ||
|
|
288e3b86d1 | ||
|
|
8bc4064670 | ||
|
|
9e6e95108d | ||
|
|
375ccd7413 | ||
|
|
d0c76a7eaa | ||
|
|
7462dd68f8 | ||
|
|
9ba91d870c | ||
|
|
ef57ffc2f4 | ||
|
|
1509448a34 | ||
|
|
bb232382cf | ||
|
|
e21dfcb457 | ||
|
|
ae3fb54c02 | ||
|
|
16a8a46f42 | ||
|
|
9cb2892ca9 | ||
|
|
c9c4632a87 | ||
|
|
f2abe516f3 | ||
|
|
cb7d117bdf | ||
|
|
de503bb2d5 | ||
|
|
39b57cbf41 | ||
|
|
66473f03ab | ||
|
|
dbd3721b00 | ||
|
|
565047e93b | ||
|
|
ee4d74a1af | ||
|
|
f2038a8a1a | ||
|
|
a93eeebff0 | ||
|
|
5d57da1755 | ||
|
|
fe44dda809 | ||
|
|
3da5910c23 | ||
|
|
268a483bdb | ||
|
|
6440c64b77 | ||
|
|
2a2ed22e5b | ||
|
|
402ee8636e | ||
|
|
74ba7899fd | ||
|
|
bc5ee36bd8 | ||
|
|
a8c8549015 | ||
|
|
89dc0c66dc | ||
|
|
05495cd1bc | ||
|
|
d905410591 | ||
|
|
9a5e34b546 | ||
|
|
a1b48d0a9e | ||
|
|
bb06c75cb4 | ||
|
|
ea2d9d9167 | ||
|
|
5d267307b2 | ||
|
|
dc625bca33 | ||
|
|
2b0f35b58b | ||
|
|
a9b485da3d | ||
|
|
ebc8ebd638 | ||
|
|
ba82e4ef57 | ||
|
|
6c7c093729 | ||
|
|
3d74bac90b | ||
|
|
74ab0f7878 | ||
|
|
ef4c3984b5 | ||
|
|
51ca0d20ee | ||
|
|
41d2cdc82c | ||
|
|
63d4a7ce8c | ||
|
|
6425a999a6 | ||
|
|
be00e257b8 | ||
|
|
650ae9a074 | ||
|
|
60509b2c3c | ||
|
|
67729990e3 | ||
|
|
9116f5de2d | ||
|
|
018363dac6 | ||
|
|
662d71a57a | ||
|
|
d3807cbd08 | ||
|
|
5cf412aad8 | ||
|
|
a1215c6d6f | ||
|
|
d25a477ffc | ||
|
|
150608a980 | ||
|
|
1df396bbf4 | ||
|
|
a884633723 | ||
|
|
762d855e99 | ||
|
|
19e407df62 | ||
|
|
8c47a03df9 | ||
|
|
4dfb29f9d8 | ||
|
|
e67ea63121 | ||
|
|
60540d2a57 | ||
|
|
a1f58671e5 | ||
|
|
c239490899 | ||
|
|
c30500b66e | ||
|
|
6d26547928 | ||
|
|
261dc508f8 | ||
|
|
a0890c291a | ||
|
|
89ff900e68 | ||
|
|
f469da2606 | ||
|
|
38d099ebd6 | ||
|
|
063bf44a19 | ||
|
|
9c61b389d6 | ||
|
|
2b582676a6 | ||
|
|
ba36ad69f5 | ||
|
|
76be16f6b2 | ||
|
|
2557478d55 | ||
|
|
c68e737c51 | ||
|
|
a95ecf9c9c | ||
|
|
c153fa8d26 | ||
|
|
0f6ea85224 | ||
|
|
d1d63a912a | ||
|
|
55eab4c7e7 | ||
|
|
38fbe6311e | ||
|
|
0b97fc2c8e | ||
|
|
5f5b08b594 | ||
|
|
88bae48ded | ||
|
|
12227fd0ab | ||
|
|
74112e13f7 | ||
|
|
f82bf2276b | ||
|
|
61197d4c12 | ||
|
|
5a53de0eb8 | ||
|
|
9b36fd1f6f | ||
|
|
5ea90dcb46 | ||
|
|
1d5c457c83 | ||
|
|
c0c7854c86 | ||
|
|
3e884bd384 | ||
|
|
103522b72a | ||
|
|
9a08bbf597 | ||
|
|
34018db925 | ||
|
|
843eda19dd | ||
|
|
bfb77b2a00 | ||
|
|
269bb1b221 | ||
|
|
f68849f0d3 | ||
|
|
967619ab09 | ||
|
|
6e7fcdaac7 | ||
|
|
96d6b8bc3f | ||
|
|
3d741cea93 | ||
|
|
9d6cdd9d84 | ||
|
|
7eee0f9164 | ||
|
|
8dc9081244 | ||
|
|
31dc7c2269 | ||
|
|
0ca8add409 | ||
|
|
48cd864a59 | ||
|
|
89b369cd07 | ||
|
|
f78f94c1f0 | ||
|
|
f2f4ade45e | ||
|
|
294b8bd9ec | ||
|
|
4074cf4c9c | ||
|
|
8420e00ee1 | ||
|
|
f767190ce8 | ||
|
|
165db5d28b | ||
|
|
5f1ab9bfa8 | ||
|
|
da51f480ed | ||
|
|
fa494aa8ce | ||
|
|
4e29b31ed8 | ||
|
|
a90e95bb33 | ||
|
|
dfeb15f8e5 | ||
|
|
7733f2b0bb | ||
|
|
5a6b389916 | ||
|
|
59f0b7eddf | ||
|
|
ed1bce988f | ||
|
|
53cb148180 | ||
|
|
f2f00cdb6e | ||
|
|
7bd18faafa | ||
|
|
9869f2f8d5 | ||
|
|
372f96cfc0 | ||
|
|
8038422eda | ||
|
|
dca5d84ae6 | ||
|
|
c5bd3ba96e | ||
|
|
f75837922e | ||
|
|
71fc9cc37b | ||
|
|
6359cb973c | ||
|
|
bafa6d9896 | ||
|
|
7f1310bef5 | ||
|
|
d48cab0fce | ||
|
|
8c7f9e5e9e | ||
|
|
6095e2ae1c | ||
|
|
f24a8e6876 | ||
|
|
a1973e323e | ||
|
|
72d9d86008 | ||
|
|
fec0c7a3b6 | ||
|
|
4619ab6b59 | ||
|
|
4070013d8a | ||
|
|
c8fac05fbe | ||
|
|
0bc03a1dab | ||
|
|
b1c0793bff | ||
|
|
92d4820995 | ||
|
|
6b6b58fa9d | ||
|
|
b8f0b8ec05 | ||
|
|
a8f1f668c1 | ||
|
|
d2d7f17385 | ||
|
|
4b23a1bd44 | ||
|
|
9f40a341cc | ||
|
|
826dfd01fc | ||
|
|
67d8d56dd0 | ||
|
|
b95e04743e | ||
|
|
495010275b | ||
|
|
4b686359ec | ||
|
|
09e72fe917 | ||
|
|
7c019c4157 | ||
|
|
bc44909501 | ||
|
|
f942837785 | ||
|
|
72355be198 | ||
|
|
af1da1c93f | ||
|
|
d0d22f04a7 | ||
|
|
abb81c6eaa | ||
|
|
5b87f62d6a | ||
|
|
b0057e959d | ||
|
|
5e4d6cc5de | ||
|
|
5f4566620f | ||
|
|
e78157908d | ||
|
|
16d32f3730 | ||
|
|
1e7cdbda47 | ||
|
|
7b04b3b27a | ||
|
|
13f3322ae8 | ||
|
|
70b9c34f1a | ||
|
|
69d3f47e34 | ||
|
|
ecbebfab00 | ||
|
|
aecc626634 | ||
|
|
13180db544 | ||
|
|
a7b59b4620 | ||
|
|
ee72bcec69 | ||
|
|
cfa7d1736b | ||
|
|
252d0cb56a | ||
|
|
4e835bafdb | ||
|
|
33f8109dfb | ||
|
|
89e17ec2f1 | ||
|
|
d73f8bf968 | ||
|
|
6ee2699f51 | ||
|
|
23a46dcb65 | ||
|
|
9a04166d9f | ||
|
|
f86a869509 | ||
|
|
e4cadff3f5 | ||
|
|
465c8cb2d4 | ||
|
|
9acc16dde3 | ||
|
|
6fc5f2e979 | ||
|
|
a6665320e9 | ||
|
|
9100cc9bc5 | ||
|
|
6024b0026f | ||
|
|
4320760e8e | ||
|
|
a20afd147e | ||
|
|
cea490ab62 | ||
|
|
20faa3083d | ||
|
|
65ef9e3ac4 | ||
|
|
42e2870410 | ||
|
|
ca3bc07959 | ||
|
|
f21ac8fd04 | ||
|
|
cb36670ce0 | ||
|
|
bc2be1cbdf | ||
|
|
fa4c49e951 | ||
|
|
b6e259e374 | ||
|
|
ab307fe4a6 | ||
|
|
9e8982edb4 | ||
|
|
9afe340f46 | ||
|
|
c07a679d87 | ||
|
|
ba2ef3cb9d | ||
|
|
30537a2ce9 | ||
|
|
328d3cce8c | ||
|
|
b18f9ecee0 | ||
|
|
a5dbc27018 | ||
|
|
c18ae68d65 | ||
|
|
6c22137075 | ||
|
|
41a3d9561d | ||
|
|
e3228c0241 | ||
|
|
b63da42715 | ||
|
|
9d6f729f81 |
No files matched your search
@@ -17,20 +17,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
steps:
|
||||
- name: Cache Qt
|
||||
id: cache-qt-lin
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ github.workspace }}/../Qt
|
||||
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
setup-python: 'false'
|
||||
aqtversion: ==1.1.3
|
||||
# - name: 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
|
||||
@@ -109,30 +109,30 @@ jobs:
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Cache Qt
|
||||
id: cache-qt-win
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ github.workspace }}/../Qt
|
||||
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
|
||||
- name: Install Qt (32 bit)
|
||||
uses: jurplel/install-qt-action@v2
|
||||
if: ${{ matrix.arch == 'Win32' }}
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
arch: win32_msvc2017
|
||||
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
aqtversion: ==0.8
|
||||
- name: Install Qt (64 bit)
|
||||
uses: jurplel/install-qt-action@v2
|
||||
if: ${{ matrix.arch == 'x64' }}
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
arch: win64_msvc2017_64
|
||||
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
aqtversion: ==0.8
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-win
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ${{ github.workspace }}/../Qt
|
||||
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
|
||||
# - name: Install Qt (32 bit)
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# if: ${{ matrix.arch == 'Win32' }}
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# arch: win32_msvc2017
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
# - name: Install Qt (64 bit)
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# if: ${{ matrix.arch == 'x64' }}
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# arch: win64_msvc2017_64
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
|
||||
- name: Configure CMake
|
||||
env:
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=ON -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
- name: Compile
|
||||
@@ -220,20 +220,21 @@ jobs:
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Cache Qt
|
||||
id: cache-qt-mac
|
||||
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-mac.outputs.cache-hit }}
|
||||
setup-python: 'false'
|
||||
aqtversion: ==1.1.3
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-mac
|
||||
# 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-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
|
||||
@@ -46,9 +46,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
steps:
|
||||
- name: Cache Qt
|
||||
id: cache-qt-lin
|
||||
uses: actions/cache@v1
|
||||
# - 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.
|
||||
@@ -56,11 +56,11 @@ jobs:
|
||||
# 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
|
||||
# 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
|
||||
@@ -81,12 +81,12 @@ jobs:
|
||||
# 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
|
||||
# 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.
|
||||
@@ -186,33 +186,33 @@ jobs:
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Cache Qt
|
||||
# Cache Qt
|
||||
id: cache-qt-win
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ github.workspace }}/../Qt
|
||||
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
|
||||
- name: Install Qt (32 bit)
|
||||
# Install Qt 32bit if matrix.arch == Win32
|
||||
uses: jurplel/install-qt-action@v2
|
||||
if: ${{ matrix.arch == 'Win32' }}
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
arch: win32_msvc2017
|
||||
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
aqtversion: ==0.8
|
||||
- name: Install Qt (64 bit)
|
||||
# Install Qt 64bit if matrix.arch == x64
|
||||
uses: jurplel/install-qt-action@v2
|
||||
if: ${{ matrix.arch == 'x64' }}
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
arch: win64_msvc2017_64
|
||||
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
aqtversion: ==0.8
|
||||
# - name: Cache Qt
|
||||
# # Cache Qt
|
||||
# id: cache-qt-win
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ${{ github.workspace }}/../Qt
|
||||
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
|
||||
# - name: Install Qt (32 bit)
|
||||
# # Install Qt 32bit if matrix.arch == Win32
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# if: ${{ matrix.arch == 'Win32' }}
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# arch: win32_msvc2017
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
# - name: Install Qt (64 bit)
|
||||
# # Install Qt 64bit if matrix.arch == x64
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# if: ${{ matrix.arch == 'x64' }}
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# arch: win64_msvc2017_64
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
|
||||
- name: Configure CMake
|
||||
env:
|
||||
@@ -226,7 +226,7 @@ jobs:
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=ON -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
- name: Compile
|
||||
@@ -310,11 +310,104 @@ jobs:
|
||||
${{ steps.generate_package.outputs.package_path }}
|
||||
${{ steps.generate_package.outputs.debug_path }}
|
||||
|
||||
build_mac:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [FastDebug, Release]
|
||||
compiler: [clang]
|
||||
arch: [x86_64]
|
||||
name: Mac
|
||||
needs: create_release
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-mac
|
||||
# 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-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- name: Configure CMake
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
ARCHITECTURE: ${{ matrix.arch }}
|
||||
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
|
||||
- name: Run Tests
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: ${{ matrix.configuration }}
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Package build result
|
||||
working-directory: ./build
|
||||
run: cd bin && tar -cvzf macos-build.tar *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build.tar
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: mac-Release
|
||||
path: builds
|
||||
- name: Download FastDebug builds
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: mac-FastDebug
|
||||
path: builds
|
||||
- name: Create Distribution package
|
||||
id: generate_package
|
||||
working-directory: ./builds
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
- name: Upload result package
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ steps.generate_package.outputs.package_name }}
|
||||
path: ${{ steps.generate_package.outputs.package_path }}
|
||||
- name: Publish result package
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
files: ${{ steps.generate_package.outputs.package_path }}
|
||||
|
||||
post_build:
|
||||
name: Post builds to Nebula and Forum
|
||||
needs: [linux_zip, windows_zip]
|
||||
needs: [linux_zip, windows_zip, mac_zip]
|
||||
uses: ./.github/workflows/post-build-release.yaml
|
||||
with:
|
||||
linux_result: ${{ needs.linux_zip.result }}
|
||||
windows_result: ${{ needs.windows_zip.result }}
|
||||
mac_result: ${{ needs.mac_zip.result }}
|
||||
releaseTag: ${{ github.ref_name }}
|
||||
@@ -17,20 +17,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
steps:
|
||||
- name: Cache Qt
|
||||
id: cache-qt-lin
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ github.workspace }}/../Qt
|
||||
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
setup-python: 'false'
|
||||
aqtversion: ==1.1.3
|
||||
# - name: 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
|
||||
@@ -122,30 +122,30 @@ 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: Cache Qt
|
||||
id: cache-qt-win
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ github.workspace }}/../Qt
|
||||
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
|
||||
- name: Install Qt (32 bit)
|
||||
uses: jurplel/install-qt-action@v2
|
||||
if: ${{ matrix.arch == 'Win32' }}
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
arch: win32_msvc2017
|
||||
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
aqtversion: ==0.8
|
||||
- name: Install Qt (64 bit)
|
||||
uses: jurplel/install-qt-action@v2
|
||||
if: ${{ matrix.arch == 'x64' }}
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
arch: win64_msvc2017_64
|
||||
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
aqtversion: ==0.8
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-win
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ${{ github.workspace }}/../Qt
|
||||
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
|
||||
# - name: Install Qt (32 bit)
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# if: ${{ matrix.arch == 'Win32' }}
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# arch: win32_msvc2017
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
# - name: Install Qt (64 bit)
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# if: ${{ matrix.arch == 'x64' }}
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# arch: win64_msvc2017_64
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
|
||||
- name: Configure CMake
|
||||
env:
|
||||
@@ -159,7 +159,7 @@ jobs:
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_USE_SPEECH="ON" \
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$SIMD" \
|
||||
-DFSO_BUILD_QTFRED=ON -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_BUILD_QTFRED=OFF -DFSO_BUILD_TESTS=ON \
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" -A "$ARCHITECTURE" \
|
||||
-G "Visual Studio 16 2019" -T "v142" ..
|
||||
- name: Compile
|
||||
@@ -234,20 +234,21 @@ jobs:
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Cache Qt
|
||||
id: cache-qt-mac
|
||||
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-mac.outputs.cache-hit }}
|
||||
setup-python: 'false'
|
||||
aqtversion: ==1.1.3
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-mac
|
||||
# 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-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
|
||||
@@ -27,20 +27,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
steps:
|
||||
- name: Cache Qt
|
||||
id: cache-qt-lin
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ github.workspace }}/../Qt
|
||||
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
setup-python: 'false'
|
||||
aqtversion: ==1.1.3
|
||||
# - name: 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
|
||||
|
||||
@@ -10,6 +10,9 @@ on:
|
||||
windows_result: # job.result
|
||||
required: true
|
||||
type: string
|
||||
mac_result: # job.result
|
||||
required: true
|
||||
type: string
|
||||
releaseTag:
|
||||
required: true
|
||||
type: string
|
||||
@@ -55,6 +58,15 @@ jobs:
|
||||
env:
|
||||
LINUX_RESULT: ${{ inputs.linux_result }}
|
||||
WINDOWS_RESULT: ${{ inputs.windows_result }}
|
||||
MAC_RESULT: ${{ inputs.mac_result }}
|
||||
GITHUB_REPO: ${{ github.repository }} # repo this workflow was called from
|
||||
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
|
||||
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
|
||||
NEBULA_USER: ${{ secrets.NEBULA_USER }}
|
||||
NEBULA_PASSWORD: ${{ secrets.NEBULA_PASSWORD }}
|
||||
HLP_API: ${{ secrets.HLP_API }}
|
||||
HLP_KEY: ${{ secrets.HLP_KEY }}
|
||||
RELEASE_TAG: ${{ inputs.releaseTag }}
|
||||
run: python ci/post/main.py release
|
||||
|
||||
- name: Post Builds (Manual trigger)
|
||||
@@ -63,7 +75,8 @@ jobs:
|
||||
env:
|
||||
LINUX_RESULT: success
|
||||
WINDOWS_RESULT: success
|
||||
MAC_RESULT: success
|
||||
run: |
|
||||
echo "releaseTag= ${{ env.RELEASE_TAG }}"
|
||||
echo "repository= ${{ github.repository }}"
|
||||
python ci/post/main.py release
|
||||
python ci/post/main.py release
|
||||
@@ -24,20 +24,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
steps:
|
||||
- name: Cache Qt
|
||||
id: cache-qt-lin
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ github.workspace }}/../Qt
|
||||
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
setup-python: 'false'
|
||||
aqtversion: ==1.1.3
|
||||
# - name: 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
|
||||
@@ -89,30 +89,30 @@ jobs:
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
- name: Cache Qt
|
||||
id: cache-qt-win
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ github.workspace }}/../Qt
|
||||
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
|
||||
- name: Install Qt (32 bit)
|
||||
uses: jurplel/install-qt-action@v2
|
||||
if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'Win32' }}
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
arch: win32_msvc2017
|
||||
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
aqtversion: ==0.8
|
||||
- name: Install Qt (64 bit)
|
||||
uses: jurplel/install-qt-action@v2
|
||||
if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'x64' }}
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
dir: ${{ github.workspace }}/..
|
||||
arch: win64_msvc2017_64
|
||||
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
aqtversion: ==0.8
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-win
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ${{ github.workspace }}/../Qt
|
||||
# key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
|
||||
# - name: Install Qt (32 bit)
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'Win32' }}
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# arch: win32_msvc2017
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
# - name: Install Qt (64 bit)
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# if: ${{ matrix.compiler == 'MSVC' && matrix.arch == 'x64' }}
|
||||
# with:
|
||||
# version: ${{ env.QT_VERSION }}
|
||||
# dir: ${{ github.workspace }}/..
|
||||
# arch: win64_msvc2017_64
|
||||
# cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
|
||||
# aqtversion: ==0.8
|
||||
|
||||
- name: Configure CMake
|
||||
env:
|
||||
@@ -130,7 +130,7 @@ jobs:
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "Visual Studio 16 2019" \
|
||||
-DFSO_BUILD_QTFRED=ON -T "v142" -A "$ARCHITECTURE" ..
|
||||
-DFSO_BUILD_QTFRED=OFF -T "v142" -A "$ARCHITECTURE" ..
|
||||
fi
|
||||
- name: Compile
|
||||
working-directory: ./build
|
||||
@@ -167,20 +167,21 @@ jobs:
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Cache Qt
|
||||
id: cache-qt-mac
|
||||
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-mac.outputs.cache-hit }}
|
||||
setup-python: 'false'
|
||||
aqtversion: ==1.1.3
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-mac
|
||||
# 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-mac.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# py7zrversion: '==0.19.*'
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
[submodule "lib/libRocket"]
|
||||
path = lib/libRocket
|
||||
url = https://github.com/asarium/libRocket.git
|
||||
|
||||
+14
-4
@@ -39,7 +39,13 @@ endif(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||
# Override standard CMake configurations
|
||||
set(CMAKE_CONFIGURATION_TYPES Debug Release FastDebug CACHE STRING "Available configurations" FORCE)
|
||||
|
||||
PROJECT(FS2_Open)
|
||||
set(FSO_LANGUAGES C CXX)
|
||||
|
||||
if(APPLE)
|
||||
set(FSO_LANGUAGES ${FSO_LANGUAGES} OBJC OBJCXX)
|
||||
endif()
|
||||
|
||||
PROJECT(FS2_Open LANGUAGES ${FSO_LANGUAGES})
|
||||
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
# Currently only GCC support ccache properly without generating additional warnings
|
||||
@@ -83,9 +89,11 @@ IF(RESET_INSTALL_PREFIX)
|
||||
ENDIF(NOT $ENV{FS2PATH} STREQUAL "")
|
||||
ENDIF(RESET_INSTALL_PREFIX)
|
||||
|
||||
IF (WIN32)
|
||||
OPTION(FSO_USE_SPEECH "Use Windows specific text-to-speach libraries" ON)
|
||||
IF(WIN32 OR APPLE)
|
||||
OPTION(FSO_USE_SPEECH "Use text-to-speach libraries" ON)
|
||||
ENDIF(WIN32 OR APPLE)
|
||||
|
||||
IF (WIN32)
|
||||
OPTION(FSO_USE_VOICEREC "Enable voice recognition support" ON)
|
||||
|
||||
OPTION(FSO_BUILD_FRED2 "Build FRED2 binary" ON)
|
||||
@@ -208,8 +216,10 @@ include(package)
|
||||
include(doxygen)
|
||||
|
||||
# Print used options to log
|
||||
IF (WIN32)
|
||||
IF(WIN32 OR APPLE)
|
||||
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
|
||||
ENDIF()
|
||||
IF (WIN32)
|
||||
message(STATUS "Using voice recogition: ${FSO_USE_VOICEREC}")
|
||||
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
|
||||
elseif(UNIX)
|
||||
|
||||
+387
@@ -3,7 +3,394 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [22.2.0] - 2022-08-06
|
||||
|
||||
```
|
||||
Changelog note:
|
||||
As of this version, in an attempt to make the changelog easier to navigate and read,
|
||||
each section will have collapsible subsections, ordered alphabetically by topic.
|
||||
Headlining features will always be on top.
|
||||
```
|
||||
### Added
|
||||
|
||||
<details><summary> <b>Big Feature: SEXP Containers</b> </summary>
|
||||
|
||||
> As opposed to a SEXP variable, which stores only one value, a SEXP container stores a collection of values.
|
||||
> Consequently, containers allow for handling data in much more sophisticated ways than variables.
|
||||
> Containers come in two types:
|
||||
> * List container - an ordered sequence of values, sort of a cross between Python lists and deques
|
||||
> * Map container - pairs of keys associated with data, like Lua tables or Python dictionaries
|
||||
> Further details in the [SEXP Containers announcement thread](https://www.hard-light.net/forums/index.php?topic=98209.0)
|
||||
</details>
|
||||
|
||||
<details><summary> <b>Big Feature: LuaAI</b> </summary>
|
||||
|
||||
> LuaAI allows scripters to add a new AI Goal (like ai-chase) that will run script instead of internal logic.
|
||||
> Adding a Lua AI section in a -sexp.tbm and a few functions to a corresponding -sct.tbm to define the AI logic in certain conditions. More documentation on these functions is available in the LuaAISEXP-Object of the Scripting Docs.
|
||||
</details>
|
||||
|
||||
<details><summary>AI:</summary>
|
||||
|
||||
- `$AI ignores aspect lock for leading:` Flag, which lets AI continue to lead their target while performing an Aspect Lock
|
||||
</details>
|
||||
|
||||
<details><summary>Animation: </summary>
|
||||
|
||||
- `pause on reverse` Flag
|
||||
</details>
|
||||
|
||||
<details><summary>Controls: </summary>
|
||||
|
||||
- Handle international keyboard layouts
|
||||
- Re-Add `-joy-info` command line flag, for slightly quicker Joystick GUID retrieval
|
||||
- Add `-controlconfig_tbl` command line flag to print out a template controlconfigdefaults.tbl
|
||||
</details>
|
||||
|
||||
<details><summary>FRED: </summary>
|
||||
|
||||
- Support the full number of nebula poofs using a multi-select list
|
||||
- Add the ability to edit nebula fog colors, since that previously was not part of the FRED UI
|
||||
- Flags `same-arrival-warp-when-docked` and `same-departure-warp-when-docked` to allow docked ships to still use custom warp parameters
|
||||
- Allow highlighting custom-colored events by drawing a border on them
|
||||
- Can now rotate objects relative to other objects in the Object Editor
|
||||
- Dialog to calculate relative distance and orientation between ships
|
||||
- Flag "Point using uvec" to point ships while incorporating the ship's uvec
|
||||
- `ai-attackable-if-no-collide` flag, which prevents turrets from ignoring a target with `no_collide`
|
||||
</details>
|
||||
|
||||
<details><summary>QtFRED: </summary>
|
||||
|
||||
- Reinforcements Dialog
|
||||
- Implemented Replace Data for Number and String
|
||||
- Texture Replacement Dialog
|
||||
- TBL Viewer in the Ship Editor
|
||||
</details>
|
||||
|
||||
<details><summary>Graphics: </summary>
|
||||
|
||||
- Allow particles to use a random chance for spawning through the `+Chance` parameter
|
||||
- Command-line parameter `-fov_cockpit` which allows setting an FoV for the cockpit model separately from the viewport FoV. This allows using custom FoVs without distorting the cockpit
|
||||
- Allow user to export environment map to a PNG from the F3 Lab by pressing M
|
||||
- Weapon lights: Configurable lighting data for weapons, both on a per-weapon basis and globally via lighting profiles
|
||||
- Implemented debug sphere queuing and rendering
|
||||
</details>
|
||||
|
||||
<details><summary>Localization: </summary>
|
||||
|
||||
- Make strings for Match Speed Indicator, Glide Indicator, and Afterburner Indicator translateable
|
||||
</details>
|
||||
|
||||
<details><summary>Modding: </summary>
|
||||
|
||||
- `game_settings.tbl` setting `$Supernova hits at zero:`, which causes Supernovae to hit when the timer gets to 0, instead of the default of hitting 5 seconds before the time is up
|
||||
- `game_settings.tbl` settings `$Show-subtitle uses pixels:` and `$Show-subtitle base resolution:`, which can be used in conjunction to scale subtitles
|
||||
- `game_settings.tbl` setting `$Always warn player about unbound keys used in Directives Gauge:`, to show such warning to players when needed (without it these warnings only apply to Training Missions)
|
||||
- Ship flags `fail-sound-locked-primary` and `fail-sound-locked-secondary` to allow the firing fail sound to play if the player tries to fire weapons that are locked
|
||||
- Subsystem Flag "hide turret from loadout stats"
|
||||
- Allow weapon to override turret name with `$Turret Name:`
|
||||
</details>
|
||||
|
||||
<details><summary>Multiplayer: </summary>
|
||||
|
||||
- Save PXO stats to local pilot file
|
||||
</details>
|
||||
|
||||
<details><summary>Performance: </summary>
|
||||
|
||||
- Preload subspace tunnel if the `mission-set-subspace` SEXP is used in the mission
|
||||
</details>
|
||||
|
||||
<details><summary>SEXPs: </summary>
|
||||
|
||||
- `cancel-future-waves`, for stopping wings that still had waves queued from spawning
|
||||
- Added optional flag to `show-subtitle-text` and `show-subtitle-image` to not change the subtitle aspect ratio
|
||||
- `set-nav-color` and `set-nav-visited-color`, which allows setting custom colors to Navpoints in a mission
|
||||
</details>
|
||||
|
||||
<details><summary>Scripting: </summary>
|
||||
|
||||
- Support for decals (see `decaldefinition` in the Scripting documentation)
|
||||
- Missile list iterator: `mn.getMissileList()`
|
||||
- Campaign Start hook: `On Campaign Begin`
|
||||
- Player Loaded hook: `On Player Loaded`
|
||||
- Added a few functions to get information on HUD gauges (check `HudGauge` in the Scripting documentation)
|
||||
- Function `ship.checkVisibility` which checks if a ship can appear on the viewer's radar
|
||||
- Function `hu.flashTargetBox` which causes the target box to flash
|
||||
- Function `hu.getTargetDistance` to return the distance to target as reported by the HUD
|
||||
- Function `mn.hasLineOfSight` which checks if one point has line of sight to the other
|
||||
- Function `mn.getLineOfSightFirstIntersect` which checks for line of sight and returns the distance of the first interruption if not
|
||||
- Variable `gr.CurrentResizeMode`, which can get or set the scaling mode to be used by the `gr.*` drawing methods
|
||||
- Function `gr.draw3dLine`, which draws a line in space between two points
|
||||
- Allow SCPUI to run `$On Briefing Stage:` hooks
|
||||
- New bindings to allow proper hooking into control actions based on the control's enumeration name
|
||||
- Allow scripted controls to override hardcoded functionality
|
||||
- Fennel script support
|
||||
- Lua BitOp 1.0.2 extension library, allowing the usage of bit operations
|
||||
</details>
|
||||
|
||||
<details><summary>Technical: </summary>
|
||||
|
||||
- Class encapsulation for Volition's linked list
|
||||
- Improve a debug console message to be more informative
|
||||
- Type-safe `TIMESTAMP` class
|
||||
- Add `timestamp_since()` function
|
||||
- Add methods to compare timestamps, calculate deltas from an existing timestamp and a number of milliseconds, and to calculate deltas between timestamps
|
||||
- Create a command line option for logging data packets
|
||||
- Add more information to Multi-related debug logging
|
||||
- Enable Doxygen for QTFred
|
||||
- Set up Mac builds on CI, allowing builds to be published automatically for Mac
|
||||
- Add some logging to `waitAsync`
|
||||
</details>
|
||||
|
||||
### Changed
|
||||
|
||||
<details><summary>Game: </summary>
|
||||
|
||||
- Only display one popup when the player gets to the main hall
|
||||
- Allow an unlimited number of ship flags to be parsed at once
|
||||
</details>
|
||||
|
||||
<details><summary>AI: </summary>
|
||||
|
||||
- Improve Player Orders to allow for a nearly unlimited number of player orders, as opposed to the 32 before
|
||||
- Update `ai_turn_towards_vector` to use a target velocity for banking
|
||||
</details>
|
||||
|
||||
<details><summary>Audio: </summary>
|
||||
|
||||
- Allow unlimited soundtracks and spooled music (Previously limited to 30 and 50 respectively)
|
||||
- Allow unlimited sound effects
|
||||
- Dynamically set the maximum number of audio channels based on how many the user's system can support
|
||||
</details>
|
||||
|
||||
<details><summary>FRED: </summary>
|
||||
|
||||
- CTRL+V is now add-paste (used to be CTRL+P)
|
||||
- CTRL+SHIFT+V is now overwrite-paste (used to be CTRL+V)
|
||||
- Replace `Always_show_goals` with `Toggle_showing_goals` which toggles whether the goals are shown, and works in any mission (instead of only Training Missions)
|
||||
- No longer disable icon dropdowns for models that have their own icons
|
||||
- No longer change the ship class when the icon type is a special popup
|
||||
- Make the number of player orders FRED can handle dynamic
|
||||
- Restore original Error Checking behavior where the function would exit after one check (for consistency)
|
||||
- Exclude player ships from Error Checking for ships in a wing sharing the same orders
|
||||
- Split "No subsystems found" and "Not all subsystems have a record in ships.tbl" warnings into two different warning flags
|
||||
</details>
|
||||
|
||||
<details><summary>Graphics: </summary>
|
||||
|
||||
- Improved light attenuation to look more real
|
||||
- Increase POF vertex limit, allowing up to `2^32 - 1` vertices to be used by a single subobject
|
||||
</details>
|
||||
|
||||
<details><summary>Performance: </summary>
|
||||
|
||||
- Delay `ai_new_maybe_reposition_attack_subsys` to only run once a second. Before this change, it could take around 13% of runtime in crowded missions
|
||||
- Cached subsystem indexing, speeding up subsystem lookups, which run for multiple ships, multiple times per frame
|
||||
</details>
|
||||
|
||||
<details><summary>Scripting: </summary>
|
||||
|
||||
- Enhance help text for Lua SEXPs
|
||||
- Converted the following Lua Hooks to the new format to add documentation: `On Death`, `On Game Init`, `On Ship Collision`
|
||||
</details>
|
||||
|
||||
<details><summary>Technical: </summary>
|
||||
|
||||
- Turn `insertion_sort` into a templated function that uses assignment
|
||||
- CMake: Update `PREBUILT_VERSION_NAME` to latest (mac libs)
|
||||
- Optimized space used in the new POF version
|
||||
- Cleanup model code
|
||||
- Cleanup beam light functions by consolidating some duplicated code and removing unreachable logic
|
||||
- Cleanup wing wave code
|
||||
- Move special parsing functions into new `parsehi.cpp` and `parsehi.h` files
|
||||
- Actually clear delayed SSM parsing data when it's no longer needed
|
||||
- Allow C++ to interact more with LuaTables, allowing it to extract userdata like objects or ships from them
|
||||
- Use `SCP_string` for constructing multi/event log lines
|
||||
- Replace `+Orders Accepted:` Bitfield with flag list
|
||||
- Handle deprecated command line flags programmatically, avoiding lots of code duplication
|
||||
- Set up debug_filter.cfg to have default filters that can be turned off
|
||||
</details>
|
||||
|
||||
### Removed
|
||||
|
||||
<details><summary>FRED: </summary>
|
||||
|
||||
- Remove the `Allow Daisy-Chained Docking` mission flag
|
||||
- Remove "Delete Item" from the right-click menu in the Event Editor
|
||||
</details>
|
||||
|
||||
<details><summary>Technical: </summary>
|
||||
|
||||
- Remove light filtering data which didn't work and increased code complexity
|
||||
- Remove a pointless assert that checked if `SEXP_NODE_INCREMENT` (a define, set at 250) was greater than zero
|
||||
</details>
|
||||
|
||||
### Fixed
|
||||
|
||||
<details><summary>Game: </summary>
|
||||
|
||||
- Missing whitespace in credits
|
||||
- Stopped destroyed submodels from showing in Techroom
|
||||
- Prevent a crash when an object dies in the same frame as their goal
|
||||
- Always record primary bank ammo capacity during ship creation, preventing situations where a ballistic weapon would accidentally be set to zero ammo
|
||||
- Properly remove ships from the Techroom when they're not in the Tech Database
|
||||
- Load the correct Techroom data after a Tech Database Reset
|
||||
- Don't tick Supernova timer while the game is paused
|
||||
- Make `set-camera-facing` use default identity orientation when the `$Use host orientation` flag is active and no host is present
|
||||
- When a hotkey text replacement string refers to an unbound control, use the name of the binding instead of "none"
|
||||
- Fix usage of default tech database flags
|
||||
- Prevent a crash in the loadout screen with a weapons-locked ship
|
||||
- Fix two crashes in the F3 lab
|
||||
- End the campaign properly when a mission is skipped, preventing crashing in some situations
|
||||
- Prevent a crash when a message is sent from an invalid source
|
||||
- Prevent a broken campaign state if the player quits the game from the options menu during the debriefing
|
||||
- Add some checks before converting a message to Command
|
||||
- Prevent accidentally skipping cutscenes caused by hitting the spacebar during a loading screen
|
||||
- Fixed an issue where ships would start with the wrong hull values in Red Alert missions
|
||||
</details>
|
||||
|
||||
<details><summary>AI: </summary>
|
||||
|
||||
- Fix turret swarm weapons by removing a few checks that are no longer valid
|
||||
- Fix a few issues with maneuvers
|
||||
</details>
|
||||
|
||||
<details><summary>Animations: </summary>
|
||||
|
||||
- Fix broken turret animations in the Techroom
|
||||
</details>
|
||||
|
||||
<details><summary>Audio: </summary>
|
||||
|
||||
- Fix cockpit engine sound volume changing unexpectedly
|
||||
- Fix a timing bug that would sometimes prevent music from being initialized when re-playing a mission
|
||||
- Check all possible extensions for audio files
|
||||
</details>
|
||||
|
||||
<details><summary>Controls: </summary>
|
||||
|
||||
- Flush the mouse state after toggling between `Use_mouse_to_fly` states, preventing situations where a stale mouse state would be used
|
||||
- Fix a conflict between Free Look View controls and directional thrust controls
|
||||
</details>
|
||||
|
||||
<details><summary>FRED: </summary>
|
||||
|
||||
- Prevent Ship Select Dialog from crashing if there are too many IFFs
|
||||
- Support saving nebula fog colors
|
||||
- Properly save `nav-carry-status` flag
|
||||
- Don't treat a bare `<argument>` as an error
|
||||
- Prevent adding duplicated variables and display an error to the user when they try
|
||||
- Clean up some parse problems
|
||||
- Fix assignment of alt-name when using the hash
|
||||
- Guard against off-by-one errors in `replace_one` and `replace_all`
|
||||
- Improve error checking of campaign loop branches
|
||||
- Improve error reporting for bad SEXP nodes
|
||||
- Prevent a crash with paste/add-paste when the clipboard was empty
|
||||
- Prevent rounding/conversion issues that caused FRED to think an angle or position was modified when it wasn't
|
||||
- Skip absent ships or wings when running `clear-goals`, instead of stopping the whole operation
|
||||
</details>
|
||||
|
||||
<details><summary>Graphics: </summary>
|
||||
|
||||
- Disable Lightshafts while the Supernova glare effect is active. This partial fix ensures the glare shows up with the correct brightness
|
||||
- Update and correctly load environment maps in F3 Lab
|
||||
- Correctly set textures and Team Colors with `change-ship-class`
|
||||
- Fixes Team Colors not working with `show-ship`
|
||||
- Correct positioning and angles for background bitmaps and suns
|
||||
- Clean up ship arrival and departure effects
|
||||
- Fix clearing a skybox model when it isn't the mission default
|
||||
- Fix an assertion with Fireball LODs which would wrongly trigger if the number of LODs was the same as the maximum
|
||||
</details>
|
||||
|
||||
<details><summary>HUD: </summary>
|
||||
|
||||
- Make HUD Target distance consistent
|
||||
- Fix a crash with scripted HUDs
|
||||
- Correctly update RTT Cockpit Gauges with `change-ship-class`
|
||||
- Ignore HUD brackets with a size of zero or less (instead of just crashing)
|
||||
- Squad menu wasn't scrolling properly with PageDown in some cases
|
||||
- Fix issues with loading of hud config presets
|
||||
- Fix parsing issues with HUD color presets
|
||||
- Continue parsing remaining gauges if one isn't found
|
||||
- Use translated strings both when saving and loading
|
||||
- Fix an issue where a target's orders would be displayed wrongly in the target box
|
||||
- Fix asteroid brackets disappearing or displaying wrong values
|
||||
</details>
|
||||
|
||||
<details><summary>Modding: </summary>
|
||||
|
||||
- Delay processing `$Player Weapon Precedence:` until after parsing, avoiding ships starting with the wrong weapons in some situations
|
||||
- Make the `$Player Weapon Precedence:` list actually give precedence
|
||||
- Empty `+Orders Accepted List:` entries were causing the ship to accept the default orders, instead of no orders as would be correct
|
||||
- Show a Warning if a turret submodel is not an immediate child of the base object and handle it as a single-part object to prevent a crash
|
||||
</details>
|
||||
|
||||
<details><summary>Multiplayer: </summary>
|
||||
|
||||
- Limit client collisions to prevent bugs, such as flinging players with high pings who collided multiple times between packet updates
|
||||
- Fix multiple timestamp issues
|
||||
- Multi messaging and multi pause screen
|
||||
- Make sure maintenance stuff (pings, voice, file xfer, etc.) isn't affected by pausing or time compression
|
||||
- Sync issues caused by options menu and screenshots
|
||||
- Prevent an error with long messages in PXO Chat by using proper buffer size
|
||||
- Fix some issues with Multiplayer SEXPs
|
||||
- Try to handle incompatible sexp packets better
|
||||
- Fix operator name issue with debug messages
|
||||
- Enable the new show-subtitle-text options
|
||||
- Improve interpolation, fixing the jerkiness that used to occur when the interpolation code basically guessed the timing on when packets were coming in
|
||||
- Fix rollback primary collisions, vastly improving accuracy on moving targets even at high pings
|
||||
- Fix the standalone ship being added to ship list
|
||||
- Stop non-printable keys adding text to multi message buffer
|
||||
- Prevent the standalone from crashing if a player tried to switch secondaries in a ship that doesn't have secondaries
|
||||
- Fix a standalone crash from disabled uniform buffer manager
|
||||
- Prevent a crash related to Observer-type players
|
||||
- Fix network issues on MacOS
|
||||
</details>
|
||||
|
||||
<details><summary>Scripting: </summary>
|
||||
|
||||
- Make hook conditions consistent and handle combinations that didn't work properly before
|
||||
- Fix `maybePlayCutscene` arguments
|
||||
- Add `isActive` checks for new-style script hooks
|
||||
- Sync the two `VIRTVAR`s for Orientation in subsystems and submodel instances, which behaved in different ways
|
||||
- Fixed a few timing and framerate related issues for playing movies via script
|
||||
- Ensure the Lua interpreter has enough space in its stack, and allow reserving more space if necessary
|
||||
- Fixed an memory leak in the Lua interpreter caused by string-eval sexps, which never cleaned up the generated code
|
||||
</details>
|
||||
|
||||
<details><summary>SEXPs: </summary>
|
||||
|
||||
- Avoid setting .rest for `Locked_sexp_true/false` with malformed SEXPs
|
||||
- Fix some memory management problems in the `for-*` operators, avoiding a memory leak
|
||||
- Fix crash when removing form-on-wing order with `remove-goal`
|
||||
- Fix `show-subtitle` SEXP which was missing the `width` argument
|
||||
- Reset volumes changed via `adjust-audio-volume` when the mission closes
|
||||
- Prevent too many dynamic SEXPs from breaking the SEXP system
|
||||
</details>
|
||||
|
||||
<details><summary>Technical: </summary>
|
||||
|
||||
- Check if index is valid before accessing `Weapon_info`, preventing CTDs under certain conditions
|
||||
- When `weapon_create` was called while `MAX_WEAPONS` was reached, the previous algorithm didn't achieve desired results, and simply locked up the game. Instead, we now simply won't allow a new weapon to be created in such condition
|
||||
- Refactored Supernova code and fixed some state transition issues in it
|
||||
- Prevent crashes in the event of a subsystem mismatch during `change_ship_type`
|
||||
- Change include order to fix compilation of unit tests on Mac
|
||||
- Patch freeing of SEXP nodes, preventing a crash in certain conditions
|
||||
- Fix a memory leak in model code
|
||||
- Fix a crash in the Ship Creation code if a ship's name was exactly the maximum allowed length
|
||||
- Removed vestigial bit-depth asserts for aabitmaps, preventing crashes with certain image types
|
||||
- Prevent a crash when Escort Priority was parsed for a ship not present in the Escort List
|
||||
- Fix a bunch of graphics functions to respect GR_STUB, preventing problems in standalone server
|
||||
- Clean up line endings in several files (replaced CRLF with LF basically everywhere)
|
||||
- Fixed a timestamp issue which helps lay the groundwork to add In-Game Joining to multiplayer
|
||||
- Prevent pilot and campaign files from having invalid values, by clamping them within the expected ranges when saving and loading
|
||||
- Also warn the player if such an invalid value was detected, telling them which setting had the wrong value and what it was reset to
|
||||
- Try to avoid assertions by preventing invalid types from being handled by `obj_team()`
|
||||
- Shut down the SEXP system before the Scripting system, otherwise a crash could happen if the SEXP system held references to Lua
|
||||
</details>
|
||||
|
||||
----
|
||||
|
||||
## [22.0.0] - 2022-04-01 ([Thread](https://www.hard-light.net/forums/index.php?topic=98125.0))
|
||||
### Changed
|
||||
- Controls5 PR (aka multi-joy)
|
||||
|
||||
@@ -133,7 +133,7 @@ if ($DeployBuild) {
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
|
||||
-DQT5_INSTALL_ROOT="$($buildConfig.QtDir)" -DFSO_BUILD_QTFRED=ON `
|
||||
-DQT5_INSTALL_ROOT="$($buildConfig.QtDir)" -DFSO_BUILD_QTFRED=OFF `
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" `
|
||||
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
|
||||
|
||||
@@ -153,7 +153,7 @@ if ($DeployBuild) {
|
||||
Push-AppveyorArtifact "$($PackageName)-debug-$($buildConfig.PackageType).7z"
|
||||
} else {
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
|
||||
-DFSO_BUILD_QTFRED=ON -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="ON" `
|
||||
-DFSO_BUILD_QTFRED=OFF -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="ON" `
|
||||
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
|
||||
|
||||
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
|
||||
|
||||
@@ -43,5 +43,5 @@ if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
fi
|
||||
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=ON \
|
||||
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=OFF \
|
||||
-DSHADERS_ENABLE_COMPILATION=ON ..
|
||||
+1
-1
@@ -40,7 +40,7 @@ class ForumAPI:
|
||||
"body": content
|
||||
})
|
||||
|
||||
if resp.text != "OK":
|
||||
if resp.status_code != 200:
|
||||
print("Post failed! Response: %s" %resp.text)
|
||||
|
||||
return resp.json()
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ MAJOR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_MAJO
|
||||
MINOR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_MINOR (\d+)\)")
|
||||
BUILD_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_BUILD (\d+)\)")
|
||||
REVISION_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_REVISION (\d+)\)")
|
||||
REVISION_STR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_REVISION_STR (\w+)\)")
|
||||
REVISION_STR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_REVISION_STR (\w*)\)")
|
||||
|
||||
LOG_FORMAT = """
|
||||
------------------------------------------------------------------------%n
|
||||
|
||||
+25
-18
@@ -7,6 +7,13 @@ import requests
|
||||
from file_list import ReleaseFile
|
||||
from util import retry_multi, GLOBAL_TIMEOUT
|
||||
|
||||
LINUX_KEY = "Linux"
|
||||
MACOSX_KEY = "Mac"
|
||||
WIN32_SSE2_KEY = "Win32-SSE2"
|
||||
WIN64_SSE2_KEY = "Win64-SSE2"
|
||||
WIN32_AVX_KEY = "Win32-AVX"
|
||||
WIN64_AVX_KEY = "Win64-AVX"
|
||||
|
||||
metadata = {
|
||||
'type': 'engine',
|
||||
'title': 'FSO',
|
||||
@@ -26,28 +33,28 @@ metadata = {
|
||||
}
|
||||
|
||||
platforms = {
|
||||
'Linux': 'linux',
|
||||
'MacOSX': 'macosx',
|
||||
'Win32-SSE2': 'windows',
|
||||
'Win64-SSE2': 'windows',
|
||||
'Win32-AVX': 'windows',
|
||||
'Win64-AVX': 'windows'
|
||||
LINUX_KEY: 'linux',
|
||||
MACOSX_KEY: 'macosx',
|
||||
WIN32_SSE2_KEY: 'windows',
|
||||
WIN64_SSE2_KEY: 'windows',
|
||||
WIN32_AVX_KEY: 'windows',
|
||||
WIN64_AVX_KEY: 'windows'
|
||||
}
|
||||
|
||||
envs = {
|
||||
'Linux': 'linux && x86_64', # Linux only has 64bit builds
|
||||
'MacOSX': 'macosx',
|
||||
'Win32-SSE2': 'windows',
|
||||
'Win64-SSE2': 'windows && x86_64',
|
||||
'Win32-AVX': 'windows && avx',
|
||||
'Win64-AVX': 'windows && avx && x86_64'
|
||||
LINUX_KEY: 'linux && x86_64', # Linux only has 64bit builds
|
||||
MACOSX_KEY: 'macosx',
|
||||
WIN32_SSE2_KEY: 'windows',
|
||||
WIN64_SSE2_KEY: 'windows && x86_64',
|
||||
WIN32_AVX_KEY: 'windows && avx',
|
||||
WIN64_AVX_KEY: 'windows && avx && x86_64'
|
||||
}
|
||||
|
||||
subdirs = {
|
||||
'Win32-SSE2': 'x86',
|
||||
'Win64-SSE2': 'x64',
|
||||
'Win32-AVX': 'x86_avx',
|
||||
'Win64-AVX': 'x64_avx'
|
||||
WIN32_SSE2_KEY: 'x86',
|
||||
WIN64_SSE2_KEY: 'x64',
|
||||
WIN32_AVX_KEY: 'x86_avx',
|
||||
WIN64_AVX_KEY: 'x64_avx'
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +110,7 @@ def render_nebula_release(version, stability, files, config):
|
||||
'filename': dest_fn
|
||||
})
|
||||
|
||||
if group == 'Linux' and fn.endswith('.AppImage'):
|
||||
if group == LINUX_KEY and fn.endswith('.AppImage'):
|
||||
if 'qtfred' in fn:
|
||||
if '-FASTDBG' in fn:
|
||||
label = 'QtFRED Debug'
|
||||
@@ -128,7 +135,7 @@ def render_nebula_release(version, stability, files, config):
|
||||
'label': label,
|
||||
'properties': props,
|
||||
})
|
||||
elif group == 'MacOSX' and fn.startswith(os.path.basename(fn) + '.app/'):
|
||||
elif group == MACOSX_KEY and fn.startswith(os.path.basename(fn) + '.app/'):
|
||||
if 'qtfred' in fn:
|
||||
if '-FASTDBG' in fn:
|
||||
label = 'QtFRED Debug'
|
||||
|
||||
@@ -9,18 +9,18 @@ PLACEHOLDER
|
||||
|
||||
Deprecations are a mechanism in FSO where a certain feature or aspect of the engine has changed or is no longer supported. Since this would normally break existing mods we have the mod table feature "[tt]$Target Version:[/tt]" with which a mod can specify what version of FSO it was developed with. The features listed above will be removed or changed when the target version of a mod is at least the version released in this post.
|
||||
|
||||
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=97293.0]21.0 Release Thread[/url][/size]
|
||||
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=98360.0]22.2.0 Release Thread[/url][/size]
|
||||
|
||||
Launchers, if you don't have one already:
|
||||
[b]All platforms: [/b] For every day use, we recommend [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url], an integrated solution for downloading and launching mods.
|
||||
|
||||
[hidden=Alternative Launchers]
|
||||
Cross-platform: [url=http://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] (ongoing project for a unified launcher, you should upgrade to the latest RC/test build if you have not yet)
|
||||
[b]Important:[/b] For best compatibility with FSO 3.8 and later you should use at least wxLauncher 0.12.
|
||||
|
||||
Windows: [url=http://scp.fsmods.net/files/Launcher55g.zip]Launcher 5.5g[/url] ([url=http://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=http://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
|
||||
OS X: Soulstorm's [url=http://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
|
||||
Linux: [url=http://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=http://www.hard-light.net/wiki/index.php/Fs2_open_on_Linux/Graphics_Settings]by hand[/url] or whatever you can figure out.[/hidden]
|
||||
Windows: [url=http://scp.fsmods.net/builds/Launcher55g.zip]Launcher 5.5g[/url] ([url=http://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=https://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
|
||||
OS X: Soulstorm's [url=https://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
|
||||
Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=https://www.hard-light.net/wiki/index.php/Fs2_open_on_Linux/Graphics_Settings]by hand[/url] or whatever you can figure out.[/hidden]
|
||||
|
||||
[img]http://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
|
||||
[size=8pt]Compiled using GitHub Actions on Windows Server 2019 (10.0.17763), Visual Studio Enterprise 2019[/size]
|
||||
@@ -40,7 +40,7 @@ Linux: [url=http://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/
|
||||
[size=8pt]This one is based on the AVX Optimizations from the MSVC Compiler.[/size]
|
||||
|
||||
[b]What are those SSE, SSE2 and AVX builds I keep seeing everywhere?[/b]
|
||||
[url=http://www.hard-light.net/forums/index.php?topic=65628.0]Your answer is in this topic.[/url]
|
||||
[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!
|
||||
[/hidden]
|
||||
|
||||
@@ -48,7 +48,7 @@ Don't want to deal with that? Use [url=https://www.hard-light.net/forums/index.p
|
||||
[size=8pt]Compiled with Ubuntu 16.04 LTS 64-bit, GCC 5[/size]
|
||||
${build(groups["Linux"].mainFile)}
|
||||
|
||||
These builds use a mechanism called [url=http://appimage.org/]AppImage[/url] which should allow these builds to run on most Linux distributions. However, we recommend that you compile your own builds which will result in less issues.
|
||||
These builds use a mechanism called [url=https://appimage.org/]AppImage[/url] which should allow these builds to run on most Linux distributions. However, we recommend that you compile your own builds which will result in less issues.
|
||||
Alternatively, if there is a package in your software repository then you should use that. If you are the maintainer of such a package for a distribution then let us know and we will include that here.
|
||||
|
||||
|
||||
@@ -59,10 +59,10 @@ Alternatively, if there is a package in your software repository then you should
|
||||
[size=12pt]Important!![/size]
|
||||
An external DLL is required for FSO to use TrackIR functions. The following DLL is simply unpacked in to your main FreeSpace2 root dir.
|
||||
TrackIR is only supported on Windows.
|
||||
[url=http://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=http://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
|
||||
[url=https://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=http://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
|
||||
|
||||
Known issues:
|
||||
[list]
|
||||
[li][url=https://github.com/scp-fs2open/fs2open.github.com/issues]Github issues[/url] and [url=https://github.com/scp-fs2open/fs2open.github.com/pulls]pending pull requests[/url][/li]
|
||||
[li]See the list of [url=http://scp.indiegames.us/mantis/search.php?project_id=1&status_id%5B%5D=10&status_id%5B%5D=20&status_id%5B%5D=30&status_id%5B%5D=40&status_id%5B%5D=50&priority_id%5B%5D=40&priority_id%5B%5D=50&priority_id%5B%5D=60&sticky_issues=on&sortby=last_updated&dir=DESC&per_page=200&hide_status_id=-2]Fix for next release[/url] bugs - mark a bug as an elevated priority (high, urgent, immediate) to get it included in that filter.[/li]
|
||||
[li]See the list of [url=https://github.com/scp-fs2open/fs2open.github.com/projects/8]bugs ranked by priority[/url][/li]
|
||||
[/list]
|
||||
@@ -1,3 +1,3 @@
|
||||
Mako==1.1.5
|
||||
Mako==1.2.2
|
||||
requests==2.26.0
|
||||
semantic-version==2.8.5
|
||||
@@ -31,7 +31,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
cd ..
|
||||
done
|
||||
else
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON ..
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=OFF ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
buildType:
|
||||
default: release
|
||||
description: R
|
||||
choices:
|
||||
release:
|
||||
short: Release
|
||||
long: Release builds
|
||||
buildType: Release
|
||||
fastDebug:
|
||||
short: FastDebug
|
||||
long: Debug with optimizations
|
||||
buildType: FastDebug
|
||||
debug:
|
||||
short: Debug
|
||||
long: Debug without optimizations
|
||||
buildType: Debug
|
||||
@@ -9,6 +9,8 @@ if (WIN32)
|
||||
if (NOT HAVE_SAPI_H)
|
||||
message(SEND_ERROR "sapi.h could not be found on your platform. Please disable speech support.")
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
# it should just work
|
||||
else()
|
||||
message(SEND_ERROR "Text to Speech is not supported on this platform!")
|
||||
endif()
|
||||
|
||||
@@ -10,6 +10,7 @@ SET(WIN32_LIBS
|
||||
winmm
|
||||
ws2_32
|
||||
psapi
|
||||
shlwapi
|
||||
)
|
||||
|
||||
IF (MINGW)
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
endif()
|
||||
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 22)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 1)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 3)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 0)
|
||||
|
||||
# A numeric revision e.g. the CI build number
|
||||
|
||||
@@ -68,6 +68,10 @@ target_link_libraries(code PUBLIC variant)
|
||||
|
||||
target_link_libraries(code PUBLIC any)
|
||||
|
||||
target_link_libraries(code PUBLIC optional)
|
||||
|
||||
target_link_libraries(code PUBLIC imgui)
|
||||
|
||||
# Headers for standalone "gui" on UNIX
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${MONGOOSE_LIBS})
|
||||
|
||||
@@ -18,7 +18,7 @@ struct ProgramLocals {
|
||||
matrix localOrient = vmd_identity_matrix;
|
||||
int hostSubobject = -1;
|
||||
|
||||
int waitTimestamp = 0;
|
||||
TIMESTAMP waitTimestamp = TIMESTAMP::invalid();
|
||||
|
||||
expression::ProgramVariables variables;
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ WaitAction::~WaitAction() = default;
|
||||
|
||||
ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
|
||||
{
|
||||
if (!timestamp_valid(locals.waitTimestamp)) {
|
||||
if (!locals.waitTimestamp.isValid()) {
|
||||
auto waitTime = _waitTimeExpression.execute(locals.variables);
|
||||
|
||||
// Catch errors in the expression
|
||||
@@ -28,7 +28,7 @@ ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
|
||||
waitTime = 0.001f;
|
||||
}
|
||||
|
||||
locals.waitTimestamp = timestamp(fl2i(waitTime * TIMESTAMP_FREQUENCY));
|
||||
locals.waitTimestamp = _timestamp(fl2i(waitTime * MILLISECONDS_PER_SECOND));
|
||||
}
|
||||
if (!timestamp_elapsed(locals.waitTimestamp)) {
|
||||
// Wait until the timestamp is elapsed
|
||||
@@ -36,7 +36,7 @@ ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
|
||||
}
|
||||
// Timestamp is elapsed. The timestamp is elapsed so that timestamp_valid above returns false for the next wait
|
||||
// action
|
||||
locals.waitTimestamp = 0;
|
||||
locals.waitTimestamp = TIMESTAMP::invalid();
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
std::unique_ptr<Action> WaitAction::clone() const
|
||||
|
||||
@@ -52,34 +52,6 @@ void ai_free_slot(int ai_index)
|
||||
Ai_info[ai_index].shipnum = -1;
|
||||
}
|
||||
|
||||
int get_wingnum(int objnum)
|
||||
{
|
||||
int shipnum, ai_index;
|
||||
|
||||
shipnum = Objects[objnum].instance;
|
||||
|
||||
ai_index = Ships[shipnum].ai_index;
|
||||
|
||||
return Ai_info[ai_index].wing;
|
||||
}
|
||||
|
||||
void set_wingnum(int objnum, int wingnum)
|
||||
{
|
||||
int shipnum, ai_index;
|
||||
|
||||
Assert(Objects[objnum].type == OBJ_SHIP);
|
||||
|
||||
shipnum = Objects[objnum].instance;
|
||||
|
||||
Assert((shipnum >= 0) && (shipnum < MAX_SHIPS));
|
||||
|
||||
ai_index = Ships[shipnum].ai_index;
|
||||
|
||||
Assert( (ai_index >= 0) && (ai_index < MAX_AI_INFO) );
|
||||
|
||||
Ai_info[ai_index].wing = wingnum;
|
||||
}
|
||||
|
||||
const char *ai_get_goal_target_name(const char *name, int *index)
|
||||
{
|
||||
Assertion(name != nullptr && index != nullptr, "Arguments cannot be null!");
|
||||
|
||||
+9
-61
@@ -12,6 +12,7 @@
|
||||
#ifndef _AI_H
|
||||
#define _AI_H
|
||||
|
||||
#include "ai/aigoals.h"
|
||||
#include "ai/ai_profiles.h"
|
||||
#include "globalincs/globals.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
@@ -33,8 +34,8 @@ typedef struct ai_flag_name {
|
||||
char flag_name[TOKEN_LENGTH];
|
||||
} ai_flag_name;
|
||||
|
||||
#define MAX_AI_FLAG_NAMES 2
|
||||
extern ai_flag_name Ai_flag_names[];
|
||||
extern const int Num_ai_flag_names;
|
||||
|
||||
// dock_orient_and_approach() modes.
|
||||
#define DOA_APPROACH 1 // Approach the current point on the path (aip->path_cur)
|
||||
@@ -55,18 +56,6 @@ extern ai_flag_name Ai_flag_names[];
|
||||
#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
|
||||
|
||||
#define MAX_AI_GOALS 5
|
||||
|
||||
// types of ai goals -- tyese types will help us to determination on which goals should
|
||||
// have priority over others (i.e. when a player issues a goal to a wing, then a seperate
|
||||
// goal to a ship in that wing). We would probably use this type in conjunction with
|
||||
// goal priority to establish which goal to follow
|
||||
#define AIG_TYPE_EVENT_SHIP 1 // from mission event direct to ship
|
||||
#define AIG_TYPE_EVENT_WING 2 // from mission event direct to wing
|
||||
#define AIG_TYPE_PLAYER_SHIP 3 // from player direct to ship
|
||||
#define AIG_TYPE_PLAYER_WING 4 // from player direct to wing
|
||||
#define AIG_TYPE_DYNAMIC 5 // created on the fly
|
||||
|
||||
// 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
|
||||
@@ -76,39 +65,7 @@ extern ai_flag_name Ai_flag_names[];
|
||||
|
||||
#define KAMIKAZE_HULL_ON_DEATH -1000.0f // Hull strength ship gets set to if it crash-dies.
|
||||
|
||||
// structure for AI goals
|
||||
typedef struct ai_goal {
|
||||
int signature; // Unique identifier. All goals ever created (per mission) have a unique signature.
|
||||
int ai_mode; // one of the AIM_* modes for this goal
|
||||
int ai_submode; // maybe need a submode
|
||||
int type; // one of the AIG_TYPE_* values above
|
||||
flagset<AI::Goal_Flags> flags; // one of the AIGF_* values above
|
||||
fix time; // time at which this goal was issued.
|
||||
int priority; // how important is this goal -- number 0 - 100
|
||||
|
||||
const char *target_name; // name of the thing that this goal acts upon
|
||||
int target_name_index; // index of goal_target_name in Goal_target_names[][]
|
||||
waypoint_list *wp_list; // waypoints that this ship might fly.
|
||||
int target_instance; // instance of thing this ship might be chasing (currently only used for weapons; note, not the same as objnum!)
|
||||
int target_signature; // signature of object this ship might be chasing (currently only used for weapons; paired with above value to confirm target)
|
||||
|
||||
// unions for docking stuff.
|
||||
// (AIGF_DOCKER_INDEX_VALID and AIGF_DOCKEE_INDEX_VALID tell us to use indexes; otherwise we use names)
|
||||
// these are the dockpoints used on the docker and dockee ships, not the ships themselves
|
||||
union {
|
||||
const char *name;
|
||||
int index;
|
||||
} docker;
|
||||
|
||||
union {
|
||||
const char *name;
|
||||
int index;
|
||||
} dockee;
|
||||
|
||||
object_ship_wing_point_team lua_ai_target;
|
||||
|
||||
} ai_goal;
|
||||
|
||||
// individual AI modes aka AI behaviors
|
||||
#define AIM_CHASE 0
|
||||
#define AIM_EVADE 1
|
||||
#define AIM_GET_BEHIND 2 // This mode is not actually implemented.
|
||||
@@ -138,8 +95,7 @@ typedef struct ai_goal {
|
||||
#define MAX_WAYPOINTS_PER_LIST 20
|
||||
#define MAX_ENEMY_DISTANCE 2500.0f // Maximum distance from which a ship will pursue an enemy.
|
||||
|
||||
#define AI_GOAL_NONE -1
|
||||
|
||||
#define MAX_AI_GOALS 5
|
||||
#define AI_ACTIVE_GOAL_DYNAMIC 999
|
||||
|
||||
typedef struct ai_class {
|
||||
@@ -277,8 +233,6 @@ extern pnode *Ppfp; // Free pointer in path points.
|
||||
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 type; //
|
||||
int wing; // Member of what wing? -1 means none.
|
||||
|
||||
int behavior; // AI behavior; vestigial field from early development of FS1
|
||||
int mode;
|
||||
@@ -504,9 +458,12 @@ typedef struct ai_info {
|
||||
int multilock_check_timestamp; // when to check for multilock next
|
||||
SCP_vector<std::pair<int, ship_subsys*>> ai_missile_locks_firing; // a list of missile locks (locked objnum, locked subsys) the ai is currently firing
|
||||
|
||||
object_ship_wing_point_team lua_ai_target;
|
||||
ai_lua_parameters lua_ai_target;
|
||||
} ai_info;
|
||||
|
||||
int ai_maybe_autoscale(int absolute_index = -1);
|
||||
int ai_get_autoscale_index(int absolute_index = -1);
|
||||
|
||||
// Goober5000
|
||||
typedef struct {
|
||||
vec3d docker_point;
|
||||
@@ -531,11 +488,6 @@ typedef struct {
|
||||
|
||||
extern int Mission_all_attack; // !0 means all teams attack all teams.
|
||||
|
||||
extern void update_ai_info_for_hit(int hitter_obj, int hit_obj);
|
||||
extern void ai_frame_all(void);
|
||||
|
||||
extern int find_guard_obj(void);
|
||||
|
||||
extern ai_info Ai_info[];
|
||||
extern ai_info *Player_ai;
|
||||
|
||||
@@ -546,7 +498,6 @@ extern int Num_ai_classes;
|
||||
extern int Ai_firing_enabled;
|
||||
|
||||
extern const char *Skill_level_names(int skill_level, int translate = 1);
|
||||
extern int Ai_goal_signature;
|
||||
|
||||
extern control_info AI_ci;
|
||||
|
||||
@@ -570,9 +521,6 @@ void ai_object_init(object * obj, int ai_index);
|
||||
// Called once a frame
|
||||
void ai_process( object * obj, int ai_index, float frametime );
|
||||
|
||||
int get_wingnum(int objnum);
|
||||
|
||||
void set_wingnum(int objnum, int wingnum);
|
||||
const char *ai_get_goal_target_name(const char *name, int *index);
|
||||
void ai_clear_goal_target_names();
|
||||
|
||||
@@ -687,6 +635,6 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip);
|
||||
void ai_formation_object_recalculate_slotnums(int form_objnum, int exiting_objnum = -1);
|
||||
|
||||
|
||||
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*>&& excluded_objects = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr);
|
||||
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*>&& excluded_objects = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
|
||||
|
||||
#endif
|
||||
@@ -145,6 +145,11 @@ namespace AI {
|
||||
Prevent_negative_turret_ammo,
|
||||
Fix_keep_safe_distance,
|
||||
Ignore_aspect_when_leading,
|
||||
Fix_good_rearm_time_bug,
|
||||
No_continuous_turn_on_attack,
|
||||
Fixed_removing_play_dead_order,
|
||||
Disable_bay_emerge_timeout,
|
||||
Adjusted_AI_class_autoscale,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
@@ -600,6 +600,16 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$AI ignores aspect lock for leading:", AI::Profile_Flags::Ignore_aspect_when_leading);
|
||||
|
||||
set_flag(profile, "$fix good-rearm-time bug:", AI::Profile_Flags::Fix_good_rearm_time_bug);
|
||||
|
||||
set_flag(profile, "$no continuous turn on attack:", AI::Profile_Flags::No_continuous_turn_on_attack);
|
||||
|
||||
set_flag(profile, "$remove-goal properly removes play-dead order:", AI::Profile_Flags::Fixed_removing_play_dead_order);
|
||||
|
||||
set_flag(profile, "$bay arrivals not time limited:", AI::Profile_Flags::Disable_bay_emerge_timeout);
|
||||
|
||||
set_flag(profile, "$use adjusted AI class autoscale:", AI::Profile_Flags::Adjusted_AI_class_autoscale);
|
||||
|
||||
|
||||
// if we've been through once already and are at the same place, force a move
|
||||
if (saved_Mp && (saved_Mp == Mp))
|
||||
@@ -768,4 +778,9 @@ void ai_profile_t::reset()
|
||||
flags.set(AI::Profile_Flags::Prevent_negative_turret_ammo);
|
||||
flags.set(AI::Profile_Flags::Fix_keep_safe_distance);
|
||||
}
|
||||
if (mod_supports_version(23, 0, 0)) {
|
||||
flags.set(AI::Profile_Flags::Fix_good_rearm_time_bug);
|
||||
flags.set(AI::Profile_Flags::No_continuous_turn_on_attack);
|
||||
flags.set(AI::Profile_Flags::Fixed_removing_play_dead_order);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
#define AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL 0
|
||||
#define AI_RANGE_AWARE_SEC_SEL_MODE_AWARE 1
|
||||
|
||||
#define MAX_AI_PROFILES 5
|
||||
#define MAX_AI_PROFILES 8
|
||||
|
||||
class ai_profile_t {
|
||||
public:
|
||||
|
||||
+44
-17
@@ -661,16 +661,17 @@ int ai_big_maybe_start_strafe(ai_info *aip, ship_info *sip)
|
||||
// are near
|
||||
if ( sip->is_small_ship() ) {
|
||||
if ( timestamp_elapsed(aip->scan_for_enemy_timestamp) ) {
|
||||
ship_obj *so;
|
||||
object *test_objp;
|
||||
ship *test_sp;
|
||||
float dist_squared;
|
||||
|
||||
aip->scan_for_enemy_timestamp = timestamp(SCAN_FIGHTERS_INTERVAL);
|
||||
// iterate through ships, and see if any fighter/bomber from opposite team are near
|
||||
so = GET_FIRST(&Ship_obj_list);
|
||||
while( so != END_OF_LIST(&Ship_obj_list) ) {
|
||||
for (auto so: list_range(&Ship_obj_list)) {
|
||||
test_objp = &Objects[so->objnum];
|
||||
if (test_objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
|
||||
test_sp = &Ships[test_objp->instance];
|
||||
|
||||
if ( iff_x_attacks_y(Ships[Pl_objp->instance].team, test_sp->team) ) {
|
||||
@@ -681,7 +682,6 @@ int ai_big_maybe_start_strafe(ai_info *aip, ship_info *sip)
|
||||
}
|
||||
}
|
||||
}
|
||||
so = GET_NEXT(so);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -706,6 +706,9 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
if (Pl_objp->phys_info.speed < 3.0f) {
|
||||
object *objp;
|
||||
for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
|
||||
if (objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
|
||||
if ((objp->type == OBJ_WEAPON) && (iff_x_attacks_y(Ships[Pl_objp->instance].team, Weapons[objp->instance].team)))
|
||||
if (Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_LASER) {
|
||||
vec3d in_vec;
|
||||
@@ -900,7 +903,7 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
|
||||
// Chance of hitting ship is based on dot product of firing ship's forward vector with vector to ship
|
||||
// and also the size of the target relative to distance to target.
|
||||
if (dot_to_enemy > MAX(0.5f, 0.90f + aip->ai_accuracy/10.0f - En_objp->radius/MAX(1.0f,dist_to_enemy))) {
|
||||
if (dot_to_enemy > std::max(0.5f, 0.90f + aip->ai_accuracy / 10.0f - En_objp->radius / std::max(1.0f, dist_to_enemy))) {
|
||||
|
||||
ship *temp_shipp;
|
||||
temp_shipp = &Ships[Pl_objp->instance];
|
||||
@@ -1019,6 +1022,8 @@ void ai_big_switch_to_chase_mode(ai_info *aip)
|
||||
aip->submode_start_time = Missiontime;
|
||||
}
|
||||
|
||||
extern weapon_info* ai_get_weapon(ship_weapon* swp);
|
||||
|
||||
// Make object Pl_objp chase object En_objp, which is a big ship, not a small ship.
|
||||
void ai_big_chase()
|
||||
{
|
||||
@@ -1038,16 +1043,38 @@ void ai_big_chase()
|
||||
player_pos = Pl_objp->pos;
|
||||
ai_big_pick_attack_point(En_objp, Pl_objp, &enemy_pos, 0.8f);
|
||||
|
||||
// Compute the predicted position of the center of the ship, then add the delta to the goal pos.
|
||||
if (En_objp->phys_info.speed > 3.0f) {
|
||||
set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
|
||||
vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
|
||||
vm_vec_sub2(&enemy_pos, &En_objp->pos);
|
||||
} else
|
||||
predicted_enemy_pos = En_objp->pos;
|
||||
weapon_info* wip = ai_get_weapon(&shipp->weapons);
|
||||
bool ballistic_aiming = !IS_VEC_NULL(&The_mission.gravity) && wip->gravity_const != 0.0f;
|
||||
bool valid_ballistic_trajectory = true;
|
||||
|
||||
if (aip->targeted_subsys != NULL) {
|
||||
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
|
||||
if (!ballistic_aiming) {
|
||||
// Compute the predicted position of the center of the ship, then add the delta to the goal pos.
|
||||
if (En_objp->phys_info.speed > 3.0f) {
|
||||
set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
|
||||
vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
|
||||
vm_vec_sub2(&enemy_pos, &En_objp->pos);
|
||||
} else
|
||||
predicted_enemy_pos = En_objp->pos;
|
||||
|
||||
if (aip->targeted_subsys != NULL) {
|
||||
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
|
||||
}
|
||||
} else {
|
||||
if (aip->targeted_subsys != NULL) {
|
||||
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
|
||||
}
|
||||
|
||||
vec3d gravity = The_mission.gravity * wip->gravity_const;
|
||||
vec3d target;
|
||||
valid_ballistic_trajectory =
|
||||
physics_lead_ballistic_trajectory(&player_pos, &enemy_pos, &En_objp->phys_info.vel, wip->max_speed, &gravity, &target);
|
||||
|
||||
if (valid_ballistic_trajectory) {
|
||||
enemy_pos = Pl_objp->pos + target * vm_vec_dist(&Pl_objp->pos, &enemy_pos);
|
||||
predicted_enemy_pos = enemy_pos;
|
||||
} else {
|
||||
set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
|
||||
}
|
||||
}
|
||||
|
||||
dist_to_enemy = vm_vec_normalized_dir(&vec_to_enemy, &enemy_pos, &player_pos); // - En_objp->radius;
|
||||
@@ -1078,7 +1105,7 @@ void ai_big_chase()
|
||||
// If just acquired target, or target is not in reasonable cone, don't refine believed enemy position.
|
||||
if ((dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags[AI::AI_Flags::Seek_lock])) {
|
||||
update_aspect_lock_information(aip, &vec_to_enemy, dist_to_enemy - En_objp->radius, En_objp->radius);
|
||||
} else if (aip->targeted_subsys != NULL) {
|
||||
} else if (aip->targeted_subsys != NULL && !ballistic_aiming) {
|
||||
Assert(aip->targeted_subsys != NULL);
|
||||
get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
|
||||
vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
|
||||
@@ -1110,7 +1137,7 @@ void ai_big_chase()
|
||||
}
|
||||
}
|
||||
|
||||
if (aip->target_time < 2.0f)
|
||||
if (!aip->ai_profile_flags[AI::Profile_Flags::No_continuous_turn_on_attack] && aip->target_time < 2.0f)
|
||||
if ((dot_to_enemy < 0.9f) || (dist_to_enemy > 300.0f)) {
|
||||
aip->submode = SM_CONTINUOUS_TURN;
|
||||
aip->submode_start_time = Missiontime - fl2f(2.75f); // This backdated start time allows immediate switchout.
|
||||
@@ -1318,7 +1345,7 @@ void ai_big_chase()
|
||||
// I noticed AI ships firing inappropriately when following a path near a big ship.
|
||||
// TODO: investigate why ships fire (and aren't close to hitting ship) when following a path near
|
||||
// a big ship
|
||||
if (aip->mode != AIM_EVADE && aip->path_start == -1 ) {
|
||||
if (aip->mode != AIM_EVADE && aip->path_start == -1 && (!ballistic_aiming || valid_ballistic_trajectory)) {
|
||||
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy);
|
||||
} else {
|
||||
if (flFrametime < 1.0f)
|
||||
|
||||
+453
-282
File diff suppressed because it is too large.
Load diff
+148
-101
@@ -21,7 +21,9 @@
|
||||
#include "object/objectdock.h"
|
||||
#include "object/waypoint.h"
|
||||
#include "parse/sexp.h"
|
||||
#include "parse/sexp/LuaAISEXP.h"
|
||||
#include "playerman/player.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "ship/ship.h"
|
||||
#include "ship/awacs.h"
|
||||
@@ -54,7 +56,7 @@ struct ship_registry_entry;
|
||||
// goals given from the player to other ships in the game are also handled in this
|
||||
// code
|
||||
|
||||
int Ai_goal_signature;
|
||||
int Ai_goal_signature = 0;
|
||||
int Num_ai_dock_names = 0;
|
||||
char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
|
||||
|
||||
@@ -137,6 +139,41 @@ const char *Ai_goal_text(int goal, int submode)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all fields to their uninitialized defaults. But if this is being called before adding a new goal, the function will set the correct signature and time.
|
||||
* Similarly the added mode, submode, and type can be assigned.
|
||||
*/
|
||||
void ai_goal_reset(ai_goal *aigp, bool adding_goal, int ai_mode, int ai_submode, int type)
|
||||
{
|
||||
if (ai_mode != AI_GOAL_NONE)
|
||||
Assertion(adding_goal, "If a goal mode is being assigned, the adding_goal parameter must be true so that the signature and mission time can be set");
|
||||
|
||||
aigp->signature = adding_goal ? Ai_goal_signature++ : -1;
|
||||
aigp->ai_mode = ai_mode;
|
||||
aigp->ai_submode = ai_submode;
|
||||
aigp->type = type;
|
||||
aigp->flags.reset(); // must reset the flags since not doing so will screw up goal sorting.
|
||||
aigp->time = adding_goal ? Missiontime : 0;
|
||||
aigp->priority = -1;
|
||||
|
||||
aigp->target_name = nullptr;
|
||||
aigp->target_name_index = -1;
|
||||
|
||||
aigp->wp_list = nullptr;
|
||||
|
||||
aigp->target_instance = -1;
|
||||
aigp->target_signature = -1;
|
||||
|
||||
aigp->int_data = 0;
|
||||
aigp->float_data = 0.0f;
|
||||
|
||||
aigp->docker.name = nullptr;
|
||||
aigp->dockee.name = nullptr;
|
||||
|
||||
aigp->lua_ai_target.target.clear();
|
||||
aigp->lua_ai_target.arguments.clear();
|
||||
}
|
||||
|
||||
void ai_maybe_add_form_goal(wing* wingp)
|
||||
{
|
||||
// Cyborg17 - Changes from the client would just get overridden by the server anyway
|
||||
@@ -217,6 +254,8 @@ void ai_post_process_mission()
|
||||
// mission following the orders in the mission file right away instead of waiting N seconds
|
||||
// before following them. Do both the created list and the object list for safety
|
||||
for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
|
||||
if (objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
if ( objp->type != OBJ_SHIP )
|
||||
continue;
|
||||
ai_process_mission_orders( OBJ_INDEX(objp), &Ai_info[Ships[objp->instance].ai_index] );
|
||||
@@ -268,17 +307,37 @@ void ai_remove_ship_goal( ai_info *aip, int index )
|
||||
|
||||
if (index == aip->active_goal)
|
||||
{
|
||||
auto shipp = &Ships[aip->shipnum];
|
||||
|
||||
// rearm/repair needs a bit of extra cleanup
|
||||
if (aip->goals[index].ai_mode == AI_GOAL_REARM_REPAIR)
|
||||
ai_abort_rearm_request(&Objects[Ships[aip->shipnum].objnum]);
|
||||
ai_abort_rearm_request(&Objects[shipp->objnum]);
|
||||
|
||||
// play dead needs some extra cleanup, too
|
||||
if (aip->goals[index].ai_mode == AI_GOAL_PLAY_DEAD || aip->goals[index].ai_mode == AI_GOAL_PLAY_DEAD_PERSISTENT)
|
||||
{
|
||||
// wookieejedi - there is an early return for the mode AIM_PLAY_DEAD in AI frame, so it needs to be set back to AIM_NONE
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Fixed_removing_play_dead_order])
|
||||
{
|
||||
aip->mode = AIM_NONE;
|
||||
aip->submode_start_time = Missiontime;
|
||||
}
|
||||
|
||||
// Goober5000 - any ship subsystems will start moving now, so their initial velocity should be 0 to match original behavior
|
||||
for (auto pss = GET_FIRST(&shipp->subsys_list); pss != END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss))
|
||||
{
|
||||
if (pss->submodel_instance_1)
|
||||
{
|
||||
pss->submodel_instance_1->current_turn_rate = 0.0f;
|
||||
pss->submodel_instance_1->current_shift_rate = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aip->active_goal = AI_GOAL_NONE;
|
||||
}
|
||||
|
||||
aip->goals[index].ai_mode = AI_GOAL_NONE;
|
||||
aip->goals[index].signature = -1;
|
||||
aip->goals[index].priority = -1;
|
||||
aip->goals[index].flags.reset(); // must reset the flags since not doing so will screw up goal sorting.
|
||||
ai_goal_reset(&aip->goals[index]);
|
||||
|
||||
// mwa -- removed this line 8/5/97. Just because we remove a goal doesn't mean to do the default
|
||||
// behavior. We will make the call commented out below in a more reasonable location
|
||||
@@ -304,10 +363,9 @@ void ai_clear_ship_goals( ai_info *aip )
|
||||
}
|
||||
|
||||
// add scripting hook for 'On Goals Cleared' --wookieejedi
|
||||
if (Script_system.IsActiveAction(CHA_ONGOALSCLEARED)) {
|
||||
Script_system.SetHookObject("Ship", &Objects[Ships[aip->shipnum].objnum]);
|
||||
Script_system.RunCondition(CHA_ONGOALSCLEARED, &Objects[Ships[aip->shipnum].objnum]);
|
||||
Script_system.RemHookVars({"Ship"});
|
||||
if (scripting::hooks::OnGoalsCleared->isActive()) {
|
||||
scripting::hooks::OnGoalsCleared->run(scripting::hooks::ShipSourceConditions{ &Ships[aip->shipnum] },
|
||||
scripting::hook_param_list(scripting::hook_param("Ship", 'o', &Objects[Ships[aip->shipnum].objnum])));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,10 +384,7 @@ void ai_clear_wing_goals( wing *wingp )
|
||||
|
||||
// clear out the goals for the wing now
|
||||
for (i = 0; i < MAX_AI_GOALS; i++) {
|
||||
wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
|
||||
wingp->ai_goals[i].signature = -1;
|
||||
wingp->ai_goals[i].priority = -1;
|
||||
wingp->ai_goals[i].flags.reset();
|
||||
ai_goal_reset(&wingp->ai_goals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,10 +439,7 @@ void ai_mission_wing_goal_complete( int wingnum, ai_goal *remove_goalp )
|
||||
continue;
|
||||
|
||||
if ( (aigp->ai_mode == mode) && (aigp->ai_submode == submode) && (aigp->priority == priority) && !stricmp(name, aigp->target_name) ) {
|
||||
wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
|
||||
wingp->ai_goals[i].signature = -1;
|
||||
wingp->ai_goals[i].priority = -1;
|
||||
wingp->ai_goals[i].flags.reset();
|
||||
ai_goal_reset(aigp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -487,7 +539,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
|
||||
// for wings we grab the ship type of the wing leader
|
||||
if (ai_wingnum >= 0) {
|
||||
ai_ship_type = Ship_info[Ships[Wings[ai_wingnum].special_ship].ship_info_index].class_type;
|
||||
ai_ship_type = Ship_info[Wings[ai_wingnum].special_ship_ship_info_index].class_type;
|
||||
}
|
||||
// otherwise we simply grab it from the ship itself
|
||||
else {
|
||||
@@ -523,6 +575,8 @@ void ai_goal_purge_all_invalid_goals(ai_goal *aigp)
|
||||
|
||||
for (sop = GET_FIRST(&Ship_obj_list); sop != END_OF_LIST(&Ship_obj_list); sop = GET_NEXT(sop))
|
||||
{
|
||||
if (Objects[sop->objnum].flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
ship *shipp = &Ships[Objects[sop->objnum].instance];
|
||||
ai_goal_purge_invalid_goals(aigp, Ai_info[shipp->ai_index].goals, &Ai_info[shipp->ai_index], -1);
|
||||
}
|
||||
@@ -632,7 +686,7 @@ void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
|
||||
}
|
||||
}
|
||||
|
||||
// look for docking points of the appriopriate type. Use cargo docks for cargo ships.
|
||||
// look for docking points of the appropriate type. Use cargo docks for cargo ships.
|
||||
/*
|
||||
if (Ship_info[Ships[shipnum].ship_info_index].flags[Ship::Info_Flags::Cargo]) {
|
||||
docker_index = ai_goal_find_dockpoint(aip->shipnum, DOCK_TYPE_CARGO);
|
||||
@@ -659,37 +713,29 @@ 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 object_ship_wing_point_team& lua_target )
|
||||
void ai_add_goal_sub_player(int type, int mode, int submode, char *target_name, ai_goal *aigp, const ai_lua_parameters& lua_target )
|
||||
{
|
||||
Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
|
||||
|
||||
aigp->time = Missiontime;
|
||||
aigp->type = type; // from player for sure -- could be to ship or to wing
|
||||
aigp->ai_mode = mode; // major mode for this goal
|
||||
aigp->ai_submode = submode; // could mean different things depending on mode
|
||||
ai_goal_reset(aigp, true, mode, submode, type);
|
||||
|
||||
aigp->lua_ai_target = lua_target;
|
||||
|
||||
if ( mode == AI_GOAL_WARP ) {
|
||||
if (submode >= 0) {
|
||||
aigp->wp_list = find_waypoint_list_at_index(submode);
|
||||
Assert(aigp->wp_list != NULL);
|
||||
} else {
|
||||
aigp->wp_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ( mode == AI_GOAL_CHASE_WEAPON ) {
|
||||
aigp->target_instance = submode; // submode contains the instance of the weapon
|
||||
aigp->target_signature = Objects[Weapons[submode].objnum].signature;
|
||||
} else {
|
||||
aigp->target_instance = -1;
|
||||
aigp->target_signature = -1;
|
||||
}
|
||||
|
||||
if ( target_name != NULL )
|
||||
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
|
||||
else
|
||||
aigp->target_name = NULL;
|
||||
|
||||
|
||||
// special case certain orders from player so that ships continue to do the right thing
|
||||
|
||||
@@ -758,29 +804,15 @@ void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, ch
|
||||
{
|
||||
Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
|
||||
|
||||
aigp->time = Missiontime;
|
||||
aigp->type = type; // from player for sure -- could be to ship or to wing
|
||||
aigp->ai_mode = mode; // major mode for this goal
|
||||
aigp->ai_submode = submode; // could mean different things depending on mode
|
||||
|
||||
if ( mode == AI_GOAL_WARP )
|
||||
aigp->wp_list = NULL;
|
||||
ai_goal_reset(aigp, true, mode, submode, type);
|
||||
|
||||
if ( mode == AI_GOAL_CHASE_WEAPON ) {
|
||||
aigp->target_instance = submode; // submode contains the instance of the weapon
|
||||
aigp->target_signature = Objects[Weapons[submode].objnum].signature;
|
||||
}
|
||||
|
||||
if ( mode == AI_GOAL_WAYPOINTS_ONCE || mode == AI_GOAL_WAYPOINTS ) {
|
||||
// should be the same as setting via sexp, see ai_add_goal_sub_sexp
|
||||
// set to null so the AI code can setup the new waypoint list, see ai_mission_goal_achievable
|
||||
aigp->wp_list = nullptr;
|
||||
}
|
||||
|
||||
if ( target_name != NULL )
|
||||
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
|
||||
else
|
||||
aigp->target_name = NULL;
|
||||
|
||||
aigp->priority = priority;
|
||||
}
|
||||
@@ -792,35 +824,29 @@ void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipn
|
||||
|
||||
empty_index = ai_goal_find_empty_slot(aip->goals, aip->active_goal);
|
||||
aigp = &aip->goals[empty_index];
|
||||
ai_add_goal_sub_scripting(AIG_TYPE_PLAYER_SHIP, mode, submode, priority, shipname, aigp);
|
||||
|
||||
//WMC - hack to get docking setup correctly
|
||||
if ( mode == AI_GOAL_DOCK ) {
|
||||
aigp->docker.name = Ships[aip->shipnum].ship_name;
|
||||
aigp->dockee.name = shipname;
|
||||
aigp->flags.remove(AI::Goal_Flags::Dockee_index_valid);
|
||||
aigp->flags.remove(AI::Goal_Flags::Docker_index_valid);
|
||||
}
|
||||
ai_add_goal_sub_scripting(AIG_TYPE_PLAYER_SHIP, mode, submode, priority, shipname, aigp);
|
||||
|
||||
if ( (mode == AI_GOAL_REARM_REPAIR) || ((mode == AI_GOAL_DOCK) && (submode == AIS_DOCK_0)) ) {
|
||||
if ( (mode == AI_GOAL_REARM_REPAIR) || (mode == AI_GOAL_DOCK) ) {
|
||||
ai_goal_fixup_dockpoints( aip, aigp );
|
||||
}
|
||||
|
||||
aigp->signature = Ai_goal_signature++;
|
||||
}
|
||||
|
||||
// adds a goal from a player to the given ship's ai_info structure. 'type' tells us if goal
|
||||
// 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 object_ship_wing_point_team& lua_target)
|
||||
void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip, const ai_lua_parameters& lua_target)
|
||||
{
|
||||
int empty_index;
|
||||
ai_goal *aigp;
|
||||
|
||||
empty_index = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
|
||||
|
||||
// get a pointer to the goal structure
|
||||
aigp = &aip->goals[empty_index];
|
||||
ai_add_goal_sub_player( type, mode, submode, shipname, aigp, lua_target );
|
||||
|
||||
@@ -829,17 +855,14 @@ void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, a
|
||||
// on both ships. Code is here instead of in ai_add_goal_sub_player() since a dock goal
|
||||
// should only occur to a specific ship.
|
||||
|
||||
if ( (mode == AI_GOAL_REARM_REPAIR) || ((mode == AI_GOAL_DOCK) && (submode == AIS_DOCK_0)) ) {
|
||||
if ( (mode == AI_GOAL_REARM_REPAIR) || (mode == AI_GOAL_DOCK) ) {
|
||||
ai_goal_fixup_dockpoints( aip, aigp );
|
||||
}
|
||||
|
||||
aigp->signature = Ai_goal_signature++;
|
||||
|
||||
}
|
||||
|
||||
// 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 object_ship_wing_point_team& lua_target)
|
||||
void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum, const ai_lua_parameters& lua_target)
|
||||
{
|
||||
int i, empty_index;
|
||||
wing *wingp = &Wings[wingnum];
|
||||
@@ -863,7 +886,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_goal *aigp, char *actor_name )
|
||||
void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char *actor_name )
|
||||
{
|
||||
int node, dummy, op;
|
||||
|
||||
@@ -871,12 +894,8 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
node = Sexp_nodes[sexp].first;
|
||||
op = get_operator_const( node );
|
||||
|
||||
aigp->signature = Ai_goal_signature++;
|
||||
|
||||
aigp->target_name = NULL;
|
||||
aigp->time = Missiontime;
|
||||
ai_goal_reset(aigp, true);
|
||||
aigp->type = type;
|
||||
aigp->flags.reset();
|
||||
|
||||
switch (op) {
|
||||
|
||||
@@ -889,7 +908,6 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_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;
|
||||
aigp->wp_list = NULL;
|
||||
|
||||
} else
|
||||
Int3();
|
||||
@@ -934,7 +952,6 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
case OP_AI_WARP:
|
||||
aigp->ai_mode = AI_GOAL_WARP;
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
|
||||
aigp->wp_list = NULL;
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
break;
|
||||
|
||||
@@ -944,13 +961,30 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
// Goober5000 - optional undock with something
|
||||
if (CDR(CDR(node)) != -1)
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(CDR(node))), &aigp->target_name_index );
|
||||
else
|
||||
aigp->target_name = NULL;
|
||||
|
||||
aigp->ai_mode = AI_GOAL_UNDOCK;
|
||||
aigp->ai_submode = AIS_UNDOCK_0;
|
||||
break;
|
||||
|
||||
case OP_AI_REARM_REPAIR:
|
||||
{
|
||||
aigp->ai_mode = AI_GOAL_REARM_REPAIR;
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index);
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
|
||||
// this goal needs some extra setup
|
||||
// if this doesn't work, the goal will be immediately removed
|
||||
auto ship_entry = ship_registry_get(aigp->target_name);
|
||||
if (ship_entry->status == ShipStatus::PRESENT)
|
||||
{
|
||||
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 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_AI_STAY_STILL:
|
||||
aigp->ai_mode = AI_GOAL_STAY_STILL;
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
|
||||
@@ -961,8 +995,6 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->docker.name = ai_add_dock_name(CTEXT(CDR(CDR(node))));
|
||||
aigp->dockee.name = ai_add_dock_name(CTEXT(CDR(CDR(CDR(node)))));
|
||||
aigp->flags.remove(AI::Goal_Flags::Dockee_index_valid);
|
||||
aigp->flags.remove(AI::Goal_Flags::Docker_index_valid);
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(CDR(CDR(node))))) );
|
||||
|
||||
aigp->ai_mode = AI_GOAL_DOCK;
|
||||
@@ -989,6 +1021,16 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
aigp->ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
|
||||
break;
|
||||
|
||||
case OP_AI_STAY_NEAR_SHIP:
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->priority = atoi( CTEXT(CDDR(node)) );
|
||||
if ( CDDDR(node) < 0 )
|
||||
aigp->float_data = 300.0f;
|
||||
else
|
||||
aigp->float_data = i2fl(atoi( CTEXT(CDDDR(node)) ));
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
break;
|
||||
|
||||
case OP_AI_FORM_ON_WING:
|
||||
aigp->priority = 99;
|
||||
aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index);
|
||||
@@ -1001,9 +1043,9 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
case OP_AI_GUARD:
|
||||
case OP_AI_GUARD_WING:
|
||||
case OP_AI_EVADE_SHIP:
|
||||
case OP_AI_STAY_NEAR_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))) );
|
||||
|
||||
@@ -1036,8 +1078,10 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
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
|
||||
Int3(); // this is impossible
|
||||
UNREACHABLE("Coding error: unhandled AI goal in ai_add_goal_sub_sexp!");
|
||||
|
||||
break;
|
||||
|
||||
@@ -1050,12 +1094,16 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
aigp->ai_mode = AI_GOAL_LUA;
|
||||
aigp->ai_submode = op;
|
||||
|
||||
|
||||
object_ship_wing_point_team target;
|
||||
if(luaAIMode->needsTarget) {
|
||||
eval_object_ship_wing_point_team(&aigp->lua_ai_target, localnode);
|
||||
eval_object_ship_wing_point_team(&target, localnode);
|
||||
localnode = CDR(localnode);
|
||||
}
|
||||
|
||||
aigp->priority = atoi( CTEXT(localnode) );
|
||||
|
||||
aigp->lua_ai_target = { std::move(target), luaAIMode->sexp.getSEXPArgumentList(CDR(localnode)) };
|
||||
}
|
||||
else {
|
||||
UNREACHABLE("Invalid SEXP-OP number %d for an AI goal!", op);
|
||||
@@ -1081,12 +1129,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
// don't assign the goal if the actor's goal target is itself
|
||||
if (aigp->target_name != NULL && !strcmp(aigp->target_name, actor_name))
|
||||
{
|
||||
// based on ai_remove_ship_goal, these seem to be the only statements
|
||||
// necessary to cause this goal to "never have been assigned"
|
||||
aigp->ai_mode = AI_GOAL_NONE;
|
||||
aigp->signature = -1;
|
||||
aigp->priority = -1;
|
||||
aigp->flags.reset();
|
||||
ai_goal_reset(aigp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1239,6 +1282,14 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
priority = 99;
|
||||
goalmode = AI_GOAL_FORM_ON_WING;
|
||||
break;
|
||||
case OP_AI_FLY_TO_SHIP:
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_FLY_TO_SHIP;
|
||||
break;
|
||||
case OP_AI_REARM_REPAIR:
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_REARM_REPAIR;
|
||||
break;
|
||||
default:
|
||||
const ai_mode_lua* luaAIMode = ai_lua_find_mode(op);
|
||||
if(luaAIMode != nullptr){
|
||||
@@ -1268,10 +1319,7 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
|
||||
/* Clear out the contents of the goal. We can't use ai_remove_ship_goal since it needs ai_info and
|
||||
* we've only got ai_goals */
|
||||
aigp[goalindex].ai_mode = AI_GOAL_NONE;
|
||||
aigp[goalindex].signature = -1;
|
||||
aigp[goalindex].priority = -1;
|
||||
aigp[goalindex].flags.reset(); // must reset the flags since not doing so will screw up goal sorting.
|
||||
ai_goal_reset(&aigp[goalindex]);
|
||||
|
||||
return goalindex;
|
||||
}
|
||||
@@ -1309,7 +1357,7 @@ void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip )
|
||||
int gindex;
|
||||
|
||||
gindex = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
|
||||
ai_add_goal_sub_sexp( sexp, type, &aip->goals[gindex], Ships[aip->shipnum].ship_name );
|
||||
ai_add_goal_sub_sexp( sexp, type, aip, &aip->goals[gindex], Ships[aip->shipnum].ship_name );
|
||||
}
|
||||
|
||||
// code to add ai goals to wings.
|
||||
@@ -1333,7 +1381,7 @@ void ai_add_wing_goal_sexp(int sexp, int type, wing *wingp)
|
||||
int gindex;
|
||||
|
||||
gindex = ai_goal_find_empty_slot( wingp->ai_goals, -1 );
|
||||
ai_add_goal_sub_sexp( sexp, type, &wingp->ai_goals[gindex], wingp->name );
|
||||
ai_add_goal_sub_sexp( sexp, type, nullptr, &wingp->ai_goals[gindex], wingp->name );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1364,12 +1412,9 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*
|
||||
// find an empty slot to put this goal in.
|
||||
gindex = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
|
||||
aigp = &(aip->goals[gindex]);
|
||||
ai_goal_reset(aigp, true);
|
||||
|
||||
aigp->signature = Ai_goal_signature++;
|
||||
|
||||
aigp->time = Missiontime;
|
||||
aigp->type = AIG_TYPE_DYNAMIC;
|
||||
aigp->flags.reset();
|
||||
aigp->flags.set(AI::Goal_Flags::Goal_override);
|
||||
|
||||
switch ( goal_type ) {
|
||||
@@ -1453,12 +1498,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
{
|
||||
int status;
|
||||
ai_achievability return_val;
|
||||
object *objp;
|
||||
ai_info *aip;
|
||||
int index = -1, sindex = -1;
|
||||
int modelnum = -1;
|
||||
|
||||
objp = &Objects[objnum];
|
||||
auto objp = &Objects[objnum];
|
||||
Assert( objp->instance != -1 );
|
||||
aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
|
||||
@@ -1521,8 +1565,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// if not, the status is not known because more ships of that class could arrive in the future
|
||||
// (c.f. AI_GOAL_CHASE_WING subsequent to the next switch statement)
|
||||
if ( aigp->ai_mode == AI_GOAL_CHASE_SHIP_CLASS ) {
|
||||
for (objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp)) {
|
||||
if ((objp->type == OBJ_SHIP) && !strcmp(aigp->target_name, Ship_info[Ships[objp->instance].ship_info_index].name)) {
|
||||
for (auto so: list_range(&Ship_obj_list)) {
|
||||
auto class_objp = &Objects[so->objnum];
|
||||
if (class_objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
if ((class_objp->type == OBJ_SHIP) && !strcmp(aigp->target_name, Ship_info[Ships[class_objp->instance].ship_info_index].name)) {
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
}
|
||||
@@ -2400,13 +2447,14 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
break;
|
||||
|
||||
case AI_GOAL_FORM_ON_WING:
|
||||
// get the ship first, since we're going to wipe it out next
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
// for form on wing, we need to clear out all goals for this ship, and then call the form
|
||||
// on wing AI code
|
||||
// clearing out goals is okay here since we are now what mode to set this AI object to.
|
||||
ai_clear_ship_goals( aip );
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
ai_form_on_wing( objp, other_obj );
|
||||
break;
|
||||
|
||||
@@ -2416,8 +2464,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
// todo MK: hook to keep support ship near other_obj -- other_obj could be the player object!!!
|
||||
float dist = 300.0f; // How far away to stay from ship. Should be set in SEXP?
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
+66
-4
@@ -12,16 +12,30 @@
|
||||
#ifndef _AIGOALS_H
|
||||
#define _AIGOALS_H
|
||||
|
||||
#include "ai/ai_flags.h"
|
||||
#include "globalincs/globals.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "parse/sexp.h"
|
||||
#include "scripting/lua/LuaTypes.h"
|
||||
#include "scripting/lua/LuaValue.h"
|
||||
|
||||
struct wing;
|
||||
struct ai_info;
|
||||
struct ai_goal;
|
||||
|
||||
// macros for goals which get set via sexpressions in the mission code
|
||||
|
||||
// types of ai goals -- tyese types will help us to determination on which goals should
|
||||
// have priority over others (i.e. when a player issues a goal to a wing, then a seperate
|
||||
// goal to a ship in that wing). We would probably use this type in conjunction with
|
||||
// goal priority to establish which goal to follow
|
||||
#define AIG_TYPE_EVENT_SHIP 1 // from mission event direct to ship
|
||||
#define AIG_TYPE_EVENT_WING 2 // from mission event direct to wing
|
||||
#define AIG_TYPE_PLAYER_SHIP 3 // from player direct to ship
|
||||
#define AIG_TYPE_PLAYER_WING 4 // from player direct to wing
|
||||
#define AIG_TYPE_DYNAMIC 5 // created on the fly
|
||||
|
||||
#define AI_GOAL_NONE -1
|
||||
|
||||
// IMPORTANT! If you add a new AI_GOAL_x define, be sure to update the functions
|
||||
// ai_update_goal_references() and query_referenced_in_ai_goals() or else risk breaking
|
||||
// Fred. If the goal you add doesn't have a target (such as chase_any), then you don't have
|
||||
@@ -86,6 +100,51 @@ struct ai_goal;
|
||||
|
||||
enum class ai_achievability { ACHIEVABLE, NOT_ACHIEVABLE, NOT_KNOWN, SATISFIED };
|
||||
|
||||
struct ai_lua_parameters {
|
||||
object_ship_wing_point_team target;
|
||||
luacpp::LuaValueList arguments;
|
||||
};
|
||||
|
||||
// structure for AI goals
|
||||
typedef struct ai_goal {
|
||||
int signature; // Unique identifier. All goals ever created (per mission) have a unique signature.
|
||||
int ai_mode; // one of the AIM_* modes for this goal
|
||||
int ai_submode; // maybe need a submode
|
||||
int type; // one of the AIG_TYPE_* values above
|
||||
flagset<AI::Goal_Flags> flags; // one of the AIGF_* values above
|
||||
fix time; // time at which this goal was issued.
|
||||
int priority; // how important is this goal -- number 0 - 100
|
||||
|
||||
const char *target_name; // name of the thing that this goal acts upon
|
||||
int target_name_index; // index of goal_target_name in Goal_target_names[][]
|
||||
waypoint_list *wp_list; // waypoints that this ship might fly.
|
||||
int target_instance; // instance of thing this ship might be chasing (currently only used for weapons; note, not the same as objnum!)
|
||||
int target_signature; // signature of object this ship might be chasing (currently only used for weapons; paired with above value to confirm target)
|
||||
|
||||
// extra goal-specific data
|
||||
int int_data;
|
||||
float float_data;
|
||||
|
||||
// unions for docking stuff.
|
||||
// (AIGF_DOCKER_INDEX_VALID and AIGF_DOCKEE_INDEX_VALID tell us to use indexes; otherwise we use names)
|
||||
// these are the dockpoints used on the docker and dockee ships, not the ships themselves
|
||||
union {
|
||||
const char *name;
|
||||
int index;
|
||||
} docker;
|
||||
|
||||
union {
|
||||
const char *name;
|
||||
int index;
|
||||
} dockee;
|
||||
|
||||
ai_lua_parameters lua_ai_target;
|
||||
|
||||
} ai_goal;
|
||||
|
||||
extern void ai_goal_reset(ai_goal *aigp, bool adding_goal = false, int ai_mode = AI_GOAL_NONE, int ai_submode = -1, int type = -1);
|
||||
|
||||
|
||||
typedef flag_def_list ai_goal_list;
|
||||
|
||||
extern ai_goal_list Ai_goal_names[];
|
||||
@@ -96,6 +155,9 @@ extern char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
|
||||
|
||||
extern const char *Ai_goal_text(int goal, int submode);
|
||||
|
||||
// every goal in a mission gets a unique signature
|
||||
extern int Ai_goal_signature;
|
||||
|
||||
// extern function definitions
|
||||
extern void ai_post_process_mission();
|
||||
extern void ai_maybe_add_form_goal( wing *wingp );
|
||||
@@ -107,14 +169,14 @@ extern int ai_goal_num(ai_goal *goals);
|
||||
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, 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_goal *aigp, char *actor_name);
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, 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 object_ship_wing_point_team& lua_target = object_ship_wing_point_team());
|
||||
extern void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum, const object_ship_wing_point_team& lua_target = object_ship_wing_point_team());
|
||||
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_remove_ship_goal( ai_info *aip, int index );
|
||||
extern void ai_clear_ship_goals( ai_info *aip );
|
||||
|
||||
+65
-71
@@ -58,7 +58,10 @@ 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 (lua_ai.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target)));
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target.target)));
|
||||
}
|
||||
for (const auto& additionalParam : aip->lua_ai_target.arguments) {
|
||||
luaParameters.push_back(additionalParam);
|
||||
}
|
||||
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
@@ -74,14 +77,10 @@ void ai_lua(ai_info* aip){
|
||||
|
||||
const auto& lua_ai = Lua_ai_modes.at(aip->submode);
|
||||
|
||||
auto dynamicSEXP = sexp::get_dynamic_sexp(aip->submode);
|
||||
const auto& lua_ai_sexp = lua_ai.sexp;
|
||||
const auto& action = lua_ai_sexp.getAction();
|
||||
|
||||
if (dynamicSEXP != nullptr && typeid(*dynamicSEXP) == typeid(sexp::LuaAISEXP)) {
|
||||
auto lua_ai_sexp = static_cast<sexp::LuaAISEXP*>(dynamicSEXP);
|
||||
const auto& action = lua_ai_sexp->getActionFrame();
|
||||
|
||||
run_ai_lua_action(action, lua_ai, aip);
|
||||
}
|
||||
run_ai_lua_action(action, lua_ai, aip);
|
||||
}
|
||||
|
||||
void ai_lua_start(ai_goal* aigp, object* objp){
|
||||
@@ -98,15 +97,10 @@ void ai_lua_start(ai_goal* aigp, object* objp){
|
||||
|
||||
const auto& lua_ai = Lua_ai_modes.at(aigp->ai_submode);
|
||||
|
||||
auto dynamicSEXP = sexp::get_dynamic_sexp(aigp->ai_submode);
|
||||
const auto& lua_ai_sexp = lua_ai.sexp;
|
||||
const auto& action = lua_ai_sexp.getActionEnter();
|
||||
|
||||
if (dynamicSEXP != nullptr && typeid(*dynamicSEXP) == typeid(sexp::LuaAISEXP)) {
|
||||
auto lua_ai_sexp = static_cast<sexp::LuaAISEXP*>(dynamicSEXP);
|
||||
const auto& action = lua_ai_sexp->getActionEnter();
|
||||
|
||||
run_ai_lua_action(action, lua_ai, aip);
|
||||
}
|
||||
|
||||
run_ai_lua_action(action, lua_ai, aip);
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_target_intrinsic(int sexp_op, int target_objnum, ship* self) {
|
||||
@@ -139,36 +133,32 @@ bool ai_lua_is_valid_target_intrinsic(int sexp_op, int target_objnum, ship* self
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_target_lua(const ai_mode_lua& mode, int sexp_op, int target_objnum, ship* self) {
|
||||
auto dynamicSEXP = sexp::get_dynamic_sexp(sexp_op);
|
||||
bool ai_lua_is_valid_target_lua(const ai_mode_lua& mode, int target_objnum, ship* self) {
|
||||
|
||||
if (dynamicSEXP != nullptr && typeid(*dynamicSEXP) == typeid(sexp::LuaAISEXP)) {
|
||||
auto lua_ai_sexp = static_cast<sexp::LuaAISEXP*>(dynamicSEXP);
|
||||
const auto& action = lua_ai_sexp->getTargetRestrict();
|
||||
const auto& action = mode.sexp.getTargetRestrict();
|
||||
|
||||
if (!action.isValid())
|
||||
return true;
|
||||
if (!action.isValid())
|
||||
return true;
|
||||
|
||||
luacpp::LuaValueList luaParameters;
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_Ship.Set(object_h(&Objects[self->objnum]))));
|
||||
if (mode.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]))));
|
||||
}
|
||||
luacpp::LuaValueList luaParameters;
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_Ship.Set(object_h(&Objects[self->objnum]))));
|
||||
if (mode.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]))));
|
||||
}
|
||||
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
|
||||
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
|
||||
return retVals[0].getValue<bool>();
|
||||
}
|
||||
else {
|
||||
Error(LOCATION, "LuaAI target restriction function did not return a valid boolean!");
|
||||
}
|
||||
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
|
||||
return retVals[0].getValue<bool>();
|
||||
}
|
||||
else {
|
||||
Error(LOCATION, "LuaAI target restriction function did not return a valid boolean!");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self) {
|
||||
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order) {
|
||||
const ai_mode_lua& mode = *ai_lua_find_mode(sexp_op);
|
||||
|
||||
//All targetless AI modes are fine
|
||||
@@ -184,56 +174,60 @@ bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self) {
|
||||
|
||||
if (!ai_lua_is_valid_target_intrinsic(sexp_op, target_objnum, self))
|
||||
return false;
|
||||
|
||||
// check if this order can be issued against the target
|
||||
ship *shipp = &Ships[Objects[target_objnum].instance];
|
||||
if (shipp->orders_allowed_against.find(order) == shipp->orders_allowed_against.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//If we haven't bailed yet, query the custom callback
|
||||
return ai_lua_is_valid_target_lua(mode, sexp_op, target_objnum, self);
|
||||
return ai_lua_is_valid_target_lua(mode, target_objnum, self);
|
||||
}
|
||||
|
||||
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum){
|
||||
const auto& lua_ai = Lua_ai_modes.at(aigp->ai_submode);
|
||||
|
||||
auto dynamicSEXP = sexp::get_dynamic_sexp(aigp->ai_submode);
|
||||
const auto& action = lua_ai.sexp.getAchievable();
|
||||
|
||||
if (dynamicSEXP != nullptr && typeid(*dynamicSEXP) == typeid(sexp::LuaAISEXP)) {
|
||||
auto lua_ai_sexp = static_cast<sexp::LuaAISEXP*>(dynamicSEXP);
|
||||
const auto& action = lua_ai_sexp->getAchievable();
|
||||
if (!action.isValid())
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
|
||||
if (!action.isValid())
|
||||
luacpp::LuaValueList luaParameters;
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_Ship.Set(object_h(&Objects[objnum]))));
|
||||
if (lua_ai.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aigp->lua_ai_target.target)));
|
||||
}
|
||||
for (const auto& additionalParam : aigp->lua_ai_target.arguments) {
|
||||
luaParameters.push_back(additionalParam);
|
||||
}
|
||||
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
|
||||
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()) {
|
||||
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
|
||||
luacpp::LuaValueList luaParameters;
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_Ship.Set(object_h(&Objects[objnum]))));
|
||||
if (lua_ai.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aigp->lua_ai_target)));
|
||||
}
|
||||
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
|
||||
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()) {
|
||||
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
|
||||
switch (enumData.index) {
|
||||
case scripting::api::LE_LUAAI_ACHIEVABLE:
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
case scripting::api::LE_LUAAI_NOT_YET_ACHIEVABLE:
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
case scripting::api::LE_LUAAI_UNACHIEVABLE:
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
default:
|
||||
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Error(LOCATION, "LuaAI SEXP achievability hook did not return any avilability enum!");
|
||||
switch (enumData.index) {
|
||||
case scripting::api::LE_LUAAI_ACHIEVABLE:
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
case scripting::api::LE_LUAAI_NOT_YET_ACHIEVABLE:
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
case scripting::api::LE_LUAAI_UNACHIEVABLE:
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
default:
|
||||
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Error(LOCATION, "LuaAI SEXP achievability hook did not return any avilability enum!");
|
||||
}
|
||||
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
+6
-1
@@ -4,9 +4,13 @@
|
||||
#include "ai/aigoals.h"
|
||||
#include "mission/missionmessage.h"
|
||||
#include "ship/ship.h"
|
||||
#include "parse/sexp.h"
|
||||
#include "globalincs/globals.h"
|
||||
|
||||
namespace sexp { class LuaAISEXP; }
|
||||
|
||||
struct ai_mode_lua {
|
||||
const sexp::LuaAISEXP& sexp;
|
||||
bool needsTarget;
|
||||
const char* hudText;
|
||||
};
|
||||
@@ -18,6 +22,7 @@ struct player_order_lua {
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
bool ai_lua_has_mode(int sexp_op);
|
||||
@@ -25,5 +30,5 @@ const ai_mode_lua* ai_lua_find_mode(int sexp_op);
|
||||
const player_order_lua* ai_lua_find_player_order(int sexp_op);
|
||||
void ai_lua(ai_info* aip);
|
||||
void ai_lua_start(ai_goal* aigp, object* objp);
|
||||
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self);
|
||||
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order);
|
||||
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum);
|
||||
+119
-44
@@ -14,6 +14,7 @@
|
||||
#include "network/multi.h"
|
||||
#include "network/multimsgs.h"
|
||||
#include "object/objectdock.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "render/3d.h"
|
||||
#include "ship/ship.h"
|
||||
@@ -765,7 +766,6 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
{
|
||||
//float weapon_travel_dist;
|
||||
int weapon_system_ok;
|
||||
object *objp;
|
||||
eval_enemy_obj_struct eeo;
|
||||
ship_weapon *swp = &turret_subsys->weapons;
|
||||
|
||||
@@ -862,9 +862,10 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
int n_w_classes = (int)tt->weapon_class.size();
|
||||
|
||||
bool found_something;
|
||||
object *ptr = GET_FIRST(&obj_used_list);
|
||||
|
||||
while (ptr != END_OF_LIST(&obj_used_list)) {
|
||||
for (auto ptr: list_range(&obj_used_list)) {
|
||||
if (ptr->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
|
||||
found_something = false;
|
||||
|
||||
if(tt->obj_type > -1 && (ptr->type == tt->obj_type)) {
|
||||
@@ -915,15 +916,10 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
if(!(found_something)) {
|
||||
//we didnt find this object within this priority group
|
||||
//skip to next without evaluating the object as target
|
||||
ptr = GET_NEXT(ptr);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
evaluate_obj_as_target(ptr, &eeo);
|
||||
|
||||
ptr = GET_NEXT(ptr);
|
||||
}
|
||||
|
||||
//homing weapon entry...
|
||||
@@ -994,8 +990,10 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
{
|
||||
// Missile_obj_list
|
||||
for( mo = GET_FIRST(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) {
|
||||
objp = &Objects[mo->objnum];
|
||||
|
||||
auto objp = &Objects[mo->objnum];
|
||||
if (objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
|
||||
Assert(objp->type == OBJ_WEAPON);
|
||||
if ((Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Bomb]) || (Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Turret_Interceptable]))
|
||||
{
|
||||
@@ -1015,7 +1013,9 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
//Return if a ship is found
|
||||
// Ship_used_list
|
||||
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
|
||||
objp = &Objects[so->objnum];
|
||||
auto objp = &Objects[so->objnum];
|
||||
if (objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
evaluate_obj_as_target(objp, &eeo);
|
||||
}
|
||||
|
||||
@@ -1043,7 +1043,9 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
if ( !all_turret_weapons_have_flags(swp, tmp_flagset) ) {
|
||||
// Asteroid_obj_list
|
||||
for ( ao = GET_FIRST(&Asteroid_obj_list); ao != END_OF_LIST(&Asteroid_obj_list); ao = GET_NEXT(ao) ) {
|
||||
objp = &Objects[ao->objnum];
|
||||
auto objp = &Objects[ao->objnum];
|
||||
if (objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
evaluate_obj_as_target(objp, &eeo);
|
||||
}
|
||||
|
||||
@@ -1319,7 +1321,7 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
|
||||
if (ss->turret_enemy_objnum != -1) {
|
||||
model_subsystem *tp = ss->system_info;
|
||||
vec3d gun_pos, gun_vec, target_moving_direction;
|
||||
vec3d gun_pos, gun_vec, target_vel;
|
||||
//float weapon_speed;
|
||||
float weapon_system_strength;
|
||||
//HACK HACK HACK -WMC
|
||||
@@ -1357,14 +1359,33 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
}
|
||||
}
|
||||
|
||||
target_moving_direction = ss->last_aim_enemy_vel;
|
||||
target_vel = ss->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);
|
||||
vm_vec_scale_sub2(&target_vel, &objp->phys_info.vel, wip->vel_inherit_amount);
|
||||
}
|
||||
|
||||
set_predicted_enemy_pos_turret(predicted_enemy_pos, &gun_pos, objp, &enemy_point, &target_moving_direction, wip->max_speed, ss->turret_time_enemy_in_range * (weapon_system_strength + 1.0f)/2.0f);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//Mess with the turret's accuracy if the weapon system is damaged.
|
||||
if (weapon_system_strength < Weapon_SS_Threshold_Turret_Inaccuracy) {
|
||||
@@ -1643,11 +1664,21 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
|
||||
wait *= aip->ai_ship_fire_delay_scale_friendly * 0.5f;
|
||||
if (aip->ai_class_autoscale)
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 40.0f;
|
||||
{
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale])
|
||||
wait += (ai_get_autoscale_index(Num_ai_classes) - ai_get_autoscale_index(aip->ai_class) - 1) * 40.0f;
|
||||
else
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 40.0f;
|
||||
}
|
||||
} else {
|
||||
wait *= aip->ai_ship_fire_delay_scale_friendly;
|
||||
if (aip->ai_class_autoscale)
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 100.0f;
|
||||
{
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale])
|
||||
wait += (ai_get_autoscale_index(Num_ai_classes) - ai_get_autoscale_index(aip->ai_class) - 1) * 100.0f;
|
||||
else
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 100.0f;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// flak guns need to fire more rapidly
|
||||
@@ -1658,13 +1689,23 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
|
||||
wait *= aip->ai_ship_fire_delay_scale_hostile * 0.5f;
|
||||
}
|
||||
if (aip->ai_class_autoscale)
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 40.0f;
|
||||
{
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale])
|
||||
wait += (ai_get_autoscale_index(Num_ai_classes) - ai_get_autoscale_index(aip->ai_class) - 1) * 40.0f;
|
||||
else
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 40.0f;
|
||||
}
|
||||
|
||||
} else if (wip->wi_flags[Weapon::Info_Flags::Huge]) {
|
||||
// make huge weapons fire independently of team
|
||||
wait *= aip->ai_ship_fire_delay_scale_friendly;
|
||||
if (aip->ai_class_autoscale)
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 100.0f;
|
||||
{
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale])
|
||||
wait += (ai_get_autoscale_index(Num_ai_classes) - ai_get_autoscale_index(aip->ai_class) - 1) * 100.0f;
|
||||
else
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 100.0f;
|
||||
}
|
||||
} else {
|
||||
// give team friendly an advantage
|
||||
if (Ships[aip->shipnum].team == Player_ship->team) {
|
||||
@@ -1673,7 +1714,12 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
|
||||
wait *= aip->ai_ship_fire_delay_scale_hostile;
|
||||
}
|
||||
if (aip->ai_class_autoscale)
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 100.0f;
|
||||
{
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale])
|
||||
wait += (ai_get_autoscale_index(Num_ai_classes) - ai_get_autoscale_index(aip->ai_class) - 1) * 100.0f;
|
||||
else
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 100.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
// vary wait time +/- 10%
|
||||
@@ -1842,10 +1888,13 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
parent_ship->last_fired_turret = turret;
|
||||
turret->last_fired_weapon_info_index = turret_weapon_class;
|
||||
|
||||
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
|
||||
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", nullptr, "Beam", objp, "Target", turret_enemy_objp);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum], objp);
|
||||
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
|
||||
if (scripting::hooks::OnTurretFired->isActive()) {
|
||||
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, turret_weapon_class, true },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Ship", 'o', &Objects[parent_objnum]),
|
||||
scripting::hook_param("Beam", 'o', objp),
|
||||
scripting::hook_param("Target", 'o', turret_enemy_objp)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1985,10 +2034,13 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
// AL 1-6-97: Store pointer to turret subsystem
|
||||
wp->turret_subsys = turret;
|
||||
|
||||
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
|
||||
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", objp, "Beam", nullptr, "Target", turret_enemy_objp);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum], objp);
|
||||
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
|
||||
if (scripting::hooks::OnTurretFired->isActive()) {
|
||||
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, turret_weapon_class, wip->subtype == WP_LASER },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Ship", 'o', &Objects[parent_objnum]),
|
||||
scripting::hook_param("Weapon", 'o', objp),
|
||||
scripting::hook_param("Target", 'o', turret_enemy_objp)
|
||||
));
|
||||
}
|
||||
|
||||
// if the gun is a flak gun
|
||||
@@ -2052,7 +2104,8 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set has fired flag for scriptng - nuke
|
||||
|
||||
//Fire animation stuff
|
||||
Ship_info[parent_ship->ship_info_index].animations.start(model_get_instance(parent_ship->model_instance_num), animation::ModelAnimationTriggerType::TurretFired, animation::anim_name_from_subsys(turret->system_info), animation::ModelAnimationDirection::FWD, true);
|
||||
Ship_info[parent_ship->ship_info_index].animations.get(model_get_instance(parent_ship->model_instance_num), animation::ModelAnimationTriggerType::TurretFired, animation::anim_name_from_subsys(turret->system_info))
|
||||
.start(animation::ModelAnimationDirection::FWD, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2103,10 +2156,17 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
Ships[Objects[tsi->parent_objnum].instance].last_fired_turret = tsi->turret;
|
||||
tsi->turret->last_fired_weapon_info_index = tsi->weapon_class;
|
||||
|
||||
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
|
||||
Script_system.SetHookObjects(4, "Ship", &Objects[tsi->parent_objnum], "Weapon", &Objects[weapon_objnum], "Beam", nullptr, "Target", &Objects[tsi->turret->turret_enemy_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[tsi->parent_objnum], &Objects[weapon_objnum]);
|
||||
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
|
||||
if (scripting::hooks::OnTurretFired->isActive()) {
|
||||
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{
|
||||
&Ships[Objects[tsi->parent_objnum].instance],
|
||||
&Objects[tsi->turret->turret_enemy_objnum],
|
||||
tsi->weapon_class, Weapon_info[tsi->weapon_class].subtype == WP_LASER
|
||||
},
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Ship", 'o', &Objects[tsi->parent_objnum]),
|
||||
scripting::hook_param("Weapon", 'o', &Objects[weapon_objnum]),
|
||||
scripting::hook_param("Target", 'o', &Objects[tsi->turret->turret_enemy_objnum])
|
||||
));
|
||||
}
|
||||
|
||||
// muzzle flash?
|
||||
@@ -2234,6 +2294,12 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
// 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);
|
||||
|
||||
// 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.
|
||||
if (MULTIPLAYER_CLIENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((tp->flags[Model::Subsystem_Flags::Fire_on_target]) && (ss->points_to_target >= 0.0f))
|
||||
{
|
||||
// value probably needs tweaking... could perhaps be made into table option?
|
||||
@@ -2338,6 +2404,15 @@ 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;
|
||||
}
|
||||
|
||||
// Don't try to fire beyond weapon_limit_range (or within min range)
|
||||
if (dist_to_enemy < weapon_min_range || dist_to_enemy > weapon_firing_range) {
|
||||
// it's possible another weapon is in range, but if not,
|
||||
@@ -2526,7 +2601,9 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
bool in_fov = turret_fov_test(ss, &gvec, &v2e);
|
||||
bool something_was_ok_to_fire = false;
|
||||
|
||||
if (in_fov) {
|
||||
// the only reason predicted_enemy_pos might be zero, while everything else is valid is if
|
||||
// its a ballistic trajectory with no valid path
|
||||
if (in_fov && num_valid && predicted_enemy_pos != vmd_zero_vector) {
|
||||
|
||||
// Do salvo thing separately - to prevent messing up things
|
||||
int number_of_firings;
|
||||
@@ -2669,15 +2746,13 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
|
||||
{
|
||||
// starting animation checks
|
||||
if (ss->turret_animation_position == MA_POS_NOT_SET) {
|
||||
bool started = false;
|
||||
//For legacy animations using subtype for turret number
|
||||
started |= Ship_info[shipp->ship_info_index].animations.startAll(model_get_instance(shipp->model_instance_num), animation::ModelAnimationTriggerType::TurretFiring, animation::ModelAnimationDirection::FWD, false, false, false, ss->system_info->subobj_num, true);
|
||||
auto animList = Ship_info[shipp->ship_info_index].animations.getAll(model_get_instance(shipp->model_instance_num), animation::ModelAnimationTriggerType::TurretFiring, ss->system_info->subobj_num, true);
|
||||
//For modern animations using proper triggered-by-subsys name
|
||||
started |= Ship_info[shipp->ship_info_index].animations.start(model_get_instance(shipp->model_instance_num), animation::ModelAnimationTriggerType::TurretFiring, animation::anim_name_from_subsys(ss->system_info), animation::ModelAnimationDirection::FWD);
|
||||
if (started) {
|
||||
int duration = Ship_info[shipp->ship_info_index].animations.getTimeAll(model_get_instance(shipp->model_instance_num), animation::ModelAnimationTriggerType::TurretFiring, ss->system_info->subobj_num, true);
|
||||
int duration2 = Ship_info[shipp->ship_info_index].animations.getTime(model_get_instance(shipp->model_instance_num), animation::ModelAnimationTriggerType::TurretFiring, animation::anim_name_from_subsys(ss->system_info));
|
||||
ss->turret_animation_done_time = timestamp(duration > duration2 ? duration : duration2);
|
||||
animList += Ship_info[shipp->ship_info_index].animations.get(model_get_instance(shipp->model_instance_num), animation::ModelAnimationTriggerType::TurretFiring, animation::anim_name_from_subsys(ss->system_info));
|
||||
|
||||
if (animList.start(animation::ModelAnimationDirection::FWD)) {
|
||||
ss->turret_animation_done_time = timestamp(animList.getTime());
|
||||
ss->turret_animation_position = MA_POS_SET;
|
||||
}
|
||||
}
|
||||
@@ -2814,7 +2889,7 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
|
||||
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
|
||||
{
|
||||
bool in_fov = false;
|
||||
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_restricted_fov])
|
||||
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_base_restricted_fov])
|
||||
in_fov = turret_adv_fov_test(ss, gvec, v2e, size_mod);
|
||||
else
|
||||
in_fov = turret_std_fov_test(ss, gvec, v2e, size_mod);
|
||||
|
||||
@@ -397,8 +397,6 @@ int anim_show_next_frame(anim_instance *instance, float frametime)
|
||||
|
||||
t1 = timer_get_fixed_seconds();
|
||||
for ( i = 0; i < frame_diff; i++ ) {
|
||||
anim_check_for_palette_change(instance);
|
||||
|
||||
// if we're playing backwards, every frame must be a keyframe and we set the data ptr here
|
||||
if(instance->direction == ANIM_DIRECT_REVERSE){
|
||||
if ( anim_instance_is_streamed(instance) ) {
|
||||
@@ -643,7 +641,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
|
||||
|
||||
if (diff != 0) {
|
||||
if (ptr->height > 16) {
|
||||
mprintf(("ANI %s with size %dx%d (%.1f%% wasted)\n", ptr->name, ptr->width, ptr->height, waste));
|
||||
nprintf(("ANI","ANI %s with size %dx%d (%.1f%% wasted)\n", ptr->name, ptr->width, ptr->height, waste));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -790,9 +788,6 @@ anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
|
||||
|
||||
cfclose(fp);
|
||||
|
||||
// store screen signature, so we can tell if palette changes
|
||||
ptr->screen_sig = gr_screen.signature;
|
||||
|
||||
anim_set_palette(ptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,6 @@
|
||||
const int packer_code = PACKER_CODE;
|
||||
const int transparent_code = 254;
|
||||
|
||||
void anim_check_for_palette_change(anim_instance *instance) {
|
||||
if ( instance->parent->screen_sig != gr_screen.signature ) {
|
||||
instance->parent->screen_sig = gr_screen.signature;
|
||||
anim_set_palette(instance->parent);
|
||||
}
|
||||
}
|
||||
|
||||
anim_instance *init_anim_instance(anim *ptr, int bpp)
|
||||
{
|
||||
anim_instance *inst;
|
||||
@@ -97,8 +90,6 @@ ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap
|
||||
return NULL;
|
||||
}
|
||||
|
||||
anim_check_for_palette_change(inst);
|
||||
|
||||
if ( anim_instance_is_streamed(inst) ) {
|
||||
if ( xlate_pal ){
|
||||
inst->file_offset = unpack_frame_from_file(inst, inst->frame, inst->parent->width*inst->parent->height, inst->parent->palette_translation, aabitmap, bpp);
|
||||
|
||||
@@ -58,7 +58,6 @@ typedef struct anim {
|
||||
ubyte xparent_g; // green component for the transparent color in source image
|
||||
ubyte xparent_b; // blue component for the transparent color in source image
|
||||
int flags;
|
||||
uint screen_sig;
|
||||
int file_offset; // file offset to start of frame data
|
||||
int cache_file_offset;
|
||||
ubyte *cache;
|
||||
@@ -105,7 +104,6 @@ anim_instance *init_anim_instance(anim *ptr, int bpp);
|
||||
void free_anim_instance(anim_instance *inst);
|
||||
ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap, int bpp);
|
||||
void anim_set_palette(anim *a);
|
||||
void anim_check_for_palette_change(anim_instance *inst);
|
||||
|
||||
|
||||
#endif /* __PACKUNPACK_H__ */
|
||||
+633
-244
File diff suppressed because it is too large.
Load diff
+31
-27
@@ -14,34 +14,29 @@
|
||||
|
||||
#include "globalincs/globals.h" // for NAME_LENGTH
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include "io/timer.h"
|
||||
|
||||
class object;
|
||||
class polymodel;
|
||||
struct collision_info_struct;
|
||||
class model_draw_list;
|
||||
|
||||
#define MAX_ASTEROIDS 512
|
||||
#define MAX_ASTEROIDS 2000 //Increased from 512 to 2000 in 2022
|
||||
|
||||
#define NUM_DEBRIS_SIZES 3
|
||||
#define NUM_DEBRIS_POFS 3 // Number of POFs per debris size
|
||||
#define NUM_ASTEROID_SIZES 3
|
||||
#define NUM_ASTEROID_POFS 3 // Number of POFs per debris size
|
||||
|
||||
#define ASTEROID_TYPE_DEBRIS -1
|
||||
#define ASTEROID_TYPE_SMALL 0
|
||||
#define ASTEROID_TYPE_MEDIUM 1
|
||||
#define ASTEROID_TYPE_LARGE 2
|
||||
|
||||
// these should always be equal for the benefit of generic asteroids (c.f. asteroid_page_in)
|
||||
#define MAX_ACTIVE_DEBRIS_TYPES NUM_DEBRIS_SIZES
|
||||
#define MAX_ACTIVE_DEBRIS_TYPES NUM_ASTEROID_SIZES
|
||||
|
||||
// Goober5000 - currently same as MAX_SHIP_DETAIL_LEVELS (put here to avoid an #include)
|
||||
#define MAX_ASTEROID_DETAIL_LEVELS 5
|
||||
|
||||
// whether to do retail behavior, just throw at the first big ship in the field
|
||||
// must be explicitly opted out of by the mission
|
||||
extern bool Default_asteroid_throwing_behavior;
|
||||
|
||||
extern SCP_vector<SCP_string> Asteroid_target_ships;
|
||||
|
||||
// Data structure to track the active asteroids
|
||||
typedef struct asteroid_obj {
|
||||
asteroid_obj *next, *prev;
|
||||
@@ -53,16 +48,18 @@ extern asteroid_obj Asteroid_obj_list;
|
||||
// Data structure for determining a type and amount of other asteroids an
|
||||
// asteroid will split to when destroyed.
|
||||
typedef struct asteroid_split_info {
|
||||
int asteroid_type;
|
||||
int min;
|
||||
int max;
|
||||
int asteroid_type; //index position
|
||||
char name[NAME_LENGTH]; //asteroid name
|
||||
int min; //minimum asteroids to spawn
|
||||
int max; //maximum asteroids to spawn
|
||||
} asteroid_split_info;
|
||||
|
||||
class asteroid_info
|
||||
{
|
||||
public:
|
||||
char name[NAME_LENGTH]; // name for the asteroid
|
||||
char pof_files[NUM_DEBRIS_POFS][MAX_FILENAME_LEN]; // POF files to load/associate with ship
|
||||
int type; // type of asteroid, 0 = small, 1 = medium, 2 = large, -1 = debris
|
||||
char pof_files[NUM_ASTEROID_POFS][MAX_FILENAME_LEN]; // POF files to load/associate with ship
|
||||
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
|
||||
@@ -74,27 +71,29 @@ public:
|
||||
float blast; // maximum blast impulse from area effect explosion
|
||||
float initial_asteroid_strength; // starting strength of asteroid
|
||||
SCP_vector< asteroid_split_info > split_info;
|
||||
polymodel *modelp[NUM_DEBRIS_POFS];
|
||||
int model_num[NUM_DEBRIS_POFS];
|
||||
polymodel *modelp[NUM_ASTEROID_POFS];
|
||||
int model_num[NUM_ASTEROID_POFS];
|
||||
SCP_vector<int> explosion_bitmap_anims;
|
||||
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
|
||||
SCP_string display_name; // only used for hud targeting display and for 'ship' asteroids
|
||||
float spawn_weight; // ship asteroids only, relative proportion to spawn compared to other types in its asteroid field
|
||||
float gravity_const; // multiplier for mission gravity
|
||||
|
||||
asteroid_info( )
|
||||
: num_detail_levels( 0 ), max_speed( 0 ), damage_type_idx( 0 ),
|
||||
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0), 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 )
|
||||
fireball_radius_multiplier( -1 ), spawn_weight( 1 ), gravity_const( 0 )
|
||||
{
|
||||
name[ 0 ] = 0;
|
||||
display_name = "";
|
||||
memset( detail_distance, 0, sizeof( detail_distance ) );
|
||||
|
||||
for (int i = 0; i < NUM_DEBRIS_POFS; i++)
|
||||
for (int i = 0; i < NUM_ASTEROID_POFS; i++)
|
||||
{
|
||||
modelp[i] = NULL;
|
||||
model_num[i] = -1;
|
||||
pof_files[i][0] = 0;
|
||||
pof_files[i][0] = '\0';
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -108,9 +107,9 @@ typedef struct asteroid {
|
||||
int model_instance_num;
|
||||
int asteroid_type; // 0..MAX_DEBRIS_TYPES
|
||||
int asteroid_subtype; // Index in asteroid_info for modelnum and modelp
|
||||
int check_for_wrap; // timestamp to check for asteroid wrapping around field
|
||||
int check_for_collide; // timestamp to check for asteroid colliding with escort ships
|
||||
int final_death_time; // timestamp to swap in new models after explosion starts
|
||||
TIMESTAMP check_for_wrap; // timestamp to check for asteroid wrapping around field
|
||||
TIMESTAMP check_for_collide; // timestamp to check for asteroid colliding with escort ships
|
||||
TIMESTAMP final_death_time; // timestamp to swap in new models after explosion starts
|
||||
int collide_objnum; // set to objnum that asteroid will be impacting soon
|
||||
int collide_objsig; // object signature corresponding to collide_objnum
|
||||
vec3d death_hit_pos; // hit pos that caused death
|
||||
@@ -121,7 +120,7 @@ typedef struct asteroid {
|
||||
// TYPEDEF FOR DEBRIS TYPE
|
||||
typedef enum {
|
||||
DG_ASTEROID,
|
||||
DG_SHIP
|
||||
DG_DEBRIS
|
||||
} debris_genre_t;
|
||||
|
||||
// TYPEDEF FOR FIELD TYPE
|
||||
@@ -134,7 +133,7 @@ typedef struct asteroid_field {
|
||||
vec3d min_bound; // Minimum range of field.
|
||||
vec3d max_bound; // Maximum range of field.
|
||||
float bound_rad;
|
||||
int has_inner_bound;
|
||||
bool has_inner_bound;
|
||||
vec3d inner_min_bound;
|
||||
vec3d inner_max_bound;
|
||||
vec3d vel; // Average asteroid moves at this velocity.
|
||||
@@ -144,6 +143,8 @@ typedef struct asteroid_field {
|
||||
debris_genre_t debris_genre; // type of debris (ship or asteroid) [generic type]
|
||||
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]; // one of the debris type defines above
|
||||
int num_used_field_debris_types; // how many of the above are used
|
||||
|
||||
SCP_vector<SCP_string> target_names; // default retail behavior is to just throw at the first big ship in the field
|
||||
} asteroid_field;
|
||||
|
||||
extern SCP_vector< asteroid_info > Asteroid_info;
|
||||
@@ -160,7 +161,9 @@ void asteroid_init();
|
||||
void asteroid_level_init();
|
||||
void asteroid_level_close();
|
||||
void asteroid_create_all();
|
||||
void asteroid_render(object * obj, model_draw_list *scene);
|
||||
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, bool brown, bool blue, bool orange, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> targets);
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max);
|
||||
void asteroid_render(object* obj, model_draw_list* scene);
|
||||
void asteroid_delete( object *asteroid_objp );
|
||||
void asteroid_process_pre( object *asteroid_objp );
|
||||
void asteroid_process_post( object *asteroid_objp);
|
||||
@@ -172,6 +175,7 @@ float asteroid_time_to_impact(object *asteroid_objp);
|
||||
void asteroid_show_brackets();
|
||||
void asteroid_target_closest_danger();
|
||||
void asteroid_add_target(object* objp);
|
||||
int get_asteroid_position(const char* name);
|
||||
|
||||
// need to extern for multiplayer
|
||||
void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec);
|
||||
|
||||
@@ -47,10 +47,9 @@ NavMessage NavMsgs[NP_NUM_MESSAGES];
|
||||
int audio_handle;
|
||||
int NavLinkDistance;
|
||||
// time offsets for autonav events
|
||||
int LockAPConv;
|
||||
int EndAPCinematic;
|
||||
int MoveCamera;
|
||||
int camMovingTime;
|
||||
TIMESTAMP LockAPConv;
|
||||
TIMESTAMP EndAPCinematic;
|
||||
TIMESTAMP MoveCamera;
|
||||
//float CameraSpeed;
|
||||
bool CinematicStarted, CameraMoving;
|
||||
vec3d cameraPos, cameraTarget;
|
||||
@@ -151,6 +150,9 @@ bool CanAutopilot(const vec3d *targetPos, bool send_msg)
|
||||
for (ship_obj *so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so))
|
||||
{
|
||||
object *other_objp = &Objects[so->objnum];
|
||||
if (other_objp->flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
|
||||
// attacks player?
|
||||
if (iff_x_attacks_y(obj_team(other_objp), obj_team(Player_obj))
|
||||
&& !(Ship_info[Ships[other_objp->instance].ship_info_index].flags[Ship::Info_Flags::Cargo])) // ignore cargo
|
||||
@@ -206,8 +208,9 @@ bool StartAutopilot()
|
||||
{
|
||||
// Check for support ship and dismiss it if it is not doing anything.
|
||||
// If the support ship is doing something then tell the user such.
|
||||
for ( object *objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
|
||||
for (auto so: list_range(&Ship_obj_list))
|
||||
{
|
||||
auto objp = &Objects[so->objnum];
|
||||
if ((objp->type == OBJ_SHIP) && !(objp->flags[Object::Object_Flags::Should_be_dead]))
|
||||
{
|
||||
Assertion((objp->instance >= 0) && (objp->instance < MAX_SHIPS),
|
||||
@@ -262,9 +265,9 @@ bool StartAutopilot()
|
||||
}
|
||||
|
||||
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics])
|
||||
LockAPConv = timestamp(); // lock convergence instantly
|
||||
LockAPConv = _timestamp(); // lock convergence instantly
|
||||
else
|
||||
LockAPConv = timestamp(3000); // 3 seconds before we lock convergence
|
||||
LockAPConv = _timestamp(3 * MILLISECONDS_PER_SECOND); // 3 seconds before we lock convergence
|
||||
Player_use_ai = 1;
|
||||
set_time_compression(1);
|
||||
lock_time_compression(true);
|
||||
@@ -402,7 +405,7 @@ bool StartAutopilot()
|
||||
&& Autopilot_flight_leader != &Objects[Ships[i].objnum]) //only if not flight leader's object
|
||||
{
|
||||
ai_info *aip = &Ai_info[Ships[i].ai_index];
|
||||
int wingnum = aip->wing, wing_index = get_wing_index(&Objects[Ships[i].objnum], wingnum);
|
||||
int wingnum = Ships[i].wingnum, wing_index = get_wing_index(&Objects[Ships[i].objnum], wingnum);
|
||||
vec3d goal_point;
|
||||
object *leader_objp = get_wing_leader(wingnum);
|
||||
|
||||
@@ -828,9 +831,8 @@ bool StartAutopilot()
|
||||
//CameraMoving = false;
|
||||
|
||||
|
||||
EndAPCinematic = timestamp((10000*tc_factor)+NPS_TICKRATE); // 10 objective seconds before end of cinematic
|
||||
MoveCamera = timestamp((5500*tc_factor)+NPS_TICKRATE);
|
||||
camMovingTime = int(4.5*float(tc_factor));
|
||||
EndAPCinematic = _timestamp((10 * MILLISECONDS_PER_SECOND * tc_factor) + NPS_TICKRATE); // 10 objective seconds before end of cinematic
|
||||
MoveCamera = _timestamp(fl2i(5.5 * MILLISECONDS_PER_SECOND * tc_factor) + NPS_TICKRATE);
|
||||
set_time_compression((float)tc_factor);
|
||||
}
|
||||
|
||||
@@ -923,10 +925,7 @@ void EndAutoPilot()
|
||||
if ( ((aigp->target_name != NULL) && !stricmp(aigp->target_name, goal_name))
|
||||
&& (aigp->ai_mode == goal) )
|
||||
{
|
||||
aigp->ai_mode = AI_GOAL_NONE;
|
||||
aigp->signature = -1;
|
||||
aigp->priority = -1;
|
||||
aigp->flags.reset();
|
||||
ai_goal_reset(aigp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -947,10 +946,7 @@ void EndAutoPilot()
|
||||
if ( ((aigp->target_name != NULL) && !stricmp(aigp->target_name, goal_name))
|
||||
&& (aigp->ai_mode == goal) )
|
||||
{
|
||||
aigp->ai_mode = AI_GOAL_NONE;
|
||||
aigp->signature = -1;
|
||||
aigp->priority = -1;
|
||||
aigp->flags.reset();
|
||||
ai_goal_reset(aigp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1053,15 +1049,13 @@ void NavSystem_Do()
|
||||
if(cam != NULL)
|
||||
cam->set_rotation_facing(&Player_obj->pos);
|
||||
|
||||
if (timestamp() >= MoveCamera && !CameraMoving && vm_vec_mag(&cameraTarget) > 0.0f)
|
||||
if (timestamp_elapsed(MoveCamera) && !CameraMoving && vm_vec_mag(&cameraTarget) > 0.0f)
|
||||
{
|
||||
//Free_camera->set_position(&cameraTarget, float(camMovingTime), float(camMovingTime)/2.0f);
|
||||
//Free_camera->set_translation_velocity(&cameraTarget);
|
||||
CameraMoving = true;
|
||||
}
|
||||
|
||||
|
||||
if (timestamp() >= EndAPCinematic || !CanAutopilot())
|
||||
if (timestamp_elapsed(EndAPCinematic) || !CanAutopilot())
|
||||
{
|
||||
nav_warp();
|
||||
EndAutoPilot();
|
||||
@@ -1218,7 +1212,7 @@ void send_autopilot_msg(const char *msg, const char *snd)
|
||||
}
|
||||
|
||||
if (msg[0] != '\0' && strcmp(msg, "none") != 0)
|
||||
message_training_queue("autopilot builtin message", timestamp(0), 5); // display message for five seconds
|
||||
message_training_queue("autopilot builtin message", TIMESTAMP::immediate(), 5); // display message for five seconds
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
|
||||
@@ -29,16 +29,17 @@
|
||||
class NavPoint
|
||||
{
|
||||
public:
|
||||
char m_NavName[32];
|
||||
int flags;
|
||||
ubyte normal_color[3];
|
||||
ubyte visited_color[3];
|
||||
char m_NavName[32] = { 0 };
|
||||
int flags = 0;
|
||||
ubyte normal_color[3] = { 0x80, 0x80, 0xFF };
|
||||
ubyte visited_color[3] = { 0xFF, 0xFF, 0x00 };
|
||||
|
||||
const void *target_obj;
|
||||
int waypoint_num; //only used when flags & NP_WAYPOINT
|
||||
const void *target_obj = nullptr;
|
||||
int waypoint_num = -1; //only used when flags & NP_WAYPOINT
|
||||
|
||||
const vec3d *GetPosition();
|
||||
|
||||
// these assignments should match the initialization
|
||||
void clear()
|
||||
{
|
||||
m_NavName[0] = 0;
|
||||
@@ -78,7 +79,7 @@ extern bool AutoPilotEngaged;
|
||||
extern int CurrentNav;
|
||||
extern NavPoint Navs[MAX_NAVPOINTS];
|
||||
extern NavMessage NavMsgs[NP_NUM_MESSAGES];
|
||||
extern int LockAPConv;
|
||||
extern TIMESTAMP LockAPConv;
|
||||
extern SCP_map<int,int> autopilot_wings;
|
||||
|
||||
// Cycles through the NavPoint List
|
||||
|
||||
@@ -53,6 +53,7 @@ MONITOR(SizeBitmapPage)
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Definition of public variables (declared as extern in bmpman.h).
|
||||
int ENVMAP = -1;
|
||||
int IRRMAP = -1;
|
||||
|
||||
size_t bm_texture_ram = 0;
|
||||
int Bm_paging = 0;
|
||||
@@ -1530,7 +1531,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
cfclose(img_cfp);
|
||||
return -1;
|
||||
} else {
|
||||
mprintf(("BMPMAN: Found EFF (%s) with %d frames at %d fps.\n", filename, anim_frames, anim_fps));
|
||||
nprintf(("BmpMan","BMPMAN: Found EFF (%s) with %d frames at %d fps.\n", filename, anim_frames, anim_fps));
|
||||
}
|
||||
if (anim_fps == 0) {
|
||||
Error(LOCATION, "animation (%s) has invalid fps of 0, fix this!", filename);
|
||||
@@ -1599,7 +1600,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
throw e;
|
||||
}
|
||||
else {
|
||||
mprintf(("Failed to load apng: %s\n", e.what()));
|
||||
nprintf(("apng","Failed to load apng: %s\n", e.what()));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -1834,7 +1835,7 @@ int bm_load_sub_fast(const char *real_filename, int *handle, int dir_type, bool
|
||||
}
|
||||
|
||||
int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **ext_list, CFILE **img_cfp, int dir_type) {
|
||||
auto res = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, false);
|
||||
auto res = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type);
|
||||
|
||||
// could not be found, or is invalid for some reason
|
||||
if (!res.found)
|
||||
@@ -2622,7 +2623,7 @@ void bm_page_in_stop() {
|
||||
}
|
||||
}
|
||||
|
||||
mprintf(("Bmpman: %d/%d bitmap slots in use.\n", total_bitmaps, total_slots));
|
||||
nprintf(("BmpMan","BMPMAN: %d/%d bitmap slots in use.\n", total_bitmaps, total_slots));
|
||||
#endif
|
||||
|
||||
Bm_paging = 0;
|
||||
|
||||
@@ -116,6 +116,7 @@ extern const char *bm_ani_ext_list[]; //!< List of extensions for those types
|
||||
extern const int BM_ANI_NUM_TYPES; //!< Calculated number of bitmap animation types
|
||||
|
||||
extern int ENVMAP; //!< References a map that is for environment mapping -Bobboau
|
||||
extern int IRRMAP; //!< References a filtered envmap for diffuse environment lighting - qazwsxal
|
||||
|
||||
/**
|
||||
* @brief Initilizes the bitmap manager
|
||||
@@ -546,7 +547,6 @@ void bm_set_components_argb_32_tex(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, u
|
||||
*/
|
||||
void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
extern int ENVMAP; //this holds a reference to a map that is for environment mapping -Bobboau
|
||||
|
||||
/**
|
||||
* @brief Returns the compression type of the bitmap indexed by handle
|
||||
|
||||
@@ -831,7 +831,10 @@ void subtitle::do_frame(float frametime)
|
||||
|
||||
auto sizing_mode = do_screen_scaling ? GR_RESIZE_FULL : GR_RESIZE_NONE;
|
||||
if (do_screen_scaling)
|
||||
{
|
||||
gr_set_screen_scale(Show_subtitle_screen_adjusted_res[0], Show_subtitle_screen_adjusted_res[1]);
|
||||
gr_set_clip(0, 0, Show_subtitle_screen_adjusted_res[0], Show_subtitle_screen_adjusted_res[1]);
|
||||
}
|
||||
|
||||
// do the actual drawing ---------------------
|
||||
|
||||
@@ -879,7 +882,10 @@ void subtitle::do_frame(float frametime)
|
||||
// finished the actual drawing ---------------
|
||||
|
||||
if (do_screen_scaling)
|
||||
{
|
||||
gr_reset_screen_scale();
|
||||
gr_reset_clip();
|
||||
}
|
||||
|
||||
// restore old font
|
||||
if (old_fontnum >= 0)
|
||||
|
||||
+78
-57
@@ -59,8 +59,6 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
{ CF_TYPE_MODELS, "data" DIR_SEPARATOR_STR "models", ".pof", CF_TYPE_DATA },
|
||||
{ CF_TYPE_TABLES, "data" DIR_SEPARATOR_STR "tables", ".tbl .tbm .lua", CF_TYPE_DATA },
|
||||
{ CF_TYPE_SOUNDS, "data" DIR_SEPARATOR_STR "sounds", ".wav .ogg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_SOUNDS_8B22K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "8b22k", ".wav .ogg", CF_TYPE_SOUNDS },
|
||||
{ CF_TYPE_SOUNDS_16B11K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "16b11k", ".wav .ogg", CF_TYPE_SOUNDS },
|
||||
{ CF_TYPE_VOICE, "data" DIR_SEPARATOR_STR "voice", "", CF_TYPE_DATA },
|
||||
{ CF_TYPE_VOICE_BRIEFINGS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "briefing", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_VOICE_CMD_BRIEF, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "command_briefings", ".wav .ogg", CF_TYPE_VOICE },
|
||||
@@ -70,7 +68,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
{ CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt .webm .png",CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg .rml .rcss", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf .otf", CF_TYPE_DATA },
|
||||
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA },
|
||||
{ CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
@@ -79,6 +77,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
{ CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css .json", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr .json", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_PLAYER_BINDS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "presets", ".json", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA }, //clr=cached color
|
||||
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .jpg .dds .fs2 .txt", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA },
|
||||
@@ -88,10 +87,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc .fnl", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTERFACE_MARKUP, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "markup", ".rml", CF_TYPE_INTERFACE },
|
||||
{ CF_TYPE_INTERFACE_CSS, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "css", ".rcss", CF_TYPE_INTERFACE },
|
||||
{ CF_TYPE_PLAYER_BINDS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "presets", ".json", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -329,7 +325,7 @@ static int _cfile_chdir(const char *new_dir, const char *cur_dir __UNUSED)
|
||||
*/
|
||||
int cfile_push_chdir(int type)
|
||||
{
|
||||
char dir[CFILE_ROOT_DIRECTORY_LEN];
|
||||
SCP_string dir;
|
||||
char OriginalDirectory[CFILE_ROOT_DIRECTORY_LEN];
|
||||
|
||||
_getcwd(OriginalDirectory, CFILE_ROOT_DIRECTORY_LEN - 1);
|
||||
@@ -342,9 +338,9 @@ int cfile_push_chdir(int type)
|
||||
|
||||
strcpy_s(Cfile_stack[Cfile_stack_pos++], OriginalDirectory);
|
||||
|
||||
cf_create_default_path_string(dir, sizeof(dir) - 1, type, NULL);
|
||||
cf_create_default_path_string(dir, type, NULL);
|
||||
|
||||
return _cfile_chdir(dir, OriginalDirectory);
|
||||
return _cfile_chdir(dir.c_str(), OriginalDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -469,26 +465,26 @@ char *cf_add_ext(const char *filename, const char *ext)
|
||||
*/
|
||||
int cf_delete(const char *filename, int path_type, uint32_t location_flags)
|
||||
{
|
||||
char longname[MAX_PATH_LEN];
|
||||
SCP_string longname;
|
||||
|
||||
Assert(CF_TYPE_SPECIFIED(path_type));
|
||||
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, path_type, filename, false, location_flags);
|
||||
cf_create_default_path_string(longname, path_type, filename, location_flags);
|
||||
|
||||
return (_unlink(longname) != -1);
|
||||
return (_unlink(longname.c_str()) != -1);
|
||||
}
|
||||
|
||||
|
||||
// Same as _access function to read a file's access bits
|
||||
int cf_access(const char *filename, int dir_type, int mode)
|
||||
{
|
||||
char longname[MAX_PATH_LEN];
|
||||
SCP_string longname;
|
||||
|
||||
Assert( CF_TYPE_SPECIFIED(dir_type) );
|
||||
|
||||
cf_create_default_path_string( longname, sizeof(longname)-1, dir_type, filename );
|
||||
cf_create_default_path_string(longname, dir_type, filename);
|
||||
|
||||
return access(longname,mode);
|
||||
return access(longname.c_str(), mode);
|
||||
}
|
||||
|
||||
|
||||
@@ -533,18 +529,18 @@ int cf_exists_full_ext(const char *filename, int dir_type, const int num_ext, co
|
||||
#ifdef _WIN32
|
||||
void cf_attrib(const char *filename, int set, int clear, int dir_type)
|
||||
{
|
||||
char longname[MAX_PATH_LEN];
|
||||
SCP_string longname;
|
||||
|
||||
Assert( CF_TYPE_SPECIFIED(dir_type) );
|
||||
|
||||
cf_create_default_path_string( longname, sizeof(longname)-1, dir_type, filename );
|
||||
cf_create_default_path_string(longname, dir_type, filename);
|
||||
|
||||
FILE *fp = fopen(longname, "rb");
|
||||
FILE *fp = fopen(longname.c_str(), "rb");
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
|
||||
DWORD z = GetFileAttributes(longname);
|
||||
SetFileAttributes(longname, z | (set & ~clear));
|
||||
DWORD z = GetFileAttributes(longname.c_str());
|
||||
SetFileAttributes(longname.c_str(), z | (set & ~clear));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -555,13 +551,13 @@ int cf_rename(const char *old_name, const char *name, int dir_type)
|
||||
Assert( CF_TYPE_SPECIFIED(dir_type) );
|
||||
|
||||
int ret_code;
|
||||
char old_longname[_MAX_PATH];
|
||||
char new_longname[_MAX_PATH];
|
||||
SCP_string old_longname;
|
||||
SCP_string new_longname;
|
||||
|
||||
cf_create_default_path_string( old_longname, sizeof(old_longname)-1, dir_type, old_name );
|
||||
cf_create_default_path_string( new_longname, sizeof(old_longname)-1, dir_type, name );
|
||||
cf_create_default_path_string(old_longname, dir_type, old_name);
|
||||
cf_create_default_path_string(new_longname, dir_type, name);
|
||||
|
||||
ret_code = rename(old_longname, new_longname );
|
||||
ret_code = rename(old_longname.c_str(), new_longname.c_str());
|
||||
if(ret_code != 0){
|
||||
switch(errno){
|
||||
case EACCES :
|
||||
@@ -605,7 +601,7 @@ void cf_create_directory(int dir_type, uint32_t location_flags)
|
||||
{
|
||||
int num_dirs = 0;
|
||||
int dir_tree[CF_MAX_PATH_TYPES];
|
||||
char longname[MAX_PATH_LEN];
|
||||
SCP_string longname;
|
||||
struct stat statbuf;
|
||||
|
||||
Assertion( CF_TYPE_SPECIFIED(dir_type), "Invalid dir_type passed to cf_create_directory." );
|
||||
@@ -623,10 +619,10 @@ void cf_create_directory(int dir_type, uint32_t location_flags)
|
||||
int i;
|
||||
|
||||
for (i=num_dirs-1; i>=0; i-- ) {
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_tree[i], nullptr, false, location_flags);
|
||||
if (stat(longname, &statbuf) != 0) {
|
||||
mprintf(( "CFILE: Creating new directory '%s'\n", longname ));
|
||||
mkdir_recursive(longname);
|
||||
cf_create_default_path_string(longname, dir_tree[i], nullptr, location_flags);
|
||||
if (stat(longname.c_str(), &statbuf) != 0) {
|
||||
mprintf(( "CFILE: Creating new directory '%s'\n", longname.c_str() ));
|
||||
mkdir_recursive(longname.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -648,7 +644,7 @@ void cf_create_directory(int dir_type, uint32_t location_flags)
|
||||
//
|
||||
|
||||
CFILE* _cfopen(const char* source, int line, const char* file_path, const char* mode, int type, int dir_type,
|
||||
bool localize, uint32_t location_flags)
|
||||
bool /* localize */, uint32_t location_flags)
|
||||
{
|
||||
/* Bobboau, what is this doing here? 31 is way too short... - Goober5000
|
||||
if( strlen(file_path) > 31 )
|
||||
@@ -675,13 +671,13 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
// the harddisk. No fancy packfile stuff here!
|
||||
|
||||
if ( strchr(mode,'w') || strchr(mode,'+') || strchr(mode,'a') ) {
|
||||
char longname[_MAX_PATH];
|
||||
SCP_string longname;
|
||||
auto last_separator = strrchr(file_path, DIR_SEPARATOR_CHAR);
|
||||
|
||||
// For write-only files, require a full path or a path type
|
||||
if ( last_separator ) {
|
||||
// Full path given?
|
||||
strcpy_s(longname, file_path );
|
||||
longname = file_path;
|
||||
} else {
|
||||
// Path type given?
|
||||
Assert( dir_type != CF_TYPE_ANY );
|
||||
@@ -689,7 +685,7 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
// Create the directory if necessary
|
||||
cf_create_directory(dir_type, location_flags);
|
||||
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_type, file_path, false, location_flags);
|
||||
cf_create_default_path_string(longname, dir_type, file_path, location_flags);
|
||||
}
|
||||
Assert( !(type & CFILE_MEMORY_MAPPED) );
|
||||
|
||||
@@ -728,7 +724,7 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
strcpy_s(happy_mode, mode);
|
||||
}
|
||||
|
||||
FILE *fp = fopen(longname, happy_mode);
|
||||
FILE *fp = fopen(longname.c_str(), happy_mode);
|
||||
if (fp) {
|
||||
return cf_open_fill_cfblock(source, line, last_separator ? (last_separator + 1) : file_path, fp, dir_type);
|
||||
}
|
||||
@@ -739,10 +735,8 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
|
||||
//================================================
|
||||
// Search for file on disk, on cdrom, or in a packfile
|
||||
|
||||
char copy_file_path[MAX_PATH_LEN]; // FIX change in memory from cf_find_file_location
|
||||
strcpy_s(copy_file_path, file_path);
|
||||
auto find_res = cf_find_file_location(file_path, dir_type, location_flags);
|
||||
|
||||
auto find_res = cf_find_file_location( copy_file_path, dir_type, localize, location_flags );
|
||||
if ( find_res.found ) {
|
||||
|
||||
// Fount it, now create a cfile out of it
|
||||
@@ -1239,15 +1233,17 @@ void cfread_string(char *buf, int n, CFILE *file)
|
||||
} while (c != 0 );
|
||||
}
|
||||
|
||||
void cfread_string_len(char *buf,int n, CFILE *file)
|
||||
void cfread_string_len(char *buf, int buffer_size, CFILE *file)
|
||||
{
|
||||
int len;
|
||||
len = cfread_int(file);
|
||||
Assertion( (len < n), "len: %i, n: %i", len, n );
|
||||
if (len)
|
||||
Assertion( (len <= buffer_size), "String cannot fit in buffer, len: %i, buffer: %i", len, buffer_size);
|
||||
if (len) {
|
||||
cfread(buf, len, 1, file);
|
||||
Assertion(len != buffer_size || buf[len - 1] == 0, "Unterminated string does not fit in buffer");
|
||||
}
|
||||
|
||||
buf[len] = 0;
|
||||
buf[MIN(len, buffer_size - 1)] = 0;
|
||||
}
|
||||
|
||||
SCP_string cfread_string_len(CFILE *file)
|
||||
@@ -1846,28 +1842,53 @@ int cfile_get_path_type(const SCP_string& dir)
|
||||
{
|
||||
SCP_string buf = dir;
|
||||
|
||||
// Remove trailing slashes; avoid buffer overflow on 1-char strings
|
||||
while (buf.size() > 0 && (buf[buf.size() - 1] == '\\' || buf[buf.size() - 1] == '/')) {
|
||||
buf.resize(buf.size() - 1);
|
||||
// remove leading and trailing slashes
|
||||
if ( !buf.empty() ) {
|
||||
auto start = buf.find_first_not_of("\\/");
|
||||
auto end = buf.find_last_not_of("\\/");
|
||||
|
||||
if (start == SCP_string::npos) {
|
||||
buf = "";
|
||||
} else if ( (start > 0) || (end < buf.length()-1) ) {
|
||||
buf = buf.substr(start, end-start+1);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove leading slashes
|
||||
while (buf.size() > 0 && (buf[0] == '\\' || buf[0] == '/')) {
|
||||
buf = buf.substr(1);
|
||||
if (buf.empty()) {
|
||||
return CF_TYPE_ROOT;
|
||||
}
|
||||
|
||||
// Use official DIR_SEPARATOR_CHAR
|
||||
for (char& c : buf) {
|
||||
if (c == '\\' || c == '/') {
|
||||
c = DIR_SEPARATOR_CHAR;
|
||||
}
|
||||
}
|
||||
extern void normalize_directory_separators(SCP_string &str);
|
||||
normalize_directory_separators(buf);
|
||||
|
||||
// identify path type
|
||||
auto best_match = CF_TYPE_INVALID;
|
||||
|
||||
for (auto& Pathtype : Pathtypes) {
|
||||
if (Pathtype.path != nullptr && buf == Pathtype.path) {
|
||||
return Pathtype.index;
|
||||
if ( !Pathtype.path ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip root, it should have been detected before getting here
|
||||
if (Pathtype.index == CF_TYPE_ROOT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't allow unknown subdirs directly under data
|
||||
if (Pathtype.index == CF_TYPE_DATA) {
|
||||
if (buf == Pathtype.path) {
|
||||
best_match = CF_TYPE_DATA;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// for everything else just find closest match, allowing for unknown subdirectories
|
||||
if ( !strnicmp(buf.c_str(), Pathtype.path, strlen(Pathtype.path)) ) {
|
||||
best_match = Pathtype.index;
|
||||
}
|
||||
}
|
||||
|
||||
return CF_TYPE_INVALID;
|
||||
return best_match;
|
||||
}
|
||||
+37
-40
@@ -49,42 +49,38 @@ typedef struct {
|
||||
#define CF_TYPE_MODELS 5
|
||||
#define CF_TYPE_TABLES 6
|
||||
#define CF_TYPE_SOUNDS 7
|
||||
#define CF_TYPE_SOUNDS_8B22K 8
|
||||
#define CF_TYPE_SOUNDS_16B11K 9
|
||||
#define CF_TYPE_VOICE 10
|
||||
#define CF_TYPE_VOICE_BRIEFINGS 11
|
||||
#define CF_TYPE_VOICE_CMD_BRIEF 12
|
||||
#define CF_TYPE_VOICE_DEBRIEFINGS 13
|
||||
#define CF_TYPE_VOICE_PERSONAS 14
|
||||
#define CF_TYPE_VOICE_SPECIAL 15
|
||||
#define CF_TYPE_VOICE_TRAINING 16
|
||||
#define CF_TYPE_MUSIC 17
|
||||
#define CF_TYPE_MOVIES 18
|
||||
#define CF_TYPE_INTERFACE 19
|
||||
#define CF_TYPE_FONT 20
|
||||
#define CF_TYPE_EFFECTS 21
|
||||
#define CF_TYPE_HUD 22
|
||||
#define CF_TYPE_PLAYERS 23
|
||||
#define CF_TYPE_PLAYER_IMAGES 24
|
||||
#define CF_TYPE_SQUAD_IMAGES 25
|
||||
#define CF_TYPE_SINGLE_PLAYERS 26
|
||||
#define CF_TYPE_MULTI_PLAYERS 27
|
||||
#define CF_TYPE_CACHE 28
|
||||
#define CF_TYPE_MULTI_CACHE 29
|
||||
#define CF_TYPE_MISSIONS 30
|
||||
#define CF_TYPE_CONFIG 31
|
||||
#define CF_TYPE_DEMOS 32
|
||||
#define CF_TYPE_CBANIMS 33
|
||||
#define CF_TYPE_INTEL_ANIMS 34
|
||||
#define CF_TYPE_SCRIPTS 35
|
||||
#define CF_TYPE_FICTION 36
|
||||
#define CF_TYPE_FREDDOCS 37
|
||||
#define CF_TYPE_INTERFACE_MARKUP 38
|
||||
#define CF_TYPE_INTERFACE_CSS 39
|
||||
#define CF_TYPE_PLAYER_BINDS 40
|
||||
#define CF_TYPE_VOICE 8
|
||||
#define CF_TYPE_VOICE_BRIEFINGS 9
|
||||
#define CF_TYPE_VOICE_CMD_BRIEF 10
|
||||
#define CF_TYPE_VOICE_DEBRIEFINGS 11
|
||||
#define CF_TYPE_VOICE_PERSONAS 12
|
||||
#define CF_TYPE_VOICE_SPECIAL 13
|
||||
#define CF_TYPE_VOICE_TRAINING 14
|
||||
#define CF_TYPE_MUSIC 15
|
||||
#define CF_TYPE_MOVIES 16
|
||||
#define CF_TYPE_INTERFACE 17
|
||||
#define CF_TYPE_FONT 18
|
||||
#define CF_TYPE_EFFECTS 19
|
||||
#define CF_TYPE_HUD 20
|
||||
#define CF_TYPE_PLAYERS 21
|
||||
#define CF_TYPE_PLAYER_IMAGES 22
|
||||
#define CF_TYPE_SQUAD_IMAGES 23
|
||||
#define CF_TYPE_SINGLE_PLAYERS 24
|
||||
#define CF_TYPE_MULTI_PLAYERS 25
|
||||
#define CF_TYPE_PLAYER_BINDS 26
|
||||
#define CF_TYPE_CACHE 27
|
||||
#define CF_TYPE_MULTI_CACHE 28
|
||||
#define CF_TYPE_MISSIONS 29
|
||||
#define CF_TYPE_CONFIG 30
|
||||
#define CF_TYPE_DEMOS 31
|
||||
#define CF_TYPE_CBANIMS 32
|
||||
#define CF_TYPE_INTEL_ANIMS 33
|
||||
#define CF_TYPE_SCRIPTS 34
|
||||
#define CF_TYPE_FICTION 35
|
||||
#define CF_TYPE_FREDDOCS 36
|
||||
|
||||
#define CF_MAX_PATH_TYPES \
|
||||
41 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
|
||||
37 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
|
||||
|
||||
// TRUE if type is specified and valid
|
||||
#define CF_TYPE_SPECIFIED(path_type) (((path_type)>CF_TYPE_INVALID) && ((path_type)<CF_MAX_PATH_TYPES))
|
||||
@@ -326,15 +322,17 @@ void cfread_vector(vec3d* vec, CFILE* file, vec3d* deflt = nullptr);
|
||||
// to n characters.
|
||||
void cfread_string(char *buf,int n, CFILE *file);
|
||||
/**
|
||||
* @brief Read a fixed length string that is not null-terminated, with the length stored in file
|
||||
* @brief Read a fixed length string that is not null-terminated, with the length stored in file.
|
||||
*
|
||||
* If it is not null-terminated, the length of the string *must* be less than the size of the buffer (to make room for one)
|
||||
*
|
||||
* @param buf Pre-allocated array to store string
|
||||
* @param n Size of pre-allocated array
|
||||
* @param buffer_size Size of pre-allocated array
|
||||
* @param file File to read from
|
||||
*
|
||||
* @note Appends NULL character to string (buf)
|
||||
*/
|
||||
void cfread_string_len(char *buf,int n, CFILE *file);
|
||||
void cfread_string_len(char *buf,int buffer_size, CFILE *file);
|
||||
|
||||
/**
|
||||
* @brief Read a string from the file where the length is stored in the file
|
||||
@@ -393,7 +391,7 @@ struct CFileLocation {
|
||||
// size - File size
|
||||
// offset - Offset into pack file. 0 if not a packfile.
|
||||
// Returns: If not found returns 0.
|
||||
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize = false,
|
||||
CFileLocation cf_find_file_location(const char* filespec, int pathtype,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
|
||||
struct CFileLocationExt : public CFileLocation {
|
||||
@@ -417,8 +415,7 @@ struct CFileLocationExt : public CFileLocation {
|
||||
// offset - Offset into pack file. 0 if not a packfile.
|
||||
// Returns: If not found returns -1, else returns offset into ext_list.
|
||||
// (NOTE: This function is exponentially slow, so don't use it unless truely needed!!)
|
||||
CFileLocationExt cf_find_file_location_ext(const char* filename, const int ext_num, const char** ext_list, int pathtype,
|
||||
bool localize = false);
|
||||
CFileLocationExt cf_find_file_location_ext(const char* filename, const int ext_num, const char** ext_list, int pathtype);
|
||||
|
||||
// Functions to change directories
|
||||
int cfile_chdir(const char *dir);
|
||||
|
||||
+618
-338
File diff suppressed because it is too large.
Load diff
@@ -42,8 +42,8 @@ bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags);
|
||||
// Output: path - Fully qualified pathname.
|
||||
//Returns 0 if result would be too long (invalid result)
|
||||
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename = nullptr,
|
||||
bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename = nullptr, bool localize = false,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename = nullptr,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
|
||||
#endif //_CFILESYSTEM_H
|
||||
@@ -0,0 +1,181 @@
|
||||
#include "cheats_table.h"
|
||||
#include "parse/parselo.h"
|
||||
|
||||
void cheat_table_init() {
|
||||
customCheats.clear();
|
||||
|
||||
if (cf_exists_full("cheats.tbl", CF_TYPE_TABLES)) {
|
||||
parse_cheat_table("cheats.tbl");
|
||||
}
|
||||
parse_modular_table("*-cht.tbm", parse_cheat_table);
|
||||
}
|
||||
|
||||
bool CustomCheat::canUseCheat() {
|
||||
return !requireCheatsEnabled || Cheats_enabled;
|
||||
}
|
||||
|
||||
void CustomCheat::runCheat() {
|
||||
if (!canUseCheat()) return;
|
||||
HUD_printf("%s", cheatMsg.c_str());
|
||||
scripting::hooks::OnCheat->run(scripting::hook_param_list(scripting::hook_param("Cheat", 's', cheatCode)));
|
||||
CheatUsed = cheatCode;
|
||||
}
|
||||
|
||||
void SpawnShipCheat::runCheat() {
|
||||
CustomCheat::runCheat();
|
||||
|
||||
if (canUseCheat() && (Game_mode & GM_IN_MISSION) && Player_obj != nullptr) {
|
||||
extern void prevent_spawning_collision(object *new_obj);
|
||||
ship_subsys *ptr;
|
||||
char name[NAME_LENGTH];
|
||||
int ship_idx, ship_class;
|
||||
|
||||
// if not found, then don't create it :(
|
||||
ship_class = ship_info_lookup(shipClassName.c_str());
|
||||
if (ship_class < 0)
|
||||
return;
|
||||
|
||||
vec3d pos = Player_obj->pos;
|
||||
matrix orient = Player_obj->orient;
|
||||
pos.xyz.x += frand_range(-700.0f, 700.0f);
|
||||
pos.xyz.y += frand_range(-700.0f, 700.0f);
|
||||
pos.xyz.z += frand_range(-700.0f, 700.0f);
|
||||
|
||||
int objnum = ship_create(&orient, &pos, ship_class);
|
||||
if (objnum < 0)
|
||||
return;
|
||||
|
||||
ship *shipp = &Ships[Objects[objnum].instance];
|
||||
shipp->ship_name[0] = '\0';
|
||||
shipp->display_name.clear();
|
||||
for (size_t j = 0; j < Player_orders.size(); j++)
|
||||
shipp->orders_accepted.insert(j);
|
||||
|
||||
// Goober5000 - stolen from support ship creation
|
||||
// create a name for the ship with a number. look for collisions until one isn't found anymore
|
||||
ship_idx = 1;
|
||||
do {
|
||||
sprintf(name, "%s %d", shipName.c_str(), ship_idx);
|
||||
if ( (ship_name_lookup(name) == -1) && (ship_find_exited_ship_by_name(name) == -1) )
|
||||
{
|
||||
strcpy_s(shipp->ship_name, name);
|
||||
break;
|
||||
}
|
||||
|
||||
ship_idx++;
|
||||
} while(1);
|
||||
|
||||
shipp->flags.set(Ship::Ship_Flags::Escort);
|
||||
shipp->escort_priority = 1000 - ship_idx;
|
||||
|
||||
// now make sure we're not colliding with anyone
|
||||
prevent_spawning_collision(&Objects[objnum]);
|
||||
|
||||
// Goober5000 - beam free
|
||||
for (ptr = GET_FIRST(&shipp->subsys_list); ptr != END_OF_LIST(&shipp->subsys_list); ptr = GET_NEXT(ptr))
|
||||
{
|
||||
// mark all turrets as beam free
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// Cyborg17 to prevent a nullptr...
|
||||
ship_set_warp_effects(&Objects[objnum]);
|
||||
// warpin
|
||||
shipfx_warpin_start(&Objects[objnum]);
|
||||
}
|
||||
}
|
||||
|
||||
void parse_cheat_table(const char* filename) {
|
||||
try {
|
||||
read_file_text(filename, CF_TYPE_TABLES);
|
||||
reset_parse();
|
||||
optional_string("#CUSTOM CHEATS");
|
||||
|
||||
while (optional_string("$Cheat:")) {
|
||||
SCP_string code, msg, shipClass, shipName;
|
||||
bool requireCheats = false;
|
||||
bool shipSpawn = false;
|
||||
required_string("+Code:");
|
||||
stuff_string(code, F_RAW);
|
||||
|
||||
//We are limited to the buffer size used for the traditional cheats. We can still use short cheats, though.
|
||||
if (code.length() > CHEAT_BUFFER_LEN) {
|
||||
Warning(LOCATION, "Cheat code %s is too long. It will be cut off to maximum length (%i characters).", code.c_str(), CHEAT_BUFFER_LEN);
|
||||
code = code.substr(0, CHEAT_BUFFER_LEN);
|
||||
}
|
||||
|
||||
required_string("+Message:");
|
||||
stuff_string(msg, F_MESSAGE);
|
||||
|
||||
if (optional_string("+RequireCheats:")) {
|
||||
stuff_boolean(&requireCheats);
|
||||
}
|
||||
|
||||
if (optional_string("+SpawnShip:")) {
|
||||
shipSpawn = true;
|
||||
required_string("+Name:");
|
||||
stuff_string(shipName, F_NAME);
|
||||
required_string("+Class:");
|
||||
stuff_string(shipClass, F_NAME);
|
||||
|
||||
int shipClassInfo = ship_info_lookup(shipClass.c_str());
|
||||
if (shipClassInfo < 0) {
|
||||
shipSpawn = false;
|
||||
Warning(LOCATION, "There is no ship class named '%s'. The '%s' cheat won't summon a ship.", shipClass.c_str(), code.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (shipSpawn) {
|
||||
std::unique_ptr<CustomCheat> shipCheat(new SpawnShipCheat(code, msg, requireCheats, shipClass, shipName));
|
||||
|
||||
if(customCheats.count(code) == 1) {
|
||||
Warning(LOCATION, "A cheat for code '%s' already exists. It will be replaced.", code.c_str());
|
||||
customCheats[code] = std::move(shipCheat);
|
||||
} else {
|
||||
customCheats.emplace(code, std::move(shipCheat));
|
||||
}
|
||||
} else {
|
||||
std::unique_ptr<CustomCheat> cheat(new CustomCheat(code, msg, requireCheats));
|
||||
|
||||
if(customCheats.count(code) == 1) {
|
||||
Warning(LOCATION, "A cheat for code '%s' already exists. It will be replaced.", code.c_str());
|
||||
customCheats[code] = std::move(cheat);
|
||||
} else {
|
||||
customCheats.emplace(code, std::move(cheat));
|
||||
}
|
||||
}
|
||||
}
|
||||
required_string("#END");
|
||||
}
|
||||
catch (const parse::ParseException& e) {
|
||||
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool checkForCustomCheats(const char* buffer, int buffer_length) {
|
||||
const char* check_buffer = buffer;
|
||||
for (int i = 0; i < buffer_length; i++) {
|
||||
if (*check_buffer == '\0') {
|
||||
check_buffer++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through our map of custom cheats and check if the code is within the buffer.
|
||||
// We don't just check for equality, as the player may have typed other characters before the cheat.
|
||||
for (auto &ccheat : customCheats) {
|
||||
auto found = std::strstr(check_buffer, ccheat.first.c_str());
|
||||
if (found != nullptr) {
|
||||
ccheat.second->runCheat();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "globalincs/globals.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "io/key.h"
|
||||
#include "hud/hudmessage.h"
|
||||
#include "hud/hudsquadmsg.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
#include "scripting/hook_api.h"
|
||||
#include "ship/ship.h"
|
||||
#include "ship/shipfx.h"
|
||||
|
||||
#define CHEAT_BUFFER_LEN 17
|
||||
|
||||
class CustomCheat {
|
||||
public:
|
||||
SCP_string cheatCode;
|
||||
SCP_string cheatMsg;
|
||||
bool requireCheatsEnabled;
|
||||
|
||||
CustomCheat(SCP_string cheat_code, SCP_string cheat_msg, bool require_cheats_enabled) :
|
||||
cheatCode(std::move(cheat_code)),
|
||||
cheatMsg(std::move(cheat_msg)),
|
||||
requireCheatsEnabled(require_cheats_enabled) { }
|
||||
|
||||
virtual ~CustomCheat() = default;
|
||||
|
||||
virtual void runCheat();
|
||||
|
||||
bool canUseCheat();
|
||||
};
|
||||
|
||||
class SpawnShipCheat : public CustomCheat {
|
||||
protected:
|
||||
SCP_string shipClassName;
|
||||
SCP_string shipName;
|
||||
public:
|
||||
|
||||
SpawnShipCheat(SCP_string cheat_code, SCP_string cheat_msg, bool require_cheats_enabled, SCP_string class_name, SCP_string ship_name) : CustomCheat(cheat_code, cheat_msg, require_cheats_enabled),
|
||||
shipClassName(std::move(class_name)),
|
||||
shipName(std::move(ship_name)) { }
|
||||
|
||||
void runCheat() override;
|
||||
};
|
||||
|
||||
static SCP_map<SCP_string, std::unique_ptr<CustomCheat>> customCheats;
|
||||
|
||||
void cheat_table_init();
|
||||
void parse_cheat_table(const char* filename);
|
||||
bool checkForCustomCheats(const char* converted_buffer, int buffer_length);
|
||||
+91
-47
@@ -22,6 +22,7 @@
|
||||
#include "network/multi_log.h"
|
||||
#include "options/OptionsManager.h"
|
||||
#include "osapi/osapi.h"
|
||||
#include "osapi/dialogs.h"
|
||||
#include "parse/sexp.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "sound/openal.h"
|
||||
@@ -155,6 +156,7 @@ typedef struct
|
||||
// Please group them by type, ie graphics, gameplay etc, maximum 20 different types
|
||||
Flag exe_params[] =
|
||||
{
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-nospec", "Disable specular", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nospec", },
|
||||
{ "-noglow", "Disable glow maps", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noglow", },
|
||||
{ "-noenv", "Disable environment maps", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noenv", },
|
||||
@@ -170,9 +172,12 @@ Flag exe_params[] =
|
||||
{ "-fb_thrusters", "Enable Framebuffer Thrusters", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_thrusters", },
|
||||
{ "-no_deferred", "Disable Deferred Lighting", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_deferred"},
|
||||
{ "-enable_shadows", "Enable Shadows", true, EASY_ALL_ON | EASY_HI_MEM_ON, EASY_DEFAULT | EASY_HI_MEM_OFF, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-enable_shadows"},
|
||||
{ "-deferred_cockpit", "Enable Deferred Lighting for Cockpits", true, EASY_ALL_ON | EASY_HI_MEM_ON, EASY_DEFAULT | EASY_HI_MEM_OFF, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-deferred_cockpit"},
|
||||
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-no_vsync", "Disable vertical sync", true, 0, EASY_DEFAULT, "Game Speed", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_vsync", },
|
||||
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-fps", "Show frames per second on HUD", false, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fps", },
|
||||
{ "-dualscanlines", "Add another pair of scanning lines", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-dualscanlines", },
|
||||
{ "-targetinfo", "Enable info next to target", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-targetinfo", },
|
||||
@@ -180,25 +185,27 @@ Flag exe_params[] =
|
||||
{ "-rearm_timer", "Enable rearm/repair completion timer", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-rearm_timer", },
|
||||
{ "-ballistic_gauge", "Enable analog ballistic ammo gauge", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-ballistic_gauge", },
|
||||
|
||||
//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", },
|
||||
{ "-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",},
|
||||
{ "-ship_choice_3d", "Use 3D models for ship selection", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-ship_choice_3d", },
|
||||
{ "-weapon_choice_3d", "Use 3D models for weapon selection", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-weapon_choice_3d", },
|
||||
{ "-3dwarp", "Enable 3D warp", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dwarp", },
|
||||
{ "-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", },
|
||||
|
||||
//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", },
|
||||
{ "-nomusic", "Disable music", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomusic", },
|
||||
{ "-no_enhanced_sound", "Disable enhanced sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_enhanced_sound", },
|
||||
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-portable_mode", "Store config in portable location", false, 0, EASY_DEFAULT, "Launcher", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-portable_mode", },
|
||||
{ "-joy_info", "Outputs SDL joystick info", true, 0, EASY_DEFAULT, "Launcher", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-joy_info",},
|
||||
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-standalone", "Run as standalone server", false, 0, EASY_DEFAULT, "Multiplayer", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-standalone", },
|
||||
{ "-startgame", "Skip mainhall and start hosting", false, 0, EASY_DEFAULT, "Multiplayer", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-startgame", },
|
||||
{ "-closed", "Start hosted server as closed", false, 0, EASY_DEFAULT, "Multiplayer", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-closed", },
|
||||
@@ -207,7 +214,9 @@ Flag exe_params[] =
|
||||
{ "-clientdamage", "", false, 0, EASY_DEFAULT, "Multiplayer", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-clientdamage", },
|
||||
{ "-mpnoreturn", "Disable flight deck option", true, 0, EASY_DEFAULT, "Multiplayer", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-mpnoreturn", },
|
||||
{ "-gateway_ip", "Set gateway IP address", false, 0, EASY_DEFAULT, "Multiplayer", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-gateway_ip", },
|
||||
{ "-ingame_join", "Disable in-game joining", true, 0, EASY_DEFAULT, "Multiplayer", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-ingame_join", },
|
||||
|
||||
//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", },
|
||||
{ "-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", },
|
||||
@@ -230,9 +239,11 @@ Flag exe_params[] =
|
||||
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fix_registry", },
|
||||
#endif
|
||||
|
||||
{ "-ingame_join", "Allow in-game joining", true, 0, EASY_DEFAULT, "Experimental", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-ingame_join", },
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-voicer", "Enable voice recognition", true, 0, EASY_DEFAULT, "Experimental", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-voicer", },
|
||||
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-override_data", "Enable override directory", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-override_data", },
|
||||
{ "-bmpmanusage", "Show how many BMPMAN slots are in use", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-bmpmanusage", },
|
||||
{ "-pos", "Show position of camera", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-pos", },
|
||||
{ "-stats", "Show statistics", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stats", },
|
||||
@@ -260,6 +271,8 @@ Flag exe_params[] =
|
||||
{ "-gr_debug", "Output graphics debug information", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-gr_debug", },
|
||||
{ "-stdout_log", "Output log file to stdout", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stdout_log", },
|
||||
{ "-slow_frames_ok", "Don't adjust timestamps for slow frames", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-slow_frames_ok", },
|
||||
{ "-imgui_debug", "Show imgui debug/demo window in the lab", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-imgui_debug", },
|
||||
{ "-luadev", "Make lua errors non-fatal", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-luadev", },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -317,16 +330,15 @@ int Cmdline_use_last_pilot = 0;
|
||||
cmdline_parm fov_arg("-fov", "Vertical field-of-view factor", AT_FLOAT); // Cmdline_fov -- comand line FOV -Bobboau
|
||||
cmdline_parm fov_cockpit_arg("-fov_cockpit", "Vertical field-of-view factor for Cockpits", AT_FLOAT);
|
||||
cmdline_parm clip_dist_arg("-clipdist", "Changes the distance from the viewpoint for the near-clipping plane", AT_FLOAT); // Cmdline_clip_dist
|
||||
cmdline_parm spec_static_arg("-spec_static", "Adjusts suns contribution to specular highlights", AT_FLOAT);
|
||||
cmdline_parm spec_point_arg("-spec_point", "Adjusts laser weapons contribution to specular highlights", AT_FLOAT);
|
||||
cmdline_parm spec_tube_arg("-spec_tube", "Adjusts beam weapons contribution to specular highlights", AT_FLOAT);
|
||||
cmdline_parm ambient_factor_arg("-ambient_factor", "Adjusts ambient light applied to all parts of a ship", AT_INT); // Cmdline_ambient_factor
|
||||
cmdline_parm ambient_power_arg("-ambient", "Multiplies the brightness of all ambient light", AT_FLOAT);
|
||||
cmdline_parm light_power_arg("-light", "Multiplies the brightness of all light", AT_FLOAT);
|
||||
cmdline_parm emissive_power_arg("-emissive", "Multiplies the brightness of all ambient light", AT_FLOAT);
|
||||
cmdline_parm emissive_arg("-emissive_light", "Enable emissive light from ships", AT_NONE); // semi-deprecated but still functional
|
||||
cmdline_parm env("-noenv", NULL, AT_NONE); // Cmdline_env
|
||||
cmdline_parm glow_arg("-noglow", NULL, AT_NONE); // Cmdline_glow -- use Bobs glow code
|
||||
cmdline_parm nomotiondebris_arg("-nomotiondebris", NULL, AT_NONE); // Cmdline_nomotiondebris -- Removes those ugly floating rocks -C
|
||||
cmdline_parm noscalevid_arg("-noscalevid", NULL, AT_NONE); // Cmdline_noscalevid -- disable video scaling that fits to window
|
||||
cmdline_parm spec_arg("-nospec", NULL, AT_NONE); // Cmdline_spec --
|
||||
cmdline_parm emissive_arg("-emissive_light", "Enable emissive light from ships", AT_NONE); // Cmdline_no_emissive -- don't use emissive light in OGL
|
||||
cmdline_parm normal_arg("-nonormal", NULL, AT_NONE); // Cmdline_normal -- disable normal mapping
|
||||
cmdline_parm height_arg("-noheight", NULL, AT_NONE); // Cmdline_height -- enable support for parallax mapping
|
||||
cmdline_parm enable_3d_shockwave_arg("-3dshockwave", NULL, AT_NONE);
|
||||
@@ -345,10 +357,13 @@ cmdline_parm flightshaftsoff_arg("-nolightshafts", NULL, AT_NONE);
|
||||
cmdline_parm shadow_quality_arg("-shadow_quality", NULL, AT_INT);
|
||||
cmdline_parm enable_shadows_arg("-enable_shadows", NULL, AT_NONE);
|
||||
cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline_no_deferred
|
||||
cmdline_parm deferred_lighting_cockpit_arg("-deferred_cockpit", nullptr, AT_NONE);
|
||||
cmdline_parm anisotropy_level_arg("-anisotropic_filter", NULL, AT_INT);
|
||||
|
||||
float Cmdline_clip_dist = Default_min_draw_distance;
|
||||
int Cmdline_ambient_factor = 128;
|
||||
float Cmdline_ambient_power = 1.0f;
|
||||
float Cmdline_emissive_power = 0.0f;
|
||||
float Cmdline_light_power = 1.0f;
|
||||
int Cmdline_env = 1;
|
||||
int Cmdline_mipmap = 0;
|
||||
int Cmdline_glow = 1;
|
||||
@@ -362,6 +377,7 @@ int Cmdline_softparticles = 0;
|
||||
int Cmdline_bloom_intensity = 25;
|
||||
bool Cmdline_force_lightshaft_off = false;
|
||||
int Cmdline_no_deferred_lighting = 0;
|
||||
bool Cmdline_deferred_lighting_cockpit = false;
|
||||
int Cmdline_aniso_level = 0;
|
||||
|
||||
// Game Speed related
|
||||
@@ -373,21 +389,18 @@ int Cmdline_no_vsync = 0;
|
||||
|
||||
// HUD related
|
||||
cmdline_parm ballistic_gauge("-ballistic_gauge", NULL, AT_NONE); // Cmdline_ballistic_gauge
|
||||
cmdline_parm dualscanlines_arg("-dualscanlines", NULL, AT_NONE); // Cmdline_dualscanlines -- Change to phreaks options including new targeting code
|
||||
cmdline_parm dualscanlines_arg("-dualscanlines", NULL, AT_NONE); // Cmdline_dualscanlines -- Change to phreaks options including new targeting code; semi-deprecated but still functional
|
||||
cmdline_parm orb_radar("-orbradar", NULL, AT_NONE); // Cmdline_orb_radar
|
||||
cmdline_parm rearm_timer_arg("-rearm_timer", NULL, AT_NONE); // Cmdline_rearm_timer
|
||||
cmdline_parm targetinfo_arg("-targetinfo", NULL, AT_NONE); // Cmdline_targetinfo -- Adds ship name/class to right of target box -C
|
||||
cmdline_parm rearm_timer_arg("-rearm_timer", NULL, AT_NONE); // Cmdline_rearm_timer; semi-deprecated but still functional-Mjn
|
||||
cmdline_parm targetinfo_arg("-targetinfo", NULL, AT_NONE); // Cmdline_targetinfo -- Adds ship name/class to right of target box -C; semi-deprecated but still functional-Mjn
|
||||
|
||||
int Cmdline_ballistic_gauge = 0; // WMCoolmon's gauge thingy
|
||||
int Cmdline_dualscanlines = 0;
|
||||
int Cmdline_orb_radar = 0;
|
||||
int Cmdline_rearm_timer = 0;
|
||||
int Cmdline_targetinfo = 0;
|
||||
|
||||
// Gameplay related
|
||||
cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3d_warp
|
||||
cmdline_parm ship_choice_3d_arg("-ship_choice_3d", nullptr, AT_NONE); // Cmdline_ship_choice_3d
|
||||
cmdline_parm weapon_choice_3d_arg("-weapon_choice_3d", nullptr, AT_NONE); // Cmdline_weapon_choice_3d
|
||||
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
|
||||
@@ -397,7 +410,6 @@ cmdline_parm deadzone("-deadzone",
|
||||
|
||||
int Cmdline_ship_choice_3d = 0;
|
||||
int Cmdline_weapon_choice_3d = 0;
|
||||
int Cmdline_warp_flash = 0;
|
||||
int Cmdline_autopilot_interruptable = 1;
|
||||
int Cmdline_stretch_menu = 0;
|
||||
int Cmdline_no_screenshake = 0;
|
||||
@@ -421,8 +433,8 @@ cmdline_parm mpnoreturn_arg("-mpnoreturn", NULL, AT_NONE); // Cmdline_mpnoreturn
|
||||
cmdline_parm objupd_arg("-cap_object_update", "Multiplayer object update cap (0-3)", AT_INT);
|
||||
cmdline_parm gateway_ip_arg("-gateway_ip", "Set gateway IP address", AT_STRING);
|
||||
|
||||
char *Cmdline_almission = NULL; //DTP for autoload multi mission.
|
||||
int Cmdline_ingamejoin = 0;
|
||||
char *Cmdline_almission = nullptr; //DTP for autoload multi mission.
|
||||
int Cmdline_ingamejoin = 1;
|
||||
int Cmdline_mpnoreturn = 0;
|
||||
int Cmdline_objupd = 3; // client object updates on LAN by default
|
||||
char *Cmdline_gateway_ip = nullptr;
|
||||
@@ -476,6 +488,8 @@ bool Cmdline_dump_packet_type = false;
|
||||
#ifdef WIN32
|
||||
bool Cmdline_alternate_registry_path = false;
|
||||
#endif
|
||||
uint Cmdline_rng_seed = 0;
|
||||
bool Cmdline_reuse_rng_seed = false;
|
||||
|
||||
// Developer/Testing related
|
||||
cmdline_parm start_mission_arg("-start_mission", "Skip mainhall and run this mission", AT_STRING); // Cmdline_start_mission
|
||||
@@ -507,7 +521,10 @@ cmdline_parm debug_window_arg("-debug_window", NULL, AT_NONE); // Cmdline_debug_
|
||||
cmdline_parm graphics_debug_output_arg("-gr_debug", nullptr, AT_NONE); // Cmdline_graphics_debug_output
|
||||
cmdline_parm log_to_stdout_arg("-stdout_log", nullptr, AT_NONE); // Cmdline_log_to_stdout
|
||||
cmdline_parm slow_frames_ok_arg("-slow_frames_ok", nullptr, AT_NONE); // Cmdline_slow_frames_ok
|
||||
|
||||
cmdline_parm fixed_seed_rand("-seed", nullptr, AT_INT); // Cmdline_rng_seed,Cmdline_reuse_rng_seed;
|
||||
cmdline_parm luadev_arg("-luadev", "Make lua errors non-fatal", AT_NONE); // Cmdline_lua_devmode
|
||||
cmdline_parm override_arg("-override_data", "Enable override directory", AT_NONE); // Cmdline_override_data
|
||||
cmdline_parm imgui_debug_arg("-imgui_debug", nullptr, AT_NONE);
|
||||
|
||||
char *Cmdline_start_mission = NULL;
|
||||
int Cmdline_dis_collisions = 0;
|
||||
@@ -540,6 +557,9 @@ bool Cmdline_debug_window = false;
|
||||
bool Cmdline_graphics_debug_output = false;
|
||||
bool Cmdline_log_to_stdout = false;
|
||||
bool Cmdline_slow_frames_ok = false;
|
||||
bool Cmdline_lua_devmode = false;
|
||||
bool Cmdline_override_data = false;
|
||||
bool Cmdline_show_imgui_debug = false;
|
||||
|
||||
// Other
|
||||
cmdline_parm get_flags_arg(GET_FLAGS_STRING, "Output the launcher flags file", AT_STRING);
|
||||
@@ -562,6 +582,12 @@ cmdline_parm deprecated_missile_lighting_arg("-missile_lighting", "Deprecated",
|
||||
cmdline_parm deprecated_cache_bitmaps_arg("-cache_bitmaps", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_no_emissive_arg("-no_emissive_light", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_postprocess_arg("-post_process", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_spec_static_arg("-spec_static", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_spec_point_arg("-spec_point", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_spec_tube_arg("-spec_tube", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_ambient_factor_arg("-ambient_factor", "Deprecated", AT_NONE); //
|
||||
cmdline_parm deprecated_ship_choice_3d_arg("-ship_choice_3d", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_weapon_choice_3d_arg("-weapon_choice_3d", "Deprecated", AT_NONE);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
|
||||
@@ -1716,7 +1742,7 @@ bool SetCmdlineParams()
|
||||
|
||||
if(targetinfo_arg.found())
|
||||
{
|
||||
Cmdline_targetinfo = 1;
|
||||
Extra_target_info = true;
|
||||
}
|
||||
|
||||
if(nomovies_arg.found() ) {
|
||||
@@ -1823,7 +1849,7 @@ bool SetCmdlineParams()
|
||||
}
|
||||
|
||||
if ( use_warp_flash.found() ) {
|
||||
Cmdline_warp_flash = 1;
|
||||
Fireball_warp_flash = true;
|
||||
}
|
||||
|
||||
if ( allow_autpilot_interrupt.found() ) {
|
||||
@@ -1841,22 +1867,21 @@ bool SetCmdlineParams()
|
||||
if ( stretch_menu.found() ) {
|
||||
Cmdline_stretch_menu = 1;
|
||||
}
|
||||
// new lighting lines
|
||||
if ( ambient_power_arg.found() )
|
||||
Cmdline_ambient_power = ambient_power_arg.get_float();
|
||||
|
||||
// specular comand lines
|
||||
if ( spec_point_arg.found() ) {
|
||||
static_point_factor = spec_point_arg.get_float();
|
||||
if (emissive_power_arg.found() && emissive_power_arg.has_param()) {
|
||||
Cmdline_emissive_power = emissive_power_arg.get_float();
|
||||
} else if (emissive_arg.found() || emissive_power_arg.found()) {
|
||||
// for legacy support no argument param defaults to the old emissive value
|
||||
Cmdline_emissive_power = 0.30f;
|
||||
}
|
||||
|
||||
if ( spec_static_arg.found() ) {
|
||||
static_light_factor = spec_static_arg.get_float();
|
||||
}
|
||||
if (light_power_arg.found())
|
||||
Cmdline_light_power = light_power_arg.get_float();
|
||||
|
||||
if ( spec_tube_arg.found() ) {
|
||||
static_tube_factor = spec_tube_arg.get_float();
|
||||
}
|
||||
|
||||
if ( spec_arg.found() )
|
||||
{
|
||||
if (spec_arg.found()) {
|
||||
Cmdline_spec = 0;
|
||||
}
|
||||
|
||||
@@ -1911,22 +1936,13 @@ bool SetCmdlineParams()
|
||||
if ( glow_arg.found() )
|
||||
Cmdline_glow = 0;
|
||||
|
||||
if ( ship_choice_3d_arg.found() )
|
||||
Cmdline_ship_choice_3d = 1;
|
||||
|
||||
if ( weapon_choice_3d_arg.found() )
|
||||
Cmdline_weapon_choice_3d = 1;
|
||||
|
||||
if (ingamejoin_arg.found() )
|
||||
Cmdline_ingamejoin = 1;
|
||||
Cmdline_ingamejoin = 0;
|
||||
|
||||
if ( start_mission_arg.found() ) {
|
||||
Cmdline_start_mission = start_mission_arg.str();
|
||||
}
|
||||
|
||||
if ( ambient_factor_arg.found() )
|
||||
Cmdline_ambient_factor = ambient_factor_arg.get_int();
|
||||
|
||||
if ( output_scripting_arg.found() )
|
||||
Output_scripting_meta = true;
|
||||
|
||||
@@ -2009,10 +2025,6 @@ bool SetCmdlineParams()
|
||||
Cmdline_no_fbo = 1;
|
||||
}
|
||||
|
||||
if ( emissive_arg.found() ) {
|
||||
Cmdline_emissive = 1;
|
||||
}
|
||||
|
||||
if ( rearm_timer_arg.found() )
|
||||
Cmdline_rearm_timer = 1;
|
||||
|
||||
@@ -2072,11 +2084,17 @@ bool SetCmdlineParams()
|
||||
|
||||
if( enable_shadows_arg.found() )
|
||||
{
|
||||
// if only using `enable_shadows` then default quality level can be overriden in mod_settings.tbl --wookieejedi
|
||||
Shadow_quality_uses_mod_option = true;
|
||||
|
||||
Shadow_quality = ShadowQuality::Medium;
|
||||
}
|
||||
|
||||
if( shadow_quality_arg.found() )
|
||||
{
|
||||
// set that we are not using default shadow quality level --wookieejedi
|
||||
Shadow_quality_uses_mod_option = false;
|
||||
|
||||
switch (shadow_quality_arg.get_int()) {
|
||||
case 0:
|
||||
Shadow_quality = ShadowQuality::Disabled;
|
||||
@@ -2105,6 +2123,11 @@ bool SetCmdlineParams()
|
||||
Cmdline_no_deferred_lighting = 1;
|
||||
}
|
||||
|
||||
if( deferred_lighting_cockpit_arg.found() )
|
||||
{
|
||||
Cmdline_deferred_lighting_cockpit = true;
|
||||
}
|
||||
|
||||
if (anisotropy_level_arg.found())
|
||||
{
|
||||
Cmdline_aniso_level = anisotropy_level_arg.get_int();
|
||||
@@ -2160,6 +2183,17 @@ bool SetCmdlineParams()
|
||||
if (slow_frames_ok_arg.found()) {
|
||||
Cmdline_slow_frames_ok = true;
|
||||
}
|
||||
if ( luadev_arg.found()) {
|
||||
Cmdline_lua_devmode = true;
|
||||
}
|
||||
|
||||
if ( override_arg.found()) {
|
||||
Cmdline_override_data = true;
|
||||
}
|
||||
|
||||
if (imgui_debug_arg.found()) {
|
||||
Cmdline_show_imgui_debug = true;
|
||||
}
|
||||
|
||||
if (show_video_info.found())
|
||||
{
|
||||
@@ -2230,6 +2264,16 @@ bool SetCmdlineParams()
|
||||
Cmdline_dump_packet_type = true;
|
||||
}
|
||||
|
||||
if (fixed_seed_rand.found()) {
|
||||
Cmdline_rng_seed = abs(fixed_seed_rand.get_int());
|
||||
if (Cmdline_rng_seed>0) {
|
||||
Cmdline_reuse_rng_seed = true;
|
||||
}
|
||||
else {
|
||||
Warning(LOCATION,"-seed must be an integer greater than 0. Invalid input seed will be disregarded.");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,10 +53,9 @@ extern char *Cmdline_center_res;
|
||||
|
||||
// Graphics related
|
||||
extern float Cmdline_clip_dist;
|
||||
extern float static_light_factor;
|
||||
extern float static_point_factor;
|
||||
extern float static_tube_factor;
|
||||
extern int Cmdline_ambient_factor;
|
||||
extern float Cmdline_ambient_power;
|
||||
extern float Cmdline_emissive_power;
|
||||
extern float Cmdline_light_power;
|
||||
extern int Cmdline_env;
|
||||
extern int Cmdline_glow;
|
||||
extern int Cmdline_noscalevid; // disables fit-to-window for movies - taylor
|
||||
@@ -68,6 +67,7 @@ extern int Cmdline_softparticles;
|
||||
extern int Cmdline_bloom_intensity;
|
||||
extern bool Cmdline_force_lightshaft_off;
|
||||
extern int Cmdline_no_deferred_lighting;
|
||||
extern bool Cmdline_deferred_lighting_cockpit;
|
||||
extern int Cmdline_emissive;
|
||||
extern int Cmdline_aniso_level;
|
||||
|
||||
@@ -80,12 +80,10 @@ extern int Cmdline_ballistic_gauge;
|
||||
extern int Cmdline_dualscanlines;
|
||||
extern int Cmdline_orb_radar;
|
||||
extern int Cmdline_rearm_timer;
|
||||
extern int Cmdline_targetinfo;
|
||||
|
||||
// Gameplay related
|
||||
extern int Cmdline_ship_choice_3d;
|
||||
extern int Cmdline_weapon_choice_3d;
|
||||
extern int Cmdline_warp_flash;
|
||||
extern int Cmdline_autopilot_interruptable;
|
||||
extern int Cmdline_stretch_menu;
|
||||
extern int Cmdline_no_screenshake;
|
||||
@@ -155,6 +153,9 @@ extern bool Cmdline_debug_window;
|
||||
extern bool Cmdline_graphics_debug_output;
|
||||
extern bool Cmdline_log_to_stdout;
|
||||
extern bool Cmdline_slow_frames_ok;
|
||||
extern bool Cmdline_lua_devmode;
|
||||
extern bool Cmdline_override_data;
|
||||
extern bool Cmdline_show_imgui_debug;
|
||||
|
||||
enum class WeaponSpewType { NONE = 0, STANDARD, ALL };
|
||||
extern WeaponSpewType Cmdline_spew_weapon_stats;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "network/multi_pmsg.h"
|
||||
#include "network/multiutil.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
#include "playerman/player.h"
|
||||
#include "pilotfile/pilotfile.h"
|
||||
#include "popup/popup.h"
|
||||
@@ -174,7 +175,7 @@ int Control_check_count = 0;
|
||||
|
||||
static int Tab; // which tab we are currently in
|
||||
static int Binding_mode = 0; // are we waiting for a key to bind it?
|
||||
static int Bind_time = 0;
|
||||
static UI_TIMESTAMP Bind_time = UI_TIMESTAMP::invalid();
|
||||
static int Search_mode = 0; // are we waiting for a key to bind it?
|
||||
static int Last_key = -1;
|
||||
static int Selected_line = 0; // line that is currently selected for binding
|
||||
@@ -1173,7 +1174,7 @@ void control_config_do_bind()
|
||||
control_config_detect_axis_reset();
|
||||
|
||||
Binding_mode = 1;
|
||||
Bind_time = timer_get_milliseconds();
|
||||
Bind_time = ui_timestamp();
|
||||
Search_mode = 0;
|
||||
Last_key = -1;
|
||||
Axis_override.clear();
|
||||
@@ -1970,7 +1971,7 @@ void control_config_do_frame(float frametime)
|
||||
}
|
||||
|
||||
// Debounce timer to allow mouse double-click (maybe?)
|
||||
if (!done && (Bind_time + 375 < timer_get_milliseconds())) {
|
||||
if (!done && (ui_timestamp_since(Bind_time) > 375)) {
|
||||
for (i=0; i<NUM_BUTTONS; i++){
|
||||
if ( (CC_Buttons[gr_screen.res][i].button.is_mouse_on()) && (CC_Buttons[gr_screen.res][i].button.enabled()) ){
|
||||
break;
|
||||
@@ -2635,10 +2636,11 @@ int check_control(int id, int key)
|
||||
// If we reach this point, then it means this is a continuous control
|
||||
// which has just been released
|
||||
|
||||
if (Script_system.IsActiveAction(CHA_ONACTIONSTOPPED)) {
|
||||
Script_system.SetHookVar("Action", 's', Control_config[id].text);
|
||||
Script_system.RunCondition(CHA_ONACTIONSTOPPED, nullptr, nullptr, id);
|
||||
Script_system.RemHookVar("Action");
|
||||
if (scripting::hooks::OnActionStopped->isActive()) {
|
||||
scripting::hooks::OnActionStopped->run(scripting::hooks::ControlActionConditions{ id },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Action", 's', Control_config[id].text)
|
||||
));
|
||||
}
|
||||
|
||||
Control_config[id].continuous_ongoing = false;
|
||||
@@ -2794,7 +2796,7 @@ void control_get_axes_readings(int *axis_v, float frame_time)
|
||||
|
||||
switch (item.type) {
|
||||
case CC_TYPE_AXIS_ABS:
|
||||
axis_v[action] = item.used;
|
||||
axis_v[action] = item.analog_value;
|
||||
break;
|
||||
case CC_TYPE_AXIS_REL:
|
||||
axis_v[action] = 0;
|
||||
@@ -2803,12 +2805,13 @@ void control_get_axes_readings(int *axis_v, float frame_time)
|
||||
case CC_TYPE_AXIS_BTN_POS:
|
||||
default:
|
||||
//This should never happen, especially with the above Assertion. This is required as incomplete switches on an enum generate warnings
|
||||
UNREACHABLE("Unhandled control item type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Store values for possible lua override
|
||||
item.used = axis_v[action];
|
||||
item.analog_value = axis_v[action];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2821,24 +2824,29 @@ void control_used(int id)
|
||||
|
||||
// This check needs to be done because the control code might call this function more than once per frame,
|
||||
// and we don't want to run the hooks more than once per frame
|
||||
if (Control_config[id].used < Last_frame_timestamp) {
|
||||
if (!Control_config[id].digital_used.isValid() || timestamp_compare(Control_config[id].digital_used, Last_frame_timestamp) < 0) {
|
||||
if (!Control_config[id].continuous_ongoing) {
|
||||
Script_system.SetHookVar("Action", 's', Control_config[id].text);
|
||||
Script_system.RunCondition(CHA_ONACTION, nullptr, nullptr, id);
|
||||
Script_system.RemHookVar("Action");
|
||||
if (scripting::hooks::OnAction->isActive()) {
|
||||
scripting::hooks::OnAction->run(scripting::hooks::ControlActionConditions{ id },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Action", 's', Control_config[id].text)
|
||||
));
|
||||
}
|
||||
|
||||
if (Control_config[id].type == CC_TYPE_CONTINUOUS)
|
||||
Control_config[id].continuous_ongoing = true;
|
||||
}
|
||||
|
||||
Control_config[id].used = timestamp();
|
||||
Control_config[id].digital_used = Last_frame_timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
void control_config_clear_used_status()
|
||||
{
|
||||
// note: this is only for digital controls like button presses,
|
||||
// so we don't need to clear the analog value
|
||||
for (auto &item : Control_config) {
|
||||
item.used = 0;
|
||||
item.digital_used = TIMESTAMP::invalid();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#define CCF_HAT 0x04 //!< btn is a hat
|
||||
#define CCF_BALL 0x02 //!< btn is a ball
|
||||
#define CCF_BUTTON 0x01 //!< btn is actually a button
|
||||
#define CCF_NONE 0x00 //!< No flags. Alias is "NONE"
|
||||
|
||||
/*!
|
||||
* These are used to index a corresponding axis value from an array.
|
||||
@@ -294,6 +295,8 @@ enum IoActionId : int {
|
||||
JOY_ABS_THROTTLE_AXIS = 127,
|
||||
JOY_REL_THROTTLE_AXIS = 128,
|
||||
|
||||
TOGGLE_HUD_SHADOWS,
|
||||
|
||||
/*!
|
||||
* This must always be below the last defined item
|
||||
*/
|
||||
@@ -565,7 +568,9 @@ public:
|
||||
CC_type type; //!< manner control should be checked in
|
||||
|
||||
// Items used during gameplay
|
||||
int used; //!< has control been used yet in mission? If so, this is the timestamp. For axes, this denotes the last frame's value
|
||||
TIMESTAMP digital_used; //!< has control been used yet in mission? If so, this is the timestamp.
|
||||
// Note this is not a UI timestamp because this is purely for mission timing purposes.
|
||||
int analog_value; // For axes, this denotes the last frame's value
|
||||
bool disabled = true; //!< whether this action should be available at all
|
||||
bool locked = false; //!< whether this action will be triggered by the respectively bound key
|
||||
bool scriptEnabledByDefault = false; //!< whether this binding will execute it's registered hooks if triggered. Resets each mission
|
||||
|
||||
@@ -258,6 +258,7 @@ 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)
|
||||
(HUD_TARGETBOX_TOGGLE_WIREFRAME, KEY_ALTED | KEY_SHIFTED | KEY_Q, -1, COMPUTER_TAB, 1, "Toggle HUD Wireframe Target View", CC_TYPE_TRIGGER)
|
||||
|
||||
// Custom Controls
|
||||
@@ -409,6 +410,7 @@ SCP_unordered_map<SCP_string, IoActionId> old_text = {
|
||||
{"Increase Time Compression", TIME_SPEED_UP},
|
||||
{"Decrease Time Compression", TIME_SLOW_DOWN},
|
||||
{"Toggle High HUD Contrast", TOGGLE_HUD_CONTRAST},
|
||||
{"Toggle HUD Drop Shadows", TOGGLE_HUD_SHADOWS},
|
||||
{"(Multiplayer) Toggle Network Info", MULTI_TOGGLE_NETINFO},
|
||||
{"(Multiplayer) Self Destruct", MULTI_SELF_DESTRUCT},
|
||||
|
||||
@@ -736,7 +738,8 @@ void control_config_common_init()
|
||||
}
|
||||
|
||||
for (int i = 0; i < Action::NUM_VALUES; i++) {
|
||||
Control_config[i + JOY_AXIS_BEGIN].used = JOY_AXIS_CENTER;
|
||||
Control_config[i + JOY_AXIS_BEGIN].analog_value = JOY_AXIS_CENTER;
|
||||
Control_config[i + JOY_AXIS_BEGIN].digital_used = TIMESTAMP::invalid();
|
||||
}
|
||||
|
||||
// TODO It's not memory efficient to keep the presets loaded into memory all the time, but we do need to know which
|
||||
@@ -1122,6 +1125,7 @@ void LoadEnumsIntoActionMap() {
|
||||
ADD_ENUM_TO_ACTION_MAP(TIME_SLOW_DOWN)
|
||||
|
||||
ADD_ENUM_TO_ACTION_MAP(TOGGLE_HUD_CONTRAST)
|
||||
ADD_ENUM_TO_ACTION_MAP(TOGGLE_HUD_SHADOWS)
|
||||
|
||||
ADD_ENUM_TO_ACTION_MAP(MULTI_TOGGLE_NETINFO)
|
||||
|
||||
@@ -1396,7 +1400,8 @@ void control_enable_hook(IoActionId id, bool enable) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Stuffs the CCF flags into the given char. Needs item_id for validation
|
||||
* Stuffs the CCF flags into the given char. Needs item_id for validation.
|
||||
* @details Unknown, unrecognized, or excessive flags are silently ignored on Release builds. Debug builds complain.
|
||||
*/
|
||||
void stuff_CCF(char& flags, size_t item_id) {
|
||||
Assert(item_id < Control_config.size());
|
||||
@@ -1410,7 +1415,9 @@ void stuff_CCF(char& flags, size_t item_id) {
|
||||
SCP_string flag_str;
|
||||
size_t pos = 0;
|
||||
size_t len = 0;
|
||||
|
||||
|
||||
// Lambda to add flags.
|
||||
// Debug version Eats the substring as it is found.
|
||||
auto ADD_FLAG = [&](char id) {
|
||||
flag_str = ValToCCF(id);
|
||||
pos = szTempBuffer.find(flag_str);
|
||||
@@ -1421,6 +1428,8 @@ void stuff_CCF(char& flags, size_t item_id) {
|
||||
}
|
||||
};
|
||||
#else
|
||||
// Lambda to add flags.
|
||||
// Release version doesn't modify szTempBuffer as it searches for substrings.
|
||||
auto ADD_FLAG = [&](char id) {
|
||||
if (szTempBuffer.find(ValToCCF(id)) != SCP_string::npos)
|
||||
flags |= id;
|
||||
@@ -1434,13 +1443,38 @@ void stuff_CCF(char& flags, size_t item_id) {
|
||||
ADD_FLAG(CCF_HAT);
|
||||
ADD_FLAG(CCF_BALL);
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Eat the "CCF_NONE" and "NONE" substrings
|
||||
auto EAT_FLAG = [&](SCP_string str) {
|
||||
pos = szTempBuffer.find(str);
|
||||
len = str.length();
|
||||
if (pos != SCP_string::npos) {
|
||||
if (flags != 0) {
|
||||
// Complain about bad habits
|
||||
error_display(0,
|
||||
"Flag 'NONE' passed to config item %i along with other flags, ignoring: \n'%s'",
|
||||
static_cast<int>(item_id),
|
||||
szTempBuffer.c_str()
|
||||
);
|
||||
}
|
||||
szTempBuffer.erase(pos, len);
|
||||
}
|
||||
};
|
||||
|
||||
EAT_FLAG("CCF_NONE");
|
||||
EAT_FLAG("NONE");
|
||||
|
||||
// Complain about any unknown flag strings
|
||||
replace_all(szTempBuffer, ",", " ");
|
||||
drop_white_space(szTempBuffer);
|
||||
|
||||
if (!szTempBuffer.empty()) {
|
||||
error_display(0, "Unknown flags passed to config item %i, ignoring: \n'%s'", static_cast<int>(item_id), szTempBuffer.c_str());
|
||||
error_display(0,
|
||||
"Unknown (or excessive) flags passed to config item %i, ignoring: \n'%s'",
|
||||
static_cast<int>(item_id),
|
||||
szTempBuffer.c_str()
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2272,7 +2306,7 @@ SCP_string ValToCCF(char id) {
|
||||
}
|
||||
|
||||
if (str.empty()) {
|
||||
// If unsupported flags, or no flags at all, list as "None"
|
||||
// If unsupported flags, or (id == CCF_NONE), list as "None"
|
||||
str = "NONE";
|
||||
}
|
||||
|
||||
@@ -2756,7 +2790,8 @@ CCI& CCI::operator=(const CCI& A) {
|
||||
indexXSTR = A.indexXSTR;
|
||||
text = A.text;
|
||||
type = A.type;
|
||||
used = A.used;
|
||||
analog_value = A.analog_value;
|
||||
digital_used = A.digital_used;
|
||||
disabled = A.disabled;
|
||||
locked = A.locked;
|
||||
scriptEnabledByDefault = A.scriptEnabledByDefault;
|
||||
|
||||
@@ -95,7 +95,7 @@ void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
|
||||
void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2, float alpha) {
|
||||
GR_DEBUG_SCOPE("Draw video frame");
|
||||
|
||||
movie_vertex vertex_data[4];
|
||||
@@ -127,10 +127,26 @@ void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
|
||||
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offsetof(movie_vertex, pos));
|
||||
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offsetof(movie_vertex, uv));
|
||||
|
||||
if (_properties.pixelFormat == FramePixelFormat::YUV420) {
|
||||
switch (_properties.pixelFormat) {
|
||||
case FramePixelFormat::YUV420:
|
||||
material_set_movie(&_movie_material,
|
||||
_planeTextureHandles[0],
|
||||
_planeTextureHandles[1],
|
||||
_planeTextureHandles[2],
|
||||
alpha);
|
||||
gr_render_movie(&_movie_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle, offset);
|
||||
} else {
|
||||
break;
|
||||
case FramePixelFormat::BGR:
|
||||
material_set_unlit(&_rgb_material, _planeTextureHandles[0], alpha, false, false);
|
||||
gr_render_primitives(&_rgb_material, PRIM_TYPE_TRISTRIP, &layout, 0, 4, gr_immediate_buffer_handle, offset);
|
||||
break;
|
||||
case FramePixelFormat::BGRA:
|
||||
material_set_unlit(&_rgb_material, _planeTextureHandles[0], alpha, true, false);
|
||||
gr_render_primitives(&_rgb_material, PRIM_TYPE_TRISTRIP, &layout, 0, 4, gr_immediate_buffer_handle, offset);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled enum value!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class VideoPresenter {
|
||||
|
||||
void uploadVideoFrame(const VideoFramePtr& frame);
|
||||
|
||||
void displayFrame(float x1, float y1, float x2, float y2);
|
||||
void displayFrame(float x1, float y1, float x2, float y2, float alpha = 1.0f);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+100
-23
@@ -48,38 +48,101 @@ void cutscene_close()
|
||||
}
|
||||
}
|
||||
|
||||
// initialization stuff for cutscenes
|
||||
void cutscene_init()
|
||||
static cutscene_info *get_cutscene_pointer(char *cutscene_filename)
|
||||
{
|
||||
atexit(cutscene_close);
|
||||
for (int i = 0; i < (int)Cutscenes.size(); i++) {
|
||||
if (!stricmp(cutscene_filename, Cutscenes[i].filename)) {
|
||||
return &Cutscenes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find anything.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cutscene_info_init(cutscene_info *csni)
|
||||
{
|
||||
csni->filename[0] = '\0';
|
||||
csni->name[0] = '\0';
|
||||
csni->description = NULL;
|
||||
csni->flags = {};
|
||||
}
|
||||
|
||||
// initialization stuff for cutscenes
|
||||
void parse_cutscene_table(const char* filename)
|
||||
{
|
||||
|
||||
char buf[MULTITEXT_LENGTH];
|
||||
cutscene_info cutinfo;
|
||||
cutscene_info csnt;
|
||||
cutscene_info_init(&csnt);
|
||||
|
||||
cutscene_info *csnp;
|
||||
bool create_if_not_found = true;
|
||||
|
||||
try
|
||||
{
|
||||
read_file_text("cutscenes.tbl", CF_TYPE_TABLES);
|
||||
|
||||
read_file_text(filename, CF_TYPE_TABLES);
|
||||
|
||||
reset_parse();
|
||||
|
||||
// parse in all the cutscenes
|
||||
Cutscenes.clear();
|
||||
skip_to_string("#Cutscenes");
|
||||
ignore_white_space();
|
||||
|
||||
bool isFirstCutscene = true;
|
||||
|
||||
while (required_string_either("#End", "$Filename:"))
|
||||
{
|
||||
bool csn_new = false;
|
||||
|
||||
required_string("$Filename:");
|
||||
stuff_string(cutinfo.filename, F_PATHNAME, MAX_FILENAME_LEN);
|
||||
stuff_string(csnt.filename, F_PATHNAME, MAX_FILENAME_LEN);
|
||||
|
||||
required_string("$Name:");
|
||||
stuff_string(cutinfo.name, F_NAME, NAME_LENGTH);
|
||||
if (optional_string("+nocreate")) {
|
||||
if (!Parsing_modular_table) {
|
||||
Warning(LOCATION, "+nocreate flag used for cutscene in non-modular table\n");
|
||||
}
|
||||
create_if_not_found = false;
|
||||
}
|
||||
|
||||
required_string("$Description:");
|
||||
stuff_string(buf, F_MULTITEXT, sizeof(buf));
|
||||
drop_white_space(buf);
|
||||
compact_multitext_string(buf);
|
||||
cutinfo.description = vm_strdup(buf);
|
||||
// Does this cutscene exist already?
|
||||
// If so, load this new info into it
|
||||
csnp = get_cutscene_pointer(csnt.filename);
|
||||
if (csnp != NULL) {
|
||||
if (!Parsing_modular_table) {
|
||||
error_display(1,
|
||||
"Error: Cutscene %s already exists. All cutscene names must be unique.",
|
||||
csnt.filename);
|
||||
}
|
||||
} else {
|
||||
// Don't create cutscene if it has +nocreate and is in a modular table.
|
||||
if (!create_if_not_found && Parsing_modular_table) {
|
||||
if (!skip_to_start_of_string_either("$Filename:", "#End")) {
|
||||
error_display(1, "Missing [#End] or [$Filename] after cutscene %s", csnt.filename);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Cutscenes.push_back(csnt);
|
||||
csn_new = true;
|
||||
csnp = &Cutscenes[Cutscenes.size() -1];
|
||||
}
|
||||
|
||||
//If $Name is not found use the $Filename instead because this field needs data
|
||||
//but only do this if if we're parsing the tbl and not a tbm
|
||||
if (optional_string("$Name:")) {
|
||||
stuff_string(csnp->name, F_NAME, NAME_LENGTH);
|
||||
mprintf(("Adding cutscene %s\n", csnp->name));
|
||||
} else if (strlen(csnp->name) == 0) {
|
||||
strcpy_s(csnp->name, csnt.filename);
|
||||
mprintf(("Missing $Name: in cutscene.tbl. Using filename %s instead.\n", csnt.filename));
|
||||
}
|
||||
|
||||
//If $Description is not found we can leave it blank
|
||||
if (optional_string("$Description:")) {
|
||||
stuff_string(buf, F_MULTITEXT, sizeof(buf));
|
||||
drop_white_space(buf);
|
||||
compact_multitext_string(buf);
|
||||
csnp->description = vm_strdup(buf);
|
||||
}
|
||||
|
||||
if (optional_string("$cd:"))
|
||||
{
|
||||
@@ -88,13 +151,14 @@ void cutscene_init()
|
||||
stuff_int(&junk);
|
||||
}
|
||||
|
||||
cutinfo.flags.reset();
|
||||
if (csn_new) {
|
||||
csnp->flags.reset();
|
||||
}
|
||||
|
||||
if (isFirstCutscene)
|
||||
if (Cutscenes.empty())
|
||||
{
|
||||
isFirstCutscene = false;
|
||||
// The original code assumes the first movie is the intro, so make it viewable
|
||||
cutinfo.flags.set(Cutscene::Cutscene_Flags::Viewable);
|
||||
csnp->flags.set(Cutscene::Cutscene_Flags::Viewable);
|
||||
}
|
||||
|
||||
if (optional_string("$Always Viewable:"))
|
||||
@@ -102,17 +166,16 @@ void cutscene_init()
|
||||
bool flag;
|
||||
stuff_boolean(&flag);
|
||||
if (flag)
|
||||
cutinfo.flags.set(Cutscene::Cutscene_Flags::Always_viewable);
|
||||
csnp->flags.set(Cutscene::Cutscene_Flags::Always_viewable);
|
||||
}
|
||||
if (optional_string("$Never Viewable:"))
|
||||
{
|
||||
bool flag;
|
||||
stuff_boolean(&flag);
|
||||
if (flag)
|
||||
cutinfo.flags.set(Cutscene::Cutscene_Flags::Never_viewable);
|
||||
csnp->flags.set(Cutscene::Cutscene_Flags::Never_viewable);
|
||||
}
|
||||
|
||||
Cutscenes.push_back(cutinfo);
|
||||
}
|
||||
|
||||
required_string("#End");
|
||||
@@ -124,6 +187,20 @@ void cutscene_init()
|
||||
}
|
||||
}
|
||||
|
||||
void cutscene_init()
|
||||
{
|
||||
|
||||
atexit(cutscene_close);
|
||||
|
||||
Cutscenes.clear();
|
||||
|
||||
// first parse the default table
|
||||
parse_cutscene_table("cutscenes.tbl");
|
||||
|
||||
// parse any modular tables
|
||||
parse_modular_table("*-csn.tbm", parse_cutscene_table);
|
||||
}
|
||||
|
||||
// marks a cutscene as viewable
|
||||
void cutscene_mark_viewable(const char* filename)
|
||||
{
|
||||
|
||||
@@ -355,7 +355,8 @@ void Player::stopPlayback() {
|
||||
audioPlaybackClose(&m_state);
|
||||
videoPlaybackClose(&m_state);
|
||||
|
||||
m_decoderThread->join();
|
||||
if(m_decoderThread->joinable())
|
||||
m_decoderThread->join();
|
||||
}
|
||||
|
||||
void Player::decoderThread() {
|
||||
@@ -385,13 +386,13 @@ const PlayerState& Player::getInternalState() const {
|
||||
const MovieProperties& Player::getMovieProperties() const {
|
||||
return m_state.props;
|
||||
}
|
||||
void Player::draw(float x1, float y1, float x2, float y2) {
|
||||
void Player::draw(float x1, float y1, float x2, float y2, float alpha) {
|
||||
if (!m_state.currentFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state.videoPresenter) {
|
||||
m_state.videoPresenter->displayFrame(x1, y1, x2, y2);
|
||||
m_state.videoPresenter->displayFrame(x1, y1, x2, y2, alpha);
|
||||
}
|
||||
}
|
||||
SCP_string Player::getCurrentSubtitle() {
|
||||
|
||||
@@ -110,7 +110,7 @@ class Player {
|
||||
* @param x2 The X coordinate of the bottom right corner
|
||||
* @param y2 The Y coordinate of the bottom right corner
|
||||
*/
|
||||
void draw(float x1, float y1, float x2, float y2);
|
||||
void draw(float x1, float y1, float x2, float y2, float alpha = 1.0f);
|
||||
|
||||
/**
|
||||
* @brief Gets the subtitle text that should be displayed now
|
||||
|
||||
+226
-136
@@ -25,8 +25,10 @@
|
||||
#include "radar/radar.h"
|
||||
#include "radar/radarsetup.h"
|
||||
#include "render/3d.h"
|
||||
#include "scripting/global_hooks.h"
|
||||
#include "scripting/hook_api.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "scripting/api/objs/vecmath.h"
|
||||
#include "ship/ship.h"
|
||||
#include "ship/shipfx.h"
|
||||
#include "species_defs/species_defs.h"
|
||||
@@ -34,8 +36,8 @@
|
||||
#include "utils/Random.h"
|
||||
#include "weapon/weapon.h"
|
||||
|
||||
#define MIN_RADIUS_FOR_PERSISTANT_DEBRIS 50 // ship radius at which debris from it becomes persistant
|
||||
#define DEBRIS_SOUND_DELAY 2000 // time to start debris sound after created
|
||||
constexpr int MIN_RADIUS_FOR_PERSISTENT_DEBRIS = 50; // ship radius at which debris from it becomes persistant
|
||||
constexpr int DEBRIS_SOUND_DELAY = 2000; // time to start debris sound after created
|
||||
|
||||
int Num_hull_pieces; // number of hull pieces in existence
|
||||
// we now maintain a kind of "virtual" Hull_debris_list,
|
||||
@@ -54,18 +56,11 @@ int Debris_num_submodels = 0;
|
||||
|
||||
#define DEBRIS_INDEX(dp) (int)(dp-Debris.data())
|
||||
|
||||
const auto OnDebrisCreatedHook = scripting::Hook::Factory(
|
||||
"On Debris Created",
|
||||
"Invoked when a piece of debris is created.",
|
||||
{
|
||||
{"Debris", "debris", "The newly created debris object"},
|
||||
{"Source", "object", "The object (probably a ship) from which this debris piece was spawned."},
|
||||
});
|
||||
|
||||
/**
|
||||
* Start the sequence of a piece of debris writhing in unholy agony!!!
|
||||
*/
|
||||
static void debris_start_death_roll(object *debris_obj, debris *debris_p)
|
||||
static void debris_start_death_roll(object *debris_obj, debris *debris_p, vec3d *hitpos = nullptr)
|
||||
{
|
||||
if (debris_p->is_hull) {
|
||||
// tell everyone else to blow up the piece of debris
|
||||
@@ -87,6 +82,15 @@ static void debris_start_death_roll(object *debris_obj, debris *debris_p)
|
||||
}
|
||||
}
|
||||
|
||||
if (scripting::hooks::OnDebrisDeath->isActive()) {
|
||||
scripting::hooks::OnDebrisDeath->run(scripting::hook_param_list(
|
||||
scripting::hook_param("Debris", 'o', debris_obj),
|
||||
scripting::hook_param("Hitpos",
|
||||
'o',
|
||||
scripting::api::l_Vector.Set(hitpos ? *hitpos : vmd_zero_vector),
|
||||
hitpos != nullptr)));
|
||||
}
|
||||
|
||||
debris_obj->flags.set(Object::Object_Flags::Should_be_dead);
|
||||
}
|
||||
|
||||
@@ -185,7 +189,9 @@ void debris_delete( object * obj )
|
||||
|
||||
db = &Debris[num];
|
||||
|
||||
model_delete_instance(db->model_instance_num);
|
||||
if (db->model_instance_num >= 0) {
|
||||
model_delete_instance(db->model_instance_num);
|
||||
}
|
||||
|
||||
if ( db->is_hull ) {
|
||||
debris_remove_from_hull_list(db);
|
||||
@@ -218,7 +224,7 @@ void debris_process_post(object * obj, float frame_time)
|
||||
|
||||
if ( timestamp_elapsed(db->sound_delay) ) {
|
||||
obj_snd_assign(objnum, db->ambient_sound, &vmd_zero_vector);
|
||||
db->sound_delay = 0;
|
||||
db->sound_delay = TIMESTAMP::invalid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +244,7 @@ void debris_process_post(object * obj, float frame_time)
|
||||
|
||||
if ( !timestamp_elapsed(db->fire_timeout) && timestamp_elapsed(db->next_fireball)) {
|
||||
|
||||
db->next_fireball = timestamp_rand(db->arc_frequency,db->arc_frequency*2 );
|
||||
db->next_fireball = _timestamp_rand(db->arc_frequency,db->arc_frequency*2 );
|
||||
db->arc_frequency += 100;
|
||||
|
||||
if (db->is_hull) {
|
||||
@@ -256,9 +262,9 @@ void debris_process_post(object * obj, float frame_time)
|
||||
|
||||
// Create the spark effects
|
||||
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) {
|
||||
if ( !timestamp_valid( db->arc_timestamp[i] ) ) {
|
||||
if ( !db->arc_timestamp[i].isValid() ) {
|
||||
|
||||
db->arc_timestamp[i] = timestamp(lifetime); // live up to a second
|
||||
db->arc_timestamp[i] = _timestamp(lifetime); // live up to a second
|
||||
|
||||
switch( n ) {
|
||||
case 0:
|
||||
@@ -313,10 +319,10 @@ void debris_process_post(object * obj, float frame_time)
|
||||
}
|
||||
|
||||
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) {
|
||||
if ( timestamp_valid( db->arc_timestamp[i] ) ) {
|
||||
if ( db->arc_timestamp[i].isValid() ) {
|
||||
if ( timestamp_elapsed( db->arc_timestamp[i] ) ) {
|
||||
// Kill off the spark
|
||||
db->arc_timestamp[i] = timestamp(-1);
|
||||
db->arc_timestamp[i] = TIMESTAMP::invalid();
|
||||
} else {
|
||||
// Maybe move a vertex.... 20% of the time maybe?
|
||||
int mr = Random::next();
|
||||
@@ -368,30 +374,44 @@ MONITOR(NumHullDebris)
|
||||
* @param source_obj Source object
|
||||
* @param model_num Model number
|
||||
* @param submodel_num Sub-model number
|
||||
* @param pos Position in vector space
|
||||
* @param exp_center Explosion center in vector space
|
||||
* @param hull_flag Hull flag settings
|
||||
* @param pos Position in global coordinates
|
||||
* @param exp_center Explosion center in global coordinates
|
||||
* @param hull_flag Whether this debris is a chunk of a ship's hull (as opposed to shrapnel)
|
||||
* @param exp_force Explosion force, used to assign velocity to pieces. 1.0f assigns velocity like before. 2.0f assigns twice as much to non-inherited part of velocity
|
||||
*/
|
||||
object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, int hull_flag, float exp_force)
|
||||
object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force)
|
||||
{
|
||||
int objnum, parent_objnum;
|
||||
object *obj;
|
||||
ship *shipp;
|
||||
debris *db;
|
||||
polymodel *pm;
|
||||
int vaporize;
|
||||
physics_info *pi = NULL;
|
||||
ship_info *sip = NULL;
|
||||
int parent_objnum;
|
||||
object *obj;
|
||||
ship *shipp;
|
||||
bool vaporize;
|
||||
|
||||
parent_objnum = OBJ_INDEX(source_obj);
|
||||
|
||||
Assert( (source_obj->type == OBJ_SHIP ) || (source_obj->type == OBJ_GHOST));
|
||||
Assert( source_obj->instance >= 0 && source_obj->instance < MAX_SHIPS );
|
||||
shipp = &Ships[source_obj->instance];
|
||||
sip = &Ship_info[shipp->ship_info_index];
|
||||
|
||||
vaporize = (shipp->flags[Ship::Ship_Flags::Vaporize]);
|
||||
|
||||
obj = debris_create_only(parent_objnum, shipp->ship_info_index, shipp->alt_type_index, shipp->team, -1.0f, -1, model_num, submodel_num, pos, nullptr, hull_flag, vaporize, shipp->debris_damage_type_idx);
|
||||
if (obj != nullptr)
|
||||
{
|
||||
debris_create_set_velocity(&Debris[obj->instance], shipp, exp_center, exp_force);
|
||||
debris_create_fire_hook(obj, source_obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_type_index, int team, float hull_strength, int spark_timeout, int model_num, int submodel_num, vec3d *pos, matrix *orient, bool hull_flag, bool vaporize, int damage_type_idx)
|
||||
{
|
||||
int objnum;
|
||||
object *obj;
|
||||
debris *db;
|
||||
ship_info *sip;
|
||||
matrix orient_buf;
|
||||
|
||||
// try to maintain our soft limit
|
||||
if (hull_flag && (Num_hull_pieces >= SOFT_LIMIT_DEBRIS_PIECES)) {
|
||||
// cause oldest hull debris chunk to blow up
|
||||
@@ -414,10 +434,73 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
|
||||
db = &Debris[n];
|
||||
|
||||
|
||||
// validate or deduce some parameters
|
||||
|
||||
if ( pos == nullptr ) {
|
||||
if (parent_objnum >= 0) {
|
||||
pos = &Objects[parent_objnum].pos;
|
||||
} else {
|
||||
pos = &vmd_zero_vector;
|
||||
}
|
||||
}
|
||||
|
||||
if ( orient == nullptr ) {
|
||||
if (parent_objnum >= 0 && hull_flag) {
|
||||
orient = &Objects[parent_objnum].orient;
|
||||
} else {
|
||||
// non-hull debris has no relation to its parent orientation
|
||||
vec3d rand;
|
||||
vm_vec_rand_vec(&rand);
|
||||
vm_vector_2_matrix(&orient_buf, &rand);
|
||||
orient = &orient_buf;
|
||||
}
|
||||
}
|
||||
|
||||
sip = (parent_ship_class < 0) ? nullptr : &Ship_info[parent_ship_class];
|
||||
if (hull_flag && !sip)
|
||||
{
|
||||
Warning(LOCATION, "Cannot create hull debris without a ship class!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (hull_strength < 0.0f)
|
||||
{
|
||||
if (parent_objnum >= 0 && Objects[parent_objnum].type == OBJ_SHIP)
|
||||
hull_strength = Ships[Objects[parent_objnum].instance].ship_max_hull_strength / 8.0f;
|
||||
else
|
||||
hull_strength = 10.0f;
|
||||
}
|
||||
|
||||
if (hull_flag && (model_num < 0 || submodel_num < 0))
|
||||
{
|
||||
Warning(LOCATION, "Model and submodel numbers must be specified for hull debris!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (team < 0 && hull_flag)
|
||||
{
|
||||
if (parent_objnum >= 0 && Objects[parent_objnum].type == OBJ_SHIP)
|
||||
team = Ships[Objects[parent_objnum].instance].team;
|
||||
else if (Player_ship)
|
||||
team = Player_ship->team;
|
||||
else
|
||||
team = 0;
|
||||
}
|
||||
|
||||
if (damage_type_idx < 0)
|
||||
{
|
||||
if (parent_objnum >= 0 && Objects[parent_objnum].type == OBJ_SHIP)
|
||||
damage_type_idx = Ships[Objects[parent_objnum].instance].debris_damage_type_idx;
|
||||
}
|
||||
|
||||
// done validation
|
||||
|
||||
|
||||
if (!hull_flag) {
|
||||
if (model_num >= 0) {
|
||||
db->model_num = model_num;
|
||||
db->submodel_num = Random::next(sip->generic_debris_num_submodels);
|
||||
db->submodel_num = (sip == nullptr || sip->generic_debris_num_submodels <= 0) ? 0 : Random::next(sip->generic_debris_num_submodels);
|
||||
}
|
||||
else if (vaporize) {
|
||||
db->model_num = Debris_vaporize_model;
|
||||
@@ -447,25 +530,18 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
}
|
||||
}
|
||||
|
||||
if(hull_flag && sip->debris_min_lifetime >= 0.0f && sip->debris_max_lifetime >= 0.0f)
|
||||
{
|
||||
db->lifeleft = (( sip->debris_max_lifetime - sip->debris_min_lifetime ) * frand()) + sip->debris_min_lifetime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create Debris piece n!
|
||||
if ( hull_flag ) {
|
||||
if (Random::next() < (Random::MAX_VALUE/6)) // Make some pieces blow up shortly after explosion.
|
||||
db->lifeleft = 2.0f * (frand()) + 0.5f;
|
||||
else {
|
||||
db->flags.set(Debris_Flags::DoNotExpire);
|
||||
db->lifeleft = -1.0f; // large hull pieces stay around forever
|
||||
}
|
||||
} else {
|
||||
// small non-hull pieces should stick around longer the larger they are
|
||||
// sqrtf should make sure its never too crazy long
|
||||
db->lifeleft = (frand() * 2.0f + 0.1f) * sqrtf(radius);
|
||||
// Create Debris piece n!
|
||||
if ( hull_flag ) {
|
||||
if (Random::next() < (Random::MAX_VALUE/6)) // Make some pieces blow up shortly after explosion.
|
||||
db->lifeleft = 2.0f * (frand()) + 0.5f;
|
||||
else {
|
||||
db->flags.set(Debris_Flags::DoNotExpire);
|
||||
db->lifeleft = -1.0f; // large hull pieces stay around forever
|
||||
}
|
||||
} else {
|
||||
// small non-hull pieces should stick around longer the larger they are
|
||||
// sqrtf should make sure its never too crazy long
|
||||
db->lifeleft = (frand() * 2.0f + 0.1f) * sqrtf(radius);
|
||||
}
|
||||
|
||||
//WMC - Oh noes, we may need to change lifeleft
|
||||
@@ -494,18 +570,18 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
db->flags.set(Debris_Flags::Used);
|
||||
db->is_hull = hull_flag;
|
||||
db->source_objnum = parent_objnum;
|
||||
db->damage_type_idx = shipp->debris_damage_type_idx;
|
||||
db->ship_info_index = shipp->ship_info_index;
|
||||
db->team = shipp->team;
|
||||
db->ambient_sound = sip->debris_ambient_sound;
|
||||
db->fire_timeout = 0; // if not changed, timestamp_elapsed() will return false
|
||||
db->damage_type_idx = damage_type_idx;
|
||||
db->ship_info_index = parent_ship_class;
|
||||
db->team = team;
|
||||
db->ambient_sound = (sip == nullptr) ? gamesnd_id(-1) : sip->debris_ambient_sound;
|
||||
db->fire_timeout = TIMESTAMP::never(); // if not changed, timestamp_elapsed() will return false
|
||||
db->time_started = Missiontime;
|
||||
db->species = Ship_info[shipp->ship_info_index].species;
|
||||
db->parent_alt_name = shipp->alt_type_index;
|
||||
db->species = (sip == nullptr) ? -1 : sip->species;
|
||||
db->parent_alt_name = alt_type_index;
|
||||
db->damage_mult = 1.0f;
|
||||
|
||||
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) { // NOLINT
|
||||
db->arc_timestamp[i] = timestamp(-1);
|
||||
db->arc_timestamp[i] = TIMESTAMP::invalid();
|
||||
}
|
||||
|
||||
if ( db->is_hull ) {
|
||||
@@ -519,36 +595,23 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
db->arc_frequency = 0;
|
||||
}
|
||||
|
||||
db->next_fireball = timestamp_rand(500,2000); //start one 1/2 - 2 secs later
|
||||
db->next_fireball = _timestamp_rand(500,2000); //start one 1/2 - 2 secs later
|
||||
|
||||
if ( pos == nullptr )
|
||||
pos = &source_obj->pos;
|
||||
flagset<Object::Object_Flags> default_flags;
|
||||
default_flags.set(Object::Object_Flags::Renders);
|
||||
default_flags.set(Object::Object_Flags::Physics);
|
||||
default_flags.set(Object::Object_Flags::Collides, hull_flag != 0);
|
||||
|
||||
flagset<Object::Object_Flags> default_flags;
|
||||
default_flags.set(Object::Object_Flags::Renders);
|
||||
default_flags.set(Object::Object_Flags::Physics);
|
||||
default_flags.set(Object::Object_Flags::Collides, hull_flag != 0);
|
||||
|
||||
matrix orient = source_obj->orient;
|
||||
if (!db->is_hull) {
|
||||
// non-hull debris has no relation to its parent orientation
|
||||
vec3d rand;
|
||||
vm_vec_rand_vec(&rand);
|
||||
vm_vector_2_matrix(&orient, &rand);
|
||||
}
|
||||
|
||||
objnum = obj_create(OBJ_DEBRIS, parent_objnum, n, &orient, pos, radius, default_flags, false);
|
||||
objnum = obj_create(OBJ_DEBRIS, parent_objnum, n, orient, pos, radius, default_flags, false);
|
||||
if ( objnum == -1 ) {
|
||||
mprintf(("Couldn't create debris object -- out of object slots\n"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
db->objnum = objnum;
|
||||
|
||||
obj = &Objects[objnum];
|
||||
pi = &obj->phys_info;
|
||||
|
||||
db->model_instance_num = model_create_instance(objnum, db->model_num);
|
||||
db->model_instance_num = hull_flag ? model_create_instance(objnum, db->model_num) : -1;
|
||||
|
||||
// assign the network signature. The signature will be 0 for non-hull pieces, but since that
|
||||
// is our invalid signature, it should be okay.
|
||||
@@ -558,10 +621,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
obj->net_signature = multi_get_next_network_signature( MULTI_SIG_DEBRIS );
|
||||
}
|
||||
|
||||
if (source_obj->type == OBJ_SHIP) {
|
||||
obj->hull_strength = Ships[source_obj->instance].ship_max_hull_strength/8.0f;
|
||||
} else
|
||||
obj->hull_strength = 10.0f;
|
||||
obj->hull_strength = hull_strength;
|
||||
|
||||
if (hull_flag) {
|
||||
if(sip->debris_min_hitpoints >= 0.0f && sip->debris_max_hitpoints >= 0.0f)
|
||||
@@ -579,40 +639,58 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
obj->hull_strength = sip->debris_max_hitpoints;
|
||||
}
|
||||
db->damage_mult = sip->debris_damage_mult;
|
||||
|
||||
db->sound_delay = _timestamp(DEBRIS_SOUND_DELAY);
|
||||
|
||||
// limit the amount of time that fireballs appear
|
||||
// let fireball length be linked to radius of ship. Range is .33 radius => 3.33 radius seconds.
|
||||
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));
|
||||
db->fire_timeout = _timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
|
||||
} else {
|
||||
db->fire_timeout = TIMESTAMP::immediate();
|
||||
}
|
||||
|
||||
if (parent_objnum >= 0 && Objects[parent_objnum].radius >= MIN_RADIUS_FOR_PERSISTENT_DEBRIS) {
|
||||
db->flags.set(Debris_Flags::DoNotExpire);
|
||||
} else {
|
||||
debris_add_to_hull_list(db);
|
||||
}
|
||||
}
|
||||
|
||||
if (hull_flag) {
|
||||
MONITOR_INC(NumHullDebris,1);
|
||||
} else {
|
||||
MONITOR_INC(NumSmallDebris,1);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force)
|
||||
{
|
||||
auto obj = &Objects[db->objnum];
|
||||
auto source_obj = (source_shipp == nullptr) ? nullptr : &Objects[source_shipp->objnum];
|
||||
physics_info *pi = &obj->phys_info;
|
||||
vec3d rotvel, radial_vel, to_center;
|
||||
|
||||
if ( exp_center )
|
||||
vm_vec_sub( &to_center,pos, exp_center );
|
||||
vm_vec_sub( &to_center, &obj->pos, exp_center );
|
||||
else
|
||||
vm_vec_zero(&to_center);
|
||||
|
||||
float scale;
|
||||
|
||||
if ( hull_flag ) {
|
||||
float t;
|
||||
if ( db->is_hull ) {
|
||||
scale = exp_force * i2fl(Random::next(10, 29)); // for radial_vel away from location of blast center
|
||||
db->sound_delay = timestamp(DEBRIS_SOUND_DELAY);
|
||||
|
||||
// set up physics mass and I_inv for hull debris pieces
|
||||
pm = model_get(model_num);
|
||||
auto pm = model_get(db->model_num);
|
||||
vec3d *min, *max;
|
||||
min = &pm->submodel[submodel_num].min;
|
||||
max = &pm->submodel[submodel_num].max;
|
||||
min = &pm->submodel[db->submodel_num].min;
|
||||
max = &pm->submodel[db->submodel_num].max;
|
||||
calc_debris_physics_properties( &obj->phys_info, min, max );
|
||||
|
||||
// limit the amount of time that fireballs appear
|
||||
// let fireball length be linked to radius of ship. Range is .33 radius => 3.33 radius seconds.
|
||||
t = 1000*Objects[db->source_objnum].radius/3 + Random::next(fl2i(1000*3*Objects[db->source_objnum].radius));
|
||||
db->fire_timeout = timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
|
||||
|
||||
if ( Objects[db->source_objnum].radius < MIN_RADIUS_FOR_PERSISTANT_DEBRIS ) {
|
||||
debris_add_to_hull_list(db);
|
||||
} else {
|
||||
db->flags.set(Debris_Flags::DoNotExpire);
|
||||
nprintf(("Alan","A forever chunk of debris was created from ship with radius %f\n",Objects[db->source_objnum].radius));
|
||||
}
|
||||
}
|
||||
else {
|
||||
scale = exp_force * i2fl(Random::next(10, 29)); // for radial_vel away from blast center (non-hull)
|
||||
@@ -627,15 +705,21 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
vm_vec_copy_scale(&radial_vel, &to_center, scale );
|
||||
}
|
||||
|
||||
// DA: here we need to vel_from_rot = w x to_center, where w is world is unrotated to world coords and offset is the
|
||||
// displacement fromt the center of the parent object to the center of the debris piece
|
||||
vec3d world_rotvel, vel_from_rotvel;
|
||||
vm_vec_unrotate ( &world_rotvel, &source_obj->phys_info.rotvel, &source_obj->orient );
|
||||
vm_vec_cross ( &vel_from_rotvel, &world_rotvel, &to_center );
|
||||
vm_vec_scale ( &vel_from_rotvel, DEBRIS_ROTVEL_SCALE);
|
||||
if (source_obj)
|
||||
{
|
||||
// DA: here we need to vel_from_rot = w x to_center, where w is world is unrotated to world coords and offset is the
|
||||
// displacement fromt the center of the parent object to the center of the debris piece
|
||||
vec3d world_rotvel, vel_from_rotvel;
|
||||
vm_vec_unrotate ( &world_rotvel, &source_obj->phys_info.rotvel, &source_obj->orient );
|
||||
vm_vec_cross ( &vel_from_rotvel, &world_rotvel, &to_center );
|
||||
vm_vec_scale ( &vel_from_rotvel, DEBRIS_ROTVEL_SCALE);
|
||||
|
||||
vm_vec_add (&obj->phys_info.vel, &radial_vel, &source_obj->phys_info.vel);
|
||||
vm_vec_add2(&obj->phys_info.vel, &vel_from_rotvel);
|
||||
vm_vec_add (&obj->phys_info.vel, &radial_vel, &source_obj->phys_info.vel);
|
||||
vm_vec_add2(&obj->phys_info.vel, &vel_from_rotvel);
|
||||
}
|
||||
|
||||
|
||||
float radius = submodel_get_radius(db->model_num, db->submodel_num);
|
||||
|
||||
// make sure rotational velocity does not get too high
|
||||
if (radius < 1.0) {
|
||||
@@ -647,40 +731,42 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
vm_vec_rand_vec_quick(&rotvel);
|
||||
vm_vec_scale(&rotvel, scale);
|
||||
|
||||
pi->flags |= PF_DEAD_DAMP;
|
||||
pi->rotvel = rotvel;
|
||||
pi->flags |= (PF_DEAD_DAMP | PF_BALLISTIC);
|
||||
check_rotvel_limit( &obj->phys_info );
|
||||
|
||||
// check that debris is not created with too high a velocity
|
||||
if (hull_flag)
|
||||
if (db->is_hull)
|
||||
{
|
||||
shipfx_debris_limit_speed(db, shipp);
|
||||
shipfx_debris_limit_speed(db, source_shipp);
|
||||
}
|
||||
|
||||
// blow out his reverse thrusters. Or drag, same thing.
|
||||
pi->rotdamp = 10000.0f;
|
||||
pi->side_slip_time_const = 10000.0f;
|
||||
pi->flags |= (PF_REDUCED_DAMP | PF_DEAD_DAMP); // set damping equal for all axis and not changable
|
||||
if (source_shipp != nullptr) {
|
||||
pi->gravity_const = Ship_info[source_shipp->ship_info_index].debris_gravity_const;
|
||||
} else {
|
||||
pi->gravity_const = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
vm_vec_zero(&pi->max_vel); // make so he can't turn on his own VOLITION anymore.
|
||||
vm_vec_zero(&pi->max_rotvel); // make so he can't change speed on his own VOLITION anymore.
|
||||
|
||||
// ensure vel is valid
|
||||
Assert( !vm_is_vec_nan(&obj->phys_info.vel) );
|
||||
}
|
||||
|
||||
if (OnDebrisCreatedHook->isActive()) {
|
||||
OnDebrisCreatedHook->run(scripting::hook_param_list(
|
||||
scripting::hook_param("Debris", 'o', obj),
|
||||
scripting::hook_param("Source", 'o', source_obj)));
|
||||
void debris_create_fire_hook(object *obj, object *source_obj)
|
||||
{
|
||||
if (scripting::hooks::OnDebrisCreated->isActive()) {
|
||||
scripting::hooks::ShipSourceConditions conditions;
|
||||
conditions.source_shipp = (source_obj != nullptr && source_obj->type == OBJ_SHIP) ? &Ships[source_obj->instance] : nullptr;
|
||||
scripting::hooks::OnDebrisCreated->run(std::move(conditions),
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Debris", 'o', obj),
|
||||
scripting::hook_param("Source", 'o', source_obj)));
|
||||
}
|
||||
|
||||
if (db->is_hull) {
|
||||
MONITOR_INC(NumHullDebris,1);
|
||||
} else {
|
||||
MONITOR_INC(NumSmallDebris,1);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -730,7 +816,7 @@ void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float
|
||||
debris_obj->hull_strength -= damage;
|
||||
|
||||
if (debris_obj->hull_strength < 0.0f) {
|
||||
debris_start_death_roll(debris_obj, debris_p );
|
||||
debris_start_death_roll(debris_obj, debris_p, hitpos);
|
||||
} else {
|
||||
// otherwise, give all the other players an update on the debris
|
||||
if(MULTIPLAYER_MASTER){
|
||||
@@ -1071,11 +1157,8 @@ void debris_render(object * obj, model_draw_list *scene)
|
||||
|
||||
texture_info *tbase = nullptr;
|
||||
|
||||
auto pmi = model_get_instance(db->model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
auto pm = model_get(db->model_num);
|
||||
model_clear_instance( db->model_num );
|
||||
model_instance_clear_arcs(pm, pmi);
|
||||
|
||||
// Swap in a different texture depending on the species
|
||||
if (db->species >= 0)
|
||||
@@ -1088,11 +1171,18 @@ void debris_render(object * obj, model_draw_list *scene)
|
||||
}
|
||||
}
|
||||
|
||||
// Only render electrical arcs if within 500m of the eye (for a 10m piece)
|
||||
if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f ) {
|
||||
for (i=0; i<MAX_DEBRIS_ARCS; i++ ) {
|
||||
if ( timestamp_valid( db->arc_timestamp[i] ) ) {
|
||||
model_instance_add_arc( pm, pmi, db->submodel_num, &db->arc_pts[i][0], &db->arc_pts[i][1], MARC_TYPE_DAMAGED );
|
||||
polymodel_instance *pmi = nullptr;
|
||||
if (db->model_instance_num >= 0)
|
||||
{
|
||||
pmi = model_get_instance(db->model_instance_num);
|
||||
model_instance_clear_arcs(pm, pmi);
|
||||
|
||||
// Only render electrical arcs if within 500m of the eye (for a 10m piece)
|
||||
if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f ) {
|
||||
for (i=0; i<MAX_DEBRIS_ARCS; i++ ) {
|
||||
if ( db->arc_timestamp[i].isValid() ) {
|
||||
model_instance_add_arc( pm, pmi, db->submodel_num, &db->arc_pts[i][0], &db->arc_pts[i][1], MARC_TYPE_DAMAGED );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-6
@@ -43,15 +43,15 @@ typedef struct debris {
|
||||
int model_num; // What model this uses
|
||||
int model_instance_num; // What model instance this uses - needed for arcs
|
||||
int submodel_num; // What submodel this uses
|
||||
int next_fireball; // When to start a fireball
|
||||
int is_hull; // indicates whether this is a collideable, destructable piece of debris from the model, or just a generic debris fragment
|
||||
TIMESTAMP next_fireball; // When to start a fireball
|
||||
bool is_hull; // indicates whether this is a collideable, destructable piece of debris from the model, or just a generic debris fragment
|
||||
int species; // What species this is from. -1 if don't care.
|
||||
int fire_timeout; // timestamp that holds time for fireballs to stop appearing
|
||||
int sound_delay; // timestamp to signal when sound should start
|
||||
TIMESTAMP fire_timeout; // timestamp that holds time for fireballs to stop appearing
|
||||
TIMESTAMP sound_delay; // timestamp to signal when sound should start
|
||||
fix time_started; // time when debris was created
|
||||
|
||||
vec3d arc_pts[MAX_DEBRIS_ARCS][2]; // The endpoints of each arc
|
||||
int arc_timestamp[MAX_DEBRIS_ARCS]; // When this times out, the spark goes away. -1 is not used
|
||||
TIMESTAMP arc_timestamp[MAX_DEBRIS_ARCS]; // When this times out, the spark goes away. Invalid is not used
|
||||
int arc_frequency; // Starts at 1000, gets bigger
|
||||
|
||||
int parent_alt_name;
|
||||
@@ -69,7 +69,19 @@ void debris_init();
|
||||
void debris_render(object * obj, model_draw_list *scene);
|
||||
void debris_delete( object * obj );
|
||||
void debris_process_post( object * obj, float frame_time);
|
||||
object *debris_create( object * source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, int hull_flag, float exp_force );
|
||||
|
||||
// Create debris, set velocity, and fire scripting hook
|
||||
object *debris_create( object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, bool hull_flag, float exp_force );
|
||||
|
||||
// Create debris but don't do anything else
|
||||
object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_type_index, int team, float hull_strength, int spark_timeout, int model_num, int submodel_num, vec3d *pos, matrix *orient, bool hull_flag, bool vaporize, int damage_type_idx);
|
||||
|
||||
// Set velocity after debris creation
|
||||
void debris_create_set_velocity(debris *db, ship *source_shipp, vec3d *exp_center, float exp_force);
|
||||
|
||||
// Fire scripting hook after debris creation
|
||||
void debris_create_fire_hook(object *obj, object *source_obj);
|
||||
|
||||
int debris_check_collision( object * obj, object * other_obj, vec3d * hitpos, collision_info_struct *debris_hit_info=NULL, vec3d* hitnormal = NULL );
|
||||
void debris_hit( object * debris_obj, object * other_obj, vec3d * hitpos, float damage );
|
||||
int debris_get_team(object *objp);
|
||||
|
||||
+37
-25
@@ -161,6 +161,7 @@ SCP_vector<DecalDefinition> DecalDefinitions;
|
||||
|
||||
// Variable to indicate if the system is able to work correctly on the current system
|
||||
bool Decal_system_active = true;
|
||||
bool Decal_option_active = true;
|
||||
|
||||
void parse_decals_table(const char* filename) {
|
||||
try {
|
||||
@@ -186,7 +187,7 @@ void parse_decals_table(const char* filename) {
|
||||
}
|
||||
|
||||
if (!gr_is_capable(CAPABILITY_DEFERRED_LIGHTING)) {
|
||||
// we need deferred lighting
|
||||
// We need deferred lighting
|
||||
Decal_system_active = false;
|
||||
mprintf(("Note: Decal system has been disabled due to lack of deferred lighting.\n"));
|
||||
}
|
||||
@@ -196,7 +197,7 @@ void parse_decals_table(const char* filename) {
|
||||
mprintf(("Note: Decal system has been disabled due to lack of normal mapping.\n"));
|
||||
}
|
||||
if (!gr_is_capable(CAPABILITY_SEPARATE_BLEND_FUNCTIONS)) {
|
||||
// WWe need separate blending functions for different color buffers
|
||||
// We need separate blending functions for different color buffers
|
||||
Decal_system_active = false;
|
||||
mprintf(("Note: Decal system has been disabled due to lack of separate color buffer blend functions.\n"));
|
||||
}
|
||||
@@ -327,20 +328,18 @@ void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
|
||||
SCP_string name;
|
||||
stuff_string(name, F_NAME);
|
||||
|
||||
auto decalRef = findDecalDefinition(name);
|
||||
// decals are not initialized in FRED, so no decal definitions are known
|
||||
if (!Fred_running) {
|
||||
auto decalRef = findDecalDefinition(name);
|
||||
|
||||
if (decalRef < 0) {
|
||||
error_display(0, "Decal definition '%s' is unknown!", name.c_str());
|
||||
if (decalRef < 0) {
|
||||
error_display(0, "Decal definition '%s' is unknown!", name.c_str());
|
||||
}
|
||||
dest_info.definition_handle = decalRef;
|
||||
}
|
||||
dest_info.definition_handle = decalRef;
|
||||
|
||||
if (required_string_if_new("+Radius:", is_new_entry)) {
|
||||
stuff_float(&dest_info.radius);
|
||||
|
||||
if (dest_info.radius <= 0.0f) {
|
||||
error_display(0, "Invalid radius of %f! Must be a positive number.", dest_info.radius);
|
||||
dest_info.radius = 1.0f;
|
||||
}
|
||||
dest_info.radius = util::parseUniformRange(0.0001f);
|
||||
}
|
||||
|
||||
if (required_string_if_new("+Lifetime:", is_new_entry)) {
|
||||
@@ -351,10 +350,14 @@ void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
|
||||
dest_info.lifetime = util::parseUniformRange(0.0001f);
|
||||
}
|
||||
}
|
||||
|
||||
if (optional_string("+Use Random Rotation:")) {
|
||||
stuff_boolean(&dest_info.random_rotation);
|
||||
}
|
||||
}
|
||||
|
||||
void loadBitmaps(const creation_info& info) {
|
||||
if (!Decal_system_active) {
|
||||
if (!Decal_system_active || !Decal_option_active) {
|
||||
return;
|
||||
}
|
||||
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
|
||||
@@ -371,7 +374,7 @@ void loadBitmaps(const creation_info& info) {
|
||||
}
|
||||
|
||||
void pageInDecal(const creation_info& info) {
|
||||
if (!Decal_system_active) {
|
||||
if (!Decal_system_active || !Decal_option_active) {
|
||||
return;
|
||||
}
|
||||
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
|
||||
@@ -413,9 +416,12 @@ matrix4 getDecalTransform(Decal& decal) {
|
||||
// this will lead to a situation where we would look at the decal texture "from behind" causing the texture to
|
||||
// appear flipped. We fix that here for the graphics transform by inverting the Z scaling.
|
||||
|
||||
// ALSO for some reason the uvec needs to be flipped as well, otherwise the decals render upside-down. Without
|
||||
// being sure of the root cause, this at least makes it appear correct for modders.
|
||||
|
||||
// Apply scaling
|
||||
vm_vec_scale(&worldOrient.vec.rvec, decal.scale.xyz.x);
|
||||
vm_vec_scale(&worldOrient.vec.uvec, decal.scale.xyz.y);
|
||||
vm_vec_scale(&worldOrient.vec.uvec, -decal.scale.xyz.y);
|
||||
vm_vec_scale(&worldOrient.vec.fvec, -decal.scale.xyz.z);
|
||||
|
||||
matrix4 mat4;
|
||||
@@ -425,12 +431,12 @@ matrix4 getDecalTransform(Decal& decal) {
|
||||
}
|
||||
|
||||
void renderAll() {
|
||||
if (!Decal_system_active) {
|
||||
if (!Decal_system_active || !Decal_option_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear out any invalid decals
|
||||
for (auto iter = active_decals.begin(); iter != active_decals.end(); ++iter) {
|
||||
for (auto iter = active_decals.begin(); iter != active_decals.end();) {
|
||||
if (!iter->isValid()) {
|
||||
// if we're sitting on the very last element, popping-back will invalidate the iterator!
|
||||
if (iter + 1 == active_decals.end()) {
|
||||
@@ -442,6 +448,10 @@ void renderAll() {
|
||||
active_decals.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
// next decal, only increment the iterator if we found a valid value so nothing gets skipped
|
||||
// otherwise we may skip a decal which can then get through to the draw_list loop while being invalid
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (active_decals.empty()) {
|
||||
@@ -452,14 +462,15 @@ void renderAll() {
|
||||
|
||||
graphics::decal_draw_list draw_list(active_decals.size());
|
||||
for (auto& decal : active_decals) {
|
||||
|
||||
Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int)DecalDefinitions.size(),
|
||||
"Invalid decal handle detected!");
|
||||
auto& decalDef = DecalDefinitions[decal.definition_handle];
|
||||
|
||||
int diffuse_bm = -1;
|
||||
int glow_bm = -1;
|
||||
int normal_bm = -1;
|
||||
|
||||
Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int) DecalDefinitions.size(),
|
||||
"Invalid decal handle detected!");
|
||||
auto& decalDef = DecalDefinitions[decal.definition_handle];
|
||||
|
||||
auto decal_time = mission_time - decal.creation_time;
|
||||
auto progress = decal_time / decal.lifetime;
|
||||
|
||||
@@ -491,7 +502,7 @@ void renderAll() {
|
||||
}
|
||||
|
||||
void addDecal(creation_info& info, object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
|
||||
if (!Decal_system_active) {
|
||||
if (!Decal_system_active || !Decal_option_active) {
|
||||
return;
|
||||
}
|
||||
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
|
||||
@@ -519,9 +530,10 @@ void addDecal(creation_info& info, object* host, int submodel, const vec3d& loca
|
||||
newDecal.position = local_pos;
|
||||
newDecal.orientation = local_orient;
|
||||
if (info.width < 0.0f || info.height < 0.0f) {
|
||||
newDecal.scale.xyz.x = info.radius;
|
||||
newDecal.scale.xyz.y = info.radius;
|
||||
newDecal.scale.xyz.z = info.radius;
|
||||
float radius = info.radius.next();
|
||||
newDecal.scale.xyz.x = radius;
|
||||
newDecal.scale.xyz.y = radius;
|
||||
newDecal.scale.xyz.z = radius;
|
||||
} else {
|
||||
newDecal.scale.xyz.x = info.width;
|
||||
newDecal.scale.xyz.y = info.height;
|
||||
|
||||
@@ -52,6 +52,7 @@ class DecalDefinition {
|
||||
|
||||
extern SCP_vector<DecalDefinition> DecalDefinitions;
|
||||
extern bool Decal_system_active;
|
||||
extern bool Decal_option_active;
|
||||
|
||||
|
||||
/**
|
||||
@@ -64,10 +65,11 @@ typedef int DecalReference;
|
||||
*/
|
||||
struct creation_info {
|
||||
DecalReference definition_handle = -1;
|
||||
float radius = -1.0f;
|
||||
util::UniformFloatRange radius = ::util::UniformFloatRange(-1.0f);
|
||||
float width = -1.0f;
|
||||
float height = -1.0f;
|
||||
util::UniformFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
|
||||
bool random_rotation = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -118,7 +118,7 @@ void main() {
|
||||
vec3 normal = getPixelNormal(frag_position, gl_FragCoord.xy, alpha, binormal, tangent);
|
||||
|
||||
vec4 diffuse_out = vec4(0.0);
|
||||
vec4 emissive_out = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec4 emissive_out = vec4(0.0);
|
||||
vec3 normal_out = vec3(0.0);
|
||||
|
||||
if (diffuse_index >= 0) {
|
||||
@@ -147,7 +147,7 @@ void main() {
|
||||
}
|
||||
|
||||
if (glow_index >= 0) {
|
||||
// We have a valid diffuse map
|
||||
// We have a valid glow map
|
||||
vec4 color = texture(glowMap, vec3(tex_coord, float(glow_index)));
|
||||
|
||||
color.rgb = srgb_to_linear(color.rgb) * GLOW_MAP_SRGB_MULTIPLIER;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//? #version 150
|
||||
#include "lighting.sdr" //! #include "lighting.sdr"
|
||||
|
||||
#include "lighting.sdr"
|
||||
|
||||
#include "shadows.sdr"
|
||||
#include "shadows.sdr" //! #include "shadows.sdr"
|
||||
|
||||
in vec3 beamVec;
|
||||
in vec3 lightPosition;
|
||||
@@ -32,7 +32,7 @@ layout (std140) uniform lightData {
|
||||
vec3 diffuseLightColor;
|
||||
float coneAngle;
|
||||
|
||||
vec3 specLightColor;
|
||||
vec3 lightDir;
|
||||
float coneInnerAngle;
|
||||
|
||||
vec3 coneDir;
|
||||
@@ -41,49 +41,105 @@ layout (std140) uniform lightData {
|
||||
vec3 scale;
|
||||
float lightRadius;
|
||||
|
||||
vec3 lightDir;
|
||||
int lightType;
|
||||
|
||||
bool enable_shadows;
|
||||
|
||||
float sourceRadius;
|
||||
};
|
||||
|
||||
void GetLightInfo(vec3 position, out vec3 lightDir, out float attenuation)
|
||||
// Nearest point sphere and tube light calculations taken from
|
||||
// "Real Shading in Unreal Engine 4" by Brian Karis, Epic Games
|
||||
// Part of SIGGRAPH 2013 Course: Physically Based Shading in Theory and Practice
|
||||
|
||||
vec3 ExpandLightSize(in vec3 lightDir, in vec3 reflectDir) {
|
||||
// There's an extra max(...,sourceRadius) call here vs the version in the paper.
|
||||
// This prevents the centerToRay calculation from choosing a point behind
|
||||
// the reflection ray's origin (i.e. underneath the surface).
|
||||
// this is necessary for situations where the fragment being shaded lies inside
|
||||
// the sourceRadius of the light.
|
||||
// Instead, we choose a point suffciently far away from the reflection origin (hence max(...,sourceRadius))
|
||||
// so that we have a gradual transition as the shaded fragments along the surface
|
||||
// shift from being inside to outside the light.
|
||||
vec3 centerToRay = max(dot(lightDir, reflectDir),sourceRadius) * reflectDir - lightDir;
|
||||
return lightDir + centerToRay * clamp(sourceRadius/length(centerToRay), 0.0, 1.0);
|
||||
}
|
||||
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDir, out float attenuation, out float area_normalisation)
|
||||
{
|
||||
if (lightType == LT_DIRECTIONAL) {
|
||||
lightDir = normalize(lightPosition);
|
||||
attenuation = 1.0;
|
||||
area_normalisation = 1.0;
|
||||
} else {
|
||||
// Positional light source
|
||||
lightDir = lightPosition - position.xyz;
|
||||
float dist = length(lightDir);
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
if (lightType == LT_POINT) {
|
||||
lightDir = lightPosition - position.xyz;
|
||||
float dist = length(lightDir);
|
||||
|
||||
if(dist > lightRadius && lightType != LT_TUBE) {
|
||||
discard;
|
||||
}
|
||||
|
||||
if (lightType == LT_TUBE) { // Tube light
|
||||
float beamLength = length(beamVec);
|
||||
vec3 beamDir = beamVec / beamLength;
|
||||
//The actual 'lighting element' is shorter than the light volume cylinder
|
||||
//To compensate the light is moved forward along the beam one radius and the length shortened
|
||||
//this allows room for clean falloff of the light past the ends of beams.
|
||||
vec3 adjustedLightPos = lightPosition - (beamDir * lightRadius);
|
||||
beamLength = beamLength - (lightRadius * 2.0);
|
||||
//adjustments having been made, lightdir needs recalculating
|
||||
lightDir = adjustedLightPos - position.xyz;
|
||||
// Get nearest point on line
|
||||
float neardist = clamp(dot(lightDir, beamDir), 0.0, beamLength);
|
||||
// Move back from the endpoint of the beam along the beam by the distance we calculated
|
||||
vec3 nearest = adjustedLightPos - beamDir * neardist;
|
||||
lightDir = nearest - position.xyz;
|
||||
// this chunk is unneccessary if sourceRadius= 0.0, but let's avoid a branch.
|
||||
// given a sphere of radius sourceRadius centered at lightDir,
|
||||
// move lightDir towards the ray defined by reflectDir
|
||||
lightDir = ExpandLightSize(lightDir, reflectDir);
|
||||
dist = length(lightDir);
|
||||
// Energy conservation term
|
||||
float alpha_adjust = clamp(alpha + (sourceRadius/(2*dist)), 0.0, 1.0);
|
||||
area_normalisation = alpha/alpha_adjust;
|
||||
area_normalisation *= area_normalisation;
|
||||
//end chunk
|
||||
|
||||
|
||||
if(dist > lightRadius) {
|
||||
discard;
|
||||
}
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
} else if (lightType == LT_CONE) {
|
||||
}
|
||||
else if (lightType == LT_TUBE) { // Tube light
|
||||
|
||||
vec3 beamDir = normalize(beamVec);
|
||||
//The actual 'lighting element' is shorter than the light volume cylinder
|
||||
//To compensate the light is moved forward along the beam one radius and the length shortened
|
||||
//this allows room for clean falloff of the light past the ends of beams.
|
||||
vec3 adjustedLightPos = lightPosition - (beamDir * lightRadius);
|
||||
vec3 adjustedbeamVec = beamVec - 2.0 * lightRadius * beamDir;
|
||||
float beamLength = length(adjustedbeamVec);
|
||||
//adjustments having been made, sourceDir needs recalculating
|
||||
vec3 sourceDir = adjustedLightPos - position.xyz;
|
||||
|
||||
// Get point on beam nearest to the reflection ray.
|
||||
vec3 a_t = reflectDir;
|
||||
vec3 b_t = beamDir;
|
||||
vec3 b_0 = sourceDir;
|
||||
vec3 c = cross(a_t, b_t);
|
||||
vec3 d = b_0;
|
||||
vec3 r = d - a_t * dot(d, a_t) - c * dot(d,c);
|
||||
float neardist = dot(r, r)/dot(b_t, r);
|
||||
// Move along the beam by the distance we calculated
|
||||
lightDir = sourceDir - beamDir * clamp(neardist, 0.0, beamLength);
|
||||
// Somebody with a symbolic expression simplifier or a wrinklier brain than me
|
||||
// should figure out how to optimise these calcs - qaz
|
||||
|
||||
|
||||
// this chunk is unneccessary if sourceRadius = 0.0, but let's avoid a branch.
|
||||
// Same principle as in LT_POINT, treat chosen location as a spherelight.
|
||||
lightDir = ExpandLightSize(lightDir, reflectDir);
|
||||
float dist = length(lightDir);
|
||||
// Energy conservation term
|
||||
float alpha_adjust = min(alpha + (sourceRadius/(2*dist)), 1.0);
|
||||
area_normalisation = alpha/alpha_adjust;
|
||||
// don't need to square as it's a line rather than a sphere.
|
||||
//end chunk
|
||||
|
||||
if(dist > lightRadius) {
|
||||
discard;
|
||||
}
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
}
|
||||
else if (lightType == LT_CONE) {
|
||||
lightDir = lightPosition - position.xyz;
|
||||
float coneDot = dot(normalize(-lightDir), coneDir);
|
||||
float dist = length(lightDir);
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
area_normalisation = 1.0;
|
||||
|
||||
if(dualCone) {
|
||||
if(abs(coneDot) < coneAngle) {
|
||||
discard;
|
||||
@@ -111,19 +167,22 @@ void main()
|
||||
if(abs(dot(position, position)) < 0.1)
|
||||
discard;
|
||||
|
||||
vec3 color = texture(ColorBuffer, screenPos).rgb;
|
||||
vec3 diffColor = texture(ColorBuffer, screenPos).rgb;
|
||||
vec4 normalData = texture(NormalBuffer, screenPos);
|
||||
vec4 specColor = texture(SpecBuffer, screenPos);
|
||||
// The vector in the normal buffer could be longer than the unit vector since decal rendering only adds to the normal buffer
|
||||
vec3 normal = normalize(normalData.xyz);
|
||||
float gloss = normalData.a;
|
||||
float roughness = clamp(1.0f - gloss, 0.0f, 1.0f);
|
||||
float alpha = roughness * roughness;
|
||||
float fresnel = specColor.a;
|
||||
vec3 eyeDir = normalize(-position);
|
||||
|
||||
vec3 lightDir;
|
||||
float attenuation;
|
||||
|
||||
GetLightInfo(position, lightDir, attenuation);
|
||||
float area_normalisation;
|
||||
vec3 reflectDir = reflect(-eyeDir, normal);
|
||||
GetLightInfo(position, alpha, reflectDir, lightDir, attenuation, area_normalisation);
|
||||
|
||||
if (enable_shadows) {
|
||||
vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0);
|
||||
@@ -139,7 +198,7 @@ void main()
|
||||
|
||||
vec3 halfVec = normalize(lightDir + eyeDir);
|
||||
float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0);
|
||||
vec4 fragmentColor = vec4(color * (diffuseLightColor * NdotL * attenuation), 1.0);
|
||||
fragmentColor.rgb += computeLighting(specColor.rgb, lightDir, normal.xyz, halfVec, eyeDir, gloss, fresnel, NdotL).rgb * specLightColor * attenuation;
|
||||
vec4 fragmentColor = vec4(1.0);
|
||||
fragmentColor.rgb = computeLighting(specColor.rgb, diffColor, lightDir, normal.xyz, halfVec, eyeDir, roughness, fresnel, NdotL).rgb * diffuseLightColor * attenuation * area_normalisation;
|
||||
fragOut0 = max(fragmentColor, vec4(0.0));
|
||||
}
|
||||
@@ -12,7 +12,7 @@ layout (std140) uniform lightData {
|
||||
vec3 diffuseLightColor;
|
||||
float coneAngle;
|
||||
|
||||
vec3 specLightColor;
|
||||
vec3 lightDir;
|
||||
float coneInnerAngle;
|
||||
|
||||
vec3 coneDir;
|
||||
@@ -21,10 +21,10 @@ layout (std140) uniform lightData {
|
||||
vec3 scale;
|
||||
float lightRadius;
|
||||
|
||||
vec3 lightDir;
|
||||
int lightType;
|
||||
|
||||
bool enable_shadows;
|
||||
|
||||
float sourceRadius;
|
||||
};
|
||||
|
||||
out vec3 lightPosition;
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
//!#version 150
|
||||
#include "gamma.sdr" //! #include "gamma.sdr"
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
uniform samplerCube envmap;
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
int face;
|
||||
};
|
||||
|
||||
in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
// Iteratively optimised points to give low discrepancy distribution on arbritrary hemisphere.
|
||||
const vec3 points[128] = vec3[128](
|
||||
vec3(-0.2268, 0.6185, 0.7523),
|
||||
vec3( 0.9958, -0.0871, -0.0277),
|
||||
vec3( 0.7132, -0.6099, 0.3455),
|
||||
vec3(-0.9243, -0.3644, 0.1137),
|
||||
vec3( 0.4580, -0.3977, -0.7950),
|
||||
vec3(-0.2989, -0.7422, -0.5998),
|
||||
vec3(-0.7263, -0.5965, 0.3416),
|
||||
vec3(-0.7906, 0.4955, 0.3597),
|
||||
vec3(-0.5006, -0.5116, 0.6984),
|
||||
vec3( 0.3924, 0.8514, 0.3479),
|
||||
vec3(-0.5916, -0.8009, 0.0925),
|
||||
vec3( 0.5076, 0.2359, -0.8287),
|
||||
vec3(-0.6712, 0.5976, -0.4386),
|
||||
vec3( 0.5255, -0.5998, -0.6034),
|
||||
vec3( 0.2083, 0.7588, -0.6172),
|
||||
vec3( 0.8282, 0.0486, 0.5584),
|
||||
vec3( 0.2563, -0.6217, -0.7401),
|
||||
vec3(-0.4601, 0.2289, -0.8579),
|
||||
vec3( 0.6840, 0.5803, -0.4421),
|
||||
vec3(-0.0167, 0.9512, -0.3080),
|
||||
vec3( 0.2259, 0.3423, 0.9120),
|
||||
vec3( 0.3726, -0.7409, 0.5587),
|
||||
vec3( 0.0440, -0.4696, 0.8818),
|
||||
vec3(-0.5011, -0.6169, -0.6069),
|
||||
vec3( 0.2801, 0.8534, 0.4396),
|
||||
vec3(-0.2464, -0.9090, 0.3360),
|
||||
vec3(-0.7297, 0.1734, 0.6614),
|
||||
vec3(-0.2619, 0.2954, 0.9188),
|
||||
vec3( 0.1519, -0.5555, -0.8176),
|
||||
vec3(-0.6161, -0.7542, 0.2274),
|
||||
vec3( 0.3067, -0.8999, -0.3100),
|
||||
vec3( 0.4223, -0.6110, 0.6696),
|
||||
vec3(-0.7079, 0.5325, 0.4640),
|
||||
vec3( 0.9522, -0.3022, 0.0443),
|
||||
vec3(-0.3054, -0.5260, -0.7937),
|
||||
vec3(-0.7502, 0.1605, -0.6414),
|
||||
vec3( 0.9070, -0.0741, -0.4145),
|
||||
vec3(-0.1592, 0.8002, -0.5783),
|
||||
vec3( 0.7672, 0.4286, 0.4772),
|
||||
vec3(-0.9340, 0.2468, -0.2584),
|
||||
vec3( 0.9905, -0.1254, 0.0563),
|
||||
vec3(-0.7776, -0.4144, -0.4729),
|
||||
vec3(-0.7503, 0.6316, -0.1952),
|
||||
vec3(-0.3313, -0.2916, -0.8973),
|
||||
vec3( 0.1147, -0.7738, 0.6230),
|
||||
vec3( 0.1481, 0.3008, -0.9421),
|
||||
vec3(-0.8300, 0.0980, 0.5491),
|
||||
vec3(-0.1374, 0.9904, 0.0163),
|
||||
vec3( 0.0996, -0.9950, -0.0014),
|
||||
vec3( 0.7040, 0.0177, -0.7100),
|
||||
vec3(-0.3455, 0.8607, -0.3740),
|
||||
vec3(-0.6005, 0.2897, 0.7453),
|
||||
vec3( 0.3546, -0.8403, -0.4100),
|
||||
vec3(-0.5317, 0.5463, -0.6472),
|
||||
vec3( 0.4780, -0.1825, -0.8592),
|
||||
vec3( 0.3033, -0.1953, 0.9327),
|
||||
vec3(-0.8416, -0.1018, -0.5304),
|
||||
vec3( 0.2834, -0.6792, -0.6771),
|
||||
vec3( 0.9488, 0.1900, -0.2522),
|
||||
vec3( 0.3215, 0.7569, -0.5690),
|
||||
vec3(-0.7391, 0.5883, -0.3281),
|
||||
vec3( 0.4351, -0.2649, 0.8605),
|
||||
vec3( 0.0829, -0.8264, 0.5570),
|
||||
vec3(-0.6900, 0.5097, 0.5139),
|
||||
vec3( 0.6869, -0.5626, 0.4601),
|
||||
vec3(-0.9385, -0.1405, -0.3153),
|
||||
vec3(-0.2377, 0.7921, 0.5622),
|
||||
vec3( 0.3259, -0.1633, -0.9312),
|
||||
vec3( 0.4753, 0.8652, -0.1597),
|
||||
vec3( 0.9267, 0.0849, -0.3661),
|
||||
vec3(-0.8777, -0.4241, -0.2231),
|
||||
vec3( 0.5195, -0.8463, -0.1177),
|
||||
vec3(-0.2962, -0.5401, 0.7878),
|
||||
vec3( 0.9439, 0.3300, -0.0130),
|
||||
vec3(-0.9481, 0.2886, 0.1333),
|
||||
vec3(-0.0272, -0.5312, 0.8468),
|
||||
vec3(-0.3538, 0.6180, -0.7021),
|
||||
vec3(-0.9996, 0.0160, -0.0217),
|
||||
vec3( 0.2800, -0.3399, 0.8978),
|
||||
vec3( 0.2090, 0.9773, 0.0338),
|
||||
vec3( 0.5249, 0.0450, 0.8500),
|
||||
vec3( 0.8165, 0.3275, -0.4755),
|
||||
vec3( 0.1568, -0.6439, -0.7489),
|
||||
vec3( 0.3034, 0.6192, -0.7243),
|
||||
vec3(-0.7233, -0.6519, -0.2278),
|
||||
vec3(-0.8259, -0.4757, 0.3027),
|
||||
vec3( 0.2690, -0.7823, 0.5618),
|
||||
vec3( 0.3309, 0.4864, -0.8087),
|
||||
vec3(-0.3891, 0.4036, 0.8281),
|
||||
vec3(-0.0919, 0.1208, 0.9884),
|
||||
vec3(-0.2482, -0.5348, 0.8077),
|
||||
vec3( 0.8195, 0.3333, 0.4661),
|
||||
vec3( 0.7890, -0.6104, 0.0702),
|
||||
vec3(-0.4653, 0.8046, 0.3688),
|
||||
vec3(-0.0413, -0.2247, -0.9736),
|
||||
vec3( 0.1926, 0.2839, -0.9393),
|
||||
vec3( 0.9205, -0.2443, -0.3048),
|
||||
vec3(-0.4891, 0.8229, 0.2891),
|
||||
vec3(-0.9010, -0.4189, -0.1128),
|
||||
vec3( 0.0706, 0.2715, 0.9598),
|
||||
vec3(-0.2682, 0.4639, -0.8443),
|
||||
vec3(-0.6389, -0.0442, 0.7680),
|
||||
vec3(-0.2588, 0.9613, -0.0949),
|
||||
vec3( 0.5469, -0.4194, 0.7246),
|
||||
vec3( 0.8399, 0.3814, 0.3860),
|
||||
vec3( 0.8060, -0.3544, -0.4741),
|
||||
vec3(-0.7109, -0.4466, 0.5432),
|
||||
vec3(-0.2986, -0.9381, -0.1753),
|
||||
vec3( 0.3983, -0.3642, -0.8418),
|
||||
vec3( 0.4518, 0.8744, 0.1770),
|
||||
vec3( 0.8792, -0.4098, 0.2432),
|
||||
vec3(-0.7904, 0.6106, -0.0494),
|
||||
vec3( 0.1667, -0.2852, -0.9438),
|
||||
vec3( 0.5566, 0.6694, 0.4920),
|
||||
vec3( 0.1761, 0.9638, 0.2000),
|
||||
vec3( 0.6951, 0.7188, 0.0090),
|
||||
vec3(-0.2659, -0.0544, 0.9625),
|
||||
vec3(-0.0370, 0.6667, 0.7444),
|
||||
vec3( 0.1119, -0.5816, 0.8058),
|
||||
vec3(-0.1706, -0.9310, -0.3226),
|
||||
vec3( 0.5573, -0.8143, 0.1624),
|
||||
vec3( 0.3899, -0.9183, 0.0682),
|
||||
vec3(-0.2921, -0.7937, 0.5336),
|
||||
vec3( 0.8488, 0.4895, 0.1997),
|
||||
vec3(-0.6887, 0.1527, 0.7088),
|
||||
vec3(-0.3092, 0.0011, -0.9510),
|
||||
vec3( 0.3066, 0.6124, 0.7287),
|
||||
vec3( 0.7305, 0.6698, 0.1333)
|
||||
);
|
||||
|
||||
void main() {
|
||||
float xpos = 2 * gl_FragCoord.x/16 - 1; // remap to (-1, 1)
|
||||
float ypos = 2 * gl_FragCoord.y/16 - 1;
|
||||
vec3 fragDir;
|
||||
vec4 fragCol = vec4(0.0);
|
||||
|
||||
switch (face) {
|
||||
case 0: // +X
|
||||
fragDir = vec3(1.0, -ypos, -xpos);
|
||||
break;
|
||||
case 1: // -X
|
||||
fragDir = vec3(-1.0, -ypos, xpos);
|
||||
break;
|
||||
case 2: // +Y
|
||||
fragDir = vec3(xpos, 1.0, ypos);
|
||||
break;
|
||||
case 3: // -Y
|
||||
fragDir = vec3(xpos, -1.0, -ypos);
|
||||
break;
|
||||
case 4: // +Z
|
||||
fragDir = vec3(xpos, -ypos, 1.0);
|
||||
break;
|
||||
case 5: // -Z
|
||||
fragDir = vec3(-xpos, -ypos, -1.0);
|
||||
break;
|
||||
}
|
||||
fragDir = normalize(fragDir);
|
||||
for(int i=0;i<128;++i)
|
||||
{
|
||||
// This precalcualted sampling method seems weird, but by having a set of fixed directions
|
||||
// and mirroring the bad ones onto the correct side of the normal means that
|
||||
// approximately 50% of envmap texture samples (the non-mirrored ones)
|
||||
// are shared between adjacent fragments, improving texture cache hit rate.
|
||||
float PdotD = dot(points[i], fragDir);
|
||||
float aPdotD = abs(PdotD);
|
||||
vec3 sampDir = points[i] + (aPdotD - PdotD) * fragDir;
|
||||
fragCol += aPdotD * vec4(srgb_to_linear(texture(envmap, sampDir)).rgb, 1.0);
|
||||
}
|
||||
fragOut0 = linear_to_srgb(PI * fragCol * (1.0/128));
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
//? #version 150
|
||||
const int LT_DIRECTIONAL = 0; // A light like a sun
|
||||
const int LT_POINT = 1; // A point light, like an explosion
|
||||
const int LT_TUBE = 2; // A tube light, like a fluorescent light
|
||||
@@ -7,10 +7,12 @@ const int LT_CONE = 3; // A cone light, like a flood light
|
||||
const float SPEC_FACTOR_NO_SPEC_MAP = 0.1;
|
||||
const float GLOW_MAP_INTENSITY = 1.5;
|
||||
const float GLOW_MAP_SRGB_MULTIPLIER = 3.0;
|
||||
const float PI = 3.14159f;
|
||||
|
||||
vec3 FresnelSchlick(vec3 specColor, vec3 light, vec3 halfVec)
|
||||
|
||||
vec3 FresnelSchlick(vec3 halfVec, vec3 view, vec3 specColor)
|
||||
{
|
||||
return specColor + (vec3(1.0) - specColor) * pow(1.0 - clamp(dot(light, halfVec), 0.0, 1.0), 5.0);
|
||||
return specColor + (vec3(1.0) - specColor) * pow(1.0 - clamp(dot(view, halfVec), 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
vec3 SpecularBlinnPhong(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, float specPower, float fresnel, float dotNL)
|
||||
@@ -18,35 +20,67 @@ vec3 SpecularBlinnPhong(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, f
|
||||
return mix(specColor, FresnelSchlick(specColor, light, halfVec), fresnel) * ((specPower + 2.0) / 8.0 ) * pow(clamp(dot(normal, halfVec), 0.0, 1.0), specPower) * dotNL;
|
||||
}
|
||||
|
||||
vec3 SpecularGGX(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float gloss, float fresnelFactor, float dotNL)
|
||||
float GeometrySchlickGGX(float dotAB, float k)
|
||||
{
|
||||
return dotAB / (dotAB * (1.0f - k) + k);
|
||||
}
|
||||
vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float roughness, float fresnelFactor, float dotNL)
|
||||
{
|
||||
float roughness = clamp(1.0f - gloss, 0.0f, 1.0f);
|
||||
float alpha = roughness * roughness;
|
||||
|
||||
float alphaSqr = alpha * alpha;
|
||||
float dotNH = clamp(dot(normal, halfVec), 0.0f, 1.0f);
|
||||
float dotNV = clamp(dot(normal, view), 0.0f, 1.0f);
|
||||
|
||||
float alphaSqr = alpha * alpha;
|
||||
float pi = 3.14159f;
|
||||
float denom = dotNH * dotNH * (alphaSqr - 1.0f) + 1.0f;
|
||||
float distribution = alphaSqr / (pi * denom * denom);
|
||||
// NOTE - we're intentionally using UE4's reflectance model as modellers are using tools designed for common engines.
|
||||
|
||||
vec3 fresnel = mix(specColor, FresnelSchlick(specColor, light, halfVec), fresnelFactor);
|
||||
// Cook-Torrance BRDF Model (Specular Reflection) = Distibution * Fresnel * Geometry / (4*dotNV*dotNL)
|
||||
|
||||
float alphaPrime = roughness + 1.0f;
|
||||
float k = alphaPrime * alphaPrime / 8.0f;
|
||||
float g1vNL = 1.0f / (dotNL * (1.0f - k) + k);
|
||||
float g1vNV = 1.0f / (dotNV * (1.0f - k) + k);
|
||||
float visibility = g1vNL * g1vNV;
|
||||
// Distribution Term - Trowbridge-Reitz GGX
|
||||
|
||||
float denom = dotNH * dotNH * (alphaSqr - 1.0f) + 1.0001f; // Extra .0001 to prevent div 0
|
||||
float distribution = alphaSqr / (PI * denom * denom);
|
||||
|
||||
return distribution * fresnel * visibility * dotNL;
|
||||
// Fresnel Term - Fresnel-Schlick
|
||||
vec3 fresnel = mix(specColor, FresnelSchlick(halfVec, view, specColor), fresnelFactor);
|
||||
|
||||
// Geometry Term - Schlick-GGX approximation
|
||||
float r = roughness + 1.0;
|
||||
float k = r * r / 8.0f;
|
||||
// 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.
|
||||
float g1vNL = GeometrySchlickGGX(dotNL, k);
|
||||
float g1vNV = GeometrySchlickGGX(dotNV, k);
|
||||
float geometry = g1vNL * g1vNV;
|
||||
|
||||
|
||||
|
||||
vec3 specular = distribution * fresnel * geometry / (4*dotNV*dotNL + 0.0001);
|
||||
|
||||
// Diffuse term - Lambertian, kD represents energy lost to specular reflection.
|
||||
vec3 kD = vec3(1.0)-fresnel;
|
||||
kD *= (vec3(1.0) - specColor);
|
||||
vec3 diffuse = kD * diffColor/PI;
|
||||
|
||||
return (specular + diffuse) * dotNL;
|
||||
}
|
||||
|
||||
vec3 computeLighting(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float gloss, float fresnelFactor, float dotNL)
|
||||
vec3 computeLighting(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float roughness, float fresnelFactor, float dotNL)
|
||||
{
|
||||
#ifdef FLAG_LIGHT_MODEL_BLINN_PHONG
|
||||
return SpecularBlinnPhong(specColor, light, normal, halfVec, 32, fresnelFactor, dotNL);
|
||||
#else
|
||||
return SpecularGGX(specColor, light, normal, halfVec, view, gloss, fresnelFactor, dotNL);
|
||||
return ComputeGGX(specColor, diffColor, light, normal, halfVec, view, roughness, fresnelFactor, dotNL);
|
||||
#endif
|
||||
}
|
||||
|
||||
mat3 localCoordinates(vec3 normal, vec3 tangent_in)
|
||||
{
|
||||
// Create basis so we can transform `view` direction into local coord system
|
||||
// We're not particularly attached to any basis as we have an isotropic roughness, and don't need to align axes with x,y terms.
|
||||
vec3 tangent = normalize (tangent_in - dot (tangent_in, normal) * normal);
|
||||
vec3 bitangent = cross(tangent, normal);
|
||||
mat3 basis = mat3(tangent, bitangent, normal);
|
||||
return basis;
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
//? #version 150
|
||||
#include "shadows.sdr" //! #include "shadows.sdr"
|
||||
#include "lighting.sdr" //! #include "lighting.sdr"
|
||||
#include "gamma.sdr" //! #include "gamma.sdr"
|
||||
|
||||
#include "shadows.sdr"
|
||||
#include "lighting.sdr"
|
||||
#include "gamma.sdr"
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
#define LT_DIRECTIONAL 0
|
||||
@@ -13,10 +14,11 @@ struct model_light {
|
||||
vec3 diffuse_color;
|
||||
int light_type;
|
||||
|
||||
vec3 spec_color;
|
||||
vec3 direction;
|
||||
float attenuation;
|
||||
|
||||
vec3 direction;
|
||||
float ml_sourceRadius;
|
||||
|
||||
};
|
||||
|
||||
layout (std140) uniform modelData {
|
||||
@@ -52,20 +54,20 @@ layout (std140) uniform modelData {
|
||||
int blend_alpha;
|
||||
|
||||
vec3 emissionFactor;
|
||||
bool overrideDiffuse;
|
||||
bool overrideDiffuse_;
|
||||
|
||||
vec3 diffuseClr;
|
||||
bool overrideGlow;
|
||||
vec3 diffuseClr_;
|
||||
bool overrideGlow_;
|
||||
|
||||
vec3 glowClr;
|
||||
bool overrideSpec;
|
||||
vec3 glowClr_;
|
||||
bool overrideSpec_;
|
||||
|
||||
vec3 specClr;
|
||||
vec3 specClr_;
|
||||
bool alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
bool alpha_spec;
|
||||
bool alpha_spec_;
|
||||
int effect_num;
|
||||
|
||||
vec4 fogColor;
|
||||
@@ -86,7 +88,7 @@ layout (std140) uniform modelData {
|
||||
float middist;
|
||||
float fardist;
|
||||
|
||||
vec2 normalAlphaMinMax;
|
||||
vec2 normalAlphaMinMax_;
|
||||
int sBasemapIndex;
|
||||
int sGlowmapIndex;
|
||||
|
||||
@@ -102,9 +104,9 @@ in VertexOutput {
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vec3 envReflect;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
mat3 tangentMatrix;
|
||||
#endif
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#ifdef FLAG_FOG
|
||||
float fogDist;
|
||||
#endif
|
||||
@@ -128,6 +130,7 @@ uniform sampler2DArray sSpecmap;
|
||||
#endif
|
||||
#ifdef FLAG_ENV_MAP
|
||||
uniform samplerCube sEnvmap;
|
||||
uniform samplerCube sIrrmap;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
uniform sampler2DArray sNormalmap;
|
||||
@@ -139,7 +142,7 @@ uniform sampler2DArray sAmbientmap;
|
||||
uniform sampler2D sFramebuffer;
|
||||
#endif
|
||||
#ifdef FLAG_TEAMCOLOR
|
||||
vec2 teamMask = vec2(0.0, 0.0);
|
||||
vec4 teamMask;
|
||||
#endif
|
||||
#ifdef FLAG_MISC_MAP
|
||||
uniform sampler2DArray sMiscmap;
|
||||
@@ -196,7 +199,8 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
|
||||
if(i > 0) {
|
||||
shadow = 1.0;
|
||||
}
|
||||
|
||||
float roughness = clamp(1.0f - gloss, 0.0f, 1.0f);
|
||||
float alpha = roughness * roughness;
|
||||
vec3 lightDir;
|
||||
float attenuation;
|
||||
// gather light params
|
||||
@@ -205,9 +209,9 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
|
||||
float NdotL = clamp(dot(normal, lightDir), 0.0f, 1.0f);
|
||||
// Ambient, Diffuse, and Specular
|
||||
lightDiffuse += (lights[i].diffuse_color.rgb * diffuseFactor * NdotL * attenuation) * shadow;
|
||||
lightSpecular += lights[i].spec_color * computeLighting(specularMaterial, lightDir, normal, halfVec, eyeDir, gloss, fresnel, NdotL) * attenuation * shadow;
|
||||
lightSpecular += lights[i].diffuse_color.rgb * computeLighting(specularMaterial, diffuseMaterial, lightDir, normal, halfVec, eyeDir, roughness, fresnel, NdotL) * attenuation * shadow;
|
||||
}
|
||||
return diffuseMaterial * (lightAmbient + lightDiffuse) + lightSpecular;
|
||||
return diffuseMaterial * lightAmbient + lightSpecular;
|
||||
}
|
||||
|
||||
void main()
|
||||
@@ -225,10 +229,7 @@ void main()
|
||||
vec4 specColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
vec4 emissiveColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
float fresnelFactor = 0.0;
|
||||
float glossData = 0.6;
|
||||
#ifdef FLAG_LIGHT
|
||||
glossData = defaultGloss;
|
||||
#endif
|
||||
float glossData = defaultGloss;
|
||||
vec2 aoFactors = vec2(1.0, 1.0);
|
||||
#ifdef FLAG_AMBIENT_MAP
|
||||
// red channel is ambient occlusion factor which only affects ambient lighting.
|
||||
@@ -272,7 +273,6 @@ void main()
|
||||
// premultiply alpha if blend_alpha is 1. assume that our blend function is srcColor + (1-Alpha)*destColor.
|
||||
// if blend_alpha is 2, assume blend func is additive and don't modify color
|
||||
if(blend_alpha == 1) baseColor.rgb = baseColor.rgb * baseColor.a;
|
||||
if(overrideDiffuse) baseColor.rgb = diffuseClr;
|
||||
#endif
|
||||
specColor = vec4(baseColor.rgb * SPEC_FACTOR_NO_SPEC_MAP, glossData);
|
||||
#ifdef FLAG_HDR
|
||||
@@ -281,10 +281,6 @@ void main()
|
||||
#ifdef FLAG_SPEC_MAP
|
||||
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
|
||||
if(alphaGloss) glossData = specColor.a;
|
||||
if(overrideSpec) {
|
||||
specColor.rgb = specClr;
|
||||
fresnelFactor = 1.0;
|
||||
}
|
||||
if(gammaSpec) {
|
||||
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
|
||||
fresnelFactor = 1.0;
|
||||
@@ -295,9 +291,17 @@ void main()
|
||||
#endif
|
||||
baseColor.rgb *= aoFactors.y;
|
||||
specColor.rgb *= aoFactors.y;
|
||||
|
||||
// Anti-glint "trick" based on Valve's "Advanced VR Rendering" talk at GDC2015:
|
||||
// http://media.steampowered.com/apps/valve/2015/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf Page 43
|
||||
// basically make surfaces rougher if local normals change too fast in screenspace
|
||||
vec2 normDx = dFdx(unitNormal.xy);
|
||||
vec2 normDy = dFdy(unitNormal.xy);
|
||||
float glossGeo = 1.0f - pow(clamp(max(dot(normDx,normDx), dot(normDy,normDy)),0.0,1.0),0.33);
|
||||
glossData = min(glossData, glossGeo);
|
||||
|
||||
#ifdef FLAG_MISC_MAP
|
||||
#ifdef FLAG_TEAMCOLOR
|
||||
vec4 teamMask = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
|
||||
|
||||
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
|
||||
@@ -351,30 +355,62 @@ void main()
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vec3 envReflectNM = vertIn.envReflect;
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
envReflectNM += vec3(normalSample, 0.0);
|
||||
envReflectNM = normalize(envReflectNM);
|
||||
#endif
|
||||
float mip = (envGloss) ? (1.0 - glossData) * 7.0 : 0.0;
|
||||
vec4 envColour = textureLod(sEnvmap, envReflectNM, mip);
|
||||
#ifdef FLAG_HDR
|
||||
envColour.rgb = srgb_to_linear(envColour.rgb);
|
||||
#endif
|
||||
envColour.rgb *= (envGloss) ? 1.0 : specColor.a;
|
||||
emissiveColor.rgb += envColour.rgb * FresnelLazarovEnv(specColor.rgb, eyeDir, normal, glossData);
|
||||
#ifdef FLAG_LIGHT
|
||||
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
|
||||
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
|
||||
// to determine the mip bias.
|
||||
// We use the specular term listed at http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
|
||||
// 1/(pi*alpha^2) * NdotM^((2/alpha^2)-2)
|
||||
// so let s = (2/alpha^2 - 2)
|
||||
// 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1)
|
||||
|
||||
const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes
|
||||
const float REZ_BIAS = log2(ENV_REZ * sqrt(3));
|
||||
|
||||
float roughness = clamp(1.0f - glossData, 0.0f, 1.0f);
|
||||
float alpha = roughness * roughness;
|
||||
float alphaSqr = alpha * alpha;
|
||||
float rough_bias = 0.5 * log2(2/alphaSqr - 1);
|
||||
float mip_bias = REZ_BIAS - rough_bias;
|
||||
|
||||
// Sample light, using mip bias to blur it.
|
||||
vec3 light_dir = reflect(-eyeDir, normal);
|
||||
vec3 env_light_dir = vec3(envMatrix * vec4(light_dir, 0.0));
|
||||
vec4 specEnvColour = srgb_to_linear(textureLod(sEnvmap, env_light_dir, mip_bias));
|
||||
|
||||
vec3 halfVec = normal;
|
||||
|
||||
// Lots of hacks here to get things to look right. We aren't loading a BRDF split-sum integral texture
|
||||
// or properly calculating IBL levels.
|
||||
// Fresnel calculation as with standard lights.
|
||||
|
||||
vec3 fresnel = mix(specColor.rgb, FresnelSchlick(halfVec, eyeDir, specColor.rgb), specColor.a);
|
||||
|
||||
// Pseudo-IBL, so use k_IBL
|
||||
float k = alpha * alpha/ 2.0f;
|
||||
|
||||
float NdotL = max(dot(light_dir, normal),0);
|
||||
|
||||
float g1vNL = GeometrySchlickGGX(NdotL, k);
|
||||
vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL;
|
||||
|
||||
vec3 kD = vec3(1.0)-fresnel;
|
||||
kD *= (vec3(1.0) - specColor.rgb);
|
||||
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb);
|
||||
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x;
|
||||
emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_GLOW_MAP
|
||||
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
|
||||
if(overrideGlow) glowColor = glowClr;
|
||||
#ifdef FLAG_HDR
|
||||
glowColor = srgb_to_linear(glowColor) * GLOW_MAP_SRGB_MULTIPLIER;
|
||||
#endif
|
||||
#ifdef FLAG_MISC_MAP
|
||||
#ifdef FLAG_TEAMCOLOR
|
||||
float glowColorLuminance = dot(glowColor, vec3(0.299, 0.587, 0.114));
|
||||
glowColor = team_glow_enabled ? mix(max(team_color_glow, vec3(0.0)), glowColor, clamp(glowColorLuminance - teamMask.b - teamMask.a, 0.0, 1.0)) : glowColor;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_HDR
|
||||
glowColor = srgb_to_linear(glowColor) * GLOW_MAP_SRGB_MULTIPLIER;
|
||||
#endif
|
||||
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
|
||||
#endif
|
||||
@@ -424,10 +460,6 @@ void main()
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_ALPHA
|
||||
float normViewOffset = dot(vec3(0.0, 0.0, 1.0), normal);
|
||||
baseColor.a = smoothstep(min(normalAlphaMinMax.x, normalAlphaMinMax.y), max(normalAlphaMinMax.x, normalAlphaMinMax.y), clamp(normalAlphaMinMax.x > normalAlphaMinMax.y ? normViewOffset : 1.0 - normViewOffset, 0.0, 1.0));
|
||||
#endif
|
||||
#ifndef FLAG_DEFERRED
|
||||
// emissive colors won't be added later when we are using forward rendering so we need to do that here
|
||||
baseColor.rgb += emissiveColor.rgb;
|
||||
@@ -436,15 +468,7 @@ void main()
|
||||
fragOut0 = baseColor;
|
||||
#ifdef FLAG_DEFERRED
|
||||
fragOut1 = vec4(vertIn.position.xyz, 1.0);
|
||||
|
||||
// Anti-glint "trick" based on Valve's "Advanced VR Rendering" talk at GDC2015:
|
||||
// http://media.steampowered.com/apps/valve/2015/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf Page 43
|
||||
// basically make surfaces rougher if local normals change too fast in screenspace
|
||||
vec2 normDx = dFdx(normal.xy);
|
||||
vec2 normDy = dFdy(normal.xy);
|
||||
float glossGeo = 1.0f - pow(clamp(max(dot(normDx,normDx), dot(normDy,normDy)),0.0,1.0),0.33);
|
||||
fragOut2 = vec4(normal, min(glossData, glossGeo));
|
||||
|
||||
fragOut2 = vec4(normal, glossData);
|
||||
fragOut3 = vec4(specColor.rgb, fresnelFactor);
|
||||
fragOut4 = emissiveColor;
|
||||
#endif
|
||||
|
||||
@@ -22,10 +22,10 @@ struct model_light {
|
||||
vec3 diffuse_color;
|
||||
int light_type;
|
||||
|
||||
vec3 spec_color;
|
||||
vec3 direction;
|
||||
float attenuation;
|
||||
|
||||
vec3 direction;
|
||||
float ml_sourceRadius;
|
||||
};
|
||||
|
||||
layout (std140) uniform modelData {
|
||||
@@ -61,20 +61,20 @@ layout (std140) uniform modelData {
|
||||
int blend_alpha;
|
||||
|
||||
vec3 emissionFactor;
|
||||
bool overrideDiffuse;
|
||||
bool overrideDiffuse_;
|
||||
|
||||
vec3 diffuseClr;
|
||||
bool overrideGlow;
|
||||
vec3 diffuseClr_;
|
||||
bool overrideGlow_;
|
||||
|
||||
vec3 glowClr;
|
||||
bool overrideSpec;
|
||||
vec3 glowClr_;
|
||||
bool overrideSpec_;
|
||||
|
||||
vec3 specClr;
|
||||
vec3 specClr_;
|
||||
bool alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
bool alpha_spec;
|
||||
bool alpha_spec_;
|
||||
int effect_num;
|
||||
|
||||
vec4 fogColor;
|
||||
@@ -95,7 +95,7 @@ layout (std140) uniform modelData {
|
||||
float middist;
|
||||
float fardist;
|
||||
|
||||
vec2 normalAlphaMinMax;
|
||||
vec2 normalAlphaMinMax_;
|
||||
int sBasemapIndex;
|
||||
int sGlowmapIndex;
|
||||
|
||||
@@ -111,9 +111,9 @@ in VertexOutput {
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vec3 envReflect;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
mat3 tangentMatrix;
|
||||
#endif
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#ifdef FLAG_FOG
|
||||
float fogDist;
|
||||
#endif
|
||||
@@ -139,9 +139,9 @@ out VertexOutput {
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vec3 envReflect;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
mat3 tangentMatrix;
|
||||
#endif
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#ifdef FLAG_FOG
|
||||
float fogDist;
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//? #version 150
|
||||
#extension GL_ARB_gpu_shader5: enable
|
||||
|
||||
#include "shadows.sdr"
|
||||
@@ -16,10 +17,10 @@ struct model_light {
|
||||
vec3 diffuse_color;
|
||||
int light_type;
|
||||
|
||||
vec3 spec_color;
|
||||
vec3 direction;
|
||||
float attenuation;
|
||||
|
||||
vec3 direction;
|
||||
float ml_sourceRadius;
|
||||
};
|
||||
|
||||
layout (std140) uniform modelData {
|
||||
@@ -55,20 +56,20 @@ layout (std140) uniform modelData {
|
||||
int blend_alpha;
|
||||
|
||||
vec3 emissionFactor;
|
||||
bool overrideDiffuse;
|
||||
bool overrideDiffuse_;
|
||||
|
||||
vec3 diffuseClr;
|
||||
bool overrideGlow;
|
||||
vec3 diffuseClr_;
|
||||
bool overrideGlow_;
|
||||
|
||||
vec3 glowClr;
|
||||
bool overrideSpec;
|
||||
vec3 glowClr_;
|
||||
bool overrideSpec_;
|
||||
|
||||
vec3 specClr;
|
||||
vec3 specClr_;
|
||||
bool alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
bool alpha_spec;
|
||||
bool alpha_spec_;
|
||||
int effect_num;
|
||||
|
||||
vec4 fogColor;
|
||||
@@ -89,7 +90,7 @@ layout (std140) uniform modelData {
|
||||
float middist;
|
||||
float fardist;
|
||||
|
||||
vec2 normalAlphaMinMax;
|
||||
vec2 normalAlphaMinMax_;
|
||||
int sBasemapIndex;
|
||||
int sGlowmapIndex;
|
||||
|
||||
@@ -109,9 +110,7 @@ out VertexOutput {
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vec3 envReflect;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
mat3 tangentMatrix;
|
||||
#endif
|
||||
mat3 tangentMatrix;
|
||||
#ifdef FLAG_FOG
|
||||
float fogDist;
|
||||
#endif
|
||||
@@ -188,12 +187,12 @@ void main()
|
||||
vertOut.shadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, shadowPos);
|
||||
vertOut.shadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, shadowPos);
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
// Setup stuff for normal maps
|
||||
vec3 t = normalize(mat3(modelViewMatrix) * mat3(orient) * vertTangent.xyz);
|
||||
vec3 b = cross(normal, t) * vertTangent.w;
|
||||
vertOut.tangentMatrix = mat3(t, b, normal);
|
||||
#endif
|
||||
|
||||
// Setup stuff for normal maps and envmaps
|
||||
vec3 t = normalize(mat3(modelViewMatrix) * mat3(orient) * vertTangent.xyz);
|
||||
vec3 b = cross(normal, t) * vertTangent.w;
|
||||
vertOut.tangentMatrix = mat3(t, b, normal);
|
||||
|
||||
#ifdef FLAG_ENV_MAP
|
||||
// Environment mapping reflection vector.
|
||||
vec3 envReflect = reflect(normalize(position.xyz), normal);
|
||||
|
||||
@@ -3,6 +3,11 @@ out vec4 fragOut0;
|
||||
uniform sampler2DArray ytex;
|
||||
uniform sampler2DArray utex;
|
||||
uniform sampler2DArray vtex;
|
||||
layout (std140) uniform movieData {
|
||||
float alpha;
|
||||
float pad[3];
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
float y = texture(ytex, vec3(fragTexCoord.st, 0.0)).r;
|
||||
@@ -12,5 +17,5 @@ void main()
|
||||
fragOut0.r = dot(val, vec3(1.1640625, 0.0, 1.59765625));
|
||||
fragOut0.g = dot(val, vec3(1.1640625, -0.390625, -0.8125));
|
||||
fragOut0.b = dot(val, vec3(1.1640625, 2.015625, 0.0));
|
||||
fragOut0.a = 1.0;
|
||||
fragOut0.a = alpha;
|
||||
}
|
||||
@@ -8,7 +8,7 @@ local function cfileLoader(name)
|
||||
local file = nil
|
||||
|
||||
for i,v in ipairs(exts) do
|
||||
local real_name = name .. v
|
||||
local real_name = string.gsub(name, "%.", "/") .. v
|
||||
file = cf.openFile(real_name, "r", "data/scripts")
|
||||
|
||||
if (file:isValid()) then
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#CUSTOM CHEATS
|
||||
|
||||
$Cheat:
|
||||
+Code: arrrrwalktheplank
|
||||
+Message: Walk the plank
|
||||
+SpawnShip:
|
||||
+Name: Volition Bravos
|
||||
+Class: Volition Bravos
|
||||
|
||||
#END
|
||||
@@ -79,7 +79,7 @@ $Fog:
|
||||
+Start dist: 10.0
|
||||
+Compl dist: 500.0
|
||||
$AI:
|
||||
+Valid goals: ( "fly to ship" "dock" "undock" "waypoints" "waypoints once" "stay near ship" "keep safe dist" "stay still" "play dead" "play dead (persistent)" )
|
||||
+Valid goals: ( "fly to ship" "dock" "undock" "waypoints" "waypoints once" "stay near ship" "keep safe dist" "stay still" "play dead" "play dead (persistent)" "rearm ship" )
|
||||
+Accept Player Orders: YES
|
||||
+Player orders: ( "rearm me" "abort rearm" "depart" )
|
||||
+Auto attacks: YES
|
||||
|
||||
@@ -147,6 +147,8 @@ extern bool Knossos_warp_ani_used;
|
||||
|
||||
extern bool Fireball_use_3d_warp;
|
||||
|
||||
extern bool Fireball_warp_flash;
|
||||
|
||||
// Cyborg - get a count of how many valid fireballs are in the mission.
|
||||
int fireball_get_count();
|
||||
|
||||
|
||||
@@ -17,10 +17,21 @@
|
||||
#include "mission/missionparse.h"
|
||||
#include "model/model.h"
|
||||
#include "nebula/neb.h"
|
||||
#include "options/Option.h"
|
||||
#include "render/3d.h"
|
||||
#include "render/batching.h"
|
||||
#include "ship/ship.h"
|
||||
|
||||
bool Fireball_warp_flash = false;
|
||||
|
||||
static auto WarpFlashOption = 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();
|
||||
|
||||
void warpin_batch_draw_face( int texture, vertex *v1, vertex *v2, vertex *v3 )
|
||||
{
|
||||
vec3d norm;
|
||||
@@ -55,47 +66,27 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
|
||||
verts[1] = verts[2] = verts[3] = verts[4] = verts[0];
|
||||
|
||||
if (warp_glow_bitmap >= 0) {
|
||||
|
||||
float r = radius;
|
||||
bool render_it = true;
|
||||
// Add in noise
|
||||
int noise_frame = fl2i(Missiontime/15.0f) % NOISE_NUM_FRAMES;
|
||||
|
||||
#define OUT_PERCENT1 0.80f
|
||||
#define OUT_PERCENT2 0.90f
|
||||
r *= (0.40f + Noise[noise_frame] * 0.30f);
|
||||
|
||||
#define IN_PERCENT1 0.10f
|
||||
#define IN_PERCENT2 0.20f
|
||||
|
||||
if (Cmdline_warp_flash)
|
||||
{
|
||||
if ( (life_percent >= IN_PERCENT1) && (life_percent < IN_PERCENT2) ) {
|
||||
r *= (life_percent - IN_PERCENT1) / (IN_PERCENT2 - IN_PERCENT1);
|
||||
//render_it = true;
|
||||
} else if ( (life_percent >= OUT_PERCENT1) && (life_percent < OUT_PERCENT2) ) {
|
||||
r *= (OUT_PERCENT2 - life_percent) / (OUT_PERCENT2 - OUT_PERCENT1);
|
||||
//render_it = true;
|
||||
}
|
||||
// Bobboau's warp thingie, toggled by cmdline
|
||||
if (Fireball_warp_flash) {
|
||||
r += powf((2.0f * life_percent) - 1.0f, 24.0f) * max_radius * 1.5f;
|
||||
}
|
||||
|
||||
if (render_it) {
|
||||
// Add in noise
|
||||
int noise_frame = fl2i(Missiontime/15.0f) % NOISE_NUM_FRAMES;
|
||||
vecs[4] = center;
|
||||
verts[4].texture_position.u = 0.5f; verts[4].texture_position.v = 0.5f;
|
||||
|
||||
r *= (0.40f + Noise[noise_frame] * 0.30f);
|
||||
g3_transfer_vertex( &verts[4], &vecs[4] );
|
||||
|
||||
// Bobboau's warp thingie, toggled by cmdline
|
||||
if (Cmdline_warp_flash) {
|
||||
r += powf((2.0f * life_percent) - 1.0f, 24.0f) * max_radius * 1.5f;
|
||||
}
|
||||
float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? neb2_get_fog_visibility(&obj->pos, 1.0f) : 1.0f;
|
||||
|
||||
vecs[4] = center;
|
||||
verts[4].texture_position.u = 0.5f; verts[4].texture_position.v = 0.5f;
|
||||
|
||||
g3_transfer_vertex( &verts[4], &vecs[4] );
|
||||
|
||||
float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? neb2_get_fog_visibility(&obj->pos, 1.0f) : 1.0f;
|
||||
|
||||
//batch_add_bitmap(warp_glow_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT, &verts[4], 0, r, alpha);
|
||||
batching_add_bitmap(warp_glow_bitmap, &verts[4], 0, r, alpha);
|
||||
}
|
||||
//batch_add_bitmap(warp_glow_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT, &verts[4], 0, r, alpha);
|
||||
batching_add_bitmap(warp_glow_bitmap, &verts[4], 0, r, alpha);
|
||||
}
|
||||
|
||||
if ( (warp_model_id >= 0) && (warp_3d) ) {
|
||||
@@ -165,7 +156,7 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
|
||||
warpin_batch_draw_face( texture_bitmap_num, &verts[0], &verts[3], &verts[4] );
|
||||
}
|
||||
|
||||
if (warp_ball_bitmap >= 0 && Cmdline_warp_flash) {
|
||||
if (warp_ball_bitmap >= 0 && Fireball_warp_flash) {
|
||||
flash_ball warp_ball(20, .1f,.25f, &orient->vec.fvec, pos, 4.0f, 0.5f);
|
||||
|
||||
float adg = (2.0f * life_percent) - 1.0f;
|
||||
|
||||
+36
-33
@@ -73,19 +73,20 @@ SCP_vector<SOUNDTRACK_INFO> Soundtracks;
|
||||
int Current_soundtrack_num; // Active soundtrack for the current mission.. index into Soundtracks[]
|
||||
|
||||
int Current_pattern = -1; // currently playing part of track
|
||||
int Pattern_timer_id = 0;
|
||||
TIMESTAMP Pattern_timer_id = TIMESTAMP::invalid();
|
||||
|
||||
// File Globals
|
||||
static int Num_enemy_arrivals;
|
||||
static int Num_friendly_arrivals;
|
||||
|
||||
#define ARRIVAL_INTERVAL_TIMESTAMP 5000
|
||||
#define BATTLE_CHECK_INTERVAL 15000
|
||||
static int Battle_over_timestamp;
|
||||
static int Mission_over_timestamp;
|
||||
static int Victory2_music_played;
|
||||
static int Next_arrival_timestamp;
|
||||
static int Check_for_battle_music;
|
||||
constexpr int ARRIVAL_INTERVAL_TIMESTAMP = 5 * MILLISECONDS_PER_SECOND;
|
||||
constexpr int BATTLE_CHECK_INTERVAL = 15 * MILLISECONDS_PER_SECOND;
|
||||
|
||||
static TIMESTAMP Battle_over_timestamp;
|
||||
static TIMESTAMP Mission_over_timestamp;
|
||||
static bool Victory2_music_played;
|
||||
static TIMESTAMP Next_arrival_timestamp;
|
||||
static TIMESTAMP Check_for_battle_music; // this timestamp is actually never set
|
||||
|
||||
typedef struct pattern_info
|
||||
{
|
||||
@@ -409,7 +410,7 @@ void event_music_do_frame()
|
||||
|
||||
// start off the music delayed
|
||||
if ( timestamp_elapsed(Pattern_timer_id) ) {
|
||||
Pattern_timer_id = 0;
|
||||
Pattern_timer_id = TIMESTAMP::invalid();
|
||||
Event_music_begun = TRUE;
|
||||
if ( Current_pattern != -1 && Patterns[Current_pattern].handle >= 0) {
|
||||
//WMC - removed in favor of if
|
||||
@@ -457,7 +458,7 @@ void event_music_do_frame()
|
||||
if (Event_Music_battle_started == 0) {
|
||||
if (Current_pattern == SONG_NRML_1 || Current_pattern == SONG_NRML_2 || Current_pattern == SONG_NRML_3 ) {
|
||||
if (timestamp_elapsed(Check_for_battle_music)) {
|
||||
Check_for_battle_music = timestamp(1000);
|
||||
Check_for_battle_music = _timestamp(1 * MILLISECONDS_PER_SECOND);
|
||||
if (hostile_ships_present() == TRUE) {
|
||||
Patterns[Current_pattern].next_pattern = SONG_BTTL_1;
|
||||
Patterns[Current_pattern].force_pattern = TRUE;
|
||||
@@ -465,7 +466,7 @@ void event_music_do_frame()
|
||||
}
|
||||
} else if (Current_pattern == SONG_BTTL_1 || Current_pattern == SONG_BTTL_2 || Current_pattern == SONG_BTTL_3) {
|
||||
if (timestamp_elapsed(Battle_over_timestamp)) {
|
||||
Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
|
||||
Battle_over_timestamp = _timestamp(BATTLE_CHECK_INTERVAL);
|
||||
if (hostile_ships_present() == FALSE) {
|
||||
Patterns[Current_pattern].force_pattern = TRUE;
|
||||
|
||||
@@ -501,11 +502,11 @@ void event_music_do_frame()
|
||||
|
||||
if ( !Victory2_music_played ) {
|
||||
if ( timestamp_elapsed(Mission_over_timestamp) ) {
|
||||
Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
|
||||
Mission_over_timestamp = _timestamp(BATTLE_CHECK_INTERVAL);
|
||||
if ( mission_goals_met() && (!hostile_ships_present()) ) {
|
||||
Patterns[Current_pattern].next_pattern = SONG_VICT_2;
|
||||
Patterns[Current_pattern].force_pattern = TRUE;
|
||||
Victory2_music_played = 1;
|
||||
Victory2_music_played = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -596,11 +597,11 @@ void event_music_level_start(int force_soundtrack)
|
||||
|
||||
Num_enemy_arrivals = 0;
|
||||
Num_friendly_arrivals = 0;
|
||||
Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
|
||||
Mission_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
|
||||
Next_arrival_timestamp = timestamp(1);
|
||||
Victory2_music_played = 0;
|
||||
Check_for_battle_music = 0;
|
||||
Battle_over_timestamp = _timestamp(BATTLE_CHECK_INTERVAL);
|
||||
Mission_over_timestamp = _timestamp(BATTLE_CHECK_INTERVAL);
|
||||
Next_arrival_timestamp = TIMESTAMP::immediate();
|
||||
Victory2_music_played = false;
|
||||
Check_for_battle_music = TIMESTAMP::invalid(); // this should probably be immediate; we might introduce a flag later
|
||||
|
||||
if (Event_music_level_inited)
|
||||
{
|
||||
@@ -642,9 +643,9 @@ void event_music_first_pattern()
|
||||
|
||||
// if we really are initializing the level
|
||||
if (Missiontime == 0) {
|
||||
Pattern_timer_id = timestamp(-1); // don't let this start quite yet; see event_music_set_start_delay()
|
||||
Pattern_timer_id = TIMESTAMP::invalid(); // don't let this start quite yet; see event_music_set_start_delay()
|
||||
} else {
|
||||
Pattern_timer_id = timestamp(0); // start immediately
|
||||
Pattern_timer_id = TIMESTAMP::immediate(); // start immediately
|
||||
}
|
||||
|
||||
Event_music_begun = FALSE;
|
||||
@@ -672,7 +673,7 @@ void event_music_set_start_delay()
|
||||
return;
|
||||
}
|
||||
|
||||
Pattern_timer_id = timestamp(1000);
|
||||
Pattern_timer_id = _timestamp(1 * MILLISECONDS_PER_SECOND);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
@@ -752,7 +753,7 @@ int event_music_battle_start()
|
||||
}
|
||||
|
||||
Event_Music_battle_started = 1; // keep track of this state though, need on restore
|
||||
Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
|
||||
Battle_over_timestamp = _timestamp(BATTLE_CHECK_INTERVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -847,7 +848,7 @@ int event_music_enemy_arrival()
|
||||
Patterns[Current_pattern].force_pattern = TRUE;
|
||||
}
|
||||
|
||||
Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
|
||||
Battle_over_timestamp = _timestamp(BATTLE_CHECK_INTERVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -934,9 +935,9 @@ int event_music_friendly_arrival()
|
||||
}
|
||||
}
|
||||
|
||||
Next_arrival_timestamp = timestamp(ARRIVAL_INTERVAL_TIMESTAMP);
|
||||
Next_arrival_timestamp = _timestamp(ARRIVAL_INTERVAL_TIMESTAMP);
|
||||
|
||||
Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
|
||||
Battle_over_timestamp = _timestamp(BATTLE_CHECK_INTERVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1031,10 +1032,10 @@ int event_music_primary_goals_met()
|
||||
|
||||
// If the mission goals aren't met (or there are no goals), or if victory 2 music has already played, then go
|
||||
// to the next default track
|
||||
if ( !mission_goals_met() || Victory2_music_played || (Num_goals == 0)) {
|
||||
if ( !mission_goals_met() || Victory2_music_played || Mission_goals.empty()) {
|
||||
Patterns[next_pattern].next_pattern = Patterns[next_pattern].default_next_pattern;
|
||||
} else {
|
||||
Victory2_music_played = 1;
|
||||
Victory2_music_played = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1474,7 +1475,7 @@ void event_music_enable()
|
||||
else {
|
||||
// start a new pattern
|
||||
Event_music_begun = FALSE;
|
||||
Pattern_timer_id = timestamp(150);
|
||||
Pattern_timer_id = _timestamp(150);
|
||||
event_music_start_default();
|
||||
}
|
||||
}
|
||||
@@ -1539,6 +1540,8 @@ int hostile_ships_present()
|
||||
|
||||
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) )
|
||||
{
|
||||
if (Objects[so->objnum].flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
shipp = &Ships[Objects[so->objnum].instance];
|
||||
|
||||
// skip ourselves
|
||||
@@ -1684,7 +1687,7 @@ int event_music_get_spooled_music_index(const char *name)
|
||||
int event_music_get_spooled_music_index(const SCP_string& name)
|
||||
{
|
||||
return event_music_get_spooled_music_index(name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// set a score based on name
|
||||
void event_music_set_score(int score_index, const char *name)
|
||||
@@ -1702,9 +1705,9 @@ void event_music_reset_choices()
|
||||
mprintf(("Current soundtrack set to -1 in event_music_reset_choices\n"));
|
||||
Mission_music[SCORE_BRIEFING] = -1;
|
||||
Mission_music[SCORE_FICTION_VIEWER] = -1;
|
||||
event_music_set_score(SCORE_DEBRIEF_SUCCESS, "Success");
|
||||
event_music_set_score(SCORE_DEBRIEF_AVERAGE, "Average");
|
||||
event_music_set_score(SCORE_DEBRIEF_FAIL, "Failure");
|
||||
event_music_set_score(SCORE_DEBRIEFING_SUCCESS, "Success");
|
||||
event_music_set_score(SCORE_DEBRIEFING_AVERAGE, "Average");
|
||||
event_music_set_score(SCORE_DEBRIEFING_FAILURE, "Failure");
|
||||
|
||||
// Goober5000
|
||||
strcpy_s(The_mission.substitute_briefing_music_name, "None");
|
||||
@@ -1713,7 +1716,7 @@ void event_music_reset_choices()
|
||||
|
||||
void event_music_hostile_ship_destroyed()
|
||||
{
|
||||
Battle_over_timestamp = timestamp(BATTLE_CHECK_INTERVAL);
|
||||
Battle_over_timestamp = _timestamp(BATTLE_CHECK_INTERVAL);
|
||||
}
|
||||
|
||||
void event_music_set_volume(float volume)
|
||||
|
||||
@@ -50,9 +50,9 @@ extern float Master_event_music_volume; // range is 0->1
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#define NUM_SCORES 5
|
||||
#define SCORE_BRIEFING 0
|
||||
#define SCORE_DEBRIEF_SUCCESS 1
|
||||
#define SCORE_DEBRIEF_AVERAGE 2
|
||||
#define SCORE_DEBRIEF_FAIL 3
|
||||
#define SCORE_DEBRIEFING_SUCCESS 1
|
||||
#define SCORE_DEBRIEFING_AVERAGE 2
|
||||
#define SCORE_DEBRIEFING_FAILURE 3
|
||||
#define SCORE_FICTION_VIEWER 4
|
||||
extern int Mission_music[NUM_SCORES]; // indicies into Spooled_music[]
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+15
-17
@@ -642,6 +642,9 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
|
||||
stuff_string(entry.filename, F_NAME, MAX_FILENAME_LEN, ",");
|
||||
|
||||
// since we have a new filename, first assume it's valid
|
||||
gs->flags &= ~GAME_SND_NOT_VALID;
|
||||
|
||||
if (!stricmp(entry.filename, NOX("empty")) || !stricmp(entry.filename, NOX("none")))
|
||||
{
|
||||
entry.filename[0] = 0;
|
||||
@@ -684,7 +687,7 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
{
|
||||
if (stuff_int_optional(&temp_max) == 2)
|
||||
{
|
||||
mprintf(("Dutifully converting retail sound %s, '%s' to a 3D sound...\n", gs->name.c_str(), entry.filename));
|
||||
nprintf(("Sound","Dutifully converting retail sound %s, '%s' to a 3D sound...\n", gs->name.c_str(), entry.filename));
|
||||
is_3d = 1;
|
||||
|
||||
gs->flags |= GAME_SND_USE_DS3D;
|
||||
@@ -854,12 +857,15 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
entry = &gs->sound_entries.back();
|
||||
}
|
||||
|
||||
// Default pitch is 1.0. This is set here in case we don't have a valid file name
|
||||
gs->pitch_range = util::UniformFloatRange(1.0f);
|
||||
|
||||
char name[MAX_FILENAME_LEN];
|
||||
// New extended format found
|
||||
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
// Default pitch is 1.0. This is set here in case we don't have a valid file name
|
||||
gs->pitch_range = util::UniformFloatRange(1.0f);
|
||||
// since we have a new filename, first assume it's valid
|
||||
gs->flags &= ~GAME_SND_NOT_VALID;
|
||||
|
||||
if (!stricmp(name, NOX("empty")) || !stricmp(name, NOX("none")))
|
||||
{
|
||||
@@ -1183,8 +1189,6 @@ void parse_sound_environments()
|
||||
required_string("#Sound Environments End");
|
||||
}
|
||||
|
||||
static SCP_vector<species_info> missingFlybySounds;
|
||||
|
||||
void parse_sound_table(const char* filename)
|
||||
{
|
||||
try
|
||||
@@ -1285,20 +1289,14 @@ void gamesnd_parse_soundstbl()
|
||||
|
||||
parse_modular_table("*-snd.tbm", parse_sound_table);
|
||||
|
||||
// if we are missing any species then report
|
||||
if (!missingFlybySounds.empty())
|
||||
{
|
||||
SCP_string errorString;
|
||||
for (size_t i = 0; i < missingFlybySounds.size(); i++)
|
||||
{
|
||||
errorString.append(missingFlybySounds[i].species_name);
|
||||
errorString.append("\n");
|
||||
//Set any flyby sounds for species that use the borrowed feature
|
||||
for (size_t i = 0; i < Species_info.size(); i++) {
|
||||
if (Species_info[i].borrows_flyby_sounds_species >= 0) {
|
||||
int idx = Species_info[i].borrows_flyby_sounds_species;
|
||||
Species_info[i].snd_flyby_fighter = Species_info[idx].snd_flyby_fighter;
|
||||
Species_info[i].snd_flyby_bomber = Species_info[idx].snd_flyby_bomber;
|
||||
}
|
||||
|
||||
Error(LOCATION, "The following species are missing flyby sounds in sounds.tbl:\n%s", errorString.c_str());
|
||||
}
|
||||
|
||||
missingFlybySounds.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "osapi/dialogs.h"
|
||||
|
||||
constexpr size_t UBYTE_SIZE = 8;
|
||||
|
||||
template<typename TEnum, size_t SIZE>
|
||||
struct flag_combinator;
|
||||
|
||||
@@ -114,6 +116,61 @@ class flagset {
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t to_ubyte_vector(SCP_vector<ubyte>& vector_out)
|
||||
{
|
||||
int counter = 0; // a counter to determine how far to bitshift
|
||||
ubyte ubyte_out= 0; // the holder for our bitshifted flags
|
||||
|
||||
for (size_t i = 0; i < SIZE; i++) {
|
||||
|
||||
// this needs to be at the beginning for push_back after the loop
|
||||
// to work properly.
|
||||
if (counter == UBYTE_SIZE) {
|
||||
vector_out.push_back(ubyte_out);
|
||||
counter = 0;
|
||||
ubyte_out = 0;
|
||||
}
|
||||
|
||||
// check whether that flag was set
|
||||
// there is probably a more efficient way to do this,
|
||||
// but not unless we can copy the underlying data safely.
|
||||
if (values[i]) {
|
||||
ubyte_out |= 1 << counter;
|
||||
}
|
||||
|
||||
// iterate
|
||||
++counter;
|
||||
}
|
||||
|
||||
vector_out.push_back(ubyte_out);
|
||||
|
||||
return vector_out.size();
|
||||
}
|
||||
|
||||
void set_from_vector(const SCP_vector<ubyte>& vector_in)
|
||||
{
|
||||
size_t flag = 0;
|
||||
|
||||
// just iterate through the entries, and set flags as appropriate.
|
||||
for (auto& entry : vector_in) {
|
||||
|
||||
for (uint bitshift = 0; bitshift < UBYTE_SIZE; bitshift++){
|
||||
if (entry & (1 << bitshift)) {
|
||||
values.set(flag, true);
|
||||
}
|
||||
|
||||
++flag;
|
||||
|
||||
// this function is used in multi where the size of flagsets can be different
|
||||
// on server and client. Small differences in flagset sizes should not affect
|
||||
// gameplay, but we have to make sure not to exceed the size of the flagset.
|
||||
if (flag >= SIZE){
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flagset<T>& toggle(T idx) {
|
||||
values[static_cast < size_t >(idx)] = !values[static_cast < size_t >(idx)];
|
||||
|
||||
@@ -124,6 +181,7 @@ class flagset {
|
||||
bool none_set() { return values.none(); }
|
||||
|
||||
void from_u64(std::uint64_t num) { values = (unsigned long) num; }
|
||||
|
||||
std::uint64_t to_u64() const { return (std::uint64_t) values.to_ulong(); }
|
||||
|
||||
size_t hash() const { return std::hash<std::bitset<SIZE>>()(values); }
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
#define SHORT_CALLSIGN_PIXEL_W 80 // max width of short_callsign[] in pixels
|
||||
|
||||
// from ship.h
|
||||
#define MAX_SHIPS 400 // max number of ship instances there can be.DTP; bumped from 200 to 400
|
||||
#define SHIPS_LIMIT 400 // what MAX_SHIPS will be at release time (for error checking in debug mode); dtp Bumped from 200 to 400
|
||||
#define MAX_SHIPS 500 // max number of ship instances there can be.DTP; bumped from 200 to 400, then to 500 in 2022
|
||||
#define SHIPS_LIMIT 500 // what MAX_SHIPS will be at release time (for error checking in debug mode); dtp Bumped from 200 to 400, then to 500 in 2022
|
||||
|
||||
// from missionparse.h and then redefined to the same value in sexp.h
|
||||
#define TOKEN_LENGTH 32
|
||||
@@ -61,7 +61,7 @@
|
||||
#define MAX_COMPLETE_ESCORT_LIST 20
|
||||
|
||||
// from weapon.h
|
||||
#define MAX_WEAPONS 2000
|
||||
#define MAX_WEAPONS 3000 //Increased from 2000 to 3000 in 2022
|
||||
|
||||
#define MAX_WEAPON_TYPES 500
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
#define MAX_POLYGON_MODELS 300
|
||||
|
||||
// object.h
|
||||
#define MAX_OBJECTS 3500
|
||||
#define MAX_OBJECTS 5000 //Increased from 3500 to 5000 in 2022
|
||||
|
||||
// from weapon.h (and beam.h)
|
||||
#define MAX_BEAM_SECTIONS 5
|
||||
|
||||
@@ -46,3 +46,18 @@ inline void *vm_realloc(void *ptr, size_t size)
|
||||
|
||||
return ret_ptr;
|
||||
}
|
||||
|
||||
// For use with unique_ptr
|
||||
template <typename T>
|
||||
struct VmFreeDeleter
|
||||
{
|
||||
void operator()(T* const p) const
|
||||
{
|
||||
vm_free(p);
|
||||
}
|
||||
};
|
||||
|
||||
// Managed unique pointer for data allocated using vm_malloc. Never use with data allocated with new or malloc;
|
||||
// allocation and deallocation must always be performed using matching operations.
|
||||
template<typename T>
|
||||
using SCP_vm_unique_ptr = std::unique_ptr<T, VmFreeDeleter<T>>;
|
||||
+40
-14
@@ -17,6 +17,7 @@
|
||||
#include "windows_stub/config.h"
|
||||
#include "globalincs/scp_defines.h"
|
||||
#include "globalincs/toolchain.h"
|
||||
#include "globalincs/vmallocator.h"
|
||||
#include "utils/strings.h"
|
||||
|
||||
#include <cstdio> // For NULL, etc
|
||||
@@ -25,6 +26,7 @@
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
// value to represent an uninitialized state in any int or uint
|
||||
#define UNINITIALIZED 0x7f8e6d9c
|
||||
@@ -209,6 +211,7 @@ struct flag_def_list {
|
||||
ubyte var;
|
||||
};
|
||||
|
||||
//A list of parse names for a flag enum
|
||||
template<class T>
|
||||
struct flag_def_list_new {
|
||||
const char* name; // The parseable representation of this flag
|
||||
@@ -217,6 +220,17 @@ struct flag_def_list_new {
|
||||
bool is_special; // Whether this flag requires special processing. See parse_string_flag_list<T, T> for details
|
||||
};
|
||||
|
||||
//A list of parse names for a flag enum. Instead of specifying whether an argument needs special handling,
|
||||
//a functor can passed that is called to handle an argument proceeding the flag. If used with parse_string_flag_list_special,
|
||||
//these will automatically be called when a special argument is encountered
|
||||
template<class T, typename... additional_args>
|
||||
struct special_flag_def_list_new : public flag_def_list_new<T> {
|
||||
std::function<void(const SCP_string&, additional_args...)> parse_special;
|
||||
|
||||
special_flag_def_list_new(const char* name, T flag, bool in_use) : flag_def_list_new<T>{ name, flag, in_use, false } {}
|
||||
special_flag_def_list_new(const char* name, T flag, bool in_use, const decltype(parse_special)& parseSpecial) : flag_def_list_new<T>{ name, flag, in_use, true }, parse_special(parseSpecial) { }
|
||||
};
|
||||
|
||||
// weapon count list (mainly for pilot files)
|
||||
typedef struct wep_t {
|
||||
int index;
|
||||
@@ -468,25 +482,37 @@ SCP_string dump_stacktrace();
|
||||
const auto ptr_memset = std::memset;
|
||||
#define memset memset_if_trivial_else_error
|
||||
|
||||
// Forward declarations from libraries
|
||||
struct ImDrawListSplitter;
|
||||
|
||||
// Put into std to be compatible with code that uses std::mem*
|
||||
namespace std
|
||||
{
|
||||
template<typename T>
|
||||
using trivial_check = std::is_trivially_copyable<T>;
|
||||
template <typename T>
|
||||
using trivial_check = std::is_trivially_copyable<T>;
|
||||
|
||||
template<typename T>
|
||||
void *memset_if_trivial_else_error(T *memset_data, int ch, size_t count)
|
||||
{
|
||||
static_assert(trivial_check<T>::value, "memset on non-trivial object");
|
||||
return ptr_memset(memset_data, ch, count);
|
||||
}
|
||||
template <typename T>
|
||||
void* memset_if_trivial_else_error(
|
||||
typename std::enable_if<!std::is_same<T, ImDrawListSplitter>::value, T>::type* memset_data,
|
||||
int ch,
|
||||
size_t count)
|
||||
{
|
||||
static_assert(trivial_check<T>::value, "memset on non-trivial object");
|
||||
return ptr_memset(memset_data, ch, count);
|
||||
}
|
||||
|
||||
// assume memset on a void* is "safe"
|
||||
// only used in cutscene/mveplayer.cpp:mve_video_createbuf()
|
||||
inline void *memset_if_trivial_else_error(void *memset_data, int ch, size_t count)
|
||||
{
|
||||
return ptr_memset(memset_data, ch, count);
|
||||
}
|
||||
// assume memset on a void* is "safe"
|
||||
// only used in cutscene/mveplayer.cpp:mve_video_createbuf()
|
||||
inline void* memset_if_trivial_else_error(void* memset_data, int ch, size_t count)
|
||||
{
|
||||
return ptr_memset(memset_data, ch, count);
|
||||
}
|
||||
|
||||
// Dear ImGui triggers these as well, so we need to let them pass
|
||||
inline void* memset_if_trivial_else_error(ImDrawListSplitter* memset_data, int ch, size_t count)
|
||||
{
|
||||
return ptr_memset(memset_data, ch, count);
|
||||
}
|
||||
|
||||
// MEMCPY!
|
||||
const auto ptr_memcpy = std::memcpy;
|
||||
|
||||
@@ -61,6 +61,51 @@ errno_t scp_strcpy_s( const char* file, int line, char* strDest, size_t sizeInBy
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno_t scp_strncpy_s(const char* file, int line, char* strDest, size_t sizeInBytes, const char* strSource, size_t inputSizeInBytes) {
|
||||
char* pDest;
|
||||
const char* pSource;
|
||||
size_t bufferLeft = sizeInBytes;
|
||||
|
||||
if (!strDest || !strSource)
|
||||
{
|
||||
if (strDest)
|
||||
*strDest = '\0';
|
||||
__safe_strings_error_handler(EINVAL);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (sizeInBytes == 0)
|
||||
{
|
||||
*strDest = '\0';
|
||||
__safe_strings_error_handler(ERANGE);
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
if (inputSizeInBytes == 0)
|
||||
{
|
||||
*strDest = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
pDest = strDest;
|
||||
pSource = strSource;
|
||||
|
||||
while ((*pDest++ = *pSource++) != 0 && (--inputSizeInBytes > 0) && --bufferLeft > 0);
|
||||
|
||||
if (bufferLeft == 0 || (inputSizeInBytes == 0 && bufferLeft <= 1))
|
||||
{
|
||||
*strDest = '\0';
|
||||
__safe_strings_error_handler(ERANGE);
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
if (inputSizeInBytes == 0) {
|
||||
*pDest = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno_t scp_strcat_s( const char* file, int line, char* strDest, size_t sizeInBytes, const char* strSource )
|
||||
{
|
||||
char* pDest;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
/* errno_t, EINVAL, ERANGE, etc.. */
|
||||
#include <cerrno>
|
||||
#include <cstdlib> /* size_t */
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
/* Because errno_t is not (yet) standard, we define it here like this */
|
||||
typedef int errno_t;
|
||||
@@ -48,6 +49,7 @@ typedef int errno_t;
|
||||
#endif
|
||||
|
||||
extern errno_t scp_strcpy_s( const char* file, int line, char* strDest, size_t sizeInBytes, const char* strSource );
|
||||
extern errno_t scp_strncpy_s( const char* file, int line, char* strDest, size_t sizeInBytes, const char* strSource, size_t inputSizeInBytes );
|
||||
extern errno_t scp_strcat_s( const char* file, int line, char* strDest, size_t sizeInBytes, const char* strSource );
|
||||
|
||||
template< size_t size>
|
||||
@@ -57,6 +59,13 @@ errno_t scp_strcpy_s( const char* file, int line, char (&strDest)[ size ], const
|
||||
return scp_strcpy_s( file, line, strDest, size, strSource );
|
||||
}
|
||||
|
||||
template< size_t size>
|
||||
inline
|
||||
errno_t scp_strncpy_s(const char* file, int line, char(&strDest)[size], const char* strSource, size_t count)
|
||||
{
|
||||
return scp_strncpy_s(file, line, strDest, size, strSource, count);
|
||||
}
|
||||
|
||||
template< size_t size >
|
||||
inline
|
||||
errno_t scp_strcat_s( const char* file, int line, char (&strDest)[ size ], const char* strSource )
|
||||
@@ -65,6 +74,7 @@ errno_t scp_strcat_s( const char* file, int line, char (&strDest)[ size ], const
|
||||
}
|
||||
|
||||
#define strcpy_s( ... ) scp_strcpy_s( __FILE__, __LINE__, __VA_ARGS__ )
|
||||
#define strncpy_s( ... ) scp_strncpy_s( __FILE__, __LINE__, __VA_ARGS__ )
|
||||
#define strcat_s( ... ) scp_strcat_s( __FILE__, __LINE__, __VA_ARGS__ )
|
||||
|
||||
#elif defined(_MSC_VER) && _MSC_VER < 1400 || defined(NO_SAFE_STRINGS)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "options/Option.h"
|
||||
|
||||
fix Missiontime;
|
||||
fix Skybox_timestamp;
|
||||
fix Frametime;
|
||||
int Framecount=0;
|
||||
|
||||
@@ -66,29 +65,13 @@ char Processing_filename[MAX_PATH_LEN];
|
||||
#endif
|
||||
|
||||
// override states to skip rendering of certain elements, but without disabling them completely
|
||||
bool Basemap_override = false;
|
||||
bool Envmap_override = false;
|
||||
bool Specmap_override = false;
|
||||
bool Normalmap_override = false;
|
||||
bool Heightmap_override = false;
|
||||
bool Glowpoint_override = false;
|
||||
bool Glowpoint_use_depth_buffer = true;
|
||||
bool PostProcessing_override = false;
|
||||
bool Shadow_override = false;
|
||||
bool Trail_render_override = false;
|
||||
|
||||
bool Basemap_color_override_set = false;
|
||||
float Basemap_color_override[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
||||
bool Glowmap_color_override_set = false;
|
||||
float Glowmap_color_override[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
bool Specmap_color_override_set = false;
|
||||
float Specmap_color_override[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
bool Gloss_override_set = false;
|
||||
float Gloss_override = 0.0f;
|
||||
|
||||
// Values used for noise for thruster animations
|
||||
float Noise[NOISE_NUM_FRAMES] = {
|
||||
0.468225f,
|
||||
|
||||
@@ -85,7 +85,6 @@ typedef struct vci {
|
||||
} vci;
|
||||
|
||||
extern fix Missiontime;
|
||||
extern fix Skybox_timestamp;
|
||||
extern fix Frametime;
|
||||
extern int Framecount;
|
||||
|
||||
@@ -138,31 +137,14 @@ extern float Noise[NOISE_NUM_FRAMES];
|
||||
|
||||
|
||||
// override states to skip rendering of certain elements, but without disabling them completely
|
||||
extern bool Basemap_override;
|
||||
extern bool Envmap_override;
|
||||
extern bool Specmap_override;
|
||||
extern bool Normalmap_override;
|
||||
extern bool Heightmap_override;
|
||||
extern bool Glowpoint_override;
|
||||
extern bool Glowpoint_use_depth_buffer;
|
||||
extern bool GLSL_override;
|
||||
extern bool PostProcessing_override;
|
||||
extern bool Shadow_override;
|
||||
extern bool Trail_render_override;
|
||||
|
||||
extern bool Basemap_color_override_set;
|
||||
extern float Basemap_color_override[4];
|
||||
|
||||
extern bool Glowmap_color_override_set;
|
||||
extern float Glowmap_color_override[3];
|
||||
|
||||
extern bool Specmap_color_override_set;
|
||||
extern float Specmap_color_override[3];
|
||||
|
||||
extern bool Gloss_override_set;
|
||||
extern float Gloss_override;
|
||||
|
||||
// game skill levels
|
||||
// game skill levels
|
||||
#define NUM_SKILL_LEVELS 5
|
||||
|
||||
//====================================================================================
|
||||
@@ -216,8 +198,8 @@ int current_detail_level();
|
||||
// A sort for use with small or almost-sorted lists. Iteration time is O(n) for a fully-sorted list.
|
||||
// This uses a type-safe version of the function prototype for stdlib's qsort, although the size is an int rather than a size_t (for the reasons that j is an int).
|
||||
// The fncompare function should return <0, 0, or >0 as the left item is less than, equal to, or greater than the right item.
|
||||
template <typename T>
|
||||
void insertion_sort(T* array_base, int array_size, int (*fncompare)(const T*, const T*))
|
||||
template <typename array_t, typename T>
|
||||
void insertion_sort(array_t& array_base, int array_size, int (*fncompare)(const T*, const T*))
|
||||
{
|
||||
// NOTE: j *must* be a signed type because j reaches -1 and j+1 must be 0.
|
||||
int i, j;
|
||||
@@ -225,7 +207,7 @@ void insertion_sort(T* array_base, int array_size, int (*fncompare)(const T*, co
|
||||
|
||||
// allocate space for the element being moved
|
||||
// (Taylor says that for optimization purposes malloc/free should be used rather than vm_malloc/vm_free here)
|
||||
current_buf = (T*)malloc(sizeof(T));
|
||||
current_buf = new T();
|
||||
if (current_buf == nullptr)
|
||||
{
|
||||
UNREACHABLE("Malloc failed!");
|
||||
@@ -264,7 +246,7 @@ void insertion_sort(T* array_base, int array_size, int (*fncompare)(const T*, co
|
||||
}
|
||||
|
||||
// free the allocated space
|
||||
free(current_buf);
|
||||
delete current_buf;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -48,6 +48,43 @@ 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;
|
||||
}
|
||||
version get_executable_version() {
|
||||
version v;
|
||||
v.major = FS_VERSION_MAJOR;
|
||||
|
||||
@@ -68,6 +68,7 @@ struct version {
|
||||
};
|
||||
|
||||
version parse_version();
|
||||
version parse_version_inline();
|
||||
|
||||
version get_executable_version();
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#ifndef _VMALLOCATOR_H_INCLUDED_
|
||||
#define _VMALLOCATOR_H_INCLUDED_
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <locale>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
@@ -14,24 +17,24 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
template< typename T >
|
||||
using SCP_vector = std::vector< T, std::allocator< T > >;
|
||||
template <typename T>
|
||||
using SCP_vector = std::vector<T, std::allocator<T>>;
|
||||
|
||||
template< typename T >
|
||||
template <typename T>
|
||||
bool SCP_vector_contains(SCP_vector<T>& vector, T item) {
|
||||
return std::find(vector.begin(), vector.end(), item) != vector.end();
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
using SCP_list = std::list< T, std::allocator< T > >;
|
||||
template <typename T>
|
||||
using SCP_list = std::list<T, std::allocator<T>>;
|
||||
|
||||
|
||||
extern std::locale SCP_default_locale;
|
||||
|
||||
template< class charT >
|
||||
template <class charT>
|
||||
charT SCP_toupper(charT ch) { return std::toupper(ch, SCP_default_locale); }
|
||||
|
||||
template< class charT >
|
||||
template <class charT>
|
||||
charT SCP_tolower(charT ch) { return std::tolower(ch, SCP_default_locale); }
|
||||
|
||||
typedef std::basic_string<char, std::char_traits<char>, std::allocator<char> > SCP_string;
|
||||
@@ -46,24 +49,36 @@ inline void SCP_toupper(SCP_string &str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](char c) { return SCP_toupper(c); });
|
||||
}
|
||||
|
||||
inline bool SCP_truncate(SCP_string &str, size_t c_str_size) {
|
||||
if (str.length() >= c_str_size) {
|
||||
str.resize(c_str_size - 1);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extern void SCP_tolower(char *str);
|
||||
extern void SCP_toupper(char *str);
|
||||
|
||||
|
||||
template< typename T, typename U >
|
||||
using SCP_map = std::map<T, U, std::less<T>, std::allocator<std::pair<const T, U> > >;
|
||||
template <typename T, typename U>
|
||||
using SCP_map = std::map<T, U, std::less<T>, std::allocator<std::pair<const T, U>>>;
|
||||
|
||||
template< typename T, typename U >
|
||||
using SCP_multimap = std::multimap<T, U, std::less<T>, std::allocator<std::pair<const T, U> > >;
|
||||
template <typename T, typename U>
|
||||
using SCP_multimap = std::multimap<T, U, std::less<T>, std::allocator<std::pair<const T, U>>>;
|
||||
|
||||
template< typename T >
|
||||
using SCP_queue = std::queue< T, std::deque< T, std::allocator< T > > >;
|
||||
template <typename T>
|
||||
using SCP_queue = std::queue<T, std::deque<T, std::allocator<T>>>;
|
||||
|
||||
template< typename T >
|
||||
using SCP_deque = std::deque< T, std::allocator< T > >;
|
||||
template <typename T>
|
||||
using SCP_deque = std::deque<T, std::allocator<T>>;
|
||||
|
||||
template <typename T>
|
||||
using SCP_set = std::set<T, std::less<T>, std::allocator<T>>;
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
template <class T, bool>
|
||||
template<class T, bool>
|
||||
struct enum_hasher_util {
|
||||
inline size_t operator()(const T& elem) { return std::hash<T>()(elem); }
|
||||
};
|
||||
@@ -155,4 +170,22 @@ using SCP_unordered_map = std::unordered_map<Key, T, Hash, KeyEqual, std::alloca
|
||||
template <typename Key, typename Hash = SCP_hash<Key>, typename KeyEqual = std::equal_to<Key>>
|
||||
using SCP_unordered_set = std::unordered_set<Key, Hash, KeyEqual, std::allocator<Key>>;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type make_unique(Args&&... args) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type make_unique(std::size_t n) {
|
||||
return std::unique_ptr<T>(new typename std::remove_extent<T>::type[n]());
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::shared_ptr<T>>::type make_shared(Args&&... args) {
|
||||
return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
typename std::enable_if<std::is_array<T>::value, std::shared_ptr<T>>::type make_shared(std::size_t n) {
|
||||
return std::shared_ptr<T>(new typename std::remove_extent<T>::type[n]());
|
||||
}
|
||||
|
||||
#endif // _VMALLOCATOR_H_INCLUDED_
|
||||
+6
-23
@@ -78,8 +78,6 @@ io::mouse::Cursor* Web_cursor = NULL;
|
||||
|
||||
int Gr_inited = 0;
|
||||
|
||||
uint Gr_signature = 0;
|
||||
|
||||
float Gr_gamma = 1.0f;
|
||||
|
||||
static SCP_vector<float> gamma_value_enumerator()
|
||||
@@ -175,7 +173,7 @@ static auto WindowModeOption = options::OptionBuilder<os::ViewportState>("Graphi
|
||||
.change_listener(mode_change_func)
|
||||
.finish();
|
||||
|
||||
const std::shared_ptr<scripting::OverridableHook> OnFrameHook = scripting::OverridableHook::Factory(
|
||||
const std::shared_ptr<scripting::OverridableHook<>> OnFrameHook = scripting::OverridableHook<>::Factory(
|
||||
"On Frame", "Called every frame as the last action before showing the frame result to the user.", {}, CHA_ONFRAME);
|
||||
|
||||
// z-buffer stuff
|
||||
@@ -432,7 +430,7 @@ bool gr_is_smaa_mode(AntiAliasMode mode) {
|
||||
bool Gr_post_processing_enabled = true;
|
||||
|
||||
static auto PostProcessOption =
|
||||
options::OptionBuilder<bool>("Graphis.PostProcessing", "Post processing",
|
||||
options::OptionBuilder<bool>("Graphics.PostProcessing", "Post processing",
|
||||
"Controls whether post processing is enabled in the engine")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
@@ -443,7 +441,7 @@ static auto PostProcessOption =
|
||||
|
||||
bool Gr_enable_vsync = true;
|
||||
|
||||
static auto VSyncOption = options::OptionBuilder<bool>("Graphis.VSync", "Vertical Sync",
|
||||
static auto VSyncOption = options::OptionBuilder<bool>("Graphics.VSync", "Vertical Sync",
|
||||
"Controls how the engine does vertical synchronization")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
@@ -1299,12 +1297,11 @@ static bool gr_init_sub(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, i
|
||||
Gr_save_menu_zoomed_offset_X = Gr_menu_zoomed_offset_X = Gr_menu_offset_X;
|
||||
Gr_save_menu_zoomed_offset_Y = Gr_menu_zoomed_offset_Y = Gr_menu_offset_Y;
|
||||
|
||||
|
||||
gr_screen.signature = Gr_signature++;
|
||||
gr_screen.bits_per_pixel = depth;
|
||||
gr_screen.bytes_per_pixel= depth / 8;
|
||||
gr_screen.rendering_to_texture = -1;
|
||||
gr_screen.envmap_render_target = -1;
|
||||
gr_screen.irrmap_render_target = -1;
|
||||
gr_screen.line_width = 1.0f;
|
||||
gr_screen.mode = mode;
|
||||
gr_screen.res = res;
|
||||
@@ -1552,7 +1549,8 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_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
|
||||
if ( !cf_exists_full("2_ChoosePilot-m.pcx", CF_TYPE_ANY)) {
|
||||
// Lafiel: BUT! Only do this if the "low res graphic" ACTUALLY exists. Using SCPUI, not having this file is not a sufficient indicator for being on forced low-res.
|
||||
if ( !cf_exists_full("2_ChoosePilot-m.pcx", CF_TYPE_ANY) && cf_exists_full("ChoosePilot-m.pcx", CF_TYPE_ANY)) {
|
||||
if ( (width == 1024) && (height == 768) ) {
|
||||
width = 640;
|
||||
height = 480;
|
||||
@@ -1736,7 +1734,6 @@ void gr_init_color(color *c, int r, int g, int b)
|
||||
CAP(g, 0, 255);
|
||||
CAP(b, 0, 255);
|
||||
|
||||
c->screen_sig = gr_screen.signature;
|
||||
c->red = (ubyte)r;
|
||||
c->green = (ubyte)g;
|
||||
c->blue = (ubyte)b;
|
||||
@@ -1774,21 +1771,12 @@ void gr_set_color( int r, int g, int b )
|
||||
|
||||
void gr_set_color_fast(color *dst)
|
||||
{
|
||||
if ( dst->screen_sig != gr_screen.signature ) {
|
||||
if (dst->is_alphacolor) {
|
||||
gr_init_alphacolor( dst, dst->red, dst->green, dst->blue, dst->alpha, dst->ac_type );
|
||||
} else {
|
||||
gr_init_color( dst, dst->red, dst->green, dst->blue );
|
||||
}
|
||||
}
|
||||
|
||||
gr_screen.current_color = *dst;
|
||||
}
|
||||
|
||||
// shader functions
|
||||
void gr_create_shader(shader *shade, ubyte r, ubyte g, ubyte b, ubyte c )
|
||||
{
|
||||
shade->screen_sig = gr_screen.signature;
|
||||
shade->r = r;
|
||||
shade->g = g;
|
||||
shade->b = b;
|
||||
@@ -1798,9 +1786,6 @@ void gr_create_shader(shader *shade, ubyte r, ubyte g, ubyte b, ubyte c )
|
||||
void gr_set_shader(shader *shade)
|
||||
{
|
||||
if (shade) {
|
||||
if (shade->screen_sig != gr_screen.signature) {
|
||||
gr_create_shader( shade, shade->r, shade->g, shade->b, shade->c );
|
||||
}
|
||||
gr_screen.current_shader = *shade;
|
||||
} else {
|
||||
gr_create_shader( &gr_screen.current_shader, 0, 0, 0, 0 );
|
||||
@@ -2560,8 +2545,6 @@ void gr_flip(bool execute_scripting)
|
||||
if (OnFrameHook->isActive()) {
|
||||
OnFrameHook->run();
|
||||
}
|
||||
// WMC - Do scripting reset stuff
|
||||
Script_system.EndFrame();
|
||||
}
|
||||
|
||||
gr_reset_immediate_buffer();
|
||||
|
||||
+16
-7
@@ -30,6 +30,7 @@ class GPUMemoryHeap;
|
||||
} // namespace util
|
||||
} // namespace graphics
|
||||
namespace scripting {
|
||||
template<typename condition_t>
|
||||
class OverridableHook;
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ extern bool High_dynamic_range;
|
||||
|
||||
extern os::ViewportState Gr_configured_window_state;
|
||||
|
||||
extern const std::shared_ptr<scripting::OverridableHook> OnFrameHook;
|
||||
extern const std::shared_ptr<scripting::OverridableHook<void>> OnFrameHook;
|
||||
|
||||
class material;
|
||||
class model_material;
|
||||
@@ -206,6 +207,8 @@ enum shader_type {
|
||||
|
||||
SDR_TYPE_ENVMAP_SPHERE_WARP,
|
||||
|
||||
SDR_TYPE_IRRADIANCE_MAP_GEN,
|
||||
|
||||
NUM_SHADER_TYPES
|
||||
};
|
||||
|
||||
@@ -230,7 +233,7 @@ enum shader_type {
|
||||
#define SDR_FLAG_MODEL_CLIP (1<<17)
|
||||
#define SDR_FLAG_MODEL_HDR (1<<18)
|
||||
#define SDR_FLAG_MODEL_AMBIENT_MAP (1<<19)
|
||||
#define SDR_FLAG_MODEL_NORMAL_ALPHA (1<<20)
|
||||
#define SDR_FLAG_MODEL_UNUSED20 (1<<20)
|
||||
#define SDR_FLAG_MODEL_THICK_OUTLINES (1<<21) // Renders the model geometry as an outline with configurable line width
|
||||
#define SDR_FLAG_MODEL_ALPHA_MULT (1<<22)
|
||||
|
||||
@@ -251,7 +254,8 @@ enum class uniform_block_type {
|
||||
DecalGlobals = 4,
|
||||
DeferredGlobals = 5,
|
||||
Matrices = 6,
|
||||
GenericData = 7,
|
||||
MovieData = 7,
|
||||
GenericData = 8,
|
||||
|
||||
NUM_BLOCK_TYPES
|
||||
};
|
||||
@@ -356,7 +360,6 @@ extern int gr_stencil_mode;
|
||||
* of the values you want to use in the shade primitive.
|
||||
*/
|
||||
typedef struct shader {
|
||||
uint screen_sig; // current mode this is in
|
||||
ubyte r, g, b, c; // factors and constant
|
||||
ubyte lookup[256];
|
||||
} shader;
|
||||
@@ -369,7 +372,6 @@ typedef struct shader {
|
||||
// If you need to get the rgb values of a "color" struct call
|
||||
// gr_get_colors after calling gr_set_colors_fast.
|
||||
typedef struct color {
|
||||
uint screen_sig;
|
||||
int is_alphacolor;
|
||||
int alphacolor;
|
||||
int magic;
|
||||
@@ -650,7 +652,6 @@ enum class BufferUsageHint { Static, Dynamic, Streaming, PersistentMapping };
|
||||
typedef void* gr_sync;
|
||||
|
||||
typedef struct screen {
|
||||
uint signature = 0; // changes when mode or palette or width or height changes
|
||||
int max_w = 0, max_h = 0; // Width and height
|
||||
int max_w_unscaled = 0, max_h_unscaled = 0;
|
||||
int max_w_unscaled_zoomed = 0, max_h_unscaled_zoomed = 0;
|
||||
@@ -697,6 +698,7 @@ typedef struct screen {
|
||||
int rendering_to_face = 0; // wich face of the texture we are rendering to, -1 if the back buffer
|
||||
|
||||
int envmap_render_target = 0;
|
||||
int irrmap_render_target = -1; // Irradiance map for diffuse env lighting.
|
||||
|
||||
float line_width = 0.0f;
|
||||
|
||||
@@ -715,9 +717,15 @@ typedef struct screen {
|
||||
// dumps the current screen to a file
|
||||
std::function<void(const char* filename)> gf_print_screen;
|
||||
|
||||
// dumps the current screen to a html blob string
|
||||
std::function<SCP_string()> gf_blob_screen;
|
||||
|
||||
// transforms and dumps the current environment map to a file
|
||||
std::function<void(const char* filename)> gf_dump_envmap;
|
||||
|
||||
// generate diffuse irradiance cubemap for IBL.
|
||||
std::function<void()> gf_calculate_irrmap;
|
||||
|
||||
// Retrieves the zbuffer mode.
|
||||
std::function<int()> gf_zbuffer_get;
|
||||
|
||||
@@ -790,7 +798,7 @@ typedef struct screen {
|
||||
std::function<void()> gf_post_process_save_zbuffer;
|
||||
std::function<void()> gf_post_process_restore_zbuffer;
|
||||
|
||||
std::function<void()> gf_deferred_lighting_begin;
|
||||
std::function<void(bool clearNonColorBufs)> gf_deferred_lighting_begin;
|
||||
std::function<void()> gf_deferred_lighting_end;
|
||||
std::function<void()> gf_deferred_lighting_finish;
|
||||
|
||||
@@ -1002,6 +1010,7 @@ extern void gr_activate(int active);
|
||||
// old Descent-style gr_xxx calls.
|
||||
|
||||
#define gr_print_screen GR_CALL(gr_screen.gf_print_screen)
|
||||
#define gr_blob_screen GR_CALL(gr_screen.gf_blob_screen)
|
||||
#define gr_dump_envmap GR_CALL(gr_screen.gf_dump_envmap)
|
||||
|
||||
//#define gr_flip GR_CALL(gr_screen.gf_flip)
|
||||
|
||||
@@ -114,13 +114,7 @@ decal_draw_list::decal_draw_list(size_t num_decals)
|
||||
header->viewportSize.x = (float) gr_screen.max_w;
|
||||
header->viewportSize.y = (float) gr_screen.max_h;
|
||||
|
||||
header->ambientLight.xyz.x = gr_light_ambient[0] + gr_user_ambient;
|
||||
header->ambientLight.xyz.y = gr_light_ambient[1] + gr_user_ambient;
|
||||
header->ambientLight.xyz.z = gr_light_ambient[2] + gr_user_ambient;
|
||||
|
||||
CLAMP(header->ambientLight.xyz.x, 0.02f, 1.0f);
|
||||
CLAMP(header->ambientLight.xyz.y, 0.02f, 1.0f);
|
||||
CLAMP(header->ambientLight.xyz.z, 0.02f, 1.0f);
|
||||
gr_get_ambient_light(&header->ambientLight);
|
||||
|
||||
// Square the ambient part of the light to match the formula used in the main model shader
|
||||
header->ambientLight.xyz.x *= header->ambientLight.xyz.x;
|
||||
|
||||
@@ -162,7 +162,7 @@ int generic_anim_stream(generic_anim *ga, const bool cache)
|
||||
|
||||
ga->type = BM_TYPE_NONE;
|
||||
|
||||
auto res = cf_find_file_location_ext(ga->filename, BM_ANI_NUM_TYPES, bm_ani_ext_list, CF_TYPE_ANY, false);
|
||||
auto res = cf_find_file_location_ext(ga->filename, BM_ANI_NUM_TYPES, bm_ani_ext_list, CF_TYPE_ANY);
|
||||
|
||||
// could not be found, or is invalid for some reason
|
||||
if ( !res.found )
|
||||
@@ -217,7 +217,7 @@ int generic_anim_stream(generic_anim *ga, const bool cache)
|
||||
ga->png.anim = new apng::apng_ani(ga->filename, cache);
|
||||
}
|
||||
catch (const apng::ApngException& e) {
|
||||
mprintf(("Failed to load apng: %s\n", e.what() ));
|
||||
nprintf(("apng","Failed to load apng: %s\n", e.what() ));
|
||||
delete ga->png.anim;
|
||||
ga->png.anim = nullptr;
|
||||
ga->type = BM_TYPE_NONE;
|
||||
@@ -413,7 +413,6 @@ void generic_render_ani_stream(generic_anim *ga)
|
||||
mprintf(("frame: %d\n", ga->current_frame));
|
||||
#endif
|
||||
|
||||
anim_check_for_palette_change(ga->ani.instance);
|
||||
// if we're using bitmap polys
|
||||
BM_SELECT_TEX_FORMAT();
|
||||
if(ga->direction & GENERIC_ANIM_DIRECTION_BACKWARDS) {
|
||||
|
||||
@@ -91,6 +91,11 @@ void gr_stub_print_screen(const char * /*filename*/)
|
||||
{
|
||||
}
|
||||
|
||||
SCP_string gr_stub_blob_screen()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
void gr_stub_rect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*resize_mode*/)
|
||||
{
|
||||
}
|
||||
@@ -217,7 +222,7 @@ void gr_stub_copy_effect_texture()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_deferred_lighting_begin()
|
||||
void gr_stub_deferred_lighting_begin(bool /*clearNonColorBufs*/)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -449,6 +454,7 @@ bool gr_stub_init()
|
||||
// gr_screen.gf_shade = gr_stub_shade;
|
||||
|
||||
gr_screen.gf_print_screen = gr_stub_print_screen;
|
||||
gr_screen.gf_blob_screen = gr_stub_blob_screen;
|
||||
|
||||
gr_screen.gf_zbuffer_get = gr_stub_zbuffer_get;
|
||||
gr_screen.gf_zbuffer_set = gr_stub_zbuffer_set;
|
||||
|
||||
+13
-38
@@ -15,6 +15,8 @@
|
||||
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "lighting/lighting.h"
|
||||
#include "lighting/lighting_profiles.h"
|
||||
#include "math/bitarray.h"
|
||||
#include "render/3d.h"
|
||||
#include "util/uniform_structs.h"
|
||||
@@ -24,7 +26,6 @@ struct gr_light
|
||||
{
|
||||
vec4 Ambient;
|
||||
vec4 Diffuse;
|
||||
vec4 Specular;
|
||||
|
||||
// light position
|
||||
vec4 Position;
|
||||
@@ -34,6 +35,7 @@ struct gr_light
|
||||
|
||||
float SpotCutOff;
|
||||
float ConstantAtten, LinearAtten, QuadraticAtten;
|
||||
float SourceRadius;
|
||||
|
||||
int type;
|
||||
};
|
||||
@@ -49,7 +51,7 @@ const float gr_light_color[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
|
||||
const float gr_light_zero[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
const float gr_light_emission[4] = { 0.09f, 0.09f, 0.09f, 1.0f };
|
||||
float gr_light_ambient[4] = { 0.47f, 0.47f, 0.47f, 1.0f };
|
||||
float gr_user_ambient = 0.0f;
|
||||
|
||||
|
||||
void FSLight2GLLight(light* FSLight, gr_light* GLLight) {
|
||||
GLLight->Ambient.xyzw.x = 0.0f;
|
||||
@@ -62,11 +64,6 @@ void FSLight2GLLight(light* FSLight, gr_light* GLLight) {
|
||||
GLLight->Diffuse.xyzw.z = FSLight->b * FSLight->intensity;
|
||||
GLLight->Diffuse.xyzw.w = 1.0f;
|
||||
|
||||
GLLight->Specular.xyzw.x = FSLight->spec_r * FSLight->intensity;
|
||||
GLLight->Specular.xyzw.y = FSLight->spec_g * FSLight->intensity;
|
||||
GLLight->Specular.xyzw.z = FSLight->spec_b * FSLight->intensity;
|
||||
GLLight->Specular.xyzw.w = 1.0f;
|
||||
|
||||
GLLight->type = static_cast<int>(FSLight->type);
|
||||
|
||||
// GL default values...
|
||||
@@ -85,6 +82,7 @@ void FSLight2GLLight(light* FSLight, gr_light* GLLight) {
|
||||
GLLight->Position.xyzw.y = FSLight->vec.xyz.y;
|
||||
GLLight->Position.xyzw.z = FSLight->vec.xyz.z; // flipped axis for FS2
|
||||
GLLight->Position.xyzw.w = 1.0f;
|
||||
GLLight->SourceRadius = FSLight->source_radius;
|
||||
|
||||
|
||||
switch (FSLight->type) {
|
||||
@@ -93,9 +91,6 @@ void FSLight2GLLight(light* FSLight, gr_light* GLLight) {
|
||||
GLLight->ConstantAtten = 1.0f;
|
||||
GLLight->LinearAtten = (1.0f / MAX(FSLight->rada, FSLight->radb)) * 1.25f;
|
||||
|
||||
GLLight->Specular.xyzw.x *= static_point_factor;
|
||||
GLLight->Specular.xyzw.y *= static_point_factor;
|
||||
GLLight->Specular.xyzw.z *= static_point_factor;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -105,10 +100,6 @@ void FSLight2GLLight(light* FSLight, gr_light* GLLight) {
|
||||
GLLight->LinearAtten = (1.0f / MAX(FSLight->rada, FSLight->radb)) * 1.25f;
|
||||
GLLight->QuadraticAtten = (1.0f / MAX(FSLight->rada_squared, FSLight->radb_squared)) * 1.25f;
|
||||
|
||||
GLLight->Specular.xyzw.x *= static_tube_factor;
|
||||
GLLight->Specular.xyzw.y *= static_tube_factor;
|
||||
GLLight->Specular.xyzw.z *= static_tube_factor;
|
||||
|
||||
GLLight->Position.xyzw.x = FSLight->vec2.xyz.x; // Valathil: Use endpoint of tube as light position
|
||||
GLLight->Position.xyzw.y = FSLight->vec2.xyz.y;
|
||||
GLLight->Position.xyzw.z = FSLight->vec2.xyz.z;
|
||||
@@ -130,10 +121,6 @@ void FSLight2GLLight(light* FSLight, gr_light* GLLight) {
|
||||
GLLight->Position.xyzw.z = -FSLight->vec.xyz.z;
|
||||
GLLight->Position.xyzw.w = 0.0f; // This is a direction so the w part must be 0
|
||||
|
||||
GLLight->Specular.xyzw.x *= static_light_factor;
|
||||
GLLight->Specular.xyzw.y *= static_light_factor;
|
||||
GLLight->Specular.xyzw.z *= static_light_factor;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -154,11 +141,10 @@ static void set_light(int light_num, gr_light* ltp) {
|
||||
|
||||
gr_light_uniforms[light_num].diffuse_color = vm_vec4_to_vec3(ltp->Diffuse);
|
||||
|
||||
gr_light_uniforms[light_num].spec_color = vm_vec4_to_vec3(ltp->Specular);
|
||||
|
||||
gr_light_uniforms[light_num].light_type = ltp->type;
|
||||
|
||||
gr_light_uniforms[light_num].attenuation = ltp->LinearAtten;
|
||||
gr_light_uniforms[light_num].ml_sourceRadius = ltp->SourceRadius;
|
||||
}
|
||||
|
||||
static bool sort_active_lights(const gr_light& la, const gr_light& lb) {
|
||||
@@ -249,11 +235,6 @@ void gr_set_center_alpha(int type) {
|
||||
}
|
||||
glight.type = type;
|
||||
|
||||
glight.Specular.xyzw.x = 0.0f;
|
||||
glight.Specular.xyzw.y = 0.0f;
|
||||
glight.Specular.xyzw.z = 0.0f;
|
||||
glight.Specular.xyzw.w = 0.0f;
|
||||
|
||||
glight.Ambient.xyzw.w = 1.0f;
|
||||
glight.Diffuse.xyzw.w = 1.0f;
|
||||
|
||||
@@ -291,14 +272,6 @@ void gr_reset_lighting() {
|
||||
Num_active_gr_lights = 0;
|
||||
}
|
||||
|
||||
void gr_calculate_ambient_factor(int ambient_factor) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
return;
|
||||
}
|
||||
|
||||
gr_user_ambient = (float) ((ambient_factor * 2) - 255) / 255.0f;
|
||||
}
|
||||
|
||||
void gr_light_shutdown() {
|
||||
gr_lights.clear();
|
||||
}
|
||||
@@ -308,8 +281,6 @@ void gr_light_init() {
|
||||
return;
|
||||
}
|
||||
|
||||
gr_calculate_ambient_factor();
|
||||
|
||||
// allocate memory for enabled lights
|
||||
gr_lights.reserve(1024);
|
||||
}
|
||||
@@ -320,7 +291,6 @@ void gr_set_lighting() {
|
||||
}
|
||||
|
||||
//Valathil: Sort lights by priority
|
||||
extern bool Deferred_lighting;
|
||||
if (!Deferred_lighting) {
|
||||
pre_render_init_lights();
|
||||
}
|
||||
@@ -357,8 +327,13 @@ void gr_set_ambient_light(int red, int green, int blue) {
|
||||
gr_light_ambient[1] = i2fl(green) / 255.0f;
|
||||
gr_light_ambient[2] = i2fl(blue) / 255.0f;
|
||||
gr_light_ambient[3] = 1.0f;
|
||||
|
||||
gr_calculate_ambient_factor();
|
||||
}
|
||||
void gr_get_ambient_light(vec3d* light_vector) {
|
||||
auto abv = lighting_profile::current()->ambient_light_brightness;
|
||||
auto over = lighting_profile::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]));
|
||||
}
|
||||
|
||||
void gr_lighting_fill_uniforms(void* data_out, size_t buffer_size) {
|
||||
|
||||
Loaded 100 of 762 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user