mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
769 Commits
2.9.9
...
f4cd214823
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4cd214823 | ||
|
|
bb6db2b7f8 | ||
|
|
fd2dacaefb | ||
|
|
cc60e85901 | ||
|
|
9520782a04 | ||
|
|
f172f6efeb | ||
|
|
b6b6686873 | ||
|
|
5e724e7a3f | ||
|
|
90f1d1df2a | ||
|
|
a5726c0ed8 | ||
|
|
1860366986 | ||
|
|
9db1d38a15 | ||
|
|
04ceda693b | ||
|
|
23ff128ac8 | ||
|
|
3749142670 | ||
|
|
7d3fc1740a | ||
|
|
b2a084d669 | ||
|
|
30203668e4 | ||
|
|
ebecc70693 | ||
|
|
74712b6e27 | ||
|
|
40253ea8bb | ||
|
|
7279da7f09 | ||
|
|
31c40c96f2 | ||
|
|
7a833365ce | ||
|
|
4e56078d2a | ||
|
|
0ac156f2b5 | ||
|
|
4bbf20ca4e | ||
|
|
a462c5a493 | ||
|
|
179cb5f589 | ||
|
|
367014ebf3 | ||
|
|
9d8d0c2155 | ||
|
|
edfe91274d | ||
|
|
326b20b08d | ||
|
|
11b0ce6275 | ||
|
|
03763e16d6 | ||
|
|
c1e8ee12e0 | ||
|
|
ac8cc408c1 | ||
|
|
dad91cca8c | ||
|
|
2f9c384ac0 | ||
|
|
f23a2267cf | ||
|
|
ada38fa3ea | ||
|
|
2ee0597d48 | ||
|
|
b39a83ad6e | ||
|
|
7ae4cdc8f1 | ||
|
|
7d47227fab | ||
|
|
1f09b8fe0b | ||
|
|
8c92a578ed | ||
|
|
992f09d9ba | ||
|
|
096f2caf9c | ||
|
|
0b37c909b3 | ||
|
|
bdad38e707 | ||
|
|
1b18ae1597 | ||
|
|
8dcc3cbe8f | ||
|
|
aa8f3a824c | ||
|
|
b5a19528a1 | ||
|
|
bd20e8fc81 | ||
|
|
2f806801bc | ||
|
|
be006bd2bf | ||
|
|
18a08288ec | ||
|
|
c9ac6d73e6 | ||
|
|
f602455d1f | ||
|
|
d5c34a37b0 | ||
|
|
8a0e9a3400 | ||
|
|
0e836973fd | ||
|
|
1b57af88a0 | ||
|
|
be40d7be9a | ||
|
|
00de8d911c | ||
|
|
9df3fcfdf7 | ||
|
|
d675e34f37 | ||
|
|
2d96ba0f56 | ||
|
|
21c2bd1103 | ||
|
|
f3b7740041 | ||
|
|
7d7488db6f | ||
|
|
b9197d65d5 | ||
|
|
ec6f190b68 | ||
|
|
5e4f9f035b | ||
|
|
7b6bf7f39b | ||
|
|
2e8875dd2f | ||
|
|
4964cc2f2d | ||
|
|
f0a4c5b008 | ||
|
|
1b6412821b | ||
|
|
926a0733e4 | ||
|
|
124ebd3240 | ||
|
|
7728609165 | ||
|
|
da70f4ce6c | ||
|
|
69b3e9abad | ||
|
|
f9f77bfa7b | ||
|
|
429db73854 | ||
|
|
1e9c45c115 | ||
|
|
727cb3276c | ||
|
|
a68175448d | ||
|
|
33e63a4819 | ||
|
|
d7431478d1 | ||
|
|
3543b2c79a | ||
|
|
4489efff94 | ||
|
|
dcdea379ef | ||
|
|
6a4bddde99 | ||
|
|
2088359756 | ||
|
|
dc2511942c | ||
|
|
f0c257c4a5 | ||
|
|
068d21612f | ||
|
|
773461aad9 | ||
|
|
f9257b2b0d | ||
|
|
9e0f03a3cd | ||
|
|
0ab6a10ec4 | ||
|
|
73f393c542 | ||
|
|
a467fabdc8 | ||
|
|
a2ab84c45a | ||
|
|
7ec7228cb8 | ||
|
|
9fd6729967 | ||
|
|
f1d4f1753a | ||
|
|
1f268b3b5d | ||
|
|
6d9c3fd0aa | ||
|
|
28ae63bd8d | ||
|
|
42e7e3f94f | ||
|
|
4a5204aecb | ||
|
|
6466c5e95e | ||
|
|
829f5af25f | ||
|
|
0d1147bac4 | ||
|
|
24b47b02e0 | ||
|
|
10262fd30b | ||
|
|
3cabc07d58 | ||
|
|
b0546b1e60 | ||
|
|
a988e67490 | ||
|
|
fa951838d2 | ||
|
|
2594c5bbf0 | ||
|
|
db70fa341c | ||
|
|
763e3852ac | ||
|
|
66157d0596 | ||
|
|
8ec86973c6 | ||
|
|
eb2c6ac6f2 | ||
|
|
93a8d8bc2d | ||
|
|
cbcc893ce5 | ||
|
|
c19713949d | ||
|
|
54450935a1 | ||
|
|
d0f5712ca8 | ||
|
|
382b049c5f | ||
|
|
6c2cc37abe | ||
|
|
a53763221c | ||
|
|
83447a3fb4 | ||
|
|
b7bac28113 | ||
|
|
a9edb16554 | ||
|
|
52cbb7202c | ||
|
|
f6a8317c42 | ||
|
|
2a9a7db9b8 | ||
|
|
3aeec78f79 | ||
|
|
0aeb1fc6af | ||
|
|
26565d7549 | ||
|
|
62816f217b | ||
|
|
eeeeda4e5e | ||
|
|
95767c5ef4 | ||
|
|
f5881eda53 | ||
|
|
fca6faa3a8 | ||
|
|
c1997d9f70 | ||
|
|
bb1caa6642 | ||
|
|
638f083729 | ||
|
|
59d41cf98b | ||
|
|
793adafda7 | ||
|
|
dd5ca93f26 | ||
|
|
0d1a7c770b | ||
|
|
1889df4952 | ||
|
|
7ca219748d | ||
|
|
b3f944e82e | ||
|
|
2fc16ba694 | ||
|
|
432fc0ef4b | ||
|
|
20c50c751f | ||
|
|
d3b62d0260 | ||
|
|
d0449265c1 | ||
|
|
a4feafab8e | ||
|
|
309eedd165 | ||
|
|
997baf21a0 | ||
|
|
fa676cc750 | ||
|
|
b126cc00d0 | ||
|
|
1e0c27f599 | ||
|
|
09b7922b84 | ||
|
|
66032d6894 | ||
|
|
7c98a793c7 | ||
|
|
7a5b9a75f3 | ||
|
|
0ea5631955 | ||
|
|
4bab2ee1de | ||
|
|
f5b9713639 | ||
|
|
1bfb4fc4e1 | ||
|
|
d7defe6f7f | ||
|
|
ebb94c07b3 | ||
|
|
f4cdbec376 | ||
|
|
21d5a5dfac | ||
|
|
f8947aab9c | ||
|
|
db869bcb6d | ||
|
|
36a0cfd635 | ||
|
|
ea4a1f9ff9 | ||
|
|
20406e40ca | ||
|
|
acbcb14cba | ||
|
|
3b50fee5a0 | ||
|
|
804004198b | ||
|
|
67ef6c6e7b | ||
|
|
5b8b8a5566 | ||
|
|
0468bacc0b | ||
|
|
eacc43cb5a | ||
|
|
f3dcde075c | ||
|
|
7eba1349ae | ||
|
|
b6074a4795 | ||
|
|
615afb7cc4 | ||
|
|
36c9f551d9 | ||
|
|
89c3f7310b | ||
|
|
6791a0e704 | ||
|
|
a6b622ed31 | ||
|
|
f1af3a50b8 | ||
|
|
f999e45323 | ||
|
|
0c90e90c18 | ||
|
|
4747f3f48f | ||
|
|
f97ef25104 | ||
|
|
e1a670185e | ||
|
|
069c0aa03f | ||
|
|
b145588ed5 | ||
|
|
b678e2cde1 | ||
|
|
db23a0bf2b | ||
|
|
3ad60a95ce | ||
|
|
5c3b7312c0 | ||
|
|
f177d0a257 | ||
|
|
ac4b620f16 | ||
|
|
c49b56eefc | ||
|
|
ccada18a6a | ||
|
|
1547d66327 | ||
|
|
e21236655a | ||
|
|
cdad3bd058 | ||
|
|
0db9c27f7e | ||
|
|
8042e8bfaf | ||
|
|
dd7b87e9cd | ||
|
|
68a539923f | ||
|
|
460d2768ff | ||
|
|
3c74272749 | ||
|
|
3442725525 | ||
|
|
82c409d77a | ||
|
|
195aac4504 | ||
|
|
326e27327d | ||
|
|
08d8f3e25f | ||
|
|
6f72697e26 | ||
|
|
296d4b1e93 | ||
|
|
0f6439cf9f | ||
|
|
9705b49dbe | ||
|
|
9364579a18 | ||
|
|
02a6d8f2c0 | ||
|
|
2c10943cb1 | ||
|
|
a293c59d6d | ||
|
|
544db963ea | ||
|
|
d3fd21e6da | ||
|
|
207698a2dd | ||
|
|
27cd90a0ce | ||
|
|
d1ae2c0f5e | ||
|
|
66e6a603f1 | ||
|
|
0392417189 | ||
|
|
0678ad17f8 | ||
|
|
be4beea9d0 | ||
|
|
5da899138b | ||
|
|
1ec1e00bde | ||
|
|
d7d46d4f1b | ||
|
|
5d93b33d42 | ||
|
|
b2077bfc74 | ||
|
|
e958ca103a | ||
|
|
1d9ef869a7 | ||
|
|
6fdf9a649f | ||
|
|
90c6c57449 | ||
|
|
d013bbc751 | ||
|
|
e0092fdba0 | ||
|
|
ecce2eff9b | ||
|
|
fbeada439f | ||
|
|
6c8858d2f5 | ||
|
|
e2b77878df | ||
|
|
53d7972858 | ||
|
|
04a55e4104 | ||
|
|
d11acecdac | ||
|
|
4b23c86daa | ||
|
|
49c11073e6 | ||
|
|
daa5caa125 | ||
|
|
1a156e7e12 | ||
|
|
6fe88a6319 | ||
|
|
1856754614 | ||
|
|
b9f6c1b9c7 | ||
|
|
6ac452ff15 | ||
|
|
b52176a0ff | ||
|
|
d707a4775c | ||
|
|
ffccc31e38 | ||
|
|
0405af2bde | ||
|
|
d09f0b1f6f | ||
|
|
e50e572c78 | ||
|
|
2e688e7da1 | ||
|
|
3083599158 | ||
|
|
2921f7a76b | ||
|
|
b7b6c1ea19 | ||
|
|
8a185c352e | ||
|
|
5b107ce2da | ||
|
|
5c1e342a79 | ||
|
|
3fc8f52796 | ||
|
|
ddf33da787 | ||
|
|
e7cee4d97b | ||
|
|
b0a192a767 | ||
|
|
986c340211 | ||
|
|
2109537f86 | ||
|
|
bad9d1ea92 | ||
|
|
690db7f12f | ||
|
|
4f3fd06cc9 | ||
|
|
f5b1050086 | ||
|
|
4074023ed3 | ||
|
|
f729b1d358 | ||
|
|
6c00b0c7eb | ||
|
|
5adefe6f7b | ||
|
|
76dc0d690a | ||
|
|
13c16b8674 | ||
|
|
222722225e | ||
|
|
82e1dcfc04 | ||
|
|
c26220d1fd | ||
|
|
d783f7be99 | ||
|
|
b66e91b11f | ||
|
|
dd0b2ace65 | ||
|
|
dc83af4d02 | ||
|
|
342e901dd1 | ||
|
|
0a38700edb | ||
|
|
659615114a | ||
|
|
bfd26522d6 | ||
|
|
00d14c7c0a | ||
|
|
47c9e1ba1f | ||
|
|
92e680a276 | ||
|
|
4955fe4d92 | ||
|
|
e439bcdd0f | ||
|
|
792aa73832 | ||
|
|
d375e0ce29 | ||
|
|
e3670219ed | ||
|
|
a915452e6e | ||
|
|
6662a1cf97 | ||
|
|
be8405b72b | ||
|
|
9b24695377 | ||
|
|
5ca3e3b2b8 | ||
|
|
8bbef34b74 | ||
|
|
618a8744a2 | ||
|
|
5329da32eb | ||
|
|
df86c3f2a1 | ||
|
|
784fcb7882 | ||
|
|
23aeef7a20 | ||
|
|
0ee24b86dc | ||
|
|
9ac4f136aa | ||
|
|
ca9b2d79cc | ||
|
|
c9a09c2fc9 | ||
|
|
813286f7f3 | ||
|
|
6028c91f81 | ||
|
|
11b6bb2638 | ||
|
|
3c57928f46 | ||
|
|
e091e659a2 | ||
|
|
32f0bb33c3 | ||
|
|
dea64751c3 | ||
|
|
31d0410284 | ||
|
|
9cdf550432 | ||
|
|
09525029ab | ||
|
|
87c436ba34 | ||
|
|
b1002017e5 | ||
|
|
6e9727e265 | ||
|
|
383e953ba1 | ||
|
|
94ee76fe62 | ||
|
|
9b52b640e6 | ||
|
|
ea23162ca9 | ||
|
|
68d0220912 | ||
|
|
683388faee | ||
|
|
56ec3920c5 | ||
|
|
88842d1c67 | ||
|
|
f335ffc4ec | ||
|
|
f76aefa976 | ||
|
|
4976cd86f2 | ||
|
|
2cd66ae1d4 | ||
|
|
c00eff8b23 | ||
|
|
7f0376561b | ||
|
|
3c710613a8 | ||
|
|
3585208547 | ||
|
|
29c0017e80 | ||
|
|
45ebf9a3c7 | ||
|
|
908e505ce3 | ||
|
|
c808e4a4e2 | ||
|
|
e129eb97a7 | ||
|
|
e2612b97d7 | ||
|
|
70e9d91bb5 | ||
|
|
0b8810f8b3 | ||
|
|
3d39ccbdce | ||
|
|
41b867a4ca | ||
|
|
427baa43d7 | ||
|
|
d4e141f3c5 | ||
|
|
1c0a8d9380 | ||
|
|
f05680f23d | ||
|
|
2b0b9d44eb | ||
|
|
2fc7a3b542 | ||
|
|
820ae2759b | ||
|
|
12b596a47f | ||
|
|
a06d099917 | ||
|
|
7552309a28 | ||
|
|
b9ad5b5ba7 | ||
|
|
8ef781a9ac | ||
|
|
5e24e8658b | ||
|
|
43eeaede65 | ||
|
|
749c5f87de | ||
|
|
a520daeb56 | ||
|
|
9bb713db10 | ||
|
|
f9ba96f228 | ||
|
|
a49bd23a2a | ||
|
|
913b2c6d3f | ||
|
|
cea2f18228 | ||
|
|
fd2d8a5119 | ||
|
|
24b3200777 | ||
|
|
fa4e0447dd | ||
|
|
31aa604fc4 | ||
|
|
3518c89791 | ||
|
|
f44db27565 | ||
|
|
acaab0c6a9 | ||
|
|
9b1abab73a | ||
|
|
cad8f15b61 | ||
|
|
aafbd8c297 | ||
|
|
1d08bcf2e0 | ||
|
|
6d38346eb8 | ||
|
|
9487a5ae91 | ||
|
|
d2bb6a4fc0 | ||
|
|
c3ccecdd4a | ||
|
|
5ad54648ab | ||
|
|
96337cc5df | ||
|
|
fa0ce0927b | ||
|
|
693c2a730f | ||
|
|
0d438a9452 | ||
|
|
bc9eee22b7 | ||
|
|
f74d25b31c | ||
|
|
66af360ce6 | ||
|
|
ad9893c3ab | ||
|
|
1156971d94 | ||
|
|
c79b5c37c4 | ||
|
|
b4e6201b68 | ||
|
|
f26d8d6822 | ||
|
|
3d0b7b9267 | ||
|
|
a2b650a9e3 | ||
|
|
905b442e9b | ||
|
|
7cd95377f9 | ||
|
|
18fe3112bd | ||
|
|
84e85dd0b5 | ||
|
|
2744befbab | ||
|
|
e87dc525b9 | ||
|
|
cc057744ba | ||
|
|
db1779e1db | ||
|
|
ed31b87b2f | ||
|
|
d1e31a3652 | ||
|
|
d25a723fc7 | ||
|
|
3fb4cae7b8 | ||
|
|
f0fe1b431d | ||
|
|
8e286edd25 | ||
|
|
74520b1359 | ||
|
|
0ffcdf2f66 | ||
|
|
fe0edeb011 | ||
|
|
d06e44d37b | ||
|
|
35348d9b81 | ||
|
|
d06a618582 | ||
|
|
4b16e94eaf | ||
|
|
d5253f0420 | ||
|
|
d983676330 | ||
|
|
03c30f3cce | ||
|
|
99b93266ad | ||
|
|
4530b74367 | ||
|
|
e307b57e67 | ||
|
|
5ef9bb2acd | ||
|
|
4aacdc1567 | ||
|
|
57552f4300 | ||
|
|
09d53f7d8c | ||
|
|
161bdc0413 | ||
|
|
44ad362dbc | ||
|
|
ea776aeacc | ||
|
|
e30479329a | ||
|
|
d9948d1a19 | ||
|
|
b962096661 | ||
|
|
725b55a505 | ||
|
|
5f7a4f2bbb | ||
|
|
f555399e2f | ||
|
|
1b6945e0b0 | ||
|
|
4fd55b1bd6 | ||
|
|
fb276cf812 | ||
|
|
41dfaab82a | ||
|
|
20b8deb6de | ||
|
|
6af836c118 | ||
|
|
f87b8a2c2a | ||
|
|
daffd7412a | ||
|
|
bfb60b318e | ||
|
|
a55959dfbb | ||
|
|
4d24eb82be | ||
|
|
4656d3e019 | ||
|
|
86b76ba216 | ||
|
|
ff561410ad | ||
|
|
e26caa2f74 | ||
|
|
b32d17c2ab | ||
|
|
29111e1018 | ||
|
|
3433ebd665 | ||
|
|
b75fff60c8 | ||
|
|
a47fa3f9fc | ||
|
|
4ac57fce7a | ||
|
|
6218b94c99 | ||
|
|
74a6c89801 | ||
|
|
25a9a0120a | ||
|
|
deb0747e66 | ||
|
|
00f5fde5a8 | ||
|
|
03cd354f9e | ||
|
|
66a1fa8af5 | ||
|
|
c2096c8dfd | ||
|
|
1b4033cfce | ||
|
|
750edf1144 | ||
|
|
48bc41873a | ||
|
|
2e54f51229 | ||
|
|
e39e414e0d | ||
|
|
068a1ab99c | ||
|
|
e35d9eb07f | ||
|
|
6551383070 | ||
|
|
b03978cc3d | ||
|
|
3a7233b594 | ||
|
|
82f4c5790a | ||
|
|
5957124e9e | ||
|
|
7c91b9847b | ||
|
|
92a05ca74a | ||
|
|
a3c13c8cea | ||
|
|
d02b5db6dd | ||
|
|
bd074728fe | ||
|
|
8d87531464 | ||
|
|
5fbd3d9525 | ||
|
|
61b7b3ead6 | ||
|
|
8f2178a79c | ||
|
|
72bb23ed0d | ||
|
|
7f7999e3e5 | ||
|
|
0a08e3fdac | ||
|
|
b522b38d31 | ||
|
|
646a2aec66 | ||
|
|
7392cb9bf3 | ||
|
|
2e77988473 | ||
|
|
b2dc7bc232 | ||
|
|
1b25220729 | ||
|
|
4953000565 | ||
|
|
01b7575bca | ||
|
|
f6e6dcac9a | ||
|
|
93c307d9dd | ||
|
|
852c18cef8 | ||
|
|
def622a02c | ||
|
|
acfe1a856e | ||
|
|
9f1f6af647 | ||
|
|
30bedb39f1 | ||
|
|
fbcc4ee32b | ||
|
|
27571cc22f | ||
|
|
1182a5eb1e | ||
|
|
5f57c71c62 | ||
|
|
c0d60b1bcf | ||
|
|
63c68d729b | ||
|
|
5fe29e2ba1 | ||
|
|
16ff1ac3e7 | ||
|
|
0e4f805e1c | ||
|
|
5f29bdc7a7 | ||
|
|
04f8f6d512 | ||
|
|
f4768aff07 | ||
|
|
b74d46f762 | ||
|
|
02decc3901 | ||
|
|
dcdea16624 | ||
|
|
2635cf6345 | ||
|
|
578c65196c | ||
|
|
64fb24ce96 | ||
|
|
45dd7117c7 | ||
|
|
e86069d39c | ||
|
|
e9db714937 | ||
|
|
fdcf153b0b | ||
|
|
8523b7e20a | ||
|
|
29b992bf81 | ||
|
|
4c52509d6d | ||
|
|
8d603a0cef | ||
|
|
9bc067f2e8 | ||
|
|
5fbe0d9a70 | ||
|
|
4c1c36ef46 | ||
|
|
067fbcaeaf | ||
|
|
f0aad83d53 | ||
|
|
474f767e56 | ||
|
|
be062061d5 | ||
|
|
ac5dfab82f | ||
|
|
13d5f4ac99 | ||
|
|
f9030be843 | ||
|
|
3cea1cc78c | ||
|
|
37c1423c9f | ||
|
|
538e35d8f0 | ||
|
|
d23f029953 | ||
|
|
aafa37f80d | ||
|
|
203f0c8abc | ||
|
|
1c0e6362a1 | ||
|
|
68165cee75 | ||
|
|
8ef5f0b3f6 | ||
|
|
d0736b0b56 | ||
|
|
2fbcd9d2b9 | ||
|
|
15b1ed028e | ||
|
|
a611a38181 | ||
|
|
008617a35c | ||
|
|
81a403f02d | ||
|
|
6144a61a2e | ||
|
|
df102fba6c | ||
|
|
5d192abd25 | ||
|
|
902f6dae11 | ||
|
|
62337f445a | ||
|
|
b38c1c5827 | ||
|
|
8309768735 | ||
|
|
42e6b57296 | ||
|
|
2835ec812f | ||
|
|
990161729b | ||
|
|
c08cee2317 | ||
|
|
e1ea4322a1 | ||
|
|
0f7759d070 | ||
|
|
6523c4473f | ||
|
|
4a0842bea6 | ||
|
|
3745e6a8d8 | ||
|
|
3b3666c5f7 | ||
|
|
9e1a28f7ca | ||
|
|
82c7e921eb | ||
|
|
67ccf532ea | ||
|
|
45912911ee | ||
|
|
c7fe42d919 | ||
|
|
9916afaa49 | ||
|
|
55c5a23616 | ||
|
|
7b6df08268 | ||
|
|
9300050573 | ||
|
|
6bee1cc88e | ||
|
|
c94767a715 | ||
|
|
7aa3169523 | ||
|
|
cf86eacb16 | ||
|
|
43ab4d5f38 | ||
|
|
aa064a1d0e | ||
|
|
21240a60de | ||
|
|
0427c0d3a7 | ||
|
|
3f632b92e2 | ||
|
|
014750ea7f | ||
|
|
548b80969a | ||
|
|
e4bbfce314 | ||
|
|
278f1db9a9 | ||
|
|
359429b17e | ||
|
|
f151271cb1 | ||
|
|
6001f6abda | ||
|
|
18e5012546 | ||
|
|
fd9b5d8d16 | ||
|
|
da3ee13582 | ||
|
|
b6f184388a | ||
|
|
903c065b74 | ||
|
|
d8471698ab | ||
|
|
6204cecbbd | ||
|
|
ddeca49916 | ||
|
|
d8dcf37886 | ||
|
|
5ae41a208b | ||
|
|
0462d900e6 | ||
|
|
4fb2ad88bc | ||
|
|
ea55e90e62 | ||
|
|
6025c05f33 | ||
|
|
64f854e646 | ||
|
|
0f962461e1 | ||
|
|
62dfb5b5ff | ||
|
|
171af5a3c3 | ||
|
|
874548d1c1 | ||
|
|
aadc03c38d | ||
|
|
fb0aeafaa2 | ||
|
|
683fa13bb2 | ||
|
|
d3bd55a290 | ||
|
|
e4408a964d | ||
|
|
1fbe78b667 | ||
|
|
4902e0f597 | ||
|
|
34e248b1c3 | ||
|
|
5a05917bc2 | ||
|
|
98a613261c | ||
|
|
ee880a893e | ||
|
|
7e8555d6b7 | ||
|
|
0a6bdd6e04 | ||
|
|
f97f33ab59 | ||
|
|
f59102ee09 | ||
|
|
de304d6bb9 | ||
|
|
73181e3f45 | ||
|
|
e42e4e1ddf | ||
|
|
86e899f39b | ||
|
|
a30079c45b | ||
|
|
f644d49e71 | ||
|
|
c0b09b03d9 | ||
|
|
50ffd9aba6 | ||
|
|
4d4138c1e6 | ||
|
|
936fec1f49 | ||
|
|
9625d87dd5 | ||
|
|
c4d0319bb2 | ||
|
|
802139205c | ||
|
|
6022a3905f | ||
|
|
6f724c62fb | ||
|
|
fb918cb2a4 | ||
|
|
1a74f112ef | ||
|
|
abb4de46d7 | ||
|
|
5747c49abf | ||
|
|
b87930738a | ||
|
|
d2c78516f5 | ||
|
|
93cff96794 | ||
|
|
75e80a0091 | ||
|
|
46d2c9c196 | ||
|
|
6f61d160af | ||
|
|
13419171a9 | ||
|
|
147cfea587 | ||
|
|
c27da8e54e | ||
|
|
f3c8b4c1cd | ||
|
|
09e1883488 | ||
|
|
dce9631399 | ||
|
|
fb2ba1dea0 | ||
|
|
19073534dd | ||
|
|
23080e3cc4 | ||
|
|
b50d3fa809 | ||
|
|
1f191cf9bb | ||
|
|
6c773786d2 | ||
|
|
8939963187 | ||
|
|
e3fb693cb7 | ||
|
|
7cc11f55bb | ||
|
|
f9747d1c4c | ||
|
|
60a3d3409e | ||
|
|
cd8cbc54c8 | ||
|
|
b72124c0d9 | ||
|
|
0d6a1644e2 | ||
|
|
d51e761b26 | ||
|
|
1ebe8b82ec | ||
|
|
1445ef61a0 | ||
|
|
f82490f0d5 | ||
|
|
dfe2ed2a98 | ||
|
|
bb5c044a25 | ||
|
|
be87103b53 | ||
|
|
54f7627f9c | ||
|
|
2fb460c4bb | ||
|
|
1b3c94cc57 | ||
|
|
216ea230a8 | ||
|
|
7e727620a4 | ||
|
|
13ec9bcdd4 | ||
|
|
90096163ee | ||
|
|
d2564d4a54 | ||
|
|
cd178d6a8c | ||
|
|
2aa0b5ddfb | ||
|
|
cf6e026392 | ||
|
|
37f819458a | ||
|
|
16fb0c3081 | ||
|
|
168f4301d2 | ||
|
|
9fb03d9d8a | ||
|
|
d89ed535b7 | ||
|
|
08b4b890ce | ||
|
|
d5a406c60f | ||
|
|
cb16210577 | ||
|
|
8c0e0de45f | ||
|
|
3524cba4ef | ||
|
|
df6a37a972 | ||
|
|
13600ff6fd | ||
|
|
a957bb4968 | ||
|
|
5f8d1cf5b0 | ||
|
|
a115267e08 | ||
|
|
37998fbf1d | ||
|
|
846aa823d4 | ||
|
|
0d877853eb | ||
|
|
68298fc585 | ||
|
|
b97a7cf387 | ||
|
|
e9d75f6d94 | ||
|
|
1dce2eb747 | ||
|
|
7c110d90cd | ||
|
|
2ecc02ce4d | ||
|
|
8fa5277417 | ||
|
|
7cce5745af | ||
|
|
231f1f236d | ||
|
|
ece0a46f97 | ||
|
|
2c9b0b8376 | ||
|
|
76577c03e7 | ||
|
|
48d30250a0 | ||
|
|
a798f2d61c | ||
|
|
d0f8b1436b | ||
|
|
ddc5e0f86e | ||
|
|
ae08c87822 | ||
|
|
ae880e9d1c | ||
|
|
101d2e1de5 | ||
|
|
f6b7708567 | ||
|
|
051286acd1 |
@@ -1953,7 +1953,7 @@ local function refct_from_id(id) -- refct = refct_from_id(CTypeID)
|
|||||||
unsigned = refct.unsigned,
|
unsigned = refct.unsigned,
|
||||||
size = bit.band(bit.rshift(ctype.info, 16), 127),
|
size = bit.band(bit.rshift(ctype.info, 16), 127),
|
||||||
}
|
}
|
||||||
refct.bool, refct.const, refct.volatile, refct.unsigned = nil
|
refct.bool, refct.const, refct.volatile, refct.unsigned = nil, nil, nil, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if CT[4] then -- Merge sibling attributes onto this type.
|
if CT[4] then -- Merge sibling attributes onto this type.
|
||||||
|
|||||||
@@ -17,7 +17,9 @@
|
|||||||
|
|
||||||
--- The AI_A2A_CAP class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}
|
--- The AI_A2A_CAP class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_A2A_CAP is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event.
|
-- The AI_A2A_CAP is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event.
|
||||||
|
|||||||
@@ -32,7 +32,9 @@
|
|||||||
-- [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx)
|
-- [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- # QUICK START GUIDE
|
-- # QUICK START GUIDE
|
||||||
--
|
--
|
||||||
-- There are basically two classes available to model an A2A defense system.
|
-- There are basically two classes available to model an A2A defense system.
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- The AI_A2A_GCI is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event.
|
-- The AI_A2A_GCI is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
|
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_A2A_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event.
|
-- The AI_A2A_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event.
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage -- TODO: Documentation. This class does not exist, unable to determine what it extends.
|
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage -- TODO: Documentation. This class does not exist, unable to determine what it extends.
|
||||||
|
|
||||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
--
|
--
|
||||||
-- # QUICK START GUIDE
|
-- # QUICK START GUIDE
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- The following class is available to model an A2G defense system.
|
-- The following class is available to model an A2G defense system.
|
||||||
--
|
--
|
||||||
-- AI_A2G_DISPATCHER is the main A2G defense class that models the A2G defense system.
|
-- AI_A2G_DISPATCHER is the main A2G defense class that models the A2G defense system.
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
--- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- The AI_A2G_SEAD is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_SEAD process can be started using the **Start** event.
|
-- The AI_A2G_SEAD is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_SEAD process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
--- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}.
|
--- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
--
|
--
|
||||||
-- # 1) AI_AIR constructor
|
-- # 1) AI_AIR constructor
|
||||||
--
|
--
|
||||||
@@ -657,8 +658,8 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
|||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local FromRTBRoutePoint = FromCoord:WaypointAir(
|
local FromRTBRoutePoint = FromCoord:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
RTBSpeed,
|
RTBSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -666,8 +667,8 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
|||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local ToRTBRoutePoint = ToAirbaseCoord:WaypointAir(
|
local ToRTBRoutePoint = ToAirbaseCoord:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
RTBSpeed,
|
RTBSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -761,10 +762,10 @@ function AI_AIR:onafterRefuel( AIGroup, From, Event, To )
|
|||||||
local ToRefuelSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
local ToRefuelSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local FromRefuelRoutePoint = FromRefuelCoord:WaypointAir(self.PatrolAltType, POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToRefuelSpeed, true)
|
local FromRefuelRoutePoint = FromRefuelCoord:WaypointAir(self.PatrolAltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, ToRefuelSpeed, true)
|
||||||
|
|
||||||
--- Create a route point of type air. NOT used!
|
--- Create a route point of type air. NOT used!
|
||||||
local ToRefuelRoutePoint = Tanker:GetCoordinate():WaypointAir(self.PatrolAltType, POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToRefuelSpeed, true)
|
local ToRefuelRoutePoint = Tanker:GetCoordinate():WaypointAir(self.PatrolAltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, ToRefuelSpeed, true)
|
||||||
|
|
||||||
self:F( { ToRefuelSpeed = ToRefuelSpeed } )
|
self:F( { ToRefuelSpeed = ToRefuelSpeed } )
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
--
|
--
|
||||||
-- # QUICK START GUIDE
|
-- # QUICK START GUIDE
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- The following class is available to model an AIR defense system.
|
-- The following class is available to model an AIR defense system.
|
||||||
--
|
--
|
||||||
-- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system.
|
-- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system.
|
||||||
|
|||||||
@@ -13,12 +13,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- @type AI_AIR_ENGAGE
|
--- @type AI_AIR_ENGAGE
|
||||||
-- @extends AI.AI_AIR#AI_AIR
|
-- @extends AI.AI_AIR#AI_AIR
|
||||||
|
|
||||||
|
|
||||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- The AI_AIR_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_ENGAGE process can be started using the **Start** event.
|
-- The AI_AIR_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_ENGAGE process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||||
@@ -453,7 +455,7 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
|||||||
|
|
||||||
--- Calculate the target route point.
|
--- Calculate the target route point.
|
||||||
|
|
||||||
local FromWP = DefenderCoord:WaypointAir(self.PatrolAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, EngageSpeed, true)
|
local FromWP = DefenderCoord:WaypointAir(self.PatrolAltType or "RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, EngageSpeed, true)
|
||||||
|
|
||||||
EngageRoute[#EngageRoute+1] = FromWP
|
EngageRoute[#EngageRoute+1] = FromWP
|
||||||
|
|
||||||
@@ -462,7 +464,7 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
|||||||
local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) )
|
local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) )
|
||||||
local ToCoord=DefenderCoord:Translate( EngageDistance, FromEngageAngle, true )
|
local ToCoord=DefenderCoord:Translate( EngageDistance, FromEngageAngle, true )
|
||||||
|
|
||||||
local ToWP = ToCoord:WaypointAir(self.PatrolAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, EngageSpeed, true)
|
local ToWP = ToCoord:WaypointAir(self.PatrolAltType or "RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, EngageSpeed, true)
|
||||||
|
|
||||||
EngageRoute[#EngageRoute+1] = ToWP
|
EngageRoute[#EngageRoute+1] = ToWP
|
||||||
|
|
||||||
@@ -536,7 +538,7 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
|||||||
local EngageRoute = {}
|
local EngageRoute = {}
|
||||||
local AttackTasks = {}
|
local AttackTasks = {}
|
||||||
|
|
||||||
local FromWP = DefenderCoord:WaypointAir(self.EngageAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, EngageSpeed, true)
|
local FromWP = DefenderCoord:WaypointAir(self.EngageAltType or "RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, EngageSpeed, true)
|
||||||
EngageRoute[#EngageRoute+1] = FromWP
|
EngageRoute[#EngageRoute+1] = FromWP
|
||||||
|
|
||||||
self:SetTargetDistance( TargetCoord ) -- For RTB status check
|
self:SetTargetDistance( TargetCoord ) -- For RTB status check
|
||||||
@@ -544,7 +546,7 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
|||||||
local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) )
|
local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) )
|
||||||
local ToCoord=DefenderCoord:Translate( EngageDistance, FromEngageAngle, true )
|
local ToCoord=DefenderCoord:Translate( EngageDistance, FromEngageAngle, true )
|
||||||
|
|
||||||
local ToWP = ToCoord:WaypointAir(self.EngageAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, EngageSpeed, true)
|
local ToWP = ToCoord:WaypointAir(self.EngageAltType or "RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, EngageSpeed, true)
|
||||||
EngageRoute[#EngageRoute+1] = ToWP
|
EngageRoute[#EngageRoute+1] = ToWP
|
||||||
|
|
||||||
-- TODO: A factor of * 3 this way too low. This causes the AI NOT to engage until very close or even merged sometimes. Some A2A missiles have a much longer range! Needs more frequent updates of the task!
|
-- TODO: A factor of * 3 this way too low. This causes the AI NOT to engage until very close or even merged sometimes. Some A2A missiles have a much longer range! Needs more frequent updates of the task!
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group}
|
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group}
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_AIR_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_PATROL process can be started using the **Start** event.
|
-- The AI_AIR_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_PATROL process can be started using the **Start** event.
|
||||||
@@ -309,7 +311,7 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
|||||||
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||||
local speedkmh=ToTargetSpeed
|
local speedkmh=ToTargetSpeed
|
||||||
|
|
||||||
local FromWP = CurrentCoord:WaypointAir(self.PatrolAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToTargetSpeed, true)
|
local FromWP = CurrentCoord:WaypointAir(self.PatrolAltType or "RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, ToTargetSpeed, true)
|
||||||
PatrolRoute[#PatrolRoute+1] = FromWP
|
PatrolRoute[#PatrolRoute+1] = FromWP
|
||||||
|
|
||||||
if self.racetrack then
|
if self.racetrack then
|
||||||
@@ -359,9 +361,9 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
|||||||
else
|
else
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local ToWP = ToTargetCoord:WaypointAir(self.PatrolAltType, POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToTargetSpeed, true)
|
local ToWP = ToTargetCoord:WaypointAir(self.PatrolAltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, ToTargetSpeed, true)
|
||||||
PatrolRoute[#PatrolRoute+1] = ToWP
|
PatrolRoute[#PatrolRoute+1] = ToWP
|
||||||
|
|
||||||
local Tasks = {}
|
local Tasks = {}
|
||||||
Tasks[#Tasks+1] = AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
Tasks[#Tasks+1] = AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
||||||
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
|
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- @type AI_AIR_SQUADRON
|
--- @type AI_AIR_SQUADRON
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -21,6 +21,8 @@
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -38,6 +38,8 @@
|
|||||||
|
|
||||||
--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
@@ -174,8 +176,7 @@ function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
-- @return #boolean Return false to cancel Transition.
|
-- @return #boolean Return false to cancel Transition.
|
||||||
|
|
||||||
--- OnAfter Transition Handler for Event Engage.
|
--- OnAfter Transition Handler for Event Engage.
|
||||||
@@ -522,12 +523,12 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
|
|
||||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
self.EngageSpeed,
|
self.EngageSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -578,13 +579,13 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
self:T2( ToTargetVec2 )
|
self:T2( ToTargetVec2 )
|
||||||
|
|
||||||
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
||||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
|
local ToTargetPointVec3 = COORDINATE:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
self.EngageSpeed,
|
self.EngageSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -33,8 +33,9 @@
|
|||||||
-- @field Wrapper.Group#GROUP Test
|
-- @field Wrapper.Group#GROUP Test
|
||||||
-- @extends Core.Fsm#FSM_SET
|
-- @extends Core.Fsm#FSM_SET
|
||||||
|
|
||||||
|
--- 
|
||||||
--- Monitors and manages as many replacement AI groups as there are
|
--
|
||||||
|
-- Monitors and manages as many replacement AI groups as there are
|
||||||
-- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players.
|
-- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players.
|
||||||
-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions.
|
-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions.
|
||||||
--
|
--
|
||||||
@@ -220,16 +221,9 @@ function AI_BALANCER:onenterReturning( SetGroup, From, Event, To, AIGroup )
|
|||||||
AIGroup:MessageToRed( "Returning to home base ...", 30 )
|
AIGroup:MessageToRed( "Returning to home base ...", 30 )
|
||||||
else
|
else
|
||||||
-- Okay, we need to send this Group back to the nearest base of the Coalition of the AI.
|
-- Okay, we need to send this Group back to the nearest base of the Coalition of the AI.
|
||||||
--TODO: i need to rework the POINT_VEC2 thing.
|
local PointVec2 = COORDINATE:New(AIGroup:GetVec2().x, 0, AIGroup:GetVec2().y)
|
||||||
local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y )
|
|
||||||
local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 )
|
local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 )
|
||||||
self:T( ClosestAirbase.AirbaseName )
|
self:T( ClosestAirbase.AirbaseName )
|
||||||
--[[
|
|
||||||
AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 )
|
|
||||||
local RTBRoute = AIGroup:RouteReturnToAirbase( ClosestAirbase )
|
|
||||||
AIGroupTemplate.route = RTBRoute
|
|
||||||
AIGroup:Respawn( AIGroupTemplate )
|
|
||||||
]]
|
|
||||||
AIGroup:RouteRTB(ClosestAirbase)
|
AIGroup:RouteRTB(ClosestAirbase)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,8 @@
|
|||||||
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}
|
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_CAP_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event.
|
-- The AI_CAP_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event.
|
||||||
@@ -423,12 +425,12 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
|||||||
|
|
||||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
ToEngageZoneSpeed,
|
ToEngageZoneSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -445,13 +447,13 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
|||||||
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
|
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
|
||||||
|
|
||||||
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
||||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
local ToTargetPointVec3 = COORDINATE:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
|
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
ToTargetSpeed,
|
ToTargetSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -38,6 +38,9 @@
|
|||||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||||
|
|
||||||
--- Implements the core functions to provide Close Air Support in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
--- Implements the core functions to provide Close Air Support in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
@@ -162,7 +165,6 @@ function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
-- @return #boolean Return false to cancel Transition.
|
-- @return #boolean Return false to cancel Transition.
|
||||||
|
|
||||||
--- OnAfter Transition Handler for Event Engage.
|
--- OnAfter Transition Handler for Event Engage.
|
||||||
@@ -466,12 +468,12 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
|
|
||||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
self.EngageSpeed,
|
self.EngageSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -508,13 +510,13 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
self:T2( ToTargetVec2 )
|
self:T2( ToTargetVec2 )
|
||||||
|
|
||||||
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
||||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
|
local ToTargetPointVec3 = COORDINATE:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
self.EngageSpeed,
|
self.EngageSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,12 +9,14 @@
|
|||||||
-- @module AI.AI_Cargo
|
-- @module AI.AI_Cargo
|
||||||
-- @image Cargo.JPG
|
-- @image Cargo.JPG
|
||||||
|
|
||||||
-- @type AI_CARGO
|
--- @type AI_CARGO
|
||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
|
|
||||||
--- Base class for the dynamic cargo handling capability for AI groups.
|
--- Base class for the dynamic cargo handling capability for AI groups.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
-- The AI_CARGO module uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
-- The AI_CARGO module uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
-- CARGO derived objects must be declared within the mission to make the AI_CARGO object recognize the cargo.
|
-- CARGO derived objects must be declared within the mission to make the AI_CARGO object recognize the cargo.
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
--- Brings a dynamic cargo handling capability for an AI vehicle group.
|
--- Brings a dynamic cargo handling capability for an AI vehicle group.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_APC class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
-- The AI_CARGO_APC class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
|
|
||||||
--- Brings a dynamic cargo handling capability for an AI airplane group.
|
--- Brings a dynamic cargo handling capability for an AI airplane group.
|
||||||
|
--
|
||||||
|
-- 
|
||||||
--
|
--
|
||||||
-- Airplane carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation between airbases.
|
-- Airplane carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation between airbases.
|
||||||
--
|
--
|
||||||
@@ -440,7 +442,7 @@ function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed, Height, Uncontrolled
|
|||||||
|
|
||||||
-- To point.
|
-- To point.
|
||||||
local AirbasePointVec2 = Airbase:GetPointVec2()
|
local AirbasePointVec2 = Airbase:GetPointVec2()
|
||||||
local ToWaypoint = AirbasePointVec2:WaypointAir(POINT_VEC3.RoutePointAltType.BARO, "Land", "Landing", Speed or Airplane:GetSpeedMax()*0.8, true, Airbase)
|
local ToWaypoint = AirbasePointVec2:WaypointAir(COORDINATE.WaypointAltType.BARO, "Land", "Landing", Speed or Airplane:GetSpeedMax()*0.8, true, Airbase)
|
||||||
|
|
||||||
--ToWaypoint["airdromeId"] = Airbase:GetID()
|
--ToWaypoint["airdromeId"] = Airbase:GetID()
|
||||||
--ToWaypoint["speed_locked"] = true
|
--ToWaypoint["speed_locked"] = true
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- # The dispatcher concept.
|
-- # The dispatcher concept.
|
||||||
--
|
--
|
||||||
-- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
--- A dynamic cargo transportation capability for AI groups.
|
--- A dynamic cargo transportation capability for AI groups.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_DISPATCHER_APC module is derived from the AI_CARGO_DISPATCHER module.
|
-- The AI_CARGO_DISPATCHER_APC module is derived from the AI_CARGO_DISPATCHER module.
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
--- Brings a dynamic cargo handling capability for AI groups.
|
--- Brings a dynamic cargo handling capability for AI groups.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_DISPATCHER_AIRPLANE module is derived from the AI_CARGO_DISPATCHER module.
|
-- The AI_CARGO_DISPATCHER_AIRPLANE module is derived from the AI_CARGO_DISPATCHER module.
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
--- A dynamic cargo handling capability for AI helicopter groups.
|
--- A dynamic cargo handling capability for AI helicopter groups.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
--- A dynamic cargo transportation capability for AI groups.
|
--- A dynamic cargo transportation capability for AI groups.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Naval vessels can be mobilized to semi-intelligently transport cargo within the simulation.
|
-- Naval vessels can be mobilized to semi-intelligently transport cargo within the simulation.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_DISPATCHER_SHIP module is derived from the AI_CARGO_DISPATCHER module.
|
-- The AI_CARGO_DISPATCHER_SHIP module is derived from the AI_CARGO_DISPATCHER module.
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
--- Brings a dynamic cargo handling capability for an AI helicopter group.
|
--- Brings a dynamic cargo handling capability for an AI helicopter group.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Helicopter carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Helicopter carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
-- The AI_CARGO_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
@@ -367,8 +369,8 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina
|
|||||||
-- local CoordinateFrom = Helicopter:GetCoordinate()
|
-- local CoordinateFrom = Helicopter:GetCoordinate()
|
||||||
-- local WaypointFrom = CoordinateFrom:WaypointAir(
|
-- local WaypointFrom = CoordinateFrom:WaypointAir(
|
||||||
-- "RADIO",
|
-- "RADIO",
|
||||||
-- POINT_VEC3.RoutePointType.TurningPoint,
|
-- COORDINATE.WaypointType.TurningPoint,
|
||||||
-- POINT_VEC3.RoutePointAction.TurningPoint,
|
-- COORDINATE.WaypointAction.TurningPoint,
|
||||||
-- Speed,
|
-- Speed,
|
||||||
-- true
|
-- true
|
||||||
-- )
|
-- )
|
||||||
@@ -380,8 +382,8 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina
|
|||||||
|
|
||||||
local WaypointTo = CoordinateTo:WaypointAir(
|
local WaypointTo = CoordinateTo:WaypointAir(
|
||||||
"RADIO",
|
"RADIO",
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
50,
|
50,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -427,7 +429,7 @@ function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordina
|
|||||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||||
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
||||||
|
|
||||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, 50, true)
|
local WaypointTo = CoordinateTo:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, 50, true)
|
||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
local Tasks = {}
|
local Tasks = {}
|
||||||
@@ -496,14 +498,14 @@ function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordin
|
|||||||
local CoordinateFrom = Helicopter:GetCoordinate()
|
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, _speed, true)
|
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, _speed, true)
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local CoordinateTo = Coordinate
|
local CoordinateTo = Coordinate
|
||||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||||
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
||||||
|
|
||||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,_speed, true)
|
local WaypointTo = CoordinateTo:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint,_speed, true)
|
||||||
|
|
||||||
Route[#Route+1] = WaypointFrom
|
Route[#Route+1] = WaypointFrom
|
||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
@@ -563,7 +565,7 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin
|
|||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local CoordinateFrom = Helicopter:GetCoordinate()
|
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||||
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, _speed, true)
|
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, _speed, true)
|
||||||
Route[#Route+1] = WaypointFrom
|
Route[#Route+1] = WaypointFrom
|
||||||
Route[#Route+1] = WaypointFrom
|
Route[#Route+1] = WaypointFrom
|
||||||
|
|
||||||
@@ -573,7 +575,7 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin
|
|||||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||||
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
||||||
|
|
||||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, _speed, true)
|
local WaypointTo = CoordinateTo:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, _speed, true)
|
||||||
|
|
||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
@@ -631,7 +633,7 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
|
|||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local CoordinateFrom = Helicopter:GetCoordinate()
|
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||||
|
|
||||||
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, Speed, true)
|
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed, true)
|
||||||
Route[#Route+1] = WaypointFrom
|
Route[#Route+1] = WaypointFrom
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
@@ -639,7 +641,7 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
|
|||||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||||
CoordinateTo.y = landheight + Height -- flight height should be 50m above ground
|
CoordinateTo.y = landheight + Height -- flight height should be 50m above ground
|
||||||
|
|
||||||
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, Speed, true)
|
local WaypointTo = CoordinateTo:WaypointAir("RADIO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed, true)
|
||||||
|
|
||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
--- Brings a dynamic cargo handling capability for an AI naval group.
|
--- Brings a dynamic cargo handling capability for an AI naval group.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Naval ships can be utilized to transport cargo around the map following naval shipping lanes.
|
-- Naval ships can be utilized to transport cargo around the map following naval shipping lanes.
|
||||||
-- The AI_CARGO_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
-- The AI_CARGO_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
-- @{Cargo.Cargo} must be declared within the mission or warehouse to make the AI_CARGO_SHIP recognize the cargo.
|
-- @{Cargo.Cargo} must be declared within the mission or warehouse to make the AI_CARGO_SHIP recognize the cargo.
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
--
|
--
|
||||||
-- Allows you to interact with escorting AI on your flight and take the lead.
|
-- Allows you to interact with escorting AI on your flight and take the lead.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
|
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
|
||||||
--
|
--
|
||||||
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
--- Models the assignment of AI escorts to player flights upon request using the radio menu.
|
--- Models the assignment of AI escorts to player flights upon request using the radio menu.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
--
|
--
|
||||||
-- Allows you to interact with escorting AI on your flight and take the lead.
|
-- Allows you to interact with escorting AI on your flight and take the lead.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
|
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
|
||||||
--
|
--
|
||||||
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
||||||
|
|||||||
@@ -40,6 +40,8 @@
|
|||||||
|
|
||||||
|
|
||||||
--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader.
|
--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader.
|
||||||
|
--
|
||||||
|
-- 
|
||||||
--
|
--
|
||||||
-- AI_FORMATION makes AI @{Wrapper.Group#GROUP}s fly in formation of various compositions.
|
-- AI_FORMATION makes AI @{Wrapper.Group#GROUP}s fly in formation of various compositions.
|
||||||
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
|
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
|
||||||
@@ -725,7 +727,7 @@ function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, X
|
|||||||
|
|
||||||
for FollowID, FollowGroup in pairs( FollowSet ) do
|
for FollowID, FollowGroup in pairs( FollowSet ) do
|
||||||
|
|
||||||
local PointVec3 = POINT_VEC3:New()
|
local PointVec3 = COORDINATE:New()
|
||||||
PointVec3:SetX( XStart + i * XSpace )
|
PointVec3:SetX( XStart + i * XSpace )
|
||||||
PointVec3:SetY( YStart + i * YSpace )
|
PointVec3:SetY( YStart + i * YSpace )
|
||||||
PointVec3:SetZ( ZStart + i * ZSpace )
|
PointVec3:SetZ( ZStart + i * ZSpace )
|
||||||
@@ -877,7 +879,7 @@ function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event ,
|
|||||||
|
|
||||||
for FollowID, FollowGroup in pairs( FollowSet ) do
|
for FollowID, FollowGroup in pairs( FollowSet ) do
|
||||||
|
|
||||||
local PointVec3 = POINT_VEC3:New()
|
local PointVec3 = COORDINATE:New()
|
||||||
|
|
||||||
local Side = ( i % 2 == 0 ) and 1 or -1
|
local Side = ( i % 2 == 0 ) and 1 or -1
|
||||||
local Row = i / 2 + 1
|
local Row = i / 2 + 1
|
||||||
@@ -936,7 +938,7 @@ function AI_FORMATION:onafterFormationBox( FollowGroupSet, From , Event , To, XS
|
|||||||
|
|
||||||
for FollowID, FollowGroup in pairs( FollowSet ) do
|
for FollowID, FollowGroup in pairs( FollowSet ) do
|
||||||
|
|
||||||
local PointVec3 = POINT_VEC3:New()
|
local PointVec3 = COORDINATE:New()
|
||||||
|
|
||||||
local ZIndex = i % ZLevels
|
local ZIndex = i % ZLevels
|
||||||
local XIndex = math.floor( i / ZLevels )
|
local XIndex = math.floor( i / ZLevels )
|
||||||
|
|||||||
@@ -48,6 +48,8 @@
|
|||||||
|
|
||||||
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
|
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_PATROL_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event.
|
-- The AI_PATROL_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event.
|
||||||
@@ -751,12 +753,12 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
if not CurrentVec2 then return end
|
if not CurrentVec2 then return end
|
||||||
--Done: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--Done: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TakeOffParking,
|
COORDINATE.WaypointType.TakeOffParking,
|
||||||
POINT_VEC3.RoutePointAction.FromParkingArea,
|
COORDINATE.WaypointAction.FromParkingArea,
|
||||||
ToPatrolZoneSpeed,
|
ToPatrolZoneSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -767,12 +769,12 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
if not CurrentVec2 then return end
|
if not CurrentVec2 then return end
|
||||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
ToPatrolZoneSpeed,
|
ToPatrolZoneSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -792,13 +794,13 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
|
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
|
||||||
|
|
||||||
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
||||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
local ToTargetPointVec3 = COORDINATE:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
ToTargetSpeed,
|
ToTargetSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
@@ -846,7 +848,6 @@ function AI_PATROL_ZONE:onafterStatus()
|
|||||||
OldAIControllable:SetTask( TimedOrbitTask, 10 )
|
OldAIControllable:SetTask( TimedOrbitTask, 10 )
|
||||||
|
|
||||||
RTB = true
|
RTB = true
|
||||||
else
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO: Check GROUP damage function.
|
-- TODO: Check GROUP damage function.
|
||||||
@@ -856,6 +857,16 @@ function AI_PATROL_ZONE:onafterStatus()
|
|||||||
RTB = true
|
RTB = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self:IsInstanceOf("AI_CAS") or self:IsInstanceOf("AI_BAI") then
|
||||||
|
local atotal,shells,rockets,bombs,missiles = self.Controllable:GetAmmunition()
|
||||||
|
local arelevant = rockets+bombs
|
||||||
|
if arelevant == 0 or missiles == 0 then
|
||||||
|
RTB = true
|
||||||
|
self:T({total=atotal,shells=shells,rockets=rockets,bombs=bombs,missiles=missiles})
|
||||||
|
self:T( self.Controllable:GetName() .. " is out of ammo, RTB!" )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if RTB == true then
|
if RTB == true then
|
||||||
self:RTB()
|
self:RTB()
|
||||||
else
|
else
|
||||||
@@ -881,12 +892,12 @@ function AI_PATROL_ZONE:onafterRTB()
|
|||||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
--local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
--local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = COORDINATE:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
COORDINATE.WaypointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
COORDINATE.WaypointAction.TurningPoint,
|
||||||
ToPatrolZoneSpeed,
|
ToPatrolZoneSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs.
|
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -8,9 +8,11 @@
|
|||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
do -- ACT_ACCOUNT
|
do -- ACT_ACCOUNT
|
||||||
|
|
||||||
--- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
--- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- ## ACT_ACCOUNT state machine:
|
-- ## ACT_ACCOUNT state machine:
|
||||||
--
|
--
|
||||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||||
@@ -133,7 +135,7 @@ do -- ACT_ACCOUNT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To, Event )
|
function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To )
|
||||||
|
|
||||||
self:__NoMore( 1 )
|
self:__NoMore( 1 )
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
--- (SP) (MP) (FSM) Accept or reject process for player (task) assignments.
|
--- (SP) (MP) (FSM) Accept or reject process for player (task) assignments.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
|
--
|
||||||
|
-- 
|
||||||
--
|
--
|
||||||
-- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS}
|
-- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS}
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
|
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
-- ## ACT_ASSIST state machine:
|
-- ## ACT_ASSIST state machine:
|
||||||
--
|
--
|
||||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
-- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||||
--
|
--
|
||||||
-- ## ACT_ROUTE state machine:
|
-- ## ACT_ROUTE state machine:
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- # 1) MOOSE Cargo System.
|
-- # 1) MOOSE Cargo System.
|
||||||
--
|
--
|
||||||
-- #### Those who have used the mission editor, know that the DCS mission editor provides cargo facilities.
|
-- #### Those who have used the mission editor, know that the DCS mission editor provides cargo facilities.
|
||||||
@@ -275,14 +277,14 @@
|
|||||||
-- The cargo must be in the **Loaded** state.
|
-- The cargo must be in the **Loaded** state.
|
||||||
-- @function [parent=#CARGO] UnBoard
|
-- @function [parent=#CARGO] UnBoard
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
|
-- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
|
||||||
|
|
||||||
--- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier.
|
--- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier.
|
||||||
-- The cargo must be in the **Loaded** state.
|
-- The cargo must be in the **Loaded** state.
|
||||||
-- @function [parent=#CARGO] __UnBoard
|
-- @function [parent=#CARGO] __UnBoard
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #number DelaySeconds The amount of seconds to delay the action.
|
-- @param #number DelaySeconds The amount of seconds to delay the action.
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
|
-- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location.
|
||||||
|
|
||||||
|
|
||||||
-- Load
|
-- Load
|
||||||
@@ -307,14 +309,14 @@
|
|||||||
-- The cargo must be in the **Loaded** state.
|
-- The cargo must be in the **Loaded** state.
|
||||||
-- @function [parent=#CARGO] UnLoad
|
-- @function [parent=#CARGO] UnLoad
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
|
-- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
|
||||||
|
|
||||||
--- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading.
|
--- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading.
|
||||||
-- The cargo must be in the **Loaded** state.
|
-- The cargo must be in the **Loaded** state.
|
||||||
-- @function [parent=#CARGO] __UnLoad
|
-- @function [parent=#CARGO] __UnLoad
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #number DelaySeconds The amount of seconds to delay the action.
|
-- @param #number DelaySeconds The amount of seconds to delay the action.
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2 (optional) @{Core.Point#POINT_VEC2) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
|
-- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location.
|
||||||
|
|
||||||
-- State Transition Functions
|
-- State Transition Functions
|
||||||
|
|
||||||
@@ -467,7 +469,7 @@ do -- CARGO
|
|||||||
self.Type = Type
|
self.Type = Type
|
||||||
self.Name = Name
|
self.Name = Name
|
||||||
self.Weight = Weight or 0
|
self.Weight = Weight or 0
|
||||||
self.CargoObject = nil
|
self.CargoObject = nil -- Wrapper.Group#GROUP
|
||||||
self.CargoCarrier = nil -- Wrapper.Client#CLIENT
|
self.CargoCarrier = nil -- Wrapper.Client#CLIENT
|
||||||
self.Representable = false
|
self.Representable = false
|
||||||
self.Slingloadable = false
|
self.Slingloadable = false
|
||||||
@@ -897,7 +899,7 @@ do -- CARGO
|
|||||||
|
|
||||||
--- Get the current PointVec2 of the cargo.
|
--- Get the current PointVec2 of the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return Core.Point#POINT_VEC2
|
-- @return Core.Point#COORDINATE
|
||||||
function CARGO:GetPointVec2()
|
function CARGO:GetPointVec2()
|
||||||
return self.CargoObject:GetPointVec2()
|
return self.CargoObject:GetPointVec2()
|
||||||
end
|
end
|
||||||
@@ -1094,7 +1096,7 @@ do -- CARGO_REPRESENTABLE
|
|||||||
|
|
||||||
--- Route a cargo unit to a PointVec2.
|
--- Route a cargo unit to a PointVec2.
|
||||||
-- @param #CARGO_REPRESENTABLE self
|
-- @param #CARGO_REPRESENTABLE self
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
-- @param Core.Point#COORDINATE ToPointVec2
|
||||||
-- @param #number Speed
|
-- @param #number Speed
|
||||||
-- @return #CARGO_REPRESENTABLE
|
-- @return #CARGO_REPRESENTABLE
|
||||||
function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed )
|
function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed )
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ do -- CARGO_CRATE
|
|||||||
-- @type CARGO_CRATE
|
-- @type CARGO_CRATE
|
||||||
-- @extends Cargo.Cargo#CARGO_REPRESENTABLE
|
-- @extends Cargo.Cargo#CARGO_REPRESENTABLE
|
||||||
|
|
||||||
|
---
|
||||||
|
-- 
|
||||||
|
--
|
||||||
--- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
|
--- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
|
||||||
-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers.
|
-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers.
|
||||||
--
|
--
|
||||||
@@ -114,7 +117,7 @@ do -- CARGO_CRATE
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2
|
-- @param Core.Point#COORDINATE
|
||||||
function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 )
|
function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 )
|
||||||
--self:T( { ToPointVec2, From, Event, To } )
|
--self:T( { ToPointVec2, From, Event, To } )
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,12 @@ do -- CARGO_GROUP
|
|||||||
--- @type CARGO_GROUP
|
--- @type CARGO_GROUP
|
||||||
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
|
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
|
||||||
-- @field #string GroupName The name of the CargoGroup.
|
-- @field #string GroupName The name of the CargoGroup.
|
||||||
|
-- @field Wrapper.Group#GROUÜ CargoCarrier The carrier group.
|
||||||
-- @extends Cargo.Cargo#CARGO_REPORTABLE
|
-- @extends Cargo.Cargo#CARGO_REPORTABLE
|
||||||
|
|
||||||
--- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator.
|
--- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator.
|
||||||
|
--
|
||||||
|
-- 
|
||||||
-- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers.
|
-- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers.
|
||||||
--
|
--
|
||||||
-- The above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo:
|
-- The above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo:
|
||||||
@@ -410,7 +413,7 @@ do -- CARGO_GROUP
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
-- @param Core.Point#COORDINATE ToPointVec2
|
||||||
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||||
function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... )
|
function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... )
|
||||||
self:T( {From, Event, To, ToPointVec2, NearRadius } )
|
self:T( {From, Event, To, ToPointVec2, NearRadius } )
|
||||||
@@ -453,7 +456,7 @@ do -- CARGO_GROUP
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
-- @param Core.Point#COORDINATE ToPointVec2
|
||||||
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||||
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
|
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
|
||||||
--self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
--self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||||
@@ -491,7 +494,7 @@ do -- CARGO_GROUP
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
-- @param Core.Point#COORDINATE ToPointVec2
|
||||||
function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... )
|
function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... )
|
||||||
--self:T( { From, Event, To, ToPointVec2 } )
|
--self:T( { From, Event, To, ToPointVec2 } )
|
||||||
|
|
||||||
@@ -771,3 +774,4 @@ do -- CARGO_GROUP
|
|||||||
|
|
||||||
|
|
||||||
end -- CARGO_GROUP
|
end -- CARGO_GROUP
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ do -- CARGO_SLINGLOAD
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ do -- CARGO_UNIT
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
@@ -72,7 +74,7 @@ do -- CARGO_UNIT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
-- @param Core.Point#COORDINATE ToPointVec2
|
||||||
-- @param #number NearRadius (optional) Defaut 25 m.
|
-- @param #number NearRadius (optional) Defaut 25 m.
|
||||||
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||||
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||||
@@ -145,7 +147,7 @@ do -- CARGO_UNIT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
-- @param Core.Point#COORDINATE ToPointVec2
|
||||||
-- @param #number NearRadius (optional) Defaut 100 m.
|
-- @param #number NearRadius (optional) Defaut 100 m.
|
||||||
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||||
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||||
@@ -171,7 +173,7 @@ do -- CARGO_UNIT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
-- @param Core.Point#COORDINATE ToPointVec2
|
||||||
-- @param #number NearRadius (optional) Defaut 100 m.
|
-- @param #number NearRadius (optional) Defaut 100 m.
|
||||||
function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||||
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||||
@@ -197,7 +199,7 @@ do -- CARGO_UNIT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2
|
-- @param Core.Point#COORDINATE
|
||||||
function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
|
function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
|
||||||
self:T( { ToPointVec2, From, Event, To } )
|
self:T( { ToPointVec2, From, Event, To } )
|
||||||
|
|
||||||
|
|||||||
@@ -34,11 +34,12 @@ local _TraceClassMethod = {}
|
|||||||
|
|
||||||
local _ClassID = 0
|
local _ClassID = 0
|
||||||
|
|
||||||
---
|
--- Base class of everything
|
||||||
-- @type BASE
|
-- @type BASE
|
||||||
-- @field ClassName The name of the class.
|
-- @field #string ClassName The name of the class.
|
||||||
-- @field ClassID The ID number of the class.
|
-- @field #number ClassID The ID number of the class.
|
||||||
-- @field ClassNameAndID The name of the class concatenated with the ID number of the class.
|
-- @field #string ClassNameAndID The name of the class concatenated with the ID number of the class.
|
||||||
|
-- @field Core.Scheduler#SCHEDULER Scheduler The scheduler object.
|
||||||
|
|
||||||
--- BASE class
|
--- BASE class
|
||||||
--
|
--
|
||||||
@@ -200,6 +201,7 @@ BASE = {
|
|||||||
States = {},
|
States = {},
|
||||||
Debug = debug,
|
Debug = debug,
|
||||||
Scheduler = nil,
|
Scheduler = nil,
|
||||||
|
Properties = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
-- @field #BASE.__
|
-- @field #BASE.__
|
||||||
@@ -210,14 +212,6 @@ BASE._ = {
|
|||||||
Schedules = {}, --- Contains the Schedulers Active
|
Schedules = {}, --- Contains the Schedulers Active
|
||||||
}
|
}
|
||||||
|
|
||||||
--- The Formation Class
|
|
||||||
-- @type FORMATION
|
|
||||||
-- @field Cone A cone formation.
|
|
||||||
FORMATION = {
|
|
||||||
Cone = "Cone",
|
|
||||||
Vee = "Vee",
|
|
||||||
}
|
|
||||||
|
|
||||||
--- BASE constructor.
|
--- BASE constructor.
|
||||||
--
|
--
|
||||||
-- This is an example how to use the BASE:New() constructor in a new class definition when inheriting from BASE.
|
-- This is an example how to use the BASE:New() constructor in a new class definition when inheriting from BASE.
|
||||||
@@ -980,7 +974,7 @@ do -- Scheduling
|
|||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
||||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
||||||
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
-- @param ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||||
-- @return #string The Schedule ID of the planned schedule.
|
-- @return #string The Schedule ID of the planned schedule.
|
||||||
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
||||||
|
|
||||||
@@ -1116,6 +1110,31 @@ function BASE:ClearState( Object, StateName )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set one property of an object.
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Key The key that is used as a reference of the value. Note that the key can be a #string, but it can also be any other type!
|
||||||
|
-- @param Value The value that is stored. Note that the value can be a #string, but it can also be any other type!
|
||||||
|
function BASE:SetProperty(Key,Value)
|
||||||
|
self.Properties = self.Properties or {}
|
||||||
|
self.Properties[Key] = Value
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get one property of an object by the key.
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Key The key that is used as a reference of the value. Note that the key can be a #string, but it can also be any other type!
|
||||||
|
-- @return Value The value that is stored. Note that the value can be a #string, but it can also be any other type! Nil if not found.
|
||||||
|
function BASE:GetProperty(Key)
|
||||||
|
self.Properties = self.Properties or {}
|
||||||
|
return self.Properties[Key]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get all of the properties of an object in a table.
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @return #table of values, indexed by keys.
|
||||||
|
function BASE:GetProperties()
|
||||||
|
return self.Properties
|
||||||
|
end
|
||||||
|
|
||||||
-- Trace section
|
-- Trace section
|
||||||
|
|
||||||
-- Log a trace (only shown when trace is on)
|
-- Log a trace (only shown when trace is on)
|
||||||
@@ -1416,7 +1435,7 @@ function BASE:E( Arguments )
|
|||||||
|
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
||||||
else
|
else
|
||||||
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, BASE:_Serialize(Arguments) ) )
|
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, UTILS.BasicSerialize(Arguments) ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1443,8 +1462,7 @@ function BASE:I( Arguments )
|
|||||||
|
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
||||||
else
|
else
|
||||||
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, BASE:_Serialize(Arguments)) )
|
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, UTILS.BasicSerialize(Arguments)) )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
--
|
--
|
||||||
-- @module Core.ClientMenu
|
-- @module Core.ClientMenu
|
||||||
-- @image Core_Menu.JPG
|
-- @image Core_Menu.JPG
|
||||||
-- last change: May 2024
|
-- last change: Jan 2025
|
||||||
|
|
||||||
-- TODO
|
-- TODO
|
||||||
----------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------
|
||||||
@@ -57,9 +57,9 @@
|
|||||||
---
|
---
|
||||||
-- @field #CLIENTMENU
|
-- @field #CLIENTMENU
|
||||||
CLIENTMENU = {
|
CLIENTMENU = {
|
||||||
ClassName = "CLIENTMENUE",
|
ClassName = "CLIENTMENU",
|
||||||
lid = "",
|
lid = "",
|
||||||
version = "0.1.2",
|
version = "0.1.3",
|
||||||
name = nil,
|
name = nil,
|
||||||
path = nil,
|
path = nil,
|
||||||
group = nil,
|
group = nil,
|
||||||
@@ -455,7 +455,7 @@ end
|
|||||||
-- @param #CLIENTMENUMANAGER self
|
-- @param #CLIENTMENUMANAGER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
-- @return #CLIENTMENUMANAGER self
|
-- @return #CLIENTMENUMANAGER self
|
||||||
function CLIENTMENUMANAGER:_EventHandler(EventData)
|
function CLIENTMENUMANAGER:_EventHandler(EventData,Retry)
|
||||||
self:T(self.lid.."_EventHandler: "..EventData.id)
|
self:T(self.lid.."_EventHandler: "..EventData.id)
|
||||||
--self:I(self.lid.."_EventHandler: "..tostring(EventData.IniPlayerName))
|
--self:I(self.lid.."_EventHandler: "..tostring(EventData.IniPlayerName))
|
||||||
if EventData.id == EVENTS.PlayerLeaveUnit or EventData.id == EVENTS.Ejection or EventData.id == EVENTS.Crash or EventData.id == EVENTS.PilotDead then
|
if EventData.id == EVENTS.PlayerLeaveUnit or EventData.id == EVENTS.Ejection or EventData.id == EVENTS.Crash or EventData.id == EVENTS.PilotDead then
|
||||||
@@ -468,6 +468,10 @@ function CLIENTMENUMANAGER:_EventHandler(EventData)
|
|||||||
if EventData.IniPlayerName and EventData.IniGroup then
|
if EventData.IniPlayerName and EventData.IniGroup then
|
||||||
if (not self.clientset:IsIncludeObject(_DATABASE:FindClient( EventData.IniUnitName ))) then
|
if (not self.clientset:IsIncludeObject(_DATABASE:FindClient( EventData.IniUnitName ))) then
|
||||||
self:T(self.lid.."Client not in SET: "..EventData.IniPlayerName)
|
self:T(self.lid.."Client not in SET: "..EventData.IniPlayerName)
|
||||||
|
if not Retry then
|
||||||
|
-- try again in 2 secs
|
||||||
|
self:ScheduleOnce(2,CLIENTMENUMANAGER._EventHandler,self,EventData,true)
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
--self:I(self.lid.."Join event for player: "..EventData.IniPlayerName)
|
--self:I(self.lid.."Join event for player: "..EventData.IniPlayerName)
|
||||||
@@ -524,7 +528,7 @@ function CLIENTMENUMANAGER:InitAutoPropagation()
|
|||||||
self:HandleEvent(EVENTS.PilotDead, self._EventHandler)
|
self:HandleEvent(EVENTS.PilotDead, self._EventHandler)
|
||||||
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
|
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
|
||||||
self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler)
|
self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler)
|
||||||
self:SetEventPriority(5)
|
self:SetEventPriority(6)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -211,10 +211,9 @@ function DATABASE:AddStatic( DCSStaticName )
|
|||||||
|
|
||||||
if not self.STATICS[DCSStaticName] then
|
if not self.STATICS[DCSStaticName] then
|
||||||
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
|
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
|
||||||
return self.STATICS[DCSStaticName]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return self.STATICS[DCSStaticName]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -224,12 +223,11 @@ function DATABASE:DeleteStatic( DCSStaticName )
|
|||||||
self.STATICS[DCSStaticName] = nil
|
self.STATICS[DCSStaticName] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Finds a STATIC based on the StaticName.
|
--- Finds a STATIC based on the Static Name.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param #string StaticName
|
-- @param #string StaticName Name of the static object.
|
||||||
-- @return Wrapper.Static#STATIC The found STATIC.
|
-- @return Wrapper.Static#STATIC The found STATIC.
|
||||||
function DATABASE:FindStatic( StaticName )
|
function DATABASE:FindStatic( StaticName )
|
||||||
|
|
||||||
local StaticFound = self.STATICS[StaticName]
|
local StaticFound = self.STATICS[StaticName]
|
||||||
return StaticFound
|
return StaticFound
|
||||||
end
|
end
|
||||||
@@ -241,9 +239,8 @@ end
|
|||||||
function DATABASE:AddDynamicCargo( Name )
|
function DATABASE:AddDynamicCargo( Name )
|
||||||
if not self.DYNAMICCARGO[Name] then
|
if not self.DYNAMICCARGO[Name] then
|
||||||
self.DYNAMICCARGO[Name] = DYNAMICCARGO:Register(Name)
|
self.DYNAMICCARGO[Name] = DYNAMICCARGO:Register(Name)
|
||||||
return self.DYNAMICCARGO[Name]
|
|
||||||
end
|
end
|
||||||
return nil
|
return self.DYNAMICCARGO[Name]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Finds a DYNAMICCARGO based on the Dynamic Cargo Name.
|
--- Finds a DYNAMICCARGO based on the Dynamic Cargo Name.
|
||||||
@@ -875,6 +872,8 @@ end
|
|||||||
-- @return Wrapper.Group#GROUP The found GROUP.
|
-- @return Wrapper.Group#GROUP The found GROUP.
|
||||||
function DATABASE:FindGroup( GroupName )
|
function DATABASE:FindGroup( GroupName )
|
||||||
|
|
||||||
|
if type(GroupName) ~= "string" or GroupName == "" then return end
|
||||||
|
|
||||||
local GroupFound = self.GROUPS[GroupName]
|
local GroupFound = self.GROUPS[GroupName]
|
||||||
|
|
||||||
if GroupFound == nil and GroupName ~= nil and self.Templates.Groups[GroupName] == nil then
|
if GroupFound == nil and GroupName ~= nil and self.Templates.Groups[GroupName] == nil then
|
||||||
@@ -1113,7 +1112,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
|||||||
self:E("WARNING: Invalid STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
self:E("WARNING: Invalid STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||||
else
|
else
|
||||||
self.STNS[stn] = UnitTemplate.name
|
self.STNS[stn] = UnitTemplate.name
|
||||||
self:I("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
self:T("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if UnitTemplate.AddPropAircraft.SADL_TN then
|
if UnitTemplate.AddPropAircraft.SADL_TN then
|
||||||
@@ -1122,7 +1121,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
|||||||
self:E("WARNING: Invalid SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
self:E("WARNING: Invalid SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||||
else
|
else
|
||||||
self.SADL[sadl] = UnitTemplate.name
|
self.SADL[sadl] = UnitTemplate.name
|
||||||
self:I("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
self:T("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1383,7 +1382,7 @@ function DATABASE:GetCoalitionFromClientTemplate( ClientName )
|
|||||||
if self.Templates.ClientsByName[ClientName] then
|
if self.Templates.ClientsByName[ClientName] then
|
||||||
return self.Templates.ClientsByName[ClientName].CoalitionID
|
return self.Templates.ClientsByName[ClientName].CoalitionID
|
||||||
end
|
end
|
||||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1395,7 +1394,7 @@ function DATABASE:GetCategoryFromClientTemplate( ClientName )
|
|||||||
if self.Templates.ClientsByName[ClientName] then
|
if self.Templates.ClientsByName[ClientName] then
|
||||||
return self.Templates.ClientsByName[ClientName].CategoryID
|
return self.Templates.ClientsByName[ClientName].CategoryID
|
||||||
end
|
end
|
||||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1407,7 +1406,7 @@ function DATABASE:GetCountryFromClientTemplate( ClientName )
|
|||||||
if self.Templates.ClientsByName[ClientName] then
|
if self.Templates.ClientsByName[ClientName] then
|
||||||
return self.Templates.ClientsByName[ClientName].CountryID
|
return self.Templates.ClientsByName[ClientName].CountryID
|
||||||
end
|
end
|
||||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1582,12 +1581,29 @@ end
|
|||||||
-- @param DCS#Airbase airbase Airbase.
|
-- @param DCS#Airbase airbase Airbase.
|
||||||
-- @return #DATABASE self
|
-- @return #DATABASE self
|
||||||
function DATABASE:_RegisterAirbase(airbase)
|
function DATABASE:_RegisterAirbase(airbase)
|
||||||
|
|
||||||
|
local IsSyria = UTILS.GetDCSMap() == "Syria" and true or false
|
||||||
|
local countHSyria = 0
|
||||||
|
|
||||||
if airbase then
|
if airbase then
|
||||||
|
|
||||||
-- Get the airbase name.
|
-- Get the airbase name.
|
||||||
local DCSAirbaseName = airbase:getName()
|
local DCSAirbaseName = airbase:getName()
|
||||||
|
|
||||||
|
-- DCS 2.9.8.1107 added 143 helipads all named H with the same object ID ..
|
||||||
|
if IsSyria and DCSAirbaseName == "H" and countHSyria > 0 then
|
||||||
|
--[[
|
||||||
|
local p = airbase:getPosition().p
|
||||||
|
local mgrs = COORDINATE:New(p.x,p.z,p.y):ToStringMGRS()
|
||||||
|
self:I("Airbase on Syria map named H @ "..mgrs)
|
||||||
|
countHSyria = countHSyria + 1
|
||||||
|
if countHSyria > 1 then return self end
|
||||||
|
--]]
|
||||||
|
return self
|
||||||
|
elseif IsSyria and DCSAirbaseName == "H" and countHSyria == 0 then
|
||||||
|
countHSyria = countHSyria + 1
|
||||||
|
end
|
||||||
|
|
||||||
-- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
|
-- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
|
||||||
local airbaseID=airbase:getID()
|
local airbaseID=airbase:getID()
|
||||||
|
|
||||||
@@ -1683,7 +1699,7 @@ function DATABASE:_EventOnBirth( Event )
|
|||||||
if PlayerName then
|
if PlayerName then
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:I(string.format("Player '%s' joined unit '%s' of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniDCSGroupName)))
|
self:I(string.format("Player '%s' joined unit '%s' (%s) of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniTypeName), tostring(Event.IniDCSGroupName)))
|
||||||
|
|
||||||
-- Add client in case it does not exist already.
|
-- Add client in case it does not exist already.
|
||||||
if client == nil or (client and client:CountPlayers() == 0) then
|
if client == nil or (client and client:CountPlayers() == 0) then
|
||||||
|
|||||||
@@ -1329,6 +1329,7 @@ function EVENT:onEvent( Event )
|
|||||||
end
|
end
|
||||||
|
|
||||||
Event.IniDCSGroupName = Event.IniUnit and Event.IniUnit.GroupName or ""
|
Event.IniDCSGroupName = Event.IniUnit and Event.IniUnit.GroupName or ""
|
||||||
|
Event.IniGroupName=Event.IniDCSGroupName --At least set the group name because group might not exist any more
|
||||||
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
|
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
|
||||||
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
|
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
|
||||||
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
||||||
@@ -1371,11 +1372,12 @@ function EVENT:onEvent( Event )
|
|||||||
-- Scenery
|
-- Scenery
|
||||||
---
|
---
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
Event.IniDCSUnitName = ( Event.IniDCSUnit and Event.IniDCSUnit.getName ) and Event.IniDCSUnit:getName() or "Scenery no name "..math.random(1,20000)
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
||||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
Event.IniCategory = (Event.IniDCSUnit and Event.IniDCSUnit.getDesc ) and Event.IniDCSUnit:getDesc().category
|
||||||
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY"
|
Event.IniTypeName = (Event.initiator and Event.initiator.isExist
|
||||||
|
and Event.initiator:isExist() and Event.IniDCSUnit and Event.IniDCSUnit.getTypeName) and Event.IniDCSUnit:getTypeName() or "SCENERY"
|
||||||
|
|
||||||
elseif Event.IniObjectCategory == Object.Category.BASE then
|
elseif Event.IniObjectCategory == Object.Category.BASE then
|
||||||
---
|
---
|
||||||
@@ -1473,11 +1475,13 @@ function EVENT:onEvent( Event )
|
|||||||
-- SCENERY
|
-- SCENERY
|
||||||
---
|
---
|
||||||
Event.TgtDCSUnit = Event.target
|
Event.TgtDCSUnit = Event.target
|
||||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
Event.TgtDCSUnitName = Event.TgtDCSUnit.getName and Event.TgtDCSUnit.getName() or nil
|
||||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
if Event.TgtDCSUnitName~=nil then
|
||||||
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
|
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
|
||||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||||
|
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -948,7 +948,8 @@ do -- FSM
|
|||||||
end
|
end
|
||||||
|
|
||||||
do -- FSM_CONTROLLABLE
|
do -- FSM_CONTROLLABLE
|
||||||
|
|
||||||
|
---
|
||||||
-- @type FSM_CONTROLLABLE
|
-- @type FSM_CONTROLLABLE
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
@@ -1081,7 +1082,8 @@ do -- FSM_CONTROLLABLE
|
|||||||
end
|
end
|
||||||
|
|
||||||
do -- FSM_PROCESS
|
do -- FSM_PROCESS
|
||||||
|
|
||||||
|
---
|
||||||
-- @type FSM_PROCESS
|
-- @type FSM_PROCESS
|
||||||
-- @field Tasking.Task#TASK Task
|
-- @field Tasking.Task#TASK Task
|
||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ MARKEROPS_BASE = {
|
|||||||
ClassName = "MARKEROPS",
|
ClassName = "MARKEROPS",
|
||||||
Tag = "mytag",
|
Tag = "mytag",
|
||||||
Keywords = {},
|
Keywords = {},
|
||||||
version = "0.1.3",
|
version = "0.1.4",
|
||||||
debug = false,
|
debug = false,
|
||||||
Casesensitive = true,
|
Casesensitive = true,
|
||||||
}
|
}
|
||||||
@@ -108,26 +108,30 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
|||||||
--- On after "MarkAdded" event. Triggered when a Marker is added to the F10 map.
|
--- On after "MarkAdded" event. Triggered when a Marker is added to the F10 map.
|
||||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded
|
||||||
-- @param #MARKEROPS_BASE self
|
-- @param #MARKEROPS_BASE self
|
||||||
-- @param #string From The From state
|
-- @param #string From The From state.
|
||||||
-- @param #string Event The Event called
|
-- @param #string Event The Event called.
|
||||||
-- @param #string To The To state
|
-- @param #string To The To state.
|
||||||
-- @param #string Text The text on the marker
|
-- @param #string Text The text on the marker.
|
||||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
-- @param #table Keywords Table of matching keywords found in the Event text.
|
||||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
-- @param #number MarkerID Id of this marker
|
-- @param #number MarkerID Id of this marker.
|
||||||
-- @param #number CoalitionNumber Coalition of the marker creator
|
-- @param #number CoalitionNumber Coalition of the marker creator.
|
||||||
|
-- @param #string PlayerName Name of the player creating/changing the mark. nil if it cannot be obtained.
|
||||||
|
-- @param Core.Event#EVENTDATA EventData the event data table.
|
||||||
|
|
||||||
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
||||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
|
||||||
-- @param #MARKEROPS_BASE self
|
-- @param #MARKEROPS_BASE self
|
||||||
-- @param #string From The From state
|
-- @param #string From The From state.
|
||||||
-- @param #string Event The Event called
|
-- @param #string Event The Event called.
|
||||||
-- @param #string To The To state
|
-- @param #string To The To state.
|
||||||
-- @param #string Text The text on the marker
|
-- @param #string Text The text on the marker.
|
||||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
-- @param #table Keywords Table of matching keywords found in the Event text.
|
||||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
-- @param #number MarkerID Id of this marker
|
-- @param #number MarkerID Id of this marker.
|
||||||
-- @param #number CoalitionNumber Coalition of the marker creator
|
-- @param #number CoalitionNumber Coalition of the marker creator.
|
||||||
|
-- @param #string PlayerName Name of the player creating/changing the mark. nil if it cannot be obtained.
|
||||||
|
-- @param Core.Event#EVENTDATA EventData the event data table
|
||||||
|
|
||||||
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
|
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
|
||||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
|
||||||
@@ -150,14 +154,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
|||||||
self:E("Skipping onEvent. Event or Event.idx unknown.")
|
self:E("Skipping onEvent. Event or Event.idx unknown.")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
--position
|
|
||||||
local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}
|
|
||||||
local coord=COORDINATE:NewFromVec3(vec3)
|
|
||||||
if self.debug then
|
|
||||||
local coordtext = coord:ToStringLLDDM()
|
|
||||||
local text = tostring(Event.text)
|
|
||||||
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
|
||||||
end
|
|
||||||
local coalition = Event.MarkCoalition
|
local coalition = Event.MarkCoalition
|
||||||
-- decision
|
-- decision
|
||||||
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
||||||
@@ -166,8 +163,14 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
|||||||
local Eventtext = tostring(Event.text)
|
local Eventtext = tostring(Event.text)
|
||||||
if Eventtext~=nil then
|
if Eventtext~=nil then
|
||||||
if self:_MatchTag(Eventtext) then
|
if self:_MatchTag(Eventtext) then
|
||||||
local matchtable = self:_MatchKeywords(Eventtext)
|
local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z})
|
||||||
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition)
|
if self.debug then
|
||||||
|
local coordtext = coord:ToStringLLDDM()
|
||||||
|
local text = tostring(Event.text)
|
||||||
|
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||||
|
end
|
||||||
|
local matchtable = self:_MatchKeywords(Eventtext)
|
||||||
|
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
||||||
@@ -176,8 +179,14 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
|||||||
local Eventtext = tostring(Event.text)
|
local Eventtext = tostring(Event.text)
|
||||||
if Eventtext~=nil then
|
if Eventtext~=nil then
|
||||||
if self:_MatchTag(Eventtext) then
|
if self:_MatchTag(Eventtext) then
|
||||||
local matchtable = self:_MatchKeywords(Eventtext)
|
local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z})
|
||||||
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition)
|
if self.debug then
|
||||||
|
local coordtext = coord:ToStringLLDDM()
|
||||||
|
local text = tostring(Event.text)
|
||||||
|
local m = MESSAGE:New(string.format("Mark changed at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||||
|
end
|
||||||
|
local matchtable = self:_MatchKeywords(Eventtext)
|
||||||
|
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ function MENU_INDEX:PrepareCoalition( CoalitionSide )
|
|||||||
self.Coalition[CoalitionSide] = self.Coalition[CoalitionSide] or {}
|
self.Coalition[CoalitionSide] = self.Coalition[CoalitionSide] or {}
|
||||||
self.Coalition[CoalitionSide].Menus = self.Coalition[CoalitionSide].Menus or {}
|
self.Coalition[CoalitionSide].Menus = self.Coalition[CoalitionSide].Menus or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @param Wrapper.Group#GROUP Group
|
-- @param Wrapper.Group#GROUP Group
|
||||||
function MENU_INDEX:PrepareGroup( Group )
|
function MENU_INDEX:PrepareGroup( Group )
|
||||||
@@ -118,9 +119,11 @@ end
|
|||||||
function MENU_INDEX:HasMissionMenu( Path )
|
function MENU_INDEX:HasMissionMenu( Path )
|
||||||
return self.MenuMission.Menus[Path]
|
return self.MenuMission.Menus[Path]
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:SetMissionMenu( Path, Menu )
|
function MENU_INDEX:SetMissionMenu( Path, Menu )
|
||||||
self.MenuMission.Menus[Path] = Menu
|
self.MenuMission.Menus[Path] = Menu
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:ClearMissionMenu( Path )
|
function MENU_INDEX:ClearMissionMenu( Path )
|
||||||
self.MenuMission.Menus[Path] = nil
|
self.MenuMission.Menus[Path] = nil
|
||||||
end
|
end
|
||||||
@@ -128,9 +131,11 @@ end
|
|||||||
function MENU_INDEX:HasCoalitionMenu( Coalition, Path )
|
function MENU_INDEX:HasCoalitionMenu( Coalition, Path )
|
||||||
return self.Coalition[Coalition].Menus[Path]
|
return self.Coalition[Coalition].Menus[Path]
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:SetCoalitionMenu( Coalition, Path, Menu )
|
function MENU_INDEX:SetCoalitionMenu( Coalition, Path, Menu )
|
||||||
self.Coalition[Coalition].Menus[Path] = Menu
|
self.Coalition[Coalition].Menus[Path] = Menu
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:ClearCoalitionMenu( Coalition, Path )
|
function MENU_INDEX:ClearCoalitionMenu( Coalition, Path )
|
||||||
self.Coalition[Coalition].Menus[Path] = nil
|
self.Coalition[Coalition].Menus[Path] = nil
|
||||||
end
|
end
|
||||||
@@ -138,19 +143,24 @@ end
|
|||||||
function MENU_INDEX:HasGroupMenu( Group, Path )
|
function MENU_INDEX:HasGroupMenu( Group, Path )
|
||||||
if Group and Group:IsAlive() then
|
if Group and Group:IsAlive() then
|
||||||
local MenuGroupName = Group:GetName()
|
local MenuGroupName = Group:GetName()
|
||||||
return self.Group[MenuGroupName].Menus[Path]
|
if self.Group[MenuGroupName] and self.Group[MenuGroupName].Menus and self.Group[MenuGroupName].Menus[Path] then
|
||||||
|
return self.Group[MenuGroupName].Menus[Path]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:SetGroupMenu( Group, Path, Menu )
|
function MENU_INDEX:SetGroupMenu( Group, Path, Menu )
|
||||||
local MenuGroupName = Group:GetName()
|
local MenuGroupName = Group:GetName()
|
||||||
Group:F({MenuGroupName=MenuGroupName,Path=Path})
|
--Group:F({MenuGroupName=MenuGroupName,Path=Path})
|
||||||
self.Group[MenuGroupName].Menus[Path] = Menu
|
self.Group[MenuGroupName].Menus[Path] = Menu
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:ClearGroupMenu( Group, Path )
|
function MENU_INDEX:ClearGroupMenu( Group, Path )
|
||||||
local MenuGroupName = Group:GetName()
|
local MenuGroupName = Group:GetName()
|
||||||
self.Group[MenuGroupName].Menus[Path] = nil
|
self.Group[MenuGroupName].Menus[Path] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:Refresh( Group )
|
function MENU_INDEX:Refresh( Group )
|
||||||
for MenuID, Menu in pairs( self.MenuMission.Menus ) do
|
for MenuID, Menu in pairs( self.MenuMission.Menus ) do
|
||||||
Menu:Refresh()
|
Menu:Refresh()
|
||||||
|
|||||||
@@ -75,35 +75,37 @@ MESSAGE.Type = {
|
|||||||
|
|
||||||
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{#MESSAGE.ToClient} or @{#MESSAGE.ToCoalition} or @{#MESSAGE.ToAll} to send these Messages to the respective recipients.
|
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{#MESSAGE.ToClient} or @{#MESSAGE.ToCoalition} or @{#MESSAGE.ToAll} to send these Messages to the respective recipients.
|
||||||
-- @param self
|
-- @param self
|
||||||
-- @param #string MessageText is the text of the Message.
|
-- @param #string Text is the text of the Message.
|
||||||
-- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel.
|
-- @param #number Duration Duration in seconds how long the message text is shown.
|
||||||
-- @param #string MessageCategory (optional) is a string expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ".
|
-- @param #string Category (Optional) String expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ".
|
||||||
-- @param #boolean ClearScreen (optional) Clear all previous messages if true.
|
-- @param #boolean ClearScreen (optional) Clear all previous messages if true.
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE self
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Create a series of new Messages.
|
-- -- Create a series of new Messages.
|
||||||
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
|
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
|
||||||
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
|
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
|
||||||
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
||||||
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
||||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" )
|
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" )
|
||||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
|
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
|
||||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
|
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
|
||||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
|
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
|
||||||
--
|
--
|
||||||
function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen )
|
function MESSAGE:New( Text, Duration, Category, ClearScreen )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, BASE:New() )
|
||||||
self:F( { MessageText, MessageDuration, MessageCategory } )
|
|
||||||
|
self:F( { Text, Duration, Category } )
|
||||||
|
|
||||||
self.MessageType = nil
|
self.MessageType = nil
|
||||||
|
|
||||||
-- When no MessageCategory is given, we don't show it as a title...
|
-- When no MessageCategory is given, we don't show it as a title...
|
||||||
if MessageCategory and MessageCategory ~= "" then
|
if Category and Category ~= "" then
|
||||||
if MessageCategory:sub( -1 ) ~= "\n" then
|
if Category:sub( -1 ) ~= "\n" then
|
||||||
self.MessageCategory = MessageCategory .. ": "
|
self.MessageCategory = Category .. ": "
|
||||||
else
|
else
|
||||||
self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n"
|
self.MessageCategory = Category:sub( 1, -2 ) .. ":\n"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.MessageCategory = ""
|
self.MessageCategory = ""
|
||||||
@@ -114,9 +116,9 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen
|
|||||||
self.ClearScreen = ClearScreen
|
self.ClearScreen = ClearScreen
|
||||||
end
|
end
|
||||||
|
|
||||||
self.MessageDuration = MessageDuration or 5
|
self.MessageDuration = Duration or 5
|
||||||
self.MessageTime = timer.getTime()
|
self.MessageTime = timer.getTime()
|
||||||
self.MessageText = MessageText:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
|
self.MessageText = Text:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
|
||||||
|
|
||||||
self.MessageSent = false
|
self.MessageSent = false
|
||||||
self.MessageGroup = false
|
self.MessageGroup = false
|
||||||
@@ -204,7 +206,7 @@ end
|
|||||||
function MESSAGE:ToGroup( Group, Settings )
|
function MESSAGE:ToGroup( Group, Settings )
|
||||||
self:F( Group.GroupName )
|
self:F( Group.GroupName )
|
||||||
|
|
||||||
if Group then
|
if Group and Group:IsAlive() then
|
||||||
|
|
||||||
if self.MessageType then
|
if self.MessageType then
|
||||||
local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
@@ -229,7 +231,7 @@ end
|
|||||||
function MESSAGE:ToUnit( Unit, Settings )
|
function MESSAGE:ToUnit( Unit, Settings )
|
||||||
self:F( Unit.IdentifiableName )
|
self:F( Unit.IdentifiableName )
|
||||||
|
|
||||||
if Unit then
|
if Unit and Unit:IsAlive() then
|
||||||
|
|
||||||
if self.MessageType then
|
if self.MessageType then
|
||||||
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
@@ -450,7 +452,7 @@ end
|
|||||||
_MESSAGESRS = {}
|
_MESSAGESRS = {}
|
||||||
|
|
||||||
--- Set up MESSAGE generally to allow Text-To-Speech via SRS and TTS functions. `SetMSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible.
|
--- Set up MESSAGE generally to allow Text-To-Speech via SRS and TTS functions. `SetMSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible.
|
||||||
-- @param #string PathToSRS (optional) Path to SRS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone" or your configuration file setting.
|
-- @param #string PathToSRS (optional) Path to SRS TTS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\ExternalAudio" or your configuration file setting.
|
||||||
-- @param #number Port Port (optional) number of SRS, defaults to 5002 or your configuration file setting.
|
-- @param #number Port Port (optional) number of SRS, defaults to 5002 or your configuration file setting.
|
||||||
-- @param #string PathToCredentials (optional) Path to credentials file for Google.
|
-- @param #string PathToCredentials (optional) Path to credentials file for Google.
|
||||||
-- @param #number Frequency Frequency in MHz. Can also be given as a #table of frequencies.
|
-- @param #number Frequency Frequency in MHz. Can also be given as a #table of frequencies.
|
||||||
@@ -462,16 +464,17 @@ _MESSAGESRS = {}
|
|||||||
-- @param #number Volume (optional) Volume, can be between 0.0 and 1.0 (loudest).
|
-- @param #number Volume (optional) Volume, can be between 0.0 and 1.0 (loudest).
|
||||||
-- @param #string Label (optional) Label, defaults to "MESSAGE" or the Message Category set.
|
-- @param #string Label (optional) Label, defaults to "MESSAGE" or the Message Category set.
|
||||||
-- @param Core.Point#COORDINATE Coordinate (optional) Coordinate this messages originates from.
|
-- @param Core.Point#COORDINATE Coordinate (optional) Coordinate this messages originates from.
|
||||||
|
-- @param #string Backend (optional) Backend to be used, can be MSRS.Backend.SRSEXE or MSRS.Backend.GRPC
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Mind the dot here, not using the colon this time around!
|
-- -- Mind the dot here, not using the colon this time around!
|
||||||
-- -- Needed once only
|
-- -- Needed once only
|
||||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||||
-- -- later on in your code
|
-- -- later on in your code
|
||||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||||
--
|
--
|
||||||
function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,Gender,Culture,Voice,Coalition,Volume,Label,Coordinate)
|
function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,Gender,Culture,Voice,Coalition,Volume,Label,Coordinate,Backend)
|
||||||
|
|
||||||
_MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
_MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||||
|
|
||||||
_MESSAGESRS.frequency = Frequency or MSRS.frequencies or 243
|
_MESSAGESRS.frequency = Frequency or MSRS.frequencies or 243
|
||||||
_MESSAGESRS.modulation = Modulation or MSRS.modulations or radio.modulation.AM
|
_MESSAGESRS.modulation = Modulation or MSRS.modulations or radio.modulation.AM
|
||||||
@@ -487,6 +490,10 @@ function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,G
|
|||||||
_MESSAGESRS.MSRS:SetCoordinate(Coordinate)
|
_MESSAGESRS.MSRS:SetCoordinate(Coordinate)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Backend then
|
||||||
|
_MESSAGESRS.MSRS:SetBackend(Backend)
|
||||||
|
end
|
||||||
|
|
||||||
_MESSAGESRS.Culture = Culture or MSRS.culture or "en-GB"
|
_MESSAGESRS.Culture = Culture or MSRS.culture or "en-GB"
|
||||||
_MESSAGESRS.MSRS:SetCulture(Culture)
|
_MESSAGESRS.MSRS:SetCulture(Culture)
|
||||||
|
|
||||||
@@ -528,7 +535,7 @@ end
|
|||||||
-- @usage
|
-- @usage
|
||||||
-- -- Mind the dot here, not using the colon this time around!
|
-- -- Mind the dot here, not using the colon this time around!
|
||||||
-- -- Needed once only
|
-- -- Needed once only
|
||||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||||
-- -- later on in your code
|
-- -- later on in your code
|
||||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||||
--
|
--
|
||||||
@@ -560,7 +567,7 @@ end
|
|||||||
-- @usage
|
-- @usage
|
||||||
-- -- Mind the dot here, not using the colon this time around!
|
-- -- Mind the dot here, not using the colon this time around!
|
||||||
-- -- Needed once only
|
-- -- Needed once only
|
||||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||||
-- -- later on in your code
|
-- -- later on in your code
|
||||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSBlue()
|
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSBlue()
|
||||||
--
|
--
|
||||||
@@ -582,7 +589,7 @@ end
|
|||||||
-- @usage
|
-- @usage
|
||||||
-- -- Mind the dot here, not using the colon this time around!
|
-- -- Mind the dot here, not using the colon this time around!
|
||||||
-- -- Needed once only
|
-- -- Needed once only
|
||||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.RED)
|
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.RED)
|
||||||
-- -- later on in your code
|
-- -- later on in your code
|
||||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSRed()
|
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSRed()
|
||||||
--
|
--
|
||||||
@@ -604,7 +611,7 @@ end
|
|||||||
-- @usage
|
-- @usage
|
||||||
-- -- Mind the dot here, not using the colon this time around!
|
-- -- Mind the dot here, not using the colon this time around!
|
||||||
-- -- Needed once only
|
-- -- Needed once only
|
||||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.NEUTRAL)
|
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.NEUTRAL)
|
||||||
-- -- later on in your code
|
-- -- later on in your code
|
||||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSAll()
|
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSAll()
|
||||||
--
|
--
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -175,7 +175,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
|||||||
local Name = Info.name or "?"
|
local Name = Info.name or "?"
|
||||||
|
|
||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
env.info( "Error in timer function: " .. errmsg )
|
env.info( "Error in timer function: " .. errmsg or "" )
|
||||||
if BASE.Debug ~= nil then
|
if BASE.Debug ~= nil then
|
||||||
env.info( BASE.Debug.traceback() )
|
env.info( BASE.Debug.traceback() )
|
||||||
end
|
end
|
||||||
@@ -326,7 +326,7 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
|||||||
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
|
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
|
||||||
|
|
||||||
-- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing.
|
-- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing.
|
||||||
if Schedule.ScheduleID then
|
if Schedule and Schedule.ScheduleID then
|
||||||
|
|
||||||
self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
|
self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
|
||||||
|
|
||||||
|
|||||||
@@ -289,7 +289,14 @@ do -- SET_BASE
|
|||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
--self:T2( { ObjectName = ObjectName, Object = Object } )
|
--self:T2( { ObjectName = ObjectName, Object = Object } )
|
||||||
|
|
||||||
|
-- Error ahndling
|
||||||
|
if not ObjectName or ObjectName == "" then
|
||||||
|
self:E("SET_BASE:Add - Invalid ObjectName handed")
|
||||||
|
self:E({ObjectName=ObjectName, Object=Object})
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
-- Ensure that the existing element is removed from the Set before a new one is inserted to the Set
|
-- Ensure that the existing element is removed from the Set before a new one is inserted to the Set
|
||||||
if self.Set[ObjectName] then
|
if self.Set[ObjectName] then
|
||||||
self:Remove( ObjectName, true )
|
self:Remove( ObjectName, true )
|
||||||
@@ -524,6 +531,21 @@ do -- SET_BASE
|
|||||||
|
|
||||||
return self.SomeIteratorLimit or self:Count()
|
return self.SomeIteratorLimit or self:Count()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get max threat level of all objects in the SET.
|
||||||
|
-- @param #SET_BASE self
|
||||||
|
-- @return #number Max threat level found.
|
||||||
|
function SET_BASE:GetThreatLevelMax()
|
||||||
|
local ThreatMax = 0
|
||||||
|
for _,_unit in pairs(self.Set or {}) do
|
||||||
|
local unit = _unit -- Wrapper.Unit#UNIT
|
||||||
|
local threat = unit.GetThreatLevel and unit:GetThreatLevel() or 0
|
||||||
|
if threat > ThreatMax then
|
||||||
|
ThreatMax = threat
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ThreatMax
|
||||||
|
end
|
||||||
|
|
||||||
--- Filters for the defined collection.
|
--- Filters for the defined collection.
|
||||||
-- @param #SET_BASE self
|
-- @param #SET_BASE self
|
||||||
@@ -607,14 +629,14 @@ do -- SET_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Iterate the SET_BASE while identifying the nearest object in the set from a @{Core.Point#POINT_VEC2}.
|
--- Iterate the SET_BASE while identifying the nearest object in the set from a @{Core.Point#COORDINATE}.
|
||||||
-- @param #SET_BASE self
|
-- @param #SET_BASE self
|
||||||
-- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#COORDINATE} or @{Core.Point#POINT_VEC2} object (but **not** a simple DCS#Vec2!) from where to evaluate the closest object in the set.
|
-- @param Core.Point#COORDINATE Coordinate A @{Core.Point#COORDINATE} object (but **not** a simple DCS#Vec2!) from where to evaluate the closest object in the set.
|
||||||
-- @return Core.Base#BASE The closest object.
|
-- @return Core.Base#BASE The closest object.
|
||||||
-- @usage
|
-- @usage
|
||||||
-- myset:FindNearestObjectFromPointVec2( ZONE:New("Test Zone"):GetCoordinate() )
|
-- myset:FindNearestObjectFromPointVec2( ZONE:New("Test Zone"):GetCoordinate() )
|
||||||
function SET_BASE:FindNearestObjectFromPointVec2( PointVec2 )
|
function SET_BASE:FindNearestObjectFromPointVec2( Coordinate )
|
||||||
--self:F2( PointVec2 )
|
--self:F2( Coordinate )
|
||||||
|
|
||||||
local NearestObject = nil
|
local NearestObject = nil
|
||||||
local ClosestDistance = nil
|
local ClosestDistance = nil
|
||||||
@@ -622,9 +644,9 @@ do -- SET_BASE
|
|||||||
for ObjectID, ObjectData in pairs( self.Set ) do
|
for ObjectID, ObjectData in pairs( self.Set ) do
|
||||||
if NearestObject == nil then
|
if NearestObject == nil then
|
||||||
NearestObject = ObjectData
|
NearestObject = ObjectData
|
||||||
ClosestDistance = PointVec2:DistanceFromPointVec2( ObjectData:GetCoordinate() )
|
ClosestDistance = Coordinate:DistanceFromPointVec2( ObjectData:GetCoordinate() )
|
||||||
else
|
else
|
||||||
local Distance = PointVec2:DistanceFromPointVec2( ObjectData:GetCoordinate() )
|
local Distance = Coordinate:DistanceFromPointVec2( ObjectData:GetCoordinate() )
|
||||||
if Distance < ClosestDistance then
|
if Distance < ClosestDistance then
|
||||||
NearestObject = ObjectData
|
NearestObject = ObjectData
|
||||||
ClosestDistance = Distance
|
ClosestDistance = Distance
|
||||||
@@ -936,7 +958,26 @@ do -- SET_BASE
|
|||||||
|
|
||||||
return ObjectNames
|
return ObjectNames
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get a *new* set table that only contains alive objects.
|
||||||
|
-- @param #SET_BASE self
|
||||||
|
-- @return #table Set table of alive objects.
|
||||||
|
function SET_BASE:GetAliveSet()
|
||||||
|
--self:F2()
|
||||||
|
|
||||||
|
local AliveSet = {}
|
||||||
|
-- Clean the Set before returning with only the alive Objects.
|
||||||
|
for ObjectName, Object in pairs( self.Set ) do
|
||||||
|
if Object then
|
||||||
|
if Object:IsAlive() then
|
||||||
|
AliveSet[#AliveSet+1] = Object
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return AliveSet or {}
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -1103,25 +1144,25 @@ do
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get a *new* set that only contains alive groups.
|
--- Get a *new* set table that only contains alive groups.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @return #SET_GROUP Set of alive groups.
|
-- @return #table Set of alive groups.
|
||||||
function SET_GROUP:GetAliveSet()
|
function SET_GROUP:GetAliveSet()
|
||||||
--self:F2()
|
--self:F2()
|
||||||
|
|
||||||
local AliveSet = SET_GROUP:New()
|
--local AliveSet = SET_GROUP:New()
|
||||||
|
local AliveSet = {}
|
||||||
-- Clean the Set before returning with only the alive Groups.
|
-- Clean the Set before returning with only the alive Groups.
|
||||||
for GroupName, GroupObject in pairs( self.Set ) do
|
for GroupName, GroupObject in pairs( self.Set ) do
|
||||||
local GroupObject = GroupObject -- Wrapper.Group#GROUP
|
local GroupObject = GroupObject -- Wrapper.Group#GROUP
|
||||||
if GroupObject then
|
if GroupObject then
|
||||||
if GroupObject:IsAlive() then
|
if GroupObject:IsAlive() then
|
||||||
AliveSet:Add( GroupName, GroupObject )
|
AliveSet[GroupName] = GroupObject
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return AliveSet.Set or {}
|
return AliveSet or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a report of of unit types.
|
--- Returns a report of of unit types.
|
||||||
@@ -1220,12 +1261,12 @@ do
|
|||||||
return GroupFound
|
return GroupFound
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Iterate the SET_GROUP while identifying the nearest object from a @{Core.Point#POINT_VEC2}.
|
--- Iterate the SET_GROUP while identifying the nearest object from a @{Core.Point#COORDINATE}.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest object in the set.
|
-- @param Core.Point#COORDINATE Coordinate A @{Core.Point#COORDINATE} object from where to evaluate the closest object in the set.
|
||||||
-- @return Wrapper.Group#GROUP The closest group.
|
-- @return Wrapper.Group#GROUP The closest group.
|
||||||
function SET_GROUP:FindNearestGroupFromPointVec2( PointVec2 )
|
function SET_GROUP:FindNearestGroupFromPointVec2( Coordinate )
|
||||||
--self:F2( PointVec2 )
|
--self:F2( Coordinate )
|
||||||
|
|
||||||
local NearestGroup = nil -- Wrapper.Group#GROUP
|
local NearestGroup = nil -- Wrapper.Group#GROUP
|
||||||
local ClosestDistance = nil
|
local ClosestDistance = nil
|
||||||
@@ -1235,9 +1276,9 @@ do
|
|||||||
for ObjectID, ObjectData in pairs( Set ) do
|
for ObjectID, ObjectData in pairs( Set ) do
|
||||||
if NearestGroup == nil then
|
if NearestGroup == nil then
|
||||||
NearestGroup = ObjectData
|
NearestGroup = ObjectData
|
||||||
ClosestDistance = PointVec2:DistanceFromPointVec2( ObjectData:GetCoordinate() )
|
ClosestDistance = Coordinate:DistanceFromPointVec2( ObjectData:GetCoordinate() )
|
||||||
else
|
else
|
||||||
local Distance = PointVec2:DistanceFromPointVec2( ObjectData:GetCoordinate() )
|
local Distance = Coordinate:DistanceFromPointVec2( ObjectData:GetCoordinate() )
|
||||||
if Distance < ClosestDistance then
|
if Distance < ClosestDistance then
|
||||||
NearestGroup = ObjectData
|
NearestGroup = ObjectData
|
||||||
ClosestDistance = Distance
|
ClosestDistance = Distance
|
||||||
@@ -1538,6 +1579,13 @@ do
|
|||||||
local size = 1
|
local size = 1
|
||||||
if Event.IniDCSGroup then
|
if Event.IniDCSGroup then
|
||||||
size = Event.IniDCSGroup:getSize()
|
size = Event.IniDCSGroup:getSize()
|
||||||
|
elseif Event.IniDCSGroupName then
|
||||||
|
local grp = Group.getByName(Event.IniDCSGroupName)
|
||||||
|
if grp then
|
||||||
|
size = grp:getSize()
|
||||||
|
end
|
||||||
|
elseif Object:IsAlive() then
|
||||||
|
size = Object:CountAliveUnits()
|
||||||
end
|
end
|
||||||
if size == 1 then -- Only remove if the last unit of the group was destroyed.
|
if size == 1 then -- Only remove if the last unit of the group was destroyed.
|
||||||
self:Remove( ObjectName )
|
self:Remove( ObjectName )
|
||||||
@@ -1709,7 +1757,7 @@ do
|
|||||||
|
|
||||||
--- Iterate the SET_GROUP and return true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE}
|
--- Iterate the SET_GROUP and return true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE}
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||||
-- @return #boolean true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE}, false otherwise
|
-- @return #boolean true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE}, false otherwise
|
||||||
-- @usage
|
-- @usage
|
||||||
-- local MyZone = ZONE:New("Zone1")
|
-- local MyZone = ZONE:New("Zone1")
|
||||||
@@ -1756,7 +1804,7 @@ do
|
|||||||
|
|
||||||
--- Iterate the SET_GROUP and return true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE}
|
--- Iterate the SET_GROUP and return true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE}
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||||
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE}, false otherwise.
|
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE}, false otherwise.
|
||||||
-- @usage
|
-- @usage
|
||||||
-- local MyZone = ZONE:New("Zone1")
|
-- local MyZone = ZONE:New("Zone1")
|
||||||
@@ -1781,7 +1829,7 @@ do
|
|||||||
|
|
||||||
--- Iterate the SET_GROUP and return true if at least one @{#UNIT} of one @{Wrapper.Group#GROUP} of the @{#SET_GROUP} is in @{Core.Zone}
|
--- Iterate the SET_GROUP and return true if at least one @{#UNIT} of one @{Wrapper.Group#GROUP} of the @{#SET_GROUP} is in @{Core.Zone}
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||||
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise.
|
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise.
|
||||||
-- @usage
|
-- @usage
|
||||||
-- local MyZone = ZONE:New("Zone1")
|
-- local MyZone = ZONE:New("Zone1")
|
||||||
@@ -1807,7 +1855,7 @@ do
|
|||||||
--- Iterate the SET_GROUP and return true if at least one @{Wrapper.Group#GROUP} of the @{#SET_GROUP} is partly in @{Core.Zone}.
|
--- Iterate the SET_GROUP and return true if at least one @{Wrapper.Group#GROUP} of the @{#SET_GROUP} is partly in @{Core.Zone}.
|
||||||
-- Will return false if a @{Wrapper.Group#GROUP} is fully in the @{Core.Zone}
|
-- Will return false if a @{Wrapper.Group#GROUP} is fully in the @{Core.Zone}
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||||
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise.
|
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise.
|
||||||
-- @usage
|
-- @usage
|
||||||
-- local MyZone = ZONE:New("Zone1")
|
-- local MyZone = ZONE:New("Zone1")
|
||||||
@@ -1842,7 +1890,7 @@ do
|
|||||||
-- This could also be achieved with `not SET_GROUP:AnyPartlyInZone(Zone)`, but it's easier for the
|
-- This could also be achieved with `not SET_GROUP:AnyPartlyInZone(Zone)`, but it's easier for the
|
||||||
-- mission designer to add a dedicated method
|
-- mission designer to add a dedicated method
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||||
-- @return #boolean true if no @{Wrapper.Group#GROUP} is inside the @{Core.Zone#ZONE} in any way, false otherwise.
|
-- @return #boolean true if no @{Wrapper.Group#GROUP} is inside the @{Core.Zone#ZONE} in any way, false otherwise.
|
||||||
-- @usage
|
-- @usage
|
||||||
-- local MyZone = ZONE:New("Zone1")
|
-- local MyZone = ZONE:New("Zone1")
|
||||||
@@ -1869,7 +1917,7 @@ do
|
|||||||
-- That could easily be done with SET_GROUP:ForEachGroupCompletelyInZone(), but this function
|
-- That could easily be done with SET_GROUP:ForEachGroupCompletelyInZone(), but this function
|
||||||
-- provides an easy to use shortcut...
|
-- provides an easy to use shortcut...
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||||
-- @return #number the number of GROUPs completely in the Zone
|
-- @return #number the number of GROUPs completely in the Zone
|
||||||
-- @usage
|
-- @usage
|
||||||
-- local MyZone = ZONE:New("Zone1")
|
-- local MyZone = ZONE:New("Zone1")
|
||||||
@@ -1891,7 +1939,7 @@ do
|
|||||||
|
|
||||||
--- Iterate the SET_GROUP and count how many UNITs are completely in the Zone
|
--- Iterate the SET_GROUP and count how many UNITs are completely in the Zone
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||||
-- @return #number the number of GROUPs completely in the Zone
|
-- @return #number the number of GROUPs completely in the Zone
|
||||||
-- @usage
|
-- @usage
|
||||||
-- local MyZone = ZONE:New("Zone1")
|
-- local MyZone = ZONE:New("Zone1")
|
||||||
@@ -2490,6 +2538,35 @@ do -- SET_UNIT
|
|||||||
)
|
)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Builds a set of units which belong to groups with certain **group names**.
|
||||||
|
-- @param #SET_UNIT self
|
||||||
|
-- @param #string Prefixes The (partial) group names to look for. Can be a single string or a table of strings.
|
||||||
|
-- @return #SET_UNIT self
|
||||||
|
function SET_UNIT:FilterGroupPrefixes(Prefixes)
|
||||||
|
if type(Prefixes) == "string" then
|
||||||
|
Prefixes = {Prefixes}
|
||||||
|
end
|
||||||
|
self:FilterFunction(
|
||||||
|
function(unit,prefixes)
|
||||||
|
local outcome = false
|
||||||
|
if unit then
|
||||||
|
local grp = unit:GetGroup()
|
||||||
|
local gname = grp ~= nil and grp:GetName() or "none"
|
||||||
|
for _,_fix in pairs(prefixes or {}) do
|
||||||
|
if string.find(gname,_fix) then
|
||||||
|
outcome = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return outcome
|
||||||
|
end, Prefixes
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Builds a set of units having a radar of give types.
|
--- Builds a set of units having a radar of give types.
|
||||||
-- All the units having a radar of a given type will be included within the set.
|
-- All the units having a radar of a given type will be included within the set.
|
||||||
@@ -2537,18 +2614,16 @@ do -- SET_UNIT
|
|||||||
|
|
||||||
--- Gets the alive set.
|
--- Gets the alive set.
|
||||||
-- @param #SET_UNIT self
|
-- @param #SET_UNIT self
|
||||||
-- @return #table Table of SET objects
|
-- @return #table Table of alive UNIT objects
|
||||||
-- @return #SET_UNIT AliveSet
|
-- @return #SET_UNIT AliveSet
|
||||||
function SET_UNIT:GetAliveSet()
|
function SET_UNIT:GetAliveSet()
|
||||||
|
|
||||||
local AliveSet = SET_UNIT:New()
|
local AliveSet = SET_UNIT:New()
|
||||||
|
|
||||||
-- Clean the Set before returning with only the alive Groups.
|
-- Clean the Set before returning with only the alive Groups.
|
||||||
for GroupName, GroupObject in pairs(self.Set) do
|
for GroupName, GroupObject in pairs(self.Set) do
|
||||||
local GroupObject=GroupObject --Wrapper.Client#CLIENT
|
|
||||||
|
|
||||||
if GroupObject and GroupObject:IsAlive() then
|
if GroupObject and GroupObject:IsAlive() then
|
||||||
AliveSet:Add(GroupName, GroupObject)
|
AliveSet[GroupName] = GroupObject
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2706,7 +2781,7 @@ do -- SET_UNIT
|
|||||||
|
|
||||||
--- Check if no element of the SET_UNIT is in the Zone.
|
--- Check if no element of the SET_UNIT is in the Zone.
|
||||||
-- @param #SET_UNIT self
|
-- @param #SET_UNIT self
|
||||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
function SET_UNIT:IsNotInZone( Zone )
|
function SET_UNIT:IsNotInZone( Zone )
|
||||||
|
|
||||||
@@ -3746,7 +3821,7 @@ do -- SET_STATIC
|
|||||||
|
|
||||||
--- Check if no element of the SET_STATIC is in the Zone.
|
--- Check if no element of the SET_STATIC is in the Zone.
|
||||||
-- @param #SET_STATIC self
|
-- @param #SET_STATIC self
|
||||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
function SET_STATIC:IsNotInZone( Zone )
|
function SET_STATIC:IsNotInZone( Zone )
|
||||||
|
|
||||||
@@ -4405,6 +4480,35 @@ do -- SET_CLIENT
|
|||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Builds a set of clients which belong to groups with certain **group names**.
|
||||||
|
-- @param #SET_CLIENT self
|
||||||
|
-- @param #string Prefixes The (partial) group names to look for. Can be anywhere in the group name. Can be a single string or a table of strings.
|
||||||
|
-- @return #SET_CLIENT self
|
||||||
|
function SET_CLIENT:FilterGroupPrefixes(Prefixes)
|
||||||
|
if type(Prefixes) == "string" then
|
||||||
|
Prefixes = {Prefixes}
|
||||||
|
end
|
||||||
|
self:FilterFunction(
|
||||||
|
function(unit,prefixes)
|
||||||
|
local outcome = false
|
||||||
|
if unit then
|
||||||
|
local grp = unit:GetGroup()
|
||||||
|
local gname = grp ~= nil and grp:GetName() or "none"
|
||||||
|
for _,_fix in pairs(prefixes or {}) do
|
||||||
|
if string.find(gname,_fix) then
|
||||||
|
outcome = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return outcome
|
||||||
|
end, Prefixes
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Builds a set of clients that are only active.
|
--- Builds a set of clients that are only active.
|
||||||
-- Only the clients that are active will be included within the set.
|
-- Only the clients that are active will be included within the set.
|
||||||
@@ -4582,6 +4686,16 @@ do -- SET_CLIENT
|
|||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Make the SET handle CA slots **only** (GROUND units used by any player). Needs active filtering with `FilterStart()`
|
||||||
|
-- @param #SET_CLIENT self
|
||||||
|
-- @return #SET_CLIENT self
|
||||||
|
function SET_CLIENT:HandleCASlots()
|
||||||
|
self:HandleEvent(EVENTS.PlayerEnterUnit,SET_CLIENT._EventPlayerEnterUnit)
|
||||||
|
self:HandleEvent(EVENTS.PlayerLeaveUnit,SET_CLIENT._EventPlayerLeaveUnit)
|
||||||
|
self:FilterFunction(function(client) if client and client:IsAlive() and client:IsGround() then return true else return false end end)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
|
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
|
||||||
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
||||||
@@ -4687,18 +4801,16 @@ do -- SET_CLIENT
|
|||||||
-- @return #table Table of SET objects
|
-- @return #table Table of SET objects
|
||||||
function SET_CLIENT:GetAliveSet()
|
function SET_CLIENT:GetAliveSet()
|
||||||
|
|
||||||
local AliveSet = SET_CLIENT:New()
|
local AliveSet = {}
|
||||||
|
|
||||||
-- Clean the Set before returning with only the alive Groups.
|
-- Clean the Set before returning with only the alive Groups.
|
||||||
for GroupName, GroupObject in pairs(self.Set) do
|
for GroupName, GroupObject in pairs(self.Set) do
|
||||||
local GroupObject=GroupObject --Wrapper.Client#CLIENT
|
|
||||||
|
|
||||||
if GroupObject and GroupObject:IsAlive() then
|
if GroupObject and GroupObject:IsAlive() then
|
||||||
AliveSet:Add(GroupName, GroupObject)
|
AliveSet[GroupName] = GroupObject
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return AliveSet.Set or {}
|
return AliveSet or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [User] Add a custom condition function.
|
--- [User] Add a custom condition function.
|
||||||
@@ -5364,6 +5476,7 @@ do -- SET_AIRBASE
|
|||||||
Airbases = {},
|
Airbases = {},
|
||||||
Filter = {
|
Filter = {
|
||||||
Coalitions = nil,
|
Coalitions = nil,
|
||||||
|
Zones = nil,
|
||||||
},
|
},
|
||||||
FilterMeta = {
|
FilterMeta = {
|
||||||
Coalitions = {
|
Coalitions = {
|
||||||
@@ -5515,6 +5628,31 @@ do -- SET_AIRBASE
|
|||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Builds a set of airbase objects in zones.
|
||||||
|
-- @param #SET_AIRBASE self
|
||||||
|
-- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE
|
||||||
|
-- @return #SET_AIRBASE self
|
||||||
|
function SET_AIRBASE:FilterZones( Zones )
|
||||||
|
if not self.Filter.Zones then
|
||||||
|
self.Filter.Zones = {}
|
||||||
|
end
|
||||||
|
local zones = {}
|
||||||
|
if Zones.ClassName and Zones.ClassName == "SET_ZONE" then
|
||||||
|
zones = Zones.Set
|
||||||
|
elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then
|
||||||
|
self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!")
|
||||||
|
return self
|
||||||
|
else
|
||||||
|
zones = Zones
|
||||||
|
end
|
||||||
|
for _,Zone in pairs( zones ) do
|
||||||
|
local zonename = Zone:GetName()
|
||||||
|
--self:T((zonename)
|
||||||
|
self.Filter.Zones[zonename] = Zone
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Starts the filtering.
|
--- Starts the filtering.
|
||||||
-- @param #SET_AIRBASE self
|
-- @param #SET_AIRBASE self
|
||||||
@@ -5605,14 +5743,14 @@ do -- SET_AIRBASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Iterate the SET_AIRBASE while identifying the nearest @{Wrapper.Airbase#AIRBASE} from a @{Core.Point#POINT_VEC2}.
|
--- Iterate the SET_AIRBASE while identifying the nearest @{Wrapper.Airbase#AIRBASE} from a @{Core.Point#COORDINATE}.
|
||||||
-- @param #SET_AIRBASE self
|
-- @param #SET_AIRBASE self
|
||||||
-- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest @{Wrapper.Airbase#AIRBASE}.
|
-- @param Core.Point#COORDINATE Coordinate A @{Core.Point#COORDINATE} object from where to evaluate the closest @{Wrapper.Airbase#AIRBASE}.
|
||||||
-- @return Wrapper.Airbase#AIRBASE The closest @{Wrapper.Airbase#AIRBASE}.
|
-- @return Wrapper.Airbase#AIRBASE The closest @{Wrapper.Airbase#AIRBASE}.
|
||||||
function SET_AIRBASE:FindNearestAirbaseFromPointVec2( PointVec2 )
|
function SET_AIRBASE:FindNearestAirbaseFromPointVec2( Coordinate )
|
||||||
--self:F2( PointVec2 )
|
--self:F2( Coordinate )
|
||||||
|
|
||||||
local NearestAirbase = self:FindNearestObjectFromPointVec2( PointVec2 )
|
local NearestAirbase = self:FindNearestObjectFromPointVec2( Coordinate )
|
||||||
return NearestAirbase
|
return NearestAirbase
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -5653,6 +5791,20 @@ do -- SET_AIRBASE
|
|||||||
--self:T(( { "Evaluated Category", MAirbaseCategory } )
|
--self:T(( { "Evaluated Category", MAirbaseCategory } )
|
||||||
MAirbaseInclude = MAirbaseInclude and MAirbaseCategory
|
MAirbaseInclude = MAirbaseInclude and MAirbaseCategory
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.Filter.Zones and MAirbaseInclude then
|
||||||
|
local MAirbaseZone = false
|
||||||
|
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
||||||
|
--self:T(( "Zone:", ZoneName )
|
||||||
|
local coord = MAirbase:GetCoordinate()
|
||||||
|
if coord and Zone:IsCoordinateInZone(coord) then
|
||||||
|
MAirbaseZone = true
|
||||||
|
end
|
||||||
|
--self:T(( { "Evaluated Zone", MSceneryZone } )
|
||||||
|
end
|
||||||
|
MAirbaseInclude = MAirbaseInclude and MAirbaseZone
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.Filter.Functions and MAirbaseInclude then
|
if self.Filter.Functions and MAirbaseInclude then
|
||||||
@@ -5928,17 +6080,19 @@ do -- SET_CARGO
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (R2.1) Iterate the SET_CARGO while identifying the nearest @{Cargo.Cargo#CARGO} from a @{Core.Point#POINT_VEC2}.
|
--- (R2.1) Iterate the SET_CARGO while identifying the nearest @{Cargo.Cargo#CARGO} from a @{Core.Point#COORDINATE}.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest @{Cargo.Cargo#CARGO}.
|
-- @param Core.Point#COORDINATE Coordinate A @{Core.Point#COORDINATE} object from where to evaluate the closest @{Cargo.Cargo#CARGO}.
|
||||||
-- @return Cargo.Cargo#CARGO The closest @{Cargo.Cargo#CARGO}.
|
-- @return Cargo.Cargo#CARGO The closest @{Cargo.Cargo#CARGO}.
|
||||||
function SET_CARGO:FindNearestCargoFromPointVec2( PointVec2 ) -- R2.1
|
function SET_CARGO:FindNearestCargoFromPointVec2( Coordinate ) -- R2.1
|
||||||
--self:F2( PointVec2 )
|
--self:F2( Coordinate )
|
||||||
|
|
||||||
local NearestCargo = self:FindNearestObjectFromPointVec2( PointVec2 )
|
local NearestCargo = self:FindNearestObjectFromPointVec2( Coordinate )
|
||||||
return NearestCargo
|
return NearestCargo
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @param #SET_CARGO self
|
||||||
function SET_CARGO:FirstCargoWithState( State )
|
function SET_CARGO:FirstCargoWithState( State )
|
||||||
|
|
||||||
local FirstCargo = nil
|
local FirstCargo = nil
|
||||||
@@ -5953,6 +6107,8 @@ do -- SET_CARGO
|
|||||||
return FirstCargo
|
return FirstCargo
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @param #SET_CARGO self
|
||||||
function SET_CARGO:FirstCargoWithStateAndNotDeployed( State )
|
function SET_CARGO:FirstCargoWithStateAndNotDeployed( State )
|
||||||
|
|
||||||
local FirstCargo = nil
|
local FirstCargo = nil
|
||||||
@@ -7936,22 +8092,31 @@ do -- SET_OPSGROUP
|
|||||||
--- Handles the OnBirth event for the Set.
|
--- Handles the OnBirth event for the Set.
|
||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param Core.Event#EVENTDATA Event Event data.
|
-- @param Core.Event#EVENTDATA Event Event data.
|
||||||
function SET_OPSGROUP:_EventOnBirth( Event )
|
function SET_OPSGROUP:_EventOnBirth(Event)
|
||||||
--self:F3( { Event } )
|
--self:F3( { Event } )
|
||||||
|
|
||||||
if Event.IniDCSUnit and Event.IniDCSGroup then
|
if Event.IniDCSUnit and Event.IniDCSGroup then
|
||||||
local DCSgroup=Event.IniDCSGroup --DCS#Group
|
local DCSgroup = Event.IniDCSGroup --DCS#Group
|
||||||
|
|
||||||
if DCSgroup:getInitialSize() == DCSgroup:getSize() then -- This seems to be not a good check as even for the first birth event, getSize returns the total number of units in the group.
|
-- group:CountAliveUnits() alternative as this fails for Respawn/Teleport
|
||||||
|
local CountAliveActive = 0
|
||||||
local groupname, group = self:AddInDatabase( Event )
|
for index, data in pairs(DCSgroup:getUnits()) do
|
||||||
|
if data:isExist() and data:isActive() then
|
||||||
if group and group:CountAliveUnits()==DCSgroup:getInitialSize() then
|
CountAliveActive = CountAliveActive + 1
|
||||||
if group and self:IsIncludeObject( group ) then
|
end
|
||||||
self:Add( groupname, group )
|
end
|
||||||
end
|
|
||||||
|
if DCSgroup:getInitialSize() == DCSgroup:getSize() then
|
||||||
|
|
||||||
|
local groupname, group = self:AddInDatabase(Event)
|
||||||
|
|
||||||
|
-- group:CountAliveUnits() alternative
|
||||||
|
if group and CountAliveActive == DCSgroup:getInitialSize() then
|
||||||
|
if group and self:IsIncludeObject(group) then
|
||||||
|
self:Add(groupname, group)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -7962,7 +8127,7 @@ do -- SET_OPSGROUP
|
|||||||
function SET_OPSGROUP:_EventOnDeadOrCrash( Event )
|
function SET_OPSGROUP:_EventOnDeadOrCrash( Event )
|
||||||
--self:F( { Event } )
|
--self:F( { Event } )
|
||||||
|
|
||||||
if Event.IniDCSUnit then
|
if Event.IniDCSGroup then
|
||||||
local ObjectName, Object = self:FindInDatabase( Event )
|
local ObjectName, Object = self:FindInDatabase( Event )
|
||||||
if ObjectName then
|
if ObjectName then
|
||||||
if Event.IniDCSGroup:getSize() == 1 then -- Only remove if the last unit of the group was destroyed.
|
if Event.IniDCSGroup:getSize() == 1 then -- Only remove if the last unit of the group was destroyed.
|
||||||
@@ -8355,14 +8520,17 @@ do -- SET_SCENERY
|
|||||||
-- @param #SET_SCENERY self
|
-- @param #SET_SCENERY self
|
||||||
-- @return Core.Point#COORDINATE The center coordinate of all the objects in the set.
|
-- @return Core.Point#COORDINATE The center coordinate of all the objects in the set.
|
||||||
function SET_SCENERY:GetCoordinate()
|
function SET_SCENERY:GetCoordinate()
|
||||||
|
--[[
|
||||||
local Coordinate = COORDINATE:New({0,0,0})
|
local Coordinate = COORDINATE:New({0,0,0})
|
||||||
|
|
||||||
local Item = self:GetRandomSurely()
|
local Item = self:GetRandomSurely()
|
||||||
|
|
||||||
if Item then
|
if Item then
|
||||||
Coordinate:GetCoordinate()
|
Coordinate:GetCoordinate()
|
||||||
end
|
end
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local Coordinate = self:GetFirst():GetCoordinate()
|
||||||
|
|
||||||
local x1 = Coordinate.x
|
local x1 = Coordinate.x
|
||||||
local x2 = Coordinate.x
|
local x2 = Coordinate.x
|
||||||
@@ -8602,7 +8770,6 @@ do -- SET_DYNAMICCARGO
|
|||||||
-- @field #SET_DYNAMICCARGO SET_DYNAMICCARGO
|
-- @field #SET_DYNAMICCARGO SET_DYNAMICCARGO
|
||||||
SET_DYNAMICCARGO = {
|
SET_DYNAMICCARGO = {
|
||||||
ClassName = "SET_DYNAMICCARGO",
|
ClassName = "SET_DYNAMICCARGO",
|
||||||
Filter = {},
|
|
||||||
Set = {},
|
Set = {},
|
||||||
List = {},
|
List = {},
|
||||||
Index = {},
|
Index = {},
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ do -- SETTINGS
|
|||||||
return (self.A2ASystem and self.A2ASystem == "MGRS") or (not self.A2ASystem and _SETTINGS:IsA2A_MGRS())
|
return (self.A2ASystem and self.A2ASystem == "MGRS") or (not self.A2ASystem and _SETTINGS:IsA2A_MGRS())
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
-- @param Wrapper.Group#GROUP MenuGroup Group for which to add menus.
|
-- @param Wrapper.Group#GROUP MenuGroup Group for which to add menus.
|
||||||
-- @param #table RootMenu Root menu table
|
-- @param #table RootMenu Root menu table
|
||||||
-- @return #SETTINGS
|
-- @return #SETTINGS
|
||||||
@@ -948,49 +948,49 @@ do -- SETTINGS
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem )
|
function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem )
|
||||||
self.A2GSystem = A2GSystem
|
self.A2GSystem = A2GSystem
|
||||||
MESSAGE:New( string.format( "Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
|
MESSAGE:New( string.format( "Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
|
||||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem )
|
function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem )
|
||||||
self.A2ASystem = A2ASystem
|
self.A2ASystem = A2ASystem
|
||||||
MESSAGE:New( string.format( "Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
|
MESSAGE:New( string.format( "Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
|
||||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:MenuLL_DDM_Accuracy( MenuGroup, RootMenu, LL_Accuracy )
|
function SETTINGS:MenuLL_DDM_Accuracy( MenuGroup, RootMenu, LL_Accuracy )
|
||||||
self.LL_Accuracy = LL_Accuracy
|
self.LL_Accuracy = LL_Accuracy
|
||||||
MESSAGE:New( string.format( "Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll()
|
MESSAGE:New( string.format( "Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll()
|
||||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, MGRS_Accuracy )
|
function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, MGRS_Accuracy )
|
||||||
self.MGRS_Accuracy = MGRS_Accuracy
|
self.MGRS_Accuracy = MGRS_Accuracy
|
||||||
MESSAGE:New( string.format( "Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll()
|
MESSAGE:New( string.format( "Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll()
|
||||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:MenuMWSystem( MenuGroup, RootMenu, MW )
|
function SETTINGS:MenuMWSystem( MenuGroup, RootMenu, MW )
|
||||||
self.Metric = MW
|
self.Metric = MW
|
||||||
MESSAGE:New( string.format( "Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll()
|
MESSAGE:New( string.format( "Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll()
|
||||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:MenuMessageTimingsSystem( MenuGroup, RootMenu, MessageType, MessageTime )
|
function SETTINGS:MenuMessageTimingsSystem( MenuGroup, RootMenu, MessageType, MessageTime )
|
||||||
self:SetMessageTime( MessageType, MessageTime )
|
self:SetMessageTime( MessageType, MessageTime )
|
||||||
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToAll()
|
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToAll()
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem )
|
function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem )
|
||||||
--BASE:E( {PlayerUnit:GetName(), A2GSystem } )
|
--BASE:E( {PlayerUnit:GetName(), A2GSystem } )
|
||||||
self.A2GSystem = A2GSystem
|
self.A2GSystem = A2GSystem
|
||||||
@@ -1001,7 +1001,7 @@ do -- SETTINGS
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
|
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
|
||||||
self.A2ASystem = A2ASystem
|
self.A2ASystem = A2ASystem
|
||||||
MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||||
@@ -1011,7 +1011,7 @@ do -- SETTINGS
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
|
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
|
||||||
self.LL_Accuracy = LL_Accuracy
|
self.LL_Accuracy = LL_Accuracy
|
||||||
MESSAGE:New( string.format( "Settings: LL format accuracy set to %d decimal places for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
MESSAGE:New( string.format( "Settings: LL format accuracy set to %d decimal places for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||||
@@ -1021,7 +1021,7 @@ do -- SETTINGS
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
|
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
|
||||||
self.MGRS_Accuracy = MGRS_Accuracy
|
self.MGRS_Accuracy = MGRS_Accuracy
|
||||||
MESSAGE:New( string.format( "Settings: MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
MESSAGE:New( string.format( "Settings: MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||||
@@ -1031,7 +1031,7 @@ do -- SETTINGS
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, MW )
|
function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, MW )
|
||||||
self.Metric = MW
|
self.Metric = MW
|
||||||
MESSAGE:New( string.format( "Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
|
MESSAGE:New( string.format( "Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||||
@@ -1041,7 +1041,7 @@ do -- SETTINGS
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param #SETTINGS self
|
--- @param #SETTINGS self
|
||||||
function SETTINGS:MenuGroupMessageTimingsSystem( PlayerUnit, PlayerGroup, PlayerName, MessageType, MessageTime )
|
function SETTINGS:MenuGroupMessageTimingsSystem( PlayerUnit, PlayerGroup, PlayerName, MessageType, MessageTime )
|
||||||
self:SetMessageTime( MessageType, MessageTime )
|
self:SetMessageTime( MessageType, MessageTime )
|
||||||
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToGroup( PlayerGroup )
|
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToGroup( PlayerGroup )
|
||||||
|
|||||||
@@ -1081,7 +1081,7 @@ function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable )
|
|||||||
self.SpawnRandomizeTemplate = true
|
self.SpawnRandomizeTemplate = true
|
||||||
|
|
||||||
for SpawnGroupID = 1, self.SpawnMaxGroups do
|
for SpawnGroupID = 1, self.SpawnMaxGroups do
|
||||||
self:_RandomizeTemplate( SpawnGroupID )
|
self:_RandomizeTemplate( SpawnGroupID, RandomizePositionInZone )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -1093,6 +1093,7 @@ end
|
|||||||
-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group.
|
-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param Core.Set#SET_GROUP SpawnTemplateSet A SET_GROUP object set, that contains the groups that are possible unit representatives of the group to be spawned.
|
-- @param Core.Set#SET_GROUP SpawnTemplateSet A SET_GROUP object set, that contains the groups that are possible unit representatives of the group to be spawned.
|
||||||
|
-- @param #boolean RandomizePositionInZone If nil or true, also the position inside the selected random zone will be randomized. Set to false to use the center of the zone.
|
||||||
-- @return #SPAWN
|
-- @return #SPAWN
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -1111,11 +1112,11 @@ end
|
|||||||
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
|
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
|
||||||
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
|
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
|
||||||
--
|
--
|
||||||
function SPAWN:InitRandomizeTemplateSet( SpawnTemplateSet )
|
function SPAWN:InitRandomizeTemplateSet( SpawnTemplateSet,RandomizePositionInZone )
|
||||||
--self:F( { self.SpawnTemplatePrefix } )
|
--self:F( { self.SpawnTemplatePrefix } )
|
||||||
|
|
||||||
local setnames = SpawnTemplateSet:GetSetNames()
|
local setnames = SpawnTemplateSet:GetSetNames()
|
||||||
self:InitRandomizeTemplate(setnames)
|
self:InitRandomizeTemplate(setnames,RandomizePositionInZone)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1125,7 +1126,8 @@ end
|
|||||||
-- but they will all follow the same Template route and have the same prefix name.
|
-- but they will all follow the same Template route and have the same prefix name.
|
||||||
-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group.
|
-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #string SpawnTemplatePrefixes A string or a list of string that contains the prefixes of the groups that are possible unit representatives of the group to be spawned.
|
-- @param #string SpawnTemplatePrefixes A string or a list of string that contains the prefixes of the groups that are possible unit representatives of the group to be spawned.
|
||||||
|
-- @param #boolean RandomizePositionInZone If nil or true, also the position inside the selected random zone will be randomized. Set to false to use the center of the zone.
|
||||||
-- @return #SPAWN
|
-- @return #SPAWN
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -1141,12 +1143,12 @@ end
|
|||||||
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
|
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
|
||||||
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
|
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):SpawnScheduled( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
|
||||||
--
|
--
|
||||||
function SPAWN:InitRandomizeTemplatePrefixes( SpawnTemplatePrefixes ) -- R2.3
|
function SPAWN:InitRandomizeTemplatePrefixes( SpawnTemplatePrefixes, RandomizePositionInZone ) -- R2.3
|
||||||
--self:F( { self.SpawnTemplatePrefix } )
|
--self:F( { self.SpawnTemplatePrefix } )
|
||||||
|
|
||||||
local SpawnTemplateSet = SET_GROUP:New():FilterPrefixes( SpawnTemplatePrefixes ):FilterOnce()
|
local SpawnTemplateSet = SET_GROUP:New():FilterPrefixes( SpawnTemplatePrefixes ):FilterOnce()
|
||||||
|
|
||||||
self:InitRandomizeTemplateSet( SpawnTemplateSet )
|
self:InitRandomizeTemplateSet( SpawnTemplateSet, RandomizePositionInZone )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1166,6 +1168,7 @@ end
|
|||||||
--- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types.
|
--- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #table SpawnZoneTable A table with @{Core.Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Core.Zone}s objects.
|
-- @param #table SpawnZoneTable A table with @{Core.Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Core.Zone}s objects.
|
||||||
|
-- @param #boolean RandomizePositionInZone If nil or true, also the position inside the selected random zone will be randomized. Set to false to use the center of the zone.
|
||||||
-- @return #SPAWN self
|
-- @return #SPAWN self
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -1178,7 +1181,7 @@ end
|
|||||||
-- :InitRandomizeZones( ZoneTable )
|
-- :InitRandomizeZones( ZoneTable )
|
||||||
-- :SpawnScheduled( 5, .5 )
|
-- :SpawnScheduled( 5, .5 )
|
||||||
--
|
--
|
||||||
function SPAWN:InitRandomizeZones( SpawnZoneTable )
|
function SPAWN:InitRandomizeZones( SpawnZoneTable, RandomizePositionInZone )
|
||||||
--self:F( { self.SpawnTemplatePrefix, SpawnZoneTable } )
|
--self:F( { self.SpawnTemplatePrefix, SpawnZoneTable } )
|
||||||
|
|
||||||
local temptable = {}
|
local temptable = {}
|
||||||
@@ -1190,7 +1193,7 @@ function SPAWN:InitRandomizeZones( SpawnZoneTable )
|
|||||||
self.SpawnRandomizeZones = true
|
self.SpawnRandomizeZones = true
|
||||||
|
|
||||||
for SpawnGroupID = 1, self.SpawnMaxGroups do
|
for SpawnGroupID = 1, self.SpawnMaxGroups do
|
||||||
self:_RandomizeZones( SpawnGroupID )
|
self:_RandomizeZones( SpawnGroupID, RandomizePositionInZone )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -1275,6 +1278,7 @@ end
|
|||||||
|
|
||||||
--- Respawn group after landing.
|
--- Respawn group after landing.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
|
-- @param #number WaitingTime Wait this many seconds before despawning the alive group after landing. Defaults to 3 .
|
||||||
-- @return #SPAWN self
|
-- @return #SPAWN self
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -1282,15 +1286,16 @@ end
|
|||||||
-- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically.
|
-- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically.
|
||||||
-- SpawnRU_SU34 = SPAWN:New( 'Su-34' )
|
-- SpawnRU_SU34 = SPAWN:New( 'Su-34' )
|
||||||
-- :InitRandomizeRoute( 1, 1, 3000 )
|
-- :InitRandomizeRoute( 1, 1, 3000 )
|
||||||
-- :InitRepeatOnLanding()
|
-- :InitRepeatOnLanding(20)
|
||||||
-- :Spawn()
|
-- :Spawn()
|
||||||
--
|
--
|
||||||
function SPAWN:InitRepeatOnLanding()
|
function SPAWN:InitRepeatOnLanding(WaitingTime)
|
||||||
--self:F( { self.SpawnTemplatePrefix } )
|
--self:F( { self.SpawnTemplatePrefix } )
|
||||||
|
|
||||||
self:InitRepeat()
|
self:InitRepeat()
|
||||||
self.RepeatOnEngineShutDown = false
|
self.RepeatOnEngineShutDown = false
|
||||||
self.RepeatOnLanding = true
|
self.RepeatOnLanding = true
|
||||||
|
self.RepeatOnLandingTime = (WaitingTime and WaitingTime > 3) and WaitingTime or 3
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1626,7 +1631,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
|||||||
|
|
||||||
if SpawnTemplate then
|
if SpawnTemplate then
|
||||||
|
|
||||||
local PointVec3 = POINT_VEC3:New( SpawnTemplate.route.points[1].x, SpawnTemplate.route.points[1].alt, SpawnTemplate.route.points[1].y )
|
local PointVec3 = COORDINATE:New( SpawnTemplate.route.points[1].x, SpawnTemplate.route.points[1].alt, SpawnTemplate.route.points[1].y )
|
||||||
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, PointVec3 } )
|
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, PointVec3 } )
|
||||||
|
|
||||||
-- If RandomizePosition, then Randomize the formation in the zone band, keeping the template.
|
-- If RandomizePosition, then Randomize the formation in the zone band, keeping the template.
|
||||||
@@ -2028,12 +2033,10 @@ end
|
|||||||
--
|
--
|
||||||
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Cold, nil, AIRBASE.TerminalType.OpenBig )
|
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Cold, nil, AIRBASE.TerminalType.OpenBig )
|
||||||
--
|
--
|
||||||
function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalType, EmergencyAirSpawn, Parkingdata ) -- R2.2, R2.4
|
function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalType, EmergencyAirSpawn, Parkingdata )
|
||||||
--self:F( { self.SpawnTemplatePrefix, SpawnAirbase, Takeoff, TakeoffAltitude, TerminalType } )
|
|
||||||
|
|
||||||
-- Get position of airbase.
|
-- Get position of airbase.
|
||||||
local PointVec3 = SpawnAirbase:GetCoordinate()
|
local PointVec3 = SpawnAirbase:GetCoordinate()
|
||||||
--self:T2( PointVec3 )
|
|
||||||
|
|
||||||
-- Set take off type. Default is hot.
|
-- Set take off type. Default is hot.
|
||||||
Takeoff = Takeoff or SPAWN.Takeoff.Hot
|
Takeoff = Takeoff or SPAWN.Takeoff.Hot
|
||||||
@@ -2043,39 +2046,24 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
EmergencyAirSpawn = true
|
EmergencyAirSpawn = true
|
||||||
end
|
end
|
||||||
|
|
||||||
--self:F( { SpawnIndex = self.SpawnIndex } )
|
|
||||||
|
|
||||||
if self:_GetSpawnIndex( self.SpawnIndex + 1 ) then
|
if self:_GetSpawnIndex( self.SpawnIndex + 1 ) then
|
||||||
|
|
||||||
-- Get group template.
|
-- Get group template.
|
||||||
local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate
|
local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate
|
||||||
|
|
||||||
--self:F( { SpawnTemplate = SpawnTemplate } )
|
|
||||||
|
|
||||||
if SpawnTemplate then
|
if SpawnTemplate then
|
||||||
|
|
||||||
-- Check if the aircraft with the specified SpawnIndex is already spawned.
|
|
||||||
-- If yes, ensure that the aircraft is spawned at the same aircraft spot.
|
|
||||||
|
|
||||||
local GroupAlive = self:GetGroupFromIndex( self.SpawnIndex )
|
|
||||||
|
|
||||||
--self:F( { GroupAlive = GroupAlive } )
|
|
||||||
|
|
||||||
-- Debug output
|
|
||||||
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
|
|
||||||
|
|
||||||
-- Template group, unit and its attributes.
|
-- Template group, unit and its attributes.
|
||||||
local TemplateGroup = GROUP:FindByName( self.SpawnTemplatePrefix )
|
local group = GROUP:FindByName( self.SpawnTemplatePrefix )
|
||||||
local TemplateUnit = TemplateGroup:GetUnit( 1 )
|
local unit = group:GetUnit( 1 )
|
||||||
|
|
||||||
-- General category of spawned group.
|
-- General category of spawned group.
|
||||||
local group = TemplateGroup
|
|
||||||
local istransport = group:HasAttribute( "Transports" ) and group:HasAttribute( "Planes" )
|
local istransport = group:HasAttribute( "Transports" ) and group:HasAttribute( "Planes" )
|
||||||
local isawacs = group:HasAttribute( "AWACS" )
|
local isawacs = group:HasAttribute( "AWACS" )
|
||||||
local isfighter = group:HasAttribute( "Fighters" ) or group:HasAttribute( "Interceptors" ) or group:HasAttribute( "Multirole fighters" ) or (group:HasAttribute( "Bombers" ) and not group:HasAttribute( "Strategic bombers" ))
|
local isfighter = group:HasAttribute( "Fighters" ) or group:HasAttribute( "Interceptors" ) or group:HasAttribute( "Multirole fighters" ) or (group:HasAttribute( "Bombers" ) and not group:HasAttribute( "Strategic bombers" ))
|
||||||
local isbomber = group:HasAttribute( "Strategic bombers" )
|
local isbomber = group:HasAttribute( "Strategic bombers" )
|
||||||
local istanker = group:HasAttribute( "Tankers" )
|
local istanker = group:HasAttribute( "Tankers" )
|
||||||
local ishelo = TemplateUnit:HasAttribute( "Helicopters" )
|
local ishelo = unit:HasAttribute( "Helicopters" )
|
||||||
|
|
||||||
-- Number of units in the group. With grouping this can actually differ from the template group size!
|
-- Number of units in the group. With grouping this can actually differ from the template group size!
|
||||||
local nunits = #SpawnTemplate.units
|
local nunits = #SpawnTemplate.units
|
||||||
@@ -2093,40 +2081,32 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
local AirbaseCategory = SpawnAirbase:GetAirbaseCategory()
|
local AirbaseCategory = SpawnAirbase:GetAirbaseCategory()
|
||||||
--self:F( { AirbaseCategory = AirbaseCategory } )
|
--self:F( { AirbaseCategory = AirbaseCategory } )
|
||||||
|
|
||||||
-- Set airdromeId.
|
-- Set airdrome ID. For helipads and ships we need to add the helipad ID and linked unit.
|
||||||
|
-- Note, it is important not to set the airdrome ID for at least ships, because spawn will happen at origin of the map
|
||||||
if AirbaseCategory == Airbase.Category.SHIP then
|
if AirbaseCategory == Airbase.Category.SHIP then
|
||||||
SpawnPoint.linkUnit = AirbaseID
|
SpawnPoint.linkUnit = AirbaseID
|
||||||
SpawnPoint.helipadId = AirbaseID
|
SpawnPoint.helipadId = AirbaseID
|
||||||
elseif AirbaseCategory == Airbase.Category.HELIPAD then
|
elseif AirbaseCategory == Airbase.Category.HELIPAD then
|
||||||
SpawnPoint.linkUnit = AirbaseID
|
SpawnPoint.linkUnit = AirbaseID
|
||||||
SpawnPoint.helipadId = AirbaseID
|
SpawnPoint.helipadId = AirbaseID
|
||||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
else
|
||||||
SpawnPoint.airdromeId = AirbaseID
|
SpawnPoint.airdromeId = AirbaseID
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set waypoint type/action.
|
-- Set waypoint type/action.
|
||||||
SpawnPoint.alt = 0
|
SpawnPoint.alt = 0
|
||||||
SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
|
SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
|
||||||
SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
|
SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
|
||||||
|
|
||||||
-- Check if we spawn on ground.
|
-- Check if we spawn on ground.
|
||||||
local spawnonground = not (Takeoff == SPAWN.Takeoff.Air)
|
local spawnonground = not (Takeoff == SPAWN.Takeoff.Air)
|
||||||
--self:T2( { spawnonground = spawnonground, TOtype = Takeoff, TOair = Takeoff == SPAWN.Takeoff.Air } )
|
|
||||||
|
|
||||||
-- Check where we actually spawn if we spawn on ground.
|
-- Check where we actually spawn if we spawn on ground.
|
||||||
local spawnonship = false
|
local autoparking=false
|
||||||
local spawnonfarp = false
|
if SpawnAirbase.isAirdrome then
|
||||||
local spawnonrunway = false
|
autoparking=false
|
||||||
local spawnonairport = false
|
else
|
||||||
if spawnonground then
|
autoparking=true
|
||||||
if AirbaseCategory == Airbase.Category.SHIP then
|
|
||||||
spawnonship = true
|
|
||||||
elseif AirbaseCategory == Airbase.Category.HELIPAD then
|
|
||||||
spawnonfarp = true
|
|
||||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
|
||||||
spawnonairport = true
|
|
||||||
end
|
|
||||||
spawnonrunway = Takeoff == SPAWN.Takeoff.Runway
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Array with parking spots coordinates.
|
-- Array with parking spots coordinates.
|
||||||
@@ -2142,8 +2122,8 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
|
|
||||||
-- Set terminal type.
|
-- Set terminal type.
|
||||||
local termtype = TerminalType
|
local termtype = TerminalType
|
||||||
if spawnonrunway then
|
if Takeoff==SPAWN.Takeoff.Runway then
|
||||||
if spawnonship then
|
if SpawnAirbase.isShip then
|
||||||
-- Looks like there are no runway spawn spots on the stennis!
|
-- Looks like there are no runway spawn spots on the stennis!
|
||||||
if ishelo then
|
if ishelo then
|
||||||
termtype = AIRBASE.TerminalType.HelicopterUsable
|
termtype = AIRBASE.TerminalType.HelicopterUsable
|
||||||
@@ -2163,34 +2143,31 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
local verysafe = false
|
local verysafe = false
|
||||||
|
|
||||||
-- Number of free parking spots at the airbase.
|
-- Number of free parking spots at the airbase.
|
||||||
if spawnonship or spawnonfarp or spawnonrunway then
|
if autoparking then
|
||||||
-- These places work procedural and have some kind of build in queue ==> Less effort.
|
-- These places work procedural and have some kind of build in queue ==> Less effort.
|
||||||
--self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
|
||||||
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
|
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
|
||||||
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
|
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
|
||||||
--[[
|
|
||||||
elseif Parkingdata~=nil then
|
elseif Parkingdata~=nil then
|
||||||
-- Parking data explicitly set by user as input parameter.
|
-- Parking data explicitly set by user as input parameter. (This was commented out for some unknown reason. But I need it this way.)
|
||||||
nfree=#Parkingdata
|
nfree=#Parkingdata
|
||||||
spots=Parkingdata
|
spots=Parkingdata
|
||||||
]]
|
|
||||||
else
|
else
|
||||||
if ishelo then
|
if ishelo then
|
||||||
if termtype == nil then
|
if termtype == nil then
|
||||||
-- Helo is spawned. Try exclusive helo spots first.
|
-- Helo is spawned. Try exclusive helo spots first.
|
||||||
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
|
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
|
||||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( group, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||||
nfree = #spots
|
nfree = #spots
|
||||||
if nfree < nunits then
|
if nfree < nunits then
|
||||||
-- Not enough helo ports. Let's try also other terminal types.
|
-- Not enough helo ports. Let's try also other terminal types.
|
||||||
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
|
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
|
||||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( group, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||||
nfree = #spots
|
nfree = #spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- No terminal type specified. We try all spots except shelters.
|
-- No terminal type specified. We try all spots except shelters.
|
||||||
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
|
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
|
||||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( group, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||||
nfree = #spots
|
nfree = #spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -2199,44 +2176,33 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
if isbomber or istransport or istanker or isawacs then
|
if isbomber or istransport or istanker or isawacs then
|
||||||
-- First we fill the potentially bigger spots.
|
-- First we fill the potentially bigger spots.
|
||||||
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig ) )
|
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig ) )
|
||||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( group, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||||
nfree = #spots
|
nfree = #spots
|
||||||
if nfree < nunits then
|
if nfree < nunits then
|
||||||
-- Now we try the smaller ones.
|
-- Now we try the smaller ones.
|
||||||
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig ) )
|
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig ) )
|
||||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( group, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||||
nfree = #spots
|
nfree = #spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
--self:T2( string.format( "Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft ) )
|
--self:T2( string.format( "Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft ) )
|
||||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( group, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||||
nfree = #spots
|
nfree = #spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Terminal type explicitly given.
|
-- Terminal type explicitly given.
|
||||||
--self:T2( string.format( "Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring( termtype ) ) )
|
--self:T2( string.format( "Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring( termtype ) ) )
|
||||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( group, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||||
nfree = #spots
|
nfree = #spots
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Debug: Get parking data.
|
|
||||||
--[[
|
|
||||||
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
|
|
||||||
--self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
|
||||||
for _,_spot in pairs(parkingdata) do
|
|
||||||
--self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
|
|
||||||
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
|
|
||||||
end
|
|
||||||
--self:T2(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
|
||||||
]]
|
|
||||||
|
|
||||||
-- Set this to true if not enough spots are available for emergency air start.
|
-- Set this to true if not enough spots are available for emergency air start.
|
||||||
local _notenough = false
|
local _notenough = false
|
||||||
|
|
||||||
-- Need to differentiate some cases again.
|
-- Need to differentiate some cases again.
|
||||||
if spawnonship or spawnonfarp or spawnonrunway then
|
if autoparking then
|
||||||
|
|
||||||
-- On free spot required in these cases.
|
-- On free spot required in these cases.
|
||||||
if nfree >= 1 then
|
if nfree >= 1 then
|
||||||
@@ -2254,7 +2220,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
_notenough = true
|
_notenough = true
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif spawnonairport then
|
else
|
||||||
|
|
||||||
if nfree >= nunits then
|
if nfree >= nunits then
|
||||||
|
|
||||||
@@ -2276,13 +2242,10 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
self:E( string.format( "WARNING: Group %s has no parking spots at %s ==> air start!", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
self:E( string.format( "WARNING: Group %s has no parking spots at %s ==> air start!", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||||
|
|
||||||
-- Not enough parking spots at the airport ==> Spawn in air.
|
-- Not enough parking spots at the airport ==> Spawn in air.
|
||||||
spawnonground = false
|
autoparking=false
|
||||||
spawnonship = false
|
|
||||||
spawnonfarp = false
|
|
||||||
spawnonrunway = false
|
|
||||||
|
|
||||||
-- Set waypoint type/action to turning point.
|
-- Set waypoint type/action to turning point.
|
||||||
SpawnPoint.type = GROUPTEMPLATE.Takeoff[GROUP.Takeoff.Air][1] -- type = Turning Point
|
SpawnPoint.type = GROUPTEMPLATE.Takeoff[GROUP.Takeoff.Air][1] -- type = Turning Point
|
||||||
SpawnPoint.action = GROUPTEMPLATE.Takeoff[GROUP.Takeoff.Air][2] -- action = Turning Point
|
SpawnPoint.action = GROUPTEMPLATE.Takeoff[GROUP.Takeoff.Air][2] -- action = Turning Point
|
||||||
|
|
||||||
-- Adjust altitude to be 500-1000 m above the airbase.
|
-- Adjust altitude to be 500-1000 m above the airbase.
|
||||||
@@ -2324,7 +2287,6 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
SpawnTemplate.parked = true
|
SpawnTemplate.parked = true
|
||||||
|
|
||||||
for UnitID = 1, nunits do
|
for UnitID = 1, nunits do
|
||||||
--self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
|
||||||
|
|
||||||
-- Template of the current unit.
|
-- Template of the current unit.
|
||||||
local UnitTemplate = SpawnTemplate.units[UnitID]
|
local UnitTemplate = SpawnTemplate.units[UnitID]
|
||||||
@@ -2340,9 +2302,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
if spawnonground then
|
if spawnonground then
|
||||||
|
|
||||||
-- Ships and FARPS seem to have a build in queue.
|
-- Ships and FARPS seem to have a build in queue.
|
||||||
if spawnonship or spawnonfarp or spawnonrunway then
|
if autoparking then
|
||||||
|
|
||||||
--self:T2( string.format( "Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
|
||||||
|
|
||||||
-- Spawn on ship. We take only the position of the ship.
|
-- Spawn on ship. We take only the position of the ship.
|
||||||
SpawnTemplate.units[UnitID].x = PointVec3.x -- TX
|
SpawnTemplate.units[UnitID].x = PointVec3.x -- TX
|
||||||
@@ -2351,20 +2311,15 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
--self:T2( string.format( "Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID] ) )
|
|
||||||
|
|
||||||
-- Get coordinates of parking spot.
|
-- Get coordinates of parking spot.
|
||||||
SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x
|
SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x
|
||||||
SpawnTemplate.units[UnitID].y = parkingspots[UnitID].z
|
SpawnTemplate.units[UnitID].y = parkingspots[UnitID].z
|
||||||
SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y
|
SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y
|
||||||
|
|
||||||
-- parkingspots[UnitID]:MarkToAll(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID]))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
--self:T2( string.format( "Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
|
||||||
|
|
||||||
-- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
|
-- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
|
||||||
SpawnTemplate.units[UnitID].x = TX
|
SpawnTemplate.units[UnitID].x = TX
|
||||||
SpawnTemplate.units[UnitID].y = TY
|
SpawnTemplate.units[UnitID].y = TY
|
||||||
@@ -2378,11 +2333,6 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
if parkingindex[UnitID] then
|
if parkingindex[UnitID] then
|
||||||
UnitTemplate.parking = parkingindex[UnitID]
|
UnitTemplate.parking = parkingindex[UnitID]
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Debug output.
|
|
||||||
--self:T2( string.format( "Group %s unit number %d: Parking = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking ) ) )
|
|
||||||
--self:T2( string.format( "Group %s unit number %d: Parking ID = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking_id ) ) )
|
|
||||||
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2402,14 +2352,15 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
-- When spawned in the air, we need to generate a Takeoff Event.
|
-- When spawned in the air, we need to generate a Takeoff Event.
|
||||||
if Takeoff == GROUP.Takeoff.Air then
|
if Takeoff == GROUP.Takeoff.Air then
|
||||||
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
|
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
|
||||||
SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() }, 5 )
|
--SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() }, 5 ) --No need to create a new SCHEDULER instance every time!
|
||||||
|
self:ScheduleOnce(5, BASE.CreateEventTakeoff, {GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject()})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if we accidentally spawned on the runway. Needs to be schedules, because group is not immidiately alive.
|
-- Check if we accidentally spawned on the runway. Needs to be schedules, because group is not immidiately alive.
|
||||||
if Takeoff ~= SPAWN.Takeoff.Runway and Takeoff ~= SPAWN.Takeoff.Air and spawnonairport then
|
--if Takeoff ~= SPAWN.Takeoff.Runway and Takeoff ~= SPAWN.Takeoff.Air and spawnonairport then
|
||||||
SCHEDULER:New( nil, AIRBASE.CheckOnRunWay, { SpawnAirbase, GroupSpawned, 75, true }, 1.0 )
|
-- SCHEDULER:New( nil, AIRBASE.CheckOnRunWay, { SpawnAirbase, GroupSpawned, 75, true }, 1.0 )
|
||||||
end
|
--end
|
||||||
|
|
||||||
return GroupSpawned
|
return GroupSpawned
|
||||||
end
|
end
|
||||||
@@ -2879,7 +2830,7 @@ end
|
|||||||
function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
||||||
--self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } )
|
--self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } )
|
||||||
|
|
||||||
local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 )
|
local PointVec3 = COORDINATE:NewFromVec3( Vec3 )
|
||||||
--self:T2( PointVec3 )
|
--self:T2( PointVec3 )
|
||||||
|
|
||||||
if SpawnIndex then
|
if SpawnIndex then
|
||||||
@@ -2955,7 +2906,7 @@ end
|
|||||||
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
|
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
|
||||||
-- You can use the returned group to further define the route to be followed.
|
-- You can use the returned group to further define the route to be followed.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 coordinates where to spawn the group.
|
-- @param Core.Point#COORDINATE PointVec3 The COORDINATE coordinates where to spawn the group.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @usage
|
-- @usage
|
||||||
@@ -3003,12 +2954,12 @@ function SPAWN:SpawnFromVec2( Vec2, MinHeight, MaxHeight, SpawnIndex )
|
|||||||
return self:SpawnFromVec3( { x = Vec2.x, y = Height, z = Vec2.y }, SpawnIndex ) -- y can be nil. In this case, spawn on the ground for vehicles, and in the template altitude for air.
|
return self:SpawnFromVec3( { x = Vec2.x, y = Height, z = Vec2.y }, SpawnIndex ) -- y can be nil. In this case, spawn on the ground for vehicles, and in the template altitude for air.
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Will spawn a group from a POINT_VEC2 in 3D space.
|
--- Will spawn a group from a COORDINATE in 3D space.
|
||||||
-- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles.
|
-- This method is mostly advisable to be used if you want to simulate spawning groups on the ground from air units, like vehicles.
|
||||||
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
|
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
|
||||||
-- You can use the returned group to further define the route to be followed.
|
-- You can use the returned group to further define the route to be followed.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 coordinates where to spawn the group.
|
-- @param Core.Point#COORDINATE PointVec2 The coordinates where to spawn the group.
|
||||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
@@ -3814,8 +3765,9 @@ end
|
|||||||
--- Private method that randomizes the @{Core.Zone}s where the Group will be spawned.
|
--- Private method that randomizes the @{Core.Zone}s where the Group will be spawned.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #number SpawnIndex
|
-- @param #number SpawnIndex
|
||||||
|
-- @param #boolean RandomizePositionInZone If nil or true, also the position inside the selected random zone will be randomized. Set to false to use the center of the zone.
|
||||||
-- @return #SPAWN self
|
-- @return #SPAWN self
|
||||||
function SPAWN:_RandomizeZones( SpawnIndex )
|
function SPAWN:_RandomizeZones( SpawnIndex, RandomizePositionInZone)
|
||||||
--self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } )
|
--self:F( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } )
|
||||||
|
|
||||||
if self.SpawnRandomizeZones then
|
if self.SpawnRandomizeZones then
|
||||||
@@ -3829,7 +3781,11 @@ function SPAWN:_RandomizeZones( SpawnIndex )
|
|||||||
|
|
||||||
--self:T2( "Preparing Spawn in Zone", SpawnZone:GetName() )
|
--self:T2( "Preparing Spawn in Zone", SpawnZone:GetName() )
|
||||||
|
|
||||||
local SpawnVec2 = SpawnZone:GetRandomVec2()
|
local SpawnVec2 = SpawnZone:GetVec2()
|
||||||
|
|
||||||
|
if RandomizePositionInZone ~= false then
|
||||||
|
SpawnVec2 = SpawnZone:GetRandomVec2()
|
||||||
|
end
|
||||||
|
|
||||||
--self:T2( { SpawnVec2 = SpawnVec2 } )
|
--self:T2( { SpawnVec2 = SpawnVec2 } )
|
||||||
|
|
||||||
@@ -3956,12 +3912,17 @@ end
|
|||||||
-- @return #number count
|
-- @return #number count
|
||||||
function SPAWN:_CountAliveUnits()
|
function SPAWN:_CountAliveUnits()
|
||||||
local count = 0
|
local count = 0
|
||||||
|
--self:I("self.SpawnAliasPrefix="..tostring(self.SpawnAliasPrefix).." | self.SpawnTemplatePrefix="..tostring(self.SpawnTemplatePrefix))
|
||||||
if self.SpawnAliasPrefix then
|
if self.SpawnAliasPrefix then
|
||||||
if not self.SpawnAliasPrefixEscaped then self.SpawnAliasPrefixEscaped = string.gsub(self.SpawnAliasPrefix,"[%p%s]",".") end
|
if not self.SpawnAliasPrefixEscaped then self.SpawnAliasPrefixEscaped = string.gsub(self.SpawnAliasPrefix,"[%p%s]",".") end
|
||||||
|
--self:I("self.SpawnAliasPrefixEscaped="..tostring(self.SpawnAliasPrefixEscaped))
|
||||||
local SpawnAliasPrefix = self.SpawnAliasPrefixEscaped
|
local SpawnAliasPrefix = self.SpawnAliasPrefixEscaped
|
||||||
local agroups = GROUP:FindAllByMatching(SpawnAliasPrefix)
|
local agroups = GROUP:FindAllByMatching(SpawnAliasPrefix)
|
||||||
for _,_grp in pairs(agroups) do
|
for _,_grp in pairs(agroups) do
|
||||||
|
--self:I("Group Name = " .. _grp:GetName())
|
||||||
local game = self:_GetPrefixFromGroupName(_grp.GroupName)
|
local game = self:_GetPrefixFromGroupName(_grp.GroupName)
|
||||||
|
--self:I("Game = "..game)
|
||||||
|
--self:I("Count = ".._grp:CountAliveUnits())
|
||||||
if game and game == self.SpawnAliasPrefix then
|
if game and game == self.SpawnAliasPrefix then
|
||||||
count = count + _grp:CountAliveUnits()
|
count = count + _grp:CountAliveUnits()
|
||||||
end
|
end
|
||||||
@@ -3977,15 +3938,16 @@ function SPAWN:_CountAliveUnits()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return count
|
self.AliveUnits = count
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function SPAWN:_OnDeadOrCrash( EventData )
|
function SPAWN:_OnDeadOrCrash( EventData )
|
||||||
--self:T2( "Dead or crash event ID "..tostring(EventData.id or 0))
|
--self:I( "Dead or crash event ID "..tostring(EventData.id or 0))
|
||||||
--self:T2( "Dead or crash event for "..tostring(EventData.IniUnitName or "none") )
|
--self:I( "Dead or crash event for "..tostring(EventData.IniUnitName or "none") )
|
||||||
|
|
||||||
--if EventData.id == EVENTS.Dead then return end
|
--if EventData.id == EVENTS.Dead then return end
|
||||||
|
|
||||||
@@ -3997,11 +3959,12 @@ function SPAWN:_OnDeadOrCrash( EventData )
|
|||||||
local EventPrefix = self:_GetPrefixFromGroupName(unit.GroupName)
|
local EventPrefix = self:_GetPrefixFromGroupName(unit.GroupName)
|
||||||
|
|
||||||
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
||||||
--self:T2(string.format("EventPrefix = %s | SpawnAliasPrefix = %s | Old AliveUnits = %d",EventPrefix or "",self.SpawnAliasPrefix or "",self.AliveUnits or 0))
|
--self:I(string.format("EventPrefix = %s | SpawnAliasPrefix = %s | Old AliveUnits = %d",EventPrefix or "",self.SpawnAliasPrefix or "",self.AliveUnits or 0))
|
||||||
if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) and self.AliveUnits > 0 then
|
if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) and self.AliveUnits > 0 then
|
||||||
--self:I( { "Dead event: " .. EventPrefix } )
|
--self:I( { "Dead event: " .. EventPrefix } )
|
||||||
--self.AliveUnits = self.AliveUnits - 1
|
--self.AliveUnits = self.AliveUnits - 1
|
||||||
self.AliveUnits = self:_CountAliveUnits()
|
self:ScheduleOnce(1,self._CountAliveUnits,self)
|
||||||
|
--self.AliveUnits = self:_CountAliveUnits()
|
||||||
--self:I( "New Alive Units: " .. self.AliveUnits )
|
--self:I( "New Alive Units: " .. self.AliveUnits )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -4049,7 +4012,7 @@ function SPAWN:_OnLand( EventData )
|
|||||||
-- self:ReSpawn( SpawnGroupIndex )
|
-- self:ReSpawn( SpawnGroupIndex )
|
||||||
-- Delay respawn by three seconds due to DCS 2.5.4.26368 OB bug https://github.com/FlightControl-Master/MOOSE/issues/1076
|
-- Delay respawn by three seconds due to DCS 2.5.4.26368 OB bug https://github.com/FlightControl-Master/MOOSE/issues/1076
|
||||||
-- Bug was initially only for engine shutdown event but after ED "fixed" it, it now happens on landing events.
|
-- Bug was initially only for engine shutdown event but after ED "fixed" it, it now happens on landing events.
|
||||||
SCHEDULER:New( nil, self.ReSpawn, { self, SpawnGroupIndex }, 3 )
|
SCHEDULER:New( nil, self.ReSpawn, { self, SpawnGroupIndex }, self.RepeatOnLandingTime or 3 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
--
|
--
|
||||||
-- * @{#SPAWNSTATIC.Spawn}(Heading, NewName) spawns the static with the set parameters. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.Spawn}(Heading, NewName) spawns the static with the set parameters. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromCoordinate}(Coordinate, Heading, NewName) spawn the static at the given coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.SpawnFromCoordinate}(Coordinate, Heading, NewName) spawn the static at the given coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(PointVec2, Heading, NewName) spawns the static at a POINT_VEC2 coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(PointVec2, Heading, NewName) spawns the static at a COORDINATE coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Core.Zone}. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Core.Zone}. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
--
|
--
|
||||||
-- @field #SPAWNSTATIC SPAWNSTATIC
|
-- @field #SPAWNSTATIC SPAWNSTATIC
|
||||||
@@ -149,6 +149,7 @@ function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
|||||||
self.CategoryID = CategoryID
|
self.CategoryID = CategoryID
|
||||||
self.CoalitionID = CoalitionID
|
self.CoalitionID = CoalitionID
|
||||||
self.SpawnIndex = 0
|
self.SpawnIndex = 0
|
||||||
|
self.StaticCopyFrom = SpawnTemplateName
|
||||||
else
|
else
|
||||||
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. tostring(SpawnTemplateName) .. "'" )
|
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. tostring(SpawnTemplateName) .. "'" )
|
||||||
end
|
end
|
||||||
@@ -302,12 +303,16 @@ end
|
|||||||
-- @param #number CallsignID Callsign ID. Default 1 (="London").
|
-- @param #number CallsignID Callsign ID. Default 1 (="London").
|
||||||
-- @param #number Frequency Frequency in MHz. Default 127.5 MHz.
|
-- @param #number Frequency Frequency in MHz. Default 127.5 MHz.
|
||||||
-- @param #number Modulation Modulation 0=AM, 1=FM.
|
-- @param #number Modulation Modulation 0=AM, 1=FM.
|
||||||
|
-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns
|
||||||
|
-- @param #boolean DynamicHotStarts If true, and DynamicSpawns is true, then allow Dynamic Spawns with hot starts.
|
||||||
-- @return #SPAWNSTATIC self
|
-- @return #SPAWNSTATIC self
|
||||||
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation)
|
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation, DynamicSpawns,DynamicHotStarts)
|
||||||
self.InitFarp=true
|
self.InitFarp=true
|
||||||
self.InitFarpCallsignID=CallsignID or 1
|
self.InitFarpCallsignID=CallsignID or 1
|
||||||
self.InitFarpFreq=Frequency or 127.5
|
self.InitFarpFreq=Frequency or 127.5
|
||||||
self.InitFarpModu=Modulation or 0
|
self.InitFarpModu=Modulation or 0
|
||||||
|
self.InitFarpDynamicSpawns = DynamicSpawns
|
||||||
|
self.InitFarpDynamicHotStarts = (DynamicSpawns == true and DynamicHotStarts == true) and true or nil
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -411,9 +416,9 @@ function SPAWNSTATIC:Spawn(Heading, NewName)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates a new @{Wrapper.Static} from a POINT_VEC2.
|
--- Creates a new @{Wrapper.Static} from a COORDINATE.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
|
-- @param Core.Point#COORDINATE PointVec2 The 2D coordinate where to spawn the static.
|
||||||
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
||||||
-- @param #string NewName (Optional) The name of the new static.
|
-- @param #string NewName (Optional) The name of the new static.
|
||||||
-- @return Wrapper.Static#STATIC The static spawned.
|
-- @return Wrapper.Static#STATIC The static spawned.
|
||||||
@@ -459,8 +464,9 @@ end
|
|||||||
function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName)
|
function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName)
|
||||||
|
|
||||||
-- Spawn the new static at the center of the zone.
|
-- Spawn the new static at the center of the zone.
|
||||||
local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
--local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
||||||
|
local Static = self:SpawnFromCoordinate(Zone:GetCoordinate(), Heading, NewName)
|
||||||
|
|
||||||
return Static
|
return Static
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -535,12 +541,6 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
-- Name of the spawned static.
|
-- Name of the spawned static.
|
||||||
Template.name = self.InitStaticName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex)
|
Template.name = self.InitStaticName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex)
|
||||||
|
|
||||||
-- Add and register the new static.
|
|
||||||
local mystatic=_DATABASE:AddStatic(Template.name)
|
|
||||||
|
|
||||||
-- Debug output.
|
|
||||||
self:T(Template)
|
|
||||||
|
|
||||||
-- Add static to the game.
|
-- Add static to the game.
|
||||||
local Static=nil --DCS#StaticObject
|
local Static=nil --DCS#StaticObject
|
||||||
|
|
||||||
@@ -555,6 +555,13 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
TemplateGroup.x=Template.x
|
TemplateGroup.x=Template.x
|
||||||
TemplateGroup.y=Template.y
|
TemplateGroup.y=Template.y
|
||||||
TemplateGroup.name=Template.name
|
TemplateGroup.name=Template.name
|
||||||
|
|
||||||
|
if self.InitFarpDynamicSpawns == true then
|
||||||
|
TemplateGroup.units[1].dynamicSpawn = true
|
||||||
|
if self.InitFarpDynamicHotStarts == true then
|
||||||
|
TemplateGroup.units[1].allowHotStart = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
self:T("Spawning FARP")
|
self:T("Spawning FARP")
|
||||||
self:T({Template=Template})
|
self:T({Template=Template})
|
||||||
@@ -562,7 +569,8 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
|
|
||||||
-- ED's dirty way to spawn FARPS.
|
-- ED's dirty way to spawn FARPS.
|
||||||
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
||||||
|
--Static=coalition.addStaticObject(CountryID, Template)
|
||||||
|
|
||||||
-- Currently DCS 2.8 does not trigger birth events if FARPS are spawned!
|
-- Currently DCS 2.8 does not trigger birth events if FARPS are spawned!
|
||||||
-- We create such an event. The airbase is registered in Core.Event
|
-- We create such an event. The airbase is registered in Core.Event
|
||||||
local Event = {
|
local Event = {
|
||||||
@@ -577,13 +585,42 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
self:T("Spawning Static")
|
self:T("Spawning Static")
|
||||||
self:T2({Template=Template})
|
self:T2({Template=Template})
|
||||||
Static=coalition.addStaticObject(CountryID, Template)
|
Static=coalition.addStaticObject(CountryID, Template)
|
||||||
|
|
||||||
|
if Static then
|
||||||
|
self:T(string.format("Succesfully spawned static object \"%s\" ID=%d", Static:getName(), Static:getID()))
|
||||||
|
--[[
|
||||||
|
local static=StaticObject.getByName(Static:getName())
|
||||||
|
if static then
|
||||||
|
env.info(string.format("FF got static from StaticObject.getByName"))
|
||||||
|
else
|
||||||
|
env.error(string.format("FF error did NOT get static from StaticObject.getByName"))
|
||||||
|
end ]]
|
||||||
|
else
|
||||||
|
self:E(string.format("ERROR: DCS static object \"%s\" is nil!", tostring(Template.name)))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Add and register the new static.
|
||||||
|
local mystatic=_DATABASE:AddStatic(Template.name)
|
||||||
|
|
||||||
-- If there is a SpawnFunction hook defined, call it.
|
-- If there is a SpawnFunction hook defined, call it.
|
||||||
if self.SpawnFunctionHook then
|
if self.SpawnFunctionHook then
|
||||||
-- delay calling this for .3 seconds so that it hopefully comes after the BIRTH event of the group.
|
-- delay calling this for .3 seconds so that it hopefully comes after the BIRTH event of the group.
|
||||||
self:ScheduleOnce(0.3,self.SpawnFunctionHook,mystatic, unpack(self.SpawnFunctionArguments))
|
self:ScheduleOnce(0.3, self.SpawnFunctionHook, mystatic, unpack(self.SpawnFunctionArguments))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.StaticCopyFrom ~= nil then
|
||||||
|
mystatic.StaticCopyFrom = self.StaticCopyFrom
|
||||||
|
if not _DATABASE.Templates.Statics[Template.name] then
|
||||||
|
local TemplateGroup={}
|
||||||
|
TemplateGroup.units={}
|
||||||
|
TemplateGroup.units[1]=Template
|
||||||
|
TemplateGroup.x=Template.x
|
||||||
|
TemplateGroup.y=Template.y
|
||||||
|
TemplateGroup.name=Template.name
|
||||||
|
_DATABASE:_RegisterStaticTemplate( TemplateGroup, self.CoalitionID, self.CategoryID, CountryID )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return mystatic
|
return mystatic
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ end
|
|||||||
|
|
||||||
--- Returns if a PointVec3 is within the zone.
|
--- Returns if a PointVec3 is within the zone.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 to test.
|
-- @param Core.Point#COORDINATE PointVec3 The PointVec3 to test.
|
||||||
-- @return #boolean true if the PointVec3 is within the zone.
|
-- @return #boolean true if the PointVec3 is within the zone.
|
||||||
function ZONE_BASE:IsPointVec3InZone( PointVec3 )
|
function ZONE_BASE:IsPointVec3InZone( PointVec3 )
|
||||||
local InZone = self:IsPointVec2InZone( PointVec3 )
|
local InZone = self:IsPointVec2InZone( PointVec3 )
|
||||||
@@ -227,16 +227,16 @@ function ZONE_BASE:GetVec2()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} of the zone.
|
--- Returns a @{Core.Point#COORDINATE} of the zone.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located.
|
-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located.
|
||||||
-- @return Core.Point#POINT_VEC2 The PointVec2 of the zone.
|
-- @return Core.Point#COORDINATE The COORDINATE of the zone.
|
||||||
function ZONE_BASE:GetPointVec2()
|
function ZONE_BASE:GetPointVec2()
|
||||||
--self:F2( self.ZoneName )
|
--self:F2( self.ZoneName )
|
||||||
|
|
||||||
local Vec2 = self:GetVec2()
|
local Vec2 = self:GetVec2()
|
||||||
|
|
||||||
local PointVec2 = POINT_VEC2:NewFromVec2( Vec2 )
|
local PointVec2 = COORDINATE:NewFromVec2( Vec2 )
|
||||||
|
|
||||||
--self:T2( { PointVec2 } )
|
--self:T2( { PointVec2 } )
|
||||||
|
|
||||||
@@ -261,16 +261,16 @@ function ZONE_BASE:GetVec3( Height )
|
|||||||
return Vec3
|
return Vec3
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC3} of the zone.
|
--- Returns a @{Core.Point#COORDINATE} of the zone.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located.
|
-- @param DCS#Distance Height The height to add to the land height where the center of the zone is located.
|
||||||
-- @return Core.Point#POINT_VEC3 The PointVec3 of the zone.
|
-- @return Core.Point#COORDINATE The PointVec3 of the zone.
|
||||||
function ZONE_BASE:GetPointVec3( Height )
|
function ZONE_BASE:GetPointVec3( Height )
|
||||||
--self:F2( self.ZoneName )
|
--self:F2( self.ZoneName )
|
||||||
|
|
||||||
local Vec3 = self:GetVec3( Height )
|
local Vec3 = self:GetVec3( Height )
|
||||||
|
|
||||||
local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 )
|
local PointVec3 = COORDINATE:NewFromVec3( Vec3 )
|
||||||
|
|
||||||
--self:T2( { PointVec3 } )
|
--self:T2( { PointVec3 } )
|
||||||
|
|
||||||
@@ -330,16 +330,16 @@ function ZONE_BASE:GetRandomVec2()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
--- Define a random @{Core.Point#COORDINATE} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
-- @return Core.Point#COORDINATE The COORDINATE coordinates.
|
||||||
function ZONE_BASE:GetRandomPointVec2()
|
function ZONE_BASE:GetRandomPointVec2()
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC3} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
--- Define a random @{Core.Point#COORDINATE} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @return Core.Point#POINT_VEC3 The PointVec3 coordinates.
|
-- @return Core.Point#COORDINATE The COORDINATE coordinates.
|
||||||
function ZONE_BASE:GetRandomPointVec3()
|
function ZONE_BASE:GetRandomPointVec3()
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -534,6 +534,19 @@ function ZONE_BASE:GetZoneProbability()
|
|||||||
return self.ZoneProbability
|
return self.ZoneProbability
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the coordinate on the radius of the zone nearest to Outsidecoordinate. Useto e.g. find an ingress point.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @param Core.Point#COORDINATE Outsidecoordinate The coordinate outside of the zone from where to look.
|
||||||
|
-- @return Core.Point#COORDINATE CoordinateOnRadius
|
||||||
|
function ZONE_BASE:FindNearestCoordinateOnRadius(Outsidecoordinate)
|
||||||
|
local Vec1 = self:GetVec2()
|
||||||
|
local Radius = self:GetRadius()
|
||||||
|
local Vec2 = Outsidecoordinate:GetVec2()
|
||||||
|
local Point = UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2)
|
||||||
|
local rc = COORDINATE:NewFromVec2(Point)
|
||||||
|
return rc
|
||||||
|
end
|
||||||
|
|
||||||
--- Get the zone taking into account the randomization probability of a zone to be selected.
|
--- Get the zone taking into account the randomization probability of a zone to be selected.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @return #ZONE_BASE The zone is selected taking into account the randomization probability factor.
|
-- @return #ZONE_BASE The zone is selected taking into account the randomization probability factor.
|
||||||
@@ -605,10 +618,13 @@ function ZONE_BASE:Trigger(Objects)
|
|||||||
self:AddTransition("TriggerStopped","TriggerStart","TriggerRunning")
|
self:AddTransition("TriggerStopped","TriggerStart","TriggerRunning")
|
||||||
self:AddTransition("*","EnteredZone","*")
|
self:AddTransition("*","EnteredZone","*")
|
||||||
self:AddTransition("*","LeftZone","*")
|
self:AddTransition("*","LeftZone","*")
|
||||||
|
self:AddTransition("*","ZoneEmpty","*")
|
||||||
|
self:AddTransition("*","ObjectDead","*")
|
||||||
self:AddTransition("*","TriggerRunCheck","*")
|
self:AddTransition("*","TriggerRunCheck","*")
|
||||||
self:AddTransition("*","TriggerStop","TriggerStopped")
|
self:AddTransition("*","TriggerStop","TriggerStopped")
|
||||||
self:TriggerStart()
|
self:TriggerStart()
|
||||||
self.checkobjects = Objects
|
self.checkobjects = Objects
|
||||||
|
self.ObjectsInZone = false
|
||||||
if UTILS.IsInstanceOf(Objects,"SET_BASE") then
|
if UTILS.IsInstanceOf(Objects,"SET_BASE") then
|
||||||
self.objectset = Objects.Set
|
self.objectset = Objects.Set
|
||||||
else
|
else
|
||||||
@@ -646,6 +662,22 @@ function ZONE_BASE:Trigger(Objects)
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The controllable leaving the zone.
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The controllable leaving the zone.
|
||||||
|
|
||||||
|
--- On After "ObjectDead" event. An observed object has left the zone.
|
||||||
|
-- @function [parent=#ZONE_BASE] OnAfterObjectDead
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The controllable which died. Might be nil.
|
||||||
|
|
||||||
|
--- On After "ZoneEmpty" event. All observed objects have left the zone or are dead.
|
||||||
|
-- @function [parent=#ZONE_BASE] OnAfterZoneEmpty
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Check the assigned objects for being in/out of the zone
|
--- (Internal) Check the assigned objects for being in/out of the zone
|
||||||
@@ -659,9 +691,13 @@ function ZONE_BASE:_TriggerCheck(fromstart)
|
|||||||
-- just earmark everyone in/out
|
-- just earmark everyone in/out
|
||||||
for _,_object in pairs(objectset) do
|
for _,_object in pairs(objectset) do
|
||||||
local obj = _object -- Wrapper.Controllable#CONTROLLABLE
|
local obj = _object -- Wrapper.Controllable#CONTROLLABLE
|
||||||
if not obj.TriggerInZone then obj.TriggerInZone = {} end
|
if not obj.TriggerInZone then
|
||||||
|
obj.TriggerInZone = {}
|
||||||
|
obj.TriggerZoneDeadNotification = false
|
||||||
|
end
|
||||||
if obj and obj:IsAlive() and self:IsCoordinateInZone(obj:GetCoordinate()) then
|
if obj and obj:IsAlive() and self:IsCoordinateInZone(obj:GetCoordinate()) then
|
||||||
obj.TriggerInZone[self.ZoneName] = true
|
obj.TriggerInZone[self.ZoneName] = true
|
||||||
|
self.ObjectsInZone = true
|
||||||
else
|
else
|
||||||
obj.TriggerInZone[self.ZoneName] = false
|
obj.TriggerInZone[self.ZoneName] = false
|
||||||
end
|
end
|
||||||
@@ -669,6 +705,7 @@ function ZONE_BASE:_TriggerCheck(fromstart)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Check for changes
|
-- Check for changes
|
||||||
|
local objcount = 0
|
||||||
for _,_object in pairs(objectset) do
|
for _,_object in pairs(objectset) do
|
||||||
local obj = _object -- Wrapper.Controllable#CONTROLLABLE
|
local obj = _object -- Wrapper.Controllable#CONTROLLABLE
|
||||||
if obj and obj:IsAlive() then
|
if obj and obj:IsAlive() then
|
||||||
@@ -683,11 +720,20 @@ function ZONE_BASE:_TriggerCheck(fromstart)
|
|||||||
-- is obj in zone?
|
-- is obj in zone?
|
||||||
local inzone = self:IsCoordinateInZone(obj:GetCoordinate())
|
local inzone = self:IsCoordinateInZone(obj:GetCoordinate())
|
||||||
--self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone))
|
--self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone))
|
||||||
|
if inzone and obj.TriggerInZone[self.ZoneName] then
|
||||||
|
-- just count
|
||||||
|
objcount = objcount + 1
|
||||||
|
self.ObjectsInZone = true
|
||||||
|
obj.TriggerZoneDeadNotification = false
|
||||||
|
end
|
||||||
if inzone and not obj.TriggerInZone[self.ZoneName] then
|
if inzone and not obj.TriggerInZone[self.ZoneName] then
|
||||||
-- wasn't in zone before
|
-- wasn't in zone before
|
||||||
--self:I("Newly entered")
|
--self:I("Newly entered")
|
||||||
self:__EnteredZone(0.5,obj)
|
self:__EnteredZone(0.5,obj)
|
||||||
obj.TriggerInZone[self.ZoneName] = true
|
obj.TriggerInZone[self.ZoneName] = true
|
||||||
|
objcount = objcount + 1
|
||||||
|
self.ObjectsInZone = true
|
||||||
|
obj.TriggerZoneDeadNotification = false
|
||||||
elseif (not inzone) and obj.TriggerInZone[self.ZoneName] then
|
elseif (not inzone) and obj.TriggerInZone[self.ZoneName] then
|
||||||
-- has left the zone
|
-- has left the zone
|
||||||
--self:I("Newly left")
|
--self:I("Newly left")
|
||||||
@@ -696,8 +742,21 @@ function ZONE_BASE:_TriggerCheck(fromstart)
|
|||||||
else
|
else
|
||||||
--self:I("Not left or not entered, or something went wrong!")
|
--self:I("Not left or not entered, or something went wrong!")
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
-- object dead
|
||||||
|
if not obj.TriggerZoneDeadNotification == true then
|
||||||
|
obj.TriggerInZone = nil
|
||||||
|
self:__ObjectDead(0.5,obj)
|
||||||
|
obj.TriggerZoneDeadNotification = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- zone empty?
|
||||||
|
if objcount == 0 and self.ObjectsInZone == true then
|
||||||
|
-- zone was not but is now empty
|
||||||
|
self.ObjectsInZone = false
|
||||||
|
self:__ZoneEmpty(0.5)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -768,8 +827,8 @@ end
|
|||||||
-- Various functions exist to find random points within the zone.
|
-- Various functions exist to find random points within the zone.
|
||||||
--
|
--
|
||||||
-- * @{#ZONE_RADIUS.GetRandomVec2}(): Gets a random 2D point in the zone.
|
-- * @{#ZONE_RADIUS.GetRandomVec2}(): Gets a random 2D point in the zone.
|
||||||
-- * @{#ZONE_RADIUS.GetRandomPointVec2}(): Gets a @{Core.Point#POINT_VEC2} object representing a random 2D point in the zone.
|
-- * @{#ZONE_RADIUS.GetRandomPointVec2}(): Gets a @{Core.Point#COORDINATE} object representing a random 2D point in the zone.
|
||||||
-- * @{#ZONE_RADIUS.GetRandomPointVec3}(): Gets a @{Core.Point#POINT_VEC3} object representing a random 3D point in the zone. Note that the height of the point is at landheight.
|
-- * @{#ZONE_RADIUS.GetRandomPointVec3}(): Gets a @{Core.Point#COORDINATE} object representing a random 3D point in the zone. Note that the height of the point is at landheight.
|
||||||
--
|
--
|
||||||
-- ## Draw zone
|
-- ## Draw zone
|
||||||
--
|
--
|
||||||
@@ -964,7 +1023,7 @@ function ZONE_RADIUS:SmokeZone( SmokeColor, Points, AddHeight, AngleOffset )
|
|||||||
local Radial = ( Angle + AngleOffset ) * RadialBase / 360
|
local Radial = ( Angle + AngleOffset ) * RadialBase / 360
|
||||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||||
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Smoke( SmokeColor )
|
COORDINATE:New( Point.x, AddHeight, Point.y ):Smoke( SmokeColor )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -994,7 +1053,7 @@ function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth, AddHeight )
|
|||||||
local Radial = Angle * RadialBase / 360
|
local Radial = Angle * RadialBase / 360
|
||||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||||
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Flare( FlareColor, Azimuth )
|
COORDINATE:New( Point.x, AddHeight, Point.y ):Flare( FlareColor, Azimuth )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -1415,7 +1474,7 @@ function ZONE_RADIUS:SearchZone( EvaluateFunction, ObjectCategories )
|
|||||||
id = world.VolumeType.SPHERE,
|
id = world.VolumeType.SPHERE,
|
||||||
params = {
|
params = {
|
||||||
point = ZoneCoord:GetVec3(),
|
point = ZoneCoord:GetVec3(),
|
||||||
radius = ZoneRadius / 2,
|
radius = ZoneRadius,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1463,6 +1522,26 @@ function ZONE_RADIUS:IsVec3InZone( Vec3 )
|
|||||||
return InZone
|
return InZone
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||||
|
-- @param #ZONE_RADIUS self
|
||||||
|
-- @param #number PosRadius Required clear radius around each position.
|
||||||
|
-- @param #number NumPositions Number of positions to find.
|
||||||
|
-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found.
|
||||||
|
function ZONE_RADIUS:GetClearZonePositions(PosRadius, NumPositions)
|
||||||
|
return UTILS.GetClearZonePositions(self, PosRadius, NumPositions)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||||
|
-- @param #ZONE_RADIUS self
|
||||||
|
-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200))
|
||||||
|
-- @param #number NumPositions (Optional) Number of positions to find. (Default 50)
|
||||||
|
-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found.
|
||||||
|
-- @return #number Assigned radius for the found zones. nil if no clear positions are found.
|
||||||
|
function ZONE_RADIUS:GetRandomClearZoneCoordinate(PosRadius, NumPositions)
|
||||||
|
return UTILS.GetRandomClearZoneCoordinate(self, PosRadius, NumPositions)
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns a random Vec2 location within the zone.
|
--- Returns a random Vec2 location within the zone.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
@@ -1515,15 +1594,15 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
|||||||
return point
|
return point
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
-- @return Core.Point#POINT_VEC2 The @{Core.Point#POINT_VEC2} object reflecting the random 3D location within the zone.
|
-- @return Core.Point#COORDINATE The @{Core.Point#COORDINATE} object reflecting the random 3D location within the zone.
|
||||||
function ZONE_RADIUS:GetRandomPointVec2( inner, outer )
|
function ZONE_RADIUS:GetRandomPointVec2( inner, outer )
|
||||||
--self:F( self.ZoneName, inner, outer )
|
--self:F( self.ZoneName, inner, outer )
|
||||||
|
|
||||||
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2( inner, outer ) )
|
local PointVec2 = COORDINATE:NewFromVec2( self:GetRandomVec2( inner, outer ) )
|
||||||
|
|
||||||
--self:T3( { PointVec2 } )
|
--self:T3( { PointVec2 } )
|
||||||
|
|
||||||
@@ -1546,15 +1625,15 @@ function ZONE_RADIUS:GetRandomVec3( inner, outer )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC3} object reflecting a random 3D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
-- @return Core.Point#POINT_VEC3 The @{Core.Point#POINT_VEC3} object reflecting the random 3D location within the zone.
|
-- @return Core.Point#COORDINATE The @{Core.Point#COORDINATE} object reflecting the random 3D location within the zone.
|
||||||
function ZONE_RADIUS:GetRandomPointVec3( inner, outer )
|
function ZONE_RADIUS:GetRandomPointVec3( inner, outer )
|
||||||
--self:F( self.ZoneName, inner, outer )
|
--self:F( self.ZoneName, inner, outer )
|
||||||
|
|
||||||
local PointVec3 = POINT_VEC3:NewFromVec2( self:GetRandomVec2( inner, outer ) )
|
local PointVec3 = COORDINATE:NewFromVec2( self:GetRandomVec2( inner, outer ) )
|
||||||
|
|
||||||
--self:T3( { PointVec3 } )
|
--self:T3( { PointVec3 } )
|
||||||
|
|
||||||
@@ -1990,15 +2069,15 @@ function ZONE_GROUP:GetRandomVec2()
|
|||||||
return Point
|
return Point
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_GROUP self
|
-- @param #ZONE_GROUP self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
-- @return Core.Point#POINT_VEC2 The @{Core.Point#POINT_VEC2} object reflecting the random 3D location within the zone.
|
-- @return Core.Point#COORDINATE The @{Core.Point#COORDINATE} object reflecting the random 3D location within the zone.
|
||||||
function ZONE_GROUP:GetRandomPointVec2( inner, outer )
|
function ZONE_GROUP:GetRandomPointVec2( inner, outer )
|
||||||
--self:F( self.ZoneName, inner, outer )
|
--self:F( self.ZoneName, inner, outer )
|
||||||
|
|
||||||
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
|
local PointVec2 = COORDINATE:NewFromVec2( self:GetRandomVec2() )
|
||||||
|
|
||||||
--self:T3( { PointVec2 } )
|
--self:T3( { PointVec2 } )
|
||||||
|
|
||||||
@@ -2046,7 +2125,7 @@ function _ZONE_TRIANGLE:New(p1, p2, p3)
|
|||||||
end
|
end
|
||||||
|
|
||||||
self.SurfaceArea = math.abs((p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y)) * 0.5
|
self.SurfaceArea = math.abs((p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y)) * 0.5
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2054,7 +2133,7 @@ end
|
|||||||
-- @param #_ZONE_TRIANGLE self
|
-- @param #_ZONE_TRIANGLE self
|
||||||
-- @param #table pt The point to check
|
-- @param #table pt The point to check
|
||||||
-- @param #table points (optional) The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it
|
-- @param #table points (optional) The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it
|
||||||
-- @return #bool True if the point is contained, false otherwise
|
-- @return #boolean True if the point is contained, false otherwise
|
||||||
function _ZONE_TRIANGLE:ContainsPoint(pt, points)
|
function _ZONE_TRIANGLE:ContainsPoint(pt, points)
|
||||||
points = points or self.Points
|
points = points or self.Points
|
||||||
|
|
||||||
@@ -2146,8 +2225,8 @@ end
|
|||||||
-- Various functions exist to find random points within the zone.
|
-- Various functions exist to find random points within the zone.
|
||||||
--
|
--
|
||||||
-- * @{#ZONE_POLYGON_BASE.GetRandomVec2}(): Gets a random 2D point in the zone.
|
-- * @{#ZONE_POLYGON_BASE.GetRandomVec2}(): Gets a random 2D point in the zone.
|
||||||
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec2}(): Return a @{Core.Point#POINT_VEC2} object representing a random 2D point within the zone.
|
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec2}(): Return a @{Core.Point#COORDINATE} object representing a random 2D point within the zone.
|
||||||
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec3}(): Return a @{Core.Point#POINT_VEC3} object representing a random 3D point at landheight within the zone.
|
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec3}(): Return a @{Core.Point#COORDINATE} object representing a random 3D point at landheight within the zone.
|
||||||
--
|
--
|
||||||
-- ## Draw zone
|
-- ## Draw zone
|
||||||
--
|
--
|
||||||
@@ -2441,6 +2520,26 @@ function ZONE_POLYGON_BASE:Flush()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||||
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
|
-- @param #number PosRadius Required clear radius around each position.
|
||||||
|
-- @param #number NumPositions Number of positions to find.
|
||||||
|
-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found.
|
||||||
|
function ZONE_POLYGON_BASE:GetClearZonePositions(PosRadius, NumPositions)
|
||||||
|
return UTILS.GetClearZonePositions(self, PosRadius, NumPositions)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||||
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
|
-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200))
|
||||||
|
-- @param #number NumPositions (Optional) Number of positions to find. (Default 50)
|
||||||
|
-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found.
|
||||||
|
-- @return #number Assigned radius for the found zones. nil if no clear positions are found.
|
||||||
|
function ZONE_POLYGON_BASE:GetRandomClearZoneCoordinate(PosRadius, NumPositions)
|
||||||
|
return UTILS.GetRandomClearZoneCoordinate(self, PosRadius, NumPositions)
|
||||||
|
end
|
||||||
|
|
||||||
--- Smokes the zone boundaries in a color.
|
--- Smokes the zone boundaries in a color.
|
||||||
-- @param #ZONE_POLYGON_BASE self
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
-- @param #boolean UnBound If true, the tyres will be destroyed.
|
-- @param #boolean UnBound If true, the tyres will be destroyed.
|
||||||
@@ -2563,7 +2662,7 @@ function ZONE_POLYGON_BASE:ReFill(Color,Alpha)
|
|||||||
self.FillTriangles = {}
|
self.FillTriangles = {}
|
||||||
end
|
end
|
||||||
-- refill
|
-- refill
|
||||||
for _, triangle in pairs(self._Triangles) do
|
for _,triangle in pairs(self._Triangles) do
|
||||||
local draw_ids = triangle:Fill(coalition,color,alpha,nil)
|
local draw_ids = triangle:Fill(coalition,color,alpha,nil)
|
||||||
self.FillTriangles = draw_ids
|
self.FillTriangles = draw_ids
|
||||||
table.combine(self.DrawID, draw_ids)
|
table.combine(self.DrawID, draw_ids)
|
||||||
@@ -2723,7 +2822,7 @@ function ZONE_POLYGON_BASE:SmokeZone( SmokeColor, Segments )
|
|||||||
for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line.
|
for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line.
|
||||||
local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments )
|
local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments )
|
||||||
local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments )
|
local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments )
|
||||||
POINT_VEC2:New( PointX, PointY ):Smoke( SmokeColor )
|
COORDINATE:New( PointX, 0, PointY ):Smoke( SmokeColor )
|
||||||
end
|
end
|
||||||
j = i
|
j = i
|
||||||
i = i + 1
|
i = i + 1
|
||||||
@@ -2758,7 +2857,7 @@ function ZONE_POLYGON_BASE:FlareZone( FlareColor, Segments, Azimuth, AddHeight )
|
|||||||
for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line.
|
for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line.
|
||||||
local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments )
|
local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments )
|
||||||
local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments )
|
local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments )
|
||||||
POINT_VEC2:New( PointX, PointY, AddHeight ):Flare(FlareColor, Azimuth)
|
COORDINATE:New( PointX, AddHeight, PointY ):Flare(FlareColor, Azimuth)
|
||||||
end
|
end
|
||||||
j = i
|
j = i
|
||||||
i = i + 1
|
i = i + 1
|
||||||
@@ -2834,26 +2933,26 @@ function ZONE_POLYGON_BASE:GetRandomVec2()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return a @{Core.Point#POINT_VEC2} object representing a random 2D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
--- Return a @{Core.Point#COORDINATE} object representing a random 2D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_POLYGON_BASE self
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
-- @return @{Core.Point#POINT_VEC2}
|
-- @return @{Core.Point#COORDINATE}
|
||||||
function ZONE_POLYGON_BASE:GetRandomPointVec2()
|
function ZONE_POLYGON_BASE:GetRandomPointVec2()
|
||||||
--self:F2()
|
--self:F2()
|
||||||
|
|
||||||
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
|
local PointVec2 = COORDINATE:NewFromVec2( self:GetRandomVec2() )
|
||||||
|
|
||||||
--self:T2( PointVec2 )
|
--self:T2( PointVec2 )
|
||||||
|
|
||||||
return PointVec2
|
return PointVec2
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return a @{Core.Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
--- Return a @{Core.Point#COORDINATE} object representing a random 3D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_POLYGON_BASE self
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
-- @return @{Core.Point#POINT_VEC3}
|
-- @return @{Core.Point#COORDINATE}
|
||||||
function ZONE_POLYGON_BASE:GetRandomPointVec3()
|
function ZONE_POLYGON_BASE:GetRandomPointVec3()
|
||||||
--self:F2()
|
--self:F2()
|
||||||
|
|
||||||
local PointVec3 = POINT_VEC3:NewFromVec2( self:GetRandomVec2() )
|
local PointVec3 = COORDINATE:NewFromVec2( self:GetRandomVec2() )
|
||||||
|
|
||||||
--self:T2( PointVec3 )
|
--self:T2( PointVec3 )
|
||||||
|
|
||||||
@@ -3158,12 +3257,7 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
|||||||
|
|
||||||
local vectors = self:GetBoundingSquare()
|
local vectors = self:GetBoundingSquare()
|
||||||
|
|
||||||
local minVec3 = {x=vectors.x1, y=0, z=vectors.y1}
|
local ZoneRadius = UTILS.VecDist2D({x=vectors.x1, y=vectors.y1}, {x=vectors.x2, y=vectors.y2})/2
|
||||||
local maxVec3 = {x=vectors.x2, y=0, z=vectors.y2}
|
|
||||||
|
|
||||||
local minmarkcoord = COORDINATE:NewFromVec3(minVec3)
|
|
||||||
local maxmarkcoord = COORDINATE:NewFromVec3(maxVec3)
|
|
||||||
local ZoneRadius = minmarkcoord:Get2DDistance(maxmarkcoord)/2
|
|
||||||
-- self:I("Scan Radius:" ..ZoneRadius)
|
-- self:I("Scan Radius:" ..ZoneRadius)
|
||||||
local CenterVec3 = self:GetCoordinate():GetVec3()
|
local CenterVec3 = self:GetCoordinate():GetVec3()
|
||||||
|
|
||||||
@@ -3536,7 +3630,37 @@ do -- ZONE_ELASTIC
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Remove a vertex (point) from the polygon.
|
||||||
|
-- @param #ZONE_ELASTIC self
|
||||||
|
-- @param DCS#Vec2 Vec2 Point in 2D (with x and y coordinates).
|
||||||
|
-- @return #ZONE_ELASTIC self
|
||||||
|
function ZONE_ELASTIC:RemoveVertex2D(Vec2)
|
||||||
|
|
||||||
|
local found = false
|
||||||
|
local findex = 0
|
||||||
|
for _id,_vec2 in pairs(self.points) do
|
||||||
|
if _vec2.x == Vec2.x and _vec2.y == Vec2.y then
|
||||||
|
found = true
|
||||||
|
findex = _id
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if found == true and findex > 0 then
|
||||||
|
table.remove(self.points,findex)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove a vertex (point) from the polygon.
|
||||||
|
-- @param #ZONE_ELASTIC self
|
||||||
|
-- @param DCS#Vec3 Vec3 Point in 3D (with x, y and z coordinates). Only the x and z coordinates are used.
|
||||||
|
-- @return #ZONE_ELASTIC self
|
||||||
|
function ZONE_ELASTIC:RemoveVertex3D(Vec3)
|
||||||
|
return self:RemoveVertex2D({x=Vec3.x, y=Vec3.z})
|
||||||
|
end
|
||||||
|
|
||||||
--- Add a vertex (point) to the polygon.
|
--- Add a vertex (point) to the polygon.
|
||||||
-- @param #ZONE_ELASTIC self
|
-- @param #ZONE_ELASTIC self
|
||||||
@@ -3574,7 +3698,7 @@ do -- ZONE_ELASTIC
|
|||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
--self:T(string.format("Updating ZONE_ELASTIC %s", tostring(self.ZoneName)))
|
--self:T(string.format("Updating ZONE_ELASTIC %s", tostring(self.ZoneName)))
|
||||||
|
|
||||||
-- Copy all points.
|
-- Copy all points.
|
||||||
local points=UTILS.DeepCopy(self.points or {})
|
local points=UTILS.DeepCopy(self.points or {})
|
||||||
|
|
||||||
@@ -3592,6 +3716,9 @@ do -- ZONE_ELASTIC
|
|||||||
|
|
||||||
-- Update polygon verticies from points.
|
-- Update polygon verticies from points.
|
||||||
self._.Polygon=self:_ConvexHull(points)
|
self._.Polygon=self:_ConvexHull(points)
|
||||||
|
|
||||||
|
self._Triangles = self:_Triangulate()
|
||||||
|
self.SurfaceArea = self:_CalculateSurfaceArea()
|
||||||
|
|
||||||
if Draw~=false then
|
if Draw~=false then
|
||||||
if self.DrawID or Draw==true then
|
if self.DrawID or Draw==true then
|
||||||
@@ -3790,7 +3917,7 @@ end
|
|||||||
--- Checks if a point is contained within the oval.
|
--- Checks if a point is contained within the oval.
|
||||||
-- @param #ZONE_OVAL self
|
-- @param #ZONE_OVAL self
|
||||||
-- @param #table point The point to check
|
-- @param #table point The point to check
|
||||||
-- @return #bool True if the point is contained, false otherwise
|
-- @return #boolean True if the point is contained, false otherwise
|
||||||
function ZONE_OVAL:IsVec2InZone(vec2)
|
function ZONE_OVAL:IsVec2InZone(vec2)
|
||||||
local cos, sin = math.cos, math.sin
|
local cos, sin = math.cos, math.sin
|
||||||
local dx = vec2.x - self.CenterVec2.x
|
local dx = vec2.x - self.CenterVec2.x
|
||||||
@@ -3852,18 +3979,18 @@ function ZONE_OVAL:GetRandomVec2()
|
|||||||
return {x=rx, y=ry}
|
return {x=rx, y=ry}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
--- Define a random @{Core.Point#COORDINATE} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_OVAL self
|
-- @param #ZONE_OVAL self
|
||||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
-- @return Core.Point#COORDINATE The COORDINATE coordinates.
|
||||||
function ZONE_OVAL:GetRandomPointVec2()
|
function ZONE_OVAL:GetRandomPointVec2()
|
||||||
return POINT_VEC2:NewFromVec2(self:GetRandomVec2())
|
return COORDINATE:NewFromVec2(self:GetRandomVec2())
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
--- Define a random @{Core.Point#COORDINATE} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_OVAL self
|
-- @param #ZONE_OVAL self
|
||||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
-- @return Core.Point#COORDINATE The COORDINATE coordinates.
|
||||||
function ZONE_OVAL:GetRandomPointVec3()
|
function ZONE_OVAL:GetRandomPointVec3()
|
||||||
return POINT_VEC3:NewFromVec3(self:GetRandomVec2())
|
return COORDINATE:NewFromVec3(self:GetRandomVec2())
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Draw the zone on the F10 map.
|
--- Draw the zone on the F10 map.
|
||||||
@@ -4003,15 +4130,15 @@ do -- ZONE_AIRBASE
|
|||||||
return ZoneVec2
|
return ZoneVec2
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_AIRBASE self
|
-- @param #ZONE_AIRBASE self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
-- @return Core.Point#POINT_VEC2 The @{Core.Point#POINT_VEC2} object reflecting the random 3D location within the zone.
|
-- @return Core.Point#COORDINATE The @{Core.Point#COORDINATE} object reflecting the random 3D location within the zone.
|
||||||
function ZONE_AIRBASE:GetRandomPointVec2( inner, outer )
|
function ZONE_AIRBASE:GetRandomPointVec2( inner, outer )
|
||||||
--self:F( self.ZoneName, inner, outer )
|
--self:F( self.ZoneName, inner, outer )
|
||||||
|
|
||||||
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
|
local PointVec2 = COORDINATE:NewFromVec2( self:GetRandomVec2() )
|
||||||
|
|
||||||
--self:T3( { PointVec2 } )
|
--self:T3( { PointVec2 } )
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ function ZONE_DETECTION:SmokeZone( SmokeColor, Points, AddHeight, AngleOffset )
|
|||||||
local Radial = ( Angle + AngleOffset ) * RadialBase / 360
|
local Radial = ( Angle + AngleOffset ) * RadialBase / 360
|
||||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||||
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Smoke( SmokeColor )
|
COORDINATE:New( Point.x, AddHeight, Point.y):Smoke( SmokeColor )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -138,7 +138,7 @@ function ZONE_DETECTION:FlareZone( FlareColor, Points, Azimuth, AddHeight )
|
|||||||
local Radial = Angle * RadialBase / 360
|
local Radial = Angle * RadialBase / 360
|
||||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||||
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Flare( FlareColor, Azimuth )
|
COORDINATE:New( Point.x, AddHeight, Point.y ):Flare( FlareColor, Azimuth )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -202,4 +202,3 @@ function ZONE_DETECTION:IsVec3InZone( Vec3 )
|
|||||||
|
|
||||||
return InZone
|
return InZone
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ do -- world
|
|||||||
-- @field #world.event event [https://wiki.hoggitworld.com/view/DCS_enum_world](https://wiki.hoggitworld.com/view/DCS_enum_world)
|
-- @field #world.event event [https://wiki.hoggitworld.com/view/DCS_enum_world](https://wiki.hoggitworld.com/view/DCS_enum_world)
|
||||||
-- @field #world.BirthPlace BirthPlace The birthplace enumerator is used to define where an aircraft or helicopter has spawned in association with birth events.
|
-- @field #world.BirthPlace BirthPlace The birthplace enumerator is used to define where an aircraft or helicopter has spawned in association with birth events.
|
||||||
-- @field #world.VolumeType VolumeType The volumeType enumerator defines the types of 3d geometery used within the [world.searchObjects](https://wiki.hoggitworld.com/view/DCS_func_searchObjects) function.
|
-- @field #world.VolumeType VolumeType The volumeType enumerator defines the types of 3d geometery used within the [world.searchObjects](https://wiki.hoggitworld.com/view/DCS_func_searchObjects) function.
|
||||||
|
-- @field #world.weather weather Weather functions for fog etc.
|
||||||
|
|
||||||
--- The world singleton contains functions centered around two different but extremely useful functions.
|
--- The world singleton contains functions centered around two different but extremely useful functions.
|
||||||
-- * Events and event handlers are all governed within world.
|
-- * Events and event handlers are all governed within world.
|
||||||
@@ -132,6 +133,36 @@ do -- world
|
|||||||
-- @function [parent=#world] getAirbases
|
-- @function [parent=#world] getAirbases
|
||||||
-- @param #number coalitionId The coalition side number ID. Default is all airbases are returned.
|
-- @param #number coalitionId The coalition side number ID. Default is all airbases are returned.
|
||||||
-- @return #table Table of DCS airbase objects.
|
-- @return #table Table of DCS airbase objects.
|
||||||
|
|
||||||
|
|
||||||
|
--- Weather functions.
|
||||||
|
-- @type world.weather
|
||||||
|
|
||||||
|
--- Fog animation data structure.
|
||||||
|
-- @type world.FogAnimation
|
||||||
|
-- @field #number time
|
||||||
|
-- @field #number visibility
|
||||||
|
-- @field #number thickness
|
||||||
|
|
||||||
|
--- Returns the current fog thickness.
|
||||||
|
-- @function [parent=#world.weather] getFogThickness Returns the fog thickness.
|
||||||
|
-- @return #number Fog thickness in meters. If there is no fog, zero is returned.
|
||||||
|
|
||||||
|
--- Sets the fog thickness instantly. Any current fog animation is discarded.
|
||||||
|
-- @function [parent=#world.weather] setFogThickness
|
||||||
|
-- @param #number thickness Fog thickness in meters. Set to zero to disable fog.
|
||||||
|
|
||||||
|
--- Returns the current fog visibility distance.
|
||||||
|
-- @function [parent=#world.weather] getFogVisibilityDistance Returns the current maximum visibility distance in meters. Returns zero if fog is not present.
|
||||||
|
|
||||||
|
--- Instantly sets the maximum visibility distance of fog at sea level when looking at the horizon. Any current fog animation is discarded. Set zero to disable the fog.
|
||||||
|
-- @function [parent=#world.weather] setFogVisibilityDistance
|
||||||
|
-- @param #number visibility Max fog visibility in meters. Set to zero to disable fog.
|
||||||
|
|
||||||
|
--- Sets fog animation keys. Time is set in seconds and relative to the current simulation time, where time=0 is the current moment.
|
||||||
|
-- Time must be increasing. Previous animation is always discarded despite the data being correct.
|
||||||
|
-- @function [parent=#world.weather] setFogAnimation
|
||||||
|
-- @param #world.FogAnimation animation List of fog animations
|
||||||
|
|
||||||
end -- world
|
end -- world
|
||||||
|
|
||||||
@@ -167,7 +198,7 @@ end -- env
|
|||||||
|
|
||||||
do -- radio
|
do -- radio
|
||||||
|
|
||||||
---@type radio
|
--@type radio
|
||||||
-- @field #radio.modulation modulation
|
-- @field #radio.modulation modulation
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -407,7 +438,7 @@ do -- coalition
|
|||||||
-- @param #table groupData Group data table.
|
-- @param #table groupData Group data table.
|
||||||
-- @return DCS#Group The spawned Group object.
|
-- @return DCS#Group The spawned Group object.
|
||||||
|
|
||||||
--- Dynamically spawns a static object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addGroup)
|
--- Dynamically spawns a static object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addStaticObject)
|
||||||
-- @function [parent=#coalition] addStaticObject
|
-- @function [parent=#coalition] addStaticObject
|
||||||
-- @param #number countryId Id of the country.
|
-- @param #number countryId Id of the country.
|
||||||
-- @param #table groupData Group data table.
|
-- @param #table groupData Group data table.
|
||||||
@@ -420,6 +451,7 @@ end -- coalition
|
|||||||
|
|
||||||
do -- Types
|
do -- Types
|
||||||
|
|
||||||
|
--- Descriptors.
|
||||||
-- @type Desc
|
-- @type Desc
|
||||||
-- @field #number speedMax0 Max speed in meters/second at zero altitude.
|
-- @field #number speedMax0 Max speed in meters/second at zero altitude.
|
||||||
-- @field #number massEmpty Empty mass in kg.
|
-- @field #number massEmpty Empty mass in kg.
|
||||||
@@ -598,9 +630,13 @@ do -- Object
|
|||||||
--- @function [parent=#Object] destroy
|
--- @function [parent=#Object] destroy
|
||||||
-- @param #Object self
|
-- @param #Object self
|
||||||
|
|
||||||
--- @function [parent=#Object] getCategory
|
--- Returns an enumerator of the category for the specific object.
|
||||||
|
-- The enumerator returned is dependent on the category of the object and how the function is called.
|
||||||
|
-- As of DCS 2.9.2 when this function is called on an Object, Unit, Weapon, or Airbase a 2nd value will be returned which details the object sub-category value.
|
||||||
|
-- @function [parent=#Object] getCategory
|
||||||
-- @param #Object self
|
-- @param #Object self
|
||||||
-- @return #Object.Category
|
-- @return #Object.Category The object category (1=UNIT, 2=WEAPON, 3=STATIC, 4=BASE, 5=SCENERY, 6=Cargo)
|
||||||
|
-- @return #number The subcategory of the passed object, e.g. Unit.Category if a unit object was passed.
|
||||||
|
|
||||||
--- Returns type name of the Object.
|
--- Returns type name of the Object.
|
||||||
-- @function [parent=#Object] getTypeName
|
-- @function [parent=#Object] getTypeName
|
||||||
@@ -1013,14 +1049,16 @@ do -- Spot
|
|||||||
end -- Spot
|
end -- Spot
|
||||||
|
|
||||||
do -- Controller
|
do -- Controller
|
||||||
|
|
||||||
--- Controller is an object that performs A.I.-tasks. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C.
|
--- Controller is an object that performs A.I.-tasks. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C.
|
||||||
--
|
--
|
||||||
-- This class has 2 types of functions:
|
-- This class has 2 types of functions:
|
||||||
--
|
--
|
||||||
-- * Tasks
|
-- * Tasks
|
||||||
-- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics.
|
-- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics.
|
||||||
|
--
|
||||||
-- @type Controller
|
-- @type Controller
|
||||||
-- @field #Controller.Detection Detection Enum contains identifiers of surface types.
|
-- @field #Controller.Detection Detection Enum contains identifiers of surface types.
|
||||||
|
|
||||||
--- Enables and disables the controller.
|
--- Enables and disables the controller.
|
||||||
-- Note: Now it works only for ground / naval groups!
|
-- Note: Now it works only for ground / naval groups!
|
||||||
@@ -1079,18 +1117,18 @@ do -- Controller
|
|||||||
|
|
||||||
-- Detection
|
-- Detection
|
||||||
|
|
||||||
--- Enum contains identifiers of surface types.
|
--- Enum containing detection types.
|
||||||
-- @type Controller.Detection
|
-- @type Controller.Detection
|
||||||
-- @field VISUAL
|
-- @field #number VISUAL Visual detection. Numeric value 1.
|
||||||
-- @field OPTIC
|
-- @field #number OPTIC Optical detection. Numeric value 2.
|
||||||
-- @field RADAR
|
-- @field #number RADAR Radar detection. Numeric value 4.
|
||||||
-- @field IRST
|
-- @field #number IRST Infra-red search and track detection. Numeric value 8.
|
||||||
-- @field RWR
|
-- @field #number RWR Radar Warning Receiver detection. Numeric value 16.
|
||||||
-- @field DLINK
|
-- @field #number DLINK Data link detection. Numeric value 32.
|
||||||
|
|
||||||
--- Detected target.
|
--- Detected target.
|
||||||
-- @type DetectedTarget
|
-- @type Controller.DetectedTarget
|
||||||
-- @field Wrapper.Object#Object object The target
|
-- @field DCS#Object object The target
|
||||||
-- @field #boolean visible The target is visible
|
-- @field #boolean visible The target is visible
|
||||||
-- @field #boolean type The target type is known
|
-- @field #boolean type The target type is known
|
||||||
-- @field #boolean distance Distance to the target is known
|
-- @field #boolean distance Distance to the target is known
|
||||||
@@ -1103,9 +1141,9 @@ do -- Controller
|
|||||||
-- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
|
-- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
|
||||||
-- @return #boolean detected True if the target is detected.
|
-- @return #boolean detected True if the target is detected.
|
||||||
-- @return #boolean visible Has effect only if detected is true. True if the target is visible now.
|
-- @return #boolean visible Has effect only if detected is true. True if the target is visible now.
|
||||||
|
-- @return #boolean type Has effect only if detected is true. True if the target type is known.
|
||||||
|
-- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known.
|
||||||
-- @return #ModelTime lastTime Has effect only if visible is false. Last time when target was seen.
|
-- @return #ModelTime lastTime Has effect only if visible is false. Last time when target was seen.
|
||||||
-- @return #boolean type Has effect only if detected is true. True if the target type is known.
|
|
||||||
-- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known.
|
|
||||||
-- @return #Vec3 lastPos Has effect only if visible is false. Last position of the target when it was seen.
|
-- @return #Vec3 lastPos Has effect only if visible is false. Last position of the target when it was seen.
|
||||||
-- @return #Vec3 lastVel Has effect only if visible is false. Last velocity of the target when it was seen.
|
-- @return #Vec3 lastVel Has effect only if visible is false. Last velocity of the target when it was seen.
|
||||||
|
|
||||||
@@ -1131,6 +1169,7 @@ end -- Controller
|
|||||||
|
|
||||||
do -- Unit
|
do -- Unit
|
||||||
|
|
||||||
|
--- Unit.
|
||||||
-- @type Unit
|
-- @type Unit
|
||||||
-- @extends #CoalitionObject
|
-- @extends #CoalitionObject
|
||||||
-- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically.
|
-- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically.
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Applevangelist**
|
-- ### Author: **Applevangelist**
|
||||||
-- Last Update Sept 2023
|
-- Last Update July 2025
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
-- @module Functional.AICSAR
|
-- @module Functional.AICSAR
|
||||||
@@ -57,6 +57,8 @@
|
|||||||
-- @field #number Speed Default speed setting for the helicopter FLIGHTGROUP is 100kn.
|
-- @field #number Speed Default speed setting for the helicopter FLIGHTGROUP is 100kn.
|
||||||
-- @field #boolean UseEventEject In case Event LandingAfterEjection isn't working, use set this to true.
|
-- @field #boolean UseEventEject In case Event LandingAfterEjection isn't working, use set this to true.
|
||||||
-- @field #number Delay In case of UseEventEject wait this long until we spawn a landed pilot.
|
-- @field #number Delay In case of UseEventEject wait this long until we spawn a landed pilot.
|
||||||
|
-- @field #boolean UseRescueZone If true, use a rescue zone and not the max distance to FARP/MASH
|
||||||
|
-- @field Core.Zone#ZONE_RADIUS RescueZone Use this zone as operational area for the AICSAR instance.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
@@ -153,10 +155,10 @@
|
|||||||
-- To set up AICSAR for SRS TTS output, add e.g. the following to your script:
|
-- To set up AICSAR for SRS TTS output, add e.g. the following to your script:
|
||||||
--
|
--
|
||||||
-- -- setup for google TTS, radio 243 AM, SRS server port 5002 with a google standard-quality voice (google cloud account required)
|
-- -- setup for google TTS, radio 243 AM, SRS server port 5002 with a google standard-quality voice (google cloud account required)
|
||||||
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",243,radio.modulation.AM,5002,MSRS.Voices.Google.Standard.en_US_Standard_D,"en-US","female","C:\\Program Files\\DCS-SimpleRadio-Standalone\\google.json")
|
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",243,radio.modulation.AM,5002,MSRS.Voices.Google.Standard.en_US_Standard_D,"en-US","female","C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\google.json")
|
||||||
--
|
--
|
||||||
-- -- alternatively for MS Desktop TTS (voices need to be installed locally first!)
|
-- -- alternatively for MS Desktop TTS (voices need to be installed locally first!)
|
||||||
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",243,radio.modulation.AM,5002,MSRS.Voices.Microsoft.Hazel,"en-GB","female")
|
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",243,radio.modulation.AM,5002,MSRS.Voices.Microsoft.Hazel,"en-GB","female")
|
||||||
--
|
--
|
||||||
-- -- define a different voice for the downed pilot(s)
|
-- -- define a different voice for the downed pilot(s)
|
||||||
-- my_aicsar:SetPilotTTSVoice(MSRS.Voices.Google.Standard.en_AU_Standard_D,"en-AU","male")
|
-- my_aicsar:SetPilotTTSVoice(MSRS.Voices.Google.Standard.en_AU_Standard_D,"en-AU","male")
|
||||||
@@ -177,7 +179,7 @@
|
|||||||
--
|
--
|
||||||
-- Switch on radio transmissions via **either** SRS **or** "normal" DCS radio e.g. like so:
|
-- Switch on radio transmissions via **either** SRS **or** "normal" DCS radio e.g. like so:
|
||||||
--
|
--
|
||||||
-- my_aicsar:SetSRSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",270,radio.modulation.AM,nil,5002)
|
-- my_aicsar:SetSRSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",270,radio.modulation.AM,nil,5002)
|
||||||
--
|
--
|
||||||
-- or
|
-- or
|
||||||
--
|
--
|
||||||
@@ -191,7 +193,7 @@
|
|||||||
-- @field #AICSAR
|
-- @field #AICSAR
|
||||||
AICSAR = {
|
AICSAR = {
|
||||||
ClassName = "AICSAR",
|
ClassName = "AICSAR",
|
||||||
version = "0.1.16",
|
version = "0.1.18",
|
||||||
lid = "",
|
lid = "",
|
||||||
coalition = coalition.side.BLUE,
|
coalition = coalition.side.BLUE,
|
||||||
template = "",
|
template = "",
|
||||||
@@ -236,6 +238,8 @@ AICSAR = {
|
|||||||
Altitude = 1500,
|
Altitude = 1500,
|
||||||
UseEventEject = false,
|
UseEventEject = false,
|
||||||
Delay = 100,
|
Delay = 100,
|
||||||
|
UseRescueZone = false,
|
||||||
|
RescueZone = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- TODO Messages
|
-- TODO Messages
|
||||||
@@ -304,8 +308,9 @@ AICSAR.RadioLength = {
|
|||||||
-- @param #string Helotemplate Helicopter template name.
|
-- @param #string Helotemplate Helicopter template name.
|
||||||
-- @param Wrapper.Airbase#AIRBASE FARP FARP object or Airbase from where to start.
|
-- @param Wrapper.Airbase#AIRBASE FARP FARP object or Airbase from where to start.
|
||||||
-- @param Core.Zone#ZONE MASHZone Zone where to drop pilots after rescue.
|
-- @param Core.Zone#ZONE MASHZone Zone where to drop pilots after rescue.
|
||||||
|
-- @param #number Helonumber Max number of alive Ai Helos at the same time. Defaults to three.
|
||||||
-- @return #AICSAR self
|
-- @return #AICSAR self
|
||||||
function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone)
|
function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone,Helonumber)
|
||||||
-- Inherit everything from FSM class.
|
-- Inherit everything from FSM class.
|
||||||
local self=BASE:Inherit(self, FSM:New())
|
local self=BASE:Inherit(self, FSM:New())
|
||||||
|
|
||||||
@@ -373,7 +378,7 @@ function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone)
|
|||||||
|
|
||||||
-- limit number of available helos at the same time
|
-- limit number of available helos at the same time
|
||||||
self.limithelos = true
|
self.limithelos = true
|
||||||
self.helonumber = 3
|
self.helonumber = Helonumber or 3
|
||||||
|
|
||||||
-- localization
|
-- localization
|
||||||
self:InitLocalization()
|
self:InitLocalization()
|
||||||
@@ -524,10 +529,20 @@ function AICSAR:InitLocalization()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Use a defined zone as area of operation and not the distance to FARP.
|
||||||
|
-- @param #AICSAR self
|
||||||
|
-- @param Core.Zone#ZONE Zone The operational zone to use. Downed pilots in this area will be rescued. Can be any known #ZONE type.
|
||||||
|
-- @return #AICSAR self
|
||||||
|
function AICSAR:SetUsingRescueZone(Zone)
|
||||||
|
self.UseRescueZone = true
|
||||||
|
self.RescueZone = Zone
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [User] Switch sound output on and use SRS output for sound files.
|
--- [User] Switch sound output on and use SRS output for sound files.
|
||||||
-- @param #AICSAR self
|
-- @param #AICSAR self
|
||||||
-- @param #boolean OnOff Switch on (true) or off (false).
|
-- @param #boolean OnOff Switch on (true) or off (false).
|
||||||
-- @param #string Path Path to your SRS Server Component, e.g. "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone"
|
-- @param #string Path Path to your SRS Server External Audio Component, e.g. "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\\\ExternalAudio"
|
||||||
-- @param #number Frequency Defaults to 243 (guard)
|
-- @param #number Frequency Defaults to 243 (guard)
|
||||||
-- @param #number Modulation Radio modulation. Defaults to radio.modulation.AM
|
-- @param #number Modulation Radio modulation. Defaults to radio.modulation.AM
|
||||||
-- @param #string SoundPath Where to find the audio files. Defaults to nil, i.e. add messages via "Sound to..." in the Mission Editor.
|
-- @param #string SoundPath Where to find the audio files. Defaults to nil, i.e. add messages via "Sound to..." in the Mission Editor.
|
||||||
@@ -538,7 +553,7 @@ function AICSAR:SetSRSRadio(OnOff,Path,Frequency,Modulation,SoundPath,Port)
|
|||||||
self.SRSRadio = OnOff and true
|
self.SRSRadio = OnOff and true
|
||||||
self.SRSTTSRadio = false
|
self.SRSTTSRadio = false
|
||||||
self.SRSFrequency = Frequency or 243
|
self.SRSFrequency = Frequency or 243
|
||||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||||
self.SRS:SetLabel("ACSR")
|
self.SRS:SetLabel("ACSR")
|
||||||
self.SRS:SetCoalition(self.coalition)
|
self.SRS:SetCoalition(self.coalition)
|
||||||
self.SRSModulation = Modulation or radio.modulation.AM
|
self.SRSModulation = Modulation or radio.modulation.AM
|
||||||
@@ -556,7 +571,7 @@ end
|
|||||||
-- See `AICSAR:SetPilotTTSVoice()` and `AICSAR:SetOperatorTTSVoice()`
|
-- See `AICSAR:SetPilotTTSVoice()` and `AICSAR:SetOperatorTTSVoice()`
|
||||||
-- @param #AICSAR self
|
-- @param #AICSAR self
|
||||||
-- @param #boolean OnOff Switch on (true) or off (false).
|
-- @param #boolean OnOff Switch on (true) or off (false).
|
||||||
-- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone"
|
-- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||||
-- @param #number Frequency (Optional) Defaults to 243 (guard)
|
-- @param #number Frequency (Optional) Defaults to 243 (guard)
|
||||||
-- @param #number Modulation (Optional) Radio modulation. Defaults to radio.modulation.AM
|
-- @param #number Modulation (Optional) Radio modulation. Defaults to radio.modulation.AM
|
||||||
-- @param #number Port (Optional) Port of the SRS, defaults to 5002.
|
-- @param #number Port (Optional) Port of the SRS, defaults to 5002.
|
||||||
@@ -570,7 +585,7 @@ function AICSAR:SetSRSTTSRadio(OnOff,Path,Frequency,Modulation,Port,Voice,Cultur
|
|||||||
self.SRSTTSRadio = OnOff and true
|
self.SRSTTSRadio = OnOff and true
|
||||||
self.SRSRadio = false
|
self.SRSRadio = false
|
||||||
self.SRSFrequency = Frequency or 243
|
self.SRSFrequency = Frequency or 243
|
||||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||||
self.SRSModulation = Modulation or radio.modulation.AM
|
self.SRSModulation = Modulation or radio.modulation.AM
|
||||||
self.SRSPort = Port or MSRS.port or 5002
|
self.SRSPort = Port or MSRS.port or 5002
|
||||||
if OnOff then
|
if OnOff then
|
||||||
@@ -693,7 +708,7 @@ function AICSAR:_EjectEventHandler(EventData)
|
|||||||
local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p)
|
local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p)
|
||||||
local _country = _event.initiator:getCountry()
|
local _country = _event.initiator:getCountry()
|
||||||
local _coalition = coalition.getCountryCoalition( _country )
|
local _coalition = coalition.getCountryCoalition( _country )
|
||||||
local data = UTILS.DeepCopy(EventData)
|
--local data = UTILS.DeepCopy(EventData)
|
||||||
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
|
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
|
||||||
self:ScheduleOnce(self.Delay,self._DelayedSpawnPilot,self,_LandingPos,_coalition)
|
self:ScheduleOnce(self.Delay,self._DelayedSpawnPilot,self,_LandingPos,_coalition)
|
||||||
end
|
end
|
||||||
@@ -708,7 +723,14 @@ end
|
|||||||
-- @return #AICSAR self
|
-- @return #AICSAR self
|
||||||
function AICSAR:_DelayedSpawnPilot(_LandingPos,_coalition)
|
function AICSAR:_DelayedSpawnPilot(_LandingPos,_coalition)
|
||||||
|
|
||||||
local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate())
|
local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate())
|
||||||
|
if self.UseRescueZone == true and self.RescueZone ~= nil then
|
||||||
|
if self.RescueZone:IsCoordinateInZone(_LandingPos) then
|
||||||
|
distancetofarp = self.maxdistance - 10
|
||||||
|
else
|
||||||
|
distancetofarp = self.maxdistance + 10
|
||||||
|
end
|
||||||
|
end
|
||||||
-- Mayday Message
|
-- Mayday Message
|
||||||
local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale)
|
local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale)
|
||||||
local text = ""
|
local text = ""
|
||||||
@@ -795,7 +817,13 @@ function AICSAR:_EventHandler(EventData, FromEject)
|
|||||||
|
|
||||||
-- DONE: add distance check
|
-- DONE: add distance check
|
||||||
local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate())
|
local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate())
|
||||||
|
if self.UseRescueZone == true and self.RescueZone ~= nil then
|
||||||
|
if self.RescueZone:IsCoordinateInZone(_LandingPos) then
|
||||||
|
distancetofarp = self.maxdistance - 10
|
||||||
|
else
|
||||||
|
distancetofarp = self.maxdistance + 10
|
||||||
|
end
|
||||||
|
end
|
||||||
-- Mayday Message
|
-- Mayday Message
|
||||||
local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale)
|
local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale)
|
||||||
local text = ""
|
local text = ""
|
||||||
@@ -817,7 +845,6 @@ function AICSAR:_EventHandler(EventData, FromEject)
|
|||||||
if _coalition == self.coalition then
|
if _coalition == self.coalition then
|
||||||
if self.verbose then
|
if self.verbose then
|
||||||
MESSAGE:New(msgtxt,15,"AICSAR"):ToCoalition(self.coalition)
|
MESSAGE:New(msgtxt,15,"AICSAR"):ToCoalition(self.coalition)
|
||||||
-- MESSAGE:New(msgtxt,15,"AICSAR"):ToLog()
|
|
||||||
end
|
end
|
||||||
if self.SRSRadio then
|
if self.SRSRadio then
|
||||||
local sound = SOUNDFILE:New(Soundfile,self.SRSSoundPath,Soundlength)
|
local sound = SOUNDFILE:New(Soundfile,self.SRSSoundPath,Soundlength)
|
||||||
@@ -869,6 +896,7 @@ function AICSAR:_GetFlight()
|
|||||||
:InitUnControlled(true)
|
:InitUnControlled(true)
|
||||||
:OnSpawnGroup(
|
:OnSpawnGroup(
|
||||||
function(Group)
|
function(Group)
|
||||||
|
Group:OptionPreferVerticalLanding()
|
||||||
self:__HeloOnDuty(1,Group)
|
self:__HeloOnDuty(1,Group)
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
@@ -892,7 +920,7 @@ function AICSAR:_InitMission(Pilot,Index)
|
|||||||
--local pilotset = SET_GROUP:New()
|
--local pilotset = SET_GROUP:New()
|
||||||
--pilotset:AddGroup(Pilot)
|
--pilotset:AddGroup(Pilot)
|
||||||
|
|
||||||
-- Cargo transport assignment.
|
-- Cargo transport assignment.
|
||||||
local opstransport=OPSTRANSPORT:New(Pilot, pickupzone, self.farpzone)
|
local opstransport=OPSTRANSPORT:New(Pilot, pickupzone, self.farpzone)
|
||||||
--opstransport:SetVerbosity(3)
|
--opstransport:SetVerbosity(3)
|
||||||
|
|
||||||
@@ -934,6 +962,10 @@ function AICSAR:_InitMission(Pilot,Index)
|
|||||||
helo:__UnloadingDone(5)
|
helo:__UnloadingDone(5)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function helo:OnAfterLandAtAirbase(From,Event,To,airbase)
|
||||||
|
helo:Despawn(2)
|
||||||
|
end
|
||||||
|
|
||||||
self.helos[Index] = helo
|
self.helos[Index] = helo
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -984,7 +1016,9 @@ function AICSAR:_CheckHelos()
|
|||||||
local name = helo:GetName()
|
local name = helo:GetName()
|
||||||
self:T("Helo group "..name.." in state "..state)
|
self:T("Helo group "..name.." in state "..state)
|
||||||
if state == "Arrived" then
|
if state == "Arrived" then
|
||||||
helo:__Stop(5)
|
--helo:__Stop(5)
|
||||||
|
helo.OnAfterDead = nil
|
||||||
|
helo:Despawn(35)
|
||||||
self.helos[_index] = nil
|
self.helos[_index] = nil
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -1025,7 +1059,7 @@ function AICSAR:_CheckQueue(OpsGroup)
|
|||||||
if self:_CheckInMashZone(_pilot) then
|
if self:_CheckInMashZone(_pilot) then
|
||||||
self:T("Pilot" .. _pilot.GroupName .. " rescued!")
|
self:T("Pilot" .. _pilot.GroupName .. " rescued!")
|
||||||
if OpsGroup then
|
if OpsGroup then
|
||||||
OpsGroup:Despawn(10)
|
--OpsGroup:Despawn(10)
|
||||||
else
|
else
|
||||||
_pilot:Destroy(true,10)
|
_pilot:Destroy(true,10)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
-- ### Author: FlightControl - Framework Design & Programming
|
-- ### Author: FlightControl - Framework Design & Programming
|
||||||
-- ### Refactoring to use the Runway auto-detection: Applevangelist
|
-- ### Refactoring to use the Runway auto-detection: Applevangelist
|
||||||
-- @date August 2022
|
-- @date August 2022
|
||||||
-- Last Update Nov 2023
|
-- Last Update Feb 2025
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -416,7 +416,7 @@ end
|
|||||||
-- @field #ATC_GROUND_UNIVERSAL
|
-- @field #ATC_GROUND_UNIVERSAL
|
||||||
ATC_GROUND_UNIVERSAL = {
|
ATC_GROUND_UNIVERSAL = {
|
||||||
ClassName = "ATC_GROUND_UNIVERSAL",
|
ClassName = "ATC_GROUND_UNIVERSAL",
|
||||||
Version = "0.0.1",
|
Version = "0.0.2",
|
||||||
SetClient = nil,
|
SetClient = nil,
|
||||||
Airbases = nil,
|
Airbases = nil,
|
||||||
AirbaseList = nil,
|
AirbaseList = nil,
|
||||||
@@ -441,17 +441,25 @@ function ATC_GROUND_UNIVERSAL:New(AirbaseList)
|
|||||||
self:T( { self.ClassName } )
|
self:T( { self.ClassName } )
|
||||||
|
|
||||||
self.Airbases = {}
|
self.Airbases = {}
|
||||||
|
|
||||||
for _name,_ in pairs(_DATABASE.AIRBASES) do
|
|
||||||
self.Airbases[_name]={}
|
|
||||||
end
|
|
||||||
|
|
||||||
self.AirbaseList = AirbaseList
|
self.AirbaseList = AirbaseList
|
||||||
|
|
||||||
if not self.AirbaseList then
|
if not self.AirbaseList then
|
||||||
self.AirbaseList = {}
|
self.AirbaseList = {}
|
||||||
for _name,_ in pairs(_DATABASE.AIRBASES) do
|
for _name,_base in pairs(_DATABASE.AIRBASES) do
|
||||||
self.AirbaseList[_name]=_name
|
-- DONE exclude FARPS and Ships
|
||||||
|
if _base and _base.isAirdrome == true then
|
||||||
|
self.AirbaseList[_name]=_name
|
||||||
|
self.Airbases[_name]={}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for _,_name in pairs(AirbaseList) do
|
||||||
|
-- DONE exclude FARPS and Ships
|
||||||
|
local airbase = _DATABASE:FindAirbase(_name)
|
||||||
|
if airbase and (airbase.isAirdrome == true) then
|
||||||
|
self.Airbases[_name]={}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -721,14 +729,18 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
|||||||
|
|
||||||
if NotInRunwayZone then
|
if NotInRunwayZone then
|
||||||
|
|
||||||
|
local Taxi = Client:GetState( self, "Taxi" )
|
||||||
|
|
||||||
if IsOnGround then
|
if IsOnGround then
|
||||||
local Taxi = Client:GetState( self, "Taxi" )
|
|
||||||
self:T( Taxi )
|
self:T( Taxi )
|
||||||
if Taxi == false then
|
if Taxi == false then
|
||||||
local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed )
|
local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed )
|
||||||
Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " ..
|
Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " ..
|
||||||
Velocity:ToString() , 20, "ATC" )
|
Velocity:ToString() , 20, "ATC" )
|
||||||
Client:SetState( self, "Taxi", true )
|
Client:SetState( self, "Taxi", true )
|
||||||
|
Client:SetState( self, "Speeding", false )
|
||||||
|
Client:SetState( self, "Warnings", 0 )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO: GetVelocityKMH function usage
|
-- TODO: GetVelocityKMH function usage
|
||||||
@@ -737,7 +749,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
|||||||
local IsAboveRunway = Client:IsAboveRunway()
|
local IsAboveRunway = Client:IsAboveRunway()
|
||||||
self:T( {IsAboveRunway, IsOnGround, Velocity:Get() })
|
self:T( {IsAboveRunway, IsOnGround, Velocity:Get() })
|
||||||
|
|
||||||
if IsOnGround then
|
if IsOnGround and not Taxi then
|
||||||
local Speeding = false
|
local Speeding = false
|
||||||
if AirbaseMeta.MaximumKickSpeed then
|
if AirbaseMeta.MaximumKickSpeed then
|
||||||
if Velocity:Get() > AirbaseMeta.MaximumKickSpeed then
|
if Velocity:Get() > AirbaseMeta.MaximumKickSpeed then
|
||||||
@@ -749,15 +761,17 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if Speeding == true then
|
if Speeding == true then
|
||||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
|
--MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
|
||||||
" has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
-- " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||||
Client:Destroy()
|
--Client:Destroy()
|
||||||
Client:SetState( self, "Speeding", false )
|
Client:SetState( self, "Speeding", true )
|
||||||
Client:SetState( self, "Warnings", 0 )
|
local SpeedingWarnings = Client:GetState( self, "Warnings" )
|
||||||
|
Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
|
||||||
|
Client:Message( "Warning " .. SpeedingWarnings .. "/3! Airbase traffic rule violation! Slow down now! Your speed is " ..
|
||||||
|
Velocity:ToString(), 5, "ATC" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if IsOnGround then
|
if IsOnGround then
|
||||||
|
|
||||||
local Speeding = false
|
local Speeding = false
|
||||||
@@ -1035,23 +1049,23 @@ end
|
|||||||
-- The following airbases are monitored at the Nevada region.
|
-- The following airbases are monitored at the Nevada region.
|
||||||
-- Use the @{Wrapper.Airbase#AIRBASE.Nevada} enumeration to select the airbases to be monitored.
|
-- Use the @{Wrapper.Airbase#AIRBASE.Nevada} enumeration to select the airbases to be monitored.
|
||||||
--
|
--
|
||||||
-- * `AIRBASE.Nevada.Beatty_Airport`
|
-- * `AIRBASE.Nevada.Beatty`
|
||||||
-- * `AIRBASE.Nevada.Boulder_City_Airport`
|
-- * `AIRBASE.Nevada.Boulder_City`
|
||||||
-- * `AIRBASE.Nevada.Creech_AFB`
|
-- * `AIRBASE.Nevada.Creech`
|
||||||
-- * `AIRBASE.Nevada.Echo_Bay`
|
-- * `AIRBASE.Nevada.Echo_Bay`
|
||||||
-- * `AIRBASE.Nevada.Groom_Lake_AFB`
|
-- * `AIRBASE.Nevada.Groom_Lake`
|
||||||
-- * `AIRBASE.Nevada.Henderson_Executive_Airport`
|
-- * `AIRBASE.Nevada.Henderson_Executive`
|
||||||
-- * `AIRBASE.Nevada.Jean_Airport`
|
-- * `AIRBASE.Nevada.Jean`
|
||||||
-- * `AIRBASE.Nevada.Laughlin_Airport`
|
-- * `AIRBASE.Nevada.Laughlin`
|
||||||
-- * `AIRBASE.Nevada.Lincoln_County`
|
-- * `AIRBASE.Nevada.Lincoln_County`
|
||||||
-- * `AIRBASE.Nevada.McCarran_International_Airport`
|
-- * `AIRBASE.Nevada.McCarran_International`
|
||||||
-- * `AIRBASE.Nevada.Mesquite`
|
-- * `AIRBASE.Nevada.Mesquite`
|
||||||
-- * `AIRBASE.Nevada.Mina_Airport`
|
-- * `AIRBASE.Nevada.Mina`
|
||||||
-- * `AIRBASE.Nevada.Nellis_AFB`
|
-- * `AIRBASE.Nevada.Nellis`
|
||||||
-- * `AIRBASE.Nevada.North_Las_Vegas`
|
-- * `AIRBASE.Nevada.North_Las_Vegas`
|
||||||
-- * `AIRBASE.Nevada.Pahute_Mesa_Airstrip`
|
-- * `AIRBASE.Nevada.Pahute_Mesa`
|
||||||
-- * `AIRBASE.Nevada.Tonopah_Airport`
|
-- * `AIRBASE.Nevada.Tonopah`
|
||||||
-- * `AIRBASE.Nevada.Tonopah_Test_Range_Airfield`
|
-- * `AIRBASE.Nevada.Tonopah_Test_Range`
|
||||||
--
|
--
|
||||||
-- # Installation
|
-- # Installation
|
||||||
--
|
--
|
||||||
@@ -1088,10 +1102,10 @@ end
|
|||||||
--
|
--
|
||||||
-- -- Monitor specific airbases.
|
-- -- Monitor specific airbases.
|
||||||
-- ATC_Ground = ATC_GROUND_NEVADA:New(
|
-- ATC_Ground = ATC_GROUND_NEVADA:New(
|
||||||
-- { AIRBASE.Nevada.Laughlin_Airport,
|
-- { AIRBASE.Nevada.Laughlin,
|
||||||
-- AIRBASE.Nevada.Lincoln_County,
|
-- AIRBASE.Nevada.Lincoln_County,
|
||||||
-- AIRBASE.Nevada.North_Las_Vegas,
|
-- AIRBASE.Nevada.North_Las_Vegas,
|
||||||
-- AIRBASE.Nevada.McCarran_International_Airport
|
-- AIRBASE.Nevada.McCarran_International
|
||||||
-- }
|
-- }
|
||||||
-- )
|
-- )
|
||||||
--
|
--
|
||||||
@@ -1330,33 +1344,33 @@ end
|
|||||||
-- The following airbases are monitored at the PersianGulf region.
|
-- The following airbases are monitored at the PersianGulf region.
|
||||||
-- Use the @{Wrapper.Airbase#AIRBASE.PersianGulf} enumeration to select the airbases to be monitored.
|
-- Use the @{Wrapper.Airbase#AIRBASE.PersianGulf} enumeration to select the airbases to be monitored.
|
||||||
--
|
--
|
||||||
-- * `AIRBASE.PersianGulf.Abu_Musa_Island_Airport`
|
-- * `AIRBASE.PersianGulf.Abu_Musa_Island`
|
||||||
-- * `AIRBASE.PersianGulf.Al_Dhafra_AB`
|
-- * `AIRBASE.PersianGulf.Al_Dhafra_AFB`
|
||||||
-- * `AIRBASE.PersianGulf.Al_Maktoum_Intl`
|
-- * `AIRBASE.PersianGulf.Al_Maktoum_Intl`
|
||||||
-- * `AIRBASE.PersianGulf.Al_Minhad_AB`
|
-- * `AIRBASE.PersianGulf.Al_Minhad_AFB`
|
||||||
-- * `AIRBASE.PersianGulf.Bandar_Abbas_Intl`
|
-- * `AIRBASE.PersianGulf.Bandar_Abbas_Intl`
|
||||||
-- * `AIRBASE.PersianGulf.Bandar_Lengeh`
|
-- * `AIRBASE.PersianGulf.Bandar_Lengeh`
|
||||||
-- * `AIRBASE.PersianGulf.Dubai_Intl`
|
-- * `AIRBASE.PersianGulf.Dubai_Intl`
|
||||||
-- * `AIRBASE.PersianGulf.Fujairah_Intl`
|
-- * `AIRBASE.PersianGulf.Fujairah_Intl`
|
||||||
-- * `AIRBASE.PersianGulf.Havadarya`
|
-- * `AIRBASE.PersianGulf.Havadarya`
|
||||||
-- * `AIRBASE.PersianGulf.Kerman_Airport`
|
-- * `AIRBASE.PersianGulf.Kerman`
|
||||||
-- * `AIRBASE.PersianGulf.Khasab`
|
-- * `AIRBASE.PersianGulf.Khasab`
|
||||||
-- * `AIRBASE.PersianGulf.Lar_Airbase`
|
-- * `AIRBASE.PersianGulf.Lar`
|
||||||
-- * `AIRBASE.PersianGulf.Qeshm_Island`
|
-- * `AIRBASE.PersianGulf.Qeshm_Island`
|
||||||
-- * `AIRBASE.PersianGulf.Sharjah_Intl`
|
-- * `AIRBASE.PersianGulf.Sharjah_Intl`
|
||||||
-- * `AIRBASE.PersianGulf.Shiraz_International_Airport`
|
-- * `AIRBASE.PersianGulf.Shiraz_Intl`
|
||||||
-- * `AIRBASE.PersianGulf.Sir_Abu_Nuayr`
|
-- * `AIRBASE.PersianGulf.Sir_Abu_Nuayr`
|
||||||
-- * `AIRBASE.PersianGulf.Sirri_Island`
|
-- * `AIRBASE.PersianGulf.Sirri_Island`
|
||||||
-- * `AIRBASE.PersianGulf.Tunb_Island_AFB`
|
-- * `AIRBASE.PersianGulf.Tunb_Island_AFB`
|
||||||
-- * `AIRBASE.PersianGulf.Tunb_Kochak`
|
-- * `AIRBASE.PersianGulf.Tunb_Kochak`
|
||||||
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel_Airport`
|
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel`
|
||||||
-- * `AIRBASE.PersianGulf.Bandar_e_Jask_airfield`
|
-- * `AIRBASE.PersianGulf.Bandar_e_Jask`
|
||||||
-- * `AIRBASE.PersianGulf.Abu_Dhabi_International_Airport`
|
-- * `AIRBASE.PersianGulf.Abu_Dhabi_Intl`
|
||||||
-- * `AIRBASE.PersianGulf.Al_Bateen_Airport`
|
-- * `AIRBASE.PersianGulf.Al_Bateen`
|
||||||
-- * `AIRBASE.PersianGulf.Kish_International_Airport`
|
-- * `AIRBASE.PersianGulf.Kish_Intl`
|
||||||
-- * `AIRBASE.PersianGulf.Al_Ain_International_Airport`
|
-- * `AIRBASE.PersianGulf.Al_Ain_Intl`
|
||||||
-- * `AIRBASE.PersianGulf.Lavan_Island_Airport`
|
-- * `AIRBASE.PersianGulf.Lavan_Island`
|
||||||
-- * `AIRBASE.PersianGulf.Jiroft_Airport`
|
-- * `AIRBASE.PersianGulf.Jiroft`
|
||||||
--
|
--
|
||||||
-- # Installation
|
-- # Installation
|
||||||
--
|
--
|
||||||
@@ -1391,8 +1405,8 @@ end
|
|||||||
-- AirbasePoliceCaucasus = ATC_GROUND_PERSIANGULF:New()
|
-- AirbasePoliceCaucasus = ATC_GROUND_PERSIANGULF:New()
|
||||||
--
|
--
|
||||||
-- ATC_Ground = ATC_GROUND_PERSIANGULF:New(
|
-- ATC_Ground = ATC_GROUND_PERSIANGULF:New(
|
||||||
-- { AIRBASE.PersianGulf.Kerman_Airport,
|
-- { AIRBASE.PersianGulf.Kerman,
|
||||||
-- AIRBASE.PersianGulf.Al_Minhad_AB
|
-- AIRBASE.PersianGulf.Al_Minhad_AFB
|
||||||
-- }
|
-- }
|
||||||
-- )
|
-- )
|
||||||
--
|
--
|
||||||
@@ -1441,11 +1455,10 @@ function ATC_GROUND_PERSIANGULF:Start( RepeatScanSeconds )
|
|||||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---
|
||||||
-- @type ATC_GROUND_MARIANAISLANDS
|
-- @type ATC_GROUND_MARIANAISLANDS
|
||||||
-- @extends #ATC_GROUND
|
-- @extends #ATC_GROUND
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- # ATC\_GROUND\_MARIANA, extends @{#ATC_GROUND}
|
--- # ATC\_GROUND\_MARIANA, extends @{#ATC_GROUND}
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -619,63 +619,148 @@ ARTY.WeaponType={
|
|||||||
}
|
}
|
||||||
|
|
||||||
--- Database of common artillery unit properties.
|
--- Database of common artillery unit properties.
|
||||||
|
-- @type ARTY.dbitem
|
||||||
|
-- @field #string displayname Name displayed in ME.
|
||||||
|
-- @field #number minrange Minimum firing range in meters.
|
||||||
|
-- @field #number maxrange Maximum firing range in meters.
|
||||||
|
-- @field #number reloadtime Reload time in seconds.
|
||||||
|
|
||||||
|
--- Database of common artillery unit properties.
|
||||||
|
-- Table key is the "type name" and table value is and `ARTY.dbitem`.
|
||||||
-- @type ARTY.db
|
-- @type ARTY.db
|
||||||
ARTY.db={
|
ARTY.db={
|
||||||
["2B11 mortar"] = { -- type "2B11 mortar"
|
["LeFH_18-40-105"] = {
|
||||||
minrange = 500, -- correct?
|
displayname = "FH LeFH-18 105mm", -- name displayed in the ME
|
||||||
maxrange = 7000, -- 7 km
|
minrange = 500, -- min range (green circle) in meters
|
||||||
reloadtime = 30, -- 30 sec
|
maxrange = 10500, -- max range (red circle) in meters
|
||||||
|
reloadtime = nil, -- reload time in seconds
|
||||||
},
|
},
|
||||||
["SPH 2S1 Gvozdika"] = { -- type "SAU Gvozdika"
|
["M2A1-105"] = {
|
||||||
minrange = 300, -- correct?
|
displayname = "FH M2A1 105mm",
|
||||||
maxrange = 15000, -- 15 km
|
minrange = 500,
|
||||||
reloadtime = nil, -- unknown
|
maxrange = 11500,
|
||||||
|
reloadtime = nil,
|
||||||
},
|
},
|
||||||
["SPH 2S19 Msta"] = { --type "SAU Msta", alias "2S19 Msta"
|
["Pak40"] = {
|
||||||
minrange = 300, -- correct?
|
displayname = "FH Pak 40 75mm",
|
||||||
maxrange = 23500, -- 23.5 km
|
minrange = 500,
|
||||||
reloadtime = nil, -- unknown
|
maxrange = 3000,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
|
["L118_Unit"] = {
|
||||||
|
displayname = "L118 Light Artillery Gun",
|
||||||
|
minrange = 500,
|
||||||
|
maxrange = 17500,
|
||||||
|
reloadtime = nil,
|
||||||
},
|
},
|
||||||
["SPH 2S3 Akatsia"] = { -- type "SAU Akatsia", alias "2S3 Akatsia"
|
["Smerch"] = {
|
||||||
minrange = 300, -- correct?
|
displayname = "MLRS 9A52 Smerch CM 300mm",
|
||||||
maxrange = 17000, -- 17 km
|
minrange = 20000,
|
||||||
reloadtime = nil, -- unknown
|
maxrange = 70000,
|
||||||
|
reloadtime = 2160,
|
||||||
},
|
},
|
||||||
["SPH 2S9 Nona"] = { --type "SAU 2-C9"
|
["Smerch_HE"] = {
|
||||||
minrange = 500, -- correct?
|
displayname = "MLRS 9A52 Smerch HE 300mm",
|
||||||
maxrange = 7000, -- 7 km
|
minrange = 20000,
|
||||||
reloadtime = nil, -- unknown
|
maxrange = 70000,
|
||||||
|
reloadtime = 2160,
|
||||||
},
|
},
|
||||||
["SPH M109 Paladin"] = { -- type "M-109", alias "M109"
|
["Uragan_BM-27"] = {
|
||||||
minrange = 300, -- correct?
|
displayname = "MLRS 9K57 Uragan BM-27 220mm",
|
||||||
maxrange = 22000, -- 22 km
|
minrange = 11500,
|
||||||
reloadtime = nil, -- unknown
|
maxrange = 35800,
|
||||||
|
reloadtime = 840,
|
||||||
},
|
},
|
||||||
["SpGH Dana"] = { -- type "SpGH_Dana"
|
["Grad-URAL"] = {
|
||||||
minrange = 300, -- correct?
|
displayname = "MLRS BM-21 Grad 122mm",
|
||||||
maxrange = 18700, -- 18.7 km
|
minrange = 5000,
|
||||||
reloadtime = nil, -- unknown
|
maxrange = 19000,
|
||||||
|
reloadtime = 420,
|
||||||
},
|
},
|
||||||
["MLRS BM-21 Grad"] = { --type "Grad-URAL", alias "MLRS BM-21 Grad"
|
["HL_B8M1"] = {
|
||||||
minrange = 5000, -- 5 km
|
displayname = "MLRS HL with B8M1 80mm",
|
||||||
maxrange = 19000, -- 19 km
|
minrange = 500,
|
||||||
reloadtime = 420, -- 7 min
|
maxrange = 5000,
|
||||||
|
reloadtime = nil,
|
||||||
},
|
},
|
||||||
["MLRS 9K57 Uragan BM-27"] = { -- type "Uragan_BM-27"
|
["tt_B8M1"] = {
|
||||||
minrange = 11500, -- 11.5 km
|
displayname = "MLRS LC with B8M1 80mm",
|
||||||
maxrange = 35800, -- 35.8 km
|
minrange = 500,
|
||||||
reloadtime = 840, -- 14 min
|
maxrange = 5000,
|
||||||
|
reloadtime = nil,
|
||||||
},
|
},
|
||||||
["MLRS 9A52 Smerch"] = { -- type "Smerch"
|
["MLRS"] = {
|
||||||
minrange = 20000, -- 20 km
|
displayname = "MLRS M270 227mm",
|
||||||
maxrange = 70000, -- 70 km
|
minrange = 10000,
|
||||||
reloadtime = 2160, -- 36 min
|
maxrange = 32000,
|
||||||
|
reloadtime = 540,
|
||||||
},
|
},
|
||||||
["MLRS M270"] = { --type "MRLS", alias "M270 MRLS"
|
["2B11 mortar"] = {
|
||||||
minrange = 10000, -- 10 km
|
displayname = "Mortar 2B11 120mm",
|
||||||
maxrange = 32000, -- 32 km
|
minrange = 500,
|
||||||
reloadtime = 540, -- 9 min
|
maxrange = 7000,
|
||||||
|
reloadtime = 30,
|
||||||
},
|
},
|
||||||
|
["PLZ05"] = {
|
||||||
|
displayname = "PLZ-05",
|
||||||
|
minrange = 500,
|
||||||
|
maxrange = 23500,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
|
["SAU Gvozdika"] = {
|
||||||
|
displayname = "SPH 2S1 Gvozdika 122mm",
|
||||||
|
minrange = 300,
|
||||||
|
maxrange = 15000,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
|
["SAU Msta"] = {
|
||||||
|
displayname = "SPH 2S19 Msta 152mm",
|
||||||
|
minrange = 300,
|
||||||
|
maxrange = 23500,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
|
["SAU Akatsia"] = {
|
||||||
|
displayname = "SPH 2S3 Akatsia 152mm",
|
||||||
|
minrange = 300,
|
||||||
|
maxrange = 17000,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
|
["SpGH_Dana"] = {
|
||||||
|
displayname = "SPH Dana vz77 152mm",
|
||||||
|
minrange = 300,
|
||||||
|
maxrange = 18700,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
|
["M-109"] = {
|
||||||
|
displayname = "SPH M109 Paladin 155mm",
|
||||||
|
minrange = 300,
|
||||||
|
maxrange = 22000,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
|
["M12_GMC"] = {
|
||||||
|
displayname = "SPH M12 GMC 155mm",
|
||||||
|
minrange = 300,
|
||||||
|
maxrange = 18200,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
|
["Wespe124"] = {
|
||||||
|
displayname = "SPH Sd.Kfz.124 Wespe 105mm",
|
||||||
|
minrange = 300,
|
||||||
|
maxrange = 7000,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
|
["T155_Firtina"] = {
|
||||||
|
displayname = "SPH T155 Firtina 155mm",
|
||||||
|
minrange = 300,
|
||||||
|
maxrange = 41000,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
|
["SAU 2-C9"] = {
|
||||||
|
displayname = "SPM 2S9 Nona 120mm M",
|
||||||
|
minrange = 500,
|
||||||
|
maxrange = 7000,
|
||||||
|
reloadtime = nil,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Target.
|
--- Target.
|
||||||
@@ -695,7 +780,7 @@ ARTY.db={
|
|||||||
|
|
||||||
--- Arty script version.
|
--- Arty script version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
ARTY.version="1.3.1"
|
ARTY.version="1.3.3"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -797,8 +882,8 @@ function ARTY:New(group, alias)
|
|||||||
-- Maximum speed in km/h.
|
-- Maximum speed in km/h.
|
||||||
self.SpeedMax=group:GetSpeedMax()
|
self.SpeedMax=group:GetSpeedMax()
|
||||||
|
|
||||||
-- Group is mobile or not (e.g. mortars).
|
-- Group is mobile or not (e.g. mortars). Some immobile units have a speed of 1 m/s = 3.6 km/h. So we check this number.
|
||||||
if self.SpeedMax>1 then
|
if self.SpeedMax>3.6 then
|
||||||
self.ismobile=true
|
self.ismobile=true
|
||||||
else
|
else
|
||||||
self.ismobile=false
|
self.ismobile=false
|
||||||
@@ -1923,7 +2008,7 @@ function ARTY:onafterStart(Controllable, From, Event, To)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Check if we have and arty type that is in the DB.
|
-- Check if we have and arty type that is in the DB.
|
||||||
local _dbproperties=self:_CheckDB(self.DisplayName)
|
local _dbproperties=self:_CheckDB(self.Type)
|
||||||
self:T({dbproperties=_dbproperties})
|
self:T({dbproperties=_dbproperties})
|
||||||
if _dbproperties~=nil then
|
if _dbproperties~=nil then
|
||||||
for property,value in pairs(_dbproperties) do
|
for property,value in pairs(_dbproperties) do
|
||||||
@@ -1969,8 +2054,8 @@ function ARTY:onafterStart(Controllable, From, Event, To)
|
|||||||
text=text..string.format("Type = %s\n", self.Type)
|
text=text..string.format("Type = %s\n", self.Type)
|
||||||
text=text..string.format("Display Name = %s\n", self.DisplayName)
|
text=text..string.format("Display Name = %s\n", self.DisplayName)
|
||||||
text=text..string.format("Number of units = %d\n", self.IniGroupStrength)
|
text=text..string.format("Number of units = %d\n", self.IniGroupStrength)
|
||||||
text=text..string.format("Speed max = %d km/h\n", self.SpeedMax)
|
text=text..string.format("Speed max = %.1f km/h\n", self.SpeedMax)
|
||||||
text=text..string.format("Speed default = %d km/h\n", self.Speed)
|
text=text..string.format("Speed default = %.1f km/h\n", self.Speed)
|
||||||
text=text..string.format("Is mobile = %s\n", tostring(self.ismobile))
|
text=text..string.format("Is mobile = %s\n", tostring(self.ismobile))
|
||||||
text=text..string.format("Is cargo = %s\n", tostring(self.iscargo))
|
text=text..string.format("Is cargo = %s\n", tostring(self.iscargo))
|
||||||
text=text..string.format("Min range = %.1f km\n", self.minrange/1000)
|
text=text..string.format("Min range = %.1f km\n", self.minrange/1000)
|
||||||
@@ -3049,7 +3134,7 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target)
|
|||||||
local nfire=Narty
|
local nfire=Narty
|
||||||
local _type="shots"
|
local _type="shots"
|
||||||
if target.weapontype==ARTY.WeaponType.Auto then
|
if target.weapontype==ARTY.WeaponType.Auto then
|
||||||
nfire=Narty
|
nfire=Nammo -- We take everything that is available
|
||||||
_type="shots"
|
_type="shots"
|
||||||
elseif target.weapontype==ARTY.WeaponType.Cannon then
|
elseif target.weapontype==ARTY.WeaponType.Cannon then
|
||||||
nfire=Narty
|
nfire=Narty
|
||||||
@@ -3070,6 +3155,8 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target)
|
|||||||
nfire=Nmissiles
|
nfire=Nmissiles
|
||||||
_type="cruise missiles"
|
_type="cruise missiles"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--env.info(string.format("FF type=%s, Nrockets=%d, Nfire=%d target.nshells=%d", _type, Nrockets, nfire, target.nshells))
|
||||||
|
|
||||||
-- Adjust if less than requested ammo is left.
|
-- Adjust if less than requested ammo is left.
|
||||||
target.nshells=math.min(target.nshells, nfire)
|
target.nshells=math.min(target.nshells, nfire)
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
-- @image Designation.JPG
|
-- @image Designation.JPG
|
||||||
--
|
--
|
||||||
-- Date: 24 Oct 2021
|
-- Date: 24 Oct 2021
|
||||||
-- Last Update: May 2024
|
-- Last Update: Mar 2025
|
||||||
--
|
--
|
||||||
--- Class AUTOLASE
|
--- Class AUTOLASE
|
||||||
-- @type AUTOLASE
|
-- @type AUTOLASE
|
||||||
@@ -89,6 +89,10 @@
|
|||||||
-- @field #table playermenus
|
-- @field #table playermenus
|
||||||
-- @field #boolean smokemenu
|
-- @field #boolean smokemenu
|
||||||
-- @field #boolean threatmenu
|
-- @field #boolean threatmenu
|
||||||
|
-- @field #number RoundingPrecision
|
||||||
|
-- @field #table smokeoffset
|
||||||
|
-- @field #boolean increasegroundawareness
|
||||||
|
-- @field #number MonitorFrequency
|
||||||
-- @extends Ops.Intel#INTEL
|
-- @extends Ops.Intel#INTEL
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -100,6 +104,9 @@ AUTOLASE = {
|
|||||||
alias = "",
|
alias = "",
|
||||||
debug = false,
|
debug = false,
|
||||||
smokemenu = true,
|
smokemenu = true,
|
||||||
|
RoundingPrecision = 0,
|
||||||
|
increasegroundawareness = false,
|
||||||
|
MonitorFrequency = 30,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Laser spot info
|
--- Laser spot info
|
||||||
@@ -118,7 +125,7 @@ AUTOLASE = {
|
|||||||
|
|
||||||
--- AUTOLASE class version.
|
--- AUTOLASE class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
AUTOLASE.version = "0.1.25"
|
AUTOLASE.version = "0.1.31"
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
-- Begin Functional.Autolase.lua
|
-- Begin Functional.Autolase.lua
|
||||||
@@ -191,6 +198,7 @@ function AUTOLASE:New(RecceSet, Coalition, Alias, PilotSet)
|
|||||||
self.reporttimelong = 30
|
self.reporttimelong = 30
|
||||||
self.smoketargets = false
|
self.smoketargets = false
|
||||||
self.smokecolor = SMOKECOLOR.Red
|
self.smokecolor = SMOKECOLOR.Red
|
||||||
|
self.smokeoffset = nil
|
||||||
self.notifypilots = true
|
self.notifypilots = true
|
||||||
self.targetsperrecce = {}
|
self.targetsperrecce = {}
|
||||||
self.RecceUnits = {}
|
self.RecceUnits = {}
|
||||||
@@ -207,6 +215,11 @@ function AUTOLASE:New(RecceSet, Coalition, Alias, PilotSet)
|
|||||||
self.playermenus = {}
|
self.playermenus = {}
|
||||||
self.smokemenu = true
|
self.smokemenu = true
|
||||||
self.threatmenu = true
|
self.threatmenu = true
|
||||||
|
self.RoundingPrecision = 0
|
||||||
|
self.increasegroundawareness = false
|
||||||
|
self.MonitorFrequency = 30
|
||||||
|
|
||||||
|
self:EnableSmokeMenu({Angle=math.random(0,359),Distance=math.random(10,20)})
|
||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("AUTOLASE %s (%s) | ", self.alias, self.coalition and UTILS.GetCoalitionName(self.coalition) or "unknown")
|
self.lid=string.format("AUTOLASE %s (%s) | ", self.alias, self.coalition and UTILS.GetCoalitionName(self.coalition) or "unknown")
|
||||||
@@ -309,16 +322,41 @@ end
|
|||||||
-- Helper Functions
|
-- Helper Functions
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- [User] When using Monitor, set the frequency here in which the report will appear
|
||||||
|
-- @param #AUTOLASE self
|
||||||
|
-- @param #number Seconds Run the report loop every number of seconds defined here.
|
||||||
|
-- @return #AUTOLASE self
|
||||||
|
function AUTOLASE:SetMonitorFrequency(Seconds)
|
||||||
|
self.MonitorFrequency = Seconds or 30
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [User] Set a table of possible laser codes.
|
--- [User] Set a table of possible laser codes.
|
||||||
-- Each new RECCE can select a code from this table, default is { 1688, 1130, 4785, 6547, 1465, 4578 } .
|
-- Each new RECCE can select a code from this table, default is { 1688, 1130, 4785, 6547, 1465, 4578 }.
|
||||||
-- @param #AUTOLASE self
|
-- @param #AUTOLASE self
|
||||||
-- @param #list<#number> LaserCodes
|
-- @param #list<#number> LaserCodes
|
||||||
-- @return #AUTOLASE
|
-- @return #AUTOLASE self
|
||||||
function AUTOLASE:SetLaserCodes( LaserCodes )
|
function AUTOLASE:SetLaserCodes( LaserCodes )
|
||||||
self.LaserCodes = ( type( LaserCodes ) == "table" ) and LaserCodes or { LaserCodes }
|
self.LaserCodes = ( type( LaserCodes ) == "table" ) and LaserCodes or { LaserCodes }
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Improve ground unit detection by using a zone scan and LOS check.
|
||||||
|
-- @param #AUTOLASE self
|
||||||
|
-- @return #AUTOLASE self
|
||||||
|
function AUTOLASE:EnableImproveGroundUnitsDetection()
|
||||||
|
self.increasegroundawareness = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [User] Do not improve ground unit detection by using a zone scan and LOS check.
|
||||||
|
-- @param #AUTOLASE self
|
||||||
|
-- @return #AUTOLASE self
|
||||||
|
function AUTOLASE:DisableImproveGroundUnitsDetection()
|
||||||
|
self.increasegroundawareness = false
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- (Internal) Function to set pilot menu.
|
--- (Internal) Function to set pilot menu.
|
||||||
-- @param #AUTOLASE self
|
-- @param #AUTOLASE self
|
||||||
-- @return #AUTOLASE self
|
-- @return #AUTOLASE self
|
||||||
@@ -455,7 +493,7 @@ end
|
|||||||
--- (User) Function enable sending messages via SRS.
|
--- (User) Function enable sending messages via SRS.
|
||||||
-- @param #AUTOLASE self
|
-- @param #AUTOLASE self
|
||||||
-- @param #boolean OnOff Switch usage on and off
|
-- @param #boolean OnOff Switch usage on and off
|
||||||
-- @param #string Path Path to SRS directory, e.g. C:\\Program Files\\DCS-SimpleRadio-Standalone
|
-- @param #string Path Path to SRS TTS directory, e.g. C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio
|
||||||
-- @param #number Frequency Frequency to send, e.g. 243
|
-- @param #number Frequency Frequency to send, e.g. 243
|
||||||
-- @param #number Modulation Modulation i.e. radio.modulation.AM or radio.modulation.FM
|
-- @param #number Modulation Modulation i.e. radio.modulation.AM or radio.modulation.FM
|
||||||
-- @param #string Label (Optional) Short label to be used on the SRS Client Overlay
|
-- @param #string Label (Optional) Short label to be used on the SRS Client Overlay
|
||||||
@@ -470,7 +508,7 @@ end
|
|||||||
function AUTOLASE:SetUsingSRS(OnOff,Path,Frequency,Modulation,Label,Gender,Culture,Port,Voice,Volume,PathToGoogleKey)
|
function AUTOLASE:SetUsingSRS(OnOff,Path,Frequency,Modulation,Label,Gender,Culture,Port,Voice,Volume,PathToGoogleKey)
|
||||||
if OnOff then
|
if OnOff then
|
||||||
self.useSRS = true
|
self.useSRS = true
|
||||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||||
self.SRSFreq = Frequency or 271
|
self.SRSFreq = Frequency or 271
|
||||||
self.SRSMod = Modulation or radio.modulation.AM
|
self.SRSMod = Modulation or radio.modulation.AM
|
||||||
self.Gender = Gender or MSRS.gender or "male"
|
self.Gender = Gender or MSRS.gender or "male"
|
||||||
@@ -600,11 +638,26 @@ function AUTOLASE:SetSmokeTargets(OnOff,Color)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (User) Function to set rounding precision for BR distance output.
|
||||||
|
-- @param #AUTOLASE self
|
||||||
|
-- @param #number IDP Rounding precision before/after the decimal sign. Defaults to zero. Positive values round right of the decimal sign, negative ones left of the decimal sign.
|
||||||
|
-- @return #AUTOLASE self
|
||||||
|
function AUTOLASE:SetRoundingPrecsion(IDP)
|
||||||
|
self.RoundingPrecision = IDP or 0
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- (User) Show the "Switch smoke target..." menu entry for pilots. On by default.
|
--- (User) Show the "Switch smoke target..." menu entry for pilots. On by default.
|
||||||
-- @param #AUTOLASE self
|
-- @param #AUTOLASE self
|
||||||
|
-- @param #table Offset (Optional) Define an offset for the smoke, i.e. not directly on the unit itself, angle is degrees and distance is meters. E.g. `autolase:EnableSmokeMenu({Angle=30,Distance=20})`
|
||||||
-- @return #AUTOLASE self
|
-- @return #AUTOLASE self
|
||||||
function AUTOLASE:EnableSmokeMenu()
|
function AUTOLASE:EnableSmokeMenu(Offset)
|
||||||
self.smokemenu = true
|
self.smokemenu = true
|
||||||
|
if Offset then
|
||||||
|
self.smokeoffset = {}
|
||||||
|
self.smokeoffset.Distance = Offset.Distance or math.random(10,20)
|
||||||
|
self.smokeoffset.Angle = Offset.Angle or math.random(0,359)
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -613,6 +666,7 @@ end
|
|||||||
-- @return #AUTOLASE self
|
-- @return #AUTOLASE self
|
||||||
function AUTOLASE:DisableSmokeMenu()
|
function AUTOLASE:DisableSmokeMenu()
|
||||||
self.smokemenu = false
|
self.smokemenu = false
|
||||||
|
self.smokeoffset = nil
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -671,7 +725,8 @@ function AUTOLASE:CleanCurrentLasing()
|
|||||||
local unit = recce:GetUnit(1)
|
local unit = recce:GetUnit(1)
|
||||||
local name = unit:GetName()
|
local name = unit:GetName()
|
||||||
if not self.RecceUnits[name] then
|
if not self.RecceUnits[name] then
|
||||||
self.RecceUnits[name] = { name=name, unit=unit, cooldown = false, timestamp = timer.getAbsTime() }
|
local isground = (unit and unit.IsGround) and unit:IsGround() or false
|
||||||
|
self.RecceUnits[name] = { name=name, unit=unit, cooldown = false, timestamp = timer.getAbsTime(), isground=isground }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -757,9 +812,11 @@ function AUTOLASE:ShowStatus(Group,Unit)
|
|||||||
end
|
end
|
||||||
local code = self:GetLaserCode(unit:GetName())
|
local code = self:GetLaserCode(unit:GetName())
|
||||||
report:Add(string.format("Recce %s has code %d",name,code))
|
report:Add(string.format("Recce %s has code %d",name,code))
|
||||||
|
report:Add("---------------")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
report:Add(string.format("Lasing min threat level %d",self.minthreatlevel))
|
report:Add(string.format("Lasing min threat level %d",self.minthreatlevel))
|
||||||
|
report:Add("---------------")
|
||||||
local lines = 0
|
local lines = 0
|
||||||
for _ind,_entry in pairs(self.CurrentLasing) do
|
for _ind,_entry in pairs(self.CurrentLasing) do
|
||||||
local entry = _entry -- #AUTOLASE.LaserSpot
|
local entry = _entry -- #AUTOLASE.LaserSpot
|
||||||
@@ -779,22 +836,28 @@ function AUTOLASE:ShowStatus(Group,Unit)
|
|||||||
if playername then
|
if playername then
|
||||||
local settings = _DATABASE:GetPlayerSettings(playername)
|
local settings = _DATABASE:GetPlayerSettings(playername)
|
||||||
if settings then
|
if settings then
|
||||||
self:I("Get Settings ok!")
|
self:T("Get Settings ok!")
|
||||||
if settings:IsA2G_MGRS() then
|
if settings:IsA2G_MGRS() then
|
||||||
locationstring = entry.coordinate:ToStringMGRS(settings)
|
locationstring = entry.coordinate:ToStringMGRS(settings)
|
||||||
elseif settings:IsA2G_LL_DMS() then
|
elseif settings:IsA2G_LL_DMS() then
|
||||||
locationstring = entry.coordinate:ToStringLLDMS(settings)
|
locationstring = entry.coordinate:ToStringLLDMS(settings)
|
||||||
|
elseif settings:IsA2G_LL_DDM() then
|
||||||
|
locationstring = entry.coordinate:ToStringLLDDM(settings)
|
||||||
elseif settings:IsA2G_BR() then
|
elseif settings:IsA2G_BR() then
|
||||||
locationstring = entry.coordinate:ToStringBR(Group:GetCoordinate() or Unit:GetCoordinate(),settings)
|
-- attention this is the distance from the ASKING unit to target, not from RECCE to target!
|
||||||
|
local startcoordinate = Unit:GetCoordinate() or Group:GetCoordinate()
|
||||||
|
locationstring = entry.coordinate:ToStringBR(startcoordinate,settings,false,self.RoundingPrecision)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local text = string.format("%s lasing %s code %d\nat %s",reccename,typename,code,locationstring)
|
local text = string.format("+ %s lasing %s code %d\nat %s",reccename,typename,code,locationstring)
|
||||||
report:Add(text)
|
report:Add(text)
|
||||||
|
report:Add("---------------")
|
||||||
lines = lines + 1
|
lines = lines + 1
|
||||||
end
|
end
|
||||||
if lines == 0 then
|
if lines == 0 then
|
||||||
report:Add("No targets!")
|
report:Add("No targets!")
|
||||||
|
report:Add("---------------")
|
||||||
end
|
end
|
||||||
local reporttime = self.reporttimelong
|
local reporttime = self.reporttimelong
|
||||||
if lines == 0 then reporttime = self.reporttimeshort end
|
if lines == 0 then reporttime = self.reporttimeshort end
|
||||||
@@ -913,6 +976,65 @@ function AUTOLASE:CanLase(Recce,Unit)
|
|||||||
return canlase
|
return canlase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (Internal) Function to do a zone check per ground Recce and make found units and statics "known".
|
||||||
|
-- @param #AUTOLASE self
|
||||||
|
-- @return #AUTOLASE self
|
||||||
|
function AUTOLASE:_Prescient()
|
||||||
|
-- self.RecceUnits[name] = { name=name, unit=unit, cooldown = false, timestamp = timer.getAbsTime(), isground=isground }
|
||||||
|
for _,_data in pairs(self.RecceUnits) do
|
||||||
|
-- ground units only
|
||||||
|
if _data.isground and _data.unit and _data.unit:IsAlive() then
|
||||||
|
local unit = _data.unit -- Wrapper.Unit#UNIT
|
||||||
|
local position = unit:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
local needsinit = false
|
||||||
|
if position then
|
||||||
|
local lastposition = unit:GetProperty("lastposition")
|
||||||
|
-- property initiated?
|
||||||
|
if not lastposition then
|
||||||
|
unit:SetProperty("lastposition",position)
|
||||||
|
lastposition = position
|
||||||
|
needsinit = true
|
||||||
|
end
|
||||||
|
-- has moved?
|
||||||
|
local dist = position:Get2DDistance(lastposition)
|
||||||
|
-- refresh?
|
||||||
|
local TNow = timer.getAbsTime()
|
||||||
|
-- check
|
||||||
|
if dist > 10 or needsinit==true or TNow - _data.timestamp > 29 then
|
||||||
|
-- init scan objects
|
||||||
|
local hasunits,hasstatics,_,Units,Statics = position:ScanObjects(self.LaseDistance,true,true,false)
|
||||||
|
-- loop found units
|
||||||
|
if hasunits then
|
||||||
|
self:T(self.lid.."Checking possibly visible UNITs for Recce "..unit:GetName())
|
||||||
|
for _,_target in pairs(Units) do -- Wrapper.Unit#UNIT object here
|
||||||
|
local target = _target -- Wrapper.Unit#UNIT
|
||||||
|
if target and target:GetCoalition() ~= self.coalition then
|
||||||
|
if unit:IsLOS(target) and (not target:IsUnitDetected(unit))then
|
||||||
|
unit:KnowUnit(target,true,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- loop found statics
|
||||||
|
if hasstatics then
|
||||||
|
self:T(self.lid.."Checking possibly visible STATICs for Recce "..unit:GetName())
|
||||||
|
for _,_static in pairs(Statics) do -- DCS static object here
|
||||||
|
local static = STATIC:Find(_static)
|
||||||
|
if static and static:GetCoalition() ~= self.coalition and static:GetCoordinate() then
|
||||||
|
local IsLOS = position:IsLOS(static:GetCoordinate())
|
||||||
|
if IsLOS then
|
||||||
|
unit:KnowUnit(static,true,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
-- FSM Functions
|
-- FSM Functions
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
@@ -925,6 +1047,9 @@ end
|
|||||||
-- @return #AUTOLASE self
|
-- @return #AUTOLASE self
|
||||||
function AUTOLASE:onbeforeMonitor(From, Event, To)
|
function AUTOLASE:onbeforeMonitor(From, Event, To)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
|
if self.increasegroundawareness then
|
||||||
|
self:_Prescient()
|
||||||
|
end
|
||||||
-- Check if group has detected any units.
|
-- Check if group has detected any units.
|
||||||
self:UpdateIntel()
|
self:UpdateIntel()
|
||||||
return self
|
return self
|
||||||
@@ -953,7 +1078,7 @@ function AUTOLASE:onafterMonitor(From, Event, To)
|
|||||||
local grp = contact.group
|
local grp = contact.group
|
||||||
local coord = contact.position
|
local coord = contact.position
|
||||||
local reccename = contact.recce or "none"
|
local reccename = contact.recce or "none"
|
||||||
local threat = contact.threatlevel or 0
|
local threat = contact.threatlevel or 0
|
||||||
local reccegrp = UNIT:FindByName(reccename)
|
local reccegrp = UNIT:FindByName(reccename)
|
||||||
if reccegrp then
|
if reccegrp then
|
||||||
local reccecoord = reccegrp:GetCoordinate()
|
local reccecoord = reccegrp:GetCoordinate()
|
||||||
@@ -1077,6 +1202,9 @@ function AUTOLASE:onafterMonitor(From, Event, To)
|
|||||||
}
|
}
|
||||||
if self.smoketargets then
|
if self.smoketargets then
|
||||||
local coord = unit:GetCoordinate()
|
local coord = unit:GetCoordinate()
|
||||||
|
if self.smokeoffset then
|
||||||
|
coord:Translate(self.smokeoffset.Distance,self.smokeoffset.Angle,true,true)
|
||||||
|
end
|
||||||
local color = self:GetSmokeColor(reccename)
|
local color = self:GetSmokeColor(reccename)
|
||||||
coord:Smoke(color)
|
coord:Smoke(color)
|
||||||
end
|
end
|
||||||
@@ -1087,7 +1215,8 @@ function AUTOLASE:onafterMonitor(From, Event, To)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:__Monitor(-30)
|
local nextloop = -self.MonitorFrequency or -30
|
||||||
|
self:__Monitor(nextloop)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ function CLEANUP_AIRBASE.__:EventAddForCleanUp( Event )
|
|||||||
self:F({Event})
|
self:F({Event})
|
||||||
|
|
||||||
|
|
||||||
if Event.IniDCSUnit and Event.IniCategory == Object.Category.UNIT then
|
if Event.IniDCSUnit and Event.IniUnit and Event.IniCategory == Object.Category.UNIT then
|
||||||
if self.CleanUpList[Event.IniDCSUnitName] == nil then
|
if self.CleanUpList[Event.IniDCSUnitName] == nil then
|
||||||
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
|
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
|
||||||
self:AddForCleanUp( Event.IniUnit, Event.IniDCSUnitName )
|
self:AddForCleanUp( Event.IniUnit, Event.IniDCSUnitName )
|
||||||
@@ -365,7 +365,7 @@ function CLEANUP_AIRBASE.__:EventAddForCleanUp( Event )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if Event.TgtDCSUnit and Event.TgtCategory == Object.Category.UNIT then
|
if Event.TgtDCSUnit and Event.TgtUnit and Event.TgtCategory == Object.Category.UNIT then
|
||||||
if self.CleanUpList[Event.TgtDCSUnitName] == nil then
|
if self.CleanUpList[Event.TgtDCSUnitName] == nil then
|
||||||
if self:IsInAirbase( Event.TgtUnit:GetVec2() ) then
|
if self:IsInAirbase( Event.TgtUnit:GetVec2() ) then
|
||||||
self:AddForCleanUp( Event.TgtUnit, Event.TgtDCSUnitName )
|
self:AddForCleanUp( Event.TgtUnit, Event.TgtDCSUnitName )
|
||||||
@@ -387,7 +387,7 @@ function CLEANUP_AIRBASE.__:CleanUpSchedule()
|
|||||||
local CleanUpUnit = CleanUpListData.CleanUpUnit -- Wrapper.Unit#UNIT
|
local CleanUpUnit = CleanUpListData.CleanUpUnit -- Wrapper.Unit#UNIT
|
||||||
local CleanUpGroupName = CleanUpListData.CleanUpGroupName
|
local CleanUpGroupName = CleanUpListData.CleanUpGroupName
|
||||||
|
|
||||||
if CleanUpUnit:IsAlive() ~= nil then
|
if CleanUpUnit and CleanUpUnit:IsAlive() ~= nil then
|
||||||
|
|
||||||
if self:IsInAirbase( CleanUpUnit:GetVec2() ) then
|
if self:IsInAirbase( CleanUpUnit:GetVec2() ) then
|
||||||
|
|
||||||
@@ -414,7 +414,7 @@ function CLEANUP_AIRBASE.__:CleanUpSchedule()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Clean Units which are waiting for a very long time in the CleanUpZone.
|
-- Clean Units which are waiting for a very long time in the CleanUpZone.
|
||||||
if CleanUpUnit and not CleanUpUnit:GetPlayerName() then
|
if CleanUpUnit and (CleanUpUnit.GetPlayerName == nil or not CleanUpUnit:GetPlayerName()) then
|
||||||
local CleanUpUnitVelocity = CleanUpUnit:GetVelocityKMH()
|
local CleanUpUnitVelocity = CleanUpUnit:GetVelocityKMH()
|
||||||
if CleanUpUnitVelocity < 1 then
|
if CleanUpUnitVelocity < 1 then
|
||||||
if CleanUpListData.CleanUpMoved then
|
if CleanUpListData.CleanUpMoved then
|
||||||
|
|||||||
@@ -652,7 +652,7 @@ do -- DETECTION_BASE
|
|||||||
|
|
||||||
if DetectedObject:isExist() then
|
if DetectedObject:isExist() then
|
||||||
|
|
||||||
local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity = DetectionUnit:IsTargetDetected(
|
local TargetIsDetected, TargetIsVisible, TargetKnowType, TargetKnowDistance, TargetLastTime, TargetLastPos, TargetLastVelocity = DetectionUnit:IsTargetDetected(
|
||||||
DetectedObject,
|
DetectedObject,
|
||||||
self.DetectVisual,
|
self.DetectVisual,
|
||||||
self.DetectOptical,
|
self.DetectOptical,
|
||||||
|
|||||||
@@ -1154,8 +1154,6 @@ function ESCORT:_ReportTargetsScheduler()
|
|||||||
|
|
||||||
if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then
|
if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then
|
||||||
|
|
||||||
if true then
|
|
||||||
|
|
||||||
local EscortGroupName = self.EscortGroup:GetName()
|
local EscortGroupName = self.EscortGroup:GetName()
|
||||||
|
|
||||||
self.EscortMenuAttackNearbyTargets:RemoveSubMenus()
|
self.EscortMenuAttackNearbyTargets:RemoveSubMenus()
|
||||||
@@ -1226,177 +1224,6 @@ function ESCORT:_ReportTargetsScheduler()
|
|||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
else
|
|
||||||
-- local EscortGroupName = self.EscortGroup:GetName()
|
|
||||||
-- local EscortTargets = self.EscortGroup:GetDetectedTargets()
|
|
||||||
--
|
|
||||||
-- local ClientEscortTargets = self.EscortClient._EscortGroups[EscortGroupName].Targets
|
|
||||||
--
|
|
||||||
-- local EscortTargetMessages = ""
|
|
||||||
-- for EscortTargetID, EscortTarget in pairs( EscortTargets ) do
|
|
||||||
-- local EscortObject = EscortTarget.object
|
|
||||||
-- self:T( EscortObject )
|
|
||||||
-- if EscortObject and EscortObject:isExist() and EscortObject.id_ < 50000000 then
|
|
||||||
--
|
|
||||||
-- local EscortTargetUnit = UNIT:Find( EscortObject )
|
|
||||||
-- local EscortTargetUnitName = EscortTargetUnit:GetName()
|
|
||||||
--
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- -- local EscortTargetIsDetected,
|
|
||||||
-- -- EscortTargetIsVisible,
|
|
||||||
-- -- EscortTargetLastTime,
|
|
||||||
-- -- EscortTargetKnowType,
|
|
||||||
-- -- EscortTargetKnowDistance,
|
|
||||||
-- -- EscortTargetLastPos,
|
|
||||||
-- -- EscortTargetLastVelocity
|
|
||||||
-- -- = self.EscortGroup:IsTargetDetected( EscortObject )
|
|
||||||
-- --
|
|
||||||
-- -- self:T( { EscortTargetIsDetected,
|
|
||||||
-- -- EscortTargetIsVisible,
|
|
||||||
-- -- EscortTargetLastTime,
|
|
||||||
-- -- EscortTargetKnowType,
|
|
||||||
-- -- EscortTargetKnowDistance,
|
|
||||||
-- -- EscortTargetLastPos,
|
|
||||||
-- -- EscortTargetLastVelocity } )
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- local EscortTargetUnitVec3 = EscortTargetUnit:GetVec3()
|
|
||||||
-- local EscortVec3 = self.EscortGroup:GetVec3()
|
|
||||||
-- local Distance = ( ( EscortTargetUnitVec3.x - EscortVec3.x )^2 +
|
|
||||||
-- ( EscortTargetUnitVec3.y - EscortVec3.y )^2 +
|
|
||||||
-- ( EscortTargetUnitVec3.z - EscortVec3.z )^2
|
|
||||||
-- ) ^ 0.5 / 1000
|
|
||||||
--
|
|
||||||
-- self:T( { self.EscortGroup:GetName(), EscortTargetUnit:GetName(), Distance, EscortTarget } )
|
|
||||||
--
|
|
||||||
-- if Distance <= 15 then
|
|
||||||
--
|
|
||||||
-- if not ClientEscortTargets[EscortTargetUnitName] then
|
|
||||||
-- ClientEscortTargets[EscortTargetUnitName] = {}
|
|
||||||
-- end
|
|
||||||
-- ClientEscortTargets[EscortTargetUnitName].AttackUnit = EscortTargetUnit
|
|
||||||
-- ClientEscortTargets[EscortTargetUnitName].visible = EscortTarget.visible
|
|
||||||
-- ClientEscortTargets[EscortTargetUnitName].type = EscortTarget.type
|
|
||||||
-- ClientEscortTargets[EscortTargetUnitName].distance = EscortTarget.distance
|
|
||||||
-- else
|
|
||||||
-- if ClientEscortTargets[EscortTargetUnitName] then
|
|
||||||
-- ClientEscortTargets[EscortTargetUnitName] = nil
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- self:T( { "Sorting Targets Table:", ClientEscortTargets } )
|
|
||||||
-- table.sort( ClientEscortTargets, function( a, b ) return a.Distance < b.Distance end )
|
|
||||||
-- self:T( { "Sorted Targets Table:", ClientEscortTargets } )
|
|
||||||
--
|
|
||||||
-- -- Remove the sub menus of the Attack menu of the Escort for the EscortGroup.
|
|
||||||
-- self.EscortMenuAttackNearbyTargets:RemoveSubMenus()
|
|
||||||
--
|
|
||||||
-- if self.EscortMenuTargetAssistance then
|
|
||||||
-- self.EscortMenuTargetAssistance:RemoveSubMenus()
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- --for MenuIndex = 1, #self.EscortMenuAttackTargets do
|
|
||||||
-- -- self:T( { "Remove Menu:", self.EscortMenuAttackTargets[MenuIndex] } )
|
|
||||||
-- -- self.EscortMenuAttackTargets[MenuIndex] = self.EscortMenuAttackTargets[MenuIndex]:Remove()
|
|
||||||
-- --end
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- if ClientEscortTargets then
|
|
||||||
-- for ClientEscortTargetUnitName, ClientEscortTargetData in pairs( ClientEscortTargets ) do
|
|
||||||
--
|
|
||||||
-- for ClientEscortGroupName, EscortGroupData in pairs( self.EscortClient._EscortGroups ) do
|
|
||||||
--
|
|
||||||
-- if ClientEscortTargetData and ClientEscortTargetData.AttackUnit:IsAlive() then
|
|
||||||
--
|
|
||||||
-- local EscortTargetMessage = ""
|
|
||||||
-- local EscortTargetCategoryName = ClientEscortTargetData.AttackUnit:GetCategoryName()
|
|
||||||
-- local EscortTargetCategoryType = ClientEscortTargetData.AttackUnit:GetTypeName()
|
|
||||||
-- if ClientEscortTargetData.type then
|
|
||||||
-- EscortTargetMessage = EscortTargetMessage .. EscortTargetCategoryName .. " (" .. EscortTargetCategoryType .. ") at "
|
|
||||||
-- else
|
|
||||||
-- EscortTargetMessage = EscortTargetMessage .. "Unknown target at "
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- local EscortTargetUnitVec3 = ClientEscortTargetData.AttackUnit:GetVec3()
|
|
||||||
-- local EscortVec3 = self.EscortGroup:GetVec3()
|
|
||||||
-- local Distance = ( ( EscortTargetUnitVec3.x - EscortVec3.x )^2 +
|
|
||||||
-- ( EscortTargetUnitVec3.y - EscortVec3.y )^2 +
|
|
||||||
-- ( EscortTargetUnitVec3.z - EscortVec3.z )^2
|
|
||||||
-- ) ^ 0.5 / 1000
|
|
||||||
--
|
|
||||||
-- self:T( { self.EscortGroup:GetName(), ClientEscortTargetData.AttackUnit:GetName(), Distance, ClientEscortTargetData.AttackUnit } )
|
|
||||||
-- if ClientEscortTargetData.visible == false then
|
|
||||||
-- EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " estimated km"
|
|
||||||
-- else
|
|
||||||
-- EscortTargetMessage = EscortTargetMessage .. string.format( "%.2f", Distance ) .. " km"
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- if ClientEscortTargetData.visible then
|
|
||||||
-- EscortTargetMessage = EscortTargetMessage .. ", visual"
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- if ClientEscortGroupName == EscortGroupName then
|
|
||||||
--
|
|
||||||
-- MENU_GROUP_COMMAND:New( self.EscortClient,
|
|
||||||
-- EscortTargetMessage,
|
|
||||||
-- self.EscortMenuAttackNearbyTargets,
|
|
||||||
-- ESCORT._AttackTarget,
|
|
||||||
-- { ParamSelf = self,
|
|
||||||
-- ParamUnit = ClientEscortTargetData.AttackUnit
|
|
||||||
-- }
|
|
||||||
-- )
|
|
||||||
-- EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage
|
|
||||||
-- else
|
|
||||||
-- if self.EscortMenuTargetAssistance then
|
|
||||||
-- local MenuTargetAssistance = MENU_GROUP:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
|
|
||||||
-- MENU_GROUP_COMMAND:New( self.EscortClient,
|
|
||||||
-- EscortTargetMessage,
|
|
||||||
-- MenuTargetAssistance,
|
|
||||||
-- ESCORT._AssistTarget,
|
|
||||||
-- self,
|
|
||||||
-- EscortGroupData.EscortGroup,
|
|
||||||
-- ClientEscortTargetData.AttackUnit
|
|
||||||
-- )
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
-- else
|
|
||||||
-- ClientEscortTargetData = nil
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- if EscortTargetMessages ~= "" and self.ReportTargets == true then
|
|
||||||
-- self.EscortGroup:MessageToClient( "Detected targets within 15 km range:" .. EscortTargetMessages:gsub("\n$",""), 20, self.EscortClient )
|
|
||||||
-- else
|
|
||||||
-- self.EscortGroup:MessageToClient( "No targets detected!", 20, self.EscortClient )
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- if self.EscortMenuResumeMission then
|
|
||||||
-- self.EscortMenuResumeMission:RemoveSubMenus()
|
|
||||||
--
|
|
||||||
-- -- if self.EscortMenuResumeWayPoints then
|
|
||||||
-- -- for MenuIndex = 1, #self.EscortMenuResumeWayPoints do
|
|
||||||
-- -- self:T( { "Remove Menu:", self.EscortMenuResumeWayPoints[MenuIndex] } )
|
|
||||||
-- -- self.EscortMenuResumeWayPoints[MenuIndex] = self.EscortMenuResumeWayPoints[MenuIndex]:Remove()
|
|
||||||
-- -- end
|
|
||||||
-- -- end
|
|
||||||
--
|
|
||||||
-- local TaskPoints = self:RegisterRoute()
|
|
||||||
-- for WayPointID, WayPoint in pairs( TaskPoints ) do
|
|
||||||
-- local EscortVec3 = self.EscortGroup:GetVec3()
|
|
||||||
-- local Distance = ( ( WayPoint.x - EscortVec3.x )^2 +
|
|
||||||
-- ( WayPoint.y - EscortVec3.z )^2
|
|
||||||
-- ) ^ 0.5 / 1000
|
|
||||||
-- MENU_GROUP_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- return true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -1060,7 +1060,7 @@ function FOX:onafterMissileLaunch(From, Event, To, missile)
|
|||||||
|
|
||||||
-- Tracking info and init of last bomb position.
|
-- Tracking info and init of last bomb position.
|
||||||
local text=string.format("FOX: Tracking missile %s(%s) - target %s - shooter %s", missile.missileType, missile.missileName, tostring(missile.targetName), missile.shooterName)
|
local text=string.format("FOX: Tracking missile %s(%s) - target %s - shooter %s", missile.missileType, missile.missileName, tostring(missile.targetName), missile.shooterName)
|
||||||
self:I(FOX.lid..text)
|
self:T(FOX.lid..text)
|
||||||
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
||||||
|
|
||||||
-- Loop over players.
|
-- Loop over players.
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
-- @module Functional.Mantis
|
-- @module Functional.Mantis
|
||||||
-- @image Functional.Mantis.jpg
|
-- @image Functional.Mantis.jpg
|
||||||
--
|
--
|
||||||
-- Last Update: July 2024
|
-- Last Update: July 2025
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **MANTIS** class, extends Core.Base#BASE
|
--- **MANTIS** class, extends Core.Base#BASE
|
||||||
@@ -60,6 +60,11 @@
|
|||||||
-- @field #number ShoradActDistance Distance of an attacker in meters from a Mantis SAM site, on which Shorad will be switched on. Useful to not give away Shorad sites too early. Default 15km. Should be smaller than checkradius.
|
-- @field #number ShoradActDistance Distance of an attacker in meters from a Mantis SAM site, on which Shorad will be switched on. Useful to not give away Shorad sites too early. Default 15km. Should be smaller than checkradius.
|
||||||
-- @field #boolean checkforfriendlies If true, do not activate a SAM installation if a friendly aircraft is in firing range.
|
-- @field #boolean checkforfriendlies If true, do not activate a SAM installation if a friendly aircraft is in firing range.
|
||||||
-- @field #table FilterZones Table of Core.Zone#ZONE Zones Consider SAM groups in this zone(s) only for this MANTIS instance, must be handed as #table of Zone objects.
|
-- @field #table FilterZones Table of Core.Zone#ZONE Zones Consider SAM groups in this zone(s) only for this MANTIS instance, must be handed as #table of Zone objects.
|
||||||
|
-- @field #boolean SmokeDecoy If true, smoke short range SAM units as decoy if a plane is in firing range.
|
||||||
|
-- @field #number SmokeDecoyColor Color to use, defaults to SMOKECOLOR.White
|
||||||
|
-- @field #number checkcounter Counter for SAM Table refreshes.
|
||||||
|
-- @field #number DLinkCacheTime Seconds after which cached contacts in DLink will decay.
|
||||||
|
-- @field #boolean logsamstatus Log SAM status in dcs.log every cycle if true
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -71,10 +76,9 @@
|
|||||||
--
|
--
|
||||||
-- * Moose derived Modular, Automatic and Network capable Targeting and Interception System.
|
-- * Moose derived Modular, Automatic and Network capable Targeting and Interception System.
|
||||||
-- * Controls a network of SAM sites. Uses detection to switch on the SAM site closest to the enemy.
|
-- * Controls a network of SAM sites. Uses detection to switch on the SAM site closest to the enemy.
|
||||||
-- * **Automatic mode** (default since 0.8) can set-up your SAM site network automatically for you
|
-- * **Automatic mode** (default) will set-up your SAM site network automatically for you.
|
||||||
-- * **Classic mode** behaves like before
|
-- * Leverage evasiveness from SEAD, leverage attack range setting.
|
||||||
-- * Leverage evasiveness from SEAD, leverage attack range setting
|
-- * Automatic setup of SHORAD based on groups of the class "short-range".
|
||||||
-- * Automatic setup of SHORAD based on groups of the class "short-range"
|
|
||||||
--
|
--
|
||||||
-- # 0. Base considerations and naming conventions
|
-- # 0. Base considerations and naming conventions
|
||||||
--
|
--
|
||||||
@@ -86,6 +90,7 @@
|
|||||||
-- * SAM sites, e.g. each **group name** begins with "Red SAM"
|
-- * SAM sites, e.g. each **group name** begins with "Red SAM"
|
||||||
-- * EWR network and AWACS, e.g. each **group name** begins with "Red EWR" and *not* e.g. "Red SAM EWR" (overlap with "Red SAM"), "Red EWR Awacs" will be found by "Red EWR"
|
-- * EWR network and AWACS, e.g. each **group name** begins with "Red EWR" and *not* e.g. "Red SAM EWR" (overlap with "Red SAM"), "Red EWR Awacs" will be found by "Red EWR"
|
||||||
-- * SHORAD, e.g. each **group name** begins with "Red SHORAD" and *not" e.g. just "SHORAD" because you might also have "Blue SHORAD"
|
-- * SHORAD, e.g. each **group name** begins with "Red SHORAD" and *not" e.g. just "SHORAD" because you might also have "Blue SHORAD"
|
||||||
|
-- * Point Defense, e.g. each **group name** begins with "Red AAA" and *not" e.g. just "AAA" because you might also have "Blue AAA"
|
||||||
--
|
--
|
||||||
-- It's important to get this right because of the nature of the filter-system in @{Core.Set#SET_GROUP}. Filters are "greedy", that is they
|
-- It's important to get this right because of the nature of the filter-system in @{Core.Set#SET_GROUP}. Filters are "greedy", that is they
|
||||||
-- will match *any* string that contains the search string - hence we need to avoid that SAMs, EWR and SHORAD step on each other\'s toes.
|
-- will match *any* string that contains the search string - hence we need to avoid that SAMs, EWR and SHORAD step on each other\'s toes.
|
||||||
@@ -106,7 +111,7 @@
|
|||||||
-- * Silkworm (though strictly speaking this is a surface to ship missile)
|
-- * Silkworm (though strictly speaking this is a surface to ship missile)
|
||||||
-- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19
|
-- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19
|
||||||
-- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!)
|
-- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!)
|
||||||
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2
|
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2, SAMP/T Block 1, SAMP/T Block 1INT, SAMP/T Block2
|
||||||
--
|
--
|
||||||
-- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M
|
-- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M
|
||||||
-- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA"
|
-- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA"
|
||||||
@@ -120,19 +125,20 @@
|
|||||||
-- * SA-2 (with V759 missile, e.g. "Red SAM SA-2 HDS")
|
-- * SA-2 (with V759 missile, e.g. "Red SAM SA-2 HDS")
|
||||||
-- * SA-2 (with HQ-2 launcher, use HQ-2 in the group name, e.g. "Red SAM HQ-2" )
|
-- * SA-2 (with HQ-2 launcher, use HQ-2 in the group name, e.g. "Red SAM HQ-2" )
|
||||||
-- * SA-3 (with V601P missile, e.g. "Red SAM SA-3 HDS")
|
-- * SA-3 (with V601P missile, e.g. "Red SAM SA-3 HDS")
|
||||||
-- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS")
|
-- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS" with 5P85CE launcher)
|
||||||
-- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS")
|
-- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS" with 5P85SE launcher)
|
||||||
-- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS")
|
-- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS 2" for the 9A82 variant and "Red SAM SA-12 HDS 1" for the 9A83 variant)
|
||||||
-- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS")
|
-- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS 2" for the 9A82ME variant and "Red SAM SA-23 HDS 1" for the 9A83ME variant)
|
||||||
|
-- * SAMP/T (launcher dependent range, e.g. "Blue SAM SAMPT Block 1 HDS" for Block 1, "Blue SAM SAMPT Block 1INT HDS", "Blue SAM SAMPT Block 2 HDS")
|
||||||
--
|
--
|
||||||
-- The other HDS types work like the rest of the known SAM systems.
|
-- The other HDS types work like the rest of the known SAM systems.
|
||||||
--
|
--
|
||||||
-- # 0.1 Set-up in the mission editor
|
-- # 0.1 Set-up in the mission editor
|
||||||
--
|
--
|
||||||
-- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above.
|
-- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above.Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc.
|
||||||
-- Set up your EWR system in the mission editor. Name the groups using a systematic approach like above. Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc.
|
|
||||||
-- Search Radars usually have "SR" or "STR" in their names. Use the encyclopedia in the mission editor to inform yourself.
|
-- Search Radars usually have "SR" or "STR" in their names. Use the encyclopedia in the mission editor to inform yourself.
|
||||||
-- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one** group per SAM location. SA-15 TOR systems offer a good missile defense.
|
-- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one unit ** per group (multiple groups) for the SAM location.
|
||||||
|
-- Else, evasive manoevers might club up all defenders in one place. Red SA-15 TOR systems offer a good missile defense.
|
||||||
--
|
--
|
||||||
-- [optional] Set up your HQ. Can be any group, e.g. a command vehicle.
|
-- [optional] Set up your HQ. Can be any group, e.g. a command vehicle.
|
||||||
--
|
--
|
||||||
@@ -144,6 +150,7 @@
|
|||||||
-- **Location** is of highest importance here. Whilst AWACS in DCS has almost the "all seeing eye", EWR don't have that. Choose your location wisely, against a mountain backdrop or inside a valley even the best EWR system
|
-- **Location** is of highest importance here. Whilst AWACS in DCS has almost the "all seeing eye", EWR don't have that. Choose your location wisely, against a mountain backdrop or inside a valley even the best EWR system
|
||||||
-- doesn't work well. Prefer higher-up locations with a good view; use F7 in-game to check where you actually placed your EWR and have a look around. Apart from the obvious choice, do also consider other radar units
|
-- doesn't work well. Prefer higher-up locations with a good view; use F7 in-game to check where you actually placed your EWR and have a look around. Apart from the obvious choice, do also consider other radar units
|
||||||
-- for this role, most have "SR" (search radar) or "STR" (search and track radar) in their names, use the encyclopedia to see what they actually do.
|
-- for this role, most have "SR" (search radar) or "STR" (search and track radar) in their names, use the encyclopedia to see what they actually do.
|
||||||
|
-- **HINT** Set at least one EWR on invisible and immortal so MANTIS doesn't stop working.
|
||||||
--
|
--
|
||||||
-- ## 1.2 SAM sites
|
-- ## 1.2 SAM sites
|
||||||
--
|
--
|
||||||
@@ -183,7 +190,7 @@
|
|||||||
--
|
--
|
||||||
-- ## 2.1 Auto mode features
|
-- ## 2.1 Auto mode features
|
||||||
--
|
--
|
||||||
-- ### 2.1.1 You can now add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones:
|
-- ### 2.1.1 You can add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones:
|
||||||
--
|
--
|
||||||
-- -- Parameters are tables of Core.Zone#ZONE objects!
|
-- -- Parameters are tables of Core.Zone#ZONE objects!
|
||||||
-- -- This is effectively a 3-stage filter allowing for zone overlap. A coordinate is accepted first when
|
-- -- This is effectively a 3-stage filter allowing for zone overlap. A coordinate is accepted first when
|
||||||
@@ -192,31 +199,32 @@
|
|||||||
-- mybluemantis:AddZones(AcceptZones,RejectZones,ConflictZones)
|
-- mybluemantis:AddZones(AcceptZones,RejectZones,ConflictZones)
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ### 2.1.2 Change the number of long-, mid- and short-range systems going live on a detected target:
|
-- ### 2.1.2 Change the number of long-, mid- and short-range, point defense systems going live on a detected target:
|
||||||
--
|
--
|
||||||
-- -- parameters are numbers. Defaults are 1,2,2,6 respectively
|
-- -- parameters are numbers. Defaults are 1,2,2,6,6 respectively
|
||||||
-- mybluemantis:SetMaxActiveSAMs(Short,Mid,Long,Classic)
|
-- mybluemantis:SetMaxActiveSAMs(Short,Mid,Long,Classic,Point)
|
||||||
--
|
--
|
||||||
-- ### 2.1.3 SHORAD will automatically be added from SAM sites of type "short-range"
|
-- ### 2.1.3 SHORAD/Point defense will automatically be added from SAM sites of type "point" or if the range is less than 5km or if the type is AAA.
|
||||||
--
|
--
|
||||||
-- ### 2.1.4 Advanced features
|
-- ### 2.1.4 Advanced features
|
||||||
--
|
|
||||||
-- -- switch off auto mode **before** you start MANTIS.
|
|
||||||
-- mybluemantis.automode = false
|
|
||||||
--
|
--
|
||||||
-- -- switch off auto shorad **before** you start MANTIS.
|
-- -- Option to set the scale of the activation range, i.e. don't activate at the fringes of max range, defaults below.
|
||||||
-- mybluemantis.autoshorad = false
|
|
||||||
--
|
|
||||||
-- -- scale of the activation range, i.e. don't activate at the fringes of max range, defaults below.
|
|
||||||
-- -- also see engagerange below.
|
-- -- also see engagerange below.
|
||||||
-- self.radiusscale[MANTIS.SamType.LONG] = 1.1
|
-- self.radiusscale[MANTIS.SamType.LONG] = 1.1
|
||||||
-- self.radiusscale[MANTIS.SamType.MEDIUM] = 1.2
|
-- self.radiusscale[MANTIS.SamType.MEDIUM] = 1.2
|
||||||
-- self.radiusscale[MANTIS.SamType.SHORT] = 1.3
|
-- self.radiusscale[MANTIS.SamType.SHORT] = 1.3
|
||||||
|
-- self.radiusscale[MANTIS.SamType.POINT] = 1.4
|
||||||
--
|
--
|
||||||
-- ### 2.1.5 Friendlies check in firing range
|
-- ### 2.1.5 Friendlies check in firing range
|
||||||
--
|
--
|
||||||
-- -- For some scenarios, like Cold War, it might be useful not to activate SAMs if friendly aircraft are around to avoid death by friendly fire.
|
-- -- For some scenarios, like Cold War, it might be useful not to activate SAMs if friendly aircraft are around to avoid death by friendly fire.
|
||||||
-- mybluemantis.checkforfriendlies = true
|
-- mybluemantis.checkforfriendlies = true
|
||||||
|
--
|
||||||
|
-- ### 2.1.6 Shoot & Scoot
|
||||||
|
--
|
||||||
|
-- -- Option to make the (driveable) SHORAD units drive around and shuffle positions
|
||||||
|
-- -- We use a SET_ZONE for that, number of zones to consider defaults to three, Random is true for random coordinates and Formation is e.g. "Vee".
|
||||||
|
-- mybluemantis:AddScootZones(ZoneSet, Number, Random, Formation)
|
||||||
--
|
--
|
||||||
-- # 3. Default settings [both modes unless stated otherwise]
|
-- # 3. Default settings [both modes unless stated otherwise]
|
||||||
--
|
--
|
||||||
@@ -239,26 +247,8 @@
|
|||||||
-- E.g. mymantis:SetAdvancedMode( true, 90 )
|
-- E.g. mymantis:SetAdvancedMode( true, 90 )
|
||||||
--
|
--
|
||||||
-- Use this option if you want to make use of or allow advanced SEAD tactics.
|
-- Use this option if you want to make use of or allow advanced SEAD tactics.
|
||||||
--
|
|
||||||
-- # 5. Integrate SHORAD [classic mode, not necessary in automode]
|
|
||||||
--
|
|
||||||
-- You can also choose to integrate Mantis with @{Functional.Shorad#SHORAD} for protection against HARMs and AGMs. When SHORAD detects a missile fired at one of MANTIS' SAM sites, it will activate SHORAD systems in
|
|
||||||
-- the given defense checkradius around that SAM site. Create a SHORAD object first, then integrate with MANTIS like so:
|
|
||||||
--
|
|
||||||
-- local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()
|
|
||||||
-- myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue")
|
|
||||||
-- -- now set up MANTIS
|
|
||||||
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
|
||||||
-- mymantis:AddShorad(myshorad,720)
|
|
||||||
-- mymantis:Start()
|
|
||||||
--
|
--
|
||||||
-- If you systematically name your SHORAD groups starting with "Blue SHORAD" you'll need exactly **one** SHORAD instance to manage all SHORAD groups.
|
-- # 5. Integrated SEAD
|
||||||
--
|
|
||||||
-- (Optionally) you can remove the link later on with
|
|
||||||
--
|
|
||||||
-- mymantis:RemoveShorad()
|
|
||||||
--
|
|
||||||
-- # 6. Integrated SEAD
|
|
||||||
--
|
--
|
||||||
-- MANTIS is using @{Functional.Sead#SEAD} internally to both detect and evade HARM attacks. No extra efforts needed to set this up!
|
-- MANTIS is using @{Functional.Sead#SEAD} internally to both detect and evade HARM attacks. No extra efforts needed to set this up!
|
||||||
-- Once a HARM attack is detected, MANTIS (via SEAD) will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
|
-- Once a HARM attack is detected, MANTIS (via SEAD) will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
|
||||||
@@ -285,6 +275,7 @@
|
|||||||
MANTIS = {
|
MANTIS = {
|
||||||
ClassName = "MANTIS",
|
ClassName = "MANTIS",
|
||||||
name = "mymantis",
|
name = "mymantis",
|
||||||
|
version = "0.9.32",
|
||||||
SAM_Templates_Prefix = "",
|
SAM_Templates_Prefix = "",
|
||||||
SAM_Group = nil,
|
SAM_Group = nil,
|
||||||
EWR_Templates_Prefix = "",
|
EWR_Templates_Prefix = "",
|
||||||
@@ -296,6 +287,7 @@ MANTIS = {
|
|||||||
SAM_Table_Long = {},
|
SAM_Table_Long = {},
|
||||||
SAM_Table_Medium = {},
|
SAM_Table_Medium = {},
|
||||||
SAM_Table_Short = {},
|
SAM_Table_Short = {},
|
||||||
|
SAM_Table_PointDef = {},
|
||||||
lid = "",
|
lid = "",
|
||||||
Detection = nil,
|
Detection = nil,
|
||||||
AWACS_Detection = nil,
|
AWACS_Detection = nil,
|
||||||
@@ -329,6 +321,11 @@ MANTIS = {
|
|||||||
autoshorad = true,
|
autoshorad = true,
|
||||||
ShoradGroupSet = nil,
|
ShoradGroupSet = nil,
|
||||||
checkforfriendlies = false,
|
checkforfriendlies = false,
|
||||||
|
SmokeDecoy = false,
|
||||||
|
SmokeDecoyColor = SMOKECOLOR.White,
|
||||||
|
checkcounter = 1,
|
||||||
|
DLinkCacheTime = 120,
|
||||||
|
logsamstatus = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Advanced state enumerator
|
--- Advanced state enumerator
|
||||||
@@ -345,8 +342,17 @@ MANTIS.SamType = {
|
|||||||
SHORT = "Short",
|
SHORT = "Short",
|
||||||
MEDIUM = "Medium",
|
MEDIUM = "Medium",
|
||||||
LONG = "Long",
|
LONG = "Long",
|
||||||
|
POINT = "Point",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- SAM Radiusscale
|
||||||
|
-- @type MANTIS.radiusscale
|
||||||
|
MANTIS.radiusscale = {}
|
||||||
|
MANTIS.radiusscale[MANTIS.SamType.LONG] = 1.1
|
||||||
|
MANTIS.radiusscale[MANTIS.SamType.MEDIUM] = 1.2
|
||||||
|
MANTIS.radiusscale[MANTIS.SamType.SHORT] = 1.75
|
||||||
|
MANTIS.radiusscale[MANTIS.SamType.POINT] = 3
|
||||||
|
|
||||||
--- SAM data
|
--- SAM data
|
||||||
-- @type MANTIS.SamData
|
-- @type MANTIS.SamData
|
||||||
-- @field #number Range Max firing range in km
|
-- @field #number Range Max firing range in km
|
||||||
@@ -354,10 +360,11 @@ MANTIS.SamType = {
|
|||||||
-- @field #number Height Max firing height in km
|
-- @field #number Height Max firing height in km
|
||||||
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
||||||
-- @field #string Radar Radar typename on unit level (used as key)
|
-- @field #string Radar Radar typename on unit level (used as key)
|
||||||
|
-- @field #string Point Point defense capable
|
||||||
MANTIS.SamData = {
|
MANTIS.SamData = {
|
||||||
["Hawk"] = { Range=35, Blindspot=0, Height=12, Type="Medium", Radar="Hawk" }, -- measures in km
|
["Hawk"] = { Range=35, Blindspot=0, Height=12, Type="Medium", Radar="Hawk" }, -- measures in km
|
||||||
["NASAMS"] = { Range=14, Blindspot=0, Height=7, Type="Short", Radar="NSAMS" }, -- AIM 120B
|
["NASAMS"] = { Range=14, Blindspot=0, Height=7, Type="Short", Radar="NSAMS" }, -- AIM 120B
|
||||||
["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot" },
|
["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot str" },
|
||||||
["Rapier"] = { Range=10, Blindspot=0, Height=3, Type="Short", Radar="rapier" },
|
["Rapier"] = { Range=10, Blindspot=0, Height=3, Type="Short", Radar="rapier" },
|
||||||
["SA-2"] = { Range=40, Blindspot=7, Height=25, Type="Medium", Radar="S_75M_Volhov" },
|
["SA-2"] = { Range=40, Blindspot=7, Height=25, Type="Medium", Radar="S_75M_Volhov" },
|
||||||
["SA-3"] = { Range=18, Blindspot=6, Height=18, Type="Short", Radar="5p73 s-125 ln" },
|
["SA-3"] = { Range=18, Blindspot=6, Height=18, Type="Short", Radar="5p73 s-125 ln" },
|
||||||
@@ -365,24 +372,25 @@ MANTIS.SamData = {
|
|||||||
["SA-6"] = { Range=25, Blindspot=0, Height=8, Type="Medium", Radar="1S91" },
|
["SA-6"] = { Range=25, Blindspot=0, Height=8, Type="Medium", Radar="1S91" },
|
||||||
["SA-10"] = { Range=119, Blindspot=0, Height=18, Type="Long" , Radar="S-300PS 4"},
|
["SA-10"] = { Range=119, Blindspot=0, Height=18, Type="Long" , Radar="S-300PS 4"},
|
||||||
["SA-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" },
|
["SA-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" },
|
||||||
["Roland"] = { Range=5, Blindspot=0, Height=5, Type="Short", Radar="Roland" },
|
["Roland"] = { Range=6, Blindspot=0, Height=5, Type="Short", Radar="Roland" },
|
||||||
|
["Gepard"] = { Range=5, Blindspot=0, Height=4, Type="Point", Radar="Gepard" },
|
||||||
["HQ-7"] = { Range=12, Blindspot=0, Height=3, Type="Short", Radar="HQ-7" },
|
["HQ-7"] = { Range=12, Blindspot=0, Height=3, Type="Short", Radar="HQ-7" },
|
||||||
["SA-9"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Strela" },
|
["SA-9"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Strela", Point="true" },
|
||||||
["SA-8"] = { Range=10, Blindspot=0, Height=5, Type="Short", Radar="Osa 9A33" },
|
["SA-8"] = { Range=10, Blindspot=0, Height=5, Type="Short", Radar="Osa 9A33" },
|
||||||
["SA-19"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Tunguska" },
|
["SA-19"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Tunguska" },
|
||||||
["SA-15"] = { Range=11, Blindspot=0, Height=6, Type="Short", Radar="Tor 9A331" },
|
["SA-15"] = { Range=11, Blindspot=0, Height=6, Type="Point", Radar="Tor 9A331", Point="true" },
|
||||||
["SA-13"] = { Range=5, Blindspot=0, Height=3, Type="Short", Radar="Strela" },
|
["SA-13"] = { Range=5, Blindspot=0, Height=3, Type="Point", Radar="Strela", Point="true" },
|
||||||
["Avenger"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Avenger" },
|
["Avenger"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Avenger" },
|
||||||
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
||||||
["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Linebacker" },
|
["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Linebacker", Point="true" },
|
||||||
["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" },
|
["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" },
|
||||||
|
["HEMTT_C-RAM_Phalanx"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" },
|
||||||
-- units from HDS Mod, multi launcher options is tricky
|
-- units from HDS Mod, multi launcher options is tricky
|
||||||
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"},
|
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"},
|
||||||
["SA-17"] = { Range=50, Blindspot=3, Height=30, Type="Medium", Radar="SA-17" },
|
["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17" },
|
||||||
["SA-20A"] = { Range=150, Blindspot=5, Height=27, Type="Long" , Radar="S-300PMU1"},
|
["SA-20A"] = { Range=150, Blindspot=5, Height=27, Type="Long" , Radar="S-300PMU1"},
|
||||||
["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"},
|
["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"},
|
||||||
["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
||||||
["SHORAD"] = { Range=3, Blindspot=0, Height=3, Type="Short", Radar="Igla" },
|
|
||||||
["TAMIR IDFA"] = { Range=20, Blindspot=0.6, Height=12.3, Type="Short", Radar="IRON_DOME_LN" },
|
["TAMIR IDFA"] = { Range=20, Blindspot=0.6, Height=12.3, Type="Short", Radar="IRON_DOME_LN" },
|
||||||
["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" },
|
["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" },
|
||||||
}
|
}
|
||||||
@@ -394,18 +402,23 @@ MANTIS.SamData = {
|
|||||||
-- @field #number Height Max firing height in km
|
-- @field #number Height Max firing height in km
|
||||||
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
||||||
-- @field #string Radar Radar typename on unit level (used as key)
|
-- @field #string Radar Radar typename on unit level (used as key)
|
||||||
|
-- @field #string Point Point defense capable
|
||||||
MANTIS.SamDataHDS = {
|
MANTIS.SamDataHDS = {
|
||||||
-- units from HDS Mod, multi launcher options is tricky
|
-- units from HDS Mod, multi launcher options is tricky
|
||||||
-- group name MUST contain HDS to ID launcher type correctly!
|
-- group name MUST contain HDS to ID launcher type correctly!
|
||||||
["SA-2 HDS"] = { Range=56, Blindspot=7, Height=30, Type="Medium", Radar="V759" },
|
["SA-2 HDS"] = { Range=56, Blindspot=7, Height=30, Type="Medium", Radar="V759" },
|
||||||
["SA-3 HDS"] = { Range=20, Blindspot=6, Height=30, Type="Short", Radar="V-601P" },
|
["SA-3 HDS"] = { Range=20, Blindspot=6, Height=30, Type="Short", Radar="V-601P" },
|
||||||
["SA-10C HDS 2"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85DE ln"}, -- V55RUD
|
["SA-10B HDS"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD
|
||||||
["SA-10C HDS 1"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD
|
["SA-10C HDS"] = { Range=75, Blindspot=5, Height=25, Type="Long" , Radar="5P85SE ln"}, -- V55RUD
|
||||||
["SA-12 HDS 2"] = { Range=100, Blindspot=10, Height=25, Type="Long" , Radar="S-300V 9A82 l"},
|
["SA-17 HDS"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17 " },
|
||||||
["SA-12 HDS 1"] = { Range=75, Blindspot=1, Height=25, Type="Long" , Radar="S-300V 9A83 l"},
|
["SA-12 HDS 2"] = { Range=100, Blindspot=13, Height=30, Type="Long" , Radar="S-300V 9A82 l"},
|
||||||
|
["SA-12 HDS 1"] = { Range=75, Blindspot=6, Height=25, Type="Long" , Radar="S-300V 9A83 l"},
|
||||||
["SA-23 HDS 2"] = { Range=200, Blindspot=5, Height=37, Type="Long", Radar="S-300VM 9A82ME" },
|
["SA-23 HDS 2"] = { Range=200, Blindspot=5, Height=37, Type="Long", Radar="S-300VM 9A82ME" },
|
||||||
["SA-23 HDS 1"] = { Range=100, Blindspot=1, Height=50, Type="Long", Radar="S-300VM 9A83ME" },
|
["SA-23 HDS 1"] = { Range=100, Blindspot=1, Height=50, Type="Long", Radar="S-300VM 9A83ME" },
|
||||||
["HQ-2 HDS"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
["HQ-2 HDS"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
||||||
|
["SAMPT Block 1 HDS"] = { Range=120, Blindspot=1, Height=20, Type="long", Radar="SAMPT_MLT_Blk1" }, -- Block 1 Launcher
|
||||||
|
["SAMPT Block 1INT HDS"] = { Range=150, Blindspot=1, Height=25, Type="long", Radar="SAMPT_MLT_Blk1NT" }, -- Block 1-INT Launcher
|
||||||
|
["SAMPT Block 2 HDS"] = { Range=200, Blindspot=10, Height=70, Type="long", Radar="SAMPT_MLT_Blk2" }, -- Block 2 Launcher
|
||||||
}
|
}
|
||||||
|
|
||||||
--- SAM data SMA
|
--- SAM data SMA
|
||||||
@@ -415,20 +428,21 @@ MANTIS.SamDataHDS = {
|
|||||||
-- @field #number Height Max firing height in km
|
-- @field #number Height Max firing height in km
|
||||||
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
||||||
-- @field #string Radar Radar typename on unit level (used as key)
|
-- @field #string Radar Radar typename on unit level (used as key)
|
||||||
|
-- @field #string Point Point defense capable
|
||||||
MANTIS.SamDataSMA = {
|
MANTIS.SamDataSMA = {
|
||||||
-- units from SMA Mod (Sweedish Military Assets)
|
-- units from SMA Mod (Sweedish Military Assets)
|
||||||
-- https://forum.dcs.world/topic/295202-swedish-military-assets-for-dcs-by-currenthill/
|
-- https://forum.dcs.world/topic/295202-swedish-military-assets-for-dcs-by-currenthill/
|
||||||
-- group name MUST contain SMA to ID launcher type correctly!
|
-- group name MUST contain SMA to ID launcher type correctly!
|
||||||
["RBS98M SMA"] = { Range=20, Blindspot=0, Height=8, Type="Short", Radar="RBS-98" },
|
["RBS98M SMA"] = { Range=20, Blindspot=0.2, Height=8, Type="Short", Radar="RBS-98" },
|
||||||
["RBS70 SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-70" },
|
["RBS70 SMA"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="RBS-70" },
|
||||||
["RBS70M SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="BV410_RBS70" },
|
["RBS70M SMA"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="BV410_RBS70" },
|
||||||
["RBS90 SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-90" },
|
["RBS90 SMA"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="RBS-90" },
|
||||||
["RBS90M SMA"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="BV410_RBS90" },
|
["RBS90M SMA"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="BV410_RBS90" },
|
||||||
["RBS103A SMA"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
|
["RBS103A SMA"] = { Range=160, Blindspot=1, Height=36, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
|
||||||
["RBS103B SMA"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_Rb103B" },
|
["RBS103B SMA"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103B" },
|
||||||
["RBS103AM SMA"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
|
["RBS103AM SMA"] = { Range=160, Blindspot=1, Height=36, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
|
||||||
["RBS103BM SMA"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_HX_Rb103B" },
|
["RBS103BM SMA"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103B" },
|
||||||
["Lvkv9040M SMA"] = { Range=4, Blindspot=0, Height=2.5, Type="Short", Radar="LvKv9040" },
|
["Lvkv9040M SMA"] = { Range=2, Blindspot=0.1, Height=1.2, Type="Point", Radar="LvKv9040",Point="true" },
|
||||||
}
|
}
|
||||||
|
|
||||||
--- SAM data CH
|
--- SAM data CH
|
||||||
@@ -438,28 +452,54 @@ MANTIS.SamDataSMA = {
|
|||||||
-- @field #number Height Max firing height in km
|
-- @field #number Height Max firing height in km
|
||||||
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
||||||
-- @field #string Radar Radar typename on unit level (used as key)
|
-- @field #string Radar Radar typename on unit level (used as key)
|
||||||
|
-- @field #string Point Point defense capable
|
||||||
MANTIS.SamDataCH = {
|
MANTIS.SamDataCH = {
|
||||||
-- units from CH (Military Assets by Currenthill)
|
-- units from CH (Military Assets by Currenthill)
|
||||||
-- https://www.currenthill.com/
|
-- https://www.currenthill.com/
|
||||||
-- group name MUST contain CHM to ID launcher type correctly!
|
-- group name MUST contain CHM to ID launcher type correctly!
|
||||||
["2S38 CH"] = { Range=8, Blindspot=0.5, Height=6, Type="Short", Radar="2S38" },
|
["2S38 CHM"] = { Range=6, Blindspot=0.1, Height=4.5, Type="Short", Radar="2S38" },
|
||||||
["PantsirS1 CH"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
|
["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
|
||||||
["PantsirS2 CH"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
|
["PantsirS2 CHM"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
|
||||||
["PGL-625 CH"] = { Range=10, Blindspot=0.5, Height=5, Type="Short", Radar="PGL_625" },
|
["PGL-625 CHM"] = { Range=10, Blindspot=1, Height=5, Type="Short", Radar="PGL_625" },
|
||||||
["HQ-17A CH"] = { Range=20, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
|
["HQ-17A CHM"] = { Range=15, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
|
||||||
["M903PAC2 CH"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
|
["M903PAC2 CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
|
||||||
["M903PAC3 CH"] = { Range=120, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
|
["M903PAC3 CHM"] = { Range=160, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
|
||||||
["TorM2 CH"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
|
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
|
||||||
["TorM2K CH"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
|
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
|
||||||
["TorM2M CH"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
|
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
|
||||||
["NASAMS3-AMRAAMER CH"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
|
["NASAMS3-AMRAAMER CHM"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
|
||||||
["NASAMS3-AIM9X2 CH"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
|
["NASAMS3-AIM9X2 CHM"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
|
||||||
["C-RAM CH"] = { Range=2, Blindspot=0, Height=2, Type="Short", Radar="CH_Centurion_C_RAM" },
|
["C-RAM CHM"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="CH_Centurion_C_RAM", Point="true" },
|
||||||
["PGZ-09 CH"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="CH_PGZ09" },
|
["PGZ-09 CHM"] = { Range=4, Blindspot=0.5, Height=3, Type="Point", Radar="CH_PGZ09", Point="true" },
|
||||||
["S350-9M100 CH"] = { Range=15, Blindspot=1.5, Height=8, Type="Short", Radar="CH_S350_50P6_9M100" },
|
["S350-9M100 CHM"] = { Range=15, Blindspot=1, Height=8, Type="Short", Radar="CH_S350_50P6_9M100" },
|
||||||
["S350-9M96D CH"] = { Range=150, Blindspot=2.5, Height=30, Type="Long", Radar="CH_S350_50P6_9M96D" },
|
["S350-9M96D CHM"] = { Range=150, Blindspot=2.5, Height=30, Type="Long", Radar="CH_S350_50P6_9M96D" },
|
||||||
["LAV-AD CH"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_LAVAD" },
|
["LAV-AD CHM"] = { Range=8, Blindspot=0.16, Height=4.8, Type="Short", Radar="CH_LAVAD" },
|
||||||
["HQ-22 CH"] = { Range=170, Blindspot=5, Height=27, Type="Long", Radar="CH_HQ22_LN" },
|
["HQ-22 CHM"] = { Range=170, Blindspot=5, Height=27, Type="Long", Radar="CH_HQ22_LN" },
|
||||||
|
["PGZ-95 CHM"] = { Range=2.5, Blindspot=0.5, Height=2, Type="Point", Radar="CH_PGZ95",Point="true" },
|
||||||
|
["LD-3000 CHM"] = { Range=2.5, Blindspot=0.1, Height=3, Type="Point", Radar="CH_LD3000_stationary", Point="true" },
|
||||||
|
["LD-3000M CHM"] = { Range=2.5, Blindspot=0.1, Height=3, Type="Point", Radar="CH_LD3000", Point="true" },
|
||||||
|
["FlaRakRad CHM"] = { Range=8, Blindspot=1.5, Height=6, Type="Short", Radar="CH_FlaRakRad" },
|
||||||
|
["IRIS-T SLM CHM"] = { Range=40, Blindspot=0.5, Height=20, Type="Medium", Radar="CH_IRIST_SLM" },
|
||||||
|
["M903PAC2KAT1 CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="CH_MIM104_M903_PAC2_KAT1" },
|
||||||
|
["Skynex CHM"] = { Range=3.5, Blindspot=0.1, Height=3.5, Type="Point", Radar="CH_SkynexHX", Point="true" },
|
||||||
|
["Skyshield CHM"] = { Range=3.5, Blindspot=0.1, Height=3.5, Type="Point", Radar="CH_Skyshield_Gun", Point="true" },
|
||||||
|
["WieselOzelot CHM"] = { Range=8, Blindspot=0.16, Height=4.8, Type="Short", Radar="CH_Wiesel2Ozelot" },
|
||||||
|
["BukM3-9M317M CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317M" },
|
||||||
|
["BukM3-9M317MA CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317MA" },
|
||||||
|
["SkySabre CHM"] = { Range=30, Blindspot=0.5, Height=10, Type="Medium", Radar="CH_SkySabreLN" },
|
||||||
|
["Stormer CHM"] = { Range=7.5, Blindspot=0.3, Height=7, Type="Short", Radar="CH_StormerHVM" },
|
||||||
|
["THAAD CHM"] = { Range=200, Blindspot=40, Height=150, Type="Long", Radar="CH_THAAD_M1120" },
|
||||||
|
["USInfantryFIM92K CHM"] = { Range=8, Blindspot=0.16, Height=4.8, Type="Short", Radar="CH_USInfantry_FIM92" },
|
||||||
|
["RBS98M CHM"] = { Range=20, Blindspot=0.2, Height=8, Type="Short", Radar="RBS-98" },
|
||||||
|
["RBS70 CHM"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="RBS-70" },
|
||||||
|
["RBS70M CHM"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="BV410_RBS70" },
|
||||||
|
["RBS90 CHM"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="RBS-90" },
|
||||||
|
["RBS90M CHM"] = { Range=8, Blindspot=0.25, Height=6, Type="Short", Radar="BV410_RBS90" },
|
||||||
|
["RBS103A CHM"] = { Range=160, Blindspot=1, Height=36, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
|
||||||
|
["RBS103B CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103B" },
|
||||||
|
["RBS103AM CHM"] = { Range=160, Blindspot=1, Height=36, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
|
||||||
|
["RBS103BM CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103B" },
|
||||||
|
["Lvkv9040M CHM"] = { Range=2, Blindspot=0.1, Height=1.2, Type="Point", Radar="LvKv9040",Point="true" },
|
||||||
}
|
}
|
||||||
|
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
@@ -520,6 +560,7 @@ do
|
|||||||
self.SAM_Table_Long = {}
|
self.SAM_Table_Long = {}
|
||||||
self.SAM_Table_Medium = {}
|
self.SAM_Table_Medium = {}
|
||||||
self.SAM_Table_Short = {}
|
self.SAM_Table_Short = {}
|
||||||
|
self.SAM_Table_PointDef = {}
|
||||||
self.dynamic = dynamic or false
|
self.dynamic = dynamic or false
|
||||||
self.checkradius = 25000
|
self.checkradius = 25000
|
||||||
self.grouping = 5000
|
self.grouping = 5000
|
||||||
@@ -548,10 +589,6 @@ do
|
|||||||
self.SuppressedGroups = {}
|
self.SuppressedGroups = {}
|
||||||
-- 0.8 additions
|
-- 0.8 additions
|
||||||
self.automode = true
|
self.automode = true
|
||||||
self.radiusscale = {}
|
|
||||||
self.radiusscale[MANTIS.SamType.LONG] = 1.1
|
|
||||||
self.radiusscale[MANTIS.SamType.MEDIUM] = 1.2
|
|
||||||
self.radiusscale[MANTIS.SamType.SHORT] = 1.3
|
|
||||||
--self.SAMCheckRanges = {}
|
--self.SAMCheckRanges = {}
|
||||||
self.usezones = false
|
self.usezones = false
|
||||||
self.AcceptZones = {}
|
self.AcceptZones = {}
|
||||||
@@ -560,6 +597,7 @@ do
|
|||||||
self.maxlongrange = 1
|
self.maxlongrange = 1
|
||||||
self.maxmidrange = 2
|
self.maxmidrange = 2
|
||||||
self.maxshortrange = 2
|
self.maxshortrange = 2
|
||||||
|
self.maxpointdefrange = 6
|
||||||
self.maxclassic = 6
|
self.maxclassic = 6
|
||||||
self.autoshorad = true
|
self.autoshorad = true
|
||||||
self.ShoradGroupSet = SET_GROUP:New() -- Core.Set#SET_GROUP
|
self.ShoradGroupSet = SET_GROUP:New() -- Core.Set#SET_GROUP
|
||||||
@@ -567,7 +605,10 @@ do
|
|||||||
|
|
||||||
self.SkateZones = nil
|
self.SkateZones = nil
|
||||||
self.SkateNumber = 3
|
self.SkateNumber = 3
|
||||||
self.shootandscoot = false
|
self.shootandscoot = false
|
||||||
|
|
||||||
|
self.SmokeDecoy = false
|
||||||
|
self.SmokeDecoyColor = SMOKECOLOR.White
|
||||||
|
|
||||||
self.UseEmOnOff = true
|
self.UseEmOnOff = true
|
||||||
if EmOnOff == false then
|
if EmOnOff == false then
|
||||||
@@ -579,7 +620,9 @@ do
|
|||||||
else
|
else
|
||||||
self.advAwacs = false
|
self.advAwacs = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:SetDLinkCacheTime()
|
||||||
|
|
||||||
-- Set the string id for output to DCS.log file.
|
-- Set the string id for output to DCS.log file.
|
||||||
self.lid=string.format("MANTIS %s | ", self.name)
|
self.lid=string.format("MANTIS %s | ", self.name)
|
||||||
|
|
||||||
@@ -612,6 +655,8 @@ do
|
|||||||
table.insert(self.ewr_templates,awacs)
|
table.insert(self.ewr_templates,awacs)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.logsamstatus = false
|
||||||
|
|
||||||
self:T({self.ewr_templates})
|
self:T({self.ewr_templates})
|
||||||
|
|
||||||
self.SAM_Group = SET_GROUP:New():FilterPrefixes(self.SAM_Templates_Prefix):FilterCoalitions(self.Coalition)
|
self.SAM_Group = SET_GROUP:New():FilterPrefixes(self.SAM_Templates_Prefix):FilterCoalitions(self.Coalition)
|
||||||
@@ -638,9 +683,9 @@ do
|
|||||||
self.HQ_CC = GROUP:FindByName(self.HQ_Template_CC)
|
self.HQ_CC = GROUP:FindByName(self.HQ_Template_CC)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO Version
|
-- counter for SAM table updates
|
||||||
-- @field #string version
|
self.checkcounter = 1
|
||||||
self.version="0.8.18"
|
|
||||||
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||||
|
|
||||||
--- FSM Functions ---
|
--- FSM Functions ---
|
||||||
@@ -837,7 +882,7 @@ do
|
|||||||
self.AcceptZones = AcceptZones or {}
|
self.AcceptZones = AcceptZones or {}
|
||||||
self.RejectZones = RejectZones or {}
|
self.RejectZones = RejectZones or {}
|
||||||
self.ConflictZones = ConflictZones or {}
|
self.ConflictZones = ConflictZones or {}
|
||||||
if #AcceptZones > 0 or #RejectZones > 0 or #ConflictZones > 0 then
|
if #self.AcceptZones > 0 or #self.RejectZones > 0 or #self.ConflictZones > 0 then
|
||||||
self.usezones = true
|
self.usezones = true
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -876,19 +921,31 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Function to set Short Range SAMs to spit out smoke as decoy, if an enemy plane is in range.
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #boolean Onoff Set to true for on and nil/false for off.
|
||||||
|
-- @param #number Color (Optional) Color to use, defaults to `SMOKECOLOR.White`
|
||||||
|
function MANTIS:SetSmokeDecoy(Onoff,Color)
|
||||||
|
self.SmokeDecoy = Onoff
|
||||||
|
self.SmokeDecoyColor = Color or SMOKECOLOR.White
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Function to set number of SAMs going active on a valid, detected thread
|
--- Function to set number of SAMs going active on a valid, detected thread
|
||||||
-- @param #MANTIS self
|
-- @param #MANTIS self
|
||||||
-- @param #number Short Number of short-range systems activated, defaults to 1.
|
-- @param #number Short Number of short-range systems activated, defaults to 1.
|
||||||
-- @param #number Mid Number of mid-range systems activated, defaults to 2.
|
-- @param #number Mid Number of mid-range systems activated, defaults to 2.
|
||||||
-- @param #number Long Number of long-range systems activated, defaults to 2.
|
-- @param #number Long Number of long-range systems activated, defaults to 2.
|
||||||
-- @param #number Classic (non-automode) Number of overall systems activated, defaults to 6.
|
-- @param #number Classic (non-automode) Number of overall systems activated, defaults to 6.
|
||||||
|
-- @param #number Point Number of point defense and AAA systems activated, defaults to 6.
|
||||||
-- @return #MANTIS self
|
-- @return #MANTIS self
|
||||||
function MANTIS:SetMaxActiveSAMs(Short,Mid,Long,Classic)
|
function MANTIS:SetMaxActiveSAMs(Short,Mid,Long,Classic,Point)
|
||||||
self:T(self.lid .. "SetMaxActiveSAMs")
|
self:T(self.lid .. "SetMaxActiveSAMs")
|
||||||
self.maxclassic = Classic or 6
|
self.maxclassic = Classic or 6
|
||||||
self.maxlongrange = Long or 1
|
self.maxlongrange = Long or 1
|
||||||
self.maxmidrange = Mid or 2
|
self.maxmidrange = Mid or 2
|
||||||
self.maxshortrange = Short or 2
|
self.maxshortrange = Short or 2
|
||||||
|
self.maxpointdefrange= Point or 6
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -978,6 +1035,16 @@ do
|
|||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Function to set how long INTEL DLINK remembers contacts.
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #number seconds Remember this many seconds, at least 5 seconds.
|
||||||
|
-- @return #MANTIS self
|
||||||
|
function MANTIS:SetDLinkCacheTime(seconds)
|
||||||
|
self.DLinkCacheTime = math.abs(seconds or 120)
|
||||||
|
if self.DLinkCacheTime < 5 then self.DLinkCacheTime = 5 end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Function to set the detection interval
|
--- Function to set the detection interval
|
||||||
-- @param #MANTIS self
|
-- @param #MANTIS self
|
||||||
@@ -1090,6 +1157,24 @@ do
|
|||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [Internal] Check if any EWR or AWACS is still alive
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #boolean outcome
|
||||||
|
function MANTIS:_CheckAnyEWRAlive()
|
||||||
|
self:T(self.lid .. "_CheckAnyEWRAlive")
|
||||||
|
local alive = false
|
||||||
|
if self.EWR_Group:CountAlive() > 0 then
|
||||||
|
alive = true
|
||||||
|
end
|
||||||
|
if not alive and self.AWACS_Prefix then
|
||||||
|
local awacs = GROUP:FindByName(self.AWACS_Prefix)
|
||||||
|
if awacs and awacs:IsAlive() then
|
||||||
|
alive = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return alive
|
||||||
|
end
|
||||||
|
|
||||||
--- [Internal] Function to determine state of the advanced mode
|
--- [Internal] Function to determine state of the advanced mode
|
||||||
-- @param #MANTIS self
|
-- @param #MANTIS self
|
||||||
@@ -1264,9 +1349,9 @@ do
|
|||||||
-- DEBUG
|
-- DEBUG
|
||||||
set = self:_PreFilterHeight(height)
|
set = self:_PreFilterHeight(height)
|
||||||
end
|
end
|
||||||
local friendlyset -- Core.Set#SET_GROUP
|
--self.friendlyset -- Core.Set#SET_GROUP
|
||||||
if self.checkforfriendlies == true then
|
if self.checkforfriendlies == true and self.friendlyset == nil then
|
||||||
friendlyset = SET_GROUP:New():FilterCoalitions(self.Coalition):FilterCategories({"plane","helicopter"}):FilterFunction(function(grp) if grp and grp:InAir() then return true else return false end end):FilterOnce()
|
self.friendlyset = SET_GROUP:New():FilterCoalitions(self.Coalition):FilterCategories({"plane","helicopter"}):FilterFunction(function(grp) if grp and grp:InAir() then return true else return false end end):FilterStart()
|
||||||
end
|
end
|
||||||
for _,_coord in pairs (set) do
|
for _,_coord in pairs (set) do
|
||||||
local coord = _coord -- get current coord to check
|
local coord = _coord -- get current coord to check
|
||||||
@@ -1282,20 +1367,21 @@ do
|
|||||||
zonecheck = self:_CheckCoordinateInZones(coord)
|
zonecheck = self:_CheckCoordinateInZones(coord)
|
||||||
end
|
end
|
||||||
if self.verbose and self.debug then
|
if self.verbose and self.debug then
|
||||||
local dectstring = coord:ToStringLLDMS()
|
--local dectstring = coord:ToStringLLDMS()
|
||||||
local samstring = samcoordinate:ToStringLLDMS()
|
local samstring = samcoordinate:ToStringMGRS({MGRS_Accuracy=0})
|
||||||
|
samstring = string.gsub(samstring,"%s","")
|
||||||
local inrange = "false"
|
local inrange = "false"
|
||||||
if targetdistance <= rad then
|
if targetdistance <= rad then
|
||||||
inrange = "true"
|
inrange = "true"
|
||||||
end
|
end
|
||||||
local text = string.format("Checking SAM at %s | Targetdist %d | Rad %d | Inrange %s", samstring, targetdistance, rad, inrange)
|
local text = string.format("Checking SAM at %s | Tgtdist %.1fkm | Rad %.1fkm | Inrange %s", samstring, targetdistance/1000, rad/1000, inrange)
|
||||||
local m = MESSAGE:New(text,10,"Check"):ToAllIf(self.debug)
|
local m = MESSAGE:New(text,10,"Check"):ToAllIf(self.debug)
|
||||||
self:T(self.lid..text)
|
self:T(self.lid..text)
|
||||||
end
|
end
|
||||||
-- friendlies around?
|
-- friendlies around?
|
||||||
local nofriendlies = true
|
local nofriendlies = true
|
||||||
if self.checkforfriendlies == true then
|
if self.checkforfriendlies == true then
|
||||||
local closestfriend, distance = friendlyset:GetClosestGroup(samcoordinate)
|
local closestfriend, distance = self.friendlyset:GetClosestGroup(samcoordinate)
|
||||||
if closestfriend and distance and distance < rad then
|
if closestfriend and distance and distance < rad then
|
||||||
nofriendlies = false
|
nofriendlies = false
|
||||||
end
|
end
|
||||||
@@ -1351,7 +1437,9 @@ do
|
|||||||
--IntelTwo:SetClusterRadius(5000)
|
--IntelTwo:SetClusterRadius(5000)
|
||||||
IntelTwo:Start()
|
IntelTwo:Start()
|
||||||
|
|
||||||
local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,300)
|
local CacheTime = self.DLinkCacheTime or 120
|
||||||
|
local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,CacheTime)
|
||||||
|
|
||||||
IntelDlink:__Start(1)
|
IntelDlink:__Start(1)
|
||||||
|
|
||||||
self:SetUsingDLink(IntelDlink)
|
self:SetUsingDLink(IntelDlink)
|
||||||
@@ -1396,7 +1484,7 @@ do
|
|||||||
-- @return #string type Long, medium or short range
|
-- @return #string type Long, medium or short range
|
||||||
-- @return #number blind "blind" spot
|
-- @return #number blind "blind" spot
|
||||||
function MANTIS:_GetSAMDataFromUnits(grpname,mod,sma,chm)
|
function MANTIS:_GetSAMDataFromUnits(grpname,mod,sma,chm)
|
||||||
self:T(self.lid.."_GetSAMRangeFromUnits")
|
self:T(self.lid.."_GetSAMDataFromUnits")
|
||||||
local found = false
|
local found = false
|
||||||
local range = self.checkradius
|
local range = self.checkradius
|
||||||
local height = 3000
|
local height = 3000
|
||||||
@@ -1413,7 +1501,7 @@ do
|
|||||||
elseif chm then
|
elseif chm then
|
||||||
SAMData = self.SamDataCH
|
SAMData = self.SamDataCH
|
||||||
end
|
end
|
||||||
--self:T("Looking to auto-match for "..grpname)
|
--self:I("Looking to auto-match for "..grpname)
|
||||||
for _,_unit in pairs(units) do
|
for _,_unit in pairs(units) do
|
||||||
local unit = _unit -- Wrapper.Unit#UNIT
|
local unit = _unit -- Wrapper.Unit#UNIT
|
||||||
local type = string.lower(unit:GetTypeName())
|
local type = string.lower(unit:GetTypeName())
|
||||||
@@ -1435,6 +1523,17 @@ do
|
|||||||
end
|
end
|
||||||
if found then break end
|
if found then break end
|
||||||
end
|
end
|
||||||
|
--- AAA or Point Defense
|
||||||
|
if not found then
|
||||||
|
local grp = GROUP:FindByName(grpname)
|
||||||
|
if (grp and grp:IsAlive() and grp:IsAAA()) or string.find(grpname,"AAA",1,true) then
|
||||||
|
range = 2000
|
||||||
|
height = 2000
|
||||||
|
blind = 50
|
||||||
|
type = MANTIS.SamType.POINT
|
||||||
|
found = true
|
||||||
|
end
|
||||||
|
end
|
||||||
if not found then
|
if not found then
|
||||||
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
|
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
|
||||||
end
|
end
|
||||||
@@ -1449,7 +1548,7 @@ do
|
|||||||
-- @return #string type Long, medium or short range
|
-- @return #string type Long, medium or short range
|
||||||
-- @return #number blind "blind" spot
|
-- @return #number blind "blind" spot
|
||||||
function MANTIS:_GetSAMRange(grpname)
|
function MANTIS:_GetSAMRange(grpname)
|
||||||
self:T(self.lid.."_GetSAMRange")
|
self:T(self.lid.."_GetSAMRange for "..tostring(grpname))
|
||||||
local range = self.checkradius
|
local range = self.checkradius
|
||||||
local height = 3000
|
local height = 3000
|
||||||
local type = MANTIS.SamType.MEDIUM
|
local type = MANTIS.SamType.MEDIUM
|
||||||
@@ -1466,9 +1565,9 @@ do
|
|||||||
elseif string.find(grpname,"CHM",1,true) then
|
elseif string.find(grpname,"CHM",1,true) then
|
||||||
CHMod = true
|
CHMod = true
|
||||||
end
|
end
|
||||||
if self.automode then
|
--if self.automode then
|
||||||
for idx,entry in pairs(self.SamData) do
|
for idx,entry in pairs(self.SamData) do
|
||||||
--self:I("ID = " .. idx)
|
self:T2("ID = " .. idx)
|
||||||
if string.find(grpname,idx,1,true) then
|
if string.find(grpname,idx,1,true) then
|
||||||
local _entry = entry -- #MANTIS.SamData
|
local _entry = entry -- #MANTIS.SamData
|
||||||
type = _entry.Type
|
type = _entry.Type
|
||||||
@@ -1476,18 +1575,32 @@ do
|
|||||||
range = _entry.Range * 1000 * radiusscale -- max firing range
|
range = _entry.Range * 1000 * radiusscale -- max firing range
|
||||||
height = _entry.Height * 1000 -- max firing height
|
height = _entry.Height * 1000 -- max firing height
|
||||||
blind = _entry.Blindspot
|
blind = _entry.Blindspot
|
||||||
--self:I("Matching Groupname = " .. grpname .. " Range= " .. range)
|
self:T("Matching Groupname = " .. grpname .. " Range= " .. range)
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
--end
|
||||||
|
--- Secondary - AAA or Point Defense
|
||||||
|
if not found then
|
||||||
|
local grp = GROUP:FindByName(grpname)
|
||||||
|
if (grp and grp:IsAlive() and grp:IsAAA()) or string.find(grpname,"AAA",1,true) then
|
||||||
|
range = 2000
|
||||||
|
height = 2000
|
||||||
|
blind = 50
|
||||||
|
type = MANTIS.SamType.POINT
|
||||||
|
found = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
-- secondary filter if not found
|
--- Tertiary filter if not found
|
||||||
if (not found and self.automode) or HDSmod or SMAMod or CHMod then
|
if (not found) or HDSmod or SMAMod or CHMod then
|
||||||
range, height, type = self:_GetSAMDataFromUnits(grpname,HDSmod,SMAMod,CHMod)
|
range, height, type = self:_GetSAMDataFromUnits(grpname,HDSmod,SMAMod,CHMod)
|
||||||
elseif not found then
|
elseif not found then
|
||||||
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
|
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
|
||||||
end
|
end
|
||||||
|
if found and string.find(grpname,"SHORAD",1,true) then
|
||||||
|
type = MANTIS.SamType.POINT -- force short on match
|
||||||
|
end
|
||||||
return range, height, type, blind
|
return range, height, type, blind
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1505,6 +1618,7 @@ do
|
|||||||
local SAM_Tbl_lg = {} -- table of long range SAM defense zones
|
local SAM_Tbl_lg = {} -- table of long range SAM defense zones
|
||||||
local SAM_Tbl_md = {} -- table of mid range SAM defense zones
|
local SAM_Tbl_md = {} -- table of mid range SAM defense zones
|
||||||
local SAM_Tbl_sh = {} -- table of short range SAM defense zones
|
local SAM_Tbl_sh = {} -- table of short range SAM defense zones
|
||||||
|
local SAM_Tbl_pt = {} -- table of point defense/AAA
|
||||||
local SEAD_Grps = {} -- table of SAM names to make evasive
|
local SEAD_Grps = {} -- table of SAM names to make evasive
|
||||||
local engagerange = self.engagerange -- firing range in % of max
|
local engagerange = self.engagerange -- firing range in % of max
|
||||||
--cycle through groups and set alarm state etc
|
--cycle through groups and set alarm state etc
|
||||||
@@ -1523,23 +1637,27 @@ do
|
|||||||
local grpname = group:GetName()
|
local grpname = group:GetName()
|
||||||
local grpcoord = group:GetCoordinate()
|
local grpcoord = group:GetCoordinate()
|
||||||
local grprange,grpheight,type,blind = self:_GetSAMRange(grpname)
|
local grprange,grpheight,type,blind = self:_GetSAMRange(grpname)
|
||||||
table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind})
|
table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||||
--table.insert( SEAD_Grps, grpname )
|
--table.insert( SEAD_Grps, grpname )
|
||||||
if type == MANTIS.SamType.LONG then
|
if type == MANTIS.SamType.LONG then
|
||||||
table.insert( SAM_Tbl_lg, {grpname, grpcoord, grprange, grpheight, blind})
|
table.insert( SAM_Tbl_lg, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||||
table.insert( SEAD_Grps, grpname )
|
table.insert( SEAD_Grps, grpname )
|
||||||
--self:T("SAM "..grpname.." is type LONG")
|
self:T("SAM "..grpname.." is type LONG")
|
||||||
elseif type == MANTIS.SamType.MEDIUM then
|
elseif type == MANTIS.SamType.MEDIUM then
|
||||||
table.insert( SAM_Tbl_md, {grpname, grpcoord, grprange, grpheight, blind})
|
table.insert( SAM_Tbl_md, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||||
table.insert( SEAD_Grps, grpname )
|
table.insert( SEAD_Grps, grpname )
|
||||||
--self:T("SAM "..grpname.." is type MEDIUM")
|
self:T("SAM "..grpname.." is type MEDIUM")
|
||||||
elseif type == MANTIS.SamType.SHORT then
|
elseif type == MANTIS.SamType.SHORT then
|
||||||
table.insert( SAM_Tbl_sh, {grpname, grpcoord, grprange, grpheight, blind})
|
table.insert( SAM_Tbl_sh, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||||
--self:T("SAM "..grpname.." is type SHORT")
|
table.insert( SEAD_Grps, grpname )
|
||||||
|
self:T("SAM "..grpname.." is type SHORT")
|
||||||
|
elseif type == MANTIS.SamType.POINT then
|
||||||
|
table.insert( SAM_Tbl_pt, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||||
|
self:T("SAM "..grpname.." is type POINT")
|
||||||
self.ShoradGroupSet:Add(grpname,group)
|
self.ShoradGroupSet:Add(grpname,group)
|
||||||
if not self.autoshorad then
|
if not self.autoshorad then
|
||||||
table.insert( SEAD_Grps, grpname )
|
table.insert( SEAD_Grps, grpname )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.SamStateTracker[grpname] = "GREEN"
|
self.SamStateTracker[grpname] = "GREEN"
|
||||||
end
|
end
|
||||||
@@ -1548,6 +1666,7 @@ do
|
|||||||
self.SAM_Table_Long = SAM_Tbl_lg
|
self.SAM_Table_Long = SAM_Tbl_lg
|
||||||
self.SAM_Table_Medium = SAM_Tbl_md
|
self.SAM_Table_Medium = SAM_Tbl_md
|
||||||
self.SAM_Table_Short = SAM_Tbl_sh
|
self.SAM_Table_Short = SAM_Tbl_sh
|
||||||
|
self.SAM_Table_PointDef = SAM_Tbl_pt
|
||||||
-- make SAMs evasive
|
-- make SAMs evasive
|
||||||
local mysead = SEAD:New( SEAD_Grps, self.Padding ) -- Functional.Sead#SEAD
|
local mysead = SEAD:New( SEAD_Grps, self.Padding ) -- Functional.Sead#SEAD
|
||||||
mysead:SetEngagementRange(engagerange)
|
mysead:SetEngagementRange(engagerange)
|
||||||
@@ -1571,7 +1690,8 @@ do
|
|||||||
local SAM_Tbl = {} -- table of SAM defense zones
|
local SAM_Tbl = {} -- table of SAM defense zones
|
||||||
local SAM_Tbl_lg = {} -- table of long range SAM defense zones
|
local SAM_Tbl_lg = {} -- table of long range SAM defense zones
|
||||||
local SAM_Tbl_md = {} -- table of mid range SAM defense zones
|
local SAM_Tbl_md = {} -- table of mid range SAM defense zones
|
||||||
local SAM_Tbl_sh = {} -- table of short range SAM defense zon
|
local SAM_Tbl_sh = {} -- table of short range SAM defense zones
|
||||||
|
local SAM_Tbl_pt = {} -- table of point defense/AAA
|
||||||
local SEAD_Grps = {} -- table of SAM names to make evasive
|
local SEAD_Grps = {} -- table of SAM names to make evasive
|
||||||
local engagerange = self.engagerange -- firing range in % of max
|
local engagerange = self.engagerange -- firing range in % of max
|
||||||
--cycle through groups and set alarm state etc
|
--cycle through groups and set alarm state etc
|
||||||
@@ -1582,17 +1702,23 @@ do
|
|||||||
local grpname = group:GetName()
|
local grpname = group:GetName()
|
||||||
local grpcoord = group:GetCoordinate()
|
local grpcoord = group:GetCoordinate()
|
||||||
local grprange, grpheight,type,blind = self:_GetSAMRange(grpname)
|
local grprange, grpheight,type,blind = self:_GetSAMRange(grpname)
|
||||||
table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind}) -- make the table lighter, as I don't really use the zone here
|
-- TODO the below might stop working at some point after some hours, needs testing
|
||||||
|
--local radaralive = group:IsSAM()
|
||||||
|
local radaralive = true
|
||||||
|
table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind, type}) -- make the table lighter, as I don't really use the zone here
|
||||||
table.insert( SEAD_Grps, grpname )
|
table.insert( SEAD_Grps, grpname )
|
||||||
if type == MANTIS.SamType.LONG then
|
if type == MANTIS.SamType.LONG and radaralive then
|
||||||
table.insert( SAM_Tbl_lg, {grpname, grpcoord, grprange, grpheight, blind})
|
table.insert( SAM_Tbl_lg, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||||
--self:I({grpname,grprange, grpheight})
|
self:T({grpname,grprange, grpheight})
|
||||||
elseif type == MANTIS.SamType.MEDIUM then
|
elseif type == MANTIS.SamType.MEDIUM and radaralive then
|
||||||
table.insert( SAM_Tbl_md, {grpname, grpcoord, grprange, grpheight, blind})
|
table.insert( SAM_Tbl_md, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||||
--self:I({grpname,grprange, grpheight})
|
self:T({grpname,grprange, grpheight})
|
||||||
elseif type == MANTIS.SamType.SHORT then
|
elseif type == MANTIS.SamType.SHORT and radaralive then
|
||||||
table.insert( SAM_Tbl_sh, {grpname, grpcoord, grprange, grpheight, blind})
|
table.insert( SAM_Tbl_sh, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||||
-- self:I({grpname,grprange, grpheight})
|
self:T({grpname,grprange, grpheight})
|
||||||
|
elseif type == MANTIS.SamType.POINT or (not radaralive) then
|
||||||
|
table.insert( SAM_Tbl_pt, {grpname, grpcoord, grprange, grpheight, blind, type})
|
||||||
|
self:T({grpname,grprange, grpheight})
|
||||||
self.ShoradGroupSet:Add(grpname,group)
|
self.ShoradGroupSet:Add(grpname,group)
|
||||||
if self.autoshorad then
|
if self.autoshorad then
|
||||||
self.Shorad.Groupset = self.ShoradGroupSet
|
self.Shorad.Groupset = self.ShoradGroupSet
|
||||||
@@ -1604,6 +1730,7 @@ do
|
|||||||
self.SAM_Table_Long = SAM_Tbl_lg
|
self.SAM_Table_Long = SAM_Tbl_lg
|
||||||
self.SAM_Table_Medium = SAM_Tbl_md
|
self.SAM_Table_Medium = SAM_Tbl_md
|
||||||
self.SAM_Table_Short = SAM_Tbl_sh
|
self.SAM_Table_Short = SAM_Tbl_sh
|
||||||
|
self.SAM_Table_PointDef = SAM_Tbl_pt
|
||||||
-- make SAMs evasive
|
-- make SAMs evasive
|
||||||
if self.mysead ~= nil then
|
if self.mysead ~= nil then
|
||||||
local mysead = self.mysead
|
local mysead = self.mysead
|
||||||
@@ -1647,21 +1774,34 @@ do
|
|||||||
-- @param #table detset Table of COORDINATES
|
-- @param #table detset Table of COORDINATES
|
||||||
-- @param #boolean dlink Using DLINK
|
-- @param #boolean dlink Using DLINK
|
||||||
-- @param #number limit of SAM sites to go active on a contact
|
-- @param #number limit of SAM sites to go active on a contact
|
||||||
-- @return #MANTIS self
|
-- @return #number instatusred
|
||||||
|
-- @return #number instatusgreen
|
||||||
|
-- @return #number activeshorads
|
||||||
function MANTIS:_CheckLoop(samset,detset,dlink,limit)
|
function MANTIS:_CheckLoop(samset,detset,dlink,limit)
|
||||||
self:T(self.lid .. "CheckLoop " .. #detset .. " Coordinates")
|
self:T(self.lid .. "CheckLoop " .. #detset .. " Coordinates")
|
||||||
local switchedon = 0
|
local switchedon = 0
|
||||||
|
local instatusred = 0
|
||||||
|
local instatusgreen = 0
|
||||||
|
local activeshorads = 0
|
||||||
|
local SEADactive = 0
|
||||||
for _,_data in pairs (samset) do
|
for _,_data in pairs (samset) do
|
||||||
local samcoordinate = _data[2]
|
local samcoordinate = _data[2]
|
||||||
local name = _data[1]
|
local name = _data[1]
|
||||||
local radius = _data[3]
|
local radius = _data[3]
|
||||||
local height = _data[4]
|
local height = _data[4]
|
||||||
local blind = _data[5] * 1.25 + 1
|
local blind = _data[5] * 1.25 + 1
|
||||||
|
local shortsam = (_data[6] == MANTIS.SamType.SHORT) and true or false
|
||||||
|
if not shortsam then
|
||||||
|
shortsam = (_data[6] == MANTIS.SamType.POINT) and true or false
|
||||||
|
end
|
||||||
local samgroup = GROUP:FindByName(name)
|
local samgroup = GROUP:FindByName(name)
|
||||||
local IsInZone, Distance = self:_CheckObjectInZone(detset, samcoordinate, radius, height, dlink)
|
local IsInZone, Distance = self:_CheckObjectInZone(detset, samcoordinate, radius, height, dlink)
|
||||||
local suppressed = self.SuppressedGroups[name] or false
|
local suppressed = self.SuppressedGroups[name] or false
|
||||||
local activeshorad = self.Shorad.ActiveGroups[name] or false
|
local activeshorad = false
|
||||||
if IsInZone and not suppressed and not activeshorad then --check any target in zone and not currently managed by SEAD
|
if self.Shorad and self.Shorad.ActiveGroups and self.Shorad.ActiveGroups[name] then
|
||||||
|
activeshorad = true
|
||||||
|
end
|
||||||
|
if IsInZone and (not suppressed) and (not activeshorad) then --check any target in zone and not currently managed by SEAD
|
||||||
if samgroup:IsAlive() then
|
if samgroup:IsAlive() then
|
||||||
-- switch on SAM
|
-- switch on SAM
|
||||||
local switch = false
|
local switch = false
|
||||||
@@ -1673,16 +1813,27 @@ do
|
|||||||
elseif (not self.UseEmOnOff) and switchedon < limit then
|
elseif (not self.UseEmOnOff) and switchedon < limit then
|
||||||
samgroup:OptionAlarmStateRed()
|
samgroup:OptionAlarmStateRed()
|
||||||
switchedon = switchedon + 1
|
switchedon = switchedon + 1
|
||||||
switch = true
|
switch = true
|
||||||
end
|
end
|
||||||
if self.SamStateTracker[name] ~= "RED" and switch then
|
if self.SamStateTracker[name] ~= "RED" and switch then
|
||||||
self:__RedState(1,samgroup)
|
self:__RedState(1,samgroup)
|
||||||
self.SamStateTracker[name] = "RED"
|
self.SamStateTracker[name] = "RED"
|
||||||
end
|
end
|
||||||
|
-- TODO doesn't work
|
||||||
|
if shortsam == true and self.SmokeDecoy == true then
|
||||||
|
self:T("Smoking")
|
||||||
|
local units = samgroup:GetUnits() or {}
|
||||||
|
local smoke = self.SmokeDecoyColor or SMOKECOLOR.White
|
||||||
|
for _,unit in pairs(units) do
|
||||||
|
if unit and unit:IsAlive() then
|
||||||
|
unit:GetCoordinate():Smoke(smoke)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
-- link in to SHORAD if available
|
-- link in to SHORAD if available
|
||||||
-- DONE: Test integration fully
|
-- DONE: Test integration fully
|
||||||
if self.ShoradLink and (Distance < self.ShoradActDistance or Distance < blind ) then -- don't give SHORAD position away too early
|
if self.ShoradLink and (Distance < self.ShoradActDistance or Distance < blind ) then -- don't give SHORAD position away too early
|
||||||
local Shorad = self.Shorad
|
local Shorad = self.Shorad --Functional.Shorad#SHORAD
|
||||||
local radius = self.checkradius
|
local radius = self.checkradius
|
||||||
local ontime = self.ShoradTime
|
local ontime = self.ShoradTime
|
||||||
Shorad:WakeUpShorad(name, radius, ontime)
|
Shorad:WakeUpShorad(name, radius, ontime)
|
||||||
@@ -1691,7 +1842,7 @@ do
|
|||||||
-- debug output
|
-- debug output
|
||||||
if (self.debug or self.verbose) and switch then
|
if (self.debug or self.verbose) and switch then
|
||||||
local text = string.format("SAM %s in alarm state RED!", name)
|
local text = string.format("SAM %s in alarm state RED!", name)
|
||||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
--local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug
|
||||||
if self.verbose then self:I(self.lid..text) end
|
if self.verbose then self:I(self.lid..text) end
|
||||||
end
|
end
|
||||||
end --end alive
|
end --end alive
|
||||||
@@ -1709,41 +1860,81 @@ do
|
|||||||
end
|
end
|
||||||
if self.debug or self.verbose then
|
if self.debug or self.verbose then
|
||||||
local text = string.format("SAM %s in alarm state GREEN!", name)
|
local text = string.format("SAM %s in alarm state GREEN!", name)
|
||||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
--local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
if self.verbose then self:I(self.lid..text) end
|
if self.verbose then self:I(self.lid..text) end
|
||||||
end
|
end
|
||||||
end --end alive
|
end --end alive
|
||||||
end --end check
|
end --end check
|
||||||
end --for for loop
|
end --for loop
|
||||||
return self
|
if self.debug or self.verbose or self.logsamstatus then
|
||||||
|
for _,_status in pairs(self.SamStateTracker) do
|
||||||
|
if _status == "GREEN" then
|
||||||
|
instatusgreen=instatusgreen+1
|
||||||
|
elseif _status == "RED" then
|
||||||
|
instatusred=instatusred+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if self.Shorad then
|
||||||
|
for _,_name in pairs(self.Shorad.ActiveGroups or {}) do
|
||||||
|
activeshorads=activeshorads+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return instatusred, instatusgreen, activeshorads
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [Internal] Check detection function
|
--- [Internal] Check detection function
|
||||||
-- @param #MANTIS self
|
-- @param #MANTIS self
|
||||||
-- @param Functional.Detection#DETECTION_AREAS detection Detection object
|
-- @param Functional.Detection#DETECTION_AREAS detection Detection object
|
||||||
-- @param #boolean dlink
|
-- @param #boolean dlink
|
||||||
|
-- @param #boolean reporttolog
|
||||||
-- @return #MANTIS self
|
-- @return #MANTIS self
|
||||||
function MANTIS:_Check(detection,dlink)
|
function MANTIS:_Check(detection,dlink,reporttolog)
|
||||||
self:T(self.lid .. "Check")
|
self:T(self.lid .. "Check")
|
||||||
--get detected set
|
--get detected set
|
||||||
local detset = detection:GetDetectedItemCoordinates()
|
local detset = detection:GetDetectedItemCoordinates()
|
||||||
--self:T("Check:", {detset})
|
--self:T("Check:", {detset})
|
||||||
-- randomly update SAM Table
|
-- update SAM Table evey 3 runs
|
||||||
local rand = math.random(1,100)
|
if self.checkcounter%3 == 0 then
|
||||||
if rand > 65 then -- 1/3 of cases
|
|
||||||
self:_RefreshSAMTable()
|
self:_RefreshSAMTable()
|
||||||
end
|
end
|
||||||
|
self.checkcounter = self.checkcounter + 1
|
||||||
|
local instatusred = 0
|
||||||
|
local instatusgreen = 0
|
||||||
|
local activeshorads = 0
|
||||||
-- switch SAMs on/off if (n)one of the detected groups is inside their reach
|
-- switch SAMs on/off if (n)one of the detected groups is inside their reach
|
||||||
if self.automode then
|
if self.automode then
|
||||||
local samset = self.SAM_Table_Long -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
local samset = self.SAM_Table_Long -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
||||||
self:_CheckLoop(samset,detset,dlink,self.maxlongrange)
|
local instatusredl, instatusgreenl, activeshoradsl = self:_CheckLoop(samset,detset,dlink,self.maxlongrange)
|
||||||
local samset = self.SAM_Table_Medium -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
local samset = self.SAM_Table_Medium -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
||||||
self:_CheckLoop(samset,detset,dlink,self.maxmidrange)
|
local instatusredm, instatusgreenm, activeshoradsm = self:_CheckLoop(samset,detset,dlink,self.maxmidrange)
|
||||||
local samset = self.SAM_Table_Short -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
local samset = self.SAM_Table_Short -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
||||||
self:_CheckLoop(samset,detset,dlink,self.maxshortrange)
|
local instatusreds, instatusgreens, activeshoradss = self:_CheckLoop(samset,detset,dlink,self.maxshortrange)
|
||||||
|
local samset = self.SAM_Table_PointDef -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
||||||
|
instatusred, instatusgreen, activeshorads = self:_CheckLoop(samset,detset,dlink,self.maxpointdefrange)
|
||||||
else
|
else
|
||||||
local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
||||||
self:_CheckLoop(samset,detset,dlink,self.maxclassic)
|
instatusred, instatusgreen, activeshorads = self:_CheckLoop(samset,detset,dlink,self.maxclassic)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function GetReport()
|
||||||
|
local statusreport = REPORT:New("\nMANTIS Status "..self.name)
|
||||||
|
statusreport:Add("+-----------------------------+")
|
||||||
|
statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred))
|
||||||
|
statusreport:Add(string.format("+ SAM in GREEN State: %2d",instatusgreen))
|
||||||
|
if self.Shorad then
|
||||||
|
statusreport:Add(string.format("+ SHORAD active: %2d",activeshorads))
|
||||||
|
end
|
||||||
|
statusreport:Add("+-----------------------------+")
|
||||||
|
return statusreport
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.debug or self.verbose then
|
||||||
|
local statusreport = GetReport()
|
||||||
|
MESSAGE:New(statusreport:Text(),10):ToAll():ToLog()
|
||||||
|
elseif reporttolog == true then
|
||||||
|
local statusreport = GetReport()
|
||||||
|
MESSAGE:New(statusreport:Text(),10):ToLog()
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1828,7 +2019,7 @@ do
|
|||||||
end
|
end
|
||||||
--]]
|
--]]
|
||||||
if self.autoshorad then
|
if self.autoshorad then
|
||||||
self.Shorad = SHORAD:New(self.name.."-SHORAD",self.name.."-SHORAD",self.SAM_Group,self.ShoradActDistance,self.ShoradTime,self.coalition,self.UseEmOnOff)
|
self.Shorad = SHORAD:New(self.name.."-SHORAD","SHORAD",self.SAM_Group,self.ShoradActDistance,self.ShoradTime,self.coalition,self.UseEmOnOff)
|
||||||
self.Shorad:SetDefenseLimits(80,95)
|
self.Shorad:SetDefenseLimits(80,95)
|
||||||
self.ShoradLink = true
|
self.ShoradLink = true
|
||||||
self.Shorad.Groupset=self.ShoradGroupSet
|
self.Shorad.Groupset=self.ShoradGroupSet
|
||||||
@@ -1851,14 +2042,36 @@ do
|
|||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
-- check detection
|
-- check detection
|
||||||
if not self.state2flag then
|
if not self.state2flag then
|
||||||
self:_Check(self.Detection,self.DLink)
|
self:_Check(self.Detection,self.DLink,self.logsamstatus)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[ check Awacs
|
local EWRAlive = self:_CheckAnyEWRAlive()
|
||||||
if self.advAwacs and not self.state2flag then
|
|
||||||
self:_Check(self.AWACS_Detection,false)
|
local function FindSAMSRTR()
|
||||||
|
for i=1,1000 do
|
||||||
|
local randomsam = self.SAM_Group:GetRandom()
|
||||||
|
if randomsam and randomsam:IsAlive() then
|
||||||
|
if randomsam:IsSAM() then return randomsam end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Switch on a random SR/TR if no EWR left over
|
||||||
|
if not EWRAlive then
|
||||||
|
local randomsam = FindSAMSRTR() -- Wrapper.Group#GROUP
|
||||||
|
if randomsam and randomsam:IsAlive() then
|
||||||
|
if self.UseEmOnOff then
|
||||||
|
randomsam:EnableEmission(true)
|
||||||
|
else
|
||||||
|
randomsam:OptionAlarmStateRed()
|
||||||
|
end
|
||||||
|
local name = randomsam:GetName()
|
||||||
|
if self.SamStateTracker[name] ~= "RED" then
|
||||||
|
self:__RedState(1,randomsam)
|
||||||
|
self.SamStateTracker[name] = "RED"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
--]]
|
|
||||||
|
|
||||||
-- relocate HQ and EWR
|
-- relocate HQ and EWR
|
||||||
if self.autorelocate then
|
if self.autorelocate then
|
||||||
@@ -1868,8 +2081,6 @@ do
|
|||||||
|
|
||||||
local halfintv = math.floor(timepassed / relointerval)
|
local halfintv = math.floor(timepassed / relointerval)
|
||||||
|
|
||||||
--self:T({timepassed=timepassed, halfintv=halfintv})
|
|
||||||
|
|
||||||
if halfintv >= 1 then
|
if halfintv >= 1 then
|
||||||
self.TimeStamp = timer.getAbsTime()
|
self.TimeStamp = timer.getAbsTime()
|
||||||
self:_Relocate()
|
self:_Relocate()
|
||||||
@@ -1902,7 +2113,7 @@ do
|
|||||||
if self.debug and self.verbose then
|
if self.debug and self.verbose then
|
||||||
self:I(self.lid .. "Status Report")
|
self:I(self.lid .. "Status Report")
|
||||||
for _name,_state in pairs(self.SamStateTracker) do
|
for _name,_state in pairs(self.SamStateTracker) do
|
||||||
self:I(string.format("Site %s\tStatus %s",_name,_state))
|
self:I(string.format("Site %s | Status %s",_name,_state))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local interval = self.detectinterval * -1
|
local interval = self.detectinterval * -1
|
||||||
@@ -1998,7 +2209,7 @@ do
|
|||||||
local Shorad = self.Shorad
|
local Shorad = self.Shorad
|
||||||
local radius = self.checkradius
|
local radius = self.checkradius
|
||||||
local ontime = self.ShoradTime
|
local ontime = self.ShoradTime
|
||||||
Shorad:WakeUpShorad(Name, radius, ontime)
|
Shorad:WakeUpShorad(Name, radius, ontime, nil, true)
|
||||||
self:__ShoradActivated(1,Name, radius, ontime)
|
self:__ShoradActivated(1,Name, radius, ontime)
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE.
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE.
|
||||||
-- Therefore, this class is considered to be deprecated and superseded by the [Functional.Fox](https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Functional.Fox.html) class, which provides the same functionality.
|
-- Therefore, this class is considered to be deprecated and superseded by the [Functional.Fox](https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Functional.Fox.html) class, which provides the same functionality.
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -3814,15 +3814,20 @@ function RAT:Status(message, forID)
|
|||||||
local N0units=group:GetInitialSize()
|
local N0units=group:GetInitialSize()
|
||||||
|
|
||||||
-- Monitor travelled distance since last check.
|
-- Monitor travelled distance since last check.
|
||||||
local Pnow=coords
|
local Dtravel=0
|
||||||
local Dtravel=Pnow:Get2DDistance(ratcraft.Pnow)
|
if coords and ratcraft.Pnow then
|
||||||
ratcraft.Pnow=Pnow
|
local Dtravel=coords:Get2DDistance(ratcraft.Pnow)
|
||||||
|
ratcraft.Pnow=coords
|
||||||
|
end
|
||||||
|
|
||||||
-- Add up the travelled distance.
|
-- Add up the travelled distance.
|
||||||
ratcraft.Distance=ratcraft.Distance+Dtravel
|
ratcraft.Distance=ratcraft.Distance+Dtravel
|
||||||
|
|
||||||
-- Distance remaining to destination.
|
-- Distance remaining to destination.
|
||||||
local Ddestination=Pnow:Get2DDistance(ratcraft.destination:GetCoordinate())
|
local Ddestination=-1
|
||||||
|
if ratcraft.Pnow then
|
||||||
|
Ddestination=ratcraft.Pnow:Get2DDistance(ratcraft.destination:GetCoordinate())
|
||||||
|
end
|
||||||
|
|
||||||
-- Status report.
|
-- Status report.
|
||||||
if (forID and spawnindex==forID) or (not forID) then
|
if (forID and spawnindex==forID) or (not forID) then
|
||||||
|
|||||||
@@ -107,6 +107,9 @@
|
|||||||
-- @field Sound.SRS#MSRSQUEUE instructsrsQ SRS queue for range instructor.
|
-- @field Sound.SRS#MSRSQUEUE instructsrsQ SRS queue for range instructor.
|
||||||
-- @field #number Coalition Coalition side for the menu, if any.
|
-- @field #number Coalition Coalition side for the menu, if any.
|
||||||
-- @field Core.Menu#MENU_MISSION menuF10root Specific user defined root F10 menu.
|
-- @field Core.Menu#MENU_MISSION menuF10root Specific user defined root F10 menu.
|
||||||
|
-- @field #number ceilingaltitude Range ceiling altitude in ft MSL. Aircraft above this altitude are not considered to be in the range. Default is 20000 ft.
|
||||||
|
-- @field #boolean ceilingenabled Range has a ceiling and is not unlimited. Default is false.
|
||||||
|
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *Don't only practice your art, but force your way into its secrets; art deserves that, for it and knowledge can raise man to the Divine.* - Ludwig van Beethoven
|
--- *Don't only practice your art, but force your way into its secrets; art deserves that, for it and knowledge can raise man to the Divine.* - Ludwig van Beethoven
|
||||||
@@ -273,6 +276,10 @@
|
|||||||
-- -- Create a range object.
|
-- -- Create a range object.
|
||||||
-- GoldwaterRange=RANGE:New("Goldwater Range")
|
-- GoldwaterRange=RANGE:New("Goldwater Range")
|
||||||
--
|
--
|
||||||
|
-- -- Set and enable the range ceiling altitude in feet MSL. If aircraft are above this altitude they are not considered to be in the range.
|
||||||
|
-- GoldwaterRange:SetRangeCeiling(20000)
|
||||||
|
-- GoldwaterRange:EnableRangeCeiling(true)
|
||||||
|
--
|
||||||
-- -- Distance between strafe target and foul line. You have to specify the names of the unit or static objects.
|
-- -- Distance between strafe target and foul line. You have to specify the names of the unit or static objects.
|
||||||
-- -- Note that this could also be done manually by simply measuring the distance between the target and the foul line in the ME.
|
-- -- Note that this could also be done manually by simply measuring the distance between the target and the foul line in the ME.
|
||||||
-- GoldwaterRange:GetFoullineDistance("GWR Strafe Pit Left 1", "GWR Foul Line Left")
|
-- GoldwaterRange:GetFoullineDistance("GWR Strafe Pit Left 1", "GWR Foul Line Left")
|
||||||
@@ -358,6 +365,8 @@ RANGE = {
|
|||||||
targetpath = nil,
|
targetpath = nil,
|
||||||
targetprefix = nil,
|
targetprefix = nil,
|
||||||
Coalition = nil,
|
Coalition = nil,
|
||||||
|
ceilingaltitude = 20000,
|
||||||
|
ceilingenabled = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Default range parameters.
|
--- Default range parameters.
|
||||||
@@ -594,7 +603,7 @@ RANGE.MenuF10Root = nil
|
|||||||
|
|
||||||
--- Range script version.
|
--- Range script version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
RANGE.version = "2.8.0"
|
RANGE.version = "2.8.1"
|
||||||
|
|
||||||
-- TODO list:
|
-- TODO list:
|
||||||
-- TODO: Verbosity level for messages.
|
-- TODO: Verbosity level for messages.
|
||||||
@@ -1085,6 +1094,37 @@ function RANGE:SetRangeZone( zone )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set range ceiling altitude in feet MSL.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #number altitude (optional) Ceiling altitude of the range in ft MSL. Default 20000ft MSL
|
||||||
|
-- @return #RANGE self
|
||||||
|
function RANGE:SetRangeCeiling( altitude )
|
||||||
|
self:T(self.lid.."SetRangeCeiling")
|
||||||
|
if altitude and type(altitude) == "number" then
|
||||||
|
self.ceilingaltitude=altitude
|
||||||
|
else
|
||||||
|
self:E(self.lid.."Altitude either not provided or is not a number, using default setting (20000).")
|
||||||
|
self.ceilingaltitude=20000
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Enable range ceiling. Aircraft must be below the ceiling altitude to be considered in the range zone.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #boolean enabled True if you would like to enable the ceiling check. If no value give, will Default to false.
|
||||||
|
-- @return #RANGE self
|
||||||
|
function RANGE:EnableRangeCeiling( enabled )
|
||||||
|
self:T(self.lid.."EnableRangeCeiling")
|
||||||
|
if enabled and type(enabled) == "boolean" then
|
||||||
|
self.ceilingenabled=enabled
|
||||||
|
else
|
||||||
|
self:E(self.lid.."Enabled either not provide or is not a boolean, using default setting (false).")
|
||||||
|
self.ceilingenabled=false
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set smoke color for marking bomb targets. By default bomb targets are marked by red smoke.
|
--- Set smoke color for marking bomb targets. By default bomb targets are marked by red smoke.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default `SMOKECOLOR.Red`.
|
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default `SMOKECOLOR.Red`.
|
||||||
@@ -1893,7 +1933,7 @@ function RANGE:OnEventHit( EventData )
|
|||||||
local _currentTarget = self.strafeStatus[_unitID] --#RANGE.StrafeStatus
|
local _currentTarget = self.strafeStatus[_unitID] --#RANGE.StrafeStatus
|
||||||
|
|
||||||
-- Player has rolled in on a strafing target.
|
-- Player has rolled in on a strafing target.
|
||||||
if _currentTarget and target:IsAlive() then
|
if _currentTarget and target and target:IsAlive() then
|
||||||
|
|
||||||
local playerPos = _unit:GetCoordinate()
|
local playerPos = _unit:GetCoordinate()
|
||||||
local targetPos = target:GetCoordinate()
|
local targetPos = target:GetCoordinate()
|
||||||
@@ -1992,10 +2032,10 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
|
|||||||
|
|
||||||
-- Smoke impact point of bomb.
|
-- Smoke impact point of bomb.
|
||||||
if playerData and playerData.smokebombimpact and insidezone then
|
if playerData and playerData.smokebombimpact and insidezone then
|
||||||
if playerData and playerData.delaysmoke then
|
if playerData.delaysmoke then
|
||||||
timer.scheduleFunction( self._DelayedSmoke, { coord = impactcoord, color = playerData.smokecolor }, timer.getTime() + self.TdelaySmoke )
|
impactcoord:Smoke(playerData.smokecolor, 30, self.TdelaySmoke)
|
||||||
else
|
else
|
||||||
impactcoord:Smoke( playerData.smokecolor )
|
impactcoord:Smoke(playerData.smokecolor, 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2062,7 +2102,12 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
|
|||||||
result.attackHdg = attackHdg
|
result.attackHdg = attackHdg
|
||||||
result.attackVel = attackVel
|
result.attackVel = attackVel
|
||||||
result.attackAlt = attackAlt
|
result.attackAlt = attackAlt
|
||||||
result.date=os and os.date() or "n/a"
|
if os and os.date then
|
||||||
|
result.date=os.date()
|
||||||
|
else
|
||||||
|
self:E(self.lid.."os or os.date() not available")
|
||||||
|
result.date = "n/a"
|
||||||
|
end
|
||||||
|
|
||||||
-- Add to table.
|
-- Add to table.
|
||||||
table.insert( _results, result )
|
table.insert( _results, result )
|
||||||
@@ -2595,13 +2640,6 @@ end
|
|||||||
-- Display Messages
|
-- Display Messages
|
||||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Start smoking a coordinate with a delay.
|
|
||||||
-- @param #table _args Argements passed.
|
|
||||||
function RANGE._DelayedSmoke( _args )
|
|
||||||
_args.coord:Smoke(_args.color)
|
|
||||||
--trigger.action.smoke( _args.coord:GetVec3(), _args.color )
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Display top 10 stafing results of a specific player.
|
--- Display top 10 stafing results of a specific player.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #string _unitName Name of the player unit.
|
-- @param #string _unitName Name of the player unit.
|
||||||
@@ -2987,7 +3025,7 @@ function RANGE:_DisplayBombTargets( _unitname )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_DisplayMessageToGroup( _unit, _text, 120, true, true, _multiplayer )
|
self:_DisplayMessageToGroup( _unit, _text, 150, true, true, _multiplayer )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3112,7 +3150,10 @@ function RANGE:_CheckPlayers()
|
|||||||
|
|
||||||
if unit and unit:IsAlive() then
|
if unit and unit:IsAlive() then
|
||||||
|
|
||||||
if unit:IsInZone( self.rangezone ) then
|
local unitalt = unit:GetAltitude(false)
|
||||||
|
local unitaltinfeet = UTILS.MetersToFeet(unitalt)
|
||||||
|
|
||||||
|
if unit:IsInZone(self.rangezone) and (not self.ceilingenabled or unitaltinfeet < self.ceilingaltitude) then
|
||||||
|
|
||||||
------------------------------
|
------------------------------
|
||||||
-- Player INSIDE Range Zone --
|
-- Player INSIDE Range Zone --
|
||||||
@@ -3453,10 +3494,10 @@ function RANGE:_AddF10Commands( _unitName )
|
|||||||
-- Range menu
|
-- Range menu
|
||||||
local _rangePath = MENU_GROUP:New( group, self.rangename, _rootMenu )
|
local _rangePath = MENU_GROUP:New( group, self.rangename, _rootMenu )
|
||||||
|
|
||||||
local _statsPath = MENU_GROUP:New( group, "Statistics", _rangePath )
|
|
||||||
local _markPath = MENU_GROUP:New( group, "Mark Targets", _rangePath )
|
|
||||||
local _settingsPath = MENU_GROUP:New( group, "My Settings", _rangePath )
|
|
||||||
local _infoPath = MENU_GROUP:New( group, "Range Info", _rangePath )
|
local _infoPath = MENU_GROUP:New( group, "Range Info", _rangePath )
|
||||||
|
local _markPath = MENU_GROUP:New( group, "Mark Targets", _rangePath )
|
||||||
|
local _statsPath = MENU_GROUP:New( group, "Statistics", _rangePath )
|
||||||
|
local _settingsPath = MENU_GROUP:New( group, "My Settings", _rangePath )
|
||||||
|
|
||||||
-- F10/On the Range/<Range Name>/My Settings/
|
-- F10/On the Range/<Range Name>/My Settings/
|
||||||
local _mysmokePath = MENU_GROUP:New( group, "Smoke Color", _settingsPath )
|
local _mysmokePath = MENU_GROUP:New( group, "Smoke Color", _settingsPath )
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
--
|
--
|
||||||
-- ### Authors: **applevangelist**, **FlightControl**
|
-- ### Authors: **applevangelist**, **FlightControl**
|
||||||
--
|
--
|
||||||
-- Last Update: Dec 2023
|
-- Last Update: Dec 2024
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -28,6 +28,16 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
-- @type SEAD
|
-- @type SEAD
|
||||||
|
-- @field #string ClassName The Class Name.
|
||||||
|
-- @field #table TargetSkill Table of target skills.
|
||||||
|
-- @field #table SEADGroupPrefixes Table of SEAD prefixes.
|
||||||
|
-- @field #table SuppressedGroups Table of currently suppressed groups.
|
||||||
|
-- @field #number EngagementRange Engagement Range.
|
||||||
|
-- @field #number Padding Padding in seconds.
|
||||||
|
-- @field #function CallBack Callback function for suppression plans.
|
||||||
|
-- @field #boolean UseCallBack Switch for callback function to be used.
|
||||||
|
-- @field #boolean debug Debug switch.
|
||||||
|
-- @field #boolen WeaponTrack Track switch, if true track weapon speed for 30 secs.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- Make SAM sites execute evasive and defensive behaviour when being fired upon.
|
--- Make SAM sites execute evasive and defensive behaviour when being fired upon.
|
||||||
@@ -56,10 +66,11 @@ SEAD = {
|
|||||||
SEADGroupPrefixes = {},
|
SEADGroupPrefixes = {},
|
||||||
SuppressedGroups = {},
|
SuppressedGroups = {},
|
||||||
EngagementRange = 75, -- default 75% engagement range Feature Request #1355
|
EngagementRange = 75, -- default 75% engagement range Feature Request #1355
|
||||||
Padding = 10,
|
Padding = 15,
|
||||||
CallBack = nil,
|
CallBack = nil,
|
||||||
UseCallBack = false,
|
UseCallBack = false,
|
||||||
debug = false,
|
debug = false,
|
||||||
|
WeaponTrack = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Missile enumerators
|
--- Missile enumerators
|
||||||
@@ -69,6 +80,7 @@ SEAD = {
|
|||||||
["AGM_122"] = "AGM_122",
|
["AGM_122"] = "AGM_122",
|
||||||
["AGM_84"] = "AGM_84",
|
["AGM_84"] = "AGM_84",
|
||||||
["AGM_45"] = "AGM_45",
|
["AGM_45"] = "AGM_45",
|
||||||
|
["AGM_65"] = "AGM_65",
|
||||||
["ALARM"] = "ALARM",
|
["ALARM"] = "ALARM",
|
||||||
["LD-10"] = "LD-10",
|
["LD-10"] = "LD-10",
|
||||||
["X_58"] = "X_58",
|
["X_58"] = "X_58",
|
||||||
@@ -88,6 +100,7 @@ SEAD = {
|
|||||||
-- km and mach
|
-- km and mach
|
||||||
["AGM_88"] = { 150, 3},
|
["AGM_88"] = { 150, 3},
|
||||||
["AGM_45"] = { 12, 2},
|
["AGM_45"] = { 12, 2},
|
||||||
|
["AGM_65"] = { 16, 0.9},
|
||||||
["AGM_122"] = { 16.5, 2.3},
|
["AGM_122"] = { 16.5, 2.3},
|
||||||
["AGM_84"] = { 280, 0.8},
|
["AGM_84"] = { 280, 0.8},
|
||||||
["ALARM"] = { 45, 2},
|
["ALARM"] = { 45, 2},
|
||||||
@@ -144,7 +157,7 @@ function SEAD:New( SEADGroupPrefixes, Padding )
|
|||||||
self:AddTransition("*", "ManageEvasion", "*")
|
self:AddTransition("*", "ManageEvasion", "*")
|
||||||
self:AddTransition("*", "CalculateHitZone", "*")
|
self:AddTransition("*", "CalculateHitZone", "*")
|
||||||
|
|
||||||
self:I("*** SEAD - Started Version 0.4.6")
|
self:I("*** SEAD - Started Version 0.4.9")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -371,7 +384,7 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
|
|||||||
reach = wpndata[1] * 1.1
|
reach = wpndata[1] * 1.1
|
||||||
local mach = wpndata[2]
|
local mach = wpndata[2]
|
||||||
wpnspeed = math.floor(mach * 340.29)
|
wpnspeed = math.floor(mach * 340.29)
|
||||||
if Weapon then
|
if Weapon and Weapon:GetSpeed() > 0 then
|
||||||
wpnspeed = Weapon:GetSpeed()
|
wpnspeed = Weapon:GetSpeed()
|
||||||
self:T(string.format("*** SEAD - Weapon Speed from WEAPON: %f m/s",wpnspeed))
|
self:T(string.format("*** SEAD - Weapon Speed from WEAPON: %f m/s",wpnspeed))
|
||||||
end
|
end
|
||||||
@@ -452,29 +465,38 @@ end
|
|||||||
-- @return #SEAD self
|
-- @return #SEAD self
|
||||||
function SEAD:HandleEventShot( EventData )
|
function SEAD:HandleEventShot( EventData )
|
||||||
self:T( { EventData.id } )
|
self:T( { EventData.id } )
|
||||||
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
|
|
||||||
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
|
|
||||||
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
|
|
||||||
local SEADUnit = EventData.IniDCSUnit
|
|
||||||
local SEADUnitName = EventData.IniDCSUnitName
|
|
||||||
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
|
||||||
local SEADWeaponName = EventData.WeaponName -- return weapon type
|
|
||||||
|
|
||||||
local WeaponWrapper = WEAPON:New(EventData.Weapon)
|
|
||||||
--local SEADWeaponSpeed = WeaponWrapper:GetSpeed() -- mps
|
|
||||||
|
|
||||||
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
||||||
--self:T({ SEADWeapon })
|
local SEADWeaponName = EventData.WeaponName or "None" -- return weapon type
|
||||||
|
|
||||||
if self:_CheckHarms(SEADWeaponName) then
|
if self:_CheckHarms(SEADWeaponName) then
|
||||||
|
--UTILS.PrintTableToLog(EventData)
|
||||||
|
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
if not SEADPlane then return self end -- case IniUnit is empty
|
||||||
|
|
||||||
|
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
|
||||||
|
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
local SEADUnit = EventData.IniDCSUnit
|
||||||
|
local SEADUnitName = EventData.IniDCSUnitName
|
||||||
|
|
||||||
|
local WeaponWrapper = WEAPON:New(EventData.Weapon) -- Wrapper.Weapon#WEAPON
|
||||||
|
|
||||||
|
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
||||||
|
|
||||||
self:T( '*** SEAD - Weapon Match' )
|
self:T( '*** SEAD - Weapon Match' )
|
||||||
|
if self.WeaponTrack == true then
|
||||||
|
WeaponWrapper:SetFuncTrack(function(weapon) env.info(string.format("*** Weapon Speed: %d m/s",weapon:GetSpeed() or -1)) end)
|
||||||
|
WeaponWrapper:StartTrack(0.1)
|
||||||
|
WeaponWrapper:StopTrack(30)
|
||||||
|
end
|
||||||
local _targetskill = "Random"
|
local _targetskill = "Random"
|
||||||
local _targetgroupname = "none"
|
local _targetgroupname = "none"
|
||||||
local _target = EventData.Weapon:getTarget() -- Identify target
|
local _target = EventData.Weapon:getTarget() -- Identify target
|
||||||
if not _target or self.debug then -- AGM-88 or 154 w/o target data
|
if not _target or self.debug then -- AGM-88 or 154 w/o target data
|
||||||
self:E("***** SEAD - No target data for " .. (SEADWeaponName or "None"))
|
self:E("***** SEAD - No target data for " .. (SEADWeaponName or "None"))
|
||||||
if string.find(SEADWeaponName,"AGM_88",1,true) or string.find(SEADWeaponName,"AGM_154",1,true) then
|
if string.find(SEADWeaponName,"AGM_88",1,true) or string.find(SEADWeaponName,"AGM_154",1,true) then
|
||||||
self:I("**** Tracking AGM-88/154 with no target data.")
|
self:T("**** Tracking AGM-88/154 with no target data.")
|
||||||
local pos0 = SEADPlane:GetCoordinate()
|
local pos0 = SEADPlane:GetCoordinate()
|
||||||
local fheight = SEADPlane:GetHeight()
|
local fheight = SEADPlane:GetHeight()
|
||||||
self:__CalculateHitZone(20,SEADWeapon,pos0,fheight,SEADGroup,SEADWeaponName)
|
self:__CalculateHitZone(20,SEADWeapon,pos0,fheight,SEADGroup,SEADWeaponName)
|
||||||
@@ -520,7 +542,7 @@ function SEAD:HandleEventShot( EventData )
|
|||||||
end
|
end
|
||||||
if SEADGroupFound == true then -- yes we are being attacked
|
if SEADGroupFound == true then -- yes we are being attacked
|
||||||
if string.find(SEADWeaponName,"ADM_141",1,true) then
|
if string.find(SEADWeaponName,"ADM_141",1,true) then
|
||||||
self:__ManageEvasion(2,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
|
self:__ManageEvasion(2,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,2,WeaponWrapper)
|
||||||
else
|
else
|
||||||
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
|
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
-- @image Functional.Shorad.jpg
|
-- @image Functional.Shorad.jpg
|
||||||
--
|
--
|
||||||
-- Date: Nov 2021
|
-- Date: Nov 2021
|
||||||
-- Last Update: Nov 2023
|
-- Last Update: Jan 2025
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **SHORAD** class, extends Core.Base#BASE
|
--- **SHORAD** class, extends Core.Base#BASE
|
||||||
@@ -113,7 +113,7 @@ SHORAD = {
|
|||||||
SkateNumber = 3,
|
SkateNumber = 3,
|
||||||
SkateZones = nil,
|
SkateZones = nil,
|
||||||
minscootdist = 100,
|
minscootdist = 100,
|
||||||
minscootdist = 3000,
|
maxscootdist = 3000,
|
||||||
scootrandomcoord = false,
|
scootrandomcoord = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,7 +443,9 @@ do
|
|||||||
for _,_groups in pairs (shoradset) do
|
for _,_groups in pairs (shoradset) do
|
||||||
local groupname = _groups:GetName()
|
local groupname = _groups:GetName()
|
||||||
if string.find(groupname, tgtgrp, 1, true) then
|
if string.find(groupname, tgtgrp, 1, true) then
|
||||||
returnname = true
|
if _groups:IsSAM() then
|
||||||
|
returnname = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return returnname
|
return returnname
|
||||||
@@ -470,6 +472,7 @@ do
|
|||||||
-- @param #number Radius Radius of the #ZONE
|
-- @param #number Radius Radius of the #ZONE
|
||||||
-- @param #number ActiveTimer Number of seconds to stay active
|
-- @param #number ActiveTimer Number of seconds to stay active
|
||||||
-- @param #number TargetCat (optional) Category, i.e. Object.Category.UNIT or Object.Category.STATIC
|
-- @param #number TargetCat (optional) Category, i.e. Object.Category.UNIT or Object.Category.STATIC
|
||||||
|
-- @param #boolean ShotAt If true, function is called after a shot
|
||||||
-- @return #SHORAD self
|
-- @return #SHORAD self
|
||||||
-- @usage Use this function to integrate with other systems, example
|
-- @usage Use this function to integrate with other systems, example
|
||||||
--
|
--
|
||||||
@@ -479,7 +482,7 @@ do
|
|||||||
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
||||||
-- mymantis:AddShorad(myshorad,720)
|
-- mymantis:AddShorad(myshorad,720)
|
||||||
-- mymantis:Start()
|
-- mymantis:Start()
|
||||||
function SHORAD:onafterWakeUpShorad(From, Event, To, TargetGroup, Radius, ActiveTimer, TargetCat)
|
function SHORAD:onafterWakeUpShorad(From, Event, To, TargetGroup, Radius, ActiveTimer, TargetCat, ShotAt)
|
||||||
self:T(self.lid .. " WakeUpShorad")
|
self:T(self.lid .. " WakeUpShorad")
|
||||||
self:T({TargetGroup, Radius, ActiveTimer, TargetCat})
|
self:T({TargetGroup, Radius, ActiveTimer, TargetCat})
|
||||||
local targetcat = TargetCat or Object.Category.UNIT
|
local targetcat = TargetCat or Object.Category.UNIT
|
||||||
@@ -521,7 +524,27 @@ do
|
|||||||
-- go through set and find the one(s) to activate
|
-- go through set and find the one(s) to activate
|
||||||
local TDiff = 4
|
local TDiff = 4
|
||||||
for _,_group in pairs (shoradset) do
|
for _,_group in pairs (shoradset) do
|
||||||
if _group:IsAnyInZone(targetzone) then
|
|
||||||
|
local groupname = _group:GetName()
|
||||||
|
|
||||||
|
if groupname == TargetGroup and ShotAt==true then
|
||||||
|
-- Shot at a SHORAD group
|
||||||
|
if self.UseEmOnOff then
|
||||||
|
_group:EnableEmission(false)
|
||||||
|
end
|
||||||
|
_group:OptionAlarmStateGreen()
|
||||||
|
self.ActiveGroups[groupname] = nil
|
||||||
|
local text = string.format("Shot at SHORAD %s! Evading!", _group:GetName())
|
||||||
|
self:T(text)
|
||||||
|
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||||
|
|
||||||
|
--Shoot and Scoot
|
||||||
|
if self.shootandscoot then
|
||||||
|
self:__ShootAndScoot(1,_group)
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif _group:IsAnyInZone(targetzone) or groupname == TargetGroup then
|
||||||
|
-- shot at a group we protect
|
||||||
local text = string.format("Waking up SHORAD %s", _group:GetName())
|
local text = string.format("Waking up SHORAD %s", _group:GetName())
|
||||||
self:T(text)
|
self:T(text)
|
||||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||||
@@ -529,7 +552,6 @@ do
|
|||||||
_group:EnableEmission(true)
|
_group:EnableEmission(true)
|
||||||
end
|
end
|
||||||
_group:OptionAlarmStateRed()
|
_group:OptionAlarmStateRed()
|
||||||
local groupname = _group:GetName()
|
|
||||||
if self.ActiveGroups[groupname] == nil then -- no timer yet for this group
|
if self.ActiveGroups[groupname] == nil then -- no timer yet for this group
|
||||||
self.ActiveGroups[groupname] = { Timing = ActiveTimer }
|
self.ActiveGroups[groupname] = { Timing = ActiveTimer }
|
||||||
local endtime = timer.getTime() + (ActiveTimer * math.random(75,100) / 100 ) -- randomize wakeup a bit
|
local endtime = timer.getTime() + (ActiveTimer * math.random(75,100) / 100 ) -- randomize wakeup a bit
|
||||||
@@ -607,7 +629,7 @@ do
|
|||||||
_targetgroupname = tgtgrp:GetName() -- group name
|
_targetgroupname = tgtgrp:GetName() -- group name
|
||||||
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||||
self:T("*** Found Target = ".. _targetgroupname)
|
self:T("*** Found Target = ".. _targetgroupname)
|
||||||
self:WakeUpShorad(_targetgroupname, self.Radius, self.ActiveTimer, Object.Category.UNIT)
|
self:WakeUpShorad(_targetgroupname, self.Radius, self.ActiveTimer, Object.Category.UNIT,true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -736,7 +758,7 @@ do
|
|||||||
-- if being shot at, find closest SHORADs to activate
|
-- if being shot at, find closest SHORADs to activate
|
||||||
if shotatsams or shotatus then
|
if shotatsams or shotatus then
|
||||||
self:T({shotatsams=shotatsams,shotatus=shotatus})
|
self:T({shotatsams=shotatsams,shotatus=shotatus})
|
||||||
self:WakeUpShorad(targetgroupname, self.Radius, self.ActiveTimer, targetcat)
|
self:WakeUpShorad(targetgroupname, self.Radius, self.ActiveTimer, targetcat, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3153,7 +3153,7 @@ end
|
|||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @return Core.Point#COORDINATE The coordinate of the warehouse.
|
-- @return Core.Point#COORDINATE The coordinate of the warehouse.
|
||||||
function WAREHOUSE:GetCoordinate()
|
function WAREHOUSE:GetCoordinate()
|
||||||
return self.warehouse:GetCoordinate()
|
return self.warehouse:GetCoord()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get 3D vector of warehouse static.
|
--- Get 3D vector of warehouse static.
|
||||||
@@ -6047,7 +6047,7 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
|
|||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
if #parking<#template.units and not airstart then
|
if parking and #parking<#template.units and not airstart then
|
||||||
local text=string.format("ERROR: Not enough parking! Free parking = %d < %d aircraft to be spawned.", #parking, #template.units)
|
local text=string.format("ERROR: Not enough parking! Free parking = %d < %d aircraft to be spawned.", #parking, #template.units)
|
||||||
self:_DebugMessage(text)
|
self:_DebugMessage(text)
|
||||||
return nil
|
return nil
|
||||||
@@ -6089,7 +6089,7 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
|
|||||||
terminal=parking[i].TerminalID
|
terminal=parking[i].TerminalID
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.Debug then
|
if self.Debug and terminal then
|
||||||
local text=string.format("Spawnplace unit %s terminal %d.", unit.name, terminal)
|
local text=string.format("Spawnplace unit %s terminal %d.", unit.name, terminal)
|
||||||
coord:MarkToAll(text)
|
coord:MarkToAll(text)
|
||||||
env.info(text)
|
env.info(text)
|
||||||
@@ -6893,7 +6893,7 @@ function WAREHOUSE:_CheckConquered()
|
|||||||
for _,_unit in pairs(units) do
|
for _,_unit in pairs(units) do
|
||||||
local unit=_unit --Wrapper.Unit#UNIT
|
local unit=_unit --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
local distance=coord:Get2DDistance(unit:GetCoordinate())
|
local distance=coord:Get2DDistance(unit:GetCoord())
|
||||||
|
|
||||||
-- Filter only alive groud units. Also check distance again, because the scan routine might give some larger distances.
|
-- Filter only alive groud units. Also check distance again, because the scan routine might give some larger distances.
|
||||||
if unit:IsGround() and unit:IsAlive() and distance <= radius then
|
if unit:IsGround() and unit:IsAlive() and distance <= radius then
|
||||||
@@ -8122,9 +8122,11 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets)
|
|||||||
-- Debug output for occupied spots.
|
-- Debug output for occupied spots.
|
||||||
if self.Debug then
|
if self.Debug then
|
||||||
local coord=problem.coord --Core.Point#COORDINATE
|
local coord=problem.coord --Core.Point#COORDINATE
|
||||||
local text=string.format("Obstacle %s [type=%s] blocking spot=%d! Size=%.1f m and distance=%.1f m.", problem.name, problem.type, _termid, problem.size, problem.dist)
|
if coord then
|
||||||
self:I(self.lid..text)
|
local text=string.format("Obstacle %s [type=%s] blocking spot=%d! Size=%.1f m and distance=%.1f m.", problem.name, problem.type, _termid, problem.size, problem.dist)
|
||||||
coord:MarkToAll(string.format(text))
|
self:I(self.lid..text)
|
||||||
|
coord:MarkToAll(text)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
self:T(self.lid..string.format("Parking spot %d is occupied or not big enough!", _termid))
|
self:T(self.lid..string.format("Parking spot %d is occupied or not big enough!", _termid))
|
||||||
end
|
end
|
||||||
@@ -8433,12 +8435,14 @@ function WAREHOUSE:_GetAttribute(group)
|
|||||||
local attribute=WAREHOUSE.Attribute.OTHER_UNKNOWN --#WAREHOUSE.Attribute
|
local attribute=WAREHOUSE.Attribute.OTHER_UNKNOWN --#WAREHOUSE.Attribute
|
||||||
|
|
||||||
if group then
|
if group then
|
||||||
|
|
||||||
|
local groupCat=group:GetCategory()
|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
--- Air ---
|
--- Air ---
|
||||||
-----------
|
-----------
|
||||||
-- Planes
|
-- Planes
|
||||||
local transportplane=group:HasAttribute("Transports") and group:HasAttribute("Planes")
|
local transportplane=group:HasAttribute("Transports") and group:HasAttribute("Planes") and groupCat==Group.Category.AIRPLANE
|
||||||
local awacs=group:HasAttribute("AWACS")
|
local awacs=group:HasAttribute("AWACS")
|
||||||
local fighter=group:HasAttribute("Fighters") or group:HasAttribute("Interceptors") or group:HasAttribute("Multirole fighters") or (group:HasAttribute("Bombers") and not group:HasAttribute("Strategic bombers"))
|
local fighter=group:HasAttribute("Fighters") or group:HasAttribute("Interceptors") or group:HasAttribute("Multirole fighters") or (group:HasAttribute("Bombers") and not group:HasAttribute("Strategic bombers"))
|
||||||
local bomber=group:HasAttribute("Strategic bombers")
|
local bomber=group:HasAttribute("Strategic bombers")
|
||||||
@@ -8593,7 +8597,6 @@ end
|
|||||||
-- @param #WAREHOUSE.Queueitem qitem Item of queue to be removed.
|
-- @param #WAREHOUSE.Queueitem qitem Item of queue to be removed.
|
||||||
-- @param #table queue The queue from which the item should be deleted.
|
-- @param #table queue The queue from which the item should be deleted.
|
||||||
function WAREHOUSE:_DeleteQueueItem(qitem, queue)
|
function WAREHOUSE:_DeleteQueueItem(qitem, queue)
|
||||||
self:F({qitem=qitem, queue=queue})
|
|
||||||
|
|
||||||
for i=1,#queue do
|
for i=1,#queue do
|
||||||
local _item=queue[i] --#WAREHOUSE.Queueitem
|
local _item=queue[i] --#WAREHOUSE.Queueitem
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ _SCHEDULEDISPATCHER = SCHEDULEDISPATCHER:New() -- Core.ScheduleDispatcher#SCHEDU
|
|||||||
_DATABASE = DATABASE:New() -- Core.Database#DATABASE
|
_DATABASE = DATABASE:New() -- Core.Database#DATABASE
|
||||||
|
|
||||||
--- Settings
|
--- Settings
|
||||||
_SETTINGS = SETTINGS:Set()
|
_SETTINGS = SETTINGS:Set() -- Core.Settings#SETTINGS
|
||||||
_SETTINGS:SetPlayerMenuOn()
|
_SETTINGS:SetPlayerMenuOn()
|
||||||
|
|
||||||
--- Register cargos.
|
--- Register cargos.
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Enums.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Enums.lua' )
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Utils.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Utils.lua' )
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Profiler.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Profiler.lua' )
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Templates.lua' )
|
|
||||||
--__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/STTS.lua' )
|
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/FiFo.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/FiFo.lua' )
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Socket.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Utilities/Socket.lua' )
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,6 @@ __Moose.Include( 'Ops\\Operation.lua' )
|
|||||||
__Moose.Include( 'Ops\\FlightControl.lua' )
|
__Moose.Include( 'Ops\\FlightControl.lua' )
|
||||||
__Moose.Include( 'Ops\\PlayerRecce.lua' )
|
__Moose.Include( 'Ops\\PlayerRecce.lua' )
|
||||||
__Moose.Include( 'Ops\\EasyGCICAP.lua' )
|
__Moose.Include( 'Ops\\EasyGCICAP.lua' )
|
||||||
__Moose.Include( 'Ops\\EasyA2G.lua' )
|
|
||||||
|
|
||||||
__Moose.Include( 'AI\\AI_Balancer.lua' )
|
__Moose.Include( 'AI\\AI_Balancer.lua' )
|
||||||
__Moose.Include( 'AI\\AI_Air.lua' )
|
__Moose.Include( 'AI\\AI_Air.lua' )
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
-- * Option to present information in imperial or metric units
|
-- * Option to present information in imperial or metric units
|
||||||
-- * Runway length and airfield elevation (optional)
|
-- * Runway length and airfield elevation (optional)
|
||||||
-- * Frequencies/channels of nav aids (ILS, VOR, NDB, TACAN, PRMG, RSBN) (optional)
|
-- * Frequencies/channels of nav aids (ILS, VOR, NDB, TACAN, PRMG, RSBN) (optional)
|
||||||
-- * SRS Simple-Text-To-Speech (STTS) integration (no sound files necessary)
|
-- * SRS Simple-Text-To-Speech (MSRS) integration (no sound files necessary)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -291,7 +291,7 @@
|
|||||||
-- ## Nevada: Nellis AFB
|
-- ## Nevada: Nellis AFB
|
||||||
--
|
--
|
||||||
-- -- ATIS Nellis AFB on 270.10 MHz AM.
|
-- -- ATIS Nellis AFB on 270.10 MHz AM.
|
||||||
-- atisNellis=ATIS:New(AIRBASE.Nevada.Nellis_AFB, 270.1)
|
-- atisNellis=ATIS:New(AIRBASE.Nevada.Nellis, 270.1)
|
||||||
-- atisNellis:SetRadioRelayUnitName("Radio Relay Nellis")
|
-- atisNellis:SetRadioRelayUnitName("Radio Relay Nellis")
|
||||||
-- atisNellis:SetActiveRunway("21L")
|
-- atisNellis:SetActiveRunway("21L")
|
||||||
-- atisNellis:SetTowerFrequencies({327.000, 132.550})
|
-- atisNellis:SetTowerFrequencies({327.000, 132.550})
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
-- ## Persian Gulf: Abu Dhabi International Airport
|
-- ## Persian Gulf: Abu Dhabi International Airport
|
||||||
--
|
--
|
||||||
-- -- ATIS Abu Dhabi International on 125.1 MHz AM.
|
-- -- ATIS Abu Dhabi International on 125.1 MHz AM.
|
||||||
-- atisAbuDhabi=ATIS:New(AIRBASE.PersianGulf.Abu_Dhabi_International_Airport, 125.1)
|
-- atisAbuDhabi=ATIS:New(AIRBASE.PersianGulf.Abu_Dhabi_Intl, 125.1)
|
||||||
-- atisAbuDhabi:SetRadioRelayUnitName("Radio Relay Abu Dhabi International Airport")
|
-- atisAbuDhabi:SetRadioRelayUnitName("Radio Relay Abu Dhabi International Airport")
|
||||||
-- atisAbuDhabi:SetMetricUnits()
|
-- atisAbuDhabi:SetMetricUnits()
|
||||||
-- atisAbuDhabi:SetActiveRunway("L")
|
-- atisAbuDhabi:SetActiveRunway("L")
|
||||||
@@ -498,6 +498,10 @@ ATIS.Alphabet = {
|
|||||||
-- @field #number Syria +5° (East).
|
-- @field #number Syria +5° (East).
|
||||||
-- @field #number MarianaIslands +2° (East).
|
-- @field #number MarianaIslands +2° (East).
|
||||||
-- @field #number SinaiMap +5° (East).
|
-- @field #number SinaiMap +5° (East).
|
||||||
|
-- @field #number Kola +15° (East).
|
||||||
|
-- @field #number Afghanistan +3° (East).
|
||||||
|
-- @field #number Iraq +4.4° (East).
|
||||||
|
-- @field #number GermanyCW +0.1° (East).
|
||||||
ATIS.RunwayM2T = {
|
ATIS.RunwayM2T = {
|
||||||
Caucasus = 0,
|
Caucasus = 0,
|
||||||
Nevada = 12,
|
Nevada = 12,
|
||||||
@@ -508,6 +512,10 @@ ATIS.RunwayM2T = {
|
|||||||
MarianaIslands = 2,
|
MarianaIslands = 2,
|
||||||
Falklands = 12,
|
Falklands = 12,
|
||||||
SinaiMap = 5,
|
SinaiMap = 5,
|
||||||
|
Kola = 15,
|
||||||
|
Afghanistan = 3,
|
||||||
|
Iraq=4.4,
|
||||||
|
GermanyCW=0.1,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Whether ICAO phraseology is used for ATIS broadcasts.
|
--- Whether ICAO phraseology is used for ATIS broadcasts.
|
||||||
@@ -521,6 +529,10 @@ ATIS.RunwayM2T = {
|
|||||||
-- @field #boolean MarianaIslands true.
|
-- @field #boolean MarianaIslands true.
|
||||||
-- @field #boolean Falklands true.
|
-- @field #boolean Falklands true.
|
||||||
-- @field #boolean SinaiMap true.
|
-- @field #boolean SinaiMap true.
|
||||||
|
-- @field #boolean Kola true.
|
||||||
|
-- @field #boolean Afghanistan true.
|
||||||
|
-- @field #boolean Iraq true.
|
||||||
|
-- @field #boolean GermanyCW true.
|
||||||
ATIS.ICAOPhraseology = {
|
ATIS.ICAOPhraseology = {
|
||||||
Caucasus = true,
|
Caucasus = true,
|
||||||
Nevada = false,
|
Nevada = false,
|
||||||
@@ -531,6 +543,10 @@ ATIS.ICAOPhraseology = {
|
|||||||
MarianaIslands = true,
|
MarianaIslands = true,
|
||||||
Falklands = true,
|
Falklands = true,
|
||||||
SinaiMap = true,
|
SinaiMap = true,
|
||||||
|
Kola = true,
|
||||||
|
Afghanistan = true,
|
||||||
|
Iraq = true,
|
||||||
|
GermanyCW = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Nav point data.
|
--- Nav point data.
|
||||||
@@ -619,83 +635,83 @@ ATIS.ICAOPhraseology = {
|
|||||||
-- @field #ATIS.Soundfile TACANChannel
|
-- @field #ATIS.Soundfile TACANChannel
|
||||||
-- @field #ATIS.Soundfile VORFrequency
|
-- @field #ATIS.Soundfile VORFrequency
|
||||||
ATIS.Sound = {
|
ATIS.Sound = {
|
||||||
ActiveRunway = { filename = "ActiveRunway.ogg", duration = 0.99 },
|
ActiveRunway = { filename = "ActiveRunway.ogg", duration = 0.85 },
|
||||||
ActiveRunwayDeparture = { filename = "ActiveRunwayDeparture.ogg", duration = 0.99 },
|
ActiveRunwayDeparture = { filename = "ActiveRunwayDeparture.ogg", duration = 1.50 },
|
||||||
ActiveRunwayArrival = { filename = "ActiveRunwayArrival.ogg", duration = 0.99 },
|
ActiveRunwayArrival = { filename = "ActiveRunwayArrival.ogg", duration = 1.38 },
|
||||||
AdviceOnInitial = { filename = "AdviceOnInitial.ogg", duration = 3.00 },
|
AdviceOnInitial = { filename = "AdviceOnInitial.ogg", duration = 2.98 },
|
||||||
Airport = { filename = "Airport.ogg", duration = 0.66 },
|
Airport = { filename = "Airport.ogg", duration = 0.55 },
|
||||||
Altimeter = { filename = "Altimeter.ogg", duration = 0.68 },
|
Altimeter = { filename = "Altimeter.ogg", duration = 0.91 },
|
||||||
At = { filename = "At.ogg", duration = 0.41 },
|
At = { filename = "At.ogg", duration = 0.32 },
|
||||||
CloudBase = { filename = "CloudBase.ogg", duration = 0.82 },
|
CloudBase = { filename = "CloudBase.ogg", duration = 0.69 },
|
||||||
CloudCeiling = { filename = "CloudCeiling.ogg", duration = 0.61 },
|
CloudCeiling = { filename = "CloudCeiling.ogg", duration = 0.53 },
|
||||||
CloudsBroken = { filename = "CloudsBroken.ogg", duration = 1.07 },
|
CloudsBroken = { filename = "CloudsBroken.ogg", duration = 0.81 },
|
||||||
CloudsFew = { filename = "CloudsFew.ogg", duration = 0.99 },
|
CloudsFew = { filename = "CloudsFew.ogg", duration = 0.74 },
|
||||||
CloudsNo = { filename = "CloudsNo.ogg", duration = 1.01 },
|
CloudsNo = { filename = "CloudsNo.ogg", duration = 0.69},
|
||||||
CloudsNotAvailable = { filename = "CloudsNotAvailable.ogg", duration = 2.35 },
|
CloudsNotAvailable = { filename = "CloudsNotAvailable.ogg", duration = 2.64 },
|
||||||
CloudsOvercast = { filename = "CloudsOvercast.ogg", duration = 0.83 },
|
CloudsOvercast = { filename = "CloudsOvercast.ogg", duration = 0.82 },
|
||||||
CloudsScattered = { filename = "CloudsScattered.ogg", duration = 1.18 },
|
CloudsScattered = { filename = "CloudsScattered.ogg", duration = 0.89 },
|
||||||
Decimal = { filename = "Decimal.ogg", duration = 0.54 },
|
Decimal = { filename = "Decimal.ogg", duration = 0.71 },
|
||||||
DegreesCelsius = { filename = "DegreesCelsius.ogg", duration = 1.27 },
|
DegreesCelsius = { filename = "DegreesCelsius.ogg", duration = 1.08 },
|
||||||
DegreesFahrenheit = { filename = "DegreesFahrenheit.ogg", duration = 1.23 },
|
DegreesFahrenheit = { filename = "DegreesFahrenheit.ogg", duration = 1.07 },
|
||||||
DewPoint = { filename = "DewPoint.ogg", duration = 0.65 },
|
DewPoint = { filename = "DewPoint.ogg", duration = 0.59 },
|
||||||
Dust = { filename = "Dust.ogg", duration = 0.54 },
|
Dust = { filename = "Dust.ogg", duration = 0.37 },
|
||||||
Elevation = { filename = "Elevation.ogg", duration = 0.78 },
|
Elevation = { filename = "Elevation.ogg", duration = 0.92 },
|
||||||
EndOfInformation = { filename = "EndOfInformation.ogg", duration = 1.15 },
|
EndOfInformation = { filename = "EndOfInformation.ogg", duration = 1.24 },
|
||||||
Feet = { filename = "Feet.ogg", duration = 0.45 },
|
Feet = { filename = "Feet.ogg", duration = 0.34 },
|
||||||
Fog = { filename = "Fog.ogg", duration = 0.47 },
|
Fog = { filename = "Fog.ogg", duration = 0.41 },
|
||||||
Gusting = { filename = "Gusting.ogg", duration = 0.55 },
|
Gusting = { filename = "Gusting.ogg", duration = 0.58 },
|
||||||
HectoPascal = { filename = "HectoPascal.ogg", duration = 1.15 },
|
HectoPascal = { filename = "HectoPascal.ogg", duration = 0.92 },
|
||||||
Hundred = { filename = "Hundred.ogg", duration = 0.47 },
|
Hundred = { filename = "Hundred.ogg", duration = 0.53 },
|
||||||
InchesOfMercury = { filename = "InchesOfMercury.ogg", duration = 1.16 },
|
|
||||||
Information = { filename = "Information.ogg", duration = 0.85 },
|
|
||||||
Kilometers = { filename = "Kilometers.ogg", duration = 0.78 },
|
|
||||||
Knots = { filename = "Knots.ogg", duration = 0.59 },
|
|
||||||
Left = { filename = "Left.ogg", duration = 0.54 },
|
|
||||||
MegaHertz = { filename = "MegaHertz.ogg", duration = 0.87 },
|
|
||||||
Meters = { filename = "Meters.ogg", duration = 0.59 },
|
|
||||||
MetersPerSecond = { filename = "MetersPerSecond.ogg", duration = 1.14 },
|
|
||||||
Miles = { filename = "Miles.ogg", duration = 0.60 },
|
|
||||||
MillimetersOfMercury = { filename = "MillimetersOfMercury.ogg", duration = 1.53 },
|
|
||||||
Minus = { filename = "Minus.ogg", duration = 0.64 },
|
|
||||||
N0 = { filename = "N-0.ogg", duration = 0.55 },
|
|
||||||
N1 = { filename = "N-1.ogg", duration = 0.41 },
|
|
||||||
N2 = { filename = "N-2.ogg", duration = 0.37 },
|
|
||||||
N3 = { filename = "N-3.ogg", duration = 0.41 },
|
|
||||||
N4 = { filename = "N-4.ogg", duration = 0.37 },
|
|
||||||
N5 = { filename = "N-5.ogg", duration = 0.43 },
|
|
||||||
N6 = { filename = "N-6.ogg", duration = 0.55 },
|
|
||||||
N7 = { filename = "N-7.ogg", duration = 0.43 },
|
|
||||||
N8 = { filename = "N-8.ogg", duration = 0.38 },
|
|
||||||
N9 = { filename = "N-9.ogg", duration = 0.55 },
|
|
||||||
NauticalMiles = { filename = "NauticalMiles.ogg", duration = 1.04 },
|
|
||||||
None = { filename = "None.ogg", duration = 0.43 },
|
|
||||||
QFE = { filename = "QFE.ogg", duration = 0.63 },
|
|
||||||
QNH = { filename = "QNH.ogg", duration = 0.71 },
|
|
||||||
Rain = { filename = "Rain.ogg", duration = 0.41 },
|
|
||||||
Right = { filename = "Right.ogg", duration = 0.44 },
|
|
||||||
Snow = { filename = "Snow.ogg", duration = 0.48 },
|
|
||||||
SnowStorm = { filename = "SnowStorm.ogg", duration = 0.82 },
|
|
||||||
StatuteMiles = { filename = "StatuteMiles.ogg", duration = 1.15 },
|
|
||||||
SunriseAt = { filename = "SunriseAt.ogg", duration = 0.92 },
|
|
||||||
SunsetAt = { filename = "SunsetAt.ogg", duration = 0.95 },
|
|
||||||
Temperature = { filename = "Temperature.ogg", duration = 0.64 },
|
|
||||||
Thousand = { filename = "Thousand.ogg", duration = 0.55 },
|
|
||||||
ThunderStorm = { filename = "ThunderStorm.ogg", duration = 0.81 },
|
|
||||||
TimeLocal = { filename = "TimeLocal.ogg", duration = 0.90 },
|
|
||||||
TimeZulu = { filename = "TimeZulu.ogg", duration = 0.86 },
|
|
||||||
TowerFrequency = { filename = "TowerFrequency.ogg", duration = 1.19 },
|
|
||||||
Visibilty = { filename = "Visibility.ogg", duration = 0.79 },
|
|
||||||
WeatherPhenomena = { filename = "WeatherPhenomena.ogg", duration = 1.07 },
|
|
||||||
WindFrom = { filename = "WindFrom.ogg", duration = 0.60 },
|
|
||||||
ILSFrequency = { filename = "ILSFrequency.ogg", duration = 1.30 },
|
ILSFrequency = { filename = "ILSFrequency.ogg", duration = 1.30 },
|
||||||
InnerNDBFrequency = { filename = "InnerNDBFrequency.ogg", duration = 1.56 },
|
InchesOfMercury = { filename = "InchesOfMercury.ogg", duration = 1.26 },
|
||||||
OuterNDBFrequency = { filename = "OuterNDBFrequency.ogg", duration = 1.59 },
|
Information = { filename = "Information.ogg", duration = 0.99 },
|
||||||
RunwayLength = { filename = "RunwayLength.ogg", duration = 0.91 },
|
InnerNDBFrequency = { filename = "InnerNDBFrequency.ogg", duration = 1.69 },
|
||||||
VORFrequency = { filename = "VORFrequency.ogg", duration = 1.38 },
|
Kilometers = { filename = "Kilometers.ogg", duration = 0.93 },
|
||||||
TACANChannel = { filename = "TACANChannel.ogg", duration = 0.88 },
|
Knots = { filename = "Knots.ogg", duration = 0.46 },
|
||||||
PRMGChannel = { filename = "PRMGChannel.ogg", duration = 1.18 },
|
Left = { filename = "Left.ogg", duration = 0.41 },
|
||||||
RSBNChannel = { filename = "RSBNChannel.ogg", duration = 1.14 },
|
MegaHertz = { filename = "MegaHertz.ogg", duration = 0.83 },
|
||||||
Zulu = { filename = "Zulu.ogg", duration = 0.62 },
|
Meters = { filename = "Meters.ogg", duration = 0.55 },
|
||||||
|
MetersPerSecond = { filename = "MetersPerSecond.ogg", duration = 1.03 },
|
||||||
|
Miles = { filename = "Miles.ogg", duration = 0.44 },
|
||||||
|
MillimetersOfMercury = { filename = "MillimetersOfMercury.ogg", duration = 1.59 },
|
||||||
|
Minus = { filename = "Minus.ogg", duration = 0.55 },
|
||||||
|
N0 = { filename = "N-0.ogg", duration = 0.52 },
|
||||||
|
N1 = { filename = "N-1.ogg", duration = 0.35 },
|
||||||
|
N2 = { filename = "N-2.ogg", duration = 0.41 },
|
||||||
|
N3 = { filename = "N-3.ogg", duration = 0.34 },
|
||||||
|
N4 = { filename = "N-4.ogg", duration = 0.37 },
|
||||||
|
N5 = { filename = "N-5.ogg", duration = 0.40 },
|
||||||
|
N6 = { filename = "N-6.ogg", duration = 0.46 },
|
||||||
|
N7 = { filename = "N-7.ogg", duration = 0.52 },
|
||||||
|
N8 = { filename = "N-8.ogg", duration = 0.36 },
|
||||||
|
N9 = { filename = "N-9.ogg", duration = 0.51 },
|
||||||
|
NauticalMiles = { filename = "NauticalMiles.ogg", duration = 0.93 },
|
||||||
|
None = { filename = "None.ogg", duration = 0.33 },
|
||||||
|
OuterNDBFrequency = { filename = "OuterNDBFrequency.ogg", duration = 1.70 },
|
||||||
|
PRMGChannel = { filename = "PRMGChannel.ogg", duration = 1.27 },
|
||||||
|
QFE = { filename = "QFE.ogg", duration = 0.90 },
|
||||||
|
QNH = { filename = "QNH.ogg", duration = 0.94 },
|
||||||
|
Rain = { filename = "Rain.ogg", duration = 0.35 },
|
||||||
|
Right = { filename = "Right.ogg", duration = 0.31 },
|
||||||
|
RSBNChannel = { filename = "RSBNChannel.ogg", duration = 1.26 },
|
||||||
|
RunwayLength = { filename = "RunwayLength.ogg", duration = 0.81 },
|
||||||
|
Snow = { filename = "Snow.ogg", duration = 0.40 },
|
||||||
|
SnowStorm = { filename = "SnowStorm.ogg", duration = 0.73 },
|
||||||
|
StatuteMiles = { filename = "StatuteMiles.ogg", duration = 0.90 },
|
||||||
|
SunriseAt = { filename = "SunriseAt.ogg", duration = 0.82 },
|
||||||
|
SunsetAt = { filename = "SunsetAt.ogg", duration = 0.87 },
|
||||||
|
TACANChannel = { filename = "TACANChannel.ogg", duration = 0.81 },
|
||||||
|
Temperature = { filename = "Temperature.ogg", duration = 0.70 },
|
||||||
|
Thousand = { filename = "Thousand.ogg", duration = 0.58 },
|
||||||
|
ThunderStorm = { filename = "ThunderStorm.ogg", duration = 0.79 },
|
||||||
|
TimeLocal = { filename = "TimeLocal.ogg", duration = 0.83 },
|
||||||
|
TimeZulu = { filename = "TimeZulu.ogg", duration = 0.83 },
|
||||||
|
TowerFrequency = { filename = "TowerFrequency.ogg", duration = 1.05 },
|
||||||
|
Visibilty = { filename = "Visibility.ogg", duration = 1.16 },
|
||||||
|
VORFrequency = { filename = "VORFrequency.ogg", duration = 1.28 },
|
||||||
|
WeatherPhenomena = { filename = "WeatherPhenomena.ogg", duration = 1.09 },
|
||||||
|
WindFrom = { filename = "WindFrom.ogg", duration = 0.63 },
|
||||||
|
Zulu = { filename = "Zulu.ogg", duration = 0.51 },
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -954,7 +970,7 @@ _ATIS = {}
|
|||||||
|
|
||||||
--- ATIS class version.
|
--- ATIS class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
ATIS.version = "1.0.0"
|
ATIS.version = "1.0.1"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -2037,12 +2053,14 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
local sunrise = coord:GetSunrise()
|
local sunrise = coord:GetSunrise()
|
||||||
--self:I(sunrise)
|
--self:I(sunrise)
|
||||||
local SUNRISE = "no time"
|
local SUNRISE = "no time"
|
||||||
|
local NorthPolar = true
|
||||||
if tostring(sunrise) ~= "N/S" and tostring(sunrise) ~= "N/R" then
|
if tostring(sunrise) ~= "N/S" and tostring(sunrise) ~= "N/R" then
|
||||||
sunrise = UTILS.Split( sunrise, ":" )
|
sunrise = UTILS.Split( sunrise, ":" )
|
||||||
SUNRISE = string.format( "%s%s", sunrise[1], sunrise[2] )
|
SUNRISE = string.format( "%s%s", sunrise[1], sunrise[2] )
|
||||||
if self.useSRS then
|
if self.useSRS then
|
||||||
SUNRISE = string.format( "%s %s %s", sunrise[1], sunrise[2], hours )
|
SUNRISE = string.format( "%s %s %s", sunrise[1], sunrise[2], hours )
|
||||||
end
|
end
|
||||||
|
NorthPolar = false
|
||||||
end
|
end
|
||||||
|
|
||||||
local sunset = coord:GetSunset()
|
local sunset = coord:GetSunset()
|
||||||
@@ -2054,6 +2072,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
if self.useSRS then
|
if self.useSRS then
|
||||||
SUNSET = string.format( "%s %s %s", sunset[1], sunset[2], hours )
|
SUNSET = string.format( "%s %s %s", sunset[1], sunset[2], hours )
|
||||||
end
|
end
|
||||||
|
NorthPolar = false
|
||||||
end
|
end
|
||||||
|
|
||||||
---------------------------------
|
---------------------------------
|
||||||
@@ -2080,34 +2099,32 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
---------------
|
---------------
|
||||||
|
|
||||||
-- Get mission weather info. Most of this is static.
|
-- Get mission weather info. Most of this is static.
|
||||||
local clouds, visibility, turbulence, fog, dust, static = self:GetMissionWeather()
|
local clouds, visibility, turbulence, dustdens, static = self:GetMissionWeather()
|
||||||
|
|
||||||
-- Check that fog is actually "thick" enough to reach the airport. If an airport is in the mountains, fog might not affect it as it is measured from sea level.
|
local dust=false
|
||||||
if fog and fog.thickness < height + 25 then
|
local fog=false
|
||||||
fog = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Dust only up to 1500 ft = 457 m ASL.
|
|
||||||
if dust and height + 25 > UTILS.FeetToMeters( 1500 ) then
|
|
||||||
dust = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
------------------
|
------------------
|
||||||
--- Visibility ---
|
--- Visibility ---
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
-- Get min visibility.
|
if dustdens then
|
||||||
local visibilitymin = visibility
|
|
||||||
|
-- Dust only up to 1500 ft = 457 m ASL.
|
||||||
if fog then
|
if UTILS.FeetToMeters( 1500 )> height+25 then
|
||||||
if fog.visibility < visibilitymin then
|
dust=true
|
||||||
visibilitymin = fog.visibility
|
visibility=math.min(visibility, dustdens)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
else -- As of DCS 2.9.10.3948 (December 2024), fog and dust are mutually exclusive!
|
||||||
if dust then
|
|
||||||
if dust < visibilitymin then
|
-- Get current fog visibility and thickness
|
||||||
visibilitymin = dust
|
local fvis=world.weather.getFogVisibilityDistance()
|
||||||
|
local fheight=world.weather.getFogThickness()
|
||||||
|
|
||||||
|
if fvis>0 and fheight>height+25 then
|
||||||
|
fog=true
|
||||||
|
visibility=math.min(visibility, fvis)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2115,7 +2132,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
|
|
||||||
if self.metric then
|
if self.metric then
|
||||||
-- Visibility in km.
|
-- Visibility in km.
|
||||||
local reportedviz = UTILS.Round( visibilitymin / 1000 )
|
local reportedviz = UTILS.Round( visibility / 1000 )
|
||||||
-- max reported visibility 9999 m
|
-- max reported visibility 9999 m
|
||||||
if reportedviz > 10 then
|
if reportedviz > 10 then
|
||||||
reportedviz = 10
|
reportedviz = 10
|
||||||
@@ -2123,7 +2140,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
VISIBILITY = string.format( "%d", reportedviz )
|
VISIBILITY = string.format( "%d", reportedviz )
|
||||||
else
|
else
|
||||||
-- max reported visibility 10 NM
|
-- max reported visibility 10 NM
|
||||||
local reportedviz = UTILS.Round( UTILS.MetersToSM( visibilitymin ) )
|
local reportedviz = UTILS.Round( UTILS.MetersToSM( visibility ) )
|
||||||
if reportedviz > 10 then
|
if reportedviz > 10 then
|
||||||
reportedviz = 10
|
reportedviz = 10
|
||||||
end
|
end
|
||||||
@@ -2395,7 +2412,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
local sunrise = self.gettext:GetEntry("SUNRISEAT",self.locale)
|
local sunrise = self.gettext:GetEntry("SUNRISEAT",self.locale)
|
||||||
--subtitle = string.format( "Sunrise at %s local time", SUNRISE )
|
--subtitle = string.format( "Sunrise at %s local time", SUNRISE )
|
||||||
subtitle = string.format( sunrise, SUNRISE )
|
subtitle = string.format( sunrise, SUNRISE )
|
||||||
if not self.useSRS then
|
if not self.useSRS and NorthPolar == false then
|
||||||
self:Transmission( self.Sound.SunriseAt, 0.5, subtitle )
|
self:Transmission( self.Sound.SunriseAt, 0.5, subtitle )
|
||||||
self.radioqueue:Number2Transmission( SUNRISE, nil, 0.2 )
|
self.radioqueue:Number2Transmission( SUNRISE, nil, 0.2 )
|
||||||
self:Transmission( self.Sound.TimeLocal, 0.2 )
|
self:Transmission( self.Sound.TimeLocal, 0.2 )
|
||||||
@@ -2406,7 +2423,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
local sunset = self.gettext:GetEntry("SUNSETAT",self.locale)
|
local sunset = self.gettext:GetEntry("SUNSETAT",self.locale)
|
||||||
--subtitle = string.format( "Sunset at %s local time", SUNSET )
|
--subtitle = string.format( "Sunset at %s local time", SUNSET )
|
||||||
subtitle = string.format( sunset, SUNSET )
|
subtitle = string.format( sunset, SUNSET )
|
||||||
if not self.useSRS then
|
if not self.useSRS and NorthPolar == false then
|
||||||
self:Transmission( self.Sound.SunsetAt, 0.5, subtitle )
|
self:Transmission( self.Sound.SunsetAt, 0.5, subtitle )
|
||||||
self.radioqueue:Number2Transmission( SUNSET, nil, 0.5 )
|
self.radioqueue:Number2Transmission( SUNSET, nil, 0.5 )
|
||||||
self:Transmission( self.Sound.TimeLocal, 0.2 )
|
self:Transmission( self.Sound.TimeLocal, 0.2 )
|
||||||
@@ -2781,7 +2798,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
|
|
||||||
end
|
end
|
||||||
_RUNACT = subtitle
|
_RUNACT = subtitle
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
--alltext = alltext .. ";\n" .. subtitle
|
||||||
|
|
||||||
-- Runway length.
|
-- Runway length.
|
||||||
if self.rwylength then
|
if self.rwylength then
|
||||||
@@ -3350,28 +3367,13 @@ function ATIS:GetMissionWeather()
|
|||||||
dust = weather.dust_density
|
dust = weather.dust_density
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Fog
|
|
||||||
--[[
|
|
||||||
["enable_fog"] = false,
|
|
||||||
["fog"] =
|
|
||||||
{
|
|
||||||
["thickness"] = 0,
|
|
||||||
["visibility"] = 25,
|
|
||||||
}, -- end of ["fog"]
|
|
||||||
]]
|
|
||||||
local fog = nil
|
|
||||||
if weather.enable_fog == true then
|
|
||||||
fog = weather.fog
|
|
||||||
end
|
|
||||||
|
|
||||||
self:T( "FF weather:" )
|
self:T( "FF weather:" )
|
||||||
self:T( { clouds = clouds } )
|
self:T( { clouds = clouds } )
|
||||||
self:T( { visibility = visibility } )
|
self:T( { visibility = visibility } )
|
||||||
self:T( { turbulence = turbulence } )
|
self:T( { turbulence = turbulence } )
|
||||||
self:T( { fog = fog } )
|
|
||||||
self:T( { dust = dust } )
|
self:T( { dust = dust } )
|
||||||
self:T( { static = static } )
|
self:T( { static = static } )
|
||||||
return clouds, visibility, turbulence, fog, dust, static
|
return clouds, visibility, turbulence, dust, static
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get thousands of a number.
|
--- Get thousands of a number.
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ AIRWING = {
|
|||||||
|
|
||||||
--- AIRWING class version.
|
--- AIRWING class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
AIRWING.version="0.9.5"
|
AIRWING.version="0.9.6"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -974,6 +974,46 @@ function AIRWING:SetTakeoffAir()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set the aircraft of the AirWing to land straight in.
|
||||||
|
-- @param #AIRWING self
|
||||||
|
-- @return #FLIGHTGROUP self
|
||||||
|
function AIRWING:SetLandingStraightIn()
|
||||||
|
self.OptionLandingStraightIn = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the aircraft of the AirWing to land in pairs for groups > 1 aircraft.
|
||||||
|
-- @param #AIRWING self
|
||||||
|
-- @return #AIRWING self
|
||||||
|
function AIRWING:SetLandingForcePair()
|
||||||
|
self.OptionLandingForcePair = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the aircraft of the AirWing to NOT land in pairs.
|
||||||
|
-- @param #AIRWING self
|
||||||
|
-- @return #AIRWING self
|
||||||
|
function AIRWING:SetLandingRestrictPair()
|
||||||
|
self.OptionLandingRestrictPair = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the aircraft of the AirWing to land after overhead break.
|
||||||
|
-- @param #AIRWING self
|
||||||
|
-- @return #AIRWING self
|
||||||
|
function AIRWING:SetLandingOverheadBreak()
|
||||||
|
self.OptionLandingOverheadBreak = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Helicopter] Set the aircraft of the AirWing to prefer vertical takeoff and landing.
|
||||||
|
-- @param #AIRWING self
|
||||||
|
-- @return #AIRWING self
|
||||||
|
function AIRWING:SetOptionPreferVerticalLanding()
|
||||||
|
self.OptionPreferVerticalLanding = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set despawn after landing. Aircraft will be despawned after the landing event.
|
--- Set despawn after landing. Aircraft will be despawned after the landing event.
|
||||||
-- Can help to avoid DCS AI taxiing issues.
|
-- Can help to avoid DCS AI taxiing issues.
|
||||||
-- @param #AIRWING self
|
-- @param #AIRWING self
|
||||||
@@ -1365,16 +1405,20 @@ function AIRWING:CheckRescuhelo()
|
|||||||
|
|
||||||
local N=self:CountMissionsInQueue({AUFTRAG.Type.RESCUEHELO})
|
local N=self:CountMissionsInQueue({AUFTRAG.Type.RESCUEHELO})
|
||||||
|
|
||||||
local name=self.airbase:GetName()
|
if self.airbase then
|
||||||
|
|
||||||
local carrier=UNIT:FindByName(name)
|
local name=self.airbase:GetName()
|
||||||
|
|
||||||
for i=1,self.nflightsRescueHelo-N do
|
local carrier=UNIT:FindByName(name)
|
||||||
|
|
||||||
local mission=AUFTRAG:NewRESCUEHELO(carrier)
|
for i=1,self.nflightsRescueHelo-N do
|
||||||
|
|
||||||
self:AddMission(mission)
|
local mission=AUFTRAG:NewRESCUEHELO(carrier)
|
||||||
|
|
||||||
|
self:AddMission(mission)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -1460,7 +1504,21 @@ function AIRWING:onafterFlightOnMission(From, Event, To, FlightGroup, Mission)
|
|||||||
self:T(self.lid..string.format("Group %s on %s mission %s", FlightGroup:GetName(), Mission:GetType(), Mission:GetName()))
|
self:T(self.lid..string.format("Group %s on %s mission %s", FlightGroup:GetName(), Mission:GetType(), Mission:GetName()))
|
||||||
if self.UseConnectedOpsAwacs and self.ConnectedOpsAwacs then
|
if self.UseConnectedOpsAwacs and self.ConnectedOpsAwacs then
|
||||||
self.ConnectedOpsAwacs:__FlightOnMission(2,FlightGroup,Mission)
|
self.ConnectedOpsAwacs:__FlightOnMission(2,FlightGroup,Mission)
|
||||||
end
|
end
|
||||||
|
-- Landing Options
|
||||||
|
if self.OptionLandingForcePair then
|
||||||
|
FlightGroup:SetOptionLandingForcePair()
|
||||||
|
elseif self.OptionLandingOverheadBreak then
|
||||||
|
FlightGroup:SetOptionLandingOverheadBreak()
|
||||||
|
elseif self.OptionLandingRestrictPair then
|
||||||
|
FlightGroup:SetOptionLandingRestrictPair()
|
||||||
|
elseif self.OptionLandingStraightIn then
|
||||||
|
FlightGroup:SetOptionLandingStraightIn()
|
||||||
|
end
|
||||||
|
-- Landing Options Helo
|
||||||
|
if self.OptionPreferVerticalLanding then
|
||||||
|
FlightGroup:SetOptionPreferVertical()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -68,7 +68,7 @@ ARMYGROUP = {
|
|||||||
|
|
||||||
--- Army Group version.
|
--- Army Group version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
ARMYGROUP.version="1.0.1"
|
ARMYGROUP.version="1.0.3"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -2049,114 +2049,70 @@ end
|
|||||||
--- Initialize group parameters. Also initializes waypoints if self.waypoints is nil.
|
--- Initialize group parameters. Also initializes waypoints if self.waypoints is nil.
|
||||||
-- @param #ARMYGROUP self
|
-- @param #ARMYGROUP self
|
||||||
-- @param #table Template Template used to init the group. Default is `self.template`.
|
-- @param #table Template Template used to init the group. Default is `self.template`.
|
||||||
|
-- @param #number Delay Delay in seconds before group is initialized. Default `nil`, *i.e.* instantaneous.
|
||||||
-- @return #ARMYGROUP self
|
-- @return #ARMYGROUP self
|
||||||
function ARMYGROUP:_InitGroup(Template, Delay)
|
function ARMYGROUP:_InitGroup(Template, Delay)
|
||||||
|
|
||||||
if Delay and Delay>0 then
|
if Delay and Delay>0 then
|
||||||
self:ScheduleOnce(Delay, ARMYGROUP._InitGroup, self, Template, 0)
|
self:ScheduleOnce(Delay, ARMYGROUP._InitGroup, self, Template, 0)
|
||||||
else
|
else
|
||||||
-- First check if group was already initialized.
|
|
||||||
if self.groupinitialized then
|
|
||||||
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get template of group.
|
|
||||||
local template=Template or self:_GetTemplate()
|
|
||||||
|
|
||||||
-- Ground are always AI.
|
|
||||||
self.isAI=true
|
|
||||||
|
|
||||||
-- Is (template) group late activated.
|
|
||||||
self.isLateActivated=template.lateActivation
|
|
||||||
|
|
||||||
-- Ground groups cannot be uncontrolled.
|
|
||||||
self.isUncontrolled=false
|
|
||||||
|
|
||||||
-- Max speed in km/h.
|
|
||||||
self.speedMax=self.group:GetSpeedMax()
|
|
||||||
|
|
||||||
-- Is group mobile?
|
|
||||||
if self.speedMax and self.speedMax>3.6 then
|
|
||||||
self.isMobile=true
|
|
||||||
else
|
|
||||||
self.isMobile=false
|
|
||||||
self.speedMax = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Cruise speed in km/h
|
|
||||||
self.speedCruise=self.speedMax*0.7
|
|
||||||
|
|
||||||
-- Group ammo.
|
|
||||||
self.ammo=self:GetAmmoTot()
|
|
||||||
|
|
||||||
-- Radio parameters from template.
|
|
||||||
self.radio.On=false -- Radio is always OFF for ground.
|
|
||||||
self.radio.Freq=133
|
|
||||||
self.radio.Modu=radio.modulation.AM
|
|
||||||
|
|
||||||
-- Set default radio.
|
|
||||||
self:SetDefaultRadio(self.radio.Freq, self.radio.Modu, self.radio.On)
|
|
||||||
|
|
||||||
-- Get current formation from first waypoint.
|
|
||||||
self.option.Formation=template.route.points[1].action
|
|
||||||
|
|
||||||
-- Set default formation to "on road".
|
|
||||||
self.optionDefault.Formation=ENUMS.Formation.Vehicle.OnRoad
|
|
||||||
|
|
||||||
-- First check if group was already initialized.
|
-- First check if group was already initialized.
|
||||||
if self.groupinitialized then
|
if self.groupinitialized then
|
||||||
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T(self.lid.."FF Initializing Group")
|
|
||||||
|
|
||||||
-- Get template of group.
|
-- Get template of group.
|
||||||
local template=Template or self:_GetTemplate()
|
local template=Template or self:_GetTemplate()
|
||||||
|
|
||||||
-- Ground are always AI.
|
-- Ground are always AI.
|
||||||
self.isAI=true
|
self.isAI=true
|
||||||
|
|
||||||
-- Is (template) group late activated.
|
-- Is (template) group late activated.
|
||||||
self.isLateActivated=template.lateActivation
|
self.isLateActivated=template.lateActivation
|
||||||
|
|
||||||
-- Ground groups cannot be uncontrolled.
|
-- Ground groups cannot be uncontrolled.
|
||||||
self.isUncontrolled=false
|
self.isUncontrolled=false
|
||||||
|
|
||||||
-- Max speed in km/h.
|
-- Max speed in km/h.
|
||||||
self.speedMax=self.group:GetSpeedMax()
|
self.speedMax=self.group:GetSpeedMax()
|
||||||
|
|
||||||
-- Is group mobile?
|
-- Is group mobile?
|
||||||
if self.speedMax>3.6 then
|
if self.speedMax and self.speedMax>3.6 then
|
||||||
self.isMobile=true
|
self.isMobile=true
|
||||||
else
|
else
|
||||||
self.isMobile=false
|
self.isMobile=false
|
||||||
|
self.speedMax = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Cruise speed in km/h
|
-- Cruise speed in km/h
|
||||||
self.speedCruise=self.speedMax*0.7
|
self.speedCruise=self.speedMax*0.7
|
||||||
|
|
||||||
-- Group ammo.
|
-- Group ammo.
|
||||||
self.ammo=self:GetAmmoTot()
|
self.ammo=self:GetAmmoTot()
|
||||||
|
|
||||||
-- Radio parameters from template.
|
-- Radio parameters from template.
|
||||||
self.radio.On=false -- Radio is always OFF for ground.
|
self.radio.On=false -- Radio is always OFF for ground.
|
||||||
self.radio.Freq=133
|
self.radio.Freq=133
|
||||||
self.radio.Modu=radio.modulation.AM
|
self.radio.Modu=radio.modulation.AM
|
||||||
|
|
||||||
-- Set default radio.
|
-- Set default radio.
|
||||||
self:SetDefaultRadio(self.radio.Freq, self.radio.Modu, self.radio.On)
|
self:SetDefaultRadio(self.radio.Freq, self.radio.Modu, self.radio.On)
|
||||||
|
|
||||||
-- Get current formation from first waypoint.
|
-- Get current formation from first waypoint.
|
||||||
self.option.Formation=template.route.points[1].action
|
self.option.Formation=template.route.points[1].action
|
||||||
|
|
||||||
-- Set default formation to "on road".
|
-- Set default formation to "on road".
|
||||||
self.optionDefault.Formation=ENUMS.Formation.Vehicle.OnRoad
|
self.optionDefault.Formation=ENUMS.Formation.Vehicle.OnRoad
|
||||||
|
|
||||||
-- Default TACAN off.
|
-- Default TACAN off.
|
||||||
self:SetDefaultTACAN(nil, nil, nil, nil, true)
|
if not self.tacanDefault then
|
||||||
self.tacan=UTILS.DeepCopy(self.tacanDefault)
|
self:SetDefaultTACAN(nil, nil, nil, nil, true)
|
||||||
|
end
|
||||||
|
if not self.tacan then
|
||||||
|
self.tacan=UTILS.DeepCopy(self.tacanDefault)
|
||||||
|
end
|
||||||
|
|
||||||
-- Units of the group.
|
-- Units of the group.
|
||||||
local units=self.group:GetUnits()
|
local units=self.group:GetUnits()
|
||||||
@@ -2177,7 +2133,6 @@ function ARMYGROUP:_InitGroup(Template, Delay)
|
|||||||
self:_AddElementByName(unitname)
|
self:_AddElementByName(unitname)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Init done.
|
-- Init done.
|
||||||
self.groupinitialized=true
|
self.groupinitialized=true
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -162,6 +162,7 @@
|
|||||||
-- @field #number missionRange Mission range in meters. Used by LEGION classes (AIRWING, BRIGADE, ...).
|
-- @field #number missionRange Mission range in meters. Used by LEGION classes (AIRWING, BRIGADE, ...).
|
||||||
-- @field Core.Point#COORDINATE missionWaypointCoord Mission waypoint coordinate.
|
-- @field Core.Point#COORDINATE missionWaypointCoord Mission waypoint coordinate.
|
||||||
-- @field Core.Point#COORDINATE missionEgressCoord Mission egress waypoint coordinate.
|
-- @field Core.Point#COORDINATE missionEgressCoord Mission egress waypoint coordinate.
|
||||||
|
-- @field Core.Point#COORDINATE missionIngressCoord Mission Ingress waypoint coordinate.
|
||||||
-- @field #number missionWaypointRadius Random radius in meters.
|
-- @field #number missionWaypointRadius Random radius in meters.
|
||||||
-- @field #boolean legionReturn If `true`, assets return to their legion (default). If `false`, they will stay alive.
|
-- @field #boolean legionReturn If `true`, assets return to their legion (default). If `false`, they will stay alive.
|
||||||
--
|
--
|
||||||
@@ -396,6 +397,7 @@ AUFTRAG = {
|
|||||||
conditionPush = {},
|
conditionPush = {},
|
||||||
conditionSuccessSet = false,
|
conditionSuccessSet = false,
|
||||||
conditionFailureSet = false,
|
conditionFailureSet = false,
|
||||||
|
repeatDelay = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Global mission counter.
|
--- Global mission counter.
|
||||||
@@ -1427,7 +1429,7 @@ function AUFTRAG:NewCAP(ZoneCAP, Altitude, Speed, Coordinate, Heading, Leg, Targ
|
|||||||
mission:_SetLogID()
|
mission:_SetLogID()
|
||||||
|
|
||||||
-- DCS task parameters:
|
-- DCS task parameters:
|
||||||
mission.engageZone=ZoneCAP
|
mission.engageZone=ZoneCAP or Coordinate
|
||||||
mission.engageTargetTypes=TargetTypes or {"Air"}
|
mission.engageTargetTypes=TargetTypes or {"Air"}
|
||||||
|
|
||||||
-- Mission options:
|
-- Mission options:
|
||||||
@@ -1714,19 +1716,56 @@ function AUFTRAG:NewSEAD(Target, Altitude)
|
|||||||
return mission
|
return mission
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- **[AIR]** Create a SEAD in Zone mission.
|
||||||
|
-- @param #AUFTRAG self
|
||||||
|
-- @param Core.Zone#ZONE TargetZone The target zone to attack.
|
||||||
|
-- @param #number Altitude Engage altitude in feet. Default 25000 ft.
|
||||||
|
-- @param #table TargetTypes Table of string of DCS known target types, defaults to {"Air Defence"}. See [DCS Target Attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes)
|
||||||
|
-- @param #number Duration Engage this much time when the AUFTRAG starts executing.
|
||||||
|
-- @return #AUFTRAG self
|
||||||
|
function AUFTRAG:NewSEADInZone(TargetZone, Altitude, TargetTypes, Duration)
|
||||||
|
|
||||||
|
local mission=AUFTRAG:New(AUFTRAG.Type.SEAD)
|
||||||
|
|
||||||
|
mission:_TargetFromObject(TargetZone)
|
||||||
|
|
||||||
|
-- DCS Task options:
|
||||||
|
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
||||||
|
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||||
|
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
|
||||||
|
mission.engageZone = TargetZone
|
||||||
|
mission.engageTargetTypes = TargetTypes or {"Air Defence"}
|
||||||
|
|
||||||
|
-- Mission options:
|
||||||
|
mission.missionTask=ENUMS.MissionTask.SEAD
|
||||||
|
mission.missionAltitude=mission.engageAltitude
|
||||||
|
mission.missionFraction=0.2
|
||||||
|
mission.optionROE=ENUMS.ROE.OpenFire
|
||||||
|
mission.optionROT=ENUMS.ROT.EvadeFire
|
||||||
|
|
||||||
|
mission.categories={AUFTRAG.Category.AIRCRAFT}
|
||||||
|
|
||||||
|
mission.DCStask=mission:GetDCSMissionTask()
|
||||||
|
|
||||||
|
mission:SetDuration(Duration or 1800)
|
||||||
|
|
||||||
|
return mission
|
||||||
|
end
|
||||||
|
|
||||||
--- **[AIR]** Create a STRIKE mission. Flight will attack the closest map object to the specified coordinate.
|
--- **[AIR]** Create a STRIKE mission. Flight will attack the closest map object to the specified coordinate.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC or TARGET object.
|
-- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object.
|
||||||
-- @param #number Altitude Engage altitude in feet. Default 2000 ft.
|
-- @param #number Altitude Engage altitude in feet. Default 2000 ft.
|
||||||
|
-- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options.
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
function AUFTRAG:NewSTRIKE(Target, Altitude)
|
function AUFTRAG:NewSTRIKE(Target, Altitude, EngageWeaponType)
|
||||||
|
|
||||||
local mission=AUFTRAG:New(AUFTRAG.Type.STRIKE)
|
local mission=AUFTRAG:New(AUFTRAG.Type.STRIKE)
|
||||||
|
|
||||||
mission:_TargetFromObject(Target)
|
mission:_TargetFromObject(Target)
|
||||||
|
|
||||||
-- DCS Task options:
|
-- DCS Task options:
|
||||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
mission.engageWeaponType=EngageWeaponType or ENUMS.WeaponFlag.Auto
|
||||||
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 2000)
|
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 2000)
|
||||||
|
|
||||||
@@ -1747,17 +1786,19 @@ end
|
|||||||
--- **[AIR]** Create a BOMBING mission. Flight will drop bombs a specified coordinate.
|
--- **[AIR]** Create a BOMBING mission. Flight will drop bombs a specified coordinate.
|
||||||
-- See [DCS task bombing](https://wiki.hoggitworld.com/view/DCS_task_bombing).
|
-- See [DCS task bombing](https://wiki.hoggitworld.com/view/DCS_task_bombing).
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC or TARGET object.
|
-- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object.
|
||||||
-- @param #number Altitude Engage altitude in feet. Default 25000 ft.
|
-- @param #number Altitude Engage altitude in feet. Default 25000 ft.
|
||||||
|
-- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options.
|
||||||
|
-- @param #boolean Divebomb If true, use a dive bombing attack approach.
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
function AUFTRAG:NewBOMBING(Target, Altitude)
|
function AUFTRAG:NewBOMBING(Target, Altitude, EngageWeaponType, Divebomb)
|
||||||
|
|
||||||
local mission=AUFTRAG:New(AUFTRAG.Type.BOMBING)
|
local mission=AUFTRAG:New(AUFTRAG.Type.BOMBING)
|
||||||
|
|
||||||
mission:_TargetFromObject(Target)
|
mission:_TargetFromObject(Target)
|
||||||
|
|
||||||
-- DCS task options:
|
-- DCS task options:
|
||||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
mission.engageWeaponType=EngageWeaponType or ENUMS.WeaponFlag.Auto
|
||||||
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
|
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
|
||||||
|
|
||||||
@@ -1767,6 +1808,7 @@ function AUFTRAG:NewBOMBING(Target, Altitude)
|
|||||||
mission.missionFraction=0.5
|
mission.missionFraction=0.5
|
||||||
mission.optionROE=ENUMS.ROE.OpenFire
|
mission.optionROE=ENUMS.ROE.OpenFire
|
||||||
mission.optionROT=ENUMS.ROT.NoReaction -- No reaction is better.
|
mission.optionROT=ENUMS.ROT.NoReaction -- No reaction is better.
|
||||||
|
mission.optionDivebomb = Divebomb or nil
|
||||||
|
|
||||||
-- Evaluate result after 5 min. We might need time until the bombs have dropped and targets have been detroyed.
|
-- Evaluate result after 5 min. We might need time until the bombs have dropped and targets have been detroyed.
|
||||||
mission.dTevaluate=5*60
|
mission.dTevaluate=5*60
|
||||||
@@ -1819,7 +1861,7 @@ end
|
|||||||
|
|
||||||
--- **[AIR]** Create a BOMBRUNWAY mission.
|
--- **[AIR]** Create a BOMBRUNWAY mission.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param Wrapper.Airbase#AIRBASE Airdrome The airbase to bomb. This must be an airdrome (not a FARP or ship) as these to not have a runway.
|
-- @param Wrapper.Airbase#AIRBASE Airdrome The airbase to bomb. This must be an airdrome (not a FARP or ship) as these do not have a runway.
|
||||||
-- @param #number Altitude Engage altitude in feet. Default 25000 ft.
|
-- @param #number Altitude Engage altitude in feet. Default 25000 ft.
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
function AUFTRAG:NewBOMBRUNWAY(Airdrome, Altitude)
|
function AUFTRAG:NewBOMBRUNWAY(Airdrome, Altitude)
|
||||||
@@ -2155,7 +2197,11 @@ end
|
|||||||
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
--- **[GROUND, NAVAL]** Create an ARTY mission.
|
--- **[GROUND, NAVAL]** Create an ARTY mission ("Fire at point" task).
|
||||||
|
--
|
||||||
|
-- If the group has more than one weapon type supporting the "Fire at point" task, the employed weapon type can be set via the `AUFTRAG:SetWeaponType()` function.
|
||||||
|
--
|
||||||
|
-- **Note** that it is recommended to set the weapon range via the `OPSGROUP:AddWeaponRange()` function as this cannot be retrieved from the DCS API.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param Core.Point#COORDINATE Target Center of the firing solution.
|
-- @param Core.Point#COORDINATE Target Center of the firing solution.
|
||||||
-- @param #number Nshots Number of shots to be fired. Default `#nil`.
|
-- @param #number Nshots Number of shots to be fired. Default `#nil`.
|
||||||
@@ -2178,6 +2224,7 @@ function AUFTRAG:NewARTY(Target, Nshots, Radius, Altitude)
|
|||||||
mission.optionAlarm=0
|
mission.optionAlarm=0
|
||||||
|
|
||||||
mission.missionFraction=0.0
|
mission.missionFraction=0.0
|
||||||
|
mission.missionWaypointRadius=0.0
|
||||||
|
|
||||||
-- Evaluate after 8 min.
|
-- Evaluate after 8 min.
|
||||||
mission.dTevaluate=8*60
|
mission.dTevaluate=8*60
|
||||||
@@ -2302,7 +2349,7 @@ function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation)
|
|||||||
params.formation=Formation or "Off Road"
|
params.formation=Formation or "Off Road"
|
||||||
params.zone=mission:GetObjective()
|
params.zone=mission:GetObjective()
|
||||||
params.altitude=mission.missionAltitude
|
params.altitude=mission.missionAltitude
|
||||||
params.speed=mission.missionSpeed
|
params.speed=mission.missionSpeed and UTILS.KmphToMps(mission.missionSpeed) or nil
|
||||||
|
|
||||||
mission.DCStask.params=params
|
mission.DCStask.params=params
|
||||||
|
|
||||||
@@ -2352,7 +2399,7 @@ function AUFTRAG:NewGROUNDATTACK(Target, Speed, Formation)
|
|||||||
|
|
||||||
mission.DCStask=mission:GetDCSMissionTask()
|
mission.DCStask=mission:GetDCSMissionTask()
|
||||||
|
|
||||||
mission.DCStask.params.speed=Speed
|
mission.DCStask.params.speed=mission.missionSpeed and UTILS.KmphToMps(mission.missionSpeed) or nil
|
||||||
mission.DCStask.params.formation=Formation or ENUMS.Formation.Vehicle.Vee
|
mission.DCStask.params.formation=Formation or ENUMS.Formation.Vehicle.Vee
|
||||||
|
|
||||||
return mission
|
return mission
|
||||||
@@ -2958,6 +3005,16 @@ function AUFTRAG:SetRepeat(Nrepeat)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- **[LEGION, COMMANDER, CHIEF]** Set the repeat delay in seconds after a mission is successful/failed. Only valid if the mission is handled by a LEGION (AIRWING, BRIGADE, FLEET) or higher level.
|
||||||
|
-- @param #AUFTRAG self
|
||||||
|
-- @param #number Nrepeat Repeat delay in seconds. Default 1.
|
||||||
|
-- @return #AUFTRAG self
|
||||||
|
function AUFTRAG:SetRepeatDelay(RepeatDelay)
|
||||||
|
self.repeatDelay = RepeatDelay
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- **[LEGION, COMMANDER, CHIEF]** Set how many times the mission is repeated if it fails. Only valid if the mission is handled by a LEGION (AIRWING, BRIGADE, FLEET) or higher level.
|
--- **[LEGION, COMMANDER, CHIEF]** Set how many times the mission is repeated if it fails. Only valid if the mission is handled by a LEGION (AIRWING, BRIGADE, FLEET) or higher level.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param #number Nrepeat Number of repeats. Default 0.
|
-- @param #number Nrepeat Number of repeats. Default 0.
|
||||||
@@ -3481,7 +3538,7 @@ end
|
|||||||
|
|
||||||
--- Set Rules of Engagement (ROE) for this mission.
|
--- Set Rules of Engagement (ROE) for this mission.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param #string roe Mission ROE.
|
-- @param #number roe Mission ROE, e.g. `ENUMS.ROE.ReturnFire` (whiche equals 3)
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
function AUFTRAG:SetROE(roe)
|
function AUFTRAG:SetROE(roe)
|
||||||
|
|
||||||
@@ -3493,7 +3550,7 @@ end
|
|||||||
|
|
||||||
--- Set Reaction on Threat (ROT) for this mission.
|
--- Set Reaction on Threat (ROT) for this mission.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param #string rot Mission ROT.
|
-- @param #number rot Mission ROT, e.g. `ENUMS.ROT.NoReaction` (whiche equals 0)
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
function AUFTRAG:SetROT(rot)
|
function AUFTRAG:SetROT(rot)
|
||||||
|
|
||||||
@@ -4657,6 +4714,16 @@ function AUFTRAG:SetGroupWaypointCoordinate(opsgroup, coordinate)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [Air] Set mission (ingress) waypoint coordinate for FLIGHT group.
|
||||||
|
-- @param #AUFTRAG self
|
||||||
|
-- @param Core.Point#COORDINATE coordinate Waypoint Coordinate.
|
||||||
|
-- @return #AUFTRAG self
|
||||||
|
function AUFTRAG:SetIngressCoordinate(coordinate)
|
||||||
|
self.missionIngressCoord = coordinate
|
||||||
|
self.missionIngressCoordAlt = UTILS.MetersToFeet(coordinate.y) or 10000
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Get mission (ingress) waypoint coordinate of OPS group
|
--- Get mission (ingress) waypoint coordinate of OPS group
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param Ops.OpsGroup#OPSGROUP opsgroup The OPS group.
|
-- @param Ops.OpsGroup#OPSGROUP opsgroup The OPS group.
|
||||||
@@ -4747,6 +4814,8 @@ end
|
|||||||
-- @return #boolean If `true`, all groups are done with the mission.
|
-- @return #boolean If `true`, all groups are done with the mission.
|
||||||
function AUFTRAG:CheckGroupsDone()
|
function AUFTRAG:CheckGroupsDone()
|
||||||
|
|
||||||
|
local fsmState = self:GetState()
|
||||||
|
|
||||||
-- Check status of all OPS groups.
|
-- Check status of all OPS groups.
|
||||||
for groupname,data in pairs(self.groupdata) do
|
for groupname,data in pairs(self.groupdata) do
|
||||||
local groupdata=data --#AUFTRAG.GroupData
|
local groupdata=data --#AUFTRAG.GroupData
|
||||||
@@ -4804,6 +4873,11 @@ function AUFTRAG:CheckGroupsDone()
|
|||||||
self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] but count of alive OPSGROUP is zero. Mission DONE!", self.status, self:GetState()))
|
self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] but count of alive OPSGROUP is zero. Mission DONE!", self.status, self:GetState()))
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if (self:IsStarted() or self:IsExecuting()) and (fsmState == AUFTRAG.Status.STARTED or fsmState == AUFTRAG.Status.EXECUTING) and self:CountOpsGroups()>0 then
|
||||||
|
self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] and count of alive OPSGROUP > zero. Mission NOT DONE!", self.status, self:GetState()))
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -5142,7 +5216,7 @@ function AUFTRAG:onafterSuccess(From, Event, To)
|
|||||||
|
|
||||||
-- Repeat mission.
|
-- Repeat mission.
|
||||||
self:T(self.lid..string.format("Mission SUCCESS! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N))
|
self:T(self.lid..string.format("Mission SUCCESS! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N))
|
||||||
self:Repeat()
|
self:__Repeat(self.repeatDelay)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@@ -5184,7 +5258,7 @@ function AUFTRAG:onafterFailed(From, Event, To)
|
|||||||
|
|
||||||
-- Repeat mission.
|
-- Repeat mission.
|
||||||
self:T(self.lid..string.format("Mission FAILED! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N))
|
self:T(self.lid..string.format("Mission FAILED! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N))
|
||||||
self:Repeat()
|
self:__Repeat(self.repeatDelay)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@@ -5712,7 +5786,7 @@ function AUFTRAG:GetMissionTypesText(MissionTypes)
|
|||||||
return text
|
return text
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the mission waypoint coordinate where the mission is executed. Note that altitude is set via `:SetMissionAltitude`.
|
--- [NON-AIR] Set the mission waypoint coordinate from where the mission is executed. Note that altitude is set via `:SetMissionAltitude`.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param Core.Point#COORDINATE Coordinate Coordinate where the mission is executed.
|
-- @param Core.Point#COORDINATE Coordinate Coordinate where the mission is executed.
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
@@ -5740,8 +5814,9 @@ end
|
|||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param Core.Point#COORDINATE Coordinate Egrees coordinate.
|
-- @param Core.Point#COORDINATE Coordinate Egrees coordinate.
|
||||||
-- @param #number Altitude (Optional) Altitude in feet. Default is y component of coordinate.
|
-- @param #number Altitude (Optional) Altitude in feet. Default is y component of coordinate.
|
||||||
|
-- @param #number Speed (Optional) Speed in knots to reach this waypoint. Defaults to mission speed.
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
function AUFTRAG:SetMissionEgressCoord(Coordinate, Altitude)
|
function AUFTRAG:SetMissionEgressCoord(Coordinate, Altitude, Speed)
|
||||||
|
|
||||||
-- Obviously a zone was passed. We get the coordinate.
|
-- Obviously a zone was passed. We get the coordinate.
|
||||||
if Coordinate:IsInstanceOf("ZONE_BASE") then
|
if Coordinate:IsInstanceOf("ZONE_BASE") then
|
||||||
@@ -5752,7 +5827,64 @@ function AUFTRAG:SetMissionEgressCoord(Coordinate, Altitude)
|
|||||||
|
|
||||||
if Altitude then
|
if Altitude then
|
||||||
self.missionEgressCoord.y=UTILS.FeetToMeters(Altitude)
|
self.missionEgressCoord.y=UTILS.FeetToMeters(Altitude)
|
||||||
|
self.missionEgressCoordAlt = UTILS.FeetToMeters(Altitude)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.missionEgressCoordSpeed=Speed and Speed or nil
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Air] Set the mission ingress coordinate. This is the coordinate where the assigned group will fly before the actual mission coordinate.
|
||||||
|
-- @param #AUFTRAG self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Ingrees coordinate.
|
||||||
|
-- @param #number Altitude (Optional) Altitude in feet. Default is y component of coordinate.
|
||||||
|
-- @param #number Speed (Optional) Speed in knots to reach this waypoint. Defaults to mission speed.
|
||||||
|
-- @return #AUFTRAG self
|
||||||
|
function AUFTRAG:SetMissionIngressCoord(Coordinate, Altitude, Speed)
|
||||||
|
|
||||||
|
-- Obviously a zone was passed. We get the coordinate.
|
||||||
|
if Coordinate:IsInstanceOf("ZONE_BASE") then
|
||||||
|
Coordinate=Coordinate:GetCoordinate()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.missionIngressCoord=Coordinate
|
||||||
|
|
||||||
|
if Altitude then
|
||||||
|
self.missionIngressCoord.y=UTILS.FeetToMeters(Altitude)
|
||||||
|
self.missionIngressCoordAlt = UTILS.FeetToMeters(Altitude or 10000)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.missionIngressCoordSpeed=Speed and Speed or nil
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Air] Set the mission holding coordinate. This is the coordinate where the assigned group will fly before the actual mission execution starts. Do not forget to add a push condition, too!
|
||||||
|
-- @param #AUFTRAG self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Holding coordinate.
|
||||||
|
-- @param #number Altitude (Optional) Altitude in feet. Default is y component of coordinate.
|
||||||
|
-- @param #number Speed (Optional) Speed in knots to reach this waypoint and hold there. Defaults to mission speed.
|
||||||
|
-- @param #number Duration (Optional) Duration in seconds on how long to hold, defaults to 15 minutes. Mission continues if either a push condition is met or the time is up.
|
||||||
|
-- @return #AUFTRAG self
|
||||||
|
function AUFTRAG:SetMissionHoldingCoord(Coordinate, Altitude, Speed, Duration)
|
||||||
|
|
||||||
|
-- Obviously a zone was passed. We get the coordinate.
|
||||||
|
if Coordinate:IsInstanceOf("ZONE_BASE") then
|
||||||
|
Coordinate=Coordinate:GetCoordinate()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.missionHoldingCoord=Coordinate
|
||||||
|
self.missionHoldingDuration=Duration or 900
|
||||||
|
|
||||||
|
if Altitude then
|
||||||
|
self.missionHoldingCoord.y=UTILS.FeetToMeters(Altitude)
|
||||||
|
self.missionHoldingCoordAlt = UTILS.FeetToMeters(Altitude or 10000)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.missionHoldingCoordSpeed=Speed and Speed or nil
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the mission egress coordinate if this was defined.
|
--- Get the mission egress coordinate if this was defined.
|
||||||
@@ -5762,6 +5894,20 @@ function AUFTRAG:GetMissionEgressCoord()
|
|||||||
return self.missionEgressCoord
|
return self.missionEgressCoord
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the mission ingress coordinate if this was defined.
|
||||||
|
-- @param #AUFTRAG self
|
||||||
|
-- @return Core.Point#COORDINATE Coordinate Coordinate or nil.
|
||||||
|
function AUFTRAG:GetMissionIngressCoord()
|
||||||
|
return self.missionIngressCoord
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the mission holding coordinate if this was defined.
|
||||||
|
-- @param #AUFTRAG self
|
||||||
|
-- @return Core.Point#COORDINATE Coordinate Coordinate or nil.
|
||||||
|
function AUFTRAG:GetMissionHoldingCoord()
|
||||||
|
return self.missionHoldingCoord
|
||||||
|
end
|
||||||
|
|
||||||
--- Get coordinate which was set as mission waypoint coordinate.
|
--- Get coordinate which was set as mission waypoint coordinate.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @return Core.Point#COORDINATE Coordinate where the mission is executed or `#nil`.
|
-- @return Core.Point#COORDINATE Coordinate where the mission is executed or `#nil`.
|
||||||
@@ -5796,10 +5942,27 @@ function AUFTRAG:GetMissionWaypointCoord(group, randomradius, surfacetypes)
|
|||||||
end
|
end
|
||||||
return coord
|
return coord
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local coord=group:GetCoordinate()
|
||||||
|
|
||||||
|
-- Check if an ingress or holding coord has been explicitly set.
|
||||||
|
if self.missionHoldingCoord then
|
||||||
|
coord=self.missionHoldingCoord
|
||||||
|
if self.missionHoldingCoorddAlt then
|
||||||
|
coord:SetAltitude(self.missionHoldingCoordAlt, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.missionIngressCoord then
|
||||||
|
coord=self.missionIngressCoord
|
||||||
|
if self.missionIngressCoordAlt then
|
||||||
|
coord:SetAltitude(self.missionIngressCoordAlt, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Create waypoint coordinate half way between us and the target.
|
-- Create waypoint coordinate half way between us and the target.
|
||||||
local waypointcoord=COORDINATE:New(0,0,0)
|
local waypointcoord=COORDINATE:New(0,0,0)
|
||||||
local coord=group:GetCoordinate()
|
|
||||||
if coord then
|
if coord then
|
||||||
waypointcoord=coord:GetIntermediateCoordinate(self:GetTargetCoordinate(), self.missionFraction)
|
waypointcoord=coord:GetIntermediateCoordinate(self:GetTargetCoordinate(), self.missionFraction)
|
||||||
else
|
else
|
||||||
@@ -6001,10 +6164,13 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
-- BOMBING Mission --
|
-- BOMBING Mission --
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
local DCStask=CONTROLLABLE.TaskBombing(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, Divebomb)
|
local coords = self.engageTarget:GetCoordinates()
|
||||||
|
for _, coord in pairs(coords) do
|
||||||
|
local DCStask = CONTROLLABLE.TaskBombing(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, self.optionDivebomb)
|
||||||
|
|
||||||
|
table.insert(DCStasks, DCStask)
|
||||||
|
end
|
||||||
|
|
||||||
table.insert(DCStasks, DCStask)
|
|
||||||
|
|
||||||
elseif self.type==AUFTRAG.Type.STRAFING then
|
elseif self.type==AUFTRAG.Type.STRAFING then
|
||||||
|
|
||||||
----------------------
|
----------------------
|
||||||
@@ -6040,8 +6206,16 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
-----------------
|
-----------------
|
||||||
-- CAP Mission --
|
-- CAP Mission --
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(nil, self.engageZone:GetVec2(), self.engageZone:GetRadius(), self.engageTargetTypes, Priority)
|
local Vec2 = self.engageZone:GetVec2()
|
||||||
|
local Radius
|
||||||
|
if self.engageZone:IsInstanceOf("COORDINATE") then
|
||||||
|
Radius = UTILS.NMToMeters(20)
|
||||||
|
else
|
||||||
|
Radius = self.engageZone:GetRadius()
|
||||||
|
end
|
||||||
|
|
||||||
|
local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(nil, Vec2, Radius, self.engageTargetTypes, Priority)
|
||||||
|
|
||||||
table.insert(self.enrouteTasks, DCStask)
|
table.insert(self.enrouteTasks, DCStask)
|
||||||
|
|
||||||
@@ -6099,7 +6273,7 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
local param={}
|
local param={}
|
||||||
param.zone=self:GetObjective()
|
param.zone=self:GetObjective()
|
||||||
param.altitude=self.missionAltitude
|
param.altitude=self.missionAltitude
|
||||||
param.speed=self.missionSpeed
|
param.speed=self.missionSpeed and UTILS.KmphToMps(self.missionSpeed) or nil
|
||||||
|
|
||||||
DCStask.params=param
|
DCStask.params=param
|
||||||
|
|
||||||
@@ -6179,7 +6353,7 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
local param={}
|
local param={}
|
||||||
param.target=self.engageTarget
|
param.target=self.engageTarget
|
||||||
param.altitude=self.missionAltitude
|
param.altitude=self.missionAltitude
|
||||||
param.speed=self.missionSpeed
|
param.speed=self.missionSpeed and UTILS.KmphToMps(self.missionSpeed) or nil
|
||||||
param.lastindex=nil
|
param.lastindex=nil
|
||||||
|
|
||||||
DCStask.params=param
|
DCStask.params=param
|
||||||
@@ -6195,18 +6369,47 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
-- Add enroute task SEAD. Disabled that here because the group enganges everything on its route.
|
-- Add enroute task SEAD. Disabled that here because the group enganges everything on its route.
|
||||||
--local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.TargetType)
|
--local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.TargetType)
|
||||||
--table.insert(self.enrouteTasks, DCStask)
|
--table.insert(self.enrouteTasks, DCStask)
|
||||||
|
|
||||||
self:_GetDCSAttackTask(self.engageTarget, DCStasks)
|
if self.engageZone then
|
||||||
|
|
||||||
|
--local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.engageTargetTypes)
|
||||||
|
--table.insert(self.enrouteTasks, DCStask)
|
||||||
|
self.engageZone:Scan({Object.Category.UNIT},{Unit.Category.GROUND_UNIT})
|
||||||
|
local ScanUnitSet = self.engageZone:GetScannedSetUnit()
|
||||||
|
local SeadUnitSet = SET_UNIT:New()
|
||||||
|
for _,_unit in pairs (ScanUnitSet.Set) do
|
||||||
|
local unit = _unit -- Wrapper.Unit#UNTI
|
||||||
|
if unit and unit:IsAlive() and unit:HasSEAD() then
|
||||||
|
self:T("Adding UNIT for SEAD: "..unit:GetName())
|
||||||
|
local task = CONTROLLABLE.TaskAttackUnit(nil,unit,GroupAttack,AI.Task.WeaponExpend.ALL,1,Direction,self.engageAltitude,2956984318)
|
||||||
|
table.insert(DCStasks, task)
|
||||||
|
SeadUnitSet:AddUnit(unit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.engageTarget = TARGET:New(SeadUnitSet)
|
||||||
|
--local OrbitTask = CONTROLLABLE.TaskOrbitCircle(nil,self.engageAltitude,self.missionSpeed,self.engageZone:GetCoordinate())
|
||||||
|
--local Point = self.engageZone:GetVec2()
|
||||||
|
--local OrbitTask = CONTROLLABLE.TaskOrbitCircleAtVec2(nil,Point,self.engageAltitude,self.missionSpeed)
|
||||||
|
--table.insert(DCStasks, OrbitTask)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
self:_GetDCSAttackTask(self.engageTarget, DCStasks)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
elseif self.type==AUFTRAG.Type.STRIKE then
|
elseif self.type==AUFTRAG.Type.STRIKE then
|
||||||
|
|
||||||
--------------------
|
--------------------
|
||||||
-- STRIKE Mission --
|
-- STRIKE Mission --
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType)
|
local coords = self.engageTarget:GetCoordinates()
|
||||||
|
for _, coord in pairs(coords) do
|
||||||
|
local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType)
|
||||||
|
|
||||||
table.insert(DCStasks, DCStask)
|
table.insert(DCStasks, DCStask)
|
||||||
|
end
|
||||||
|
|
||||||
elseif self.type==AUFTRAG.Type.TANKER or self.type==AUFTRAG.Type.RECOVERYTANKER then
|
elseif self.type==AUFTRAG.Type.TANKER or self.type==AUFTRAG.Type.RECOVERYTANKER then
|
||||||
|
|
||||||
@@ -6352,7 +6555,7 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
local param={}
|
local param={}
|
||||||
param.zone=self:GetObjective()
|
param.zone=self:GetObjective()
|
||||||
param.altitude=self.missionAltitude
|
param.altitude=self.missionAltitude
|
||||||
param.speed=self.missionSpeed
|
param.speed=self.missionSpeed and UTILS.KmphToMps(self.missionSpeed) or nil
|
||||||
|
|
||||||
DCStask.params=param
|
DCStask.params=param
|
||||||
|
|
||||||
@@ -6388,7 +6591,7 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
local param={}
|
local param={}
|
||||||
param.zone=self:GetObjective()
|
param.zone=self:GetObjective()
|
||||||
param.altitude=self.missionAltitude
|
param.altitude=self.missionAltitude
|
||||||
param.speed=self.missionSpeed
|
param.speed=self.missionSpeed and UTILS.KmphToMps(self.missionSpeed) or nil
|
||||||
|
|
||||||
DCStask.params=param
|
DCStask.params=param
|
||||||
|
|
||||||
@@ -6408,7 +6611,7 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
local param={}
|
local param={}
|
||||||
param.target=self:GetTargetData()
|
param.target=self:GetTargetData()
|
||||||
param.action="Wedge"
|
param.action="Wedge"
|
||||||
param.speed=self.missionSpeed
|
param.speed=self.missionSpeed and UTILS.KmphToMps(self.missionSpeed) or nil
|
||||||
|
|
||||||
DCStask.params=param
|
DCStask.params=param
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **applevangelist**
|
-- ### Author: **applevangelist**
|
||||||
-- @date Last Update July 2024
|
-- @date Last Update July 2025
|
||||||
-- @module Ops.AWACS
|
-- @module Ops.AWACS
|
||||||
-- @image OPS_AWACS.jpg
|
-- @image OPS_AWACS.jpg
|
||||||
|
|
||||||
@@ -122,6 +122,7 @@ do
|
|||||||
-- @field #number TacticalModulation
|
-- @field #number TacticalModulation
|
||||||
-- @field #number TacticalInterval
|
-- @field #number TacticalInterval
|
||||||
-- @field Core.Set#SET_GROUP DetectionSet
|
-- @field Core.Set#SET_GROUP DetectionSet
|
||||||
|
-- @field #number MaxMissionRange
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
@@ -183,7 +184,7 @@ do
|
|||||||
--
|
--
|
||||||
-- Add Escorts Squad (recommended, optional)
|
-- Add Escorts Squad (recommended, optional)
|
||||||
--
|
--
|
||||||
-- local Squad_Two = SQUADRON:New("Escorts",4,"Escorts North")
|
-- local Squad_Two = SQUADRON:New("Escorts",4,"Escorts North") -- taking a template with 2 planes here, will result in a group of 2 escorts which can fly in formation escorting the AWACS.
|
||||||
-- Squad_Two:AddMissionCapability({AUFTRAG.Type.ESCORT})
|
-- Squad_Two:AddMissionCapability({AUFTRAG.Type.ESCORT})
|
||||||
-- Squad_Two:SetFuelLowRefuel(true)
|
-- Squad_Two:SetFuelLowRefuel(true)
|
||||||
-- Squad_Two:SetFuelLowThreshold(0.3)
|
-- Squad_Two:SetFuelLowThreshold(0.3)
|
||||||
@@ -231,12 +232,12 @@ do
|
|||||||
-- -- set up in the mission editor with a late activated helo named "Rock#ZONE_POLYGON". Note this also sets the BullsEye to be referenced as "Rock".
|
-- -- set up in the mission editor with a late activated helo named "Rock#ZONE_POLYGON". Note this also sets the BullsEye to be referenced as "Rock".
|
||||||
-- -- The CAP station zone is called "Fremont". We will be on 255 AM.
|
-- -- The CAP station zone is called "Fremont". We will be on 255 AM.
|
||||||
-- local testawacs = AWACS:New("AWACS North",AwacsAW,"blue",AIRBASE.Caucasus.Kutaisi,"Awacs Orbit",ZONE:FindByName("Rock"),"Fremont",255,radio.modulation.AM )
|
-- local testawacs = AWACS:New("AWACS North",AwacsAW,"blue",AIRBASE.Caucasus.Kutaisi,"Awacs Orbit",ZONE:FindByName("Rock"),"Fremont",255,radio.modulation.AM )
|
||||||
-- -- set two escorts
|
-- -- set one escort group; this example has two units in the template group, so they can fly a nice formation.
|
||||||
-- testawacs:SetEscort(2)
|
-- testawacs:SetEscort(1,ENUMS.Formation.FixedWing.FingerFour.Group,{x=-500,y=50,z=500},45)
|
||||||
-- -- Callsign will be "Focus". We'll be a Angels 30, doing 300 knots, orbit leg to 88deg with a length of 25nm.
|
-- -- Callsign will be "Focus". We'll be a Angels 30, doing 300 knots, orbit leg to 88deg with a length of 25nm.
|
||||||
-- testawacs:SetAwacsDetails(CALLSIGN.AWACS.Focus,1,30,300,88,25)
|
-- testawacs:SetAwacsDetails(CALLSIGN.AWACS.Focus,1,30,300,88,25)
|
||||||
-- -- Set up SRS on port 5010 - change the below to your path and port
|
-- -- Set up SRS on port 5010 - change the below to your path and port
|
||||||
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone","female","en-GB",5010)
|
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio","female","en-GB",5010)
|
||||||
-- -- Add a "red" border we don't want to cross, set up in the mission editor with a late activated helo named "Red Border#ZONE_POLYGON"
|
-- -- Add a "red" border we don't want to cross, set up in the mission editor with a late activated helo named "Red Border#ZONE_POLYGON"
|
||||||
-- testawacs:SetRejectionZone(ZONE:FindByName("Red Border"))
|
-- testawacs:SetRejectionZone(ZONE:FindByName("Red Border"))
|
||||||
-- -- Our CAP flight will have the callsign "Ford", we want 4 AI planes, Time-On-Station is four hours, doing 300 kn IAS.
|
-- -- Our CAP flight will have the callsign "Ford", we want 4 AI planes, Time-On-Station is four hours, doing 300 kn IAS.
|
||||||
@@ -254,7 +255,7 @@ do
|
|||||||
-- -- The CAP station zone is called "Fremont". We will be on 255 AM. Note the Orbit Zone is given as *nil* in the `New()`-Statement
|
-- -- The CAP station zone is called "Fremont". We will be on 255 AM. Note the Orbit Zone is given as *nil* in the `New()`-Statement
|
||||||
-- local testawacs = AWACS:New("GCI Senaki",AwacsAW,"blue",AIRBASE.Caucasus.Senaki_Kolkhi,nil,ZONE:FindByName("Rock"),"Fremont",255,radio.modulation.AM )
|
-- local testawacs = AWACS:New("GCI Senaki",AwacsAW,"blue",AIRBASE.Caucasus.Senaki_Kolkhi,nil,ZONE:FindByName("Rock"),"Fremont",255,radio.modulation.AM )
|
||||||
-- -- Set up SRS on port 5010 - change the below to your path and port
|
-- -- Set up SRS on port 5010 - change the below to your path and port
|
||||||
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone","female","en-GB",5010)
|
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio","female","en-GB",5010)
|
||||||
-- -- Add a "red" border we don't want to cross, set up in the mission editor with a late activated helo named "Red Border#ZONE_POLYGON"
|
-- -- Add a "red" border we don't want to cross, set up in the mission editor with a late activated helo named "Red Border#ZONE_POLYGON"
|
||||||
-- testawacs:SetRejectionZone(ZONE:FindByName("Red Border"))
|
-- testawacs:SetRejectionZone(ZONE:FindByName("Red Border"))
|
||||||
-- -- Our CAP flight will have the callsign "Ford", we want 4 AI planes, Time-On-Station is four hours, doing 300 kn IAS.
|
-- -- Our CAP flight will have the callsign "Ford", we want 4 AI planes, Time-On-Station is four hours, doing 300 kn IAS.
|
||||||
@@ -508,7 +509,7 @@ do
|
|||||||
-- @field #AWACS
|
-- @field #AWACS
|
||||||
AWACS = {
|
AWACS = {
|
||||||
ClassName = "AWACS", -- #string
|
ClassName = "AWACS", -- #string
|
||||||
version = "0.2.65", -- #string
|
version = "0.2.72", -- #string
|
||||||
lid = "", -- #string
|
lid = "", -- #string
|
||||||
coalition = coalition.side.BLUE, -- #number
|
coalition = coalition.side.BLUE, -- #number
|
||||||
coalitiontxt = "blue", -- #string
|
coalitiontxt = "blue", -- #string
|
||||||
@@ -605,6 +606,7 @@ AWACS = {
|
|||||||
TacticalModulation = radio.modulation.AM,
|
TacticalModulation = radio.modulation.AM,
|
||||||
TacticalInterval = 120,
|
TacticalInterval = 120,
|
||||||
DetectionSet = nil,
|
DetectionSet = nil,
|
||||||
|
MaxMissionRange = 125,
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -1121,7 +1123,7 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
|||||||
self.EscortMissionReplacement = {}
|
self.EscortMissionReplacement = {}
|
||||||
|
|
||||||
-- SRS
|
-- SRS
|
||||||
self.PathToSRS = "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
self.PathToSRS = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||||
self.Gender = "female"
|
self.Gender = "female"
|
||||||
self.Culture = "en-GB"
|
self.Culture = "en-GB"
|
||||||
self.Voice = nil
|
self.Voice = nil
|
||||||
@@ -1240,6 +1242,8 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
|||||||
self:AddTransition("*", "Intercept", "*")
|
self:AddTransition("*", "Intercept", "*")
|
||||||
self:AddTransition("*", "InterceptSuccess", "*")
|
self:AddTransition("*", "InterceptSuccess", "*")
|
||||||
self:AddTransition("*", "InterceptFailure", "*")
|
self:AddTransition("*", "InterceptFailure", "*")
|
||||||
|
self:AddTransition("*", "VIDSuccess", "*")
|
||||||
|
self:AddTransition("*", "VIDFailure", "*")
|
||||||
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
||||||
|
|
||||||
|
|
||||||
@@ -1363,18 +1367,38 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
|
|
||||||
--- On After "InterceptSuccess" event. Intercept successful.
|
--- On After "InterceptSuccess" event. Intercept successful.
|
||||||
-- @function [parent=#AWACS] OnAfterIntercept
|
-- @function [parent=#AWACS] OnAfterInterceptSuccess
|
||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
|
|
||||||
--- On After "InterceptFailure" event. Intercept failure.
|
--- On After "InterceptFailure" event. Intercept failure.
|
||||||
-- @function [parent=#AWACS] OnAfterIntercept
|
-- @function [parent=#AWACS] OnAfterInterceptFailure
|
||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
|
|
||||||
|
--- On After "VIDSuccess" event. Intercept successful.
|
||||||
|
-- @function [parent=#AWACS] OnAfterVIDSuccess
|
||||||
|
-- @param #AWACS self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #number GID Managed group ID (Player)
|
||||||
|
-- @param Wrapper.Group#GROUP Group (Player) Group done the VID
|
||||||
|
-- @param #AWACS.ManagedContact Contact The contact that was VID'd
|
||||||
|
|
||||||
|
--- On After "VIDFailure" event. Intercept failure.
|
||||||
|
-- @function [parent=#AWACS] OnAfterVIDFailure
|
||||||
|
-- @param #AWACS self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #number GID Managed group ID (Player)
|
||||||
|
-- @param Wrapper.Group#GROUP Group (Player) Group done the VID
|
||||||
|
-- @param #AWACS.ManagedContact Contact The contact that was VID'd
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1572,6 +1596,15 @@ function AWACS:SetLocale(Locale)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Set the max mission range flights can be away from their home base.
|
||||||
|
-- @param #AWACS self
|
||||||
|
-- @param #number NM Distance in nautical miles
|
||||||
|
-- @return #AWACS self
|
||||||
|
function AWACS:SetMaxMissionRange(NM)
|
||||||
|
self.MaxMissionRange = NM or 125
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [User] Add additional frequency and modulation for AWACS SRS output.
|
--- [User] Add additional frequency and modulation for AWACS SRS output.
|
||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param #number Frequency The frequency to add, e.g. 132.5
|
-- @param #number Frequency The frequency to add, e.g. 132.5
|
||||||
@@ -1762,7 +1795,7 @@ function AWACS:_EventHandler(EventData)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if Event.id == EVENTS.PlayerLeaveUnit then --player left unit
|
if Event.id == EVENTS.PlayerLeaveUnit and Event.IniGroupName then --player left unit
|
||||||
-- check known player?
|
-- check known player?
|
||||||
self:T("Player group left unit: " .. Event.IniGroupName)
|
self:T("Player group left unit: " .. Event.IniGroupName)
|
||||||
self:T("Player name left: " .. Event.IniPlayerName)
|
self:T("Player name left: " .. Event.IniPlayerName)
|
||||||
@@ -2080,7 +2113,7 @@ end
|
|||||||
|
|
||||||
--- [User] Set AWACS SRS TTS details - see @{Sound.SRS} for details. `SetSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible.
|
--- [User] Set AWACS SRS TTS details - see @{Sound.SRS} for details. `SetSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible.
|
||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||||
-- @param #string Gender Defaults to "male"
|
-- @param #string Gender Defaults to "male"
|
||||||
-- @param #string Culture Defaults to "en-US"
|
-- @param #string Culture Defaults to "en-US"
|
||||||
-- @param #number Port Defaults to 5002
|
-- @param #number Port Defaults to 5002
|
||||||
@@ -2093,7 +2126,7 @@ end
|
|||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Backend)
|
function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Backend)
|
||||||
self:T(self.lid.."SetSRS")
|
self:T(self.lid.."SetSRS")
|
||||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||||
self.Gender = Gender or MSRS.gender or "male"
|
self.Gender = Gender or MSRS.gender or "male"
|
||||||
self.Culture = Culture or MSRS.culture or "en-US"
|
self.Culture = Culture or MSRS.culture or "en-US"
|
||||||
self.Port = Port or MSRS.port or 5002
|
self.Port = Port or MSRS.port or 5002
|
||||||
@@ -2158,9 +2191,12 @@ end
|
|||||||
|
|
||||||
--- [User] Set AWACS Escorts Template
|
--- [User] Set AWACS Escorts Template
|
||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param #number EscortNumber Number of fighther planes to accompany this AWACS. 0 or nil means no escorts.
|
-- @param #number EscortNumber Number of fighther plane GROUPs to accompany this AWACS. 0 or nil means no escorts. If you want >1 plane in an escort group, you can either set the respective squadron grouping to the desired number, or use a template for escorts with >1 unit.
|
||||||
|
-- @param #number Formation Formation the escort should take (if more than one plane), e.g. `ENUMS.Formation.FixedWing.FingerFour.Group`. Formation is used on GROUP level, multiple groups of one unit will NOT conform to this formation.
|
||||||
|
-- @param #table OffsetVector Offset the escorts should fly behind the AWACS, given as table, distance in meters, e.g. `{x=-500,y=0,z=500}` - 500m behind (negative value) and to the right (negative for left), no vertical separation (positive over, negative under the AWACS flight). For multiple groups, the vectors will be slightly changed to avoid collisions.
|
||||||
|
-- @param #number EscortEngageMaxDistance Escorts engage air targets max this NM away, defaults to 45NM.
|
||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:SetEscort(EscortNumber)
|
function AWACS:SetEscort(EscortNumber,Formation,OffsetVector,EscortEngageMaxDistance)
|
||||||
self:T(self.lid.."SetEscort")
|
self:T(self.lid.."SetEscort")
|
||||||
if EscortNumber and EscortNumber > 0 then
|
if EscortNumber and EscortNumber > 0 then
|
||||||
self.HasEscorts = true
|
self.HasEscorts = true
|
||||||
@@ -2169,6 +2205,9 @@ function AWACS:SetEscort(EscortNumber)
|
|||||||
self.HasEscorts = false
|
self.HasEscorts = false
|
||||||
self.EscortNumber = 0
|
self.EscortNumber = 0
|
||||||
end
|
end
|
||||||
|
self.EscortFormation = Formation
|
||||||
|
self.OffsetVec = OffsetVector or {x=500,y=100,z=500}
|
||||||
|
self.EscortEngageMaxDistance = EscortEngageMaxDistance or 45
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2223,11 +2262,26 @@ function AWACS:_StartEscorts(Shiftchange)
|
|||||||
local group = AwacsFG:GetGroup()
|
local group = AwacsFG:GetGroup()
|
||||||
|
|
||||||
local timeonstation = (self.EscortsTimeOnStation + self.ShiftChangeTime) * 3600 -- hours to seconds
|
local timeonstation = (self.EscortsTimeOnStation + self.ShiftChangeTime) * 3600 -- hours to seconds
|
||||||
|
local OffsetX = 500
|
||||||
|
local OffsetY = 500
|
||||||
|
local OffsetZ = 500
|
||||||
|
if self.OffsetVec then
|
||||||
|
OffsetX = self.OffsetVec.x or 500
|
||||||
|
OffsetY = self.OffsetVec.y or 500
|
||||||
|
OffsetZ = self.OffsetVec.z or 500
|
||||||
|
end
|
||||||
|
|
||||||
for i=1,self.EscortNumber do
|
for i=1,self.EscortNumber do
|
||||||
-- every
|
-- every
|
||||||
local escort = AUFTRAG:NewESCORT(group, {x= -100*((i + (i%2))/2), y=0, z=(100 + 100*((i + (i%2))/2))*(-1)^i},45,{"Air"})
|
local escort = AUFTRAG:NewESCORT(group, {x= OffsetX*((i + (i%2))/2), y=OffsetY*((i + (i%2))/2), z=(OffsetZ + OffsetZ*((i + (i%2))/2))*(-1)^i},self.EscortEngageMaxDistance,{"Air"})
|
||||||
escort:SetRequiredAssets(1)
|
--local escort = AUFTRAG:NewESCORT(group,self.OffsetVec,self.EscortEngageMaxDistance,{"Air"})
|
||||||
|
--escort:SetRequiredAssets(self.EscortNumber)
|
||||||
escort:SetTime(nil,timeonstation)
|
escort:SetTime(nil,timeonstation)
|
||||||
|
if self.Escortformation then
|
||||||
|
escort:SetFormation(self.Escortformation)
|
||||||
|
end
|
||||||
|
escort:SetMissionRange(self.MaxMissionRange)
|
||||||
|
|
||||||
self.AirWing:AddMission(escort)
|
self.AirWing:AddMission(escort)
|
||||||
self.CatchAllMissions[#self.CatchAllMissions+1] = escort
|
self.CatchAllMissions[#self.CatchAllMissions+1] = escort
|
||||||
|
|
||||||
@@ -2434,7 +2488,7 @@ function AWACS:_GetCallSign(Group,GID, IsPlayer)
|
|||||||
|
|
||||||
local callsign = "Ghost 1"
|
local callsign = "Ghost 1"
|
||||||
if Group and Group:IsAlive() then
|
if Group and Group:IsAlive() then
|
||||||
callsign = Group:GetCustomCallSign(self.callsignshort,self.keepnumber,self.callsignTranslations)
|
callsign = Group:GetCustomCallSign(self.callsignshort,self.keepnumber,self.callsignTranslations,self.callsignCustomFunc,self.callsignCustomArgs)
|
||||||
end
|
end
|
||||||
return callsign
|
return callsign
|
||||||
end
|
end
|
||||||
@@ -2443,10 +2497,12 @@ end
|
|||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param #boolean ShortCallsign If true, only call out the major flight number
|
-- @param #boolean ShortCallsign If true, only call out the major flight number
|
||||||
-- @param #boolean Keepnumber If true, keep the **customized callsign** in the #GROUP name as-is, no amendments or numbers.
|
-- @param #boolean Keepnumber If true, keep the **customized callsign** in the #GROUP name as-is, no amendments or numbers.
|
||||||
-- @param #table CallsignTranslations (optional) Table to translate between DCS standard callsigns and bespoke ones. Does not apply if using customized
|
-- @param #table CallsignTranslations (Optional) Table to translate between DCS standard callsigns and bespoke ones. Does not apply if using customized.
|
||||||
-- callsigns from playername or group name.
|
-- callsigns from playername or group name.
|
||||||
|
-- @param #func CallsignCustomFunc (Optional) For player names only(!). If given, this function will return the callsign. Needs to take the groupname and the playername as first two arguments.
|
||||||
|
-- @param #arg ... (Optional) Comma separated arguments to add to the custom function call after groupname and playername.
|
||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTranslations)
|
function AWACS:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTranslations,CallsignCustomFunc,...)
|
||||||
if not ShortCallsign or ShortCallsign == false then
|
if not ShortCallsign or ShortCallsign == false then
|
||||||
self.callsignshort = false
|
self.callsignshort = false
|
||||||
else
|
else
|
||||||
@@ -2454,6 +2510,8 @@ function AWACS:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTranslations)
|
|||||||
end
|
end
|
||||||
self.keepnumber = Keepnumber or false
|
self.keepnumber = Keepnumber or false
|
||||||
self.callsignTranslations = CallsignTranslations
|
self.callsignTranslations = CallsignTranslations
|
||||||
|
self.callsignCustomFunc = CallsignCustomFunc
|
||||||
|
self.callsignCustomArgs = arg or {}
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3227,12 +3285,14 @@ function AWACS:_VID(Group,Declaration)
|
|||||||
local vidpos = self.gettext:GetEntry("VIDPOS",self.locale)
|
local vidpos = self.gettext:GetEntry("VIDPOS",self.locale)
|
||||||
text = string.format(vidpos,Callsign,self.callsigntxt, Declaration)
|
text = string.format(vidpos,Callsign,self.callsigntxt, Declaration)
|
||||||
self:T(text)
|
self:T(text)
|
||||||
|
self:__VIDSuccess(3,GID,group,cluster)
|
||||||
else
|
else
|
||||||
-- too far away
|
-- too far away
|
||||||
self:T("Contact VID not close enough")
|
self:T("Contact VID not close enough")
|
||||||
local vidneg = self.gettext:GetEntry("VIDNEG",self.locale)
|
local vidneg = self.gettext:GetEntry("VIDNEG",self.locale)
|
||||||
text = string.format(vidneg,Callsign,self.callsigntxt)
|
text = string.format(vidneg,Callsign,self.callsigntxt)
|
||||||
self:T(text)
|
self:T(text)
|
||||||
|
self:__VIDFailure(3,GID,group,cluster)
|
||||||
end
|
end
|
||||||
self:_NewRadioEntry(text,text,GID,Outcome,true,true,false,true)
|
self:_NewRadioEntry(text,text,GID,Outcome,true,true,false,true)
|
||||||
end
|
end
|
||||||
@@ -3626,7 +3686,7 @@ function AWACS:_CheckIn(Group)
|
|||||||
managedgroup.LastTasking = timer.getTime()
|
managedgroup.LastTasking = timer.getTime()
|
||||||
|
|
||||||
GID = managedgroup.GID
|
GID = managedgroup.GID
|
||||||
self.ManagedGrps[self.ManagedGrpID]=managedgroup
|
self.ManagedGrps[self.ManagedGrpID]=managedgroup
|
||||||
|
|
||||||
local alphacheckbulls = self:_ToStringBULLS(Group:GetCoordinate())
|
local alphacheckbulls = self:_ToStringBULLS(Group:GetCoordinate())
|
||||||
local alphacheckbullstts = self:_ToStringBULLS(Group:GetCoordinate(),false,true)
|
local alphacheckbullstts = self:_ToStringBULLS(Group:GetCoordinate(),false,true)
|
||||||
@@ -3893,6 +3953,12 @@ function AWACS:_SetClientMenus()
|
|||||||
checkin = checkin,
|
checkin = checkin,
|
||||||
}
|
}
|
||||||
self.clientmenus:Push(menus,cgrpname)
|
self.clientmenus:Push(menus,cgrpname)
|
||||||
|
-- catch errors - when this entry is built we should NOT have a managed entry
|
||||||
|
local GID,hasentry = self:_GetManagedGrpID(cgrp)
|
||||||
|
if hasentry then
|
||||||
|
-- this user is checked in but has the check in entry ... not good.
|
||||||
|
self:_CheckOut(cgrp,GID,true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -5739,7 +5805,7 @@ function AWACS:_AssignPilotToTarget(Pilots,Targets)
|
|||||||
local intercept = AUFTRAG:NewINTERCEPT(Target.Target)
|
local intercept = AUFTRAG:NewINTERCEPT(Target.Target)
|
||||||
intercept:SetWeaponExpend(AI.Task.WeaponExpend.ALL)
|
intercept:SetWeaponExpend(AI.Task.WeaponExpend.ALL)
|
||||||
intercept:SetWeaponType(ENUMS.WeaponFlag.Auto)
|
intercept:SetWeaponType(ENUMS.WeaponFlag.Auto)
|
||||||
|
intercept:SetMissionRange(self.MaxMissionRange)
|
||||||
-- TODO
|
-- TODO
|
||||||
-- now this is going to be interesting...
|
-- now this is going to be interesting...
|
||||||
-- Check if the target left the "hot" area or is dead already
|
-- Check if the target left the "hot" area or is dead already
|
||||||
@@ -5787,6 +5853,7 @@ function AWACS:_AssignPilotToTarget(Pilots,Targets)
|
|||||||
AnchorSpeed = UTILS.KnotsToAltKIAS(AnchorSpeed,Angels)
|
AnchorSpeed = UTILS.KnotsToAltKIAS(AnchorSpeed,Angels)
|
||||||
local Anchor = self.AnchorStacks:ReadByPointer(Pilot.AnchorStackNo) -- #AWACS.AnchorData
|
local Anchor = self.AnchorStacks:ReadByPointer(Pilot.AnchorStackNo) -- #AWACS.AnchorData
|
||||||
local capauftrag = AUFTRAG:NewCAP(Anchor.StationZone,Angels,AnchorSpeed,Anchor.StationZoneCoordinate,0,15,{})
|
local capauftrag = AUFTRAG:NewCAP(Anchor.StationZone,Angels,AnchorSpeed,Anchor.StationZoneCoordinate,0,15,{})
|
||||||
|
capauftrag:SetMissionRange(self.MaxMissionRange)
|
||||||
capauftrag:SetTime(nil,((self.CAPTimeOnStation*3600)+(15*60)))
|
capauftrag:SetTime(nil,((self.CAPTimeOnStation*3600)+(15*60)))
|
||||||
Pilot.FlightGroup:AddMission(capauftrag)
|
Pilot.FlightGroup:AddMission(capauftrag)
|
||||||
|
|
||||||
@@ -5904,6 +5971,8 @@ function AWACS:onafterStart(From, Event, To)
|
|||||||
-- set up the AWACS and let it orbit
|
-- set up the AWACS and let it orbit
|
||||||
local AwacsAW = self.AirWing -- Ops.Airwing#AIRWING
|
local AwacsAW = self.AirWing -- Ops.Airwing#AIRWING
|
||||||
local mission = AUFTRAG:NewORBIT_RACETRACK(self.OrbitZone:GetCoordinate(),self.AwacsAngels*1000,self.Speed,self.Heading,self.Leg)
|
local mission = AUFTRAG:NewORBIT_RACETRACK(self.OrbitZone:GetCoordinate(),self.AwacsAngels*1000,self.Speed,self.Heading,self.Leg)
|
||||||
|
mission:SetMissionRange(self.MaxMissionRange)
|
||||||
|
mission:SetRequiredAttribute({ GROUP.Attribute.AIR_AWACS }) -- prefered plane type, thanks to Heart8reaker
|
||||||
local timeonstation = (self.AwacsTimeOnStation + self.ShiftChangeTime) * 3600
|
local timeonstation = (self.AwacsTimeOnStation + self.ShiftChangeTime) * 3600
|
||||||
mission:SetTime(nil,timeonstation)
|
mission:SetTime(nil,timeonstation)
|
||||||
self.CatchAllMissions[#self.CatchAllMissions+1] = mission
|
self.CatchAllMissions[#self.CatchAllMissions+1] = mission
|
||||||
@@ -6046,6 +6115,7 @@ function AWACS:_CheckAwacsStatus()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
-- AWACS
|
-- AWACS
|
||||||
--------------------------------
|
--------------------------------
|
||||||
@@ -6194,12 +6264,13 @@ function AWACS:_CheckAwacsStatus()
|
|||||||
|
|
||||||
report:Add("====================")
|
report:Add("====================")
|
||||||
|
|
||||||
|
local RESMission
|
||||||
-- Check for replacement mission - if any
|
-- Check for replacement mission - if any
|
||||||
if self.ShiftChangeEscortsFlag and self.ShiftChangeEscortsRequested then -- Ops.Auftrag#AUFTRAG
|
if self.ShiftChangeEscortsFlag and self.ShiftChangeEscortsRequested then -- Ops.Auftrag#AUFTRAG
|
||||||
ESmission = self.EscortMissionReplacement[i]
|
RESMission = self.EscortMissionReplacement[i]
|
||||||
local esstatus = ESmission:GetState()
|
local esstatus = RESMission:GetState()
|
||||||
local ESmissiontime = (timer.getTime() - self.EscortsTimeStamp)
|
local RESMissiontime = (timer.getTime() - self.EscortsTimeStamp)
|
||||||
local ESTOSLeft = UTILS.Round((((self.EscortsTimeOnStation+self.ShiftChangeTime)*3600) - ESmissiontime),0) -- seconds
|
local ESTOSLeft = UTILS.Round((((self.EscortsTimeOnStation+self.ShiftChangeTime)*3600) - RESMissiontime),0) -- seconds
|
||||||
ESTOSLeft = UTILS.Round(ESTOSLeft/60,0) -- minutes
|
ESTOSLeft = UTILS.Round(ESTOSLeft/60,0) -- minutes
|
||||||
local ChangeTime = UTILS.Round(((self.ShiftChangeTime * 3600)/60),0)
|
local ChangeTime = UTILS.Round(((self.ShiftChangeTime * 3600)/60),0)
|
||||||
|
|
||||||
@@ -6207,7 +6278,7 @@ function AWACS:_CheckAwacsStatus()
|
|||||||
report:Add(string.format("Auftrag Status: %s",esstatus))
|
report:Add(string.format("Auftrag Status: %s",esstatus))
|
||||||
report:Add(string.format("TOS Left: %d min",ESTOSLeft))
|
report:Add(string.format("TOS Left: %d min",ESTOSLeft))
|
||||||
|
|
||||||
local OpsGroups = ESmission:GetOpsGroups()
|
local OpsGroups = RESMission:GetOpsGroups()
|
||||||
local OpsGroup = self:_GetAliveOpsGroupFromTable(OpsGroups) -- Ops.OpsGroup#OPSGROUP
|
local OpsGroup = self:_GetAliveOpsGroupFromTable(OpsGroups) -- Ops.OpsGroup#OPSGROUP
|
||||||
if OpsGroup then
|
if OpsGroup then
|
||||||
local OpsName = OpsGroup:GetName() or "Unknown"
|
local OpsName = OpsGroup:GetName() or "Unknown"
|
||||||
@@ -6219,13 +6290,13 @@ function AWACS:_CheckAwacsStatus()
|
|||||||
report:Add("***** Cannot obtain (yet) this missions OpsGroup!")
|
report:Add("***** Cannot obtain (yet) this missions OpsGroup!")
|
||||||
end
|
end
|
||||||
|
|
||||||
if ESmission:IsExecuting() then
|
if RESMission and RESMission:IsExecuting() then
|
||||||
-- make the actual change in the queue
|
-- make the actual change in the queue
|
||||||
self.ShiftChangeEscortsFlag = false
|
self.ShiftChangeEscortsFlag = false
|
||||||
self.ShiftChangeEscortsRequested = false
|
self.ShiftChangeEscortsRequested = false
|
||||||
-- cancel old mission
|
-- cancel old mission
|
||||||
if ESmission and ESmission:IsNotOver() then
|
if ESmission and ESmission:IsNotOver() then
|
||||||
ESmission:Cancel()
|
ESmission:__Cancel(1)
|
||||||
end
|
end
|
||||||
self.EscortMission[i] = self.EscortMissionReplacement[i]
|
self.EscortMission[i] = self.EscortMissionReplacement[i]
|
||||||
self.EscortMissionReplacement[i] = nil
|
self.EscortMissionReplacement[i] = nil
|
||||||
@@ -6477,6 +6548,7 @@ function AWACS:onafterAssignedAnchor(From, Event, To, GID, Anchor, AnchorStackNo
|
|||||||
if auftragtype == AUFTRAG.Type.ALERT5 then
|
if auftragtype == AUFTRAG.Type.ALERT5 then
|
||||||
-- all correct
|
-- all correct
|
||||||
local capauftrag = AUFTRAG:NewCAP(Anchor.StationZone,Angels*1000,AnchorSpeed,Anchor.StationZone:GetCoordinate(),0,15,{})
|
local capauftrag = AUFTRAG:NewCAP(Anchor.StationZone,Angels*1000,AnchorSpeed,Anchor.StationZone:GetCoordinate(),0,15,{})
|
||||||
|
capauftrag:SetMissionRange(self.MaxMissionRange)
|
||||||
capauftrag:SetTime(nil,((self.CAPTimeOnStation*3600)+(15*60)))
|
capauftrag:SetTime(nil,((self.CAPTimeOnStation*3600)+(15*60)))
|
||||||
capauftrag:AddAsset(managedgroup.FlightGroup)
|
capauftrag:AddAsset(managedgroup.FlightGroup)
|
||||||
self.CatchAllMissions[#self.CatchAllMissions+1] = capauftrag
|
self.CatchAllMissions[#self.CatchAllMissions+1] = capauftrag
|
||||||
@@ -6840,7 +6912,8 @@ function AWACS:onafterAwacsShiftChange(From,Event,To)
|
|||||||
self.CatchAllMissions[#self.CatchAllMissions+1] = mission
|
self.CatchAllMissions[#self.CatchAllMissions+1] = mission
|
||||||
local timeonstation = (self.AwacsTimeOnStation + self.ShiftChangeTime) * 3600
|
local timeonstation = (self.AwacsTimeOnStation + self.ShiftChangeTime) * 3600
|
||||||
mission:SetTime(nil,timeonstation)
|
mission:SetTime(nil,timeonstation)
|
||||||
|
mission:SetMissionRange(self.MaxMissionRange)
|
||||||
|
|
||||||
AwacsAW:AddMission(mission)
|
AwacsAW:AddMission(mission)
|
||||||
|
|
||||||
self.AwacsMissionReplacement = mission
|
self.AwacsMissionReplacement = mission
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
-- @image OPS_CSAR.jpg
|
-- @image OPS_CSAR.jpg
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Last Update Sep 2024
|
-- Last Update May 2025
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
-- mycsar.immortalcrew = true -- Set to true to make wounded crew immortal.
|
-- mycsar.immortalcrew = true -- Set to true to make wounded crew immortal.
|
||||||
-- mycsar.invisiblecrew = false -- Set to true to make wounded crew insvisible.
|
-- mycsar.invisiblecrew = false -- Set to true to make wounded crew insvisible.
|
||||||
-- mycsar.loadDistance = 75 -- configure distance for pilots to get into helicopter in meters.
|
-- mycsar.loadDistance = 75 -- configure distance for pilots to get into helicopter in meters.
|
||||||
-- mycsar.mashprefix = {"MASH"} -- prefixes of #GROUP objects used as MASHes.
|
-- mycsar.mashprefix = {"MASH"} -- prefixes of #GROUP objects used as MASHes. Will also try to add ZONE and STATIC objects with this prefix once at startup.
|
||||||
-- mycsar.max_units = 6 -- max number of pilots that can be carried if #CSAR.AircraftType is undefined.
|
-- mycsar.max_units = 6 -- max number of pilots that can be carried if #CSAR.AircraftType is undefined.
|
||||||
-- mycsar.messageTime = 15 -- Time to show messages for in seconds. Doubled for long messages.
|
-- mycsar.messageTime = 15 -- Time to show messages for in seconds. Doubled for long messages.
|
||||||
-- mycsar.radioSound = "beacon.ogg" -- the name of the sound file to use for the pilots\' radio beacons.
|
-- mycsar.radioSound = "beacon.ogg" -- the name of the sound file to use for the pilots\' radio beacons.
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
-- ## 2.2 SRS Features and Other Features
|
-- ## 2.2 SRS Features and Other Features
|
||||||
--
|
--
|
||||||
-- mycsar.useSRS = false -- Set true to use FF\'s SRS integration
|
-- mycsar.useSRS = false -- Set true to use FF\'s SRS integration
|
||||||
-- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!)
|
-- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\ExternalAudio\\" -- adjust your own path in your SRS installation -- server(!)
|
||||||
-- mycsar.SRSchannel = 300 -- radio channel
|
-- mycsar.SRSchannel = 300 -- radio channel
|
||||||
-- mycsar.SRSModulation = radio.modulation.AM -- modulation
|
-- mycsar.SRSModulation = radio.modulation.AM -- modulation
|
||||||
-- mycsar.SRSport = 5002 -- and SRS Server port
|
-- mycsar.SRSport = 5002 -- and SRS Server port
|
||||||
@@ -263,6 +263,7 @@ CSAR = {
|
|||||||
rescuedpilots = 0,
|
rescuedpilots = 0,
|
||||||
limitmaxdownedpilots = true,
|
limitmaxdownedpilots = true,
|
||||||
maxdownedpilots = 10,
|
maxdownedpilots = 10,
|
||||||
|
useFIFOLimitReplacement = false, -- If true, it will remove the oldest downed pilot when a new one is added, if the limit is reached.
|
||||||
allheligroupset = nil,
|
allheligroupset = nil,
|
||||||
topmenuname = "CSAR",
|
topmenuname = "CSAR",
|
||||||
ADFRadioPwr = 1000,
|
ADFRadioPwr = 1000,
|
||||||
@@ -308,12 +309,12 @@ CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
|||||||
CSAR.AircraftType["Bronco-OV-10A"] = 2
|
CSAR.AircraftType["Bronco-OV-10A"] = 2
|
||||||
CSAR.AircraftType["MH-60R"] = 10
|
CSAR.AircraftType["MH-60R"] = 10
|
||||||
CSAR.AircraftType["OH-6A"] = 2
|
CSAR.AircraftType["OH-6A"] = 2
|
||||||
CSAR.AircraftType["OH-58D"] = 2
|
CSAR.AircraftType["OH58D"] = 2
|
||||||
CSAR.AircraftType["CH-47Fbl1"] = 31
|
CSAR.AircraftType["CH-47Fbl1"] = 31
|
||||||
|
|
||||||
--- CSAR class version.
|
--- CSAR class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CSAR.version="1.0.29"
|
CSAR.version="1.0.33"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -468,7 +469,7 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
-- added 1.0.15
|
-- added 1.0.15
|
||||||
self.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
|
self.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
|
||||||
|
|
||||||
self.ADFRadioPwr = 1000
|
self.ADFRadioPwr = 500
|
||||||
|
|
||||||
-- added 1.0.16
|
-- added 1.0.16
|
||||||
self.PilotWeight = 80
|
self.PilotWeight = 80
|
||||||
@@ -480,7 +481,7 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
|
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
|
||||||
-- needs SRS => 1.9.6 to work (works on the *server* side)
|
-- needs SRS => 1.9.6 to work (works on the *server* side)
|
||||||
self.useSRS = false -- Use FF\'s SRS integration
|
self.useSRS = false -- Use FF\'s SRS integration
|
||||||
self.SRSPath = "E:\\Program Files\\DCS-SimpleRadio-Standalone" -- adjust your own path in your server(!)
|
self.SRSPath = "E:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- adjust your own path in your server(!)
|
||||||
self.SRSchannel = 300 -- radio channel
|
self.SRSchannel = 300 -- radio channel
|
||||||
self.SRSModulation = radio.modulation.AM -- modulation
|
self.SRSModulation = radio.modulation.AM -- modulation
|
||||||
self.SRSport = 5002 -- port
|
self.SRSport = 5002 -- port
|
||||||
@@ -809,6 +810,8 @@ end
|
|||||||
-- @param #boolean noMessage
|
-- @param #boolean noMessage
|
||||||
-- @param #string _description Description
|
-- @param #string _description Description
|
||||||
-- @param #boolean forcedesc Use the description only for the pilot track entry
|
-- @param #boolean forcedesc Use the description only for the pilot track entry
|
||||||
|
-- @return Wrapper.Group#GROUP PilotInField Pilot GROUP object
|
||||||
|
-- @return #string AliasName Alias display name
|
||||||
function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _playerName, _freq, noMessage, _description, forcedesc )
|
function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _playerName, _freq, noMessage, _description, forcedesc )
|
||||||
self:T(self.lid .. " _AddCsar")
|
self:T(self.lid .. " _AddCsar")
|
||||||
self:T({_coalition , _country, _point, _typeName, _unitName, _playerName, _freq, noMessage, _description})
|
self:T({_coalition , _country, _point, _typeName, _unitName, _playerName, _freq, noMessage, _description})
|
||||||
@@ -841,9 +844,9 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla
|
|||||||
local BeaconName
|
local BeaconName
|
||||||
|
|
||||||
if _playerName then
|
if _playerName then
|
||||||
BeaconName = _unitName..math.random(1,10000)
|
|
||||||
elseif _unitName then
|
|
||||||
BeaconName = _playerName..math.random(1,10000)
|
BeaconName = _playerName..math.random(1,10000)
|
||||||
|
elseif _unitName then
|
||||||
|
BeaconName = _unitName..math.random(1,10000)
|
||||||
else
|
else
|
||||||
BeaconName = "Ghost-1-1"..math.random(1,10000)
|
BeaconName = "Ghost-1-1"..math.random(1,10000)
|
||||||
end
|
end
|
||||||
@@ -878,7 +881,7 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla
|
|||||||
|
|
||||||
self:_InitSARForPilot(_spawnedGroup, _unitName, _freq, noMessage, _playerName) --shagrat use unitName to have the aircraft callsign / descriptive "name" etc.
|
self:_InitSARForPilot(_spawnedGroup, _unitName, _freq, noMessage, _playerName) --shagrat use unitName to have the aircraft callsign / descriptive "name" etc.
|
||||||
|
|
||||||
return self
|
return _spawnedGroup, _alias
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Function to add a CSAR object into the scene at a zone coordinate. For mission designers wanting to add e.g. PoWs to the scene.
|
--- (Internal) Function to add a CSAR object into the scene at a zone coordinate. For mission designers wanting to add e.g. PoWs to the scene.
|
||||||
@@ -1142,19 +1145,8 @@ function CSAR:_EventHandler(EventData)
|
|||||||
self:T("Double Ejection!")
|
self:T("Double Ejection!")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-- limit no of pilots in the field.
|
|
||||||
if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then
|
|
||||||
self:T("Maxed Downed Pilot!")
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case
|
|
||||||
-- might create dual pilots in edge cases
|
|
||||||
|
|
||||||
local wetfeet = false
|
|
||||||
|
|
||||||
local initdcscoord = nil
|
local initdcscoord = nil
|
||||||
local initcoord = nil
|
local initcoord = nil
|
||||||
if _event.id == EVENTS.Ejection then
|
if _event.id == EVENTS.Ejection then
|
||||||
@@ -1166,6 +1158,36 @@ function CSAR:_EventHandler(EventData)
|
|||||||
initcoord = COORDINATE:NewFromVec3(initdcscoord)
|
initcoord = COORDINATE:NewFromVec3(initdcscoord)
|
||||||
self:T({initdcscoord})
|
self:T({initdcscoord})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Remove downed pilot if already exists to replace with new one.
|
||||||
|
if _event.IniPlayerName then
|
||||||
|
local PilotTable = self.downedPilots --#CSAR.DownedPilot
|
||||||
|
local _foundPilot = nil
|
||||||
|
for _,_pilot in pairs(PilotTable) do
|
||||||
|
if _pilot.player == _event.IniPlayerName and _pilot.alive == true then
|
||||||
|
_foundPilot = _pilot
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if _foundPilot then
|
||||||
|
self:T("Downed pilot already exists!")
|
||||||
|
_foundPilot.group:Destroy(false)
|
||||||
|
self:_RemoveNameFromDownedPilots(_foundPilot.name)
|
||||||
|
self:_CheckDownedPilotTable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- limit no of pilots in the field.
|
||||||
|
if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then
|
||||||
|
self:T("Maxed Downed Pilot!")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case
|
||||||
|
-- might create dual pilots in edge cases
|
||||||
|
|
||||||
|
local wetfeet = false
|
||||||
|
|
||||||
--local surface = _unit:GetCoordinate():GetSurfaceType()
|
--local surface = _unit:GetCoordinate():GetSurfaceType()
|
||||||
local surface = initcoord:GetSurfaceType()
|
local surface = initcoord:GetSurfaceType()
|
||||||
@@ -1829,8 +1851,9 @@ end
|
|||||||
--- (Internal) Function to get string of a group\'s position.
|
--- (Internal) Function to get string of a group\'s position.
|
||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE _woundedGroup Group or Unit object.
|
-- @param Wrapper.Controllable#CONTROLLABLE _woundedGroup Group or Unit object.
|
||||||
|
-- @param Wrapper.Unit#UNIT _Unit Requesting helo pilot unit
|
||||||
-- @return #string Coordinates as Text
|
-- @return #string Coordinates as Text
|
||||||
function CSAR:_GetPositionOfWounded(_woundedGroup)
|
function CSAR:_GetPositionOfWounded(_woundedGroup,_Unit)
|
||||||
self:T(self.lid .. " _GetPositionOfWounded")
|
self:T(self.lid .. " _GetPositionOfWounded")
|
||||||
local _coordinate = _woundedGroup:GetCoordinate()
|
local _coordinate = _woundedGroup:GetCoordinate()
|
||||||
local _coordinatesText = "None"
|
local _coordinatesText = "None"
|
||||||
@@ -1845,6 +1868,26 @@ function CSAR:_GetPositionOfWounded(_woundedGroup)
|
|||||||
_coordinatesText = _coordinate:ToStringBULLS(self.coalition)
|
_coordinatesText = _coordinate:ToStringBULLS(self.coalition)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if _Unit and _Unit:GetPlayerName() then
|
||||||
|
local playername = _Unit:GetPlayerName()
|
||||||
|
if playername then
|
||||||
|
local settings = _DATABASE:GetPlayerSettings(playername) or _SETTINGS
|
||||||
|
if settings then
|
||||||
|
self:T("Get Settings ok!")
|
||||||
|
if settings:IsA2G_MGRS() then
|
||||||
|
_coordinatesText = _coordinate:ToStringMGRS(settings)
|
||||||
|
elseif settings:IsA2G_LL_DMS() then
|
||||||
|
_coordinatesText = _coordinate:ToStringLLDMS(settings)
|
||||||
|
elseif settings:IsA2G_LL_DDM() then
|
||||||
|
_coordinatesText = _coordinate:ToStringLLDDM(settings)
|
||||||
|
elseif settings:IsA2G_BR() then
|
||||||
|
-- attention this is the distance from the ASKING unit to target, not from RECCE to target!
|
||||||
|
local startcoordinate = _Unit:GetCoordinate()
|
||||||
|
_coordinatesText = _coordinate:ToStringBR(startcoordinate,settings)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
return _coordinatesText
|
return _coordinatesText
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1870,13 +1913,17 @@ function CSAR:_DisplayActiveSAR(_unitName)
|
|||||||
self:T({Table=_value})
|
self:T({Table=_value})
|
||||||
local _woundedGroup = _value.group
|
local _woundedGroup = _value.group
|
||||||
if _woundedGroup and _value.alive then
|
if _woundedGroup and _value.alive then
|
||||||
local _coordinatesText = self:_GetPositionOfWounded(_woundedGroup)
|
local _coordinatesText = self:_GetPositionOfWounded(_woundedGroup,_heli)
|
||||||
local _helicoord = _heli:GetCoordinate()
|
local _helicoord = _heli:GetCoordinate()
|
||||||
local _woundcoord = _woundedGroup:GetCoordinate()
|
local _woundcoord = _woundedGroup:GetCoordinate()
|
||||||
local _distance = self:_GetDistance(_helicoord, _woundcoord)
|
local _distance = self:_GetDistance(_helicoord, _woundcoord)
|
||||||
self:T({_distance = _distance})
|
self:T({_distance = _distance})
|
||||||
local distancetext = ""
|
local distancetext = ""
|
||||||
if _SETTINGS:IsImperial() then
|
local settings = _SETTINGS
|
||||||
|
if _heli:GetPlayerName() then
|
||||||
|
settings = _DATABASE:GetPlayerSettings(_heli:GetPlayerName()) or _SETTINGS
|
||||||
|
end
|
||||||
|
if settings:IsImperial() then
|
||||||
distancetext = string.format("%.1fnm",UTILS.MetersToNM(_distance))
|
distancetext = string.format("%.1fnm",UTILS.MetersToNM(_distance))
|
||||||
else
|
else
|
||||||
distancetext = string.format("%.1fkm", _distance/1000.0)
|
distancetext = string.format("%.1fkm", _distance/1000.0)
|
||||||
@@ -2089,56 +2136,50 @@ end
|
|||||||
--- (Internal) Determine distance to closest MASH.
|
--- (Internal) Determine distance to closest MASH.
|
||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
-- @param Wrapper.Unit#UNIT _heli Helicopter #UNIT
|
-- @param Wrapper.Unit#UNIT _heli Helicopter #UNIT
|
||||||
-- @return #CSAR self
|
-- @return #number Distance in meters
|
||||||
|
-- @return #string MASH Name as string
|
||||||
function CSAR:_GetClosestMASH(_heli)
|
function CSAR:_GetClosestMASH(_heli)
|
||||||
self:T(self.lid .. " _GetClosestMASH")
|
self:T(self.lid .. " _GetClosestMASH")
|
||||||
local _mashset = self.mash -- Core.Set#SET_GROUP
|
local _mashset = self.mash -- Core.Set#SET_GROUP
|
||||||
local _mashes = _mashset:GetSetObjects() -- #table
|
local MashSets = {}
|
||||||
|
--local _mashes = _mashset.Set-- #table
|
||||||
|
table.insert(MashSets,_mashset.Set)
|
||||||
|
table.insert(MashSets,self.zonemashes.Set)
|
||||||
|
table.insert(MashSets,self.staticmashes.Set)
|
||||||
local _shortestDistance = -1
|
local _shortestDistance = -1
|
||||||
local _distance = 0
|
local _distance = 0
|
||||||
local _helicoord = _heli:GetCoordinate()
|
local _helicoord = _heli:GetCoordinate()
|
||||||
|
local MashName = nil
|
||||||
local function GetCloseAirbase(coordinate,Coalition,Category)
|
|
||||||
|
|
||||||
local a=coordinate:GetVec3()
|
|
||||||
local distmin=math.huge
|
|
||||||
local airbase=nil
|
|
||||||
for DCSairbaseID, DCSairbase in pairs(world.getAirbases(Coalition)) do
|
|
||||||
local b=DCSairbase:getPoint()
|
|
||||||
|
|
||||||
local c=UTILS.VecSubstract(a,b)
|
|
||||||
local dist=UTILS.VecNorm(c)
|
|
||||||
|
|
||||||
if dist<distmin and (Category==nil or Category==DCSairbase:getDesc().category) then
|
|
||||||
distmin=dist
|
|
||||||
airbase=DCSairbase
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
return distmin
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.allowFARPRescue then
|
if self.allowFARPRescue then
|
||||||
local position = _heli:GetCoordinate()
|
local position = _heli:GetCoordinate()
|
||||||
local afb,distance = position:GetClosestAirbase(nil,self.coalition)
|
local afb,distance = position:GetClosestAirbase(nil,self.coalition)
|
||||||
_shortestDistance = distance
|
_shortestDistance = distance
|
||||||
|
MashName = (afb ~= nil) and afb:GetName() or "Unknown"
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, _mashUnit in pairs(_mashes) do
|
for _,_mashes in pairs(MashSets) do
|
||||||
if _mashUnit and _mashUnit:IsAlive() then
|
for _, _mashUnit in pairs(_mashes or {}) do
|
||||||
local _mashcoord = _mashUnit:GetCoordinate()
|
local _mashcoord
|
||||||
_distance = self:_GetDistance(_helicoord, _mashcoord)
|
if _mashUnit and (not _mashUnit:IsInstanceOf("ZONE_BASE")) and _mashUnit:IsAlive() then
|
||||||
if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then
|
_mashcoord = _mashUnit:GetCoordinate()
|
||||||
_shortestDistance = _distance
|
elseif _mashUnit and _mashUnit:IsInstanceOf("ZONE_BASE") then
|
||||||
end
|
_mashcoord = _mashUnit:GetCoordinate()
|
||||||
end
|
end
|
||||||
|
_distance = self:_GetDistance(_helicoord, _mashcoord)
|
||||||
|
if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then
|
||||||
|
_shortestDistance = _distance
|
||||||
|
MashName = _mashUnit:GetName() or "Unknown"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if _shortestDistance ~= -1 then
|
if _shortestDistance ~= -1 then
|
||||||
return _shortestDistance
|
return _shortestDistance, MashName
|
||||||
else
|
else
|
||||||
return -1
|
return -1
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Display onboarded rescued pilots.
|
--- (Internal) Display onboarded rescued pilots.
|
||||||
@@ -2296,9 +2337,9 @@ end
|
|||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
-- @param Wrapper.Group#GROUP _group Group #GROUP object.
|
-- @param Wrapper.Group#GROUP _group Group #GROUP object.
|
||||||
-- @param #number _freq Frequency to use
|
-- @param #number _freq Frequency to use
|
||||||
-- @param #string _name Beacon Name to use
|
-- @param #string BeaconName Beacon Name to use
|
||||||
-- @return #CSAR self
|
-- @return #CSAR self
|
||||||
function CSAR:_AddBeaconToGroup(_group, _freq, _name)
|
function CSAR:_AddBeaconToGroup(_group, _freq, BeaconName)
|
||||||
self:T(self.lid .. " _AddBeaconToGroup")
|
self:T(self.lid .. " _AddBeaconToGroup")
|
||||||
if self.CreateRadioBeacons == false then return end
|
if self.CreateRadioBeacons == false then return end
|
||||||
local _group = _group
|
local _group = _group
|
||||||
@@ -2319,10 +2360,11 @@ function CSAR:_AddBeaconToGroup(_group, _freq, _name)
|
|||||||
if _radioUnit then
|
if _radioUnit then
|
||||||
local name = _radioUnit:GetName()
|
local name = _radioUnit:GetName()
|
||||||
local Frequency = _freq -- Freq in Hertz
|
local Frequency = _freq -- Freq in Hertz
|
||||||
local name = _radioUnit:GetName()
|
--local name = _radioUnit:GetName()
|
||||||
local Sound = "l10n/DEFAULT/"..self.radioSound
|
local Sound = "l10n/DEFAULT/"..self.radioSound
|
||||||
local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0}
|
local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0}
|
||||||
trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, self.ADFRadioPwr or 1000,_name) -- Beacon in MP only runs for exactly 30secs straight
|
self:I(self.lid..string.format("Added Radio Beacon %d Hertz | Name %s | Position {%d,%d,%d}",Frequency,BeaconName,vec3.x,vec3.y,vec3.z))
|
||||||
|
trigger.action.radioTransmission(Sound, vec3, 0, true, Frequency, self.ADFRadioPwr or 500,BeaconName) -- Beacon in MP only runs for exactly 30secs straight
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2343,9 +2385,13 @@ function CSAR:_RefreshRadioBeacons()
|
|||||||
local group = pilot.group
|
local group = pilot.group
|
||||||
local frequency = pilot.frequency or 0 -- thanks to @Thrud
|
local frequency = pilot.frequency or 0 -- thanks to @Thrud
|
||||||
local bname = pilot.BeaconName or pilot.name..math.random(1,100000)
|
local bname = pilot.BeaconName or pilot.name..math.random(1,100000)
|
||||||
trigger.action.stopRadioTransmission(bname)
|
--trigger.action.stopRadioTransmission(bname)
|
||||||
if group and group:IsAlive() and frequency > 0 then
|
if group and group:IsAlive() and frequency > 0 then
|
||||||
self:_AddBeaconToGroup(group,frequency,bname)
|
--self:_AddBeaconToGroup(group,frequency,bname)
|
||||||
|
else
|
||||||
|
if frequency > 0 then
|
||||||
|
trigger.action.stopRadioTransmission(bname)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2375,11 +2421,26 @@ function CSAR:_ReachedPilotLimit()
|
|||||||
local limit = self.maxdownedpilots
|
local limit = self.maxdownedpilots
|
||||||
local islimited = self.limitmaxdownedpilots
|
local islimited = self.limitmaxdownedpilots
|
||||||
local count = self:_CountActiveDownedPilots()
|
local count = self:_CountActiveDownedPilots()
|
||||||
if islimited and (count >= limit) then
|
if islimited and (count >= limit) then
|
||||||
return true
|
if self.useFIFOLimitReplacement then
|
||||||
else
|
local oldIndex = -1
|
||||||
return false
|
local oldDownedPilot = nil
|
||||||
end
|
for _index, _downedpilot in pairs(self.downedPilots) do
|
||||||
|
oldIndex = _index
|
||||||
|
oldDownedPilot = _downedpilot
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if oldDownedPilot then
|
||||||
|
oldDownedPilot.group:Destroy(false)
|
||||||
|
oldDownedPilot.alive = false
|
||||||
|
self:_CheckDownedPilotTable()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- User - Function to add onw SET_GROUP Set-up for pilot filtering and assignment.
|
--- User - Function to add onw SET_GROUP Set-up for pilot filtering and assignment.
|
||||||
@@ -2425,7 +2486,26 @@ function CSAR:onafterStart(From, Event, To)
|
|||||||
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterCategoryHelicopter():FilterStart()
|
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterCategoryHelicopter():FilterStart()
|
||||||
end
|
end
|
||||||
|
|
||||||
self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() -- currently only GROUP objects, maybe support STATICs also?
|
self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart()
|
||||||
|
|
||||||
|
self.staticmashes = SET_STATIC:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart()
|
||||||
|
self.zonemashes = SET_ZONE:New():FilterPrefixes(self.mashprefix):FilterStart()
|
||||||
|
|
||||||
|
--[[
|
||||||
|
if staticmashes:Count() > 0 then
|
||||||
|
for _,_mash in pairs(staticmashes.Set) do
|
||||||
|
self.mash:AddObject(_mash)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if zonemashes:Count() > 0 then
|
||||||
|
self:T("Adding zones to self.mash SET")
|
||||||
|
for _,_mash in pairs(zonemashes.Set) do
|
||||||
|
self.mash:AddObject(_mash)
|
||||||
|
end
|
||||||
|
self:T("Objects in SET: "..self.mash:Count())
|
||||||
|
end
|
||||||
|
--]]
|
||||||
|
|
||||||
if not self.coordinate then
|
if not self.coordinate then
|
||||||
local csarhq = self.mash:GetRandom()
|
local csarhq = self.mash:GetRandom()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -88,7 +88,10 @@ COHORT = {
|
|||||||
|
|
||||||
--- COHORT class version.
|
--- COHORT class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
COHORT.version="0.3.5"
|
COHORT.version="0.3.6"
|
||||||
|
|
||||||
|
--- Global variable to store the unique(!) cohort names
|
||||||
|
_COHORTNAMES={}
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -110,6 +113,17 @@ COHORT.version="0.3.5"
|
|||||||
-- @return #COHORT self
|
-- @return #COHORT self
|
||||||
function COHORT:New(TemplateGroupName, Ngroups, CohortName)
|
function COHORT:New(TemplateGroupName, Ngroups, CohortName)
|
||||||
|
|
||||||
|
-- Name of the cohort.
|
||||||
|
local name=tostring(CohortName or TemplateGroupName)
|
||||||
|
|
||||||
|
-- Cohort name has to be unique or we will get serious problems!
|
||||||
|
if UTILS.IsAnyInTable(_COHORTNAMES, name) then
|
||||||
|
env.error(string.format('ERROR: cannot create cohort "%s" because another cohort with that name already exists. Names must be unique!', name))
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
table.insert(_COHORTNAMES, name)
|
||||||
|
end
|
||||||
|
|
||||||
-- Inherit everything from FSM class.
|
-- Inherit everything from FSM class.
|
||||||
local self=BASE:Inherit(self, FSM:New()) -- #COHORT
|
local self=BASE:Inherit(self, FSM:New()) -- #COHORT
|
||||||
|
|
||||||
@@ -117,7 +131,7 @@ function COHORT:New(TemplateGroupName, Ngroups, CohortName)
|
|||||||
self.templatename=TemplateGroupName
|
self.templatename=TemplateGroupName
|
||||||
|
|
||||||
-- Cohort name.
|
-- Cohort name.
|
||||||
self.name=tostring(CohortName or TemplateGroupName)
|
self.name=name
|
||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("COHORT %s | ", self.name)
|
self.lid=string.format("COHORT %s | ", self.name)
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ COMMANDER = {
|
|||||||
awacsZones = {},
|
awacsZones = {},
|
||||||
tankerZones = {},
|
tankerZones = {},
|
||||||
limitMission = {},
|
limitMission = {},
|
||||||
|
maxMissionsAssignPerCycle = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- COMMANDER class version.
|
--- COMMANDER class version.
|
||||||
@@ -1535,6 +1536,8 @@ function COMMANDER:CheckMissionQueue()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local missionsAssigned = 0
|
||||||
|
|
||||||
-- Loop over missions in queue.
|
-- Loop over missions in queue.
|
||||||
for _,_mission in pairs(self.missionqueue) do
|
for _,_mission in pairs(self.missionqueue) do
|
||||||
local mission=_mission --Ops.Auftrag#AUFTRAG
|
local mission=_mission --Ops.Auftrag#AUFTRAG
|
||||||
@@ -1594,9 +1597,12 @@ function COMMANDER:CheckMissionQueue()
|
|||||||
-- Recruited assets but no requested escort available. Unrecruit assets!
|
-- Recruited assets but no requested escort available. Unrecruit assets!
|
||||||
LEGION.UnRecruitAssets(assets, mission)
|
LEGION.UnRecruitAssets(assets, mission)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Only ONE mission is assigned.
|
missionsAssigned = missionsAssigned + 1
|
||||||
return
|
if missionsAssigned >= (self.maxMissionsAssignPerCycle or 1) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -1611,6 +1617,16 @@ function COMMANDER:CheckMissionQueue()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set how many missions can be assigned in a single status iteration. (eg. This is useful for persistent missions where you need to load all AUFTRAGs on mission start and then change it back to default)
|
||||||
|
--- Warning: Increasing this value will increase the number of missions started per iteration and thus may lead to performance issues if too many missions are started at once.
|
||||||
|
-- @param #COMMANDER self
|
||||||
|
-- @param #number Number of missions assigned per status iteration. Default is 1.
|
||||||
|
-- @return #COMMANDER self.
|
||||||
|
function COMMANDER:SetMaxMissionsAssignPerCycle(MaxMissionsAssignPerCycle)
|
||||||
|
self.maxMissionsAssignPerCycle = MaxMissionsAssignPerCycle or 1
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Get cohorts.
|
--- Get cohorts.
|
||||||
-- @param #COMMANDER self
|
-- @param #COMMANDER self
|
||||||
-- @param #table Legions Special legions.
|
-- @param #table Legions Special legions.
|
||||||
@@ -1670,9 +1686,12 @@ function COMMANDER:_GetCohorts(Legions, Cohorts, Operation)
|
|||||||
for _,_legion in pairs(Legions or {}) do
|
for _,_legion in pairs(Legions or {}) do
|
||||||
local legion=_legion --Ops.Legion#LEGION
|
local legion=_legion --Ops.Legion#LEGION
|
||||||
|
|
||||||
-- Check that runway is operational.
|
-- Check that runway is operational.
|
||||||
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
|
local Runway=true
|
||||||
|
if legion:IsAirwing() then
|
||||||
|
Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition()
|
||||||
|
end
|
||||||
|
|
||||||
-- Legion has to be running.
|
-- Legion has to be running.
|
||||||
if legion:IsRunning() and Runway then
|
if legion:IsRunning() and Runway then
|
||||||
|
|
||||||
@@ -1703,9 +1722,12 @@ function COMMANDER:_GetCohorts(Legions, Cohorts, Operation)
|
|||||||
for _,_legion in pairs(self.legions) do
|
for _,_legion in pairs(self.legions) do
|
||||||
local legion=_legion --Ops.Legion#LEGION
|
local legion=_legion --Ops.Legion#LEGION
|
||||||
|
|
||||||
-- Check that runway is operational.
|
-- Check that runway is operational.
|
||||||
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
|
local Runway=true
|
||||||
|
if legion:IsAirwing() then
|
||||||
|
Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition()
|
||||||
|
end
|
||||||
|
|
||||||
-- Legion has to be running.
|
-- Legion has to be running.
|
||||||
if legion:IsRunning() and Runway then
|
if legion:IsRunning() and Runway then
|
||||||
|
|
||||||
@@ -1774,8 +1796,10 @@ function COMMANDER:RecruitAssetsForMission(Mission)
|
|||||||
MaxWeight=cohort.cargobayLimit
|
MaxWeight=cohort.cargobayLimit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T(self.lid..string.format("Largest cargo bay available=%.1f", MaxWeight))
|
if MaxWeight then
|
||||||
|
self:T(self.lid..string.format("Largest cargo bay available=%.1f", MaxWeight))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local legions=self.legions
|
local legions=self.legions
|
||||||
@@ -2165,4 +2189,4 @@ end
|
|||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
-- @field #number capleg
|
-- @field #number capleg
|
||||||
-- @field #number maxinterceptsize
|
-- @field #number maxinterceptsize
|
||||||
-- @field #number missionrange
|
-- @field #number missionrange
|
||||||
-- @field #number noaltert5
|
-- @field #number noalert5
|
||||||
-- @field #table ManagedAW
|
-- @field #table ManagedAW
|
||||||
-- @field #table ManagedSQ
|
-- @field #table ManagedSQ
|
||||||
-- @field #table ManagedCP
|
-- @field #table ManagedCP
|
||||||
@@ -62,6 +62,7 @@
|
|||||||
-- @field #number repeatsonfailure
|
-- @field #number repeatsonfailure
|
||||||
-- @field Core.Set#SET_ZONE GoZoneSet
|
-- @field Core.Set#SET_ZONE GoZoneSet
|
||||||
-- @field Core.Set#SET_ZONE NoGoZoneSet
|
-- @field Core.Set#SET_ZONE NoGoZoneSet
|
||||||
|
-- @field Core.Set#SET_ZONE ConflictZoneSet
|
||||||
-- @field #boolean Monitor
|
-- @field #boolean Monitor
|
||||||
-- @field #boolean TankerInvisible
|
-- @field #boolean TankerInvisible
|
||||||
-- @field #number CapFormation
|
-- @field #number CapFormation
|
||||||
@@ -69,6 +70,7 @@
|
|||||||
-- @field #boolean DespawnAfterLanding
|
-- @field #boolean DespawnAfterLanding
|
||||||
-- @field #boolean DespawnAfterHolding
|
-- @field #boolean DespawnAfterHolding
|
||||||
-- @field #list<Ops.Auftrag#AUFTRAG> ListOfAuftrag
|
-- @field #list<Ops.Auftrag#AUFTRAG> ListOfAuftrag
|
||||||
|
-- @field #string defaulttakeofftype Take off type
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown.
|
--- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown.
|
||||||
@@ -102,6 +104,11 @@
|
|||||||
-- Next put a late activated template group for your CAP/GCI Squadron on the map. Last, put a zone on the map for the CAP operations, let's name it "Blue Zone 1". Size of the zone plays no role.
|
-- Next put a late activated template group for your CAP/GCI Squadron on the map. Last, put a zone on the map for the CAP operations, let's name it "Blue Zone 1". Size of the zone plays no role.
|
||||||
-- Put an EW radar system on the map and name it aptly, like "Blue EWR".
|
-- Put an EW radar system on the map and name it aptly, like "Blue EWR".
|
||||||
--
|
--
|
||||||
|
-- ### Zones
|
||||||
|
--
|
||||||
|
-- For our example, you create a RED and a BLUE border, as a closed polygonal zone representing the borderlines. You can also have conflict zone, where - for our example - BLUE will attack
|
||||||
|
-- RED planes, despite being on RED territory. Think of a no-fly zone or an limited area of engagement. Conflict zones take precedence over borders, i.e. they can overlap all borders.
|
||||||
|
--
|
||||||
-- ### Code it
|
-- ### Code it
|
||||||
--
|
--
|
||||||
-- -- Set up a basic system for the blue side, we'll reside on Kutaisi, and use GROUP objects with "Blue EWR" in the name as EW Radar Systems.
|
-- -- Set up a basic system for the blue side, we'll reside on Kutaisi, and use GROUP objects with "Blue EWR" in the name as EW Radar Systems.
|
||||||
@@ -114,10 +121,10 @@
|
|||||||
-- mywing:AddSquadron("Blue Sq1 M2000c","CAP Kutaisi",AIRBASE.Caucasus.Kutaisi,20,AI.Skill.GOOD,102,"ec1.5_Vendee_Jeanne_clean")
|
-- mywing:AddSquadron("Blue Sq1 M2000c","CAP Kutaisi",AIRBASE.Caucasus.Kutaisi,20,AI.Skill.GOOD,102,"ec1.5_Vendee_Jeanne_clean")
|
||||||
--
|
--
|
||||||
-- -- Add a couple of zones
|
-- -- Add a couple of zones
|
||||||
-- -- We'll defend our border
|
-- -- We'll defend our own border
|
||||||
-- mywing:AddAcceptZone(ZONE_POLYGON:New( "Blue Border", GROUP:FindByName( "Blue Border" ) ))
|
-- mywing:AddAcceptZone(ZONE_POLYGON:New( "Blue Border", GROUP:FindByName( "Blue Border" ) ))
|
||||||
-- -- We'll attack intruders also here
|
-- -- We'll attack intruders also here - conflictzones can overlap borders(!) - limited zone of engagement
|
||||||
-- mywing:AddAcceptZone(ZONE_POLYGON:New("Red Defense Zone", GROUP:FindByName( "Red Defense Zone" )))
|
-- mywing:AddConflictZone(ZONE_POLYGON:New("Red Defense Zone", GROUP:FindByName( "Red Defense Zone" )))
|
||||||
-- -- We'll leave the reds alone on their turf
|
-- -- We'll leave the reds alone on their turf
|
||||||
-- mywing:AddRejectZone(ZONE_POLYGON:New( "Red Border", GROUP:FindByName( "Red Border" ) ))
|
-- mywing:AddRejectZone(ZONE_POLYGON:New( "Red Border", GROUP:FindByName( "Red Border" ) ))
|
||||||
--
|
--
|
||||||
@@ -125,10 +132,10 @@
|
|||||||
-- -- Set up borders on map
|
-- -- Set up borders on map
|
||||||
-- local BlueBorder = ZONE_POLYGON:New( "Blue Border", GROUP:FindByName( "Blue Border" ) )
|
-- local BlueBorder = ZONE_POLYGON:New( "Blue Border", GROUP:FindByName( "Blue Border" ) )
|
||||||
-- BlueBorder:DrawZone(-1,{0,0,1},1,FillColor,FillAlpha,1,true)
|
-- BlueBorder:DrawZone(-1,{0,0,1},1,FillColor,FillAlpha,1,true)
|
||||||
-- local BlueNoGoZone = ZONE_POLYGON:New("Red Defense Zone", GROUP:FindByName( "Red Defense Zone" ))
|
-- local ConflictZone = ZONE_POLYGON:New("Red Defense Zone", GROUP:FindByName( "Red Defense Zone" ))
|
||||||
-- BlueNoGoZone:DrawZone(-1,{1,1,0},1,FillColor,FillAlpha,2,true)
|
-- ConflictZone:DrawZone(-1,{1,1,0},1,FillColor,FillAlpha,2,true)
|
||||||
-- local BlueNoGoZone2 = ZONE_POLYGON:New( "Red Border", GROUP:FindByName( "Red Border" ) )
|
-- local BlueNoGoZone = ZONE_POLYGON:New( "Red Border", GROUP:FindByName( "Red Border" ) )
|
||||||
-- BlueNoGoZone2:DrawZone(-1,{1,0,0},1,FillColor,FillAlpha,4,true)
|
-- BlueNoGoZone:DrawZone(-1,{1,0,0},1,FillColor,FillAlpha,4,true)
|
||||||
--
|
--
|
||||||
-- ### Add a second airwing with squads and own CAP point (optional)
|
-- ### Add a second airwing with squads and own CAP point (optional)
|
||||||
--
|
--
|
||||||
@@ -167,7 +174,7 @@
|
|||||||
-- * @{#EASYGCICAP.SetDefaultCAPLeg}: Set the length of the CAP leg, default is 15 NM.
|
-- * @{#EASYGCICAP.SetDefaultCAPLeg}: Set the length of the CAP leg, default is 15 NM.
|
||||||
-- * @{#EASYGCICAP.SetDefaultCAPGrouping}: Set how many planes will be spawned per mission (CVAP/GCI), defaults to 2.
|
-- * @{#EASYGCICAP.SetDefaultCAPGrouping}: Set how many planes will be spawned per mission (CVAP/GCI), defaults to 2.
|
||||||
-- * @{#EASYGCICAP.SetDefaultMissionRange}: Set how many NM the planes can go from the home base, defaults to 100.
|
-- * @{#EASYGCICAP.SetDefaultMissionRange}: Set how many NM the planes can go from the home base, defaults to 100.
|
||||||
-- * @{#EASYGCICAP.SetDefaultNumberAlter5Standby}: Set how many planes will be spawned on cold standby (Alert5), default 2.
|
-- * @{#EASYGCICAP.SetDefaultNumberAlert5Standby}: Set how many planes will be spawned on cold standby (Alert5), default 2.
|
||||||
-- * @{#EASYGCICAP.SetDefaultEngageRange}: Set max engage range for CAP flights if they detect intruders, defaults to 50.
|
-- * @{#EASYGCICAP.SetDefaultEngageRange}: Set max engage range for CAP flights if they detect intruders, defaults to 50.
|
||||||
-- * @{#EASYGCICAP.SetMaxAliveMissions}: Set max parallel missions can be done (CAP+GCI+Alert5+Tanker+AWACS), defaults to 8.
|
-- * @{#EASYGCICAP.SetMaxAliveMissions}: Set max parallel missions can be done (CAP+GCI+Alert5+Tanker+AWACS), defaults to 8.
|
||||||
-- * @{#EASYGCICAP.SetDefaultRepeatOnFailure}: Set max repeats on failure for intercepting/killing intruders, defaults to 3.
|
-- * @{#EASYGCICAP.SetDefaultRepeatOnFailure}: Set max repeats on failure for intercepting/killing intruders, defaults to 3.
|
||||||
@@ -197,7 +204,7 @@ EASYGCICAP = {
|
|||||||
capleg = 15,
|
capleg = 15,
|
||||||
maxinterceptsize = 2,
|
maxinterceptsize = 2,
|
||||||
missionrange = 100,
|
missionrange = 100,
|
||||||
noaltert5 = 4,
|
noalert5 = 4,
|
||||||
ManagedAW = {},
|
ManagedAW = {},
|
||||||
ManagedSQ = {},
|
ManagedSQ = {},
|
||||||
ManagedCP = {},
|
ManagedCP = {},
|
||||||
@@ -210,13 +217,15 @@ EASYGCICAP = {
|
|||||||
repeatsonfailure = 3,
|
repeatsonfailure = 3,
|
||||||
GoZoneSet = nil,
|
GoZoneSet = nil,
|
||||||
NoGoZoneSet = nil,
|
NoGoZoneSet = nil,
|
||||||
|
ConflictZoneSet = nil,
|
||||||
Monitor = false,
|
Monitor = false,
|
||||||
TankerInvisible = true,
|
TankerInvisible = true,
|
||||||
CapFormation = nil,
|
CapFormation = nil,
|
||||||
ReadyFlightGroups = {},
|
ReadyFlightGroups = {},
|
||||||
DespawnAfterLanding = false,
|
DespawnAfterLanding = false,
|
||||||
DespawnAfterHolding = true,
|
DespawnAfterHolding = true,
|
||||||
ListOfAuftrag = {}
|
ListOfAuftrag = {},
|
||||||
|
defaulttakeofftype = "hot",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Internal Squadron data type
|
--- Internal Squadron data type
|
||||||
@@ -252,7 +261,7 @@ EASYGCICAP = {
|
|||||||
|
|
||||||
--- EASYGCICAP class version.
|
--- EASYGCICAP class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
EASYGCICAP.version="0.1.13"
|
EASYGCICAP.version="0.1.23"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -269,7 +278,7 @@ EASYGCICAP.version="0.1.13"
|
|||||||
-- @param #string Alias A Name for this GCICAP
|
-- @param #string Alias A Name for this GCICAP
|
||||||
-- @param #string AirbaseName Name of the Home Airbase
|
-- @param #string AirbaseName Name of the Home Airbase
|
||||||
-- @param #string Coalition Coalition, e.g. "blue" or "red"
|
-- @param #string Coalition Coalition, e.g. "blue" or "red"
|
||||||
-- @param #string EWRName (Partial) group name of the EWR system of the coalition, e.g. "Red EWR"
|
-- @param #string EWRName (Partial) group name of the EWR system of the coalition, e.g. "Red EWR", can be handed in as table of names, e.g.{"EWR","Radar","SAM"}
|
||||||
-- @return #EASYGCICAP self
|
-- @return #EASYGCICAP self
|
||||||
function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
||||||
-- Inherit everything from FSM class.
|
-- Inherit everything from FSM class.
|
||||||
@@ -278,14 +287,16 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
|||||||
-- defaults
|
-- defaults
|
||||||
self.alias = Alias or AirbaseName.." CAP Wing"
|
self.alias = Alias or AirbaseName.." CAP Wing"
|
||||||
self.coalitionname = string.lower(Coalition) or "blue"
|
self.coalitionname = string.lower(Coalition) or "blue"
|
||||||
self.coalition = self.coaltitionname == "blue" and coalition.side.BLUE or coalition.side.RED
|
self.coalition = self.coalitionname == "blue" and coalition.side.BLUE or coalition.side.RED
|
||||||
self.wings = {}
|
self.wings = {}
|
||||||
self.EWRName = EWRName or self.coalitionname.." EWR"
|
if type(EWRName) == "string" then EWRName = {EWRName} end
|
||||||
|
self.EWRName = EWRName --or self.coalitionname.." EWR"
|
||||||
--self.CapZoneName = CapZoneName
|
--self.CapZoneName = CapZoneName
|
||||||
self.airbasename = AirbaseName
|
self.airbasename = AirbaseName
|
||||||
self.airbase = AIRBASE:FindByName(self.airbasename)
|
self.airbase = AIRBASE:FindByName(self.airbasename)
|
||||||
self.GoZoneSet = SET_ZONE:New()
|
self.GoZoneSet = SET_ZONE:New()
|
||||||
self.NoGoZoneSet = SET_ZONE:New()
|
self.NoGoZoneSet = SET_ZONE:New()
|
||||||
|
self.ConflictZoneSet = SET_ZONE:New()
|
||||||
self.resurrection = 900
|
self.resurrection = 900
|
||||||
self.capspeed = 300
|
self.capspeed = 300
|
||||||
self.capalt = 25000
|
self.capalt = 25000
|
||||||
@@ -293,7 +304,7 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
|||||||
self.capleg = 15
|
self.capleg = 15
|
||||||
self.capgrouping = 2
|
self.capgrouping = 2
|
||||||
self.missionrange = 100
|
self.missionrange = 100
|
||||||
self.noaltert5 = 2
|
self.noalert5 = 2
|
||||||
self.MaxAliveMissions = 8
|
self.MaxAliveMissions = 8
|
||||||
self.engagerange = 50
|
self.engagerange = 50
|
||||||
self.repeatsonfailure = 3
|
self.repeatsonfailure = 3
|
||||||
@@ -303,6 +314,7 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
|||||||
self.DespawnAfterLanding = false
|
self.DespawnAfterLanding = false
|
||||||
self.DespawnAfterHolding = true
|
self.DespawnAfterHolding = true
|
||||||
self.ListOfAuftrag = {}
|
self.ListOfAuftrag = {}
|
||||||
|
self.defaulttakeofftype = "hot"
|
||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("EASYGCICAP %s | ", self.alias)
|
self.lid=string.format("EASYGCICAP %s | ", self.alias)
|
||||||
@@ -347,9 +359,23 @@ function EASYGCICAP:SetTankerAndAWACSInvisible(Switch)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set Maximum of alive missions to stop airplanes spamming the map
|
--- Count alive missions in our internal stack.
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #number Maxiumum Maxmimum number of parallel missions allowed. Count is Cap-Missions + Intercept-Missions + Alert5-Missionsm default is 6
|
-- @return #number count
|
||||||
|
function EASYGCICAP:_CountAliveAuftrags()
|
||||||
|
local alive = 0
|
||||||
|
for _,_auftrag in pairs(self.ListOfAuftrag) do
|
||||||
|
local auftrag = _auftrag -- Ops.Auftrag#AUFTRAG
|
||||||
|
if auftrag and (not (auftrag:IsCancelled() or auftrag:IsDone() or auftrag:IsOver())) then
|
||||||
|
alive = alive + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return alive
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set Maximum of alive missions created by this instance to stop airplanes spamming the map
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param #number Maxiumum Maxmimum number of parallel missions allowed. Count is Intercept-Missions + Alert5-Missions, default is 8
|
||||||
-- @return #EASYGCICAP self
|
-- @return #EASYGCICAP self
|
||||||
function EASYGCICAP:SetMaxAliveMissions(Maxiumum)
|
function EASYGCICAP:SetMaxAliveMissions(Maxiumum)
|
||||||
self:T(self.lid.."SetMaxAliveMissions")
|
self:T(self.lid.."SetMaxAliveMissions")
|
||||||
@@ -377,6 +403,16 @@ function EASYGCICAP:SetDefaultRepeatOnFailure(Retries)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add default take off type for the airwings.
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param #string Takeoff Can be "hot", "cold", or "air" - default is "hot".
|
||||||
|
-- @return #EASYGCICAP self
|
||||||
|
function EASYGCICAP:SetDefaultTakeOffType(Takeoff)
|
||||||
|
self:T(self.lid.."SetDefaultTakeOffType")
|
||||||
|
self.defaulttakeofftype = Takeoff or "hot"
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set default CAP Speed in knots
|
--- Set default CAP Speed in knots
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #number Speed Speed defaults to 300
|
-- @param #number Speed Speed defaults to 300
|
||||||
@@ -441,9 +477,9 @@ end
|
|||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #number Airframes defaults to 2
|
-- @param #number Airframes defaults to 2
|
||||||
-- @return #EASYGCICAP self
|
-- @return #EASYGCICAP self
|
||||||
function EASYGCICAP:SetDefaultNumberAlter5Standby(Airframes)
|
function EASYGCICAP:SetDefaultNumberAlert5Standby(Airframes)
|
||||||
self:T(self.lid.."SetDefaultNumberAlter5Standby")
|
self:T(self.lid.."SetDefaultNumberAlert5Standby")
|
||||||
self.noaltert5 = math.abs(Airframes) or 2
|
self.noalert5 = math.abs(Airframes) or 2
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -452,7 +488,7 @@ end
|
|||||||
-- @param #number Range defaults to 50NM
|
-- @param #number Range defaults to 50NM
|
||||||
-- @return #EASYGCICAP self
|
-- @return #EASYGCICAP self
|
||||||
function EASYGCICAP:SetDefaultEngageRange(Range)
|
function EASYGCICAP:SetDefaultEngageRange(Range)
|
||||||
self:T(self.lid.."SetDefaultNumberAlter5Standby")
|
self:T(self.lid.."SetDefaultEngageRange")
|
||||||
self.engagerange = Range or 50
|
self.engagerange = Range or 50
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -546,6 +582,13 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
local DespawnAfterLanding = self.DespawnAfterLanding
|
local DespawnAfterLanding = self.DespawnAfterLanding
|
||||||
local DespawnAfterHolding = self.DespawnAfterHolding
|
local DespawnAfterHolding = self.DespawnAfterHolding
|
||||||
|
|
||||||
|
-- Check STATIC name
|
||||||
|
local check = STATIC:FindByName(Airbasename,false)
|
||||||
|
if check == nil then
|
||||||
|
MESSAGE:New(self.lid.."There's no warehouse static on the map (wrong naming?) for airbase "..tostring(Airbasename).."!",30,"CHECK"):ToAllIf(self.debug):ToLog()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Create Airwing
|
-- Create Airwing
|
||||||
local CAP_Wing = AIRWING:New(Airbasename,Alias)
|
local CAP_Wing = AIRWING:New(Airbasename,Alias)
|
||||||
CAP_Wing:SetVerbosityLevel(0)
|
CAP_Wing:SetVerbosityLevel(0)
|
||||||
@@ -573,9 +616,8 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
if #self.ManagedREC > 0 then
|
if #self.ManagedREC > 0 then
|
||||||
CAP_Wing:SetNumberRecon(1)
|
CAP_Wing:SetNumberRecon(1)
|
||||||
end
|
end
|
||||||
--local PatrolCoordinateKutaisi = ZONE:New(CapZoneName):GetCoordinate()
|
|
||||||
--CAP_Wing:AddPatrolPointCAP(PatrolCoordinateKutaisi,self.capalt,UTILS.KnotsToAltKIAS(self.capspeed,self.capalt),self.capdir,self.capleg)
|
CAP_Wing:SetTakeoffType(self.defaulttakeofftype)
|
||||||
CAP_Wing:SetTakeoffHot()
|
|
||||||
CAP_Wing:SetLowFuelThreshold(0.3)
|
CAP_Wing:SetLowFuelThreshold(0.3)
|
||||||
CAP_Wing.RandomAssetScore = math.random(50,100)
|
CAP_Wing.RandomAssetScore = math.random(50,100)
|
||||||
CAP_Wing:Start()
|
CAP_Wing:Start()
|
||||||
@@ -583,8 +625,11 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
local Intel = self.Intel
|
local Intel = self.Intel
|
||||||
|
|
||||||
local TankerInvisible = self.TankerInvisible
|
local TankerInvisible = self.TankerInvisible
|
||||||
|
local engagerange = self.engagerange
|
||||||
|
local GoZoneSet = self.GoZoneSet
|
||||||
|
local NoGoZoneSet = self.NoGoZoneSet
|
||||||
|
|
||||||
function CAP_Wing:OnAfterFlightOnMission(From, Event, To, Flightgroup, Mission)
|
function CAP_Wing:onbeforeFlightOnMission(From, Event, To, Flightgroup, Mission)
|
||||||
local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP
|
local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP
|
||||||
if DespawnAfterLanding then
|
if DespawnAfterLanding then
|
||||||
flightgroup:SetDespawnAfterLanding()
|
flightgroup:SetDespawnAfterLanding()
|
||||||
@@ -596,7 +641,7 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
flightgroup:GetGroup():SetOptionRadarUsingForContinousSearch()
|
flightgroup:GetGroup():SetOptionRadarUsingForContinousSearch()
|
||||||
if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then
|
if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then
|
||||||
flightgroup:SetDetection(true)
|
flightgroup:SetDetection(true)
|
||||||
flightgroup:SetEngageDetectedOn(self.engagerange,{"Air"},self.GoZoneSet,self.NoGoZoneSet)
|
flightgroup:SetEngageDetectedOn(engagerange,{"Air"},GoZoneSet,NoGoZoneSet)
|
||||||
flightgroup:SetOutOfAAMRTB()
|
flightgroup:SetOutOfAAMRTB()
|
||||||
if CapFormation then
|
if CapFormation then
|
||||||
flightgroup:GetGroup():SetOption(AI.Option.Air.id.FORMATION,CapFormation)
|
flightgroup:GetGroup():SetOption(AI.Option.Air.id.FORMATION,CapFormation)
|
||||||
@@ -614,15 +659,15 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
flightgroup:SetFuelLowRTB(true)
|
flightgroup:SetFuelLowRTB(true)
|
||||||
Intel:AddAgent(flightgroup)
|
Intel:AddAgent(flightgroup)
|
||||||
if DespawnAfterHolding then
|
if DespawnAfterHolding then
|
||||||
function flightgroup:OnAfterHolding(From,Event,To)
|
function flightgroup:onbeforeHolding(From,Event,To)
|
||||||
self:Despawn(1,true)
|
self:Despawn(1,true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.noaltert5 > 0 then
|
if self.noalert5 > 0 then
|
||||||
local alert = AUFTRAG:NewALERT5(AUFTRAG.Type.INTERCEPT)
|
local alert = AUFTRAG:NewALERT5(AUFTRAG.Type.INTERCEPT)
|
||||||
alert:SetRequiredAssets(self.noaltert5)
|
alert:SetRequiredAssets(self.noalert5)
|
||||||
alert:SetRepeat(99)
|
alert:SetRepeat(99)
|
||||||
CAP_Wing:AddMission(alert)
|
CAP_Wing:AddMission(alert)
|
||||||
table.insert(self.ListOfAuftrag,alert)
|
table.insert(self.ListOfAuftrag,alert)
|
||||||
@@ -740,6 +785,11 @@ function EASYGCICAP:_SetTankerPatrolPoints()
|
|||||||
self:T(self.lid.."_SetTankerPatrolPoints")
|
self:T(self.lid.."_SetTankerPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedTK) do
|
for _,_data in pairs(self.ManagedTK) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
|
self:T("Airbasename = "..data.AirbaseName)
|
||||||
|
if not self.wings[data.AirbaseName] then
|
||||||
|
MESSAGE:New(self.lid.."You are trying to create a TANKER point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog()
|
||||||
|
return
|
||||||
|
end
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
@@ -759,6 +809,11 @@ function EASYGCICAP:_SetAwacsPatrolPoints()
|
|||||||
self:T(self.lid.."_SetAwacsPatrolPoints")
|
self:T(self.lid.."_SetAwacsPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedEWR) do
|
for _,_data in pairs(self.ManagedEWR) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
|
self:T("Airbasename = "..data.AirbaseName)
|
||||||
|
if not self.wings[data.AirbaseName] then
|
||||||
|
MESSAGE:New(self.lid.."You are trying to create an AWACS point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog()
|
||||||
|
return
|
||||||
|
end
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
@@ -778,6 +833,11 @@ function EASYGCICAP:_SetCAPPatrolPoints()
|
|||||||
self:T(self.lid.."_SetCAPPatrolPoints")
|
self:T(self.lid.."_SetCAPPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedCP) do
|
for _,_data in pairs(self.ManagedCP) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
|
self:T("Airbasename = "..data.AirbaseName)
|
||||||
|
if not self.wings[data.AirbaseName] then
|
||||||
|
MESSAGE:New(self.lid.."You are trying to create a CAP point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog()
|
||||||
|
return
|
||||||
|
end
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
@@ -797,6 +857,11 @@ function EASYGCICAP:_SetReconPatrolPoints()
|
|||||||
self:T(self.lid.."_SetReconPatrolPoints")
|
self:T(self.lid.."_SetReconPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedREC) do
|
for _,_data in pairs(self.ManagedREC) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
|
self:T("Airbasename = "..data.AirbaseName)
|
||||||
|
if not self.wings[data.AirbaseName] then
|
||||||
|
MESSAGE:New(self.lid.."You are trying to create a RECON point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog()
|
||||||
|
return
|
||||||
|
end
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
@@ -1098,7 +1163,7 @@ end
|
|||||||
-- @param Core.Zone#ZONE_BASE Zone
|
-- @param Core.Zone#ZONE_BASE Zone
|
||||||
-- @return #EASYGCICAP self
|
-- @return #EASYGCICAP self
|
||||||
function EASYGCICAP:AddAcceptZone(Zone)
|
function EASYGCICAP:AddAcceptZone(Zone)
|
||||||
self:T(self.lid.."AddAcceptZone0")
|
self:T(self.lid.."AddAcceptZone")
|
||||||
self.GoZoneSet:AddZone(Zone)
|
self.GoZoneSet:AddZone(Zone)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1113,6 +1178,18 @@ function EASYGCICAP:AddRejectZone(Zone)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add a zone to the conflict zones set.
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param Core.Zone#ZONE_BASE Zone
|
||||||
|
-- @return #EASYGCICAP self
|
||||||
|
function EASYGCICAP:AddConflictZone(Zone)
|
||||||
|
self:T(self.lid.."AddConflictZone")
|
||||||
|
self.ConflictZoneSet:AddZone(Zone)
|
||||||
|
self.GoZoneSet:AddZone(Zone)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (Internal) Try to assign the intercept to a FlightGroup already in air and ready.
|
--- (Internal) Try to assign the intercept to a FlightGroup already in air and ready.
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #table ReadyFlightGroups ReadyFlightGroups
|
-- @param #table ReadyFlightGroups ReadyFlightGroups
|
||||||
@@ -1176,8 +1253,9 @@ function EASYGCICAP:_AssignIntercept(Cluster)
|
|||||||
|
|
||||||
local wings = self.wings
|
local wings = self.wings
|
||||||
local ctlpts = self.ManagedCP
|
local ctlpts = self.ManagedCP
|
||||||
local MaxAliveMissions = self.MaxAliveMissions * self.capgrouping
|
local MaxAliveMissions = self.MaxAliveMissions --* self.capgrouping
|
||||||
local nogozoneset = self.NoGoZoneSet
|
local nogozoneset = self.NoGoZoneSet
|
||||||
|
local conflictzoneset = self.ConflictZoneSet
|
||||||
local ReadyFlightGroups = self.ReadyFlightGroups
|
local ReadyFlightGroups = self.ReadyFlightGroups
|
||||||
|
|
||||||
-- Aircraft?
|
-- Aircraft?
|
||||||
@@ -1241,9 +1319,10 @@ function EASYGCICAP:_AssignIntercept(Cluster)
|
|||||||
-- Do we have a matching airwing?
|
-- Do we have a matching airwing?
|
||||||
if targetairwing then
|
if targetairwing then
|
||||||
local AssetCount = targetairwing:CountAssetsOnMission(MissionTypes,Cohort)
|
local AssetCount = targetairwing:CountAssetsOnMission(MissionTypes,Cohort)
|
||||||
|
local missioncount = self:_CountAliveAuftrags()
|
||||||
-- Enough airframes on mission already?
|
-- Enough airframes on mission already?
|
||||||
self:T(self.lid.." Assets on Mission "..AssetCount)
|
self:T(self.lid.." Assets on Mission "..AssetCount)
|
||||||
if AssetCount <= MaxAliveMissions then
|
if missioncount < MaxAliveMissions then
|
||||||
local repeats = repeatsonfailure
|
local repeats = repeatsonfailure
|
||||||
local InterceptAuftrag = AUFTRAG:NewINTERCEPT(contact.group)
|
local InterceptAuftrag = AUFTRAG:NewINTERCEPT(contact.group)
|
||||||
:SetMissionRange(150)
|
:SetMissionRange(150)
|
||||||
@@ -1255,18 +1334,22 @@ function EASYGCICAP:_AssignIntercept(Cluster)
|
|||||||
|
|
||||||
if nogozoneset:Count() > 0 then
|
if nogozoneset:Count() > 0 then
|
||||||
InterceptAuftrag:AddConditionSuccess(
|
InterceptAuftrag:AddConditionSuccess(
|
||||||
function(group,zoneset)
|
function(group,zoneset,conflictset)
|
||||||
local success = false
|
local success = false
|
||||||
if group and group:IsAlive() then
|
if group and group:IsAlive() then
|
||||||
local coord = group:GetCoordinate()
|
local coord = group:GetCoordinate()
|
||||||
if coord and zoneset:IsCoordinateInZone(coord) then
|
if coord and zoneset:Count() > 0 and zoneset:IsCoordinateInZone(coord) then
|
||||||
success = true
|
success = true
|
||||||
end
|
end
|
||||||
|
if coord and conflictset:Count() > 0 and conflictset:IsCoordinateInZone(coord) then
|
||||||
|
success = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return success
|
return success
|
||||||
end,
|
end,
|
||||||
contact.group,
|
contact.group,
|
||||||
nogozoneset
|
nogozoneset,
|
||||||
|
conflictzoneset
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1291,15 +1374,16 @@ function EASYGCICAP:_StartIntel()
|
|||||||
self:T(self.lid.."_StartIntel")
|
self:T(self.lid.."_StartIntel")
|
||||||
-- Border GCI Detection
|
-- Border GCI Detection
|
||||||
local BlueAir_DetectionSetGroup = SET_GROUP:New()
|
local BlueAir_DetectionSetGroup = SET_GROUP:New()
|
||||||
BlueAir_DetectionSetGroup:FilterPrefixes( { self.EWRName } )
|
BlueAir_DetectionSetGroup:FilterPrefixes( self.EWRName )
|
||||||
BlueAir_DetectionSetGroup:FilterStart()
|
BlueAir_DetectionSetGroup:FilterStart()
|
||||||
|
|
||||||
-- Intel type detection
|
-- Intel type detection
|
||||||
local BlueIntel = INTEL:New(BlueAir_DetectionSetGroup,self.coalitionname, self.EWRName)
|
local BlueIntel = INTEL:New(BlueAir_DetectionSetGroup,self.coalitionname, self.alias)
|
||||||
BlueIntel:SetClusterAnalysis(true,false,false)
|
BlueIntel:SetClusterAnalysis(true,false,false)
|
||||||
BlueIntel:SetForgetTime(300)
|
BlueIntel:SetForgetTime(300)
|
||||||
BlueIntel:SetAcceptZones(self.GoZoneSet)
|
BlueIntel:SetAcceptZones(self.GoZoneSet)
|
||||||
BlueIntel:SetRejectZones(self.NoGoZoneSet)
|
BlueIntel:SetRejectZones(self.NoGoZoneSet)
|
||||||
|
BlueIntel:SetConflictZones(self.ConflictZoneSet)
|
||||||
BlueIntel:SetVerbosity(0)
|
BlueIntel:SetVerbosity(0)
|
||||||
BlueIntel:Start()
|
BlueIntel:Start()
|
||||||
|
|
||||||
@@ -1311,7 +1395,7 @@ function EASYGCICAP:_StartIntel()
|
|||||||
self:_AssignIntercept(Cluster)
|
self:_AssignIntercept(Cluster)
|
||||||
end
|
end
|
||||||
|
|
||||||
function BlueIntel:OnAfterNewCluster(From,Event,To,Cluster)
|
function BlueIntel:onbeforeNewCluster(From,Event,To,Cluster)
|
||||||
AssignCluster(Cluster)
|
AssignCluster(Cluster)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1428,12 +1512,14 @@ function EASYGCICAP:onafterStatus(From,Event,To)
|
|||||||
local text = "GCICAP "..self.alias
|
local text = "GCICAP "..self.alias
|
||||||
text = text.."\nWings: "..wings.."\nSquads: "..squads.."\nCapPoints: "..caps.."\nAssets on Mission: "..assets.."\nAssets in Stock: "..instock
|
text = text.."\nWings: "..wings.."\nSquads: "..squads.."\nCapPoints: "..caps.."\nAssets on Mission: "..assets.."\nAssets in Stock: "..instock
|
||||||
text = text.."\nThreats: "..threatcount
|
text = text.."\nThreats: "..threatcount
|
||||||
text = text.."\nMissions: "..capmission+interceptmission
|
text = text.."\nAirWing managed Missions: "..capmission+awacsmission+tankermission+reconmission
|
||||||
text = text.."\n - CAP: "..capmission
|
text = text.."\n - CAP: "..capmission
|
||||||
text = text.."\n - Intercept: "..interceptmission
|
|
||||||
text = text.."\n - AWACS: "..awacsmission
|
text = text.."\n - AWACS: "..awacsmission
|
||||||
text = text.."\n - TANKER: "..tankermission
|
text = text.."\n - TANKER: "..tankermission
|
||||||
text = text.."\n - Recon: "..reconmission
|
text = text.."\n - Recon: "..reconmission
|
||||||
|
text = text.."\nSelf managed Missions:"
|
||||||
|
text = text.."\n - Mission Limit: "..self.MaxAliveMissions
|
||||||
|
text = text.."\n - Alert5+Intercept "..self:_CountAliveAuftrags()
|
||||||
MESSAGE:New(text,15,"GCICAP"):ToAll():ToLogIf(self.debug)
|
MESSAGE:New(text,15,"GCICAP"):ToAll():ToLogIf(self.debug)
|
||||||
end
|
end
|
||||||
self:__Status(30)
|
self:__Status(30)
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ FLIGHTGROUP.Players={}
|
|||||||
|
|
||||||
--- FLIGHTGROUP class version.
|
--- FLIGHTGROUP class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
FLIGHTGROUP.version="1.0.2"
|
FLIGHTGROUP.version="1.0.3"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -259,7 +259,7 @@ function FLIGHTGROUP:New(group)
|
|||||||
local self=BASE:Inherit(self, OPSGROUP:New(group)) -- #FLIGHTGROUP
|
local self=BASE:Inherit(self, OPSGROUP:New(group)) -- #FLIGHTGROUP
|
||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("FLIGHTGROUP %s | ", self.groupname)
|
self.lid=string.format("FLIGHTGROUP %s | ", self.groupname or "N/A")
|
||||||
|
|
||||||
-- Defaults
|
-- Defaults
|
||||||
self:SetDefaultROE()
|
self:SetDefaultROE()
|
||||||
@@ -779,6 +779,61 @@ function FLIGHTGROUP:SetJettisonWeapons(Switch)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set the aircraft to land straight in.
|
||||||
|
-- @param #FLIGHTGROUP self
|
||||||
|
-- @return #FLIGHTGROUP self
|
||||||
|
function FLIGHTGROUP:SetOptionLandingStraightIn()
|
||||||
|
self.OptionLandingStraightIn = true
|
||||||
|
if self:GetGroup():IsAlive() then
|
||||||
|
self:GetGroup():SetOptionLandingStraightIn()
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the aircraft to land in pairs.
|
||||||
|
-- @param #FLIGHTGROUP self
|
||||||
|
-- @return #FLIGHTGROUP self
|
||||||
|
function FLIGHTGROUP:SetOptionLandingForcePair()
|
||||||
|
self.OptionLandingForcePair = true
|
||||||
|
if self:GetGroup():IsAlive() then
|
||||||
|
self:GetGroup():SetOptionLandingForcePair()
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the aircraft to NOT land in pairs.
|
||||||
|
-- @param #FLIGHTGROUP self
|
||||||
|
-- @return #FLIGHTGROUP self
|
||||||
|
function FLIGHTGROUP:SetOptionLandingRestrictPair()
|
||||||
|
self.OptionLandingRestrictPair = true
|
||||||
|
if self:GetGroup():IsAlive() then
|
||||||
|
self:GetGroup():SetOptionLandingRestrictPair()
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the aircraft to land after overhead break.
|
||||||
|
-- @param #FLIGHTGROUP self
|
||||||
|
-- @return #FLIGHTGROUP self
|
||||||
|
function FLIGHTGROUP:SetOptionLandingOverheadBreak()
|
||||||
|
self.OptionLandingOverheadBreak = true
|
||||||
|
if self:GetGroup():IsAlive() then
|
||||||
|
self:GetGroup():SetOptionLandingOverheadBreak()
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [HELICOPTER] Set the aircraft to prefer takeoff and landing vertically.
|
||||||
|
-- @param #FLIGHTGROUP self
|
||||||
|
-- @return #FLIGHTGROUP self
|
||||||
|
function FLIGHTGROUP:SetOptionPreferVertical()
|
||||||
|
self.OptionPreferVertical = true
|
||||||
|
if self:GetGroup():IsAlive() then
|
||||||
|
self:GetGroup():OptionPreferVerticalLanding()
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set if group is ready for taxi/takeoff if controlled by a `FLIGHTCONTROL`.
|
--- Set if group is ready for taxi/takeoff if controlled by a `FLIGHTCONTROL`.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
-- @param #boolean ReadyTO If `true`, flight is ready for takeoff.
|
-- @param #boolean ReadyTO If `true`, flight is ready for takeoff.
|
||||||
@@ -1277,6 +1332,25 @@ function FLIGHTGROUP:Status()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- check if we need to end holding
|
||||||
|
--self:T(self.lid.."Checking if we are holding at a holding point...")
|
||||||
|
if mission and mission.missionHoldingCoord and self.isHoldingAtHoldingPoint == true then
|
||||||
|
self:T(self.lid.."...yes")
|
||||||
|
if mission:IsReadyToPush() then
|
||||||
|
--self:T(self.lid.."Ready to push -> YES")
|
||||||
|
-- move flag to 1
|
||||||
|
self.flaghold:Set(1)
|
||||||
|
-- Not waiting any more.
|
||||||
|
self.Twaiting=nil
|
||||||
|
self.dTwait=nil
|
||||||
|
self.isHoldingAtHoldingPoint = false
|
||||||
|
--else
|
||||||
|
--self:T(self.lid.."Ready to push -> NO!")
|
||||||
|
end
|
||||||
|
--else
|
||||||
|
--self:T(self.lid.."...no")
|
||||||
|
end
|
||||||
|
|
||||||
-- If mission, check if DCS task needs to be updated.
|
-- If mission, check if DCS task needs to be updated.
|
||||||
if mission and mission.updateDCSTask then
|
if mission and mission.updateDCSTask then
|
||||||
|
|
||||||
@@ -1983,6 +2057,9 @@ function FLIGHTGROUP:onafterElementAirborne(From, Event, To, Element)
|
|||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T2(self.lid..string.format("Element airborne %s", Element.name))
|
self:T2(self.lid..string.format("Element airborne %s", Element.name))
|
||||||
|
|
||||||
|
-- Set parking spot to free. Also for FC. This is usually done after taxiing but doing it here in case the group is teleported.
|
||||||
|
self:_SetElementParkingFree(Element)
|
||||||
|
|
||||||
-- Set element status.
|
-- Set element status.
|
||||||
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.AIRBORNE)
|
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.AIRBORNE)
|
||||||
@@ -3057,7 +3134,7 @@ function FLIGHTGROUP:onbeforeLandAtAirbase(From, Event, To, airbase)
|
|||||||
local Tsuspend=nil
|
local Tsuspend=nil
|
||||||
|
|
||||||
if airbase==nil then
|
if airbase==nil then
|
||||||
self:T(self.lid.."ERROR: Airbase is nil in LandAtAirase() call!")
|
self:T(self.lid.."ERROR: Airbase is nil in LandAtAirbase() call!")
|
||||||
allowed=false
|
allowed=false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3803,114 +3880,124 @@ end
|
|||||||
--- Initialize group parameters. Also initializes waypoints if self.waypoints is nil.
|
--- Initialize group parameters. Also initializes waypoints if self.waypoints is nil.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
-- @param #table Template Template used to init the group. Default is `self.template`.
|
-- @param #table Template Template used to init the group. Default is `self.template`.
|
||||||
|
-- @param #number Delay Delay in seconds before group is initialized. Default `nil`, *i.e.* instantaneous.
|
||||||
-- @return #FLIGHTGROUP self
|
-- @return #FLIGHTGROUP self
|
||||||
function FLIGHTGROUP:_InitGroup(Template)
|
function FLIGHTGROUP:_InitGroup(Template, Delay)
|
||||||
|
|
||||||
-- First check if group was already initialized.
|
if Delay and Delay>0 then
|
||||||
if self.groupinitialized then
|
self:ScheduleOnce(Delay, FLIGHTGROUP._InitGroup, self, Template, 0)
|
||||||
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Group object.
|
|
||||||
local group=self.group --Wrapper.Group#GROUP
|
|
||||||
|
|
||||||
-- Helo group.
|
|
||||||
self.isHelo=group:IsHelicopter()
|
|
||||||
|
|
||||||
-- Max speed in km/h.
|
|
||||||
self.speedMax=group:GetSpeedMax()
|
|
||||||
|
|
||||||
-- Is group mobile?
|
|
||||||
if self.speedMax and self.speedMax>3.6 then
|
|
||||||
self.isMobile=true
|
|
||||||
else
|
else
|
||||||
self.isMobile=false
|
|
||||||
self.speedMax = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Cruise speed limit 380 kts for fixed and 110 knots for rotary wings.
|
-- First check if group was already initialized.
|
||||||
local speedCruiseLimit=self.isHelo and UTILS.KnotsToKmph(110) or UTILS.KnotsToKmph(380)
|
if self.groupinitialized then
|
||||||
|
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
||||||
-- Cruise speed: 70% of max speed but within limit.
|
return
|
||||||
self.speedCruise=math.min(self.speedMax*0.7, speedCruiseLimit)
|
|
||||||
|
|
||||||
-- Group ammo.
|
|
||||||
self.ammo=self:GetAmmoTot()
|
|
||||||
|
|
||||||
-- Get template of group.
|
|
||||||
local template=Template or self:_GetTemplate()
|
|
||||||
|
|
||||||
-- Is (template) group uncontrolled.
|
|
||||||
self.isUncontrolled=template~=nil and template.uncontrolled or false
|
|
||||||
|
|
||||||
-- Is (template) group late activated.
|
|
||||||
self.isLateActivated=template~=nil and template.lateActivation or false
|
|
||||||
|
|
||||||
if template then
|
|
||||||
|
|
||||||
-- Radio parameters from template. Default is set on spawn if not modified by user.
|
|
||||||
self.radio.Freq=tonumber(template.frequency)
|
|
||||||
self.radio.Modu=tonumber(template.modulation)
|
|
||||||
self.radio.On=template.communication
|
|
||||||
|
|
||||||
-- Set callsign. Default is set on spawn if not modified by user.
|
|
||||||
local callsign=template.units[1].callsign
|
|
||||||
--self:I({callsign=callsign})
|
|
||||||
if type(callsign)=="number" then -- Sometimes callsign is just "101".
|
|
||||||
local cs=tostring(callsign)
|
|
||||||
callsign={}
|
|
||||||
callsign[1]=cs:sub(1,1)
|
|
||||||
callsign[2]=cs:sub(2,2)
|
|
||||||
callsign[3]=cs:sub(3,3)
|
|
||||||
end
|
end
|
||||||
self.callsign.NumberSquad=tonumber(callsign[1])
|
|
||||||
self.callsign.NumberGroup=tonumber(callsign[2])
|
-- Group object.
|
||||||
self.callsign.NameSquad=UTILS.GetCallsignName(self.callsign.NumberSquad)
|
local group=self.group --Wrapper.Group#GROUP
|
||||||
|
|
||||||
|
-- Helo group.
|
||||||
|
self.isHelo=group:IsHelicopter()
|
||||||
|
|
||||||
|
-- Max speed in km/h.
|
||||||
|
self.speedMax=group:GetSpeedMax()
|
||||||
|
|
||||||
end
|
-- Is group mobile?
|
||||||
|
if self.speedMax and self.speedMax>3.6 then
|
||||||
-- Set default formation.
|
self.isMobile=true
|
||||||
if self.isHelo then
|
else
|
||||||
self.optionDefault.Formation=ENUMS.Formation.RotaryWing.EchelonLeft.D300
|
self.isMobile=false
|
||||||
else
|
self.speedMax = 0
|
||||||
self.optionDefault.Formation=ENUMS.Formation.FixedWing.EchelonLeft.Group
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- Default TACAN off.
|
|
||||||
self:SetDefaultTACAN(nil, nil, nil, nil, true)
|
|
||||||
self.tacan=UTILS.DeepCopy(self.tacanDefault)
|
|
||||||
|
|
||||||
-- Is this purely AI?
|
|
||||||
self.isAI=not self:_IsHuman(group)
|
|
||||||
|
|
||||||
-- Create Menu.
|
|
||||||
if not self.isAI then
|
|
||||||
self.menu=self.menu or {}
|
|
||||||
self.menu.atc=self.menu.atc or {} --#table
|
|
||||||
self.menu.atc.root=self.menu.atc.root or MENU_GROUP:New(self.group, "ATC") --Core.Menu#MENU_GROUP
|
|
||||||
self.menu.atc.help=self.menu.atc.help or MENU_GROUP:New(self.group, "Help", self.menu.atc.root) --Core.Menu#MENU_GROUP
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Units of the group.
|
|
||||||
local units=self.group:GetUnits()
|
|
||||||
|
|
||||||
-- DCS group.
|
-- Cruise speed limit 380 kts for fixed and 110 knots for rotary wings.
|
||||||
local dcsgroup=Group.getByName(self.groupname)
|
local speedCruiseLimit=self.isHelo and UTILS.KnotsToKmph(110) or UTILS.KnotsToKmph(380)
|
||||||
local size0=dcsgroup:getInitialSize()
|
|
||||||
|
|
||||||
-- Quick check.
|
-- Cruise speed: 70% of max speed but within limit.
|
||||||
if #units~=size0 then
|
self.speedCruise=math.min(self.speedMax*0.7, speedCruiseLimit)
|
||||||
self:T(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units!", #units, size0))
|
|
||||||
end
|
-- Group ammo.
|
||||||
|
self.ammo=self:GetAmmoTot()
|
||||||
-- Add elemets.
|
|
||||||
for _,unit in pairs(units) do
|
-- Get template of group.
|
||||||
self:_AddElementByName(unit:GetName())
|
local template=Template or self:_GetTemplate()
|
||||||
|
|
||||||
|
-- Is (template) group uncontrolled.
|
||||||
|
self.isUncontrolled=template~=nil and template.uncontrolled or false
|
||||||
|
|
||||||
|
-- Is (template) group late activated.
|
||||||
|
self.isLateActivated=template~=nil and template.lateActivation or false
|
||||||
|
|
||||||
|
if template then
|
||||||
|
|
||||||
|
-- Radio parameters from template. Default is set on spawn if not modified by user.
|
||||||
|
self.radio.Freq=tonumber(template.frequency)
|
||||||
|
self.radio.Modu=tonumber(template.modulation)
|
||||||
|
self.radio.On=template.communication
|
||||||
|
|
||||||
|
-- Set callsign. Default is set on spawn if not modified by user.
|
||||||
|
local callsign=template.units[1].callsign
|
||||||
|
--self:I({callsign=callsign})
|
||||||
|
if type(callsign)=="number" then -- Sometimes callsign is just "101".
|
||||||
|
local cs=tostring(callsign)
|
||||||
|
callsign={}
|
||||||
|
callsign[1]=cs:sub(1,1)
|
||||||
|
callsign[2]=cs:sub(2,2)
|
||||||
|
callsign[3]=cs:sub(3,3)
|
||||||
|
end
|
||||||
|
self.callsign.NumberSquad=tonumber(callsign[1])
|
||||||
|
self.callsign.NumberGroup=tonumber(callsign[2])
|
||||||
|
self.callsign.NameSquad=UTILS.GetCallsignName(self.callsign.NumberSquad)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set default formation.
|
||||||
|
if self.isHelo then
|
||||||
|
self.optionDefault.Formation=ENUMS.Formation.RotaryWing.EchelonLeft.D300
|
||||||
|
else
|
||||||
|
self.optionDefault.Formation=ENUMS.Formation.FixedWing.EchelonLeft.Group
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Default TACAN off.
|
||||||
|
if not self.tacanDefault then
|
||||||
|
self:SetDefaultTACAN(nil, nil, nil, nil, true)
|
||||||
|
end
|
||||||
|
if not self.tacan then
|
||||||
|
self.tacan=UTILS.DeepCopy(self.tacanDefault)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Is this purely AI?
|
||||||
|
self.isAI=not self:_IsHuman(group)
|
||||||
|
|
||||||
|
-- Create Menu.
|
||||||
|
if not self.isAI then
|
||||||
|
self.menu=self.menu or {}
|
||||||
|
self.menu.atc=self.menu.atc or {} --#table
|
||||||
|
self.menu.atc.root=self.menu.atc.root or MENU_GROUP:New(self.group, "ATC") --Core.Menu#MENU_GROUP
|
||||||
|
self.menu.atc.help=self.menu.atc.help or MENU_GROUP:New(self.group, "Help", self.menu.atc.root) --Core.Menu#MENU_GROUP
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Units of the group.
|
||||||
|
local units=self.group:GetUnits()
|
||||||
|
|
||||||
|
-- DCS group.
|
||||||
|
local dcsgroup=Group.getByName(self.groupname)
|
||||||
|
local size0=dcsgroup:getInitialSize()
|
||||||
|
|
||||||
|
-- Quick check.
|
||||||
|
if #units~=size0 then
|
||||||
|
self:T(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units!", #units, size0))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add elemets.
|
||||||
|
for _,unit in pairs(units) do
|
||||||
|
self:_AddElementByName(unit:GetName())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Init done.
|
||||||
|
self.groupinitialized=true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Init done.
|
|
||||||
self.groupinitialized=true
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -4179,51 +4266,6 @@ function FLIGHTGROUP:IsLandingAirbase(wp)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Initialize Mission Editor waypoints.
|
|
||||||
-- @param #FLIGHTGROUP self
|
|
||||||
-- @return #FLIGHTGROUP self
|
|
||||||
function FLIGHTGROUP:InitWaypoints()
|
|
||||||
|
|
||||||
-- Template waypoints.
|
|
||||||
self.waypoints0=self.group:GetTemplateRoutePoints()
|
|
||||||
|
|
||||||
-- Waypoints
|
|
||||||
self.waypoints={}
|
|
||||||
|
|
||||||
for index,wp in pairs(self.waypoints0) do
|
|
||||||
|
|
||||||
local waypoint=self:_CreateWaypoint(wp)
|
|
||||||
self:_AddWaypoint(waypoint)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get home and destination airbases from waypoints.
|
|
||||||
self.homebase=self.homebase or self:GetHomebaseFromWaypoints()
|
|
||||||
self.destbase=self.destbase or self:GetDestinationFromWaypoints()
|
|
||||||
self.currbase=self:GetHomebaseFromWaypoints()
|
|
||||||
|
|
||||||
-- Remove the landing waypoint. We use RTB for that. It makes adding new waypoints easier as we do not have to check if the last waypoint is the landing waypoint.
|
|
||||||
if self.destbase and #self.waypoints>1 then
|
|
||||||
table.remove(self.waypoints, #self.waypoints)
|
|
||||||
else
|
|
||||||
self.destbase=self.homebase
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug info.
|
|
||||||
self:T(self.lid..string.format("Initializing %d waypoints. Homebase %s ==> %s Destination", #self.waypoints, self.homebase and self.homebase:GetName() or "unknown", self.destbase and self.destbase:GetName() or "uknown"))
|
|
||||||
|
|
||||||
-- Update route.
|
|
||||||
if #self.waypoints>0 then
|
|
||||||
|
|
||||||
-- Check if only 1 wp?
|
|
||||||
if #self.waypoints==1 then
|
|
||||||
self:_PassedFinalWaypoint(true, "FLIGHTGROUP:InitWaypoints #self.waypoints==1")
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Add an AIR waypoint to the flight plan.
|
--- Add an AIR waypoint to the flight plan.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
@@ -4510,6 +4552,11 @@ function FLIGHTGROUP:GetParkingSpot(element, maxdist, airbase)
|
|||||||
-- Airbase.
|
-- Airbase.
|
||||||
airbase=airbase or self:GetClosestAirbase()
|
airbase=airbase or self:GetClosestAirbase()
|
||||||
|
|
||||||
|
if airbase == nil then
|
||||||
|
self:T(self.lid.."No airbase found for element "..element.name)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
-- Parking table of airbase.
|
-- Parking table of airbase.
|
||||||
local parking=airbase.parking --:GetParkingSpotsTable()
|
local parking=airbase.parking --:GetParkingSpotsTable()
|
||||||
|
|
||||||
|
|||||||
@@ -2324,7 +2324,7 @@ INTEL_DLINK = {
|
|||||||
verbose = 0,
|
verbose = 0,
|
||||||
lid = nil,
|
lid = nil,
|
||||||
alias = nil,
|
alias = nil,
|
||||||
cachetime = 300,
|
cachetime = 120,
|
||||||
interval = 20,
|
interval = 20,
|
||||||
contacts = {},
|
contacts = {},
|
||||||
clusters = {},
|
clusters = {},
|
||||||
@@ -2333,7 +2333,7 @@ INTEL_DLINK = {
|
|||||||
|
|
||||||
--- Version string
|
--- Version string
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
INTEL_DLINK.version = "0.0.1"
|
INTEL_DLINK.version = "0.0.2"
|
||||||
|
|
||||||
--- Function to instantiate a new object
|
--- Function to instantiate a new object
|
||||||
-- @param #INTEL_DLINK self
|
-- @param #INTEL_DLINK self
|
||||||
@@ -2384,15 +2384,15 @@ function INTEL_DLINK:New(Intels, Alias, Interval, Cachetime)
|
|||||||
self.alias="SPECTRE"
|
self.alias="SPECTRE"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Cache time
|
|
||||||
self.cachetime = Cachetime or 300
|
|
||||||
|
|
||||||
-- Interval
|
-- Interval
|
||||||
self.interval = Interval or 20
|
self.interval = Interval or 20
|
||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("INTEL_DLINK %s | ", self.alias)
|
self.lid=string.format("INTEL_DLINK %s | ", self.alias)
|
||||||
|
|
||||||
|
-- Cache time
|
||||||
|
self:SetDLinkCacheTime(Cachetime or 120)
|
||||||
|
|
||||||
-- Start State.
|
-- Start State.
|
||||||
self:SetStartState("Stopped")
|
self:SetStartState("Stopped")
|
||||||
|
|
||||||
@@ -2477,6 +2477,16 @@ function INTEL_DLINK:onafterStart(From, Event, To)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Function to set how long INTEL DLINK remembers contacts.
|
||||||
|
-- @param #INTEL_DLINK self
|
||||||
|
-- @param #number seconds Remember this many seconds. Defaults to 180.
|
||||||
|
-- @return #INTEL_DLINK self
|
||||||
|
function INTEL_DLINK:SetDLinkCacheTime(seconds)
|
||||||
|
self.cachetime = math.abs(seconds or 120)
|
||||||
|
self:I(self.lid.."Caching for "..self.cachetime.." seconds.")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Function to collect data from the various #INTEL
|
--- Function to collect data from the various #INTEL
|
||||||
-- @param #INTEL_DLINK self
|
-- @param #INTEL_DLINK self
|
||||||
-- @param #string From The From state
|
-- @param #string From The From state
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ LEGION.RandomAssetScore=1
|
|||||||
|
|
||||||
--- LEGION class version.
|
--- LEGION class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
LEGION.version="0.5.0"
|
LEGION.version="0.5.1"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -445,6 +445,21 @@ function LEGION:DelCohort(Cohort)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Remove specific asset from legion.
|
||||||
|
-- @param #LEGION self
|
||||||
|
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset.
|
||||||
|
-- @return #LEGION self
|
||||||
|
function LEGION:DelAsset(Asset)
|
||||||
|
|
||||||
|
if Asset.cohort then
|
||||||
|
Asset.cohort:DelAsset(Asset)
|
||||||
|
else
|
||||||
|
self:E(self.lid..string.format("ERROR: Asset has not cohort attached. Cannot remove it from legion!"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Relocate a cohort to another legion.
|
--- Relocate a cohort to another legion.
|
||||||
-- Assets in stock are spawned and routed to the new legion.
|
-- Assets in stock are spawned and routed to the new legion.
|
||||||
@@ -1643,6 +1658,9 @@ function LEGION:onafterAssetDead(From, Event, To, asset, request)
|
|||||||
if self.commander and self.commander.chief then
|
if self.commander and self.commander.chief then
|
||||||
self.commander.chief.detectionset:RemoveGroupsByName({asset.spawngroupname})
|
self.commander.chief.detectionset:RemoveGroupsByName({asset.spawngroupname})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Remove asset from cohort and legion.
|
||||||
|
self:DelAsset(asset)
|
||||||
|
|
||||||
-- Remove asset from mission is done via Mission:AssetDead() call from flightgroup onafterFlightDead function
|
-- Remove asset from mission is done via Mission:AssetDead() call from flightgroup onafterFlightDead function
|
||||||
-- Remove asset from squadron same
|
-- Remove asset from squadron same
|
||||||
@@ -1827,6 +1845,9 @@ function LEGION:_CreateFlightGroup(asset)
|
|||||||
-- Set home base.
|
-- Set home base.
|
||||||
opsgroup.homebase=self.airbase
|
opsgroup.homebase=self.airbase
|
||||||
|
|
||||||
|
-- Set destination base
|
||||||
|
opsgroup.destbase=self.airbase
|
||||||
|
|
||||||
-- Set home zone.
|
-- Set home zone.
|
||||||
opsgroup.homezone=self.spawnzone
|
opsgroup.homezone=self.spawnzone
|
||||||
|
|
||||||
@@ -2492,9 +2513,12 @@ function LEGION._GetCohorts(Legions, Cohorts, Operation, OpsQueue)
|
|||||||
for _,_legion in pairs(Legions or {}) do
|
for _,_legion in pairs(Legions or {}) do
|
||||||
local legion=_legion --Ops.Legion#LEGION
|
local legion=_legion --Ops.Legion#LEGION
|
||||||
|
|
||||||
-- Check that runway is operational.
|
-- Check that runway is operational.
|
||||||
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
|
local Runway=true
|
||||||
|
if legion:IsAirwing() then
|
||||||
|
Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition()
|
||||||
|
end
|
||||||
|
|
||||||
-- Legion has to be running.
|
-- Legion has to be running.
|
||||||
if legion:IsRunning() and Runway then
|
if legion:IsRunning() and Runway then
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ NAVYGROUP = {
|
|||||||
|
|
||||||
--- NavyGroup version.
|
--- NavyGroup version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
NAVYGROUP.version="1.0.2"
|
NAVYGROUP.version="1.0.3"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -395,7 +395,7 @@ function NAVYGROUP:New(group)
|
|||||||
self:HandleEvent(EVENTS.Birth, self.OnEventBirth)
|
self:HandleEvent(EVENTS.Birth, self.OnEventBirth)
|
||||||
self:HandleEvent(EVENTS.Dead, self.OnEventDead)
|
self:HandleEvent(EVENTS.Dead, self.OnEventDead)
|
||||||
self:HandleEvent(EVENTS.RemoveUnit, self.OnEventRemoveUnit)
|
self:HandleEvent(EVENTS.RemoveUnit, self.OnEventRemoveUnit)
|
||||||
self:HandleEvent(EVENTS.UnitLost, self.OnEventRemoveUnit)
|
self:HandleEvent(EVENTS.UnitLost, self.OnEventRemoveUnit)
|
||||||
|
|
||||||
-- Start the status monitoring.
|
-- Start the status monitoring.
|
||||||
self.timerStatus=TIMER:New(self.Status, self):Start(1, 30)
|
self.timerStatus=TIMER:New(self.Status, self):Start(1, 30)
|
||||||
@@ -775,7 +775,7 @@ end
|
|||||||
|
|
||||||
--- Update status.
|
--- Update status.
|
||||||
-- @param #NAVYGROUP self
|
-- @param #NAVYGROUP self
|
||||||
function NAVYGROUP:Status(From, Event, To)
|
function NAVYGROUP:Status()
|
||||||
|
|
||||||
-- FSM state.
|
-- FSM state.
|
||||||
local fsmstate=self:GetState()
|
local fsmstate=self:GetState()
|
||||||
@@ -978,6 +978,35 @@ function NAVYGROUP:Status(From, Event, To)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Elements
|
||||||
|
---
|
||||||
|
|
||||||
|
if self.verbose>=2 then
|
||||||
|
local text="Elements:"
|
||||||
|
for i,_element in pairs(self.elements) do
|
||||||
|
local element=_element --Ops.OpsGroup#OPSGROUP.Element
|
||||||
|
|
||||||
|
local name=element.name
|
||||||
|
local status=element.status
|
||||||
|
local unit=element.unit
|
||||||
|
local life,life0=self:GetLifePoints(element)
|
||||||
|
|
||||||
|
local life0=element.life0
|
||||||
|
|
||||||
|
-- Get ammo.
|
||||||
|
local ammo=self:GetAmmoElement(element)
|
||||||
|
|
||||||
|
-- Output text for element.
|
||||||
|
text=text..string.format("\n[%d] %s: status=%s, life=%.1f/%.1f, guns=%d, rockets=%d, bombs=%d, missiles=%d, cargo=%d/%d kg",
|
||||||
|
i, name, status, life, life0, ammo.Guns, ammo.Rockets, ammo.Bombs, ammo.Missiles, element.weightCargo, element.weightMaxCargo)
|
||||||
|
end
|
||||||
|
if #self.elements==0 then
|
||||||
|
text=text.." none!"
|
||||||
|
end
|
||||||
|
self:I(self.lid..text)
|
||||||
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Engage Detected Targets
|
-- Engage Detected Targets
|
||||||
---
|
---
|
||||||
@@ -1041,7 +1070,7 @@ function NAVYGROUP:onafterSpawned(From, Event, To)
|
|||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
if self.verbose>=1 then
|
if self.verbose>=1 then
|
||||||
local text=string.format("Initialized Navy Group %s:\n", self.groupname)
|
local text=string.format("Initialized Navy Group %s [GID=%d]:\n", self.groupname, self.group:GetID())
|
||||||
text=text..string.format("Unit type = %s\n", self.actype)
|
text=text..string.format("Unit type = %s\n", self.actype)
|
||||||
text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedMax))
|
text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedMax))
|
||||||
text=text..string.format("Speed cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise))
|
text=text..string.format("Speed cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise))
|
||||||
@@ -1269,7 +1298,7 @@ function NAVYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Depth)
|
|||||||
if self.verbose>=10 then
|
if self.verbose>=10 then
|
||||||
for i=1,#waypoints do
|
for i=1,#waypoints do
|
||||||
local wp=waypoints[i] --Ops.OpsGroup#OPSGROUP.Waypoint
|
local wp=waypoints[i] --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||||
local text=string.format("%s Waypoint [%d] UID=%d speed=%d", self.groupname, i-1, wp.uid or -1, wp.speed)
|
local text=string.format("%s Waypoint [%d] UID=%d speed=%d m/s", self.groupname, i-1, wp.uid or -1, wp.speed)
|
||||||
self:I(self.lid..text)
|
self:I(self.lid..text)
|
||||||
COORDINATE:NewFromWaypoint(wp):MarkToAll(text)
|
COORDINATE:NewFromWaypoint(wp):MarkToAll(text)
|
||||||
end
|
end
|
||||||
@@ -1841,81 +1870,96 @@ end
|
|||||||
--- Initialize group parameters. Also initializes waypoints if self.waypoints is nil.
|
--- Initialize group parameters. Also initializes waypoints if self.waypoints is nil.
|
||||||
-- @param #NAVYGROUP self
|
-- @param #NAVYGROUP self
|
||||||
-- @param #table Template Template used to init the group. Default is `self.template`.
|
-- @param #table Template Template used to init the group. Default is `self.template`.
|
||||||
|
-- @param #number Delay Delay in seconds before group is initialized. Default `nil`, *i.e.* instantaneous.
|
||||||
-- @return #NAVYGROUP self
|
-- @return #NAVYGROUP self
|
||||||
function NAVYGROUP:_InitGroup(Template)
|
function NAVYGROUP:_InitGroup(Template, Delay)
|
||||||
|
|
||||||
-- First check if group was already initialized.
|
if Delay and Delay>0 then
|
||||||
if self.groupinitialized then
|
-- Delayed call
|
||||||
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
self:ScheduleOnce(Delay, NAVYGROUP._InitGroup, self, Template, 0)
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get template of group.
|
|
||||||
local template=Template or self:_GetTemplate()
|
|
||||||
|
|
||||||
-- Ships are always AI.
|
|
||||||
self.isAI=true
|
|
||||||
|
|
||||||
-- Is (template) group late activated.
|
|
||||||
self.isLateActivated=template.lateActivation
|
|
||||||
|
|
||||||
-- Naval groups cannot be uncontrolled.
|
|
||||||
self.isUncontrolled=false
|
|
||||||
|
|
||||||
-- Max speed in km/h.
|
|
||||||
self.speedMax=self.group:GetSpeedMax()
|
|
||||||
|
|
||||||
-- Is group mobile?
|
|
||||||
if self.speedMax and self.speedMax>3.6 then
|
|
||||||
self.isMobile=true
|
|
||||||
else
|
else
|
||||||
self.isMobile=false
|
|
||||||
self.speedMax = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Cruise speed: 70% of max speed.
|
-- First check if group was already initialized.
|
||||||
self.speedCruise=self.speedMax*0.7
|
if self.groupinitialized then
|
||||||
|
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Group ammo.
|
-- Get template of group.
|
||||||
self.ammo=self:GetAmmoTot()
|
local template=Template or self:_GetTemplate()
|
||||||
|
|
||||||
-- Radio parameters from template. Default is set on spawn if not modified by the user.
|
-- Ships are always AI.
|
||||||
self.radio.On=true -- Radio is always on for ships.
|
self.isAI=true
|
||||||
self.radio.Freq=tonumber(template.units[1].frequency)/1000000
|
|
||||||
self.radio.Modu=tonumber(template.units[1].modulation)
|
-- Is (template) group late activated.
|
||||||
|
self.isLateActivated=template.lateActivation
|
||||||
|
|
||||||
|
-- Naval groups cannot be uncontrolled.
|
||||||
|
self.isUncontrolled=false
|
||||||
|
|
||||||
|
-- Max speed in km/h.
|
||||||
|
self.speedMax=self.group:GetSpeedMax()
|
||||||
|
|
||||||
|
-- Is group mobile?
|
||||||
|
if self.speedMax and self.speedMax>3.6 then
|
||||||
|
self.isMobile=true
|
||||||
|
else
|
||||||
|
self.isMobile=false
|
||||||
|
self.speedMax = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Cruise speed: 70% of max speed.
|
||||||
|
self.speedCruise=self.speedMax*0.7
|
||||||
|
|
||||||
|
-- Group ammo.
|
||||||
|
self.ammo=self:GetAmmoTot()
|
||||||
|
|
||||||
|
-- Radio parameters from template. Default is set on spawn if not modified by the user.
|
||||||
|
self.radio.On=true -- Radio is always on for ships.
|
||||||
|
self.radio.Freq=tonumber(template.units[1].frequency)/1000000
|
||||||
|
self.radio.Modu=tonumber(template.units[1].modulation)
|
||||||
|
|
||||||
|
-- Set default formation. No really applicable for ships.
|
||||||
|
self.optionDefault.Formation="Off Road"
|
||||||
|
self.option.Formation=self.optionDefault.Formation
|
||||||
|
|
||||||
-- Set default formation. No really applicable for ships.
|
-- Default TACAN off (we check if something is set already to keep those values in case of respawn)
|
||||||
self.optionDefault.Formation="Off Road"
|
if not self.tacanDefault then
|
||||||
self.option.Formation=self.optionDefault.Formation
|
self:SetDefaultTACAN(nil, nil, nil, nil, true)
|
||||||
|
end
|
||||||
-- Default TACAN off.
|
if not self.tacan then
|
||||||
self:SetDefaultTACAN(nil, nil, nil, nil, true)
|
self.tacan=UTILS.DeepCopy(self.tacanDefault)
|
||||||
self.tacan=UTILS.DeepCopy(self.tacanDefault)
|
end
|
||||||
|
|
||||||
|
-- Default ICLS off.
|
||||||
|
if not self.iclsDefault then
|
||||||
|
self:SetDefaultICLS(nil, nil, nil, true)
|
||||||
|
end
|
||||||
|
if not self.icls then
|
||||||
|
self.icls=UTILS.DeepCopy(self.iclsDefault)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get all units of the group.
|
||||||
|
local units=self.group:GetUnits()
|
||||||
|
|
||||||
-- Default ICLS off.
|
-- DCS group.
|
||||||
self:SetDefaultICLS(nil, nil, nil, true)
|
local dcsgroup=Group.getByName(self.groupname)
|
||||||
self.icls=UTILS.DeepCopy(self.iclsDefault)
|
local size0=dcsgroup:getInitialSize()
|
||||||
|
|
||||||
-- Get all units of the group.
|
-- Quick check.
|
||||||
local units=self.group:GetUnits()
|
if #units~=size0 then
|
||||||
|
self:E(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units!", #units, size0))
|
||||||
-- DCS group.
|
end
|
||||||
local dcsgroup=Group.getByName(self.groupname)
|
|
||||||
local size0=dcsgroup:getInitialSize()
|
-- Add elemets.
|
||||||
|
for _,unit in pairs(units) do
|
||||||
-- Quick check.
|
self:_AddElementByName(unit:GetName())
|
||||||
if #units~=size0 then
|
end
|
||||||
self:E(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units!", #units, size0))
|
|
||||||
|
-- Init done.
|
||||||
|
self.groupinitialized=true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add elemets.
|
|
||||||
for _,unit in pairs(units) do
|
|
||||||
self:_AddElementByName(unit:GetName())
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Init done.
|
|
||||||
self.groupinitialized=true
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -512,7 +512,7 @@ OPSGROUP.CargoStatus={
|
|||||||
|
|
||||||
--- OpsGroup version.
|
--- OpsGroup version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
OPSGROUP.version="1.0.1"
|
OPSGROUP.version="1.0.4"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -1041,7 +1041,7 @@ function OPSGROUP:SetReturnToLegion(Switch)
|
|||||||
else
|
else
|
||||||
self.legionReturn=true
|
self.legionReturn=true
|
||||||
end
|
end
|
||||||
self:T(self.lid..string.format("Setting ReturnToLetion=%s", tostring(self.legionReturn)))
|
self:T(self.lid..string.format("Setting ReturnToLegion=%s", tostring(self.legionReturn)))
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1333,8 +1333,9 @@ end
|
|||||||
-- @param Core.Point#COORDINATE TargetCoord Coordinate of the target.
|
-- @param Core.Point#COORDINATE TargetCoord Coordinate of the target.
|
||||||
-- @param #number WeaponBitType Weapon type.
|
-- @param #number WeaponBitType Weapon type.
|
||||||
-- @param Core.Point#COORDINATE RefCoord Reference coordinate.
|
-- @param Core.Point#COORDINATE RefCoord Reference coordinate.
|
||||||
|
-- @param #table SurfaceTypes Valid surfaces types of the coordinate. Default any (nil).
|
||||||
-- @return Core.Point#COORDINATE Coordinate in weapon range
|
-- @return Core.Point#COORDINATE Coordinate in weapon range
|
||||||
function OPSGROUP:GetCoordinateInRange(TargetCoord, WeaponBitType, RefCoord)
|
function OPSGROUP:GetCoordinateInRange(TargetCoord, WeaponBitType, RefCoord, SurfaceTypes)
|
||||||
|
|
||||||
local coordInRange=nil --Core.Point#COORDINATE
|
local coordInRange=nil --Core.Point#COORDINATE
|
||||||
|
|
||||||
@@ -1343,35 +1344,58 @@ function OPSGROUP:GetCoordinateInRange(TargetCoord, WeaponBitType, RefCoord)
|
|||||||
-- Get weapon range.
|
-- Get weapon range.
|
||||||
local weapondata=self:GetWeaponData(WeaponBitType)
|
local weapondata=self:GetWeaponData(WeaponBitType)
|
||||||
|
|
||||||
|
-- Heading intervals to search for a possible new coordinate in range.
|
||||||
|
local dh={0, -5, 5, -10, 10, -15, 15, -20, 20, -25, 25, -30, 30, -35, 35, -40, 40, -45, 45, -50, 50, -55, 55, -60, 60, -65, 65, -70, 70, -75, 75, -80, 80}
|
||||||
|
|
||||||
|
-- Function that checks if the given surface type is valid
|
||||||
|
local function _checkSurface(point)
|
||||||
|
if SurfaceTypes then
|
||||||
|
local stype=point:GetSurfaceType()
|
||||||
|
for _,sf in pairs(SurfaceTypes) do
|
||||||
|
if sf==stype then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if weapondata then
|
if weapondata then
|
||||||
|
|
||||||
-- Heading to target.
|
-- Heading to target.
|
||||||
local heading=RefCoord:HeadingTo(TargetCoord)
|
local heading=TargetCoord:HeadingTo(RefCoord)
|
||||||
|
|
||||||
-- Distance to target.
|
-- Distance to target.
|
||||||
local dist=RefCoord:Get2DDistance(TargetCoord)
|
local dist=RefCoord:Get2DDistance(TargetCoord)
|
||||||
|
|
||||||
|
local range=nil
|
||||||
|
if dist>weapondata.RangeMax then
|
||||||
|
range=weapondata.RangeMax
|
||||||
|
self:T(self.lid..string.format("Out of max range = %.1f km by %.1f km for weapon %s", weapondata.RangeMax/1000, (weapondata.RangeMax-dist)/1000, tostring(WeaponBitType)))
|
||||||
|
elseif dist<weapondata.RangeMin then
|
||||||
|
range=weapondata.RangeMin
|
||||||
|
self:T(self.lid..string.format("Out of min range = %.1f km by %.1f km for weapon %s", weapondata.RangeMin/1000, (weapondata.RangeMin-dist)/1000, tostring(WeaponBitType)))
|
||||||
|
end
|
||||||
|
|
||||||
-- Check if we are within range.
|
-- Check if we are within range.
|
||||||
if dist>weapondata.RangeMax then
|
if range then
|
||||||
|
|
||||||
local d=(dist-weapondata.RangeMax)*1.05
|
for _,delta in pairs(dh) do
|
||||||
|
|
||||||
-- New waypoint coord.
|
local h=heading+delta
|
||||||
coordInRange=RefCoord:Translate(d, heading)
|
|
||||||
|
|
||||||
-- Debug info.
|
|
||||||
self:T(self.lid..string.format("Out of max range = %.1f km for weapon %s", weapondata.RangeMax/1000, tostring(WeaponBitType)))
|
|
||||||
elseif dist<weapondata.RangeMin then
|
|
||||||
|
|
||||||
local d=(dist-weapondata.RangeMin)*1.05
|
|
||||||
|
|
||||||
-- New waypoint coord.
|
|
||||||
coordInRange=RefCoord:Translate(d, heading)
|
|
||||||
|
|
||||||
-- Debug info.
|
|
||||||
self:T(self.lid..string.format("Out of min range = %.1f km for weapon %s", weapondata.RangeMax/1000, tostring(WeaponBitType)))
|
|
||||||
else
|
|
||||||
|
|
||||||
|
-- New waypoint coord.
|
||||||
|
coordInRange=TargetCoord:Translate(range, h)
|
||||||
|
|
||||||
|
if _checkSurface(coordInRange) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Already in range for weapon %s", tostring(WeaponBitType)))
|
self:T(self.lid..string.format("Already in range for weapon %s", tostring(WeaponBitType)))
|
||||||
end
|
end
|
||||||
@@ -1450,11 +1474,14 @@ end
|
|||||||
-- @param #number RangeMin Minimum range in nautical miles. Default 0 NM.
|
-- @param #number RangeMin Minimum range in nautical miles. Default 0 NM.
|
||||||
-- @param #number RangeMax Maximum range in nautical miles. Default 10 NM.
|
-- @param #number RangeMax Maximum range in nautical miles. Default 10 NM.
|
||||||
-- @param #number BitType Bit mask of weapon type for which the given min/max ranges apply. Default is `ENUMS.WeaponFlag.Auto`, i.e. for all weapon types.
|
-- @param #number BitType Bit mask of weapon type for which the given min/max ranges apply. Default is `ENUMS.WeaponFlag.Auto`, i.e. for all weapon types.
|
||||||
|
-- @param #function ConversionToMeters Function that converts input units of ranges to meters. Defaul `UTILS.NMToMeters`.
|
||||||
-- @return #OPSGROUP self
|
-- @return #OPSGROUP self
|
||||||
function OPSGROUP:AddWeaponRange(RangeMin, RangeMax, BitType)
|
function OPSGROUP:AddWeaponRange(RangeMin, RangeMax, BitType, ConversionToMeters)
|
||||||
|
|
||||||
RangeMin=UTILS.NMToMeters(RangeMin or 0)
|
ConversionToMeters=ConversionToMeters or UTILS.NMToMeters
|
||||||
RangeMax=UTILS.NMToMeters(RangeMax or 10)
|
|
||||||
|
RangeMin=ConversionToMeters(RangeMin or 0)
|
||||||
|
RangeMax=ConversionToMeters(RangeMax or 10)
|
||||||
|
|
||||||
local weapon={} --#OPSGROUP.WeaponData
|
local weapon={} --#OPSGROUP.WeaponData
|
||||||
|
|
||||||
@@ -4169,7 +4196,7 @@ function OPSGROUP:onbeforeTaskExecute(From, Event, To, Task)
|
|||||||
if self:IsWaiting() then
|
if self:IsWaiting() then
|
||||||
-- Group is already waiting
|
-- Group is already waiting
|
||||||
else
|
else
|
||||||
-- Wait indefinately.
|
-- Wait indefinitely.
|
||||||
local alt=Mission.missionAltitude and UTILS.MetersToFeet(Mission.missionAltitude) or nil
|
local alt=Mission.missionAltitude and UTILS.MetersToFeet(Mission.missionAltitude) or nil
|
||||||
self:Wait(nil, alt)
|
self:Wait(nil, alt)
|
||||||
end
|
end
|
||||||
@@ -4480,7 +4507,7 @@ function OPSGROUP:_UpdateTask(Task, Mission)
|
|||||||
-- Set speed. Default max.
|
-- Set speed. Default max.
|
||||||
local speed=self.speedMax and UTILS.KmphToKnots(self.speedMax) or nil
|
local speed=self.speedMax and UTILS.KmphToKnots(self.speedMax) or nil
|
||||||
if Task.dcstask.params.speed then
|
if Task.dcstask.params.speed then
|
||||||
speed=Task.dcstask.params.speed
|
speed=UTILS.MpsToKnots(Task.dcstask.params.speed)
|
||||||
end
|
end
|
||||||
|
|
||||||
if target then
|
if target then
|
||||||
@@ -5562,10 +5589,13 @@ function OPSGROUP:onafterUnpauseMission(From, Event, To)
|
|||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Unpausing mission %s [%s]", mission:GetName(), mission:GetType()))
|
self:T(self.lid..string.format("Unpausing mission %s [%s]", mission:GetName(), mission:GetType()))
|
||||||
|
|
||||||
|
-- Set state of mission, e.g. for not teleporting again
|
||||||
|
mission.unpaused=true
|
||||||
|
|
||||||
-- Start mission.
|
-- Start mission.
|
||||||
self:MissionStart(mission)
|
self:MissionStart(mission)
|
||||||
|
|
||||||
-- Remove mission from
|
-- Remove mission from pausedmissions queue
|
||||||
for i,mid in pairs(self.pausedmissions) do
|
for i,mid in pairs(self.pausedmissions) do
|
||||||
--self:T(self.lid..string.format("Checking paused mission", mid))
|
--self:T(self.lid..string.format("Checking paused mission", mid))
|
||||||
if mid==mission.auftragsnummer then
|
if mid==mission.auftragsnummer then
|
||||||
@@ -6073,17 +6103,16 @@ function OPSGROUP:RouteToMission(mission, delay)
|
|||||||
-- Target Coord.
|
-- Target Coord.
|
||||||
local targetcoord=mission:GetTargetCoordinate()
|
local targetcoord=mission:GetTargetCoordinate()
|
||||||
|
|
||||||
|
|
||||||
-- In range already?
|
-- In range already?
|
||||||
local inRange=self:InWeaponRange(targetcoord, mission.engageWeaponType)
|
local inRange=self:InWeaponRange(targetcoord, mission.engageWeaponType, waypointcoord)
|
||||||
|
|
||||||
if inRange then
|
if inRange then
|
||||||
|
|
||||||
waypointcoord=self:GetCoordinate(true)
|
--waypointcoord=self:GetCoordinate(true)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
local coordInRange=self:GetCoordinateInRange(targetcoord, mission.engageWeaponType, waypointcoord)
|
local coordInRange=self:GetCoordinateInRange(targetcoord, mission.engageWeaponType, waypointcoord, surfacetypes)
|
||||||
|
|
||||||
if coordInRange then
|
if coordInRange then
|
||||||
|
|
||||||
@@ -6118,7 +6147,32 @@ function OPSGROUP:RouteToMission(mission, delay)
|
|||||||
-- Add mission execution (ingress) waypoint.
|
-- Add mission execution (ingress) waypoint.
|
||||||
local waypoint=nil --#OPSGROUP.Waypoint
|
local waypoint=nil --#OPSGROUP.Waypoint
|
||||||
if self:IsFlightgroup() then
|
if self:IsFlightgroup() then
|
||||||
|
|
||||||
|
|
||||||
|
local ingresscoord = mission:GetMissionIngressCoord()
|
||||||
|
local holdingcoord = mission:GetMissionHoldingCoord()
|
||||||
|
|
||||||
|
if holdingcoord then
|
||||||
|
waypoint=FLIGHTGROUP.AddWaypoint(self, holdingcoord, mission.missionHoldingCoordSpeed or SpeedToMission, uid, UTILS.MetersToFeet(mission.missionHoldingCoordAlt or self.altitudeCruise), false)
|
||||||
|
uid=waypoint.uid
|
||||||
|
-- Orbit until flaghold=1 (true) but max 5 min
|
||||||
|
self.flaghold:Set(0)
|
||||||
|
local TaskOrbit = self.group:TaskOrbit(holdingcoord, mission.missionHoldingCoordAlt, UTILS.KnotsToMps(mission.missionHoldingCoordSpeed or SpeedToMission))
|
||||||
|
local TaskStop = self.group:TaskCondition(nil, self.flaghold.UserFlagName, 1, nil, mission.missionHoldingDuration or 900)
|
||||||
|
local TaskCntr = self.group:TaskControlled(TaskOrbit, TaskStop)
|
||||||
|
local TaskOver = self.group:TaskFunction("FLIGHTGROUP._FinishedWaiting", self)
|
||||||
|
local DCSTasks=self.group:TaskCombo({TaskCntr, TaskOver})
|
||||||
|
-- Add waypoint task. UpdateRoute is called inside.
|
||||||
|
local waypointtask=self:AddTaskWaypoint(DCSTasks, waypoint, "Holding")
|
||||||
|
waypointtask.ismission=false
|
||||||
|
self.isHoldingAtHoldingPoint = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if ingresscoord then
|
||||||
|
waypoint=FLIGHTGROUP.AddWaypoint(self, ingresscoord, mission.missionIngressCoordSpeed or SpeedToMission, uid, UTILS.MetersToFeet(mission.missionIngressCoordAlt or self.altitudeCruise), false)
|
||||||
|
uid=waypoint.uid
|
||||||
|
end
|
||||||
|
|
||||||
waypoint=FLIGHTGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false)
|
waypoint=FLIGHTGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false)
|
||||||
|
|
||||||
elseif self:IsArmygroup() then
|
elseif self:IsArmygroup() then
|
||||||
@@ -6157,7 +6211,7 @@ function OPSGROUP:RouteToMission(mission, delay)
|
|||||||
if egresscoord then
|
if egresscoord then
|
||||||
local Ewaypoint=nil --#OPSGROUP.Waypoint
|
local Ewaypoint=nil --#OPSGROUP.Waypoint
|
||||||
if self:IsFlightgroup() then
|
if self:IsFlightgroup() then
|
||||||
Ewaypoint=FLIGHTGROUP.AddWaypoint(self, egresscoord, SpeedToMission, waypoint.uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false)
|
Ewaypoint=FLIGHTGROUP.AddWaypoint(self, egresscoord, mission.missionEgressCoordSpeed or SpeedToMission, waypoint.uid, UTILS.MetersToFeet(mission.missionEgressCoordAlt or self.altitudeCruise), false)
|
||||||
elseif self:IsArmygroup() then
|
elseif self:IsArmygroup() then
|
||||||
Ewaypoint=ARMYGROUP.AddWaypoint(self, egresscoord, SpeedToMission, waypoint.uid, mission.optionFormation, false)
|
Ewaypoint=ARMYGROUP.AddWaypoint(self, egresscoord, SpeedToMission, waypoint.uid, mission.optionFormation, false)
|
||||||
elseif self:IsNavygroup() then
|
elseif self:IsNavygroup() then
|
||||||
@@ -6181,7 +6235,7 @@ function OPSGROUP:RouteToMission(mission, delay)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Check if group is mobile. Note that some immobile units report a speed of 1 m/s = 3.6 km/h.
|
-- Check if group is mobile. Note that some immobile units report a speed of 1 m/s = 3.6 km/h.
|
||||||
if self.speedMax<=3.6 or mission.teleport then
|
if (self.speedMax<=3.6 or mission.teleport) and not mission.unpaused then
|
||||||
|
|
||||||
-- Teleport to waypoint coordinate. Mission will not be paused.
|
-- Teleport to waypoint coordinate. Mission will not be paused.
|
||||||
self:Teleport(waypointcoord, nil, true)
|
self:Teleport(waypointcoord, nil, true)
|
||||||
@@ -7675,6 +7729,7 @@ function OPSGROUP:Teleport(Coordinate, Delay, NoPauseMission)
|
|||||||
unit.heading=math.rad(heading)
|
unit.heading=math.rad(heading)
|
||||||
unit.psi=-unit.heading
|
unit.psi=-unit.heading
|
||||||
else
|
else
|
||||||
|
-- Remove unit from spawn template because it is already dead
|
||||||
table.remove(units, i)
|
table.remove(units, i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -7762,25 +7817,41 @@ function OPSGROUP:_Respawn(Delay, Template, Reset)
|
|||||||
-- Despawn old group. Dont trigger any remove unit event since this is a respawn.
|
-- Despawn old group. Dont trigger any remove unit event since this is a respawn.
|
||||||
self:Despawn(0, true)
|
self:Despawn(0, true)
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
---
|
|
||||||
-- Group is NOT ALIVE
|
|
||||||
---
|
|
||||||
|
|
||||||
-- Ensure elements in utero.
|
|
||||||
for _,_element in pairs(self.elements) do
|
|
||||||
local element=_element --#OPSGROUP.Element
|
|
||||||
self:ElementInUtero(element)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Ensure elements in utero.
|
||||||
|
for _,_element in pairs(self.elements) do
|
||||||
|
local element=_element --#OPSGROUP.Element
|
||||||
|
if element and element.status~=OPSGROUP.ElementStatus.DEAD then
|
||||||
|
self:ElementInUtero(element)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Spawn with a little delay (especially Navy groups caused problems if they were instantly respawned)
|
||||||
|
self:_Spawn(0.01, Template)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Spawn group from a given template.
|
||||||
|
-- @param #OPSGROUP self
|
||||||
|
-- @param #number Delay Delay in seconds before respawn happens. Default 0.
|
||||||
|
-- @param DCS#Template Template (optional) The template of the Group retrieved with GROUP:GetTemplate(). If the template is not provided, the template will be retrieved of the group itself.
|
||||||
|
-- @return #OPSGROUP self
|
||||||
|
function OPSGROUP:_Spawn(Delay, Template)
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, OPSGROUP._Spawn, self, 0, Template)
|
||||||
|
else
|
||||||
-- Debug output.
|
-- Debug output.
|
||||||
self:T({Template=Template})
|
self:T2({Template=Template})
|
||||||
|
|
||||||
-- Spawn new group.
|
-- Spawn new group.
|
||||||
self.group=_DATABASE:Spawn(Template)
|
self.group=_DATABASE:Spawn(Template)
|
||||||
|
--local countryID=self.group:GetCountry()
|
||||||
|
--local categoryID=self.group:GetCategory()
|
||||||
|
--local dcsgroup=coalition.addGroup(countryID, categoryID, Template)
|
||||||
|
|
||||||
-- Set DCS group and controller.
|
-- Set DCS group and controller.
|
||||||
self.dcsgroup=self:GetDCSGroup()
|
self.dcsgroup=self:GetDCSGroup()
|
||||||
@@ -7794,7 +7865,6 @@ function OPSGROUP:_Respawn(Delay, Template, Reset)
|
|||||||
self.isDead=false
|
self.isDead=false
|
||||||
self.isDestroyed=false
|
self.isDestroyed=false
|
||||||
|
|
||||||
|
|
||||||
self.groupinitialized=false
|
self.groupinitialized=false
|
||||||
self.wpcounter=1
|
self.wpcounter=1
|
||||||
self.currentwp=1
|
self.currentwp=1
|
||||||
@@ -7802,15 +7872,12 @@ function OPSGROUP:_Respawn(Delay, Template, Reset)
|
|||||||
-- Init waypoints.
|
-- Init waypoints.
|
||||||
self:_InitWaypoints()
|
self:_InitWaypoints()
|
||||||
|
|
||||||
-- Init Group.
|
-- Init Group. This call is delayed because NAVY groups did not like to be initialized just yet (group did not contain any units).
|
||||||
self:_InitGroup(Template)
|
self:_InitGroup(Template, 0.001)
|
||||||
|
|
||||||
-- Reset events.
|
-- Reset events.
|
||||||
--self:ResetEvents()
|
--self:ResetEvents()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "InUtero" event.
|
--- On after "InUtero" event.
|
||||||
@@ -7830,24 +7897,6 @@ end
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
function OPSGROUP:onafterDamaged(From, Event, To)
|
function OPSGROUP:onafterDamaged(From, Event, To)
|
||||||
self:T(self.lid..string.format("Group damaged at t=%.3f", timer.getTime()))
|
self:T(self.lid..string.format("Group damaged at t=%.3f", timer.getTime()))
|
||||||
|
|
||||||
--[[
|
|
||||||
local lifemin=nil
|
|
||||||
for _,_element in pairs(self.elements) do
|
|
||||||
local element=_element --#OPSGROUP.Element
|
|
||||||
if element.status~=OPSGROUP.ElementStatus.DEAD and element.status~=OPSGROUP.ElementStatus.INUTERO then
|
|
||||||
local life, life0=self:GetLifePoints(element)
|
|
||||||
if lifemin==nil or life<lifemin then
|
|
||||||
lifemin=life
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if lifemin and lifemin/self.life<0.5 then
|
|
||||||
self:RTB()
|
|
||||||
end
|
|
||||||
]]
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "Destroyed" event.
|
--- On after "Destroyed" event.
|
||||||
@@ -8999,7 +9048,7 @@ function OPSGROUP:AddWeightCargo(UnitName, Weight)
|
|||||||
self:T(self.lid..string.format("%s: Adding %.1f kg cargo weight. New cargo weight=%.1f kg", UnitName, Weight, element.weightCargo))
|
self:T(self.lid..string.format("%s: Adding %.1f kg cargo weight. New cargo weight=%.1f kg", UnitName, Weight, element.weightCargo))
|
||||||
|
|
||||||
-- For airborne units, we set the weight in game.
|
-- For airborne units, we set the weight in game.
|
||||||
if self.isFlightgroup then
|
if self.isFlightgroup and element.unit and element.unit:IsAlive() then -- #2272 trying to deduct cargo weight from possibly dead units
|
||||||
trigger.action.setUnitInternalCargo(element.name, element.weightCargo) --https://wiki.hoggitworld.com/view/DCS_func_setUnitInternalCargo
|
trigger.action.setUnitInternalCargo(element.name, element.weightCargo) --https://wiki.hoggitworld.com/view/DCS_func_setUnitInternalCargo
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -11444,10 +11493,10 @@ function OPSGROUP:_InitWaypoints(WpIndexMin, WpIndexMax)
|
|||||||
if self:IsFlightgroup() then
|
if self:IsFlightgroup() then
|
||||||
|
|
||||||
-- Get home and destination airbases from waypoints.
|
-- Get home and destination airbases from waypoints.
|
||||||
self.homebase=self.homebase or self:GetHomebaseFromWaypoints()
|
self.homebase=self.homebase or self:GetHomebaseFromWaypoints() -- GetHomebaseFromWaypoints() returns carriers or destroyers if no airbase is found.
|
||||||
local destbase=self:GetDestinationFromWaypoints()
|
local destbase=self:GetDestinationFromWaypoints()
|
||||||
self.destbase=self.destbase or destbase
|
self.destbase=self.destbase or destbase
|
||||||
self.currbase=self:GetHomebaseFromWaypoints()
|
self.currbase=self:GetHomebaseFromWaypoints() -- Skipped To fix RTB issue
|
||||||
|
|
||||||
--env.info("FF home base "..(self.homebase and self.homebase:GetName() or "unknown"))
|
--env.info("FF home base "..(self.homebase and self.homebase:GetName() or "unknown"))
|
||||||
--env.info("FF dest base "..(self.destbase and self.destbase:GetName() or "unknown"))
|
--env.info("FF dest base "..(self.destbase and self.destbase:GetName() or "unknown"))
|
||||||
@@ -11458,7 +11507,7 @@ function OPSGROUP:_InitWaypoints(WpIndexMin, WpIndexMax)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Set destination to homebase.
|
-- Set destination to homebase.
|
||||||
if self.destbase==nil then
|
if self.destbase==nil then -- Skipped To fix RTB issue
|
||||||
self.destbase=self.homebase
|
self.destbase=self.homebase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,8 @@
|
|||||||
-- @field #number threatlevelCapture Threat level necessary to capture a zone.
|
-- @field #number threatlevelCapture Threat level necessary to capture a zone.
|
||||||
-- @field Core.Set#SET_UNIT ScanUnitSet Set of scanned units.
|
-- @field Core.Set#SET_UNIT ScanUnitSet Set of scanned units.
|
||||||
-- @field Core.Set#SET_GROUP ScanGroupSet Set of scanned groups.
|
-- @field Core.Set#SET_GROUP ScanGroupSet Set of scanned groups.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @field #number UpdateSeconds Run status every this many seconds.
|
||||||
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *Gentlemen, when the enemy is committed to a mistake we must not interrupt him too soon.* --- Horation Nelson
|
--- *Gentlemen, when the enemy is committed to a mistake we must not interrupt him too soon.* --- Horation Nelson
|
||||||
--
|
--
|
||||||
@@ -77,6 +78,7 @@ OPSZONE = {
|
|||||||
Tnut = 0,
|
Tnut = 0,
|
||||||
chiefs = {},
|
chiefs = {},
|
||||||
Missions = {},
|
Missions = {},
|
||||||
|
UpdateSeconds = 120,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- OPSZONE.MISSION
|
--- OPSZONE.MISSION
|
||||||
@@ -97,7 +99,7 @@ OPSZONE.ZoneType={
|
|||||||
|
|
||||||
--- OPSZONE class version.
|
--- OPSZONE class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
OPSZONE.version="0.6.1"
|
OPSZONE.version="0.6.2"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -490,6 +492,19 @@ function OPSZONE:SetDrawZone(Switch)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set if zone is drawn on the F10 map for the owner coalition only.
|
||||||
|
-- @param #OPSZONE self
|
||||||
|
-- @param #boolean Switch If `false` or `nil`, draw zone for all coalitions. If `true`, zone is drawn for the owning coalition only if drawZone is true.
|
||||||
|
-- @return #OPSZONE self
|
||||||
|
function OPSZONE:SetDrawZoneForCoalition(Switch)
|
||||||
|
if Switch==true then
|
||||||
|
self.drawZoneForCoalition=true
|
||||||
|
else
|
||||||
|
self.drawZoneForCoalition=false
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set if a marker on the F10 map shows the current zone status.
|
--- Set if a marker on the F10 map shows the current zone status.
|
||||||
-- @param #OPSZONE self
|
-- @param #OPSZONE self
|
||||||
-- @param #boolean Switch If `true`, zone is marked. If `false` or `nil`, zone is not marked.
|
-- @param #boolean Switch If `true`, zone is marked. If `false` or `nil`, zone is not marked.
|
||||||
@@ -710,6 +725,7 @@ end
|
|||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
|
-- @return #OPSZONE self
|
||||||
function OPSZONE:onafterStart(From, Event, To)
|
function OPSZONE:onafterStart(From, Event, To)
|
||||||
|
|
||||||
-- Info.
|
-- Info.
|
||||||
@@ -719,13 +735,15 @@ function OPSZONE:onafterStart(From, Event, To)
|
|||||||
self.timerStatus=self.timerStatus or TIMER:New(OPSZONE.Status, self)
|
self.timerStatus=self.timerStatus or TIMER:New(OPSZONE.Status, self)
|
||||||
|
|
||||||
-- Status update.
|
-- Status update.
|
||||||
self.timerStatus:Start(1, 120)
|
local EveryUpdateIn = self.UpdateSeconds or 120
|
||||||
|
self.timerStatus:Start(1, EveryUpdateIn)
|
||||||
|
|
||||||
-- Handle base captured event.
|
-- Handle base captured event.
|
||||||
if self.airbase then
|
if self.airbase then
|
||||||
self:HandleEvent(EVENTS.BaseCaptured)
|
self:HandleEvent(EVENTS.BaseCaptured)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stop OPSZONE FSM.
|
--- Stop OPSZONE FSM.
|
||||||
@@ -837,8 +855,12 @@ function OPSZONE:onafterCaptured(From, Event, To, NewOwnerCoalition)
|
|||||||
self.zone:UndrawZone()
|
self.zone:UndrawZone()
|
||||||
|
|
||||||
local color=self:_GetZoneColor()
|
local color=self:_GetZoneColor()
|
||||||
|
|
||||||
self.zone:DrawZone(nil, color, 1.0, color, 0.5)
|
local coalition = nil
|
||||||
|
if self.drawZoneForCoalition then
|
||||||
|
coalition = self.ownerCurrent
|
||||||
|
end
|
||||||
|
self.zone:DrawZone(coalition, color, 1.0, color, 0.5)
|
||||||
end
|
end
|
||||||
|
|
||||||
for _,_chief in pairs(self.chiefs) do
|
for _,_chief in pairs(self.chiefs) do
|
||||||
@@ -913,8 +935,12 @@ function OPSZONE:onenterGuarded(From, Event, To)
|
|||||||
self.zone:UndrawZone()
|
self.zone:UndrawZone()
|
||||||
|
|
||||||
local color=self:_GetZoneColor()
|
local color=self:_GetZoneColor()
|
||||||
|
|
||||||
self.zone:DrawZone(nil, color, 1.0, color, 0.5)
|
local coalition = nil
|
||||||
|
if self.drawZoneForCoalition then
|
||||||
|
coalition = self.ownerCurrent
|
||||||
|
end
|
||||||
|
self.zone:DrawZone(coalition, color, 1.0, color, 0.5)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -954,9 +980,13 @@ function OPSZONE:onenterAttacked(From, Event, To, AttackerCoalition)
|
|||||||
|
|
||||||
-- Color.
|
-- Color.
|
||||||
local color={1, 204/255, 204/255}
|
local color={1, 204/255, 204/255}
|
||||||
|
|
||||||
|
local coalition = nil
|
||||||
|
if self.drawZoneForCoalition then
|
||||||
|
coalition = self.ownerCurrent
|
||||||
|
end
|
||||||
-- Draw zone.
|
-- Draw zone.
|
||||||
self.zone:DrawZone(nil, color, 1.0, color, 0.5)
|
self.zone:DrawZone(coalition, color, 1.0, color, 0.5)
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_CleanMissionTable()
|
self:_CleanMissionTable()
|
||||||
@@ -987,8 +1017,12 @@ function OPSZONE:onenterEmpty(From, Event, To)
|
|||||||
self.zone:UndrawZone()
|
self.zone:UndrawZone()
|
||||||
|
|
||||||
local color=self:_GetZoneColor()
|
local color=self:_GetZoneColor()
|
||||||
|
|
||||||
self.zone:DrawZone(nil, color, 1.0, color, 0.2)
|
local coalition = nil
|
||||||
|
if self.drawZoneForCoalition then
|
||||||
|
coalition = self.ownerCurrent
|
||||||
|
end
|
||||||
|
self.zone:DrawZone(coalition, color, 1.0, color, 0.2)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1285,7 +1319,7 @@ function OPSZONE:EvaluateZone()
|
|||||||
|
|
||||||
if Nblu>0 then
|
if Nblu>0 then
|
||||||
|
|
||||||
if not self:IsAttacked() and self.Tnut>=self.threatlevelCapture then
|
if not self:IsAttacked() and self.Tblu>=self.threatlevelCapture then
|
||||||
self:Attacked(coalition.side.BLUE)
|
self:Attacked(coalition.side.BLUE)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1337,7 +1371,7 @@ function OPSZONE:EvaluateZone()
|
|||||||
|
|
||||||
if Nred>0 then
|
if Nred>0 then
|
||||||
|
|
||||||
if not self:IsAttacked() and self.Tnut>=self.threatlevelCapture then
|
if not self:IsAttacked() and self.Tred>=self.threatlevelCapture then
|
||||||
-- Red is attacking blue zone.
|
-- Red is attacking blue zone.
|
||||||
self:Attacked(coalition.side.RED)
|
self:Attacked(coalition.side.RED)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -80,6 +80,7 @@
|
|||||||
-- @field #boolean smokeownposition
|
-- @field #boolean smokeownposition
|
||||||
-- @field #table SmokeOwn
|
-- @field #table SmokeOwn
|
||||||
-- @field #boolean smokeaveragetargetpos
|
-- @field #boolean smokeaveragetargetpos
|
||||||
|
-- @field #boolean reporttostringbullsonly
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -105,7 +106,7 @@ PLAYERRECCE = {
|
|||||||
ClassName = "PLAYERRECCE",
|
ClassName = "PLAYERRECCE",
|
||||||
verbose = true,
|
verbose = true,
|
||||||
lid = nil,
|
lid = nil,
|
||||||
version = "0.1.23",
|
version = "0.1.26",
|
||||||
ViewZone = {},
|
ViewZone = {},
|
||||||
ViewZoneVisual = {},
|
ViewZoneVisual = {},
|
||||||
ViewZoneLaser = {},
|
ViewZoneLaser = {},
|
||||||
@@ -133,7 +134,8 @@ PLAYERRECCE = {
|
|||||||
TargetCache = nil,
|
TargetCache = nil,
|
||||||
smokeownposition = false,
|
smokeownposition = false,
|
||||||
SmokeOwn = {},
|
SmokeOwn = {},
|
||||||
smokeaveragetargetpos = false,
|
smokeaveragetargetpos = true,
|
||||||
|
reporttostringbullsonly = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -152,7 +154,8 @@ PLAYERRECCE.LaserRelativePos = {
|
|||||||
["SA342Minigun"] = { x = 1.7, y = 1.2, z = 0 },
|
["SA342Minigun"] = { x = 1.7, y = 1.2, z = 0 },
|
||||||
["SA342L"] = { x = 1.7, y = 1.2, z = 0 },
|
["SA342L"] = { x = 1.7, y = 1.2, z = 0 },
|
||||||
["Ka-50"] = { x = 6.1, y = -0.85 , z = 0 },
|
["Ka-50"] = { x = 6.1, y = -0.85 , z = 0 },
|
||||||
["Ka-50_3"] = { x = 6.1, y = -0.85 , z = 0 }
|
["Ka-50_3"] = { x = 6.1, y = -0.85 , z = 0 },
|
||||||
|
["OH58D"] = {x = 0, y = 2.8, z = 0},
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -164,7 +167,8 @@ PLAYERRECCE.MaxViewDistance = {
|
|||||||
["SA342Minigun"] = 8000,
|
["SA342Minigun"] = 8000,
|
||||||
["SA342L"] = 8000,
|
["SA342L"] = 8000,
|
||||||
["Ka-50"] = 8000,
|
["Ka-50"] = 8000,
|
||||||
["Ka-50_3"] = 8000,
|
["Ka-50_3"] = 8000,
|
||||||
|
["OH58D"] = 8000,
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -176,7 +180,8 @@ PLAYERRECCE.Cameraheight = {
|
|||||||
["SA342Minigun"] = 2.85,
|
["SA342Minigun"] = 2.85,
|
||||||
["SA342L"] = 2.85,
|
["SA342L"] = 2.85,
|
||||||
["Ka-50"] = 0.5,
|
["Ka-50"] = 0.5,
|
||||||
["Ka-50_3"] = 0.5,
|
["Ka-50_3"] = 0.5,
|
||||||
|
["OH58D"] = 4.25,
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -188,7 +193,8 @@ PLAYERRECCE.CanLase = {
|
|||||||
["SA342Minigun"] = false, -- no optics
|
["SA342Minigun"] = false, -- no optics
|
||||||
["SA342L"] = true,
|
["SA342L"] = true,
|
||||||
["Ka-50"] = true,
|
["Ka-50"] = true,
|
||||||
["Ka-50_3"] = true,
|
["Ka-50_3"] = true,
|
||||||
|
["OH58D"] = false, -- has onboard and useable laser
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -236,6 +242,8 @@ function PLAYERRECCE:New(Name, Coalition, PlayerSet)
|
|||||||
|
|
||||||
self.minthreatlevel = 0
|
self.minthreatlevel = 0
|
||||||
|
|
||||||
|
self.reporttostringbullsonly = true
|
||||||
|
|
||||||
self.TForget = 600
|
self.TForget = 600
|
||||||
self.TargetCache = FIFO:New()
|
self.TargetCache = FIFO:New()
|
||||||
|
|
||||||
@@ -542,7 +550,7 @@ function PLAYERRECCE:SetAttackSet(AttackSet)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
---[Internal] Check Gazelle camera in on
|
---[Internal] Check Helicopter camera in on
|
||||||
-- @param #PLAYERRECCE self
|
-- @param #PLAYERRECCE self
|
||||||
-- @param Wrapper.Client#CLIENT client
|
-- @param Wrapper.Client#CLIENT client
|
||||||
-- @param #string playername
|
-- @param #string playername
|
||||||
@@ -558,6 +566,12 @@ function PLAYERRECCE:_CameraOn(client,playername)
|
|||||||
if vivihorizontal < -0.7 or vivihorizontal > 0.7 then
|
if vivihorizontal < -0.7 or vivihorizontal > 0.7 then
|
||||||
camera = false
|
camera = false
|
||||||
end
|
end
|
||||||
|
elseif string.find(typename,"OH58") then
|
||||||
|
local dcsunit = Unit.getByName(client:GetName())
|
||||||
|
local vivihorizontal = dcsunit:getDrawArgumentValue(528) or 0 -- Kiow
|
||||||
|
if vivihorizontal < -0.527 or vivihorizontal > 0.527 then
|
||||||
|
camera = false
|
||||||
|
end
|
||||||
elseif string.find(typename,"Ka-50") then
|
elseif string.find(typename,"Ka-50") then
|
||||||
camera = true
|
camera = true
|
||||||
end
|
end
|
||||||
@@ -565,6 +579,52 @@ function PLAYERRECCE:_CameraOn(client,playername)
|
|||||||
return camera
|
return camera
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [Internal] Get the view parameters from a Kiowa MMS camera
|
||||||
|
-- @param #PLAYERRECCE self
|
||||||
|
-- @param Wrapper.Unit#UNIT Kiowa
|
||||||
|
-- @return #number cameraheading in degrees.
|
||||||
|
-- @return #number cameranodding in degrees.
|
||||||
|
-- @return #number maxview in meters.
|
||||||
|
-- @return #boolean cameraison If true, camera is on, else off.
|
||||||
|
function PLAYERRECCE:_GetKiowaMMSSight(Kiowa)
|
||||||
|
self:T(self.lid.."_GetKiowaMMSSight")
|
||||||
|
local unit = Kiowa -- Wrapper.Unit#UNIT
|
||||||
|
if unit and unit:IsAlive() then
|
||||||
|
local dcsunit = Unit.getByName(Kiowa:GetName())
|
||||||
|
--[[
|
||||||
|
shagrat — 01/01/2025 23:13
|
||||||
|
Found the necessary ARGS for the Kiowa MMS angle and rotation:
|
||||||
|
Arg 527 vertical movement
|
||||||
|
0 = neutral
|
||||||
|
-1.0 = max depression (30° max depression angle)
|
||||||
|
+1.0 = max elevation angle (30° max elevation angle)
|
||||||
|
|
||||||
|
Arg 528 horizontal movement
|
||||||
|
0 = forward (0 degr)
|
||||||
|
-0.25 = 90° left
|
||||||
|
-0.5 = rear (180°) left (max 190° = -0.527
|
||||||
|
+0.25 = 90° right
|
||||||
|
+0.5 = 180° right (max 190° = 0.527)
|
||||||
|
--]]
|
||||||
|
local mmshorizontal = dcsunit:getDrawArgumentValue(528) or 0
|
||||||
|
local mmsvertical = dcsunit:getDrawArgumentValue(527) or 0
|
||||||
|
self:T(string.format("Kiowa MMS Arguments Read: H %.3f V %.3f",mmshorizontal,mmsvertical))
|
||||||
|
local mmson = true
|
||||||
|
if mmshorizontal < -0.527 or mmshorizontal > 0.527 then mmson = false end
|
||||||
|
local horizontalview = mmshorizontal / 0.527 * 190
|
||||||
|
local heading = unit:GetHeading()
|
||||||
|
local mmsheading = (heading+horizontalview)%360
|
||||||
|
--local mmsyaw = mmsvertical * 30
|
||||||
|
local mmsyaw = math.atan(mmsvertical)*40
|
||||||
|
local maxview = self:_GetActualMaxLOSight(unit,mmsheading, mmsyaw,not mmson)
|
||||||
|
if maxview > 8000 then maxview = 8000 end
|
||||||
|
self:T(string.format("Kiowa MMS Heading %d, Yaw %d, MaxView %dm MMS On %s",mmsheading,mmsyaw,maxview,tostring(mmson)))
|
||||||
|
return mmsheading,mmsyaw,maxview,mmson
|
||||||
|
end
|
||||||
|
return 0,0,0,false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- [Internal] Get the view parameters from a Gazelle camera
|
--- [Internal] Get the view parameters from a Gazelle camera
|
||||||
-- @param #PLAYERRECCE self
|
-- @param #PLAYERRECCE self
|
||||||
-- @param Wrapper.Unit#UNIT Gazelle
|
-- @param Wrapper.Unit#UNIT Gazelle
|
||||||
@@ -593,40 +653,15 @@ function PLAYERRECCE:_GetGazelleVivianneSight(Gazelle)
|
|||||||
vivioff = true
|
vivioff = true
|
||||||
return 0,0,0,false
|
return 0,0,0,false
|
||||||
end
|
end
|
||||||
vivivertical = vivivertical / 1.10731 -- normalize
|
|
||||||
local horizontalview = vivihorizontal * -180
|
local horizontalview = vivihorizontal * -180
|
||||||
local verticalview = vivivertical * 30 -- ca +/- 30°
|
--local verticalview = vivivertical * 30 -- ca +/- 30°
|
||||||
--self:I(string.format("vivihorizontal=%.5f | vivivertical=%.5f",vivihorizontal,vivivertical))
|
local verticalview = math.atan(vivivertical)
|
||||||
--self:I(string.format("horizontal=%.5f | vertical=%.5f",horizontalview,verticalview))
|
|
||||||
local heading = unit:GetHeading()
|
local heading = unit:GetHeading()
|
||||||
local viviheading = (heading+horizontalview)%360
|
local viviheading = (heading+horizontalview)%360
|
||||||
local maxview = self:_GetActualMaxLOSight(unit,viviheading, verticalview,vivioff)
|
local maxview = self:_GetActualMaxLOSight(unit,viviheading, verticalview,vivioff)
|
||||||
--self:I(string.format("maxview=%.5f",maxview))
|
|
||||||
-- visual skew
|
|
||||||
local factor = 3.15
|
|
||||||
self.GazelleViewFactors = {
|
|
||||||
[1]=1.18,
|
|
||||||
[2]=1.32,
|
|
||||||
[3]=1.46,
|
|
||||||
[4]=1.62,
|
|
||||||
[5]=1.77,
|
|
||||||
[6]=1.85,
|
|
||||||
[7]=2.05,
|
|
||||||
[8]=2.05,
|
|
||||||
[9]=2.3,
|
|
||||||
[10]=2.3,
|
|
||||||
[11]=2.27,
|
|
||||||
[12]=2.27,
|
|
||||||
[13]=2.43,
|
|
||||||
}
|
|
||||||
local lfac = UTILS.Round(maxview,-2)
|
|
||||||
if lfac <= 1300 then
|
|
||||||
--factor = self.GazelleViewFactors[lfac/100]
|
|
||||||
factor = 3.15
|
|
||||||
maxview = math.ceil((maxview*factor)/100)*100
|
|
||||||
end
|
|
||||||
if maxview > 8000 then maxview = 8000 end
|
if maxview > 8000 then maxview = 8000 end
|
||||||
--self:I(string.format("corrected maxview=%.5f",maxview))
|
|
||||||
return viviheading, verticalview,maxview, not vivioff
|
return viviheading, verticalview,maxview, not vivioff
|
||||||
end
|
end
|
||||||
return 0,0,0,false
|
return 0,0,0,false
|
||||||
@@ -647,20 +682,20 @@ function PLAYERRECCE:_GetActualMaxLOSight(unit,vheading, vnod, vivoff)
|
|||||||
if unit and unit:IsAlive() then
|
if unit and unit:IsAlive() then
|
||||||
local typename = unit:GetTypeName()
|
local typename = unit:GetTypeName()
|
||||||
maxview = self.MaxViewDistance[typename] or 8000
|
maxview = self.MaxViewDistance[typename] or 8000
|
||||||
local CamHeight = self.Cameraheight[typename] or 0
|
local CamHeight = self.Cameraheight[typename] or 1
|
||||||
if vnod < 0 then
|
if vnod < -2 then
|
||||||
-- Looking down
|
-- Looking down
|
||||||
-- determine max distance we're looking at
|
-- determine max distance we're looking at
|
||||||
local beta = 90
|
local beta = 90
|
||||||
local gamma = math.floor(90-vnod)
|
local gamma = 90-math.abs(vnod)
|
||||||
local alpha = math.floor(180-beta-gamma)
|
local alpha = 90-gamma
|
||||||
local a = unit:GetHeight()-unit:GetCoordinate():GetLandHeight()+CamHeight
|
local a = unit:GetHeight()-unit:GetCoordinate():GetLandHeight()+CamHeight
|
||||||
local b = a / math.sin(math.rad(alpha))
|
local b = a / math.sin(math.rad(alpha))
|
||||||
local c = b * math.sin(math.rad(gamma))
|
local c = b * math.sin(math.rad(gamma))
|
||||||
maxview = c*1.2 -- +20%
|
maxview = c*1.2 -- +20%
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return math.abs(maxview)
|
return math.ceil(math.abs(maxview))
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [User] Set callsign options for TTS output. See @{Wrapper.Group#GROUP.GetCustomCallSign}() on how to set customized callsigns.
|
--- [User] Set callsign options for TTS output. See @{Wrapper.Group#GROUP.GetCustomCallSign}() on how to set customized callsigns.
|
||||||
@@ -669,8 +704,10 @@ end
|
|||||||
-- @param #boolean Keepnumber If true, keep the **customized callsign** in the #GROUP name for players as-is, no amendments or numbers.
|
-- @param #boolean Keepnumber If true, keep the **customized callsign** in the #GROUP name for players as-is, no amendments or numbers.
|
||||||
-- @param #table CallsignTranslations (optional) Table to translate between DCS standard callsigns and bespoke ones. Does not apply if using customized
|
-- @param #table CallsignTranslations (optional) Table to translate between DCS standard callsigns and bespoke ones. Does not apply if using customized
|
||||||
-- callsigns from playername or group name.
|
-- callsigns from playername or group name.
|
||||||
|
-- @param #func CallsignCustomFunc (Optional) For player names only(!). If given, this function will return the callsign. Needs to take the groupname and the playername as first two arguments.
|
||||||
|
-- @param #arg ... (Optional) Comma separated arguments to add to the custom function call after groupname and playername.
|
||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
function PLAYERRECCE:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTranslations)
|
function PLAYERRECCE:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTranslations,CallsignCustomFunc,...)
|
||||||
if not ShortCallsign or ShortCallsign == false then
|
if not ShortCallsign or ShortCallsign == false then
|
||||||
self.ShortCallsign = false
|
self.ShortCallsign = false
|
||||||
else
|
else
|
||||||
@@ -678,6 +715,8 @@ function PLAYERRECCE:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTransla
|
|||||||
end
|
end
|
||||||
self.Keepnumber = Keepnumber or false
|
self.Keepnumber = Keepnumber or false
|
||||||
self.CallsignTranslations = CallsignTranslations
|
self.CallsignTranslations = CallsignTranslations
|
||||||
|
self.CallsignCustomFunc = CallsignCustomFunc
|
||||||
|
self.CallsignCustomArgs = arg or {}
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -799,7 +838,7 @@ function PLAYERRECCE:_GetTargetSet(unit,camera,laser)
|
|||||||
local minview = 0
|
local minview = 0
|
||||||
local typename = unit:GetTypeName()
|
local typename = unit:GetTypeName()
|
||||||
local playername = unit:GetPlayerName()
|
local playername = unit:GetPlayerName()
|
||||||
local maxview = self.MaxViewDistance[typename] or 5000
|
local maxview = self.MaxViewDistance[typename] or 8000
|
||||||
local heading,nod,maxview,angle = 0,30,8000,10
|
local heading,nod,maxview,angle = 0,30,8000,10
|
||||||
local camon = false
|
local camon = false
|
||||||
local name = unit:GetName()
|
local name = unit:GetName()
|
||||||
@@ -807,16 +846,25 @@ function PLAYERRECCE:_GetTargetSet(unit,camera,laser)
|
|||||||
heading,nod,maxview,camon = self:_GetGazelleVivianneSight(unit)
|
heading,nod,maxview,camon = self:_GetGazelleVivianneSight(unit)
|
||||||
angle=10
|
angle=10
|
||||||
-- Model nod and actual TV view don't compute
|
-- Model nod and actual TV view don't compute
|
||||||
maxview = self.MaxViewDistance[typename] or 5000
|
maxview = self.MaxViewDistance[typename] or 8000
|
||||||
elseif string.find(typename,"Ka-50") and camera then
|
elseif string.find(typename,"Ka-50") and camera then
|
||||||
heading = unit:GetHeading()
|
heading = unit:GetHeading()
|
||||||
nod,maxview,camon = 10,1000,true
|
nod,maxview,camon = 10,1000,true
|
||||||
angle = 10
|
angle = 10
|
||||||
maxview = self.MaxViewDistance[typename] or 5000
|
maxview = self.MaxViewDistance[typename] or 8000
|
||||||
|
elseif string.find(typename,"OH58") and camera then
|
||||||
|
--heading = unit:GetHeading()
|
||||||
|
nod,maxview,camon = 0,8000,true
|
||||||
|
heading,nod,maxview,camon = self:_GetKiowaMMSSight(unit)
|
||||||
|
angle = 8
|
||||||
|
if maxview == 0 then
|
||||||
|
maxview = self.MaxViewDistance[typename] or 8000
|
||||||
|
end
|
||||||
else
|
else
|
||||||
-- visual
|
-- visual
|
||||||
heading = unit:GetHeading()
|
heading = unit:GetHeading()
|
||||||
nod,maxview,camon = 10,1000,true
|
nod,maxview,camon = 10,3000,true
|
||||||
|
maxview = self.MaxViewDistance[typename] or 3000
|
||||||
angle = 45
|
angle = 45
|
||||||
end
|
end
|
||||||
if laser then
|
if laser then
|
||||||
@@ -929,7 +977,8 @@ function PLAYERRECCE:_LaseTarget(client,targetset)
|
|||||||
if (not oldtarget) or targetset:IsNotInSet(oldtarget) or target:IsDead() or target:IsDestroyed() then
|
if (not oldtarget) or targetset:IsNotInSet(oldtarget) or target:IsDead() or target:IsDestroyed() then
|
||||||
-- lost LOS or dead
|
-- lost LOS or dead
|
||||||
laser:LaseOff()
|
laser:LaseOff()
|
||||||
if target:IsDead() or target:IsDestroyed() or target:GetLife() < 2 then
|
self:T(self.lid.."Target Life Points: "..target:GetLife() or "none")
|
||||||
|
if target:IsDead() or target:IsDestroyed() or target:GetDamage() > 79 or target:GetLife() <= 1 then
|
||||||
self:__Shack(-1,client,oldtarget)
|
self:__Shack(-1,client,oldtarget)
|
||||||
--self.LaserTarget[playername] = nil
|
--self.LaserTarget[playername] = nil
|
||||||
else
|
else
|
||||||
@@ -1274,6 +1323,9 @@ self:T(self.lid.."_ReportLaserTargets")
|
|||||||
report:Add("Threat Level: "..ThreatGraph.." ("..ThreatLevelText..")")
|
report:Add("Threat Level: "..ThreatGraph.." ("..ThreatLevelText..")")
|
||||||
if not self.ReferencePoint then
|
if not self.ReferencePoint then
|
||||||
report:Add("Location: "..client:GetCoordinate():ToStringBULLS(self.Coalition,Settings))
|
report:Add("Location: "..client:GetCoordinate():ToStringBULLS(self.Coalition,Settings))
|
||||||
|
if self.reporttostringbullsonly ~= true then
|
||||||
|
report:Add("Location: "..client:GetCoordinate():ToStringA2G(nil,Settings))
|
||||||
|
end
|
||||||
else
|
else
|
||||||
report:Add("Location: "..client:GetCoordinate():ToStringFromRPShort(self.ReferencePoint,self.RPName,client,Settings))
|
report:Add("Location: "..client:GetCoordinate():ToStringFromRPShort(self.ReferencePoint,self.RPName,client,Settings))
|
||||||
end
|
end
|
||||||
@@ -1317,8 +1369,14 @@ function PLAYERRECCE:_ReportVisualTargets(client,group,playername)
|
|||||||
report:Add("Threat Level: "..ThreatGraph.." ("..ThreatLevelText..")")
|
report:Add("Threat Level: "..ThreatGraph.." ("..ThreatLevelText..")")
|
||||||
if not self.ReferencePoint then
|
if not self.ReferencePoint then
|
||||||
report:Add("Location: "..client:GetCoordinate():ToStringBULLS(self.Coalition,Settings))
|
report:Add("Location: "..client:GetCoordinate():ToStringBULLS(self.Coalition,Settings))
|
||||||
|
if self.reporttostringbullsonly ~= true then
|
||||||
|
report:Add("Location: "..client:GetCoordinate():ToStringA2G(nil,Settings))
|
||||||
|
end
|
||||||
else
|
else
|
||||||
report:Add("Location: "..client:GetCoordinate():ToStringFromRPShort(self.ReferencePoint,self.RPName,client,Settings))
|
report:Add("Location: "..client:GetCoordinate():ToStringFromRPShort(self.ReferencePoint,self.RPName,client,Settings))
|
||||||
|
if self.reporttostringbullsonly ~= true then
|
||||||
|
report:Add("Location: "..client:GetCoordinate():ToStringA2G(nil,Settings))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
report:Add(string.rep("-",15))
|
report:Add(string.rep("-",15))
|
||||||
local text = report:Text()
|
local text = report:Text()
|
||||||
@@ -1347,6 +1405,7 @@ function PLAYERRECCE:_BuildMenus(Client)
|
|||||||
local client = _client -- Wrapper.Client#CLIENT
|
local client = _client -- Wrapper.Client#CLIENT
|
||||||
if client and client:IsAlive() then
|
if client and client:IsAlive() then
|
||||||
local playername = client:GetPlayerName()
|
local playername = client:GetPlayerName()
|
||||||
|
self:T("Menu for "..playername)
|
||||||
if not self.UnitLaserCodes[playername] then
|
if not self.UnitLaserCodes[playername] then
|
||||||
self:_SetClientLaserCode(nil,nil,playername,1688)
|
self:_SetClientLaserCode(nil,nil,playername,1688)
|
||||||
end
|
end
|
||||||
@@ -1355,6 +1414,7 @@ function PLAYERRECCE:_BuildMenus(Client)
|
|||||||
end
|
end
|
||||||
local group = client:GetGroup()
|
local group = client:GetGroup()
|
||||||
if not self.ClientMenus[playername] then
|
if not self.ClientMenus[playername] then
|
||||||
|
self:T("Start Menubuild for "..playername)
|
||||||
local canlase = self.CanLase[client:GetTypeName()]
|
local canlase = self.CanLase[client:GetTypeName()]
|
||||||
self.ClientMenus[playername] = MENU_GROUP:New(group,self.MenuName or self.Name or "RECCE")
|
self.ClientMenus[playername] = MENU_GROUP:New(group,self.MenuName or self.Name or "RECCE")
|
||||||
local txtonstation = self.OnStation[playername] and "ON" or "OFF"
|
local txtonstation = self.OnStation[playername] and "ON" or "OFF"
|
||||||
@@ -1484,7 +1544,7 @@ end
|
|||||||
-- @param #PLAYERRECCE self
|
-- @param #PLAYERRECCE self
|
||||||
-- @param #number Frequency Frequency to be used. Can also be given as a table of multiple frequencies, e.g. 271 or {127,251}. There needs to be exactly the same number of modulations!
|
-- @param #number Frequency Frequency to be used. Can also be given as a table of multiple frequencies, e.g. 271 or {127,251}. There needs to be exactly the same number of modulations!
|
||||||
-- @param #number Modulation Modulation to be used. Can also be given as a table of multiple modulations, e.g. radio.modulation.AM or {radio.modulation.FM,radio.modulation.AM}. There needs to be exactly the same number of frequencies!
|
-- @param #number Modulation Modulation to be used. Can also be given as a table of multiple modulations, e.g. radio.modulation.AM or {radio.modulation.FM,radio.modulation.AM}. There needs to be exactly the same number of frequencies!
|
||||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||||
-- @param #string Gender (Optional) Defaults to "male"
|
-- @param #string Gender (Optional) Defaults to "male"
|
||||||
-- @param #string Culture (Optional) Defaults to "en-US"
|
-- @param #string Culture (Optional) Defaults to "en-US"
|
||||||
-- @param #number Port (Optional) Defaults to 5002
|
-- @param #number Port (Optional) Defaults to 5002
|
||||||
@@ -1492,10 +1552,11 @@ end
|
|||||||
-- Note that this must be installed on your windows system. Can also be Google voice types, if you are using Google TTS.
|
-- Note that this must be installed on your windows system. Can also be Google voice types, if you are using Google TTS.
|
||||||
-- @param #number Volume (Optional) Volume - between 0.0 (silent) and 1.0 (loudest)
|
-- @param #number Volume (Optional) Volume - between 0.0 (silent) and 1.0 (loudest)
|
||||||
-- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS
|
-- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS
|
||||||
|
-- @param #string Backend (optional) Backend to be used, can be MSRS.Backend.SRSEXE or MSRS.Backend.GRPC
|
||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
function PLAYERRECCE:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey)
|
function PLAYERRECCE:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,Backend)
|
||||||
self:T(self.lid.."SetSRS")
|
self:T(self.lid.."SetSRS")
|
||||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" --
|
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" --
|
||||||
self.Gender = Gender or MSRS.gender or "male" --
|
self.Gender = Gender or MSRS.gender or "male" --
|
||||||
self.Culture = Culture or MSRS.culture or "en-US" --
|
self.Culture = Culture or MSRS.culture or "en-US" --
|
||||||
self.Port = Port or MSRS.port or 5002 --
|
self.Port = Port or MSRS.port or 5002 --
|
||||||
@@ -1515,6 +1576,9 @@ function PLAYERRECCE:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,V
|
|||||||
self.SRS:SetCulture(self.Culture)
|
self.SRS:SetCulture(self.Culture)
|
||||||
self.SRS:SetPort(self.Port)
|
self.SRS:SetPort(self.Port)
|
||||||
self.SRS:SetVolume(self.Volume)
|
self.SRS:SetVolume(self.Volume)
|
||||||
|
if Backend then
|
||||||
|
self.SRS:SetBackend(Backend)
|
||||||
|
end
|
||||||
if self.PathToGoogleKey then
|
if self.PathToGoogleKey then
|
||||||
self.SRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.PathToGoogleKey)
|
self.SRS:SetProviderOptionsGoogle(self.PathToGoogleKey,self.PathToGoogleKey)
|
||||||
self.SRS:SetProvider(MSRS.Provider.GOOGLE)
|
self.SRS:SetProvider(MSRS.Provider.GOOGLE)
|
||||||
@@ -1552,6 +1616,16 @@ function PLAYERRECCE:SetMenuName(Name)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Set reporting to be BULLS only or BULLS plus playersettings based coordinate.
|
||||||
|
-- @param #PLAYERRECCE self
|
||||||
|
-- @param #boolean OnOff
|
||||||
|
-- @return #PLAYERRECCE self
|
||||||
|
function PLAYERRECCE:SetReportBullsOnly(OnOff)
|
||||||
|
self:T(self.lid.."SetReportBullsOnly: "..tostring(OnOff))
|
||||||
|
self.reporttostringbullsonly = OnOff
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [User] Enable smoking of own position
|
--- [User] Enable smoking of own position
|
||||||
-- @param #PLAYERRECCE self
|
-- @param #PLAYERRECCE self
|
||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
@@ -1561,6 +1635,15 @@ function PLAYERRECCE:EnableSmokeOwnPosition()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Enable auto lasing for the Kiowa OH-58D.
|
||||||
|
-- @param #PLAYERRECCE self
|
||||||
|
-- @return #PLAYERRECCE self
|
||||||
|
function PLAYERRECCE:EnableKiowaAutolase()
|
||||||
|
self:T(self.lid.."EnableKiowaAutolase")
|
||||||
|
self.CanLase.OH58D = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [User] Disable smoking of own position
|
--- [User] Disable smoking of own position
|
||||||
-- @param #PLAYERRECCE self
|
-- @param #PLAYERRECCE self
|
||||||
-- @return #PLAYERRECCE
|
-- @return #PLAYERRECCE
|
||||||
@@ -1718,7 +1801,7 @@ end
|
|||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
function PLAYERRECCE:onafterRecceOnStation(From, Event, To, Client, Playername)
|
function PLAYERRECCE:onafterRecceOnStation(From, Event, To, Client, Playername)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations,self.CallsignCustomFunc,self.CallsignCustomArgs)
|
||||||
local coord = Client:GetCoordinate()
|
local coord = Client:GetCoordinate()
|
||||||
local coordtext = coord:ToStringBULLS(self.Coalition)
|
local coordtext = coord:ToStringBULLS(self.Coalition)
|
||||||
if self.ReferencePoint then
|
if self.ReferencePoint then
|
||||||
@@ -1727,7 +1810,7 @@ function PLAYERRECCE:onafterRecceOnStation(From, Event, To, Client, Playername)
|
|||||||
end
|
end
|
||||||
local text1 = "Party time!"
|
local text1 = "Party time!"
|
||||||
local text2 = string.format("All stations, FACA %s on station\nat %s!",callsign, coordtext)
|
local text2 = string.format("All stations, FACA %s on station\nat %s!",callsign, coordtext)
|
||||||
local text2tts = string.format("All stations, FACA %s on station at %s!",callsign, coordtext)
|
local text2tts = string.format(" All stations, FACA %s on station at %s!",callsign, coordtext)
|
||||||
text2tts = self:_GetTextForSpeech(text2tts)
|
text2tts = self:_GetTextForSpeech(text2tts)
|
||||||
if self.debug then
|
if self.debug then
|
||||||
self:T(text2.."\n"..text2tts)
|
self:T(text2.."\n"..text2tts)
|
||||||
@@ -1758,7 +1841,7 @@ end
|
|||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
function PLAYERRECCE:onafterRecceOffStation(From, Event, To, Client, Playername)
|
function PLAYERRECCE:onafterRecceOffStation(From, Event, To, Client, Playername)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations,self.CallsignCustomFunc,self.CallsignCustomArgs)
|
||||||
local coord = Client:GetCoordinate()
|
local coord = Client:GetCoordinate()
|
||||||
local coordtext = coord:ToStringBULLS(self.Coalition)
|
local coordtext = coord:ToStringBULLS(self.Coalition)
|
||||||
if self.ReferencePoint then
|
if self.ReferencePoint then
|
||||||
@@ -1898,7 +1981,7 @@ end
|
|||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
function PLAYERRECCE:onafterIllumination(From, Event, To, Client, Playername, TargetSet)
|
function PLAYERRECCE:onafterIllumination(From, Event, To, Client, Playername, TargetSet)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations,self.CallsignCustomFunc,self.CallsignCustomArgs)
|
||||||
local coord = Client:GetCoordinate()
|
local coord = Client:GetCoordinate()
|
||||||
local coordtext = coord:ToStringBULLS(self.Coalition)
|
local coordtext = coord:ToStringBULLS(self.Coalition)
|
||||||
if self.AttackSet then
|
if self.AttackSet then
|
||||||
@@ -1941,7 +2024,7 @@ end
|
|||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
function PLAYERRECCE:onafterTargetsSmoked(From, Event, To, Client, Playername, TargetSet)
|
function PLAYERRECCE:onafterTargetsSmoked(From, Event, To, Client, Playername, TargetSet)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations,self.CallsignCustomFunc,self.CallsignCustomArgs)
|
||||||
local coord = Client:GetCoordinate()
|
local coord = Client:GetCoordinate()
|
||||||
local coordtext = coord:ToStringBULLS(self.Coalition)
|
local coordtext = coord:ToStringBULLS(self.Coalition)
|
||||||
if self.AttackSet then
|
if self.AttackSet then
|
||||||
@@ -1984,7 +2067,7 @@ end
|
|||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
function PLAYERRECCE:onafterTargetsFlared(From, Event, To, Client, Playername, TargetSet)
|
function PLAYERRECCE:onafterTargetsFlared(From, Event, To, Client, Playername, TargetSet)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations,self.CallsignCustomFunc,self.CallsignCustomArgs)
|
||||||
local coord = Client:GetCoordinate()
|
local coord = Client:GetCoordinate()
|
||||||
local coordtext = coord:ToStringBULLS(self.Coalition)
|
local coordtext = coord:ToStringBULLS(self.Coalition)
|
||||||
if self.AttackSet then
|
if self.AttackSet then
|
||||||
@@ -2028,7 +2111,7 @@ end
|
|||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
function PLAYERRECCE:onafterTargetLasing(From, Event, To, Client, Target, Lasercode, Lasingtime)
|
function PLAYERRECCE:onafterTargetLasing(From, Event, To, Client, Target, Lasercode, Lasingtime)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations,self.CallsignCustomFunc,self.CallsignCustomArgs)
|
||||||
local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS
|
local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS
|
||||||
local coord = Client:GetCoordinate()
|
local coord = Client:GetCoordinate()
|
||||||
local coordtext = coord:ToStringBULLS(self.Coalition,Settings)
|
local coordtext = coord:ToStringBULLS(self.Coalition,Settings)
|
||||||
@@ -2075,7 +2158,7 @@ end
|
|||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
function PLAYERRECCE:onafterShack(From, Event, To, Client, Target)
|
function PLAYERRECCE:onafterShack(From, Event, To, Client, Target)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations,self.CallsignCustomFunc,self.CallsignCustomArgs)
|
||||||
local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS
|
local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS
|
||||||
local coord = Client:GetCoordinate()
|
local coord = Client:GetCoordinate()
|
||||||
local coordtext = coord:ToStringBULLS(self.Coalition,Settings)
|
local coordtext = coord:ToStringBULLS(self.Coalition,Settings)
|
||||||
@@ -2122,7 +2205,7 @@ end
|
|||||||
-- @return #PLAYERRECCE self
|
-- @return #PLAYERRECCE self
|
||||||
function PLAYERRECCE:onafterTargetLOSLost(From, Event, To, Client, Target)
|
function PLAYERRECCE:onafterTargetLOSLost(From, Event, To, Client, Target)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations,self.CallsignCustomFunc,self.CallsignCustomArgs)
|
||||||
local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS
|
local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS
|
||||||
local coord = Client:GetCoordinate()
|
local coord = Client:GetCoordinate()
|
||||||
local coordtext = coord:ToStringBULLS(self.Coalition,Settings)
|
local coordtext = coord:ToStringBULLS(self.Coalition,Settings)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -997,6 +997,8 @@ function RECOVERYTANKER:onafterStart(From, Event, To)
|
|||||||
|
|
||||||
-- Init status updates in 10 seconds.
|
-- Init status updates in 10 seconds.
|
||||||
self:__Status(10)
|
self:__Status(10)
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user