mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
1201 Commits
2.7.15
...
ada38fa3ea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ada38fa3ea | ||
|
|
2ee0597d48 | ||
|
|
7ae4cdc8f1 | ||
|
|
8c92a578ed | ||
|
|
096f2caf9c | ||
|
|
0b37c909b3 | ||
|
|
1b18ae1597 | ||
|
|
c9ac6d73e6 | ||
|
|
0e836973fd | ||
|
|
be40d7be9a | ||
|
|
f3b7740041 | ||
|
|
7d7488db6f | ||
|
|
4964cc2f2d | ||
|
|
f0a4c5b008 | ||
|
|
1b6412821b | ||
|
|
926a0733e4 | ||
|
|
da70f4ce6c | ||
|
|
727cb3276c | ||
|
|
33e63a4819 | ||
|
|
3543b2c79a | ||
|
|
4489efff94 | ||
|
|
6a4bddde99 | ||
|
|
dc2511942c | ||
|
|
f0c257c4a5 | ||
|
|
068d21612f | ||
|
|
773461aad9 | ||
|
|
f9257b2b0d | ||
|
|
9e0f03a3cd | ||
|
|
a467fabdc8 | ||
|
|
a2ab84c45a | ||
|
|
9fd6729967 | ||
|
|
f1d4f1753a | ||
|
|
6d9c3fd0aa | ||
|
|
28ae63bd8d | ||
|
|
42e7e3f94f | ||
|
|
6466c5e95e | ||
|
|
829f5af25f | ||
|
|
0d1147bac4 | ||
|
|
24b47b02e0 | ||
|
|
3cabc07d58 | ||
|
|
b0546b1e60 | ||
|
|
a988e67490 | ||
|
|
2594c5bbf0 | ||
|
|
db70fa341c | ||
|
|
763e3852ac | ||
|
|
8ec86973c6 | ||
|
|
eb2c6ac6f2 | ||
|
|
cbcc893ce5 | ||
|
|
382b049c5f | ||
|
|
a53763221c | ||
|
|
b7bac28113 | ||
|
|
a9edb16554 | ||
|
|
0aeb1fc6af | ||
|
|
eeeeda4e5e | ||
|
|
f5881eda53 | ||
|
|
c1997d9f70 | ||
|
|
bb1caa6642 | ||
|
|
dd5ca93f26 | ||
|
|
1889df4952 | ||
|
|
7ca219748d | ||
|
|
2fc16ba694 | ||
|
|
a4feafab8e | ||
|
|
997baf21a0 | ||
|
|
b126cc00d0 | ||
|
|
09b7922b84 | ||
|
|
7a5b9a75f3 | ||
|
|
4bab2ee1de | ||
|
|
d7defe6f7f | ||
|
|
db869bcb6d | ||
|
|
ea4a1f9ff9 | ||
|
|
20406e40ca | ||
|
|
3b50fee5a0 | ||
|
|
804004198b | ||
|
|
5b8b8a5566 | ||
|
|
0468bacc0b | ||
|
|
7eba1349ae | ||
|
|
b6074a4795 | ||
|
|
36c9f551d9 | ||
|
|
89c3f7310b | ||
|
|
a6b622ed31 | ||
|
|
f1af3a50b8 | ||
|
|
0c90e90c18 | ||
|
|
f97ef25104 | ||
|
|
069c0aa03f | ||
|
|
b145588ed5 | ||
|
|
3ad60a95ce | ||
|
|
ac4b620f16 | ||
|
|
ccada18a6a | ||
|
|
1547d66327 | ||
|
|
8042e8bfaf | ||
|
|
dd7b87e9cd | ||
|
|
460d2768ff | ||
|
|
3c74272749 | ||
|
|
82c409d77a | ||
|
|
195aac4504 | ||
|
|
08d8f3e25f | ||
|
|
6f72697e26 | ||
|
|
0f6439cf9f | ||
|
|
2c10943cb1 | ||
|
|
544db963ea | ||
|
|
207698a2dd | ||
|
|
d1ae2c0f5e | ||
|
|
0392417189 | ||
|
|
be4beea9d0 | ||
|
|
5da899138b | ||
|
|
1ec1e00bde | ||
|
|
5d93b33d42 | ||
|
|
b2077bfc74 | ||
|
|
6fdf9a649f | ||
|
|
d013bbc751 | ||
|
|
e0092fdba0 | ||
|
|
fbeada439f | ||
|
|
6c8858d2f5 | ||
|
|
e2b77878df | ||
|
|
53d7972858 | ||
|
|
04a55e4104 | ||
|
|
d11acecdac | ||
|
|
49c11073e6 | ||
|
|
1a156e7e12 | ||
|
|
1856754614 | ||
|
|
6ac452ff15 | ||
|
|
d707a4775c | ||
|
|
ffccc31e38 | ||
|
|
0405af2bde | ||
|
|
e50e572c78 | ||
|
|
3083599158 | ||
|
|
b7b6c1ea19 | ||
|
|
5b107ce2da | ||
|
|
5c1e342a79 | ||
|
|
ddf33da787 | ||
|
|
b0a192a767 | ||
|
|
986c340211 | ||
|
|
2109537f86 | ||
|
|
690db7f12f | ||
|
|
4f3fd06cc9 | ||
|
|
4074023ed3 | ||
|
|
6c00b0c7eb | ||
|
|
76dc0d690a | ||
|
|
d783f7be99 | ||
|
|
b66e91b11f | ||
|
|
dc83af4d02 | ||
|
|
0a38700edb | ||
|
|
659615114a | ||
|
|
4955fe4d92 | ||
|
|
792aa73832 | ||
|
|
a915452e6e | ||
|
|
be8405b72b | ||
|
|
5ca3e3b2b8 | ||
|
|
618a8744a2 | ||
|
|
23aeef7a20 | ||
|
|
9ac4f136aa | ||
|
|
c9a09c2fc9 | ||
|
|
6028c91f81 | ||
|
|
3c57928f46 | ||
|
|
32f0bb33c3 | ||
|
|
31d0410284 | ||
|
|
87c436ba34 | ||
|
|
6e9727e265 | ||
|
|
94ee76fe62 | ||
|
|
ea23162ca9 | ||
|
|
683388faee | ||
|
|
56ec3920c5 | ||
|
|
f335ffc4ec | ||
|
|
4976cd86f2 | ||
|
|
c00eff8b23 | ||
|
|
3c710613a8 | ||
|
|
45ebf9a3c7 | ||
|
|
c808e4a4e2 | ||
|
|
e2612b97d7 | ||
|
|
70e9d91bb5 | ||
|
|
0b8810f8b3 | ||
|
|
41b867a4ca | ||
|
|
1c0a8d9380 | ||
|
|
2b0b9d44eb | ||
|
|
2fc7a3b542 | ||
|
|
12b596a47f | ||
|
|
8ef781a9ac | ||
|
|
43eeaede65 | ||
|
|
749c5f87de | ||
|
|
a520daeb56 | ||
|
|
f9ba96f228 | ||
|
|
a49bd23a2a | ||
|
|
cea2f18228 | ||
|
|
fd2d8a5119 | ||
|
|
fa4e0447dd | ||
|
|
31aa604fc4 | ||
|
|
f44db27565 | ||
|
|
9b1abab73a | ||
|
|
cad8f15b61 | ||
|
|
1d08bcf2e0 | ||
|
|
9487a5ae91 | ||
|
|
96337cc5df | ||
|
|
bc9eee22b7 | ||
|
|
f74d25b31c | ||
|
|
1156971d94 | ||
|
|
c79b5c37c4 | ||
|
|
a2b650a9e3 | ||
|
|
905b442e9b | ||
|
|
18fe3112bd | ||
|
|
cc057744ba | ||
|
|
db1779e1db | ||
|
|
d25a723fc7 | ||
|
|
f0fe1b431d | ||
|
|
8e286edd25 | ||
|
|
74520b1359 | ||
|
|
d06e44d37b | ||
|
|
35348d9b81 | ||
|
|
4b16e94eaf | ||
|
|
d983676330 | ||
|
|
03c30f3cce | ||
|
|
99b93266ad | ||
|
|
e307b57e67 | ||
|
|
5ef9bb2acd | ||
|
|
4aacdc1567 | ||
|
|
57552f4300 | ||
|
|
09d53f7d8c | ||
|
|
d9948d1a19 | ||
|
|
5f7a4f2bbb | ||
|
|
1b6945e0b0 | ||
|
|
4fd55b1bd6 | ||
|
|
20b8deb6de | ||
|
|
6af836c118 | ||
|
|
f87b8a2c2a | ||
|
|
daffd7412a | ||
|
|
bfb60b318e | ||
|
|
a55959dfbb | ||
|
|
4d24eb82be | ||
|
|
e26caa2f74 | ||
|
|
b75fff60c8 | ||
|
|
4ac57fce7a | ||
|
|
25a9a0120a | ||
|
|
66a1fa8af5 | ||
|
|
1b4033cfce | ||
|
|
48bc41873a | ||
|
|
068a1ab99c | ||
|
|
6551383070 | ||
|
|
b03978cc3d | ||
|
|
82f4c5790a | ||
|
|
5957124e9e | ||
|
|
92a05ca74a | ||
|
|
d02b5db6dd | ||
|
|
bd074728fe | ||
|
|
61b7b3ead6 | ||
|
|
7f7999e3e5 | ||
|
|
b522b38d31 | ||
|
|
b2dc7bc232 | ||
|
|
def622a02c | ||
|
|
30bedb39f1 | ||
|
|
fbcc4ee32b | ||
|
|
63c68d729b | ||
|
|
04f8f6d512 | ||
|
|
b74d46f762 | ||
|
|
02decc3901 | ||
|
|
dcdea16624 | ||
|
|
2635cf6345 | ||
|
|
e86069d39c | ||
|
|
fdcf153b0b | ||
|
|
8523b7e20a | ||
|
|
29b992bf81 | ||
|
|
4c52509d6d | ||
|
|
9bc067f2e8 | ||
|
|
5fbe0d9a70 | ||
|
|
474f767e56 | ||
|
|
f9030be843 | ||
|
|
538e35d8f0 | ||
|
|
203f0c8abc | ||
|
|
d0736b0b56 | ||
|
|
15b1ed028e | ||
|
|
008617a35c | ||
|
|
6144a61a2e | ||
|
|
5d192abd25 | ||
|
|
62337f445a | ||
|
|
b38c1c5827 | ||
|
|
c08cee2317 | ||
|
|
0f7759d070 | ||
|
|
4a0842bea6 | ||
|
|
3b3666c5f7 | ||
|
|
45912911ee | ||
|
|
9916afaa49 | ||
|
|
55c5a23616 | ||
|
|
6bee1cc88e | ||
|
|
43ab4d5f38 | ||
|
|
0427c0d3a7 | ||
|
|
014750ea7f | ||
|
|
e4bbfce314 | ||
|
|
359429b17e | ||
|
|
6001f6abda | ||
|
|
fd9b5d8d16 | ||
|
|
b6f184388a | ||
|
|
d8471698ab | ||
|
|
6204cecbbd | ||
|
|
ddeca49916 | ||
|
|
d8dcf37886 | ||
|
|
5ae41a208b | ||
|
|
0462d900e6 | ||
|
|
0f962461e1 | ||
|
|
aadc03c38d | ||
|
|
683fa13bb2 | ||
|
|
e4408a964d | ||
|
|
f97f33ab59 | ||
|
|
f59102ee09 | ||
|
|
e42e4e1ddf | ||
|
|
a30079c45b | ||
|
|
50ffd9aba6 | ||
|
|
936fec1f49 | ||
|
|
9625d87dd5 | ||
|
|
802139205c | ||
|
|
fb918cb2a4 | ||
|
|
abb4de46d7 | ||
|
|
dce9631399 | ||
|
|
6c773786d2 | ||
|
|
8939963187 | ||
|
|
f9747d1c4c | ||
|
|
60a3d3409e | ||
|
|
b72124c0d9 | ||
|
|
d51e761b26 | ||
|
|
1445ef61a0 | ||
|
|
dfe2ed2a98 | ||
|
|
be87103b53 | ||
|
|
2fb460c4bb | ||
|
|
216ea230a8 | ||
|
|
90096163ee | ||
|
|
cd178d6a8c | ||
|
|
2aa0b5ddfb | ||
|
|
37f819458a | ||
|
|
168f4301d2 | ||
|
|
d5a406c60f | ||
|
|
cb16210577 | ||
|
|
8c0e0de45f | ||
|
|
3524cba4ef | ||
|
|
5f8d1cf5b0 | ||
|
|
846aa823d4 | ||
|
|
68298fc585 | ||
|
|
e9d75f6d94 | ||
|
|
8fa5277417 | ||
|
|
231f1f236d | ||
|
|
ece0a46f97 | ||
|
|
2c9b0b8376 | ||
|
|
a798f2d61c | ||
|
|
ae08c87822 | ||
|
|
ae880e9d1c | ||
|
|
101d2e1de5 | ||
|
|
f6b7708567 | ||
|
|
051286acd1 | ||
|
|
7f572a1a9b | ||
|
|
d62025dfe0 | ||
|
|
07009630c6 | ||
|
|
865042a843 | ||
|
|
f00d0dc871 | ||
|
|
d6adcdf8bd | ||
|
|
2c192fba30 | ||
|
|
97f11c93bb | ||
|
|
f531fdaa70 | ||
|
|
81f8e84ca4 | ||
|
|
d74de11b8b | ||
|
|
30f2097d7a | ||
|
|
f903844059 | ||
|
|
68b2b452cc | ||
|
|
668d120d60 | ||
|
|
7543f31c85 | ||
|
|
56d84e7b25 | ||
|
|
ed2d3d856b | ||
|
|
1e5c3a3c21 | ||
|
|
37d5b6a0fc | ||
|
|
c58a954d18 | ||
|
|
0d481afa16 | ||
|
|
016875d724 | ||
|
|
5df0d60135 | ||
|
|
e77d61c4cb | ||
|
|
504142c585 | ||
|
|
80df849d18 | ||
|
|
e74c79b5d6 | ||
|
|
f738ddfca8 | ||
|
|
af45b0d709 | ||
|
|
e746617139 | ||
|
|
3105f7407d | ||
|
|
2f568bca17 | ||
|
|
aeb1664134 | ||
|
|
b7702ab933 | ||
|
|
cc14f82e85 | ||
|
|
5aea17e20e | ||
|
|
ad9eaea010 | ||
|
|
284a770daa | ||
|
|
ccd190a8b1 | ||
|
|
19f6a8d8f6 | ||
|
|
24264bd885 | ||
|
|
872bb3d775 | ||
|
|
d36cd8e284 | ||
|
|
eab643268f | ||
|
|
9356794112 | ||
|
|
35c24810f9 | ||
|
|
a54944b021 | ||
|
|
bc9938d08a | ||
|
|
b77f179acc | ||
|
|
90d20076c9 | ||
|
|
a1fc18fd48 | ||
|
|
69176c118f | ||
|
|
7ae98ef5f9 | ||
|
|
bbc539fac6 | ||
|
|
c1958b62ff | ||
|
|
a3864d5f32 | ||
|
|
9dc9b21b16 | ||
|
|
4cb784cc18 | ||
|
|
16655cf070 | ||
|
|
38e10331c9 | ||
|
|
40053670ea | ||
|
|
a63a15db1c | ||
|
|
76294f11e4 | ||
|
|
cc247a0f03 | ||
|
|
37cbf212f7 | ||
|
|
500fe37ac4 | ||
|
|
50a38cf2a4 | ||
|
|
c2aa57c603 | ||
|
|
ccf3093fe8 | ||
|
|
d2d0659776 | ||
|
|
8087c87027 | ||
|
|
c4738b24eb | ||
|
|
c73d8a6339 | ||
|
|
04f2f7d34f | ||
|
|
5d6951ae11 | ||
|
|
214cd3748c | ||
|
|
6fb931a055 | ||
|
|
b5d1cee96b | ||
|
|
e6aa341863 | ||
|
|
3595afe0cc | ||
|
|
0b21cb687e | ||
|
|
8a21fe80de | ||
|
|
51eb3a2e82 | ||
|
|
ec8bfb32b4 | ||
|
|
e6dda35f3d | ||
|
|
9d2896d088 | ||
|
|
036cc9d211 | ||
|
|
e6484c1598 | ||
|
|
65c7b0d12f | ||
|
|
9f8e7f4f3c | ||
|
|
b215d0e7d4 | ||
|
|
13b272b6e5 | ||
|
|
f9031dba42 | ||
|
|
29a4f7c160 | ||
|
|
55a9c7e020 | ||
|
|
84dd1fa21c | ||
|
|
42979093b8 | ||
|
|
edf7f4677c | ||
|
|
8958d7b71f | ||
|
|
6083191f32 | ||
|
|
8e0446c594 | ||
|
|
7e20a0a0dc | ||
|
|
58139b34a8 | ||
|
|
9ceb26c7b1 | ||
|
|
9ca30fc00c | ||
|
|
1ba1738aa0 | ||
|
|
c8cdbeac5c | ||
|
|
4b12b04840 | ||
|
|
c571d32d0e | ||
|
|
b350243e50 | ||
|
|
042b82d3a6 | ||
|
|
62ef56684b | ||
|
|
1033b975f8 | ||
|
|
11a05f1333 | ||
|
|
8cdf8677c1 | ||
|
|
e1706c94af | ||
|
|
f9f0a8e866 | ||
|
|
5f9d4405b1 | ||
|
|
2d1fcb9be8 | ||
|
|
5fcd394ddd | ||
|
|
a6de09a0ca | ||
|
|
b60435fb2c | ||
|
|
754430ba75 | ||
|
|
4668132b37 | ||
|
|
ceb77e2837 | ||
|
|
137f0251fb | ||
|
|
08745c910c | ||
|
|
16dc3860f7 | ||
|
|
333ed629bb | ||
|
|
c87e91d845 | ||
|
|
778ae1b8e5 | ||
|
|
a6568a955f | ||
|
|
6df4fffafd | ||
|
|
7bac0f32fc | ||
|
|
783e29f189 | ||
|
|
af39a3ae9c | ||
|
|
c985d40ca0 | ||
|
|
90b588420f | ||
|
|
3a0d2a5c51 | ||
|
|
07a76ced88 | ||
|
|
a3805118a0 | ||
|
|
f1c03e1b86 | ||
|
|
2e6957984f | ||
|
|
433a66d530 | ||
|
|
7d3ad15f39 | ||
|
|
d0728afee7 | ||
|
|
01330bf00c | ||
|
|
01de638b8e | ||
|
|
3e8c7ad1df | ||
|
|
22c6a03161 | ||
|
|
dd8b2caa24 | ||
|
|
1e4cfd473c | ||
|
|
044fb66ca0 | ||
|
|
cc17027a7a | ||
|
|
fc52e06318 | ||
|
|
27d36f3e0d | ||
|
|
d3419d218a | ||
|
|
f9dcc9d95c | ||
|
|
a0b49fbd67 | ||
|
|
ae213c4cf1 | ||
|
|
8dea86b921 | ||
|
|
44003a8fda | ||
|
|
b883bb1e62 | ||
|
|
db35a67bd7 | ||
|
|
bc5946c76e | ||
|
|
3d7172fdf7 | ||
|
|
28411d2093 | ||
|
|
26deaca166 | ||
|
|
95baed1aac | ||
|
|
3b364c7650 | ||
|
|
2a4e242eb2 | ||
|
|
8b2237d183 | ||
|
|
abc26b1e5c | ||
|
|
b761078c18 | ||
|
|
616690391c | ||
|
|
465c395294 | ||
|
|
73bddddba4 | ||
|
|
9a3effd063 | ||
|
|
b9bd8d88a9 | ||
|
|
18fd587ab0 | ||
|
|
ba14330281 | ||
|
|
2eb4118d56 | ||
|
|
dcc15afb89 | ||
|
|
67b43e2c68 | ||
|
|
2ad111dd50 | ||
|
|
ac42b56b8e | ||
|
|
874fa7ad69 | ||
|
|
70c29de695 | ||
|
|
b263cddc07 | ||
|
|
613d33d731 | ||
|
|
50298e4109 | ||
|
|
244abe2bbb | ||
|
|
378e76e45b | ||
|
|
241b31fcec | ||
|
|
3dd069d7d6 | ||
|
|
aca4e4d7ca | ||
|
|
2f81fcb0c0 | ||
|
|
8cf11de774 | ||
|
|
176bd0eb8b | ||
|
|
10edd2f9d0 | ||
|
|
11acb578f6 | ||
|
|
4d8abe7f57 | ||
|
|
ab14fbd11c | ||
|
|
cb61177252 | ||
|
|
1e15509001 | ||
|
|
bfa8719ec3 | ||
|
|
3652376d42 | ||
|
|
3953f0e7fc | ||
|
|
5621579b5e | ||
|
|
57ce6bcec2 | ||
|
|
71b5492903 | ||
|
|
d64dadd9a9 | ||
|
|
0f30f3b1a0 | ||
|
|
51911d3292 | ||
|
|
bff60bdb69 | ||
|
|
aac3f64638 | ||
|
|
74c19f1058 | ||
|
|
1cbdafda65 | ||
|
|
595b9132e8 | ||
|
|
45aebff48e | ||
|
|
f2e22579ed | ||
|
|
1f9725530f | ||
|
|
c85f575888 | ||
|
|
5eef138507 | ||
|
|
14d6085b69 | ||
|
|
ced01a993d | ||
|
|
02e59b23c5 | ||
|
|
4c2a89ee29 | ||
|
|
e8c75b8795 | ||
|
|
2ce9f26e26 | ||
|
|
30819dad72 | ||
|
|
2eeca4451c | ||
|
|
27ea85ea57 | ||
|
|
0faa0036ee | ||
|
|
f859522052 | ||
|
|
5a772ad05e | ||
|
|
51f134538d | ||
|
|
0ee7a38c61 | ||
|
|
15dd2cf735 | ||
|
|
e895642157 | ||
|
|
154026fbf8 | ||
|
|
7dcff7ec9c | ||
|
|
67e52120d4 | ||
|
|
4b84d227f0 | ||
|
|
86e13df303 | ||
|
|
2e167358bb | ||
|
|
48dba742ad | ||
|
|
531132e8a7 | ||
|
|
7464406a17 | ||
|
|
0ddf8762c2 | ||
|
|
d984a1b142 | ||
|
|
748aa131e4 | ||
|
|
33bd928076 | ||
|
|
0b3fc515e0 | ||
|
|
581138b5bc | ||
|
|
08f2c29014 | ||
|
|
dcd4d0ab62 | ||
|
|
bb07e1935e | ||
|
|
088436c5ce | ||
|
|
797bf0047b | ||
|
|
f29d055ca3 | ||
|
|
1468641563 | ||
|
|
8b08942c4d | ||
|
|
eb84ad3cee | ||
|
|
91a34ac4d8 | ||
|
|
28c8d99878 | ||
|
|
4fda8cc5fb | ||
|
|
4ac583e434 | ||
|
|
fa762fe0fc | ||
|
|
aca5846209 | ||
|
|
4fd7d7cba9 | ||
|
|
9280a1224d | ||
|
|
fce7b07014 | ||
|
|
4696569f83 | ||
|
|
84230e2360 | ||
|
|
ca9913e38b | ||
|
|
ff951c69d9 | ||
|
|
f2f7c88299 | ||
|
|
f5d6d31b10 | ||
|
|
9b95e71d75 | ||
|
|
db6dc7b77e | ||
|
|
4c81333a0a | ||
|
|
79b1f1615f | ||
|
|
47f010cb28 | ||
|
|
d14b7e8f4c | ||
|
|
d9748ef147 | ||
|
|
64d7946c06 | ||
|
|
b052fc6243 | ||
|
|
8385b1d21a | ||
|
|
d4f4465b0a | ||
|
|
5fe77956cb | ||
|
|
d640acc7cc | ||
|
|
8dcd22f18c | ||
|
|
2d086a62f0 | ||
|
|
47ad2499d4 | ||
|
|
5d510807c9 | ||
|
|
5ba8f9e0e8 | ||
|
|
0338fd5d33 | ||
|
|
ea2175bba8 | ||
|
|
0835022c5c | ||
|
|
f306361317 | ||
|
|
0347e42fc7 | ||
|
|
9cc32ff8dc | ||
|
|
b052d99349 | ||
|
|
4fe1318e7c | ||
|
|
6ffe69484c | ||
|
|
501ab70992 | ||
|
|
6ac46addf0 | ||
|
|
3bdf4b4c76 | ||
|
|
46f70dd8a6 | ||
|
|
aeac2eb3d7 | ||
|
|
e83c8c3ee0 | ||
|
|
d65042c640 | ||
|
|
c72cdd8f0b | ||
|
|
7e2f8771b5 | ||
|
|
3ccfcdbd0f | ||
|
|
16f3dcbbb4 | ||
|
|
f6f3189504 | ||
|
|
071554bfc5 | ||
|
|
1527b53c76 | ||
|
|
bbc7f7e14c | ||
|
|
b9830a8437 | ||
|
|
caaee4f551 | ||
|
|
5f7115f4fe | ||
|
|
9ec92a8fca | ||
|
|
7cc040c234 | ||
|
|
9227ba9ecd | ||
|
|
e7fb073bab | ||
|
|
f86b3505b2 | ||
|
|
e89b921f3e | ||
|
|
0d18ce086c | ||
|
|
8fb126682f | ||
|
|
ebe486c69a | ||
|
|
702ec75935 | ||
|
|
465ec216ea | ||
|
|
d803b51e84 | ||
|
|
53f89fd42c | ||
|
|
c72f109553 | ||
|
|
92e03522db | ||
|
|
9716162739 | ||
|
|
4eea8fcadd | ||
|
|
0ae9be49da | ||
|
|
bda4efc634 | ||
|
|
e84e16f58b | ||
|
|
55ffe37a79 | ||
|
|
68548f4581 | ||
|
|
8382eb9cd8 | ||
|
|
f837e9dec7 | ||
|
|
230d9d82bf | ||
|
|
c089e56060 | ||
|
|
87f1a5ed0d | ||
|
|
d2d6fac7df | ||
|
|
bc3f9ed7c0 | ||
|
|
0f4162a9a9 | ||
|
|
6b270916c4 | ||
|
|
b3a006096c | ||
|
|
6903e252d2 | ||
|
|
ff6704f123 | ||
|
|
c770f4cb68 | ||
|
|
9ce1d360d6 | ||
|
|
6f473faa92 | ||
|
|
dd37a42470 | ||
|
|
88e1bbd60d | ||
|
|
e078e48853 | ||
|
|
fac7a5fdc6 | ||
|
|
49191fb144 | ||
|
|
f739062463 | ||
|
|
c22304f2b0 | ||
|
|
c97d2ecaba | ||
|
|
89a9d1d0a4 | ||
|
|
cf7d41cd7f | ||
|
|
afe542cc63 | ||
|
|
89a902fd57 | ||
|
|
ae604fd847 | ||
|
|
4b8d120f20 | ||
|
|
c489a88106 | ||
|
|
641707f37b | ||
|
|
67924c894d | ||
|
|
7c8f212b03 | ||
|
|
85c73cb0a5 | ||
|
|
1b1f8e0d2c | ||
|
|
f87126f22c | ||
|
|
b635490e47 | ||
|
|
cac7b39823 | ||
|
|
af3c579a03 | ||
|
|
a508c63279 | ||
|
|
427a11bd0f | ||
|
|
6f3133d48c | ||
|
|
aa7f26ac79 | ||
|
|
084caad5d7 | ||
|
|
343bf05c2c | ||
|
|
3e40d72e25 | ||
|
|
1c1daa4ebe | ||
|
|
fdcda6e5f3 | ||
|
|
a50dde7f2b | ||
|
|
1fb4cb1c4f | ||
|
|
cd0f854f41 | ||
|
|
52c2401d93 | ||
|
|
02a87d9fe0 | ||
|
|
12d68a41ca | ||
|
|
6c4a64601f | ||
|
|
434f985e77 | ||
|
|
ba1dcfcdba | ||
|
|
b346dabdf8 | ||
|
|
1376a16812 | ||
|
|
4267314260 | ||
|
|
b5110c8554 | ||
|
|
1f1d1e4f2f | ||
|
|
522eb8b256 | ||
|
|
b662ecc76b | ||
|
|
6dd69eb6db | ||
|
|
1b6aeff005 | ||
|
|
4287774d9f | ||
|
|
6bba2fec0b | ||
|
|
5d2656d679 | ||
|
|
65a729a2d6 | ||
|
|
7868930fcb | ||
|
|
67248a290c | ||
|
|
0bc52eb331 | ||
|
|
5353be482e | ||
|
|
826ae86cb7 | ||
|
|
475153be4c | ||
|
|
5f734a0d17 | ||
|
|
1b8c9367a3 | ||
|
|
19047843cc | ||
|
|
174454b8c5 | ||
|
|
d30a53333c | ||
|
|
30b89328f1 | ||
|
|
b38dc62be7 | ||
|
|
6d9333aa94 | ||
|
|
6947bcfcf2 | ||
|
|
db06154ad7 | ||
|
|
fa43a6c40b | ||
|
|
5056187fb9 | ||
|
|
72c5c2ee4d | ||
|
|
25936a526d | ||
|
|
8bc735288f | ||
|
|
f8afa1cb78 | ||
|
|
e95eb2768d | ||
|
|
f6091cd117 | ||
|
|
9fafdea0bb | ||
|
|
fbf2c4c721 | ||
|
|
9d3cb4cc1b | ||
|
|
9d500186d1 | ||
|
|
f80265786d | ||
|
|
7b9d8d375d | ||
|
|
7393cb2cbe | ||
|
|
bcbe872c7d | ||
|
|
bf60c535bc | ||
|
|
feb99e9405 | ||
|
|
9fde88d61a | ||
|
|
430b4a274c | ||
|
|
5996426119 | ||
|
|
36d9460cdf | ||
|
|
1561f49c9c | ||
|
|
e032781a92 | ||
|
|
aa7d0b1e25 | ||
|
|
13a8babe75 | ||
|
|
87dda49113 | ||
|
|
018830b539 | ||
|
|
d92d2d07c5 | ||
|
|
046e49ac6b | ||
|
|
52e66ae969 | ||
|
|
ca15d7cb00 | ||
|
|
1086c61ccf | ||
|
|
77f9721102 | ||
|
|
b05683d384 | ||
|
|
d7df08d754 | ||
|
|
92b21aa5c1 | ||
|
|
0e2dff4e6b | ||
|
|
5c9e3570e2 | ||
|
|
51102e47ae | ||
|
|
7643568706 | ||
|
|
3684a023da | ||
|
|
b0c8f05f38 | ||
|
|
d8c2b8b719 | ||
|
|
31075f7c04 | ||
|
|
6bf6b933cc | ||
|
|
5681244941 | ||
|
|
788108c5b8 | ||
|
|
3fbc76e37f | ||
|
|
4e5b483cc0 | ||
|
|
ab068670cc | ||
|
|
456c002c3c | ||
|
|
038b89776d | ||
|
|
df6d968ebe | ||
|
|
4d9197b3cc | ||
|
|
10dffb0689 | ||
|
|
722c33df62 | ||
|
|
dc54cc82af | ||
|
|
d4a46606fd | ||
|
|
015af9774c | ||
|
|
f0a37172b9 | ||
|
|
2dd2e593e8 | ||
|
|
49fd78abe7 | ||
|
|
7c8cca7f56 | ||
|
|
0658f6dc2b | ||
|
|
75558078ee | ||
|
|
f6b5c69d4e | ||
|
|
a7f01eb04a | ||
|
|
65f9db8efa | ||
|
|
2ebad9ce96 | ||
|
|
b9cc66004d | ||
|
|
17838e7fe7 | ||
|
|
b0d0dbfe72 | ||
|
|
2d081dfc03 | ||
|
|
4a594f41b0 | ||
|
|
04b4af58f7 | ||
|
|
f44ba39ec5 | ||
|
|
05df765c5c | ||
|
|
04a7c912ea | ||
|
|
55fb8f2064 | ||
|
|
912c162eee | ||
|
|
2efb6a624f | ||
|
|
ca84fa11cd | ||
|
|
ed614767e6 | ||
|
|
6d94a0c776 | ||
|
|
81fd5cb605 | ||
|
|
b70bf3b9af | ||
|
|
250d640e76 | ||
|
|
6a05789db5 | ||
|
|
5e20874dca | ||
|
|
bc16970d96 | ||
|
|
f8f4bac77e | ||
|
|
5aa8338c59 | ||
|
|
1362fe9019 | ||
|
|
ba361e7eff | ||
|
|
31fb9bc169 | ||
|
|
e95a9525c6 | ||
|
|
326d4b3135 | ||
|
|
c4fad08d58 | ||
|
|
5a57d05fd6 | ||
|
|
8a7fa326cd | ||
|
|
18afe9ad7a | ||
|
|
253cf0f5a5 | ||
|
|
c5a85456c0 | ||
|
|
9a383826e7 | ||
|
|
1e6731830e | ||
|
|
d9aff32a36 | ||
|
|
38cb8fb88e | ||
|
|
ad5488784f | ||
|
|
a4cdd62aff | ||
|
|
9a9de9306e | ||
|
|
cf824b912d | ||
|
|
8d2e291deb | ||
|
|
3a432782b2 | ||
|
|
bda1fac923 | ||
|
|
ef40b1c524 | ||
|
|
a4c81736aa | ||
|
|
045c49679d | ||
|
|
f40442d309 | ||
|
|
fe7acecdd3 | ||
|
|
4471ec9b96 | ||
|
|
32e1d4f8fa | ||
|
|
747e5d801a | ||
|
|
29ed630536 | ||
|
|
c5757ffd22 | ||
|
|
9cc08cb088 | ||
|
|
2771e7f856 | ||
|
|
7c4dd8160d | ||
|
|
1fdc50b0da | ||
|
|
f87a676e4b | ||
|
|
8bf56b8b1a | ||
|
|
f31741f934 | ||
|
|
46258492bd | ||
|
|
6481f66e27 | ||
|
|
5954b8692f | ||
|
|
f6fdecf892 | ||
|
|
53fb77b50d | ||
|
|
04a9dc3a8c | ||
|
|
10b9a32f29 | ||
|
|
40fa929eb0 | ||
|
|
8c8ef19f01 | ||
|
|
1eaa3d309d | ||
|
|
a52cd5612a | ||
|
|
e82ed762be | ||
|
|
0bb16ec827 | ||
|
|
a978420a67 | ||
|
|
f59326bf10 | ||
|
|
d937ab2679 | ||
|
|
7164e211f2 | ||
|
|
dae78d7ac1 | ||
|
|
254468c723 | ||
|
|
71be4d99d6 | ||
|
|
f86fc845e7 | ||
|
|
cc907b9c14 | ||
|
|
241b2beee1 | ||
|
|
12f260e857 | ||
|
|
096d145cf9 | ||
|
|
b3883301a2 | ||
|
|
3a7521c492 | ||
|
|
caa5a96235 | ||
|
|
cee1c592ba | ||
|
|
f1fc9f0b27 | ||
|
|
e9adcb0dd5 | ||
|
|
afe2b675e5 | ||
|
|
2c14ee74b0 | ||
|
|
f351d2a37e | ||
|
|
4cb0e70184 | ||
|
|
41bb2551d3 | ||
|
|
55ed394782 | ||
|
|
dd7a883a33 | ||
|
|
f7acbc3928 | ||
|
|
2318578126 | ||
|
|
3e6f25f17c | ||
|
|
0cd6a59ce4 | ||
|
|
91a445961b | ||
|
|
749e9b7e08 | ||
|
|
905d29b279 | ||
|
|
5f97299cb2 | ||
|
|
60b75a4c8f | ||
|
|
0868286f27 | ||
|
|
ffcc46cb2d | ||
|
|
21bcd64c9d | ||
|
|
943b68f38f | ||
|
|
256b93087f | ||
|
|
7ed0d7eec3 | ||
|
|
9b8154246f | ||
|
|
c360759e49 | ||
|
|
d8b80aab1a | ||
|
|
b96ebc1872 | ||
|
|
6896dc155a | ||
|
|
1060d63808 | ||
|
|
88b6540f5b | ||
|
|
302e785f32 | ||
|
|
1507cc0b42 | ||
|
|
240307ef94 | ||
|
|
90c74bd82c | ||
|
|
9414096de7 | ||
|
|
07c3be9d6a | ||
|
|
9869dbd95a | ||
|
|
49b702106a | ||
|
|
8eb09beb96 | ||
|
|
b402a99a25 | ||
|
|
ad8938cd74 | ||
|
|
ee409c45a0 | ||
|
|
9d5da3388d | ||
|
|
9e138aa149 | ||
|
|
cf94c4d043 | ||
|
|
63b3807cf6 | ||
|
|
f3b6b27521 | ||
|
|
ff656182e8 | ||
|
|
a85ef6e769 | ||
|
|
0bb8c56ea9 | ||
|
|
5f108aec23 | ||
|
|
bf6683f993 | ||
|
|
b7a5e8dd85 | ||
|
|
57294aeaf5 | ||
|
|
20bfb8b08f | ||
|
|
5585a8992c | ||
|
|
d92a20050c | ||
|
|
c9a91d0683 | ||
|
|
ae6716ac01 | ||
|
|
34285b26ae | ||
|
|
5341e5faee | ||
|
|
a6224b484e | ||
|
|
e95c1ad3aa | ||
|
|
9cfed56847 | ||
|
|
6c1abddb1e | ||
|
|
7dc239f506 | ||
|
|
3e8413c6b7 | ||
|
|
ff86bfb91d | ||
|
|
66494b7b5a | ||
|
|
973127aa8c | ||
|
|
83866c3dd3 | ||
|
|
4797abc287 | ||
|
|
50f73f1be2 | ||
|
|
2ebbc8f466 | ||
|
|
1a96b30a45 | ||
|
|
3b1b57a33e | ||
|
|
f85c0320ec | ||
|
|
bae7edb914 | ||
|
|
35322399e9 | ||
|
|
5d4c0f3c87 | ||
|
|
92c5c32e8c | ||
|
|
c8780b2d5f | ||
|
|
f11dbfa367 | ||
|
|
54fb9deb3e | ||
|
|
d3c34ef04d | ||
|
|
3d5470eb22 | ||
|
|
2a3d69d0d5 | ||
|
|
9862c32378 | ||
|
|
9f02232589 | ||
|
|
ffc86bf046 | ||
|
|
e4c8ca34ed | ||
|
|
f02b7036a9 | ||
|
|
6adef47340 | ||
|
|
5b044cc036 | ||
|
|
03ba7524b2 | ||
|
|
772921c6b8 | ||
|
|
d4d305d53b | ||
|
|
c58918e002 | ||
|
|
dec7854476 | ||
|
|
8ca102f584 | ||
|
|
4748c66d9c | ||
|
|
bf486b9f44 | ||
|
|
6ff433ed7a | ||
|
|
f9aa392c6d | ||
|
|
48721859fa | ||
|
|
ee59d999f5 | ||
|
|
2f4f98cfe0 | ||
|
|
ac1f202c19 | ||
|
|
3f97ba3bd7 | ||
|
|
819912cfd3 | ||
|
|
50ee1ae922 | ||
|
|
c0442fca68 | ||
|
|
c20927b6d7 | ||
|
|
0d5b6d4c3e | ||
|
|
bdc08a530d | ||
|
|
6ab1632b4b | ||
|
|
cec865b9fb | ||
|
|
d763e924a9 | ||
|
|
57a30621e1 | ||
|
|
f344084791 | ||
|
|
be68314c3a | ||
|
|
53cff8229b | ||
|
|
1d52e27668 | ||
|
|
6ec867196c | ||
|
|
80798f278c | ||
|
|
4e61bbb92e | ||
|
|
fabab9bfbb | ||
|
|
4ae0089e4f | ||
|
|
d82bce79c9 | ||
|
|
55fcaf1c05 | ||
|
|
e83df502ed | ||
|
|
6501e89fa2 | ||
|
|
91801d441f | ||
|
|
dd2a4ee7ff | ||
|
|
8cedd88ce2 | ||
|
|
c3fde2b698 | ||
|
|
59e8aed445 | ||
|
|
e47b8f377c | ||
|
|
793c0d988e | ||
|
|
b0eef34146 | ||
|
|
3fbfb8b528 | ||
|
|
cdd240abb7 | ||
|
|
5d802f0e16 | ||
|
|
8661d07e1e | ||
|
|
41eec658e0 | ||
|
|
9facf07955 | ||
|
|
cd4844d26c | ||
|
|
9619b11c58 | ||
|
|
535060153a | ||
|
|
f26ff52712 | ||
|
|
4a299ea53f | ||
|
|
6f0ba337c4 | ||
|
|
8df6e2dd57 | ||
|
|
5010cdff71 | ||
|
|
fea1839c06 | ||
|
|
80e3b157ca | ||
|
|
d5028d86df | ||
|
|
1fac6b7c93 | ||
|
|
089467c15a | ||
|
|
77e7f767d8 | ||
|
|
324739aeb9 | ||
|
|
84d301c676 | ||
|
|
dcfce8b619 | ||
|
|
813d4edc97 | ||
|
|
9ea4a5dbd4 | ||
|
|
508e36d327 | ||
|
|
37b1e7366c | ||
|
|
b29b9f1b2c | ||
|
|
7865be43bb | ||
|
|
f17f688a20 | ||
|
|
df2a6a6902 | ||
|
|
df0c0ec21e | ||
|
|
53d71d9766 | ||
|
|
eb5a72fc27 | ||
|
|
cec045045e | ||
|
|
33f30101d9 | ||
|
|
1e139a6005 | ||
|
|
eacfbad729 | ||
|
|
6834a2e083 | ||
|
|
2538d583ad | ||
|
|
c9ccc28251 | ||
|
|
0f1ad9d811 | ||
|
|
93c986f00a | ||
|
|
239e2ef86d | ||
|
|
5a7a23552d | ||
|
|
4fb98cf72b | ||
|
|
a125497fe7 | ||
|
|
ae2196585e | ||
|
|
fbad50973f | ||
|
|
782cfd1fd0 | ||
|
|
d4a06089c9 | ||
|
|
5c6efed995 | ||
|
|
68a31b1eb7 | ||
|
|
f46f755327 | ||
|
|
5d4f870a1d | ||
|
|
08c5c38c7b | ||
|
|
0c9238651a | ||
|
|
10a9b062b6 | ||
|
|
53c6a17ccb | ||
|
|
c10617e1b0 | ||
|
|
be01567a1b | ||
|
|
88fc501c24 | ||
|
|
e93bb5ceba | ||
|
|
7983621f8e | ||
|
|
6c79d6b01f | ||
|
|
b2a351e67d | ||
|
|
574fa8abf4 | ||
|
|
c4f4af5e5a | ||
|
|
1da0792ed7 | ||
|
|
7d37acb1cd | ||
|
|
fd230701e9 | ||
|
|
91d492c579 | ||
|
|
5eabe7e644 | ||
|
|
368e720cab | ||
|
|
cba156b3dc | ||
|
|
676bc0fef0 | ||
|
|
7455c63716 | ||
|
|
81818705df | ||
|
|
61ea484614 | ||
|
|
d5e8de4d74 | ||
|
|
b7d5144c91 | ||
|
|
7bba5ec69e | ||
|
|
0441acf101 | ||
|
|
89f0909a8f | ||
|
|
ff0f1c4c24 | ||
|
|
3a6c52ae73 | ||
|
|
7ec18ebf00 | ||
|
|
66f52d41eb | ||
|
|
1172cf0ae7 | ||
|
|
1d296d1cf4 | ||
|
|
a6bddc5aca | ||
|
|
bdd40fdf7d | ||
|
|
c84e153ff2 | ||
|
|
ab4c83d284 | ||
|
|
cd99c053df | ||
|
|
3434ef47d9 | ||
|
|
c5145a38e2 | ||
|
|
38b9778e9a | ||
|
|
2ca6168f47 | ||
|
|
0da2299472 | ||
|
|
bf2ce3c4af | ||
|
|
c0f82eabb2 | ||
|
|
30aba1258d | ||
|
|
f2ed920214 | ||
|
|
2fc7139f6b | ||
|
|
e8ace49e8b | ||
|
|
dddb9ff713 | ||
|
|
f582f7df7c | ||
|
|
14c6d1be9b | ||
|
|
2157f8e8cd | ||
|
|
0731e15385 | ||
|
|
9eb82060a5 | ||
|
|
9f232ab5ec | ||
|
|
ec0d164619 | ||
|
|
e804ab9254 | ||
|
|
25cb12a81a | ||
|
|
231acc7363 | ||
|
|
d8bdf6a8d3 | ||
|
|
d506067c72 | ||
|
|
4483d3231a | ||
|
|
481ee186aa | ||
|
|
8820b8a41c |
@@ -1,87 +0,0 @@
|
||||
version: 2.4.a.{build}
|
||||
shallow_clone: true
|
||||
skip_branch_with_pr: false
|
||||
skip_commits:
|
||||
message: /!nobuild/
|
||||
skip_tags: false
|
||||
|
||||
environment:
|
||||
access_token_documentation:
|
||||
secure: JVBVVL8uJUcLXN+48eRdELEeCGOGCCaMzCqutsUqNuaZ/KblG5ZTt7+LV4UKv/0f
|
||||
LUAROCKS_VER: 2.4.1
|
||||
LUA_VER: 5.1.5
|
||||
LUA: lua5.3
|
||||
matrix:
|
||||
- LUA_VER: 5.1.5
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
|
||||
init:
|
||||
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
|
||||
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
|
||||
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
|
||||
throw "There are newer queued builds for this pull request, failing early." }
|
||||
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
|
||||
install:
|
||||
- cmd:
|
||||
# Outcomment if lua environment invalidates and needs to be reinstalled, otherwise all will run from the cache.
|
||||
call choco install 7zip.commandline
|
||||
call choco install lua51
|
||||
call choco install luarocks
|
||||
call refreshenv
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
|
||||
cmd: PATH = %PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\bin
|
||||
cmd: set LUA_PATH = %LUA_PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?.lua;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?\init.lua
|
||||
cmd: set LUA_CPATH = %LUA_CPATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\lib\lua\5.1\?.dll
|
||||
call luarocks install luasrcdiet
|
||||
call luarocks install checks
|
||||
call luarocks install luadocumentor
|
||||
call luarocks install luacheck
|
||||
|
||||
|
||||
cache:
|
||||
C:\ProgramData\chocolatey\lib
|
||||
C:\ProgramData\chocolatey\bin
|
||||
|
||||
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' )
|
||||
{
|
||||
echo "Hello World!"
|
||||
$apiUrl = 'https://ci.appveyor.com/api'
|
||||
$token = 'v2.6hcv3ige78kg3yvg4ge8'
|
||||
$headers = @{
|
||||
"Authorization" = "Bearer $token"
|
||||
"Content-type" = "application/json"
|
||||
}
|
||||
$RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-include'; branch = "$env:appveyor_repo_branch"; environmentVariables = @{} } | ConvertTo-Json
|
||||
# Generate the new version ...
|
||||
$project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody
|
||||
}
|
||||
- ps: |
|
||||
if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' )
|
||||
{
|
||||
$apiUrl = 'https://ci.appveyor.com/api'
|
||||
$token = 'v2.6hcv3ige78kg3yvg4ge8'
|
||||
$headers = @{
|
||||
"Authorization" = "Bearer $token"
|
||||
"Content-type" = "application/json"
|
||||
}
|
||||
$RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-docs'; branch = "$env:appveyor_repo_branch"; environmentVariables = @{} } | ConvertTo-Json
|
||||
# get project with last build details
|
||||
$project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody
|
||||
}
|
||||
|
||||
|
||||
test: off
|
||||
# test_script:
|
||||
# - cmd: luacheck "Moose Development\Moose\moose.lua" "Moose Mission Setup\moose.lua"
|
||||
|
||||
|
||||
on_finish:
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -15,3 +15,7 @@
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
|
||||
# Avoid Windows line endings on shell scripts
|
||||
# Needed for dockerfile builds
|
||||
*.sh text eol=lf
|
||||
|
||||
168
.github/workflows/build-docs.yml
vendored
Normal file
168
.github/workflows/build-docs.yml
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
name: Moose-Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
paths:
|
||||
- 'Moose Setup/**/*.lua'
|
||||
- 'Moose Development/**/*.lua'
|
||||
- 'Moose Development/**/*.py'
|
||||
- 'Moose Development/**/*.html'
|
||||
- '.github/workflows/build-docs.yml'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Extract branch name
|
||||
shell: bash
|
||||
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
|
||||
id: extract_branch
|
||||
|
||||
- name: Build informations
|
||||
run: |
|
||||
echo "Triggered by: ${{ github.event_name }}"
|
||||
echo "Running on: ${{ runner.os }}"
|
||||
echo "Ref: ${{ github.ref }}"
|
||||
echo "Branch name: ${{ steps.extract_branch.outputs.branch }}"
|
||||
echo "Repository: ${{ github.repository }}"
|
||||
echo "Commit-Id: ${{ github.sha }}"
|
||||
echo "Owner: ${{ github.repository_owner }}"
|
||||
echo "FORCE_PUSH: ${{ vars.FORCE_PUSH }}"
|
||||
|
||||
#########################################################################
|
||||
# Prepare build environment
|
||||
#########################################################################
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare build output folders
|
||||
run: |
|
||||
mkdir -p build/tools
|
||||
mkdir -p build/doc
|
||||
|
||||
- name: Checkout FlightControls modified luadocumentor
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: Applevangelist/luadocumentor
|
||||
path: './build/tools/luadocumentor'
|
||||
ref: 'patch-1'
|
||||
token: ${{ secrets.BOT_TOKEN }}
|
||||
|
||||
- name: Update apt-get (needed for act docker image)
|
||||
run: |
|
||||
sudo apt-get -qq update
|
||||
|
||||
- name: Install tree
|
||||
run: |
|
||||
sudo apt-get -qq install tree
|
||||
|
||||
#########################################################################
|
||||
# Install all prerequisites for LuaDocumentor
|
||||
#########################################################################
|
||||
- name: Install Lua
|
||||
run: |
|
||||
sudo apt-get -qq install lua5.1
|
||||
|
||||
- name: Install LuaRocks
|
||||
run: |
|
||||
sudo apt-get -qq install luarocks -y
|
||||
|
||||
- name: Install markdown (prereq for LuaDocumentor)
|
||||
run: |
|
||||
sudo luarocks install markdown 0.32-2
|
||||
|
||||
- name: Install penlight (prereq for LuaDocumentor)
|
||||
run: |
|
||||
sudo luarocks install penlight 1.11.0-1
|
||||
|
||||
- name: Install metalua-compiler (prereq for LuaDocumentor)
|
||||
run: |
|
||||
sudo luarocks install metalua-compiler 0.7.3-1
|
||||
|
||||
- name: Install metalua-parser (prereq for LuaDocumentor)
|
||||
run: |
|
||||
sudo luarocks install metalua-parser 0.7.3-2
|
||||
|
||||
- name: Install checks (prereq for LuaDocumentor)
|
||||
run: |
|
||||
sudo luarocks install checks
|
||||
|
||||
#########################################################################
|
||||
# Run LuaDocumentor
|
||||
#########################################################################
|
||||
- name: Run LuaDocumentor
|
||||
run: |
|
||||
lua luadocumentor.lua -d ${{ github.workspace }}/build/doc "${{ github.workspace }}/Moose Development/Moose"
|
||||
working-directory: ${{ github.workspace }}/build/tools/luadocumentor
|
||||
|
||||
#########################################################################
|
||||
# Replace <head> tag
|
||||
#########################################################################
|
||||
- name: Replace head tag
|
||||
run: |
|
||||
python3 "${{ github.workspace }}/Moose Development/docs-header.py"
|
||||
working-directory: ${{ github.workspace }}/build/doc
|
||||
|
||||
- name: Check replacement of head tag
|
||||
run: |
|
||||
head -10 ${{ github.workspace }}/build/doc/AI.AI_A2A_Cap.html
|
||||
|
||||
#########################################################################
|
||||
# Push to MOOSE_DOCS
|
||||
#########################################################################
|
||||
- name: Set docs repo for branch
|
||||
shell: bash
|
||||
id: set_doc_repo
|
||||
run: |
|
||||
if [[ $GITHUB_REF == 'refs/heads/master' ]]; then
|
||||
echo "docrepo=MOOSE_DOCS" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "docrepo=MOOSE_DOCS_DEVELOP" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Checkout ${{ steps.set_doc_repo.outputs.docrepo }} to folder MOOSE_DOCS
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.repository_owner }}/${{ steps.set_doc_repo.outputs.docrepo }}
|
||||
path: './build/MOOSE_DOCS'
|
||||
fetch-depth: 0
|
||||
ref: 'master'
|
||||
token: ${{ secrets.BOT_TOKEN }}
|
||||
|
||||
- name: Delete folder to remove deleted files
|
||||
run: |
|
||||
rm -rf ./build/MOOSE_DOCS/Documentation/
|
||||
|
||||
- name: Create target folder
|
||||
run: mkdir -p build/MOOSE_DOCS/Documentation
|
||||
|
||||
- name: Copy build result to MOOSE_DOCS
|
||||
run: |
|
||||
cp ./build/doc/*.* ./build/MOOSE_DOCS/Documentation/
|
||||
|
||||
- name: Push result to docs repository
|
||||
if: ${{ vars.FORCE_PUSH == 'true' }}
|
||||
run: |
|
||||
git config user.name "MooseBotter"
|
||||
git config user.email "MooseBotter@users.noreply.github.com"
|
||||
git add .
|
||||
git commit --allow-empty -m "Auto commit by GitHub Actions Workflow"
|
||||
git push --set-upstream origin master
|
||||
|
||||
working-directory: ${{ github.workspace }}/build/MOOSE_DOCS
|
||||
|
||||
#########################################################################
|
||||
# Show the results
|
||||
#########################################################################
|
||||
- name: List files in the repository
|
||||
run: |
|
||||
tree ${{ github.workspace }}/build
|
||||
|
||||
- run: echo "This job's status is ${{ job.status }}."
|
||||
151
.github/workflows/build-includes.yml
vendored
Normal file
151
.github/workflows/build-includes.yml
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
name: Moose-Includes
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- Apple/Develop
|
||||
|
||||
paths:
|
||||
- 'Moose Setup/**/*.lua'
|
||||
- 'Moose Development/**/*.lua'
|
||||
- '.github/workflows/build-includes.yml'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Extract branch name
|
||||
shell: bash
|
||||
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
|
||||
id: extract_branch
|
||||
|
||||
- name: Build informations
|
||||
run: |
|
||||
echo "Triggered by: ${{ github.event_name }}"
|
||||
echo "Running on: ${{ runner.os }}"
|
||||
echo "Ref: ${{ github.ref }}"
|
||||
echo "Branch name: ${{ steps.extract_branch.outputs.branch }}"
|
||||
echo "Repository: ${{ github.repository }}"
|
||||
echo "Commit-Id: ${{ github.sha }}"
|
||||
echo "Owner: ${{ github.repository_owner }}"
|
||||
echo "FORCE_PUSH: ${{ vars.FORCE_PUSH }}"
|
||||
|
||||
#########################################################################
|
||||
# Prepare build environment
|
||||
#########################################################################
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare build output folders
|
||||
run: |
|
||||
mkdir -p build/result/Moose_Include_Dynamic
|
||||
mkdir -p build/result/Moose_Include_Static
|
||||
|
||||
- name: Update apt-get (needed for act docker image)
|
||||
run: |
|
||||
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
|
||||
sudo apt-get -qq update
|
||||
|
||||
- name: Install tree
|
||||
run: |
|
||||
sudo apt-get -qq install tree
|
||||
|
||||
#########################################################################
|
||||
# Install all prerequisites
|
||||
#########################################################################
|
||||
- name: Install Lua 5.3
|
||||
run: |
|
||||
sudo apt-get -qq install lua5.3 -y
|
||||
- name: Check Lua version
|
||||
run: |
|
||||
lua -v
|
||||
|
||||
- name: Install LuaRocks
|
||||
run: |
|
||||
sudo apt-get -qq install luarocks -y
|
||||
- name: Check LuaRocks version
|
||||
run: |
|
||||
luarocks --version
|
||||
|
||||
- name: Install Lua 5.3 Dev for prerequisites for LuaSrcDiet
|
||||
run: |
|
||||
sudo apt-get -qq install liblua5.3-dev -y
|
||||
|
||||
- name: Install LuaSrcDiet
|
||||
run: |
|
||||
sudo luarocks install luasrcdiet
|
||||
|
||||
- name: Install LuaCheck
|
||||
run: |
|
||||
sudo luarocks install luacheck
|
||||
|
||||
#########################################################################
|
||||
# Build Include files
|
||||
#########################################################################
|
||||
- name: Build Include Static
|
||||
run: |
|
||||
export COMMIT_TIME=$(git show -s --format=%cd ${{ github.sha }} --date=iso-strict)
|
||||
lua5.3 "./Moose Setup/Moose_Create.lua" S "$COMMIT_TIME-${{ github.sha }}" "./Moose Development/Moose" "./Moose Setup" "./build/result/Moose_Include_Static"
|
||||
|
||||
- name: Build Includes Dynamic
|
||||
run: |
|
||||
export COMMIT_TIME=$(git show -s --format=%cd ${{ github.sha }} --date=iso-strict)
|
||||
lua5.3 "./Moose Setup/Moose_Create.lua" D "$COMMIT_TIME-${{ github.sha }}" "./Moose Development/Moose" "./Moose Setup" "./build/result/Moose_Include_Dynamic"
|
||||
|
||||
#########################################################################
|
||||
# Run LuaCheck
|
||||
#########################################################################
|
||||
- name: Run LuaCheck
|
||||
if: ${{ vars.SKIP_LUACHECK != true }}
|
||||
continue-on-error: true
|
||||
run: |
|
||||
luacheck --std=lua51c --config=.luacheckrc -gurasqq "Moose Development/Moose"
|
||||
|
||||
- name: Run LuaSrcDiet
|
||||
run: |
|
||||
luasrcdiet --basic --opt-emptylines ./build/result/Moose_Include_Static/Moose.lua -o ./build/result/Moose_Include_Static/Moose_.lua
|
||||
|
||||
#########################################################################
|
||||
# Push to MOOSE_INCLUDE
|
||||
#########################################################################
|
||||
- name: Checkout MOOSE_INCLUDE
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.repository_owner }}/MOOSE_INCLUDE
|
||||
path: './build/MOOSE_INCLUDE'
|
||||
fetch-depth: 0
|
||||
ref: ${{ steps.extract_branch.outputs.branch }}
|
||||
token: ${{ secrets.BOT_TOKEN }}
|
||||
|
||||
- name: Create target folder (needed if checkout is deactivated)
|
||||
run: mkdir -p build/MOOSE_INCLUDE
|
||||
|
||||
- name: Copy build reseult to MOOSE_INCLUDE
|
||||
run: |
|
||||
cp -r ./build/result/* ./build/MOOSE_INCLUDE/
|
||||
|
||||
- name: Push result to MOOSE_INCLUDE repository
|
||||
if: ${{ vars.FORCE_PUSH == 'true' }}
|
||||
run: |
|
||||
git config user.name "MooseBotter"
|
||||
git config user.email "MooseBotter@users.noreply.github.com"
|
||||
git add .
|
||||
git commit --allow-empty -m "Auto commit by GitHub Actions Workflow"
|
||||
git push --set-upstream origin ${{ steps.extract_branch.outputs.branch }}
|
||||
|
||||
working-directory: ${{ github.workspace }}/build/MOOSE_INCLUDE
|
||||
|
||||
#########################################################################
|
||||
# Show the results
|
||||
#########################################################################
|
||||
- name: List files in the repository
|
||||
run: |
|
||||
tree ${{ github.workspace }}/build
|
||||
|
||||
- run: echo "This job's status is ${{ job.status }}."
|
||||
78
.github/workflows/gh-pages.yml
vendored
Normal file
78
.github/workflows/gh-pages.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
# Sample workflow for building and deploying a Jekyll site to GitHub Pages
|
||||
name: Deploy Jekyll site to Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '.github/workflows/gh-pages.yml'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Build job
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '3.1' # Not needed with a .ruby-version file
|
||||
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||
cache-version: 0 # Increment this number if you need to re-download cached gems
|
||||
working-directory: docs/
|
||||
- name: Setup Pages
|
||||
id: pages
|
||||
uses: actions/configure-pages@v4
|
||||
- name: Build with Jekyll
|
||||
# Outputs to the './_site' directory by default
|
||||
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
|
||||
env:
|
||||
JEKYLL_ENV: production
|
||||
working-directory: docs/
|
||||
- name: Upload artifact
|
||||
# Automatically uploads an artifact from the './_site' directory by default
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: docs/_site/
|
||||
|
||||
# Deployment job
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
needs: deploy
|
||||
steps:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
- run: npm install linkinator
|
||||
- run: npx linkinator https://flightcontrol-master.github.io/MOOSE/ --verbosity error --timeout 5000 --recurse --skip "(java.com)" --retry-errors --retry-errors-count 3 --retry-errors-jitter
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -35,6 +35,8 @@ local.properties
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
.vscode
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
@@ -219,12 +221,16 @@ pip-log.txt
|
||||
#Goodsync
|
||||
_gsdata_/
|
||||
|
||||
# PyCharm
|
||||
.idea
|
||||
|
||||
#GITHUB
|
||||
.gitattributes
|
||||
.gitignore
|
||||
Moose Test Missions/MOOSE_Test_Template.miz
|
||||
Moose Development/Moose/.vscode/launch.json
|
||||
MooseCodeWS.code-workspace
|
||||
.gitignore
|
||||
.gitignore
|
||||
/.gitignore
|
||||
|
||||
# Excludes for act (https://github.com/nektos/act)
|
||||
.secrets
|
||||
.env
|
||||
.actrc
|
||||
.vars
|
||||
|
||||
@@ -1953,7 +1953,7 @@ local function refct_from_id(id) -- refct = refct_from_id(CTypeID)
|
||||
unsigned = refct.unsigned,
|
||||
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
|
||||
|
||||
if CT[4] then -- Merge sibling attributes onto this type.
|
||||
|
||||
166
Moose Development/Moose/.editorconfig
Normal file
166
Moose Development/Moose/.editorconfig
Normal file
@@ -0,0 +1,166 @@
|
||||
# Repository: https://github.com/CppCXY/EmmyLuaCodeStyle
|
||||
# English documentation: https://github.com/CppCXY/EmmyLuaCodeStyle/blob/master/README_EN.md
|
||||
[*.lua]
|
||||
# [basic]
|
||||
|
||||
# optional space/tab
|
||||
indent_style = space
|
||||
# if indent_style is space, this is valid
|
||||
indent_size = 4
|
||||
# if indent_style is tab, this is valid
|
||||
tab_width = 4
|
||||
# none/single/double
|
||||
quote_style = none
|
||||
|
||||
# only support number
|
||||
continuation_indent_size = 0
|
||||
|
||||
# optional crlf/lf/cr/auto, if it is 'auto', in windows it is crlf other platforms are lf
|
||||
end_of_line = auto
|
||||
|
||||
detect_end_of_line = false
|
||||
|
||||
# this mean utf8 length , if this is 'unset' then the line width is no longer checked
|
||||
# this option decides when to chopdown the code
|
||||
max_line_length = 9999
|
||||
|
||||
# this will check text end with new line
|
||||
insert_final_newline = true
|
||||
|
||||
# [function]
|
||||
|
||||
# function call expression's args will align to first arg
|
||||
# optional true/false/only_after_more_indention_statement/only_not_exist_cross_row_expression
|
||||
align_call_args = false
|
||||
|
||||
# if true, all function define params will align to first param
|
||||
align_function_define_params = true
|
||||
|
||||
remove_expression_list_finish_comma = true
|
||||
|
||||
# keep/remove/remove_table_only/remove_string_only/unambiguous_remove_string_only
|
||||
call_arg_parentheses = keep
|
||||
|
||||
# [table]
|
||||
|
||||
#optional none/comma/semicolon
|
||||
table_separator_style = none
|
||||
|
||||
#optional keep/never/always/smart
|
||||
trailing_table_separator = keep
|
||||
|
||||
# see document for detail
|
||||
continuous_assign_table_field_align_to_equal_sign = true
|
||||
|
||||
# if true, format like this "local t = { 1, 2, 3 }"
|
||||
keep_one_space_between_table_and_bracket = true
|
||||
|
||||
# if indent_style is tab, this option is invalid
|
||||
align_table_field_to_first_field = true
|
||||
|
||||
# [statement]
|
||||
|
||||
align_chained_expression_statement = false
|
||||
|
||||
# continous line distance
|
||||
max_continuous_line_distance = 1
|
||||
|
||||
# see document for detail
|
||||
continuous_assign_statement_align_to_equal_sign = true
|
||||
|
||||
# if statement will align like switch case
|
||||
if_condition_align_with_each_other = false
|
||||
|
||||
# if true, continuation_indent_size for local or assign statement is invalid
|
||||
# however, if the expression list has cross row expression, it will not be aligned to the first expression
|
||||
local_assign_continuation_align_to_first_expression = false
|
||||
|
||||
statement_inline_comment_space = 1
|
||||
|
||||
# [indentation]
|
||||
|
||||
# if true, the label loses its current indentation
|
||||
label_no_indent = false
|
||||
# if true, there will be no indentation in the do statement
|
||||
do_statement_no_indent = false
|
||||
# if true, the conditional expression of the if statement will not be a continuation line indent
|
||||
if_condition_no_continuation_indent = false
|
||||
|
||||
if_branch_comments_after_block_no_indent = false
|
||||
|
||||
# [space]
|
||||
|
||||
# if true, t[#t+1] will not space wrapper '+'
|
||||
table_append_expression_no_space = false
|
||||
|
||||
long_chain_expression_allow_one_space_after_colon = false
|
||||
|
||||
remove_empty_header_and_footer_lines_in_function = true
|
||||
|
||||
space_before_function_open_parenthesis = false
|
||||
|
||||
space_inside_function_call_parentheses = false
|
||||
|
||||
space_inside_function_param_list_parentheses = false
|
||||
|
||||
space_before_open_square_bracket = false
|
||||
|
||||
space_inside_square_brackets = false
|
||||
|
||||
# if true, ormat like this "local t <const> = 1"
|
||||
keep_one_space_between_namedef_and_attribute = true
|
||||
|
||||
# [row_layout]
|
||||
# The following configuration supports four expressions
|
||||
# minLine:${n}
|
||||
# keepLine
|
||||
# keepLine:${n}
|
||||
# maxLine:${n}
|
||||
|
||||
keep_line_after_if_statement = minLine:0
|
||||
|
||||
keep_line_after_do_statement = minLine:0
|
||||
|
||||
keep_line_after_while_statement = minLine:0
|
||||
|
||||
keep_line_after_repeat_statement = minLine:0
|
||||
|
||||
keep_line_after_for_statement = minLine:0
|
||||
|
||||
keep_line_after_local_or_assign_statement = keepLine
|
||||
|
||||
keep_line_after_function_define_statement = keepLine:1
|
||||
|
||||
keep_line_after_expression_statement = keepLine
|
||||
|
||||
# [diagnostic]
|
||||
|
||||
# the following is code diagnostic options
|
||||
enable_check_codestyle = true
|
||||
|
||||
# [diagnostic.name_style]
|
||||
enable_name_style_check = false
|
||||
# the following is name style check rule
|
||||
# base option off/camel_case/snake_case/upper_snake_case/pascal_case/same(filename/first_param/'<const string>', snake_case/pascal_case/camel_case)
|
||||
# all option can use '|' represent or
|
||||
# for example:
|
||||
# snake_case | upper_snake_case
|
||||
# same(first_param, snake_case)
|
||||
# same('m')
|
||||
local_name_define_style = snake_case
|
||||
|
||||
function_param_name_style = snake_case
|
||||
|
||||
function_name_define_style = snake_case
|
||||
|
||||
local_function_name_define_style = snake_case
|
||||
|
||||
table_field_name_define_style = snake_case
|
||||
|
||||
global_variable_name_define_style = snake_case|upper_snake_case
|
||||
|
||||
module_name_define_style = same('m')|same(filename, snake_case)
|
||||
|
||||
require_module_name_style = same(first_param, snake_case)
|
||||
|
||||
class_name_define_style = same(filename, snake_case)
|
||||
@@ -1,33 +0,0 @@
|
||||
# See https://github.com/Koihik/LuaFormatter
|
||||
# Use '-- LuaFormatter off' and '-- LuaFormatter on' around code blocks to inhibit formatting
|
||||
|
||||
column_limit: 500
|
||||
indent_width: 2
|
||||
use_tab: false
|
||||
continuation_indent_width: 2
|
||||
keep_simple_control_block_one_line: false
|
||||
keep_simple_function_one_line: false
|
||||
align_args: true
|
||||
break_after_functioncall_lp: false
|
||||
break_before_functioncall_rp: false
|
||||
align_parameter: true
|
||||
chop_down_parameter: true
|
||||
break_after_functiondef_lp: false
|
||||
break_before_functiondef_rp: false
|
||||
align_table_field: true
|
||||
break_after_table_lb: true
|
||||
break_before_table_rb: true
|
||||
chop_down_table: true
|
||||
chop_down_kv_table: true
|
||||
column_table_limit: 500
|
||||
table_sep: ','
|
||||
extra_sep_at_table_end: true
|
||||
break_after_operator: true
|
||||
single_quote_to_double_quote: false
|
||||
double_quote_to_single_quote: false
|
||||
spaces_before_call: 1
|
||||
spaces_inside_functiondef_parens: true
|
||||
spaces_inside_functioncall_parens: true
|
||||
spaces_inside_table_braces: true
|
||||
spaces_around_equals_in_field: true
|
||||
line_breaks_after_function_body: 1
|
||||
@@ -1,4 +1,6 @@
|
||||
--- **AI** -- (R2.2) - Models the process of Combat Air Patrol (CAP) for airplanes.
|
||||
--- **AI** - Models the process of Combat Air Patrol (CAP) for airplanes.
|
||||
--
|
||||
-- This is a class used in the @{AI.AI_A2A_Dispatcher}.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -13,10 +15,11 @@
|
||||
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||
|
||||
|
||||
--- The AI_A2A_CAP class implements the core functions to patrol a @{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.
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
@@ -81,15 +84,20 @@
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_CAP#AI_A2A_CAP.SetEngageRange}() to define that range.
|
||||
-- Use the method @{#AI_A2A_CAP.SetEngageRange}() to define that range.
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Zone} can be set,
|
||||
-- An optional @{Core.Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_Cap#AI_A2A_CAP.SetEngageZone}() to define that Zone.
|
||||
-- Use the method @{#AI_A2A_CAP.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -106,7 +114,7 @@ AI_A2A_CAP = {
|
||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
@@ -117,7 +125,7 @@ function AI_A2A_CAP:New2( AICap, EngageMinSpeed, EngageMaxSpeed, EngageFloorAlti
|
||||
|
||||
-- Multiple inheritance ... :-)
|
||||
local AI_Air = AI_AIR:New( AICap )
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AICap, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
|
||||
local self = BASE:Inherit( self, AI_Air_Engage ) --#AI_A2A_CAP
|
||||
|
||||
@@ -132,7 +140,7 @@ end
|
||||
--- Creates a new AI_A2A_CAP object
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Group#GROUP AICap
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
@@ -191,7 +199,7 @@ end
|
||||
--- Evaluate the attack and create an AttackUnitTask list.
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
||||
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
|
||||
-- @param Wrapper.Group#GROUP DefenderGroup The group of defenders.
|
||||
-- @param #number EngageAltitude The altitude to engage the targets.
|
||||
-- @return #AI_A2A_CAP self
|
||||
function AI_A2A_CAP:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** - (R2.2) - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.
|
||||
--- **AI** - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -23,7 +23,7 @@
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [AID-A2A - AI A2A Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching)
|
||||
-- [AID-A2A - AI A2A Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -32,7 +32,9 @@
|
||||
-- [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # QUICK START GUIDE
|
||||
--
|
||||
-- There are basically two classes available to model an A2A defense system.
|
||||
@@ -57,8 +59,8 @@
|
||||
--
|
||||
-- ## 2. Which type of EWR will I setup? Grouping based per AREA, per TYPE or per UNIT? (Later others will follow).
|
||||
--
|
||||
-- The MOOSE framework leverages the @{Detection} classes to perform the EWR detection.
|
||||
-- Several types of @{Detection} classes exist, and the most common characteristics of these classes is that they:
|
||||
-- The MOOSE framework leverages the @{Functional.Detection} classes to perform the EWR detection.
|
||||
-- Several types of @{Functional.Detection} classes exist, and the most common characteristics of these classes is that they:
|
||||
--
|
||||
-- * Perform detections from multiple FACs as one co-operating entity.
|
||||
-- * Communicate with a Head Quarters, which consolidates each detection.
|
||||
@@ -126,7 +128,7 @@
|
||||
-- * polygon zones
|
||||
-- * moving zones
|
||||
--
|
||||
-- Depending on the type of zone selected, a different @{Zone} object needs to be created from a ZONE_ class.
|
||||
-- Depending on the type of zone selected, a different @{Core.Zone} object needs to be created from a ZONE_ class.
|
||||
--
|
||||
-- ## 14. For each Squadron doing CAP, what are the time intervals and CAP amounts to be performed?
|
||||
--
|
||||
@@ -177,6 +179,11 @@
|
||||
--
|
||||
-- **The default grouping is 1. That means, that each spawned defender will act individually.**
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: **FlightControl** rework of GCICAP + introduction of new concepts (squadrons).
|
||||
@@ -305,7 +312,7 @@ do -- AI_A2A_DISPATCHER
|
||||
-- Use the method @{#AI_A2A_DISPATCHER.SetEngageRadius}() to set a specific Engage Radius.
|
||||
-- **The Engage Radius is defined for ALL squadrons which are operational.**
|
||||
--
|
||||
-- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-019%20-%20AI_A2A%20-%20Engage%20Range%20Test)
|
||||
-- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher/AID-A2A-019%20-%20Engage%20Range%20Test)
|
||||
--
|
||||
-- In this example an Engage Radius is set to various values.
|
||||
--
|
||||
@@ -328,7 +335,7 @@ do -- AI_A2A_DISPATCHER
|
||||
-- Use the method @{#AI_A2A_DISPATCHER.SetGciRadius}() to set a specific controlled ground intercept radius.
|
||||
-- **The Ground Controlled Intercept radius is defined for ALL squadrons which are operational.**
|
||||
--
|
||||
-- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-013%20-%20AI_A2A%20-%20Intercept%20Test)
|
||||
-- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher/AID-A2A-013%20-%20Intercept%20Test)
|
||||
--
|
||||
-- In these examples, the Gci Radius is set to various values:
|
||||
--
|
||||
@@ -356,12 +363,12 @@ do -- AI_A2A_DISPATCHER
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}.
|
||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}.
|
||||
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than
|
||||
-- it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are.
|
||||
-- In a hot war the borders are effectively defined by the ground based radar coverage of a coalition.
|
||||
--
|
||||
-- Demonstration Mission: [AID-009 - AI_A2A - Border Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-009 - AI_A2A - Border Test)
|
||||
-- Demonstration Mission: [AID-009 - AI_A2A - Border Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher/AID-A2A-009%20-%20Border%20Test)
|
||||
--
|
||||
-- In this example a border is set for the CCCP A2A dispatcher:
|
||||
--
|
||||
@@ -592,7 +599,7 @@ do -- AI_A2A_DISPATCHER
|
||||
-- A2ADispatcher:SetSquadronCap( "Maykop", CAPZoneMiddle, 4000, 8000, 600, 800, 800, 1200, "RADIO" )
|
||||
-- A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
|
||||
--
|
||||
-- Note the different @{Zone} MOOSE classes being used to create zones of different types. Please click the @{Zone} link for more information about the different zone types.
|
||||
-- Note the different @{Core.Zone} MOOSE classes being used to create zones of different types. Please click the @{Core.Zone} link for more information about the different zone types.
|
||||
-- Zones can be circles, can be setup in the mission editor using trigger zones, but can also be setup in the mission editor as polygons and in this case GROUP objects are being used!
|
||||
--
|
||||
-- ## 7.2. Set the squadron to execute CAP:
|
||||
@@ -1146,14 +1153,14 @@ do -- AI_A2A_DISPATCHER
|
||||
|
||||
local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured.
|
||||
|
||||
self:I( "Captured " .. AirbaseName )
|
||||
self:T( "Captured " .. AirbaseName )
|
||||
|
||||
-- Now search for all squadrons located at the airbase, and sanatize them.
|
||||
-- Now search for all squadrons located at the airbase, and sanitize them.
|
||||
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
||||
if Squadron.AirbaseName == AirbaseName then
|
||||
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
||||
Squadron.Captured = true
|
||||
self:I( "Squadron " .. SquadronName .. " captured." )
|
||||
self:T( "Squadron " .. SquadronName .. " captured." )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1228,7 +1235,7 @@ do -- AI_A2A_DISPATCHER
|
||||
--
|
||||
-- **Use the method @{#AI_A2A_DISPATCHER.SetEngageRadius}() to modify the default Engage Radius for ALL squadrons.**
|
||||
--
|
||||
-- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-019%20-%20AI_A2A%20-%20Engage%20Range%20Test)
|
||||
-- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher/AID-A2A-019%20-%20Engage%20Range%20Test)
|
||||
--
|
||||
-- @param #AI_A2A_DISPATCHER self
|
||||
-- @param #number EngageRadius (Optional, Default = 100000) The radius to report friendlies near the target.
|
||||
@@ -1278,7 +1285,7 @@ do -- AI_A2A_DISPATCHER
|
||||
-- Use the method @{#AI_A2A_DISPATCHER.SetGciRadius}() to set a specific controlled ground intercept radius.
|
||||
-- **The Ground Controlled Intercept radius is defined for ALL squadrons which are operational.**
|
||||
--
|
||||
-- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-013%20-%20AI_A2A%20-%20Intercept%20Test)
|
||||
-- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher/AID-A2A-013%20-%20Intercept%20Test)
|
||||
--
|
||||
-- @param #AI_A2A_DISPATCHER self
|
||||
-- @param #number GciRadius (Optional, Default = 200000) The radius to ground control intercept detected targets from the nearest airbase.
|
||||
@@ -1304,7 +1311,7 @@ do -- AI_A2A_DISPATCHER
|
||||
--- Define a border area to simulate a **cold war** scenario.
|
||||
-- A **cold war** is one where CAP aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
||||
-- A **hot war** is one where CAP aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send CAP and GCI aircraft to attack it.
|
||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
||||
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
|
||||
-- @param #AI_A2A_DISPATCHER self
|
||||
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
|
||||
@@ -1687,6 +1694,20 @@ do -- AI_A2A_DISPATCHER
|
||||
|
||||
return DefenderSquadron
|
||||
end
|
||||
|
||||
--- Get a resource count from a specific squadron
|
||||
-- @param #AI_A2A_DISPATCHER self
|
||||
-- @param #string Squadron Name of the squadron.
|
||||
-- @return #number Number of airframes available or nil if the squadron does not exist
|
||||
function AI_A2A_DISPATCHER:QuerySquadron(Squadron)
|
||||
local Squadron = self:GetSquadron(Squadron)
|
||||
if Squadron.ResourceCount then
|
||||
self:T2(string.format("%s = %s",Squadron.Name,Squadron.ResourceCount))
|
||||
return Squadron.ResourceCount
|
||||
end
|
||||
self:F({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
||||
return nil
|
||||
end
|
||||
|
||||
--- [DEPRECATED - Might create problems launching planes] Set the Squadron visible before startup of the dispatcher.
|
||||
-- All planes will be spawned as uncontrolled on the parking spot.
|
||||
@@ -1713,7 +1734,7 @@ do -- AI_A2A_DISPATCHER
|
||||
-- Get free parking for fighter aircraft.
|
||||
local nfreeparking = DefenderSquadron.Airbase:GetFreeParkingSpotsNumber( AIRBASE.TerminalType.FighterAircraft, true )
|
||||
|
||||
-- Take number of free parking spots if no resource count was specifed.
|
||||
-- Take number of free parking spots if no resource count was specified.
|
||||
DefenderSquadron.ResourceCount = DefenderSquadron.ResourceCount or nfreeparking
|
||||
|
||||
-- Check that resource count is not larger than free parking spots.
|
||||
@@ -1758,7 +1779,7 @@ do -- AI_A2A_DISPATCHER
|
||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||
-- @param #number EngageAltType The altitude type to engage, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
|
||||
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
||||
-- @param #number PatrolMaxSpeed The maximum speed at which the cap can be executed.
|
||||
-- @param #number PatrolFloorAltitude The minimum altitude at which the cap can be executed.
|
||||
@@ -1809,7 +1830,7 @@ do -- AI_A2A_DISPATCHER
|
||||
|
||||
self:SetSquadronCapInterval( SquadronName, self.DefenderDefault.CapLimit, self.DefenderDefault.CapMinSeconds, self.DefenderDefault.CapMaxSeconds, 1 )
|
||||
|
||||
self:I( { CAP = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageAltType } } )
|
||||
self:T( { CAP = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageAltType } } )
|
||||
|
||||
-- Add the CAP to the EWR network.
|
||||
|
||||
@@ -1825,7 +1846,7 @@ do -- AI_A2A_DISPATCHER
|
||||
--- Set a CAP for a Squadron.
|
||||
-- @param #AI_A2A_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
|
||||
-- @param #number PatrolFloorAltitude The minimum altitude at which the cap can be executed.
|
||||
-- @param #number PatrolCeilingAltitude the maximum altitude at which the cap can be executed.
|
||||
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
||||
@@ -2066,7 +2087,7 @@ do -- AI_A2A_DISPATCHER
|
||||
Intercept.EngageCeilingAltitude = EngageCeilingAltitude
|
||||
Intercept.EngageAltType = EngageAltType
|
||||
|
||||
self:I( { GCI = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
self:T( { GCI = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
end
|
||||
|
||||
--- Set squadron GCI.
|
||||
@@ -2981,17 +3002,17 @@ do -- AI_A2A_DISPATCHER
|
||||
for FriendlyDistance, AIFriendly in UTILS.spairs( DefenderFriendlies or {} ) do
|
||||
-- We only allow to ENGAGE targets as long as the Units on both sides are balanced.
|
||||
if AttackerCount > DefenderCount then
|
||||
--self:I("***** AI_A2A_DISPATCHER:CountDefendersToBeEngaged() *****\nThis is supposed to be a UNIT:")
|
||||
--self:T("***** AI_A2A_DISPATCHER:CountDefendersToBeEngaged() *****\nThis is supposed to be a UNIT:")
|
||||
if AIFriendly then
|
||||
local classname = AIFriendly.ClassName or "No Class Name"
|
||||
local unitname = AIFriendly.IdentifiableName or "No Unit Name"
|
||||
--self:I("Class Name: " .. classname)
|
||||
--self:I("Unit Name: " .. unitname)
|
||||
--self:I({AIFriendly})
|
||||
--self:T("Class Name: " .. classname)
|
||||
--self:T("Unit Name: " .. unitname)
|
||||
--self:T({AIFriendly})
|
||||
end
|
||||
local Friendly = nil
|
||||
if AIFriendly and AIFriendly:IsAlive() then
|
||||
--self:I("AIFriendly alive, getting GROUP")
|
||||
--self:T("AIFriendly alive, getting GROUP")
|
||||
Friendly = AIFriendly:GetGroup() -- Wrapper.Group#GROUP
|
||||
end
|
||||
|
||||
@@ -3238,7 +3259,8 @@ do -- AI_A2A_DISPATCHER
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_DISPATCHER self
|
||||
--- AI_A2A_Fsm:onafterHome
|
||||
-- @param #AI_A2A_DISPATCHER self
|
||||
function AI_A2A_Fsm:onafterHome( Defender, From, Event, To, Action )
|
||||
if Defender and Defender:IsAlive() then
|
||||
self:F( { "CAP Home", Defender:GetName() } )
|
||||
@@ -3486,7 +3508,8 @@ do -- AI_A2A_DISPATCHER
|
||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_DISPATCHER self
|
||||
--- function Fsm:onafterLostControl
|
||||
-- @param #AI_A2A_DISPATCHER self
|
||||
function Fsm:onafterLostControl( Defender, From, Event, To )
|
||||
self:F( { "GCI LostControl", Defender:GetName() } )
|
||||
self:GetParent( self ).onafterHome( self, Defender, From, Event, To )
|
||||
@@ -3499,7 +3522,8 @@ do -- AI_A2A_DISPATCHER
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_DISPATCHER self
|
||||
--- function Fsm:onafterHome
|
||||
-- @param #AI_A2A_DISPATCHER self
|
||||
function Fsm:onafterHome( DefenderGroup, From, Event, To, Action )
|
||||
self:F( { "GCI Home", DefenderGroup:GetName() } )
|
||||
self:GetParent( self ).onafterHome( self, DefenderGroup, From, Event, To )
|
||||
@@ -3930,7 +3954,7 @@ end
|
||||
|
||||
do
|
||||
|
||||
--- @type AI_A2A_GCICAP
|
||||
-- @type AI_A2A_GCICAP
|
||||
-- @extends #AI_A2A_DISPATCHER
|
||||
|
||||
--- Create an automatic air defence system for a coalition setting up GCI and CAP air defenses.
|
||||
@@ -3940,11 +3964,7 @@ do
|
||||
--
|
||||
-- # Demo Missions
|
||||
--
|
||||
-- ### [AI\_A2A\_GCICAP for Caucasus](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-200%20-%20AI_A2A%20-%20GCICAP%20Demonstration)
|
||||
-- ### [AI\_A2A\_GCICAP for NTTR](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-210%20-%20NTTR%20AI_A2A_GCICAP%20Demonstration)
|
||||
-- ### [AI\_A2A\_GCICAP for Normandy](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-220%20-%20NORMANDY%20AI_A2A_GCICAP%20Demonstration)
|
||||
--
|
||||
-- ### [AI\_A2A\_GCICAP for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -4304,23 +4324,23 @@ do
|
||||
|
||||
-- Setup squadrons
|
||||
|
||||
self:I( { Airbases = AirbaseNames } )
|
||||
self:T( { Airbases = AirbaseNames } )
|
||||
|
||||
self:I( "Defining Templates for Airbases ..." )
|
||||
self:T( "Defining Templates for Airbases ..." )
|
||||
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
||||
local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE
|
||||
local AirbaseName = Airbase:GetName()
|
||||
local AirbaseCoord = Airbase:GetCoordinate()
|
||||
local AirbaseZone = ZONE_RADIUS:New( "Airbase", AirbaseCoord:GetVec2(), 3000 )
|
||||
local Templates = nil
|
||||
self:I( { Airbase = AirbaseName } )
|
||||
self:T( { Airbase = AirbaseName } )
|
||||
for TemplateID, Template in pairs( self.Templates:GetSet() ) do
|
||||
local Template = Template -- Wrapper.Group#GROUP
|
||||
local TemplateCoord = Template:GetCoordinate()
|
||||
if AirbaseZone:IsVec2InZone( TemplateCoord:GetVec2() ) then
|
||||
Templates = Templates or {}
|
||||
table.insert( Templates, Template:GetName() )
|
||||
self:I( { Template = Template:GetName() } )
|
||||
self:T( { Template = Template:GetName() } )
|
||||
end
|
||||
end
|
||||
if Templates then
|
||||
@@ -4336,13 +4356,13 @@ do
|
||||
self.CAPTemplates:FilterPrefixes( CapPrefixes )
|
||||
self.CAPTemplates:FilterOnce()
|
||||
|
||||
self:I( "Setting up CAP ..." )
|
||||
self:T( "Setting up CAP ..." )
|
||||
for CAPID, CAPTemplate in pairs( self.CAPTemplates:GetSet() ) do
|
||||
local CAPZone = ZONE_POLYGON:New( CAPTemplate:GetName(), CAPTemplate )
|
||||
-- Now find the closest airbase from the ZONE (start or center)
|
||||
local AirbaseDistance = 99999999
|
||||
local AirbaseClosest = nil -- Wrapper.Airbase#AIRBASE
|
||||
self:I( { CAPZoneGroup = CAPID } )
|
||||
self:T( { CAPZoneGroup = CAPID } )
|
||||
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
||||
local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE
|
||||
local AirbaseName = Airbase:GetName()
|
||||
@@ -4350,7 +4370,7 @@ do
|
||||
local Squadron = self.DefenderSquadrons[AirbaseName]
|
||||
if Squadron then
|
||||
local Distance = AirbaseCoord:Get2DDistance( CAPZone:GetCoordinate() )
|
||||
self:I( { AirbaseDistance = Distance } )
|
||||
self:T( { AirbaseDistance = Distance } )
|
||||
if Distance < AirbaseDistance then
|
||||
AirbaseDistance = Distance
|
||||
AirbaseClosest = Airbase
|
||||
@@ -4358,7 +4378,7 @@ do
|
||||
end
|
||||
end
|
||||
if AirbaseClosest then
|
||||
self:I( { CAPAirbase = AirbaseClosest:GetName() } )
|
||||
self:T( { CAPAirbase = AirbaseClosest:GetName() } )
|
||||
self:SetSquadronCap( AirbaseClosest:GetName(), CAPZone, 6000, 10000, 500, 800, 800, 1200, "RADIO" )
|
||||
self:SetSquadronCapInterval( AirbaseClosest:GetName(), CapLimit, 300, 600, 1 )
|
||||
end
|
||||
@@ -4366,14 +4386,14 @@ do
|
||||
|
||||
-- Setup GCI.
|
||||
-- GCI is setup for all Squadrons.
|
||||
self:I( "Setting up GCI ..." )
|
||||
self:T( "Setting up GCI ..." )
|
||||
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
||||
local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE
|
||||
local AirbaseName = Airbase:GetName()
|
||||
local Squadron = self.DefenderSquadrons[AirbaseName]
|
||||
self:F( { Airbase = AirbaseName } )
|
||||
if Squadron then
|
||||
self:I( { GCIAirbase = AirbaseName } )
|
||||
self:T( { GCIAirbase = AirbaseName } )
|
||||
self:SetSquadronGci( AirbaseName, 800, 1200 )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- **AI** -- (R2.2) - Models the process of Ground Controlled Interception (GCI) for airplanes.
|
||||
--- **AI** - Models the process of Ground Controlled Interception (GCI) for airplanes.
|
||||
--
|
||||
-- This is a class used in the @{AI_A2A_Dispatcher}.
|
||||
-- This is a class used in the @{AI.AI_A2A_Dispatcher}.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -8,53 +8,39 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_A2A_GCI
|
||||
-- @module AI.AI_A2A_Gci
|
||||
-- @image AI_Ground_Control_Intercept.JPG
|
||||
|
||||
|
||||
|
||||
--- @type AI_A2A_GCI
|
||||
-- @extends AI.AI_A2A#AI_A2A
|
||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||
|
||||
|
||||
--- 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 will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- This cycle will continue.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- When enemies are detected, the AI will automatically engage the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## 1. AI_A2A_GCI constructor
|
||||
--
|
||||
-- * @{#AI_A2A_GCI.New}(): Creates a new AI_A2A_GCI object.
|
||||
--
|
||||
-- ## 2. AI_A2A_GCI is a FSM
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ### 2.1 AI_A2A_GCI States
|
||||
--
|
||||
-- * **None** ( Group ): The process is not started yet.
|
||||
@@ -75,23 +61,10 @@
|
||||
-- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
||||
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||
--
|
||||
-- ## 3. Set the Range of Engagement
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional range can be set in meters,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_GCI#AI_A2A_GCI.SetEngageRange}() to define that range.
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_Cap#AI_A2A_GCI.SetEngageZone}() to define that Zone.
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -153,7 +126,7 @@ end
|
||||
--- Evaluate the attack and create an AttackUnitTask list.
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
||||
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
|
||||
-- @param Wrapper.Group#GROUP DefenderGroup The group of defenders.
|
||||
-- @param #number EngageAltitude The altitude to engage the targets.
|
||||
-- @return #AI_A2A_GCI self
|
||||
function AI_A2A_GCI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- (R2.2) - Models the process of air patrol of airplanes.
|
||||
--- **AI** - Models the process of air patrol of airplanes.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -11,9 +11,11 @@
|
||||
|
||||
|
||||
--- @type AI_A2A_PATROL
|
||||
-- @extends AI.AI_A2A#AI_A2A
|
||||
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
||||
|
||||
--- Implements the core functions to patrol a @{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}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
@@ -102,7 +104,7 @@
|
||||
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
|
||||
-- while a new AI is targetted to the AI_A2A_PATROL.
|
||||
-- while a new AI is targeted to the AI_A2A_PATROL.
|
||||
-- Once the time is finished, the old AI will return to the base.
|
||||
-- Use the method @{#AI_A2A_PATROL.ManageFuel}() to have this proces in place.
|
||||
--
|
||||
@@ -111,7 +113,12 @@
|
||||
-- When the AI is damaged, it is required that a new Patrol is started. However, damage cannon be foreseen early on.
|
||||
-- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
|
||||
-- Use the method @{#AI_A2A_PATROL.ManageDamage}() to have this proces in place.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2A_PATROL
|
||||
@@ -122,7 +129,7 @@ AI_A2A_PATROL = {
|
||||
--- Creates a new AI_A2A_PATROL object
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The patrol group object.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
@@ -264,7 +271,7 @@ function AI_A2A_PATROL:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
||||
end
|
||||
|
||||
|
||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
||||
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @return #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
@@ -287,7 +294,7 @@ function AI_A2A_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
||||
end
|
||||
|
||||
|
||||
--- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
|
||||
--- This static method is called from the route path within the last task at the last waypoint of the AIPatrol.
|
||||
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The AI group.
|
||||
-- @param #AI_A2A_PATROL Fsm The FSM.
|
||||
@@ -302,7 +309,7 @@ function AI_A2A_PATROL.PatrolRoute( AIPatrol, Fsm )
|
||||
end
|
||||
|
||||
|
||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
||||
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- **AI** -- Models the process of air to ground BAI engagement for airplanes and helicopters.
|
||||
--- **AI** - Models the process of air to ground BAI engagement for airplanes and helicopters.
|
||||
--
|
||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
||||
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -11,14 +11,19 @@
|
||||
-- @module AI.AI_A2G_BAI
|
||||
-- @image AI_Air_To_Ground_Engage.JPG
|
||||
|
||||
|
||||
|
||||
--- @type AI_A2G_BAI
|
||||
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage
|
||||
|
||||
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2G_BAI
|
||||
@@ -26,8 +31,6 @@ AI_A2G_BAI = {
|
||||
ClassName = "AI_A2G_BAI",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Creates a new AI_A2G_BAI object
|
||||
-- @param #AI_A2G_BAI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
@@ -36,7 +39,7 @@ AI_A2G_BAI = {
|
||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
@@ -46,14 +49,13 @@ AI_A2G_BAI = {
|
||||
function AI_A2G_BAI:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
|
||||
local AI_Air = AI_AIR:New( AIGroup )
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
|
||||
local self = BASE:Inherit( self, AI_Air_Engage )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Creates a new AI_A2G_BAI object
|
||||
-- @param #AI_A2G_BAI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
@@ -61,7 +63,7 @@ end
|
||||
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
@@ -76,7 +78,7 @@ end
|
||||
--- Evaluate the attack and create an AttackUnitTask list.
|
||||
-- @param #AI_A2G_BAI self
|
||||
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
||||
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
|
||||
-- @param Wrapper.Group#GROUP DefenderGroup The group of defenders.
|
||||
-- @param #number EngageAltitude The altitude to engage the targets.
|
||||
-- @return #AI_A2G_BAI self
|
||||
function AI_A2G_BAI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
||||
@@ -92,8 +94,6 @@ function AI_A2G_BAI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageA
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return AttackUnitTasks
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- **AI** -- Models the process of air to ground engagement for airplanes and helicopters.
|
||||
--- **AI** - Models the process of air to ground engagement for airplanes and helicopters.
|
||||
--
|
||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
||||
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -11,14 +11,19 @@
|
||||
-- @module AI.AI_A2G_CAS
|
||||
-- @image AI_Air_To_Ground_Engage.JPG
|
||||
|
||||
|
||||
|
||||
--- @type AI_A2G_CAS
|
||||
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL
|
||||
|
||||
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2G_CAS
|
||||
@@ -26,8 +31,6 @@ AI_A2G_CAS = {
|
||||
ClassName = "AI_A2G_CAS",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Creates a new AI_A2G_CAS object
|
||||
-- @param #AI_A2G_CAS self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
@@ -36,7 +39,7 @@ AI_A2G_CAS = {
|
||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
@@ -46,14 +49,13 @@ AI_A2G_CAS = {
|
||||
function AI_A2G_CAS:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
|
||||
local AI_Air = AI_AIR:New( AIGroup )
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
|
||||
local self = BASE:Inherit( self, AI_Air_Engage )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Creates a new AI_A2G_CAS object
|
||||
-- @param #AI_A2G_CAS self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
@@ -61,7 +63,7 @@ end
|
||||
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
@@ -76,7 +78,7 @@ end
|
||||
--- Evaluate the attack and create an AttackUnitTask list.
|
||||
-- @param #AI_A2G_CAS self
|
||||
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
||||
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
|
||||
-- @param Wrapper.Group#GROUP DefenderGroup The group of defenders.
|
||||
-- @param #number EngageAltitude The altitude to engage the targets.
|
||||
-- @return #AI_A2G_CAS self
|
||||
function AI_A2G_CAS:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
||||
@@ -92,9 +94,6 @@ function AI_A2G_CAS:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageA
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return AttackUnitTasks
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** - Create an automated A2G defense system based on a detection network of reconnaissance vehicles and air units, coordinating SEAD, BAI and CAS operations.
|
||||
--- **AI** - Create an automated A2G defense system with reconnaissance units, coordinating SEAD, BAI and CAS operations.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -24,7 +24,7 @@
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [AID-A2G - AI A2G Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2G%20-%20AI%20A2G%20Dispatching)
|
||||
-- [AID-A2G - AI A2G Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2G_Dispatcher)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -36,6 +36,8 @@
|
||||
--
|
||||
-- # QUICK START GUIDE
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
@@ -175,7 +177,7 @@
|
||||
-- * polygon zones
|
||||
-- * moving zones
|
||||
--
|
||||
-- Depending on the type of zone selected, a different @{Zone} object needs to be created from a ZONE_ class.
|
||||
-- Depending on the type of zone selected, a different @{Core.Zone} object needs to be created from a ZONE_ class.
|
||||
--
|
||||
--
|
||||
-- ## 12. Are moving defense coordinates possible?
|
||||
@@ -253,7 +255,12 @@
|
||||
--
|
||||
-- **The default grouping is 1. That means, that each spawned defender will act individually.**
|
||||
-- But you can specify a number between 1 and 4, so that the defenders will act as a group.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl** rework of GCICAP + introduction of new concepts (squadrons).
|
||||
@@ -291,8 +298,6 @@ do -- AI_A2G_DISPATCHER
|
||||
--
|
||||
-- ## 1. AI\_A2G\_DISPATCHER constructor:
|
||||
--
|
||||
-- 
|
||||
--
|
||||
--
|
||||
-- The @{#AI_A2G_DISPATCHER.New}() method creates a new AI_A2G_DISPATCHER instance.
|
||||
--
|
||||
@@ -306,8 +311,6 @@ do -- AI_A2G_DISPATCHER
|
||||
-- A reconnaissance network, is used to detect enemy ground targets,
|
||||
-- potentially group them into areas, and to understand the position, level of threat of the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- As explained in the introduction, depending on the type of mission you want to achieve, different types of units can be applied to detect ground enemy targets.
|
||||
-- Ground based units are very useful to act as a reconnaissance, but they lack sometimes the visibility to detect targets at greater range.
|
||||
-- Recce are very useful to acquire the position of enemy ground targets when spread out over the battlefield at strategic positions.
|
||||
@@ -681,8 +684,6 @@ do -- AI_A2G_DISPATCHER
|
||||
--
|
||||
-- Use the method @{#AI_A2G_DISPATCHER.SetSquadronGrouping}() to set the grouping of aircraft when spawned in.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- In the case of **on call** engagement, the @{#AI_A2G_DISPATCHER.SetSquadronGrouping}() method has additional behaviour.
|
||||
-- When there aren't enough patrol flights airborne, a on call will be initiated for the remaining
|
||||
-- targets to be engaged. Depending on the grouping parameter, the spawned flights for on call aircraft are grouped into this setting.
|
||||
@@ -696,8 +697,6 @@ do -- AI_A2G_DISPATCHER
|
||||
-- The effectiveness can be set with the **overhead parameter**. This is a number that is used to calculate the amount of Units that dispatching command will allocate to GCI in surplus of detected amount of units.
|
||||
-- The **default value** of the overhead parameter is 1.0, which means **equal balance**.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- However, depending on the (type of) aircraft (strength and payload) in the squadron and the amount of resources available, this parameter can be changed.
|
||||
--
|
||||
-- The @{#AI_A2G_DISPATCHER.SetSquadronOverhead}() method can be used to tweak the defense strength,
|
||||
@@ -843,8 +842,6 @@ do -- AI_A2G_DISPATCHER
|
||||
--
|
||||
-- For example, the following setup will set the default refuel tanker to "Tanker":
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- -- Set the default tanker for refuelling to "Tanker", when the default fuel threshold has reached 90% fuel left.
|
||||
-- A2GDispatcher:SetDefaultFuelThreshold( 0.9 )
|
||||
-- A2GDispatcher:SetDefaultTanker( "Tanker" )
|
||||
@@ -909,14 +906,14 @@ do -- AI_A2G_DISPATCHER
|
||||
-- @type AI_A2G_DISPATCHER.DefenseCoordinates
|
||||
-- @map <#string,Core.Point#COORDINATE> A list of all defense coordinates mapped per defense coordinate name.
|
||||
|
||||
--- @field #AI_A2G_DISPATCHER.DefenseCoordinates DefenseCoordinates
|
||||
-- @field #AI_A2G_DISPATCHER.DefenseCoordinates DefenseCoordinates
|
||||
AI_A2G_DISPATCHER.DefenseCoordinates = {}
|
||||
|
||||
--- Enumerator for spawns at airbases.
|
||||
-- @type AI_A2G_DISPATCHER.Takeoff
|
||||
-- @extends Wrapper.Group#GROUP.Takeoff
|
||||
|
||||
--- @field #AI_A2G_DISPATCHER.Takeoff Takeoff
|
||||
-- @field #AI_A2G_DISPATCHER.Takeoff Takeoff
|
||||
AI_A2G_DISPATCHER.Takeoff = GROUP.Takeoff
|
||||
|
||||
--- Defines Landing location.
|
||||
@@ -947,11 +944,11 @@ do -- AI_A2G_DISPATCHER
|
||||
-- @type AI_A2G_DISPATCHER.DefenseQueue
|
||||
-- @list<#AI_A2G_DISPATCHER.DefenseQueueItem> DefenseQueueItem A list of all defenses being queued ...
|
||||
|
||||
--- @field #AI_A2G_DISPATCHER.DefenseQueue DefenseQueue
|
||||
-- @field #AI_A2G_DISPATCHER.DefenseQueue DefenseQueue
|
||||
AI_A2G_DISPATCHER.DefenseQueue = {}
|
||||
|
||||
--- Defense approach types.
|
||||
-- @type #AI_A2G_DISPATCHER.DefenseApproach
|
||||
-- @type AI_A2G_DISPATCHER.DefenseApproach
|
||||
AI_A2G_DISPATCHER.DefenseApproach = {
|
||||
Random = 1,
|
||||
Distance = 2,
|
||||
@@ -1141,7 +1138,7 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:onafterStart( From, Event, To )
|
||||
|
||||
self:GetParent( self ).onafterStart( self, From, Event, To )
|
||||
@@ -1152,7 +1149,7 @@ do -- AI_A2G_DISPATCHER
|
||||
for Resource = 1, DefenderSquadron.ResourceCount or 0 do
|
||||
self:ResourcePark( DefenderSquadron )
|
||||
end
|
||||
self:I( "Parked resources for squadron " .. DefenderSquadron.Name )
|
||||
self:T( "Parked resources for squadron " .. DefenderSquadron.Name )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1206,7 +1203,7 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:ResourcePark( DefenderSquadron )
|
||||
local TemplateID = math.random( 1, #DefenderSquadron.Spawn )
|
||||
local Spawn = DefenderSquadron.Spawn[ TemplateID ] -- Core.Spawn#SPAWN
|
||||
@@ -1223,33 +1220,33 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_A2G_DISPATCHER:OnEventBaseCaptured( EventData )
|
||||
|
||||
local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured.
|
||||
|
||||
self:I( "Captured " .. AirbaseName )
|
||||
self:T( "Captured " .. AirbaseName )
|
||||
|
||||
-- Now search for all squadrons located at the airbase, and sanitize them.
|
||||
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
||||
if Squadron.AirbaseName == AirbaseName then
|
||||
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
||||
Squadron.Captured = true
|
||||
self:I( "Squadron " .. SquadronName .. " captured." )
|
||||
self:T( "Squadron " .. SquadronName .. " captured." )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_A2G_DISPATCHER:OnEventCrashOrDead( EventData )
|
||||
self.Detection:ForgetDetectedUnit( EventData.IniUnitName )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_A2G_DISPATCHER:OnEventLand( EventData )
|
||||
self:F( "Landed" )
|
||||
@@ -1266,7 +1263,7 @@ do -- AI_A2G_DISPATCHER
|
||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
end
|
||||
DefenderUnit:Destroy()
|
||||
self:ResourcePark( Squadron, Defender )
|
||||
self:ResourcePark( Squadron )
|
||||
return
|
||||
end
|
||||
if DefenderUnit:GetLife() ~= DefenderUnit:GetLife0() then
|
||||
@@ -1278,7 +1275,7 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_A2G_DISPATCHER:OnEventEngineShutdown( EventData )
|
||||
local DefenderUnit = EventData.IniUnit
|
||||
@@ -1294,7 +1291,7 @@ do -- AI_A2G_DISPATCHER
|
||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
end
|
||||
DefenderUnit:Destroy()
|
||||
self:ResourcePark( Squadron, Defender )
|
||||
self:ResourcePark( Squadron )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1302,7 +1299,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
do -- Manage the defensive behaviour
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string DefenseCoordinateName The name of the coordinate to be defended by A2G defenses.
|
||||
-- @param Core.Point#COORDINATE DefenseCoordinate The coordinate to be defended by A2G defenses.
|
||||
function AI_A2G_DISPATCHER:AddDefenseCoordinate( DefenseCoordinateName, DefenseCoordinate )
|
||||
@@ -1310,19 +1307,19 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:SetDefenseReactivityLow()
|
||||
self.DefenseReactivity = 0.05
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:SetDefenseReactivityMedium()
|
||||
self.DefenseReactivity = 0.15
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:SetDefenseReactivityHigh()
|
||||
self.DefenseReactivity = 0.5
|
||||
end
|
||||
@@ -1356,14 +1353,14 @@ do -- AI_A2G_DISPATCHER
|
||||
-- 1. the **distance of the closest airbase to target**, being smaller than the **Defend Radius**.
|
||||
-- 2. the **distance to any defense reference point**.
|
||||
--
|
||||
-- The **default** defense radius is defined as **400000** or **40km**. Override the default defense radius when the era of the warfare is early, or,
|
||||
-- The **default** defense radius is defined as **40000** or **40km**. Override the default defense radius when the era of the warfare is early, or,
|
||||
-- when you don't want to let the AI_A2G_DISPATCHER react immediately when a certain border or area is not being crossed.
|
||||
--
|
||||
-- Use the method @{#AI_A2G_DISPATCHER.SetDefendRadius}() to set a specific defend radius for all squadrons,
|
||||
-- **the Defense Radius is defined for ALL squadrons which are operational.**
|
||||
--
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #number DefenseRadius (Optional, Default = 200000) The defense radius to engage detected targets from the nearest capable and available squadron airbase.
|
||||
-- @param #number DefenseRadius (Optional, Default = 20000) The defense radius to engage detected targets from the nearest capable and available squadron airbase.
|
||||
-- @return #AI_A2G_DISPATCHER
|
||||
-- @usage
|
||||
--
|
||||
@@ -1378,7 +1375,7 @@ do -- AI_A2G_DISPATCHER
|
||||
--
|
||||
function AI_A2G_DISPATCHER:SetDefenseRadius( DefenseRadius )
|
||||
|
||||
self.DefenseRadius = DefenseRadius or 100000
|
||||
self.DefenseRadius = DefenseRadius or 40000
|
||||
|
||||
self.Detection:SetAcceptRange( self.DefenseRadius )
|
||||
|
||||
@@ -1389,7 +1386,7 @@ do -- AI_A2G_DISPATCHER
|
||||
--- Define a border area to simulate a **cold war** scenario.
|
||||
-- A **cold war** is one where Patrol aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
||||
-- A **hot war** is one where Patrol aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send Patrol and GCI aircraft to attack it.
|
||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
||||
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
|
||||
@@ -1806,6 +1803,19 @@ do -- AI_A2G_DISPATCHER
|
||||
return DefenderSquadron
|
||||
end
|
||||
|
||||
--- Get a resource count from a specific squadron
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string Squadron Name of the squadron.
|
||||
-- @return #number Number of airframes available or nil if the squadron does not exist
|
||||
function AI_A2G_DISPATCHER:QuerySquadron(Squadron)
|
||||
local Squadron = self:GetSquadron(Squadron)
|
||||
if Squadron.ResourceCount then
|
||||
self:T2(string.format("%s = %s",Squadron.Name,Squadron.ResourceCount))
|
||||
return Squadron.ResourceCount
|
||||
end
|
||||
self:F({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Set the Squadron visible before startup of the dispatcher.
|
||||
-- All planes will be spawned as uncontrolled on the parking spot.
|
||||
@@ -1839,7 +1849,7 @@ do -- AI_A2G_DISPATCHER
|
||||
--- Check if the Squadron is visible before startup of the dispatcher.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @return #bool true if visible.
|
||||
-- @return #boolean true if visible.
|
||||
-- @usage
|
||||
--
|
||||
-- -- Set the Squadron visible before startup of dispatcher.
|
||||
@@ -1860,7 +1870,7 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param #number TakeoffInterval Only Takeoff new units each specified interval in seconds in 10 seconds steps.
|
||||
-- @usage
|
||||
@@ -2136,7 +2146,7 @@ do -- AI_A2G_DISPATCHER
|
||||
Sead.EngageAltType = EngageAltType
|
||||
Sead.Defend = true
|
||||
|
||||
self:I( { SEAD = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
self:T( { SEAD = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -2185,7 +2195,7 @@ do -- AI_A2G_DISPATCHER
|
||||
-- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
|
||||
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||
@@ -2226,7 +2236,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "SEAD" )
|
||||
|
||||
self:I( { SEAD = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
self:T( { SEAD = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
end
|
||||
|
||||
|
||||
@@ -2234,7 +2244,7 @@ do -- AI_A2G_DISPATCHER
|
||||
-- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
|
||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||
@@ -2287,7 +2297,7 @@ do -- AI_A2G_DISPATCHER
|
||||
Cas.EngageAltType = EngageAltType
|
||||
Cas.Defend = true
|
||||
|
||||
self:I( { CAS = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
self:T( { CAS = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -2336,7 +2346,7 @@ do -- AI_A2G_DISPATCHER
|
||||
-- The Cas patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
|
||||
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||
@@ -2377,7 +2387,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "CAS" )
|
||||
|
||||
self:I( { CAS = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
self:T( { CAS = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
end
|
||||
|
||||
|
||||
@@ -2385,7 +2395,7 @@ do -- AI_A2G_DISPATCHER
|
||||
-- The Cas patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
|
||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||
@@ -2438,7 +2448,7 @@ do -- AI_A2G_DISPATCHER
|
||||
Bai.EngageAltType = EngageAltType
|
||||
Bai.Defend = true
|
||||
|
||||
self:I( { BAI = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
self:T( { BAI = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -2487,7 +2497,7 @@ do -- AI_A2G_DISPATCHER
|
||||
-- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
|
||||
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||
@@ -2528,7 +2538,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "BAI" )
|
||||
|
||||
self:I( { BAI = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
self:T( { BAI = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||
end
|
||||
|
||||
|
||||
@@ -2536,7 +2546,7 @@ do -- AI_A2G_DISPATCHER
|
||||
-- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
|
||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||
@@ -3361,7 +3371,7 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:AddDefenderToSquadron( Squadron, Defender, Size )
|
||||
self.Defenders = self.Defenders or {}
|
||||
local DefenderName = Defender:GetName()
|
||||
@@ -3372,7 +3382,7 @@ do -- AI_A2G_DISPATCHER
|
||||
self:F( { DefenderName = DefenderName, SquadronResourceCount = Squadron.ResourceCount } )
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
self.Defenders = self.Defenders or {}
|
||||
local DefenderName = Defender:GetName()
|
||||
@@ -3788,7 +3798,7 @@ do -- AI_A2G_DISPATCHER
|
||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_Fsm:onafterLostControl( DefenderGroup, From, Event, To )
|
||||
self:F({"LostControl", DefenderGroup:GetName()})
|
||||
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
||||
@@ -3805,7 +3815,7 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_Fsm:onafterHome( DefenderGroup, From, Event, To, Action )
|
||||
self:F({"Home", DefenderGroup:GetName()})
|
||||
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
||||
@@ -3886,11 +3896,15 @@ do -- AI_A2G_DISPATCHER
|
||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||
|
||||
if Squadron then
|
||||
local FirstUnit = AttackSetUnit:GetFirst()
|
||||
local FirstUnit = AttackSetUnit:GetRandomSurely()
|
||||
if FirstUnit then
|
||||
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
||||
if self.SetSendPlayerMessages then
|
||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", on route to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
||||
end
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
self:GetParent(self).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
||||
end
|
||||
@@ -3925,7 +3939,7 @@ do -- AI_A2G_DISPATCHER
|
||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_Fsm:onafterLostControl( DefenderGroup, From, Event, To )
|
||||
self:F({"Defender LostControl", DefenderGroup:GetName()})
|
||||
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
||||
@@ -3942,7 +3956,7 @@ do -- AI_A2G_DISPATCHER
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_DISPATCHER self
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_Fsm:onafterHome( DefenderGroup, From, Event, To, Action )
|
||||
self:F({"Defender Home", DefenderGroup:GetName()})
|
||||
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
||||
@@ -4776,4 +4790,5 @@ end
|
||||
Squadron.ResourceCount = Squadron.ResourceCount - Amount
|
||||
end
|
||||
self:T({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- **AI** -- Models the process of air to ground SEAD engagement for airplanes and helicopters.
|
||||
--- **AI** - Models the process of air to ground SEAD engagement for airplanes and helicopters.
|
||||
--
|
||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
||||
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -14,61 +14,45 @@
|
||||
|
||||
|
||||
--- @type AI_A2G_SEAD
|
||||
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL
|
||||
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||
|
||||
|
||||
--- 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 will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- This cycle will continue.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- When enemies are detected, the AI will automatically engage the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## 1. AI_A2G_SEAD constructor
|
||||
--
|
||||
-- * @{#AI_A2G_SEAD.New}(): Creates a new AI_A2G_SEAD object.
|
||||
--
|
||||
-- ## 3. Set the Range of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional range can be set in meters,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_GCI#AI_A2G_SEAD.SetEngageRange}() to define that range.
|
||||
-- Use the method @{#AI_AIR_PATROL.SetEngageRange}() to define that range.
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_Cap#AI_A2G_SEAD.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2G_SEAD
|
||||
@@ -76,8 +60,6 @@ AI_A2G_SEAD = {
|
||||
ClassName = "AI_A2G_SEAD",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Creates a new AI_A2G_SEAD object
|
||||
-- @param #AI_A2G_SEAD self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
@@ -86,7 +68,7 @@ AI_A2G_SEAD = {
|
||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
@@ -96,7 +78,7 @@ AI_A2G_SEAD = {
|
||||
function AI_A2G_SEAD:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
|
||||
local AI_Air = AI_AIR:New( AIGroup )
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
|
||||
local self = BASE:Inherit( self, AI_Air_Engage )
|
||||
|
||||
@@ -111,7 +93,7 @@ end
|
||||
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
@@ -127,7 +109,7 @@ end
|
||||
--- Evaluate the attack and create an AttackUnitTask list.
|
||||
-- @param #AI_A2G_SEAD self
|
||||
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
||||
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
|
||||
-- @param Wrapper.Group#GROUP DefenderGroup The group of defenders.
|
||||
-- @param #number EngageAltitude The altitude to engage the targets.
|
||||
-- @return #AI_A2G_SEAD self
|
||||
function AI_A2G_SEAD:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
-- @module AI.AI_Air
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
--- @type AI_AIR
|
||||
---
|
||||
-- @type AI_AIR
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
|
||||
--- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # 1) AI_AIR constructor
|
||||
--
|
||||
@@ -46,6 +48,11 @@
|
||||
-- * **Stop**: Stop the transport process.
|
||||
-- * **Monitor**: Monitor and take action.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- @field #AI_AIR
|
||||
AI_AIR = {
|
||||
ClassName = "AI_AIR",
|
||||
@@ -259,7 +266,7 @@ function AI_AIR:New( AIGroup )
|
||||
return self
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP self
|
||||
-- @param Wrapper.Group#GROUP self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function GROUP:OnEventTakeoff( EventData, Fsm )
|
||||
Fsm:Takeoff()
|
||||
@@ -374,7 +381,7 @@ end
|
||||
|
||||
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_AIR.
|
||||
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targeted to the AI_AIR.
|
||||
-- Once the time is finished, the old AI will return to the base.
|
||||
-- @param #AI_AIR self
|
||||
-- @param #number FuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
||||
@@ -409,7 +416,7 @@ end
|
||||
|
||||
|
||||
|
||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
||||
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
|
||||
-- @param #AI_AIR self
|
||||
-- @return #AI_AIR self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
@@ -441,13 +448,13 @@ function AI_AIR:onafterReturn( Controllable, From, Event, To )
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param #AI_AIR self
|
||||
function AI_AIR:onbeforeStatus()
|
||||
|
||||
return self.CheckStatus
|
||||
end
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param #AI_AIR self
|
||||
function AI_AIR:onafterStatus()
|
||||
|
||||
if self.Controllable and self.Controllable:IsAlive() then
|
||||
@@ -460,7 +467,7 @@ function AI_AIR:onafterStatus()
|
||||
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
|
||||
|
||||
if DistanceFromHomeBase > self.DisengageRadius then
|
||||
self:I( self.Controllable:GetName() .. " is too far from home base, RTB!" )
|
||||
self:T( self.Controllable:GetName() .. " is too far from home base, RTB!" )
|
||||
self:Hold( 300 )
|
||||
RTB = false
|
||||
end
|
||||
@@ -473,27 +480,27 @@ function AI_AIR:onafterStatus()
|
||||
-- self:Home( "Destroy" )
|
||||
-- end
|
||||
-- end
|
||||
|
||||
|
||||
|
||||
if not self:Is( "Fuel" ) and not self:Is( "Home" ) and not self:is( "Refuelling" )then
|
||||
|
||||
|
||||
local Fuel = self.Controllable:GetFuelMin()
|
||||
|
||||
|
||||
-- If the fuel in the controllable is below the threshold percentage,
|
||||
-- then send for refuel in case of a tanker, otherwise RTB.
|
||||
if Fuel < self.FuelThresholdPercentage then
|
||||
|
||||
|
||||
if self.TankerName then
|
||||
self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
|
||||
self:T( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
|
||||
self:Refuel()
|
||||
else
|
||||
self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
|
||||
self:T( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
|
||||
local OldAIControllable = self.Controllable
|
||||
|
||||
|
||||
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
||||
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.OutOfFuelOrbitTime,nil ) )
|
||||
OldAIControllable:SetTask( TimedOrbitTask, 10 )
|
||||
|
||||
|
||||
self:Fuel()
|
||||
RTB = true
|
||||
end
|
||||
@@ -504,21 +511,21 @@ function AI_AIR:onafterStatus()
|
||||
if self:Is( "Fuel" ) and not self:Is( "Home" ) and not self:is( "Refuelling" ) then
|
||||
RTB = true
|
||||
end
|
||||
|
||||
|
||||
-- TODO: Check GROUP damage function.
|
||||
local Damage = self.Controllable:GetLife()
|
||||
local InitialLife = self.Controllable:GetLife0()
|
||||
|
||||
|
||||
-- If the group is damaged, then RTB.
|
||||
-- Note that a group can consist of more units, so if one unit is damaged of a group, the mission may continue.
|
||||
-- The damaged unit will RTB due to DCS logic, and the others will continue to engage.
|
||||
if ( Damage / InitialLife ) < self.PatrolDamageThreshold then
|
||||
self:I( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" )
|
||||
self:T( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" )
|
||||
self:Damaged()
|
||||
RTB = true
|
||||
self:SetStatusOff()
|
||||
end
|
||||
|
||||
|
||||
-- Check if planes went RTB and are out of control.
|
||||
-- We only check if planes are out of control, when they are in duty.
|
||||
if self.Controllable:HasTask() == false then
|
||||
@@ -531,8 +538,8 @@ function AI_AIR:onafterStatus()
|
||||
if Damage ~= InitialLife then
|
||||
self:Damaged()
|
||||
else
|
||||
self:I( self.Controllable:GetName() .. " control lost! " )
|
||||
|
||||
self:T( self.Controllable:GetName() .. " control lost! " )
|
||||
|
||||
self:LostControl()
|
||||
end
|
||||
else
|
||||
@@ -550,23 +557,23 @@ function AI_AIR:onafterStatus()
|
||||
if not self:Is("Home") then
|
||||
self:__Status( 10 )
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_AIR.RTBRoute( AIGroup, Fsm )
|
||||
|
||||
AIGroup:F( { "AI_AIR.RTBRoute:", AIGroup:GetName() } )
|
||||
|
||||
|
||||
if AIGroup:IsAlive() then
|
||||
Fsm:RTB()
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_AIR.RTBHold( AIGroup, Fsm )
|
||||
|
||||
AIGroup:F( { "AI_AIR.RTBHold:", AIGroup:GetName() } )
|
||||
@@ -576,7 +583,7 @@ function AI_AIR.RTBHold( AIGroup, Fsm )
|
||||
local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
|
||||
AIGroup:SetTask( Task )
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- Set the min and max factors on RTB speed. Use this, if your planes are heading back to base too fast. Default values are 0.5 and 0.6.
|
||||
@@ -593,64 +600,66 @@ function AI_AIR:SetRTBSpeedFactors(MinFactor,MaxFactor)
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param #AI_AIR self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
||||
self:F( { AIGroup, From, Event, To } )
|
||||
|
||||
|
||||
if AIGroup and AIGroup:IsAlive() then
|
||||
if AIGroup and AIGroup:IsAlive() then
|
||||
|
||||
self:T( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
|
||||
|
||||
|
||||
self:ClearTargetDistance()
|
||||
--AIGroup:ClearTasks()
|
||||
|
||||
|
||||
AIGroup:OptionProhibitAfterburner(true)
|
||||
|
||||
|
||||
local EngageRoute = {}
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
|
||||
local FromCoord = AIGroup:GetCoordinate()
|
||||
if not FromCoord then return end
|
||||
|
||||
local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!)
|
||||
|
||||
local ToTargetVec3 = ToTargetCoord:GetVec3()
|
||||
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+3000 -- let's set this 1000m/3000 feet above ground
|
||||
local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 )
|
||||
|
||||
|
||||
if not self.RTBMinSpeed or not self.RTBMaxSpeed then
|
||||
local RTBSpeedMax = AIGroup:GetSpeedMax()
|
||||
local RTBSpeedMaxFactor = self.RTBSpeedMaxFactor or 0.6
|
||||
local RTBSpeedMinFactor = self.RTBSpeedMinFactor or 0.5
|
||||
self:SetRTBSpeed( RTBSpeedMax * RTBSpeedMinFactor, RTBSpeedMax * RTBSpeedMaxFactor)
|
||||
end
|
||||
|
||||
|
||||
local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed )
|
||||
--local ToAirbaseAngle = FromCoord:GetAngleDegrees( FromCoord:GetDirectionVec3( ToTargetCoord2 ) )
|
||||
|
||||
local Distance = FromCoord:Get2DDistance( ToTargetCoord2 )
|
||||
|
||||
|
||||
--local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle )
|
||||
local ToAirbaseCoord = ToTargetCoord2
|
||||
|
||||
|
||||
if Distance < 5000 then
|
||||
self:I( "RTB and near the airbase!" )
|
||||
self:T( "RTB and near the airbase!" )
|
||||
self:Home()
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if not AIGroup:InAir() == true then
|
||||
self:I( "Not anymore in the air, considered Home." )
|
||||
self:T( "Not anymore in the air, considered Home." )
|
||||
self:Home()
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Create a route point of type air.
|
||||
local FromRTBRoutePoint = FromCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
RTBSpeed,
|
||||
true
|
||||
)
|
||||
@@ -658,18 +667,18 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
||||
--- Create a route point of type air.
|
||||
local ToRTBRoutePoint = ToAirbaseCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
RTBSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
EngageRoute[#EngageRoute+1] = FromRTBRoutePoint
|
||||
EngageRoute[#EngageRoute+1] = ToRTBRoutePoint
|
||||
|
||||
|
||||
local Tasks = {}
|
||||
Tasks[#Tasks+1] = AIGroup:TaskFunction( "AI_AIR.RTBRoute", self )
|
||||
|
||||
|
||||
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( Tasks )
|
||||
|
||||
AIGroup:OptionROEHoldFire()
|
||||
@@ -677,17 +686,17 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
||||
|
||||
--- NOW ROUTE THE GROUP!
|
||||
AIGroup:Route( EngageRoute, self.TaskDelay )
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param #AI_AIR self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_AIR:onafterHome( AIGroup, From, Event, To )
|
||||
self:F( { AIGroup, From, Event, To } )
|
||||
|
||||
self:I( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" )
|
||||
self:T( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" )
|
||||
|
||||
if AIGroup and AIGroup:IsAlive() then
|
||||
end
|
||||
@@ -696,15 +705,17 @@ end
|
||||
|
||||
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param #AI_AIR self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_AIR:onafterHold( AIGroup, From, Event, To, HoldTime )
|
||||
self:F( { AIGroup, From, Event, To } )
|
||||
|
||||
self:I( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" )
|
||||
self:T( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" )
|
||||
|
||||
if AIGroup and AIGroup:IsAlive() then
|
||||
local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
||||
local Coordinate = AIGroup:GetCoordinate()
|
||||
if Coordinate == nil then return end
|
||||
local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed, Coordinate )
|
||||
local TimedOrbitTask = AIGroup:TaskControlled( OrbitTask, AIGroup:TaskCondition( nil, nil, nil, nil, HoldTime , nil ) )
|
||||
|
||||
local RTBTask = AIGroup:TaskFunction( "AI_AIR.RTBHold", self )
|
||||
@@ -718,17 +729,17 @@ function AI_AIR:onafterHold( AIGroup, From, Event, To, HoldTime )
|
||||
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_AIR.Resume( AIGroup, Fsm )
|
||||
|
||||
AIGroup:I( { "AI_AIR.Resume:", AIGroup:GetName() } )
|
||||
AIGroup:T( { "AI_AIR.Resume:", AIGroup:GetName() } )
|
||||
if AIGroup:IsAlive() then
|
||||
Fsm:__RTB( Fsm.TaskDelay )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param #AI_AIR self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_AIR:onafterRefuel( AIGroup, From, Event, To )
|
||||
self:F( { AIGroup, From, Event, To } )
|
||||
@@ -740,7 +751,7 @@ function AI_AIR:onafterRefuel( AIGroup, From, Event, To )
|
||||
|
||||
if Tanker and Tanker:IsAlive() and Tanker:IsAirPlane() then
|
||||
|
||||
self:I( "Group " .. self.Controllable:GetName() .. " ... Refuelling! State=" .. self:GetState() .. ", Refuelling tanker " .. self.TankerName )
|
||||
self:T( "Group " .. self.Controllable:GetName() .. " ... Refuelling! State=" .. self:GetState() .. ", Refuelling tanker " .. self.TankerName )
|
||||
|
||||
local RefuelRoute = {}
|
||||
|
||||
@@ -751,10 +762,10 @@ function AI_AIR:onafterRefuel( AIGroup, From, Event, To )
|
||||
local ToRefuelSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||
|
||||
--- 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!
|
||||
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 } )
|
||||
|
||||
@@ -794,13 +805,13 @@ end
|
||||
|
||||
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param #AI_AIR self
|
||||
function AI_AIR:onafterDead()
|
||||
self:SetStatusOff()
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param #AI_AIR self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_AIR:OnCrash( EventData )
|
||||
|
||||
@@ -811,7 +822,7 @@ function AI_AIR:OnCrash( EventData )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param #AI_AIR self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_AIR:OnEjection( EventData )
|
||||
|
||||
@@ -820,7 +831,7 @@ function AI_AIR:OnEjection( EventData )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_AIR self
|
||||
-- @param #AI_AIR self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_AIR:OnPilotDead( EventData )
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** - Create an automated AIR defense system based on a detection network of reconnaissance vehicles and air units, coordinating SEAD, BAI and CAP operations.
|
||||
--- **AI** - Create an automated AIR defense system with reconnaissance units, coordinating SEAD, BAI and CAP operations.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -7,7 +7,7 @@
|
||||
-- * Setup quickly an AIR defense system for a coalition.
|
||||
-- * Setup multiple defense zones to defend specific coordinates in your battlefield.
|
||||
-- * Setup (SEAD) Suppression of Air Defense squadrons, to gain control in the air of enemy grounds.
|
||||
-- * Setup (CAS) Controlled Air Support squadrons, to attack closeby enemy ground units near friendly installations.
|
||||
-- * Setup (CAS) Controlled Air Support squadrons, to attack close by enemy ground units near friendly installations.
|
||||
-- * Setup (BAI) Battleground Air Interdiction squadrons to attack remote enemy ground units and targets.
|
||||
-- * Define and use a detection network controlled by recce.
|
||||
-- * Define AIR defense squadrons at airbases, FARPs and carriers.
|
||||
@@ -24,7 +24,7 @@
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [AID-AIR - AI AIR Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-AIR%20-%20AI%20AIR%20Dispatching)
|
||||
-- [AI_A2A_Dispatcher](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -36,6 +36,8 @@
|
||||
--
|
||||
-- # QUICK START GUIDE
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
@@ -88,7 +90,7 @@
|
||||
--
|
||||
-- ## 4. How do the defenses decide **when and where to engage** on approaching enemy units?
|
||||
--
|
||||
-- The AIR dispacher needs you to setup (various) defense coordinates, which are strategic positions in the battle field to be defended.
|
||||
-- The AIR dispatcher needs you to setup (various) defense coordinates, which are strategic positions in the battle field to be defended.
|
||||
-- Any ground based enemy approaching within the proximity of such a defense point, may trigger for a defensive action by friendly air units.
|
||||
--
|
||||
-- There are 2 important parameters that play a role in the defensive decision making: defensiveness and reactivity.
|
||||
@@ -108,7 +110,7 @@
|
||||
-- ## 5. Are defense coordinates and defense reactivity the only parameters?
|
||||
--
|
||||
-- No, depending on the target type, and the threat level of the target, the probability of defense will be higher.
|
||||
-- In other words, when a SAM-10 radar emitter is detected, its probabilty for defense will be much higher than when a BMP-1 vehicle is
|
||||
-- In other words, when a SAM-10 radar emitter is detected, its probability for defense will be much higher than when a BMP-1 vehicle is
|
||||
-- detected, even when both enemies are at the same distance from a defense coordinate.
|
||||
-- This will ensure optimal defenses, SEAD tasks will be launched much more quicker against engaging radar emitters, to ensure air superiority.
|
||||
-- Approaching main battle tanks will be engaged much faster, than a group of approaching trucks.
|
||||
@@ -117,12 +119,12 @@
|
||||
-- ## 6. Which Squadrons will I create and which name will I give each Squadron?
|
||||
--
|
||||
-- The AIR defense system works with **Squadrons**. Each Squadron must be given a unique name, that forms the **key** to the squadron.
|
||||
-- Several options and activities can be set per Squadron. A free format name can be given, but always ensure that the name is meaningfull
|
||||
-- Several options and activities can be set per Squadron. A free format name can be given, but always ensure that the name is meaningful
|
||||
-- for your mission, and remember that squadron names are used for communication to the players of your mission.
|
||||
--
|
||||
-- There are mainly 3 types of defenses: **SEAD**, **CAS** and **BAI**.
|
||||
--
|
||||
-- Suppression of Air Defenses (SEAD) are effective agains radar emitters. Close Air Support (CAS) is launched when the enemy is close near friendly units.
|
||||
-- Suppression of Air Defenses (SEAD) are effective against radar emitters. Close Air Support (CAS) is launched when the enemy is close near friendly units.
|
||||
-- Battleground Air Interdiction (BAI) tasks are launched when there are no friendlies around.
|
||||
--
|
||||
-- Depending on the defense type, different payloads will be needed. See further points on squadron definition.
|
||||
@@ -174,13 +176,13 @@
|
||||
-- * polygon zones
|
||||
-- * moving zones
|
||||
--
|
||||
-- Depending on the type of zone selected, a different @{Zone} object needs to be created from a ZONE_ class.
|
||||
-- Depending on the type of zone selected, a different @{Core.Zone} object needs to be created from a ZONE_ class.
|
||||
--
|
||||
--
|
||||
-- ## 12. Are moving defense coordinates possible?
|
||||
--
|
||||
-- Yes, different COORDINATE types are possible to be used.
|
||||
-- The COORDINATE_UNIT will help you to specify a defense coodinate that is attached to a moving unit.
|
||||
-- The COORDINATE_UNIT will help you to specify a defense coordinate that is attached to a moving unit.
|
||||
--
|
||||
--
|
||||
-- ## 13. How much defense coordinates do I need to create?
|
||||
@@ -214,7 +216,7 @@
|
||||
-- * From a parking spot with running engines
|
||||
-- * From a parking spot with cold engines
|
||||
--
|
||||
-- **The default takeoff method is staight in the air.**
|
||||
-- **The default takeoff method is straight in the air.**
|
||||
-- This takeoff method is the most useful if you want to avoid airplane clutter at airbases!
|
||||
-- But it is the least realistic one!
|
||||
--
|
||||
@@ -236,10 +238,10 @@
|
||||
--
|
||||
-- For each Squadron, depending on the helicopter or airplane type (modern, old) and payload, which overhead is required to provide any defense?
|
||||
--
|
||||
-- In other words, if **X** enemy ground units are detected, how many **Y** defense helicpters or airplanes need to engage (per squadron)?
|
||||
-- In other words, if **X** enemy ground units are detected, how many **Y** defense helicopters or airplanes need to engage (per squadron)?
|
||||
-- The **Y** is dependent on the type of airplane (era), payload, fuel levels, skills etc.
|
||||
-- But the most important factor is the payload, which is the amount of AIR weapons the defense can carry to attack the enemy ground units.
|
||||
-- For example, a Ka-50 can carry 16 vikrs, that means, that it potentially can destroy at least 8 ground units without a reload of ammunication.
|
||||
-- For example, a Ka-50 can carry 16 vikrs, that means, that it potentially can destroy at least 8 ground units without a reload of ammunition.
|
||||
-- That means, that one defender can destroy more enemy ground units.
|
||||
-- Thus, the overhead is a **factor** that will calculate dynamically how many **Y** defenses will be required based on **X** attackers detected.
|
||||
--
|
||||
@@ -259,7 +261,7 @@
|
||||
--
|
||||
-- ### Author: **FlightControl** rework of GCICAP + introduction of new concepts (squadrons).
|
||||
--
|
||||
-- @module AI.AI_AIR_Dispatcher
|
||||
-- @module AI.AI_Air_Dispatcher
|
||||
-- @image AI_Air_To_Ground_Dispatching.JPG
|
||||
|
||||
|
||||
@@ -279,7 +281,7 @@ do -- AI_AIR_DISPATCHER
|
||||
-- Multiple defense coordinates can be setup. Defense coordinates can be strategic or tactical positions or references to strategic units or scenery.
|
||||
-- The AIR dispatcher will evaluate every x seconds the tactical situation around each defense coordinate. When a defense coordinate
|
||||
-- is under threat, it will communicate through the command center that defensive actions need to be taken and will launch groups of air units for defense.
|
||||
-- The level of threat to the defense coordinate varyies upon the strength and types of the enemy units, the distance to the defense point, and the defensiveness parameters.
|
||||
-- The level of threat to the defense coordinate varies upon the strength and types of the enemy units, the distance to the defense point, and the defensiveness parameters.
|
||||
-- Defensive actions are taken through probability, but the closer and the more threat the enemy poses to the defense coordinate, the faster it will be attacked by friendly AIR units.
|
||||
--
|
||||
-- Please study carefully the underlying explanations how to setup and use this module, as it has many features.
|
||||
@@ -292,8 +294,6 @@ do -- AI_AIR_DISPATCHER
|
||||
--
|
||||
-- ## 1. AI\_AIR\_DISPATCHER constructor:
|
||||
--
|
||||
-- 
|
||||
--
|
||||
--
|
||||
-- The @{#AI_AIR_DISPATCHER.New}() method creates a new AI_AIR_DISPATCHER instance.
|
||||
--
|
||||
@@ -306,8 +306,6 @@ do -- AI_AIR_DISPATCHER
|
||||
-- A reconnaissance network, is used to detect enemy ground targets,
|
||||
-- potentially group them into areas, and to understand the position, level of threat of the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- As explained in the introduction, depending on the type of mission you want to achieve, different types of units can be applied to detect ground enemy targets.
|
||||
-- Ground based units are very useful to act as a reconnaissance, but they lack sometimes the visibility to detect targets at greater range.
|
||||
-- Recce are very useful to acquire the position of enemy ground targets when spread out over the battlefield at strategic positions.
|
||||
@@ -328,7 +326,7 @@ do -- AI_AIR_DISPATCHER
|
||||
-- By spawning in dynamically additional recce, you can ensure that there is sufficient reconnaissance coverage so the defense mechanism is continuously
|
||||
-- alerted of new enemy ground targets.
|
||||
--
|
||||
-- The following example defens a new reconnaissance network using a @{Functional.Detection#DETECTION_AREAS} object.
|
||||
-- The following example defense a new reconnaissance network using a @{Functional.Detection#DETECTION_AREAS} object.
|
||||
--
|
||||
-- -- Define a SET_GROUP object that builds a collection of groups that define the recce network.
|
||||
-- -- Here we build the network with all the groups that have a name starting with CCCP Recce.
|
||||
@@ -473,7 +471,7 @@ do -- AI_AIR_DISPATCHER
|
||||
-- the mission designer can choose to increase or reduce the amount of planes spawned.
|
||||
--
|
||||
-- The method @{#AI_AIR_DISPATCHER.SetSquadron}() defines for you a new squadron.
|
||||
-- The provided parameters are the squadron name, airbase name and a list of template prefixe, and a number that indicates the amount of resources.
|
||||
-- The provided parameters are the squadron name, airbase name and a list of template prefixes, and a number that indicates the amount of resources.
|
||||
--
|
||||
-- For example, this defines 3 new squadrons:
|
||||
--
|
||||
@@ -619,7 +617,7 @@ do -- AI_AIR_DISPATCHER
|
||||
-- Depending on the demand of requested takeoffs by the AIR dispatcher, an airfield can become overloaded. Too many aircraft need to be taken
|
||||
-- off at the same time, which will result in clutter as described above. In order to better control this behaviour, a takeoff scheduler is implemented,
|
||||
-- which can be used to control how many aircraft are ordered for takeoff between specific time intervals.
|
||||
-- The takeff intervals can be specified per squadron, which make sense, as each squadron have a "home" airfield.
|
||||
-- The takeoff intervals can be specified per squadron, which make sense, as each squadron have a "home" airfield.
|
||||
--
|
||||
-- For this purpose, the method @{#AI_AIR_DISPATCHER.SetSquadronTakeOffInterval}() can be used to specify the takeoff intervals of
|
||||
-- aircraft groups per squadron to avoid cluttering of aircraft at airbases.
|
||||
@@ -673,8 +671,6 @@ do -- AI_AIR_DISPATCHER
|
||||
--
|
||||
-- Use the method @{#AI_AIR_DISPATCHER.SetSquadronGrouping}() to set the grouping of aircraft when spawned in.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- In the case of **on call** engagement, the @{#AI_AIR_DISPATCHER.SetSquadronGrouping}() method has additional behaviour.
|
||||
-- When there aren't enough patrol flights airborne, a on call will be initiated for the remaining
|
||||
-- targets to be engaged. Depending on the grouping parameter, the spawned flights for on call aircraft are grouped into this setting.
|
||||
@@ -688,8 +684,6 @@ do -- AI_AIR_DISPATCHER
|
||||
-- The effectiveness can be set with the **overhead parameter**. This is a number that is used to calculate the amount of Units that dispatching command will allocate to GCI in surplus of detected amount of units.
|
||||
-- The **default value** of the overhead parameter is 1.0, which means **equal balance**.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- However, depending on the (type of) aircraft (strength and payload) in the squadron and the amount of resources available, this parameter can be changed.
|
||||
--
|
||||
-- The @{#AI_AIR_DISPATCHER.SetSquadronOverhead}() method can be used to tweak the defense strength,
|
||||
@@ -835,8 +829,6 @@ do -- AI_AIR_DISPATCHER
|
||||
--
|
||||
-- For example, the following setup will set the default refuel tanker to "Tanker":
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- -- Define the CAP
|
||||
-- A2ADispatcher:SetSquadron( "Sochi", AIRBASE.Caucasus.Sochi_Adler, { "SQ CCCP SU-34" }, 20 )
|
||||
-- A2ADispatcher:SetSquadronCap( "Sochi", ZONE:New( "PatrolZone" ), 4000, 8000, 600, 800, 1000, 1300 )
|
||||
@@ -883,6 +875,11 @@ do -- AI_AIR_DISPATCHER
|
||||
-- However, the squadron will still stay alive. Any airplane that is airborne will continue its operations until all airborne airplanes
|
||||
-- of the squadron will be destroyed. This to keep consistency of air operations not to confuse the players.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- @field #AI_AIR_DISPATCHER
|
||||
AI_AIR_DISPATCHER = {
|
||||
ClassName = "AI_AIR_DISPATCHER",
|
||||
@@ -905,14 +902,14 @@ do -- AI_AIR_DISPATCHER
|
||||
-- @type AI_AIR_DISPATCHER.DefenseCoordinates
|
||||
-- @map <#string,Core.Point#COORDINATE> A list of all defense coordinates mapped per defense coordinate name.
|
||||
|
||||
--- @field #AI_AIR_DISPATCHER.DefenseCoordinates DefenseCoordinates
|
||||
-- @field #AI_AIR_DISPATCHER.DefenseCoordinates DefenseCoordinates
|
||||
AI_AIR_DISPATCHER.DefenseCoordinates = {}
|
||||
|
||||
--- Enumerator for spawns at airbases
|
||||
-- @type AI_AIR_DISPATCHER.Takeoff
|
||||
-- @extends Wrapper.Group#GROUP.Takeoff
|
||||
|
||||
--- @field #AI_AIR_DISPATCHER.Takeoff Takeoff
|
||||
-- @field #AI_AIR_DISPATCHER.Takeoff Takeoff
|
||||
AI_AIR_DISPATCHER.Takeoff = GROUP.Takeoff
|
||||
|
||||
--- Defnes Landing location.
|
||||
@@ -943,11 +940,11 @@ do -- AI_AIR_DISPATCHER
|
||||
-- @type AI_AIR_DISPATCHER.DefenseQueue
|
||||
-- @list<#AI_AIR_DISPATCHER.DefenseQueueItem> DefenseQueueItem A list of all defenses being queued ...
|
||||
|
||||
--- @field #AI_AIR_DISPATCHER.DefenseQueue DefenseQueue
|
||||
-- @field #AI_AIR_DISPATCHER.DefenseQueue DefenseQueue
|
||||
AI_AIR_DISPATCHER.DefenseQueue = {}
|
||||
|
||||
--- Defense approach types
|
||||
-- @type #AI_AIR_DISPATCHER.DefenseApproach
|
||||
-- @type AI_AIR_DISPATCHER.DefenseApproach
|
||||
AI_AIR_DISPATCHER.DefenseApproach = {
|
||||
Random = 1,
|
||||
Distance = 2,
|
||||
@@ -1021,7 +1018,7 @@ do -- AI_AIR_DISPATCHER
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @param Tasking.Task_AIR#AI_AIR Task
|
||||
-- @param AI.AI_Air#AI_AIR Task
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param #string PlayerName
|
||||
|
||||
@@ -1135,7 +1132,7 @@ do -- AI_AIR_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
function AI_AIR_DISPATCHER:onafterStart( From, Event, To )
|
||||
|
||||
self:GetParent( self ).onafterStart( self, From, Event, To )
|
||||
@@ -1146,7 +1143,7 @@ do -- AI_AIR_DISPATCHER
|
||||
for Resource = 1, DefenderSquadron.ResourceCount or 0 do
|
||||
self:ResourcePark( DefenderSquadron )
|
||||
end
|
||||
self:I( "Parked resources for squadron " .. DefenderSquadron.Name )
|
||||
self:T( "Parked resources for squadron " .. DefenderSquadron.Name )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1199,7 +1196,7 @@ do -- AI_AIR_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
function AI_AIR_DISPATCHER:ResourcePark( DefenderSquadron )
|
||||
local TemplateID = math.random( 1, #DefenderSquadron.Spawn )
|
||||
local Spawn = DefenderSquadron.Spawn[ TemplateID ] -- Core.Spawn#SPAWN
|
||||
@@ -1216,31 +1213,31 @@ do -- AI_AIR_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_AIR_DISPATCHER:OnEventBaseCaptured( EventData )
|
||||
|
||||
local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured.
|
||||
|
||||
self:I( "Captured " .. AirbaseName )
|
||||
self:T( "Captured " .. AirbaseName )
|
||||
|
||||
-- Now search for all squadrons located at the airbase, and sanatize them.
|
||||
-- Now search for all squadrons located at the airbase, and sanitize them.
|
||||
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
||||
if Squadron.AirbaseName == AirbaseName then
|
||||
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
||||
Squadron.Captured = true
|
||||
self:I( "Squadron " .. SquadronName .. " captured." )
|
||||
self:T( "Squadron " .. SquadronName .. " captured." )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_AIR_DISPATCHER:OnEventCrashOrDead( EventData )
|
||||
self.Detection:ForgetDetectedUnit( EventData.IniUnitName )
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_AIR_DISPATCHER:OnEventLand( EventData )
|
||||
self:F( "Landed" )
|
||||
@@ -1257,7 +1254,7 @@ do -- AI_AIR_DISPATCHER
|
||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
end
|
||||
DefenderUnit:Destroy()
|
||||
self:ResourcePark( Squadron, Defender )
|
||||
self:ResourcePark( Squadron )
|
||||
return
|
||||
end
|
||||
if DefenderUnit:GetLife() ~= DefenderUnit:GetLife0() then
|
||||
@@ -1268,7 +1265,7 @@ do -- AI_AIR_DISPATCHER
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_AIR_DISPATCHER:OnEventEngineShutdown( EventData )
|
||||
local DefenderUnit = EventData.IniUnit
|
||||
@@ -1284,31 +1281,31 @@ do -- AI_AIR_DISPATCHER
|
||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
end
|
||||
DefenderUnit:Destroy()
|
||||
self:ResourcePark( Squadron, Defender )
|
||||
self:ResourcePark( Squadron )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do -- Manage the defensive behaviour
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #string DefenseCoordinateName The name of the coordinate to be defended by AIR defenses.
|
||||
-- @param Core.Point#COORDINATE DefenseCoordinate The coordinate to be defended by AIR defenses.
|
||||
function AI_AIR_DISPATCHER:AddDefenseCoordinate( DefenseCoordinateName, DefenseCoordinate )
|
||||
self.DefenseCoordinates[DefenseCoordinateName] = DefenseCoordinate
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
function AI_AIR_DISPATCHER:SetDefenseReactivityLow()
|
||||
self.DefenseReactivity = 0.05
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
function AI_AIR_DISPATCHER:SetDefenseReactivityMedium()
|
||||
self.DefenseReactivity = 0.15
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
function AI_AIR_DISPATCHER:SetDefenseReactivityHigh()
|
||||
self.DefenseReactivity = 0.5
|
||||
end
|
||||
@@ -1376,7 +1373,7 @@ do -- AI_AIR_DISPATCHER
|
||||
--- Define a border area to simulate a **cold war** scenario.
|
||||
-- A **cold war** is one where Patrol aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
||||
-- A **hot war** is one where Patrol aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send Patrol and GCI aircraft to attack it.
|
||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
||||
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
|
||||
@@ -1796,12 +1793,12 @@ do -- AI_AIR_DISPATCHER
|
||||
--
|
||||
-- @return #AI_AIR_DISPATCHER
|
||||
function AI_AIR_DISPATCHER:SetSquadron2( Squadron )
|
||||
|
||||
|
||||
local SquadronName = Squadron:GetName() -- Retrieves the Squadron Name.
|
||||
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||
|
||||
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1812,15 +1809,15 @@ do -- AI_AIR_DISPATCHER
|
||||
function AI_AIR_DISPATCHER:GetSquadron( SquadronName )
|
||||
|
||||
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
|
||||
|
||||
|
||||
if not DefenderSquadron then
|
||||
error( "Unknown Squadron for Dispatcher:" .. SquadronName )
|
||||
end
|
||||
|
||||
|
||||
return DefenderSquadron
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Set the Squadron visible before startup of the dispatcher.
|
||||
-- All planes will be spawned as uncontrolled on the parking spot.
|
||||
-- They will lock the parking spot.
|
||||
@@ -1852,7 +1849,7 @@ do -- AI_AIR_DISPATCHER
|
||||
--- Check if the Squadron is visible before startup of the dispatcher.
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @return #bool true if visible.
|
||||
-- @return #boolean true if visible.
|
||||
-- @usage
|
||||
--
|
||||
-- -- Set the Squadron visible before startup of dispatcher.
|
||||
@@ -1872,7 +1869,7 @@ do -- AI_AIR_DISPATCHER
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #string SquadronName The squadron name.
|
||||
-- @param #number TakeoffInterval Only Takeoff new units each specified interval in seconds in 10 seconds steps.
|
||||
-- @usage
|
||||
@@ -2774,7 +2771,7 @@ do -- AI_AIR_DISPATCHER
|
||||
|
||||
-- TODO: Need to model the resources in a squadron.
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param AI.AI_Air_Squadron#AI_AIR_SQUADRON Squadron
|
||||
function AI_AIR_DISPATCHER:AddDefenderToSquadron( Squadron, Defender, Size )
|
||||
self.Defenders = self.Defenders or {}
|
||||
@@ -2787,7 +2784,7 @@ do -- AI_AIR_DISPATCHER
|
||||
self:F( { DefenderName = DefenderName, SquadronResourceCount = Squadron.ResourceCount } )
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param AI.AI_Air_Squadron#AI_AIR_SQUADRON Squadron
|
||||
function AI_AIR_DISPATCHER:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||
self.Defenders = self.Defenders or {}
|
||||
@@ -2800,7 +2797,7 @@ do -- AI_AIR_DISPATCHER
|
||||
self:F( { DefenderName = DefenderName, SquadronResourceCount = SquadronResourceCount } )
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_DISPATCHER self
|
||||
-- @param #AI_AIR_DISPATCHER self
|
||||
-- @param Wrapper.Group#GROUP Defender
|
||||
-- @return AI.AI_Air_Squadron#AI_AIR_SQUADRON The Squadron.
|
||||
function AI_AIR_DISPATCHER:GetSquadronFromDefender( Defender )
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- **AI** -- Models the process of air to ground engagement for airplanes and helicopters.
|
||||
--- **AI** - Models the process of air to ground engagement for airplanes and helicopters.
|
||||
--
|
||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
||||
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -19,56 +19,42 @@
|
||||
|
||||
--- 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 will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- This cycle will continue.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- When enemies are detected, the AI will automatically engage the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## 1. AI_AIR_ENGAGE constructor
|
||||
--
|
||||
-- * @{#AI_AIR_ENGAGE.New}(): Creates a new AI_AIR_ENGAGE object.
|
||||
--
|
||||
-- ## 3. Set the Range of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional range can be set in meters,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_GCI#AI_AIR_ENGAGE.SetEngageRange}() to define that range.
|
||||
-- ## 2. Set the Zone of Engagement
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Zone} can be set,
|
||||
-- An optional @{Core.Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_Cap#AI_AIR_ENGAGE.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- Use the method @{AI.AI_CAP#AI_AIR_ENGAGE.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_AIR_ENGAGE
|
||||
@@ -367,7 +353,7 @@ function AI_AIR_ENGAGE:onafterAbort( AIGroup, From, Event, To )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_AIR_ENGAGE self
|
||||
-- @param #AI_AIR_ENGAGE self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
@@ -377,7 +363,7 @@ function AI_AIR_ENGAGE:onafterAccomplish( AIGroup, From, Event, To )
|
||||
--self:SetDetectionOff()
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_ENGAGE self
|
||||
-- @param #AI_AIR_ENGAGE self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
@@ -390,7 +376,7 @@ function AI_AIR_ENGAGE:onafterDestroy( AIGroup, From, Event, To, EventData )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_AIR_ENGAGE self
|
||||
-- @param #AI_AIR_ENGAGE self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_AIR_ENGAGE:OnEventDead( EventData )
|
||||
self:F( { "EventDead", EventData } )
|
||||
@@ -403,9 +389,9 @@ function AI_AIR_ENGAGE:OnEventDead( EventData )
|
||||
end
|
||||
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIControllable
|
||||
-- @param Wrapper.Group#GROUP AIControllable
|
||||
function AI_AIR_ENGAGE.___EngageRoute( AIGroup, Fsm, AttackSetUnit )
|
||||
Fsm:I(string.format("AI_AIR_ENGAGE.___EngageRoute: %s", tostring(AIGroup:GetName())))
|
||||
Fsm:T(string.format("AI_AIR_ENGAGE.___EngageRoute: %s", tostring(AIGroup:GetName())))
|
||||
|
||||
if AIGroup and AIGroup:IsAlive() then
|
||||
Fsm:__EngageRoute( Fsm.TaskDelay or 0.1, AttackSetUnit )
|
||||
@@ -413,14 +399,14 @@ function AI_AIR_ENGAGE.___EngageRoute( AIGroup, Fsm, AttackSetUnit )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_AIR_ENGAGE self
|
||||
-- @param #AI_AIR_ENGAGE self
|
||||
-- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @param Core.Set#SET_UNIT AttackSetUnit Unit set to be attacked.
|
||||
function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit )
|
||||
self:I( { DefenderGroup, From, Event, To, AttackSetUnit } )
|
||||
self:T( { DefenderGroup, From, Event, To, AttackSetUnit } )
|
||||
|
||||
local DefenderGroupName = DefenderGroup:GetName()
|
||||
|
||||
@@ -442,7 +428,13 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
||||
local DefenderCoord = DefenderGroup:GetPointVec3()
|
||||
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
||||
|
||||
local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3()
|
||||
local TargetCoord = AttackSetUnit:GetRandomSurely():GetPointVec3()
|
||||
|
||||
if TargetCoord == nil then
|
||||
self:Return()
|
||||
return
|
||||
end
|
||||
|
||||
TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
||||
|
||||
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
|
||||
@@ -451,19 +443,19 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
||||
-- TODO: A factor of * 3 is way too close. This causes the AI not to engange until merged sometimes!
|
||||
if TargetDistance <= EngageDistance * 9 then
|
||||
|
||||
self:I(string.format("AI_AIR_ENGAGE onafterEngageRoute ==> __Engage - target distance = %.1f km", TargetDistance/1000))
|
||||
--self:T(string.format("AI_AIR_ENGAGE onafterEngageRoute ==> __Engage - target distance = %.1f km", TargetDistance/1000))
|
||||
self:__Engage( 0.1, AttackSetUnit )
|
||||
|
||||
else
|
||||
|
||||
self:I(string.format("FF AI_AIR_ENGAGE onafterEngageRoute ==> Routing - target distance = %.1f km", TargetDistance/1000))
|
||||
--self:T(string.format("FF AI_AIR_ENGAGE onafterEngageRoute ==> Routing - target distance = %.1f km", TargetDistance/1000))
|
||||
|
||||
local EngageRoute = {}
|
||||
local AttackTasks = {}
|
||||
|
||||
--- 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
|
||||
|
||||
@@ -472,7 +464,7 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
||||
local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) )
|
||||
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
|
||||
|
||||
@@ -488,16 +480,16 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
||||
end
|
||||
else
|
||||
-- TODO: This will make an A2A Dispatcher CAP flight to return rather than going back to patrolling!
|
||||
self:I( DefenderGroupName .. ": No targets found -> Going RTB")
|
||||
self:T( DefenderGroupName .. ": No targets found -> Going RTB")
|
||||
self:Return()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIControllable
|
||||
-- @param Wrapper.Group#GROUP AIControllable
|
||||
function AI_AIR_ENGAGE.___Engage( AIGroup, Fsm, AttackSetUnit )
|
||||
|
||||
Fsm:I(string.format("AI_AIR_ENGAGE.___Engage: %s", tostring(AIGroup:GetName())))
|
||||
Fsm:T(string.format("AI_AIR_ENGAGE.___Engage: %s", tostring(AIGroup:GetName())))
|
||||
|
||||
if AIGroup and AIGroup:IsAlive() then
|
||||
local delay=Fsm.TaskDelay or 0.1
|
||||
@@ -506,7 +498,7 @@ function AI_AIR_ENGAGE.___Engage( AIGroup, Fsm, AttackSetUnit )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_AIR_ENGAGE self
|
||||
-- @param #AI_AIR_ENGAGE self
|
||||
-- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
@@ -532,7 +524,7 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
||||
local DefenderCoord = DefenderGroup:GetPointVec3()
|
||||
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
||||
|
||||
local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3()
|
||||
local TargetCoord = AttackSetUnit:GetRandomSurely():GetPointVec3()
|
||||
if not TargetCoord then
|
||||
self:Return()
|
||||
return
|
||||
@@ -546,7 +538,7 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
||||
local EngageRoute = {}
|
||||
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
|
||||
|
||||
self:SetTargetDistance( TargetCoord ) -- For RTB status check
|
||||
@@ -554,7 +546,7 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
||||
local FromEngageAngle = DefenderCoord:GetAngleDegrees( DefenderCoord:GetDirectionVec3( TargetCoord ) )
|
||||
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
|
||||
|
||||
-- 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!
|
||||
@@ -563,12 +555,12 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
||||
local AttackUnitTasks = self:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude ) -- Polymorphic
|
||||
|
||||
if #AttackUnitTasks == 0 then
|
||||
self:I( DefenderGroupName .. ": No valid targets found -> Going RTB")
|
||||
self:T( DefenderGroupName .. ": No valid targets found -> Going RTB")
|
||||
self:Return()
|
||||
return
|
||||
else
|
||||
local text=string.format("%s: Engaging targets at distance %.2f NM", DefenderGroupName, UTILS.MetersToNM(TargetDistance))
|
||||
self:I(text)
|
||||
self:T(text)
|
||||
DefenderGroup:OptionROEOpenFire()
|
||||
DefenderGroup:OptionROTEvadeFire()
|
||||
DefenderGroup:OptionKeepWeaponsOnThreat()
|
||||
@@ -585,13 +577,13 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
||||
end
|
||||
else
|
||||
-- TODO: This will make an A2A Dispatcher CAP flight to return rather than going back to patrolling!
|
||||
self:I( DefenderGroupName .. ": No targets found -> returning.")
|
||||
self:T( DefenderGroupName .. ": No targets found -> returning.")
|
||||
self:Return()
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIEngage
|
||||
-- @param Wrapper.Group#GROUP AIEngage
|
||||
function AI_AIR_ENGAGE.Resume( AIEngage, Fsm )
|
||||
|
||||
AIEngage:F( { "Resume:", AIEngage:GetName() } )
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- Models the process of A2G patrolling and engaging ground targets for airplanes and helicopters.
|
||||
--- **AI** - Models the process of A2G patrolling and engaging ground targets for airplanes and helicopters.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -12,10 +12,11 @@
|
||||
--- @type AI_AIR_PATROL
|
||||
-- @extends AI.AI_Air#AI_AIR
|
||||
|
||||
|
||||
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
@@ -80,16 +81,13 @@
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_CAP#AI_AIR_PATROL.SetEngageRange}() to define that range.
|
||||
-- Use the method @{#AI_AIR_PATROL.SetEngageRange}() to define that range.
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_Cap#AI_AIR_PATROL.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_AIR_PATROL
|
||||
@@ -101,7 +99,7 @@ AI_AIR_PATROL = {
|
||||
-- @param #AI_AIR_PATROL self
|
||||
-- @param AI.AI_Air#AI_AIR AI_Air The AI_AIR FSM.
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AI group.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed of the @{Wrapper.Group} in km/h.
|
||||
@@ -114,17 +112,17 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
||||
local self = BASE:Inherit( self, AI_Air ) -- #AI_AIR_PATROL
|
||||
|
||||
local SpeedMax = AIGroup:GetSpeedMax()
|
||||
|
||||
|
||||
self.PatrolZone = PatrolZone
|
||||
|
||||
|
||||
self.PatrolFloorAltitude = PatrolFloorAltitude or 1000
|
||||
self.PatrolCeilingAltitude = PatrolCeilingAltitude or 1500
|
||||
self.PatrolMinSpeed = PatrolMinSpeed or SpeedMax * 0.5
|
||||
self.PatrolMaxSpeed = PatrolMaxSpeed or SpeedMax * 0.75
|
||||
|
||||
|
||||
-- defafult PatrolAltType to "RADIO" if not specified
|
||||
self.PatrolAltType = PatrolAltType or "RADIO"
|
||||
|
||||
|
||||
self:AddTransition( { "Started", "Airborne", "Refuelling" }, "Patrol", "Patrolling" )
|
||||
|
||||
--- OnBefore Transition Handler for Event Patrol.
|
||||
@@ -135,7 +133,7 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
|
||||
--- OnAfter Transition Handler for Event Patrol.
|
||||
-- @function [parent=#AI_AIR_PATROL] OnAfterPatrol
|
||||
-- @param #AI_AIR_PATROL self
|
||||
@@ -143,16 +141,16 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event Patrol.
|
||||
-- @function [parent=#AI_AIR_PATROL] Patrol
|
||||
-- @param #AI_AIR_PATROL self
|
||||
|
||||
|
||||
--- Asynchronous Event Trigger for Event Patrol.
|
||||
-- @function [parent=#AI_AIR_PATROL] __Patrol
|
||||
-- @param #AI_AIR_PATROL self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
|
||||
--- OnLeave Transition Handler for State Patrolling.
|
||||
-- @function [parent=#AI_AIR_PATROL] OnLeavePatrolling
|
||||
-- @param #AI_AIR_PATROL self
|
||||
@@ -161,7 +159,7 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
|
||||
--- OnEnter Transition Handler for State Patrolling.
|
||||
-- @function [parent=#AI_AIR_PATROL] OnEnterPatrolling
|
||||
-- @param #AI_AIR_PATROL self
|
||||
@@ -169,9 +167,9 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
self:AddTransition( "Patrolling", "PatrolRoute", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_PATROL.
|
||||
|
||||
|
||||
--- OnBefore Transition Handler for Event PatrolRoute.
|
||||
-- @function [parent=#AI_AIR_PATROL] OnBeforePatrolRoute
|
||||
-- @param #AI_AIR_PATROL self
|
||||
@@ -180,7 +178,7 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
|
||||
--- OnAfter Transition Handler for Event PatrolRoute.
|
||||
-- @function [parent=#AI_AIR_PATROL] OnAfterPatrolRoute
|
||||
-- @param #AI_AIR_PATROL self
|
||||
@@ -188,23 +186,21 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event PatrolRoute.
|
||||
-- @function [parent=#AI_AIR_PATROL] PatrolRoute
|
||||
-- @param #AI_AIR_PATROL self
|
||||
|
||||
|
||||
--- Asynchronous Event Trigger for Event PatrolRoute.
|
||||
-- @function [parent=#AI_AIR_PATROL] __PatrolRoute
|
||||
-- @param #AI_AIR_PATROL self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
|
||||
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_PATROL.
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the Engage Range when the AI will engage with airborne enemies.
|
||||
-- @param #AI_AIR_PATROL self
|
||||
-- @param #number EngageRange The Engage Range.
|
||||
@@ -230,7 +226,7 @@ end
|
||||
-- @param #table CapCoordinates Table of coordinates of first race track point. Second point is determined by leg length and heading.
|
||||
-- @return #AI_AIR_PATROL self
|
||||
function AI_AIR_PATROL:SetRaceTrackPattern(LegMin, LegMax, HeadingMin, HeadingMax, DurationMin, DurationMax, CapCoordinates)
|
||||
|
||||
|
||||
self.racetrack=true
|
||||
self.racetracklegmin=LegMin or 10000
|
||||
self.racetracklegmax=LegMax or 15000
|
||||
@@ -238,18 +234,16 @@ function AI_AIR_PATROL:SetRaceTrackPattern(LegMin, LegMax, HeadingMin, HeadingMa
|
||||
self.racetrackheadingmax=HeadingMax or 180
|
||||
self.racetrackdurationmin=DurationMin
|
||||
self.racetrackdurationmax=DurationMax
|
||||
|
||||
|
||||
if self.racetrackdurationmax and not self.racetrackdurationmin then
|
||||
self.racetrackdurationmin=self.racetrackdurationmax
|
||||
end
|
||||
|
||||
|
||||
self.racetrackcapcoordinates=CapCoordinates
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
||||
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
|
||||
-- @param #AI_AIR_PATROL self
|
||||
-- @return #AI_AIR_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
@@ -262,7 +256,7 @@ function AI_AIR_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
||||
self:ClearTargetDistance()
|
||||
|
||||
self:__PatrolRoute( self.TaskDelay )
|
||||
|
||||
|
||||
AIPatrol:OnReSpawn(
|
||||
function( PatrolGroup )
|
||||
self:__Reset( self.TaskDelay )
|
||||
@@ -271,7 +265,7 @@ function AI_AIR_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
||||
)
|
||||
end
|
||||
|
||||
--- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
|
||||
--- This static method is called from the route path within the last task at the last waypoint of the AIPatrol.
|
||||
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The AI group.
|
||||
-- @param #AI_AIR_PATROL Fsm The FSM.
|
||||
@@ -282,10 +276,10 @@ function AI_AIR_PATROL.___PatrolRoute( AIPatrol, Fsm )
|
||||
if AIPatrol and AIPatrol:IsAlive() then
|
||||
Fsm:PatrolRoute()
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
||||
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
|
||||
-- @param #AI_AIR_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
@@ -300,53 +294,52 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if AIPatrol and AIPatrol:IsAlive() then
|
||||
|
||||
|
||||
local PatrolRoute = {}
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
|
||||
local CurrentCoord = AIPatrol:GetCoordinate()
|
||||
|
||||
|
||||
local altitude= math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude )
|
||||
|
||||
|
||||
local ToTargetCoord = self.PatrolZone:GetRandomPointVec2()
|
||||
ToTargetCoord:SetAlt( altitude )
|
||||
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
|
||||
|
||||
|
||||
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||
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
|
||||
|
||||
if self.racetrack then
|
||||
|
||||
|
||||
-- Random heading.
|
||||
local heading = math.random(self.racetrackheadingmin, self.racetrackheadingmax)
|
||||
|
||||
|
||||
-- Random leg length.
|
||||
local leg=math.random(self.racetracklegmin, self.racetracklegmax)
|
||||
|
||||
|
||||
-- Random duration if any.
|
||||
local duration = self.racetrackdurationmin
|
||||
if self.racetrackdurationmax then
|
||||
duration=math.random(self.racetrackdurationmin, self.racetrackdurationmax)
|
||||
end
|
||||
|
||||
|
||||
-- CAP coordinate.
|
||||
local c0=self.PatrolZone:GetRandomCoordinate()
|
||||
if self.racetrackcapcoordinates and #self.racetrackcapcoordinates>0 then
|
||||
c0=self.racetrackcapcoordinates[math.random(#self.racetrackcapcoordinates)]
|
||||
end
|
||||
|
||||
|
||||
-- Race track points.
|
||||
local c1=c0:SetAltitude(altitude) --Core.Point#COORDINATE
|
||||
local c2=c1:Translate(leg, heading):SetAltitude(altitude)
|
||||
|
||||
|
||||
self:SetTargetDistance(c0) -- For RTB status check
|
||||
|
||||
|
||||
-- Debug:
|
||||
self:T(string.format("Patrol zone race track: v=%.1f knots, h=%.1f ft, heading=%03d, leg=%d m, t=%s sec", UTILS.KmphToKnots(speedkmh), UTILS.MetersToFeet(altitude), heading, leg, tostring(duration)))
|
||||
--c1:MarkToAll("Race track c1")
|
||||
@@ -354,39 +347,41 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
||||
|
||||
-- Task to orbit.
|
||||
local taskOrbit=AIPatrol:TaskOrbit(c1, altitude, UTILS.KmphToMps(speedkmh), c2)
|
||||
|
||||
|
||||
-- Task function to redo the patrol at other random position.
|
||||
local taskPatrol=AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
||||
|
||||
|
||||
-- Controlled task with task condition.
|
||||
local taskCond=AIPatrol:TaskCondition(nil, nil, nil, nil, duration, nil)
|
||||
local taskCont=AIPatrol:TaskControlled(taskOrbit, taskCond)
|
||||
|
||||
|
||||
-- Second waypoint
|
||||
PatrolRoute[2]=c1:WaypointAirTurningPoint(self.PatrolAltType, speedkmh, {taskCont, taskPatrol}, "CAP Orbit")
|
||||
|
||||
else
|
||||
|
||||
|
||||
--- 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
|
||||
|
||||
local Tasks = {}
|
||||
Tasks[#Tasks+1] = AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
||||
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
AIPatrol:OptionROEReturnFire()
|
||||
AIPatrol:OptionROTEvadeFire()
|
||||
|
||||
|
||||
AIPatrol:Route( PatrolRoute, self.TaskDelay )
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIPatrol
|
||||
--- Resumes the AIPatrol
|
||||
-- @param Wrapper.Group#GROUP AIPatrol
|
||||
-- @param Core.Fsm#FSM Fsm
|
||||
function AI_AIR_PATROL.Resume( AIPatrol, Fsm )
|
||||
|
||||
AIPatrol:F( { "AI_AIR_PATROL.Resume:", AIPatrol:GetName() } )
|
||||
@@ -394,5 +389,5 @@ function AI_AIR_PATROL.Resume( AIPatrol, Fsm )
|
||||
Fsm:__Reset( Fsm.TaskDelay )
|
||||
Fsm:__PatrolRoute( Fsm.TaskDelay )
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- **AI** - Models squadrons for airplanes and helicopters.
|
||||
--
|
||||
-- This is a class used in the @{AI_Air_Dispatcher} and derived dispatcher classes.
|
||||
-- This is a class used in the @{AI.AI_Air_Dispatcher} and derived dispatcher classes.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -18,7 +18,14 @@
|
||||
|
||||
|
||||
--- Implements the core functions modeling squadrons for airplanes and helicopters.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_AIR_SQUADRON
|
||||
@@ -33,7 +40,7 @@ AI_AIR_SQUADRON = {
|
||||
-- @return #AI_AIR_SQUADRON
|
||||
function AI_AIR_SQUADRON:New( SquadronName, AirbaseName, TemplatePrefixes, ResourceCount )
|
||||
|
||||
self:I( { Air_Squadron = { SquadronName, AirbaseName, TemplatePrefixes, ResourceCount } } )
|
||||
self:T( { Air_Squadron = { SquadronName, AirbaseName, TemplatePrefixes, ResourceCount } } )
|
||||
|
||||
local AI_Air_Squadron = BASE:New() -- #AI_AIR_SQUADRON
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- Peform Battlefield Area Interdiction (BAI) within an engagement zone.
|
||||
--- **AI** - Peform Battlefield Area Interdiction (BAI) within an engagement zone.
|
||||
--
|
||||
-- **Features:**
|
||||
--
|
||||
@@ -11,7 +11,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BAI%20-%20Battlefield%20Air%20Interdiction)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_BAI)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -22,21 +22,23 @@
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
||||
-- * **Gunterlund**: Test case revision.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_Bai
|
||||
-- @module AI.AI_BAI
|
||||
-- @image AI_Battlefield_Air_Interdiction.JPG
|
||||
|
||||
|
||||
--- AI_BAI_ZONE class
|
||||
-- @type AI_BAI_ZONE
|
||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
||||
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @field Core.Zone#ZONE_BASE TargetZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||
|
||||
--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{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.
|
||||
--
|
||||
@@ -130,7 +132,12 @@
|
||||
-- AIBAIZone:SearchOff()
|
||||
--
|
||||
-- Searching can be switched back on with the method @{#AI_BAI_ZONE.SearchOn}(). Use the method @{#AI_BAI_ZONE.SearchOnOff}() to flexibily switch searching on or off.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_BAI_ZONE
|
||||
@@ -142,7 +149,7 @@ AI_BAI_ZONE = {
|
||||
|
||||
--- Creates a new AI_BAI_ZONE object
|
||||
-- @param #AI_BAI_ZONE self
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||
@@ -169,8 +176,7 @@ function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param #string From The From State 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.
|
||||
|
||||
--- OnAfter Transition Handler for Event Engage.
|
||||
@@ -517,12 +523,12 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
|
||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
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 CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
self.EngageSpeed,
|
||||
true
|
||||
)
|
||||
@@ -566,20 +572,20 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
|
||||
EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks )
|
||||
|
||||
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
|
||||
--- Define a random point in the @{Core.Zone}. The AI will fly to that point within the zone.
|
||||
|
||||
--- Find a random 2D point in EngageZone.
|
||||
local ToTargetVec2 = self.EngageZone:GetRandomVec2()
|
||||
self:T2( ToTargetVec2 )
|
||||
|
||||
--- 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.
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
self.EngageSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- Balance player slots with AI to create an engaging simulation environment, independent of the amount of players.
|
||||
--- **AI** - Balance player slots with AI to create an engaging simulation environment, independent of the amount of players.
|
||||
--
|
||||
-- **Features:**
|
||||
--
|
||||
@@ -9,7 +9,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AIB%20-%20AI%20Balancing)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_Balancer)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -20,7 +20,7 @@
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
|
||||
-- * **Dutch_Baron**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -33,14 +33,15 @@
|
||||
-- @field Wrapper.Group#GROUP Test
|
||||
-- @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.
|
||||
-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions.
|
||||
--
|
||||
-- The parent class @{Core.Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM).
|
||||
-- The mission designer can tailor the behaviour of the AI_BALANCER, by defining event and state transition methods.
|
||||
-- An explanation about state and event transition methods can be found in the @{FSM} module documentation.
|
||||
-- An explanation about state and event transition methods can be found in the @{Core.Fsm} module documentation.
|
||||
--
|
||||
-- The mission designer can tailor the AI_BALANCER behaviour, by implementing a state or event handling method for the following:
|
||||
--
|
||||
@@ -52,7 +53,7 @@
|
||||
--
|
||||
-- ## 2. AI_BALANCER is a FSM
|
||||
--
|
||||
-- 
|
||||
-- 
|
||||
--
|
||||
-- ### 2.1. AI_BALANCER States
|
||||
--
|
||||
@@ -85,7 +86,12 @@
|
||||
--
|
||||
-- Note that when AI returns to an airbase, the AI_BALANCER will trigger the **Return** event and the AI will return,
|
||||
-- otherwise the AI_BALANCER will trigger a **Destroy** event, and the AI will be destroyed.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- @field #AI_BALANCER
|
||||
AI_BALANCER = {
|
||||
ClassName = "AI_BALANCER",
|
||||
@@ -163,7 +169,8 @@ function AI_BALANCER:ReturnToHomeAirbase( ReturnThresholdRange )
|
||||
self.ReturnThresholdRange = ReturnThresholdRange
|
||||
end
|
||||
|
||||
--- @param #AI_BALANCER self
|
||||
--- AI_BALANCER:onenterSpawning
|
||||
-- @param #AI_BALANCER self
|
||||
-- @param Core.Set#SET_GROUP SetGroup
|
||||
-- @param #string ClientName
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
@@ -185,7 +192,8 @@ function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_BALANCER self
|
||||
--- AI_BALANCER:onenterDestroying
|
||||
-- @param #AI_BALANCER self
|
||||
-- @param Core.Set#SET_GROUP SetGroup
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup )
|
||||
@@ -213,30 +221,24 @@ function AI_BALANCER:onenterReturning( SetGroup, From, Event, To, AIGroup )
|
||||
AIGroup:MessageToRed( "Returning to home base ...", 30 )
|
||||
else
|
||||
-- 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 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y )
|
||||
local PointVec2 = COORDINATE:New(AIGroup:GetVec2().x, 0, AIGroup:GetVec2().y)
|
||||
local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 )
|
||||
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)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_BALANCER self
|
||||
--- AI_BALANCER:onenterMonitoring
|
||||
-- @param #AI_BALANCER self
|
||||
function AI_BALANCER:onenterMonitoring( SetGroup )
|
||||
|
||||
self:T2( { self.SetClient:Count() } )
|
||||
--self.SetClient:Flush()
|
||||
|
||||
self.SetClient:ForEachClient(
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
--- SetClient:ForEachClient
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
function( Client )
|
||||
self:T3(Client.ClientName)
|
||||
|
||||
@@ -259,7 +261,8 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
|
||||
self:T2( RangeZone )
|
||||
|
||||
_DATABASE:ForEachPlayerUnit(
|
||||
--- @param Wrapper.Unit#UNIT RangeTestUnit
|
||||
--- Nameless function
|
||||
-- @param Wrapper.Unit#UNIT RangeTestUnit
|
||||
function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange )
|
||||
self:T2( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } )
|
||||
if RangeTestUnit:IsInZone( RangeZone ) == true then
|
||||
@@ -271,7 +274,8 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
|
||||
end
|
||||
end,
|
||||
|
||||
--- @param Core.Zone#ZONE_RADIUS RangeZone
|
||||
--- Nameless function
|
||||
-- @param Core.Zone#ZONE_RADIUS RangeZone
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function( RangeZone, AIGroup, PlayerInRange )
|
||||
if PlayerInRange.Value == false then
|
||||
@@ -302,6 +306,3 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
|
||||
|
||||
self:__Monitor( 10 )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- Perform Combat Air Patrolling (CAP) for airplanes.
|
||||
--- **AI** - Perform Combat Air Patrolling (CAP) for airplanes.
|
||||
--
|
||||
-- **Features:**
|
||||
--
|
||||
@@ -6,11 +6,10 @@
|
||||
-- * Trigger detected events when enemy airplanes are detected.
|
||||
-- * Manage a fuel threshold to RTB on time.
|
||||
-- * Engage the enemy when detected.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAP%20-%20Combat%20Air%20Patrol)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_CAP)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -19,29 +18,29 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
||||
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing.
|
||||
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
||||
-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing.
|
||||
-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing.
|
||||
-- * **Quax**: Concept, Advice & Testing.
|
||||
-- * **Pikey**: Concept, Advice & Testing.
|
||||
-- * **Gunterlund**: Test case revision.
|
||||
-- * **Whisper**: Testing.
|
||||
-- * **Delta99**: Testing.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_Cap
|
||||
-- @module AI.AI_CAP
|
||||
-- @image AI_Combat_Air_Patrol.JPG
|
||||
|
||||
|
||||
--- @type AI_CAP_ZONE
|
||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
||||
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @field Core.Zone#ZONE_BASE TargetZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||
|
||||
|
||||
--- Implements the core functions to patrol a @{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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
@@ -106,16 +105,21 @@
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageRange}() to define that range.
|
||||
-- Use the method @{#AI_CAP_ZONE.SetEngageRange}() to define that range.
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Zone} can be set,
|
||||
-- An optional @{Core.Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_Cap#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- Use the method @{#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CAP_ZONE
|
||||
@@ -123,11 +127,9 @@ AI_CAP_ZONE = {
|
||||
ClassName = "AI_CAP_ZONE",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Creates a new AI_CAP_ZONE object
|
||||
-- @param #AI_CAP_ZONE self
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||
@@ -141,7 +143,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
|
||||
self.Accomplished = false
|
||||
self.Engaging = false
|
||||
|
||||
|
||||
self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
|
||||
|
||||
--- OnBefore Transition Handler for Event Engage.
|
||||
@@ -152,7 +154,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
|
||||
--- OnAfter Transition Handler for Event Engage.
|
||||
-- @function [parent=#AI_CAP_ZONE] OnAfterEngage
|
||||
-- @param #AI_CAP_ZONE self
|
||||
@@ -160,11 +162,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event Engage.
|
||||
-- @function [parent=#AI_CAP_ZONE] Engage
|
||||
-- @param #AI_CAP_ZONE self
|
||||
|
||||
|
||||
--- Asynchronous Event Trigger for Event Engage.
|
||||
-- @function [parent=#AI_CAP_ZONE] __Engage
|
||||
-- @param #AI_CAP_ZONE self
|
||||
@@ -188,7 +190,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string To The To State string.
|
||||
|
||||
self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
|
||||
|
||||
|
||||
--- OnBefore Transition Handler for Event Fired.
|
||||
-- @function [parent=#AI_CAP_ZONE] OnBeforeFired
|
||||
-- @param #AI_CAP_ZONE self
|
||||
@@ -197,7 +199,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
|
||||
--- OnAfter Transition Handler for Event Fired.
|
||||
-- @function [parent=#AI_CAP_ZONE] OnAfterFired
|
||||
-- @param #AI_CAP_ZONE self
|
||||
@@ -205,11 +207,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event Fired.
|
||||
-- @function [parent=#AI_CAP_ZONE] Fired
|
||||
-- @param #AI_CAP_ZONE self
|
||||
|
||||
|
||||
--- Asynchronous Event Trigger for Event Fired.
|
||||
-- @function [parent=#AI_CAP_ZONE] __Fired
|
||||
-- @param #AI_CAP_ZONE self
|
||||
@@ -225,7 +227,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
|
||||
--- OnAfter Transition Handler for Event Destroy.
|
||||
-- @function [parent=#AI_CAP_ZONE] OnAfterDestroy
|
||||
-- @param #AI_CAP_ZONE self
|
||||
@@ -233,17 +235,16 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event Destroy.
|
||||
-- @function [parent=#AI_CAP_ZONE] Destroy
|
||||
-- @param #AI_CAP_ZONE self
|
||||
|
||||
|
||||
--- Asynchronous Event Trigger for Event Destroy.
|
||||
-- @function [parent=#AI_CAP_ZONE] __Destroy
|
||||
-- @param #AI_CAP_ZONE self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
|
||||
self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
|
||||
|
||||
--- OnBefore Transition Handler for Event Abort.
|
||||
@@ -254,7 +255,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
|
||||
--- OnAfter Transition Handler for Event Abort.
|
||||
-- @function [parent=#AI_CAP_ZONE] OnAfterAbort
|
||||
-- @param #AI_CAP_ZONE self
|
||||
@@ -262,11 +263,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event Abort.
|
||||
-- @function [parent=#AI_CAP_ZONE] Abort
|
||||
-- @param #AI_CAP_ZONE self
|
||||
|
||||
|
||||
--- Asynchronous Event Trigger for Event Abort.
|
||||
-- @function [parent=#AI_CAP_ZONE] __Abort
|
||||
-- @param #AI_CAP_ZONE self
|
||||
@@ -282,7 +283,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #boolean Return false to cancel Transition.
|
||||
|
||||
|
||||
--- OnAfter Transition Handler for Event Accomplish.
|
||||
-- @function [parent=#AI_CAP_ZONE] OnAfterAccomplish
|
||||
-- @param #AI_CAP_ZONE self
|
||||
@@ -290,11 +291,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event Accomplish.
|
||||
-- @function [parent=#AI_CAP_ZONE] Accomplish
|
||||
-- @param #AI_CAP_ZONE self
|
||||
|
||||
|
||||
--- Asynchronous Event Trigger for Event Accomplish.
|
||||
-- @function [parent=#AI_CAP_ZONE] __Accomplish
|
||||
-- @param #AI_CAP_ZONE self
|
||||
@@ -303,7 +304,6 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the Engage Zone which defines where the AI will engage bogies.
|
||||
-- @param #AI_CAP_ZONE self
|
||||
-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing CAP.
|
||||
@@ -311,7 +311,7 @@ end
|
||||
function AI_CAP_ZONE:SetEngageZone( EngageZone )
|
||||
self:F2()
|
||||
|
||||
if EngageZone then
|
||||
if EngageZone then
|
||||
self.EngageZone = EngageZone
|
||||
else
|
||||
self.EngageZone = nil
|
||||
@@ -346,7 +346,6 @@ function AI_CAP_ZONE:onafterStart( Controllable, From, Event, To )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param AI.AI_CAP#AI_CAP_ZONE
|
||||
-- @param Wrapper.Group#GROUP EngageGroup
|
||||
function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
|
||||
@@ -358,8 +357,6 @@ function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #AI_CAP_ZONE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
@@ -380,11 +377,11 @@ end
|
||||
function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
|
||||
|
||||
if From ~= "Engaging" then
|
||||
|
||||
|
||||
local Engage = false
|
||||
|
||||
|
||||
for DetectedUnit, Detected in pairs( self.DetectedUnits ) do
|
||||
|
||||
|
||||
local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT
|
||||
self:T( DetectedUnit )
|
||||
if DetectedUnit:IsAlive() and DetectedUnit:IsAir() then
|
||||
@@ -392,7 +389,7 @@ function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if Engage == true then
|
||||
self:F( 'Detected -> Engaging' )
|
||||
self:__Engage( 1 )
|
||||
@@ -400,7 +397,6 @@ function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_CAP_ZONE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
@@ -411,9 +407,6 @@ function AI_CAP_ZONE:onafterAbort( Controllable, From, Event, To )
|
||||
self:__Route( 1 )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- @param #AI_CAP_ZONE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
@@ -427,24 +420,23 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
|
||||
--- Calculate the current route point.
|
||||
local CurrentVec2 = self.Controllable:GetVec2()
|
||||
|
||||
|
||||
if not CurrentVec2 then return self end
|
||||
|
||||
|
||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
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 CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToEngageZoneSpeed,
|
||||
true
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
ToEngageZoneSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
|
||||
EngageRoute[#EngageRoute+1] = CurrentRoutePoint
|
||||
|
||||
|
||||
--- Find a random 2D point in PatrolZone.
|
||||
local ToTargetVec2 = self.PatrolZone:GetRandomVec2()
|
||||
self:T2( ToTargetVec2 )
|
||||
@@ -453,17 +445,17 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
local ToTargetAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude )
|
||||
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
|
||||
|
||||
|
||||
--- 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.
|
||||
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
||||
@@ -482,7 +474,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
self:F( {"Within Zone and Engaging ", DetectedUnit } )
|
||||
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit )
|
||||
end
|
||||
else
|
||||
else
|
||||
if self.EngageRange then
|
||||
if DetectedUnit:GetPointVec3():Get2DDistance(Controllable:GetPointVec3() ) <= self.EngageRange then
|
||||
self:F( {"Within Range and Engaging", DetectedUnit } )
|
||||
@@ -506,12 +498,12 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
|
||||
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAP_ZONE.EngageRoute", self )
|
||||
EngageRoute[1].task = Controllable:TaskCombo( AttackTasks )
|
||||
|
||||
|
||||
self:SetDetectionDeactivated()
|
||||
end
|
||||
|
||||
|
||||
Controllable:Route( EngageRoute, 0.5 )
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- Perform Close Air Support (CAS) near friendlies.
|
||||
--- **AI** - Perform Close Air Support (CAS) near friendlies.
|
||||
--
|
||||
-- **Features:**
|
||||
--
|
||||
@@ -11,7 +11,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAS%20-%20Close%20Air%20Support)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_CAS)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -22,22 +22,25 @@
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
||||
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing.
|
||||
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
||||
-- * **Quax**: Concept, Advice & Testing.
|
||||
-- * **Pikey**: Concept, Advice & Testing.
|
||||
-- * **Gunterlund**: Test case revision.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_Cas
|
||||
-- @module AI.AI_CAS
|
||||
-- @image AI_Close_Air_Support.JPG
|
||||
|
||||
--- AI_CAS_ZONE class
|
||||
-- @type AI_CAS_ZONE
|
||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
||||
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @field Core.Zone#ZONE_BASE TargetZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||
|
||||
--- Implements the core functions to provide Close Air Support in an Engage @{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.
|
||||
--
|
||||
-- 
|
||||
@@ -118,7 +121,12 @@
|
||||
-- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
|
||||
-- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the CAS task.
|
||||
-- * **Status**: The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CAS_ZONE
|
||||
@@ -130,7 +138,7 @@ AI_CAS_ZONE = {
|
||||
|
||||
--- Creates a new AI_CAS_ZONE object
|
||||
-- @param #AI_CAS_ZONE self
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||
@@ -461,12 +469,12 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
|
||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
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 CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
self.EngageSpeed,
|
||||
true
|
||||
)
|
||||
@@ -496,20 +504,20 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAS_ZONE.EngageRoute", self )
|
||||
EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks )
|
||||
|
||||
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
|
||||
--- Define a random point in the @{Core.Zone}. The AI will fly to that point within the zone.
|
||||
|
||||
--- Find a random 2D point in EngageZone.
|
||||
local ToTargetVec2 = self.EngageZone:GetRandomVec2()
|
||||
self:T2( ToTargetVec2 )
|
||||
|
||||
--- 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.
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
self.EngageSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
--- 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.
|
||||
-- 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.
|
||||
@@ -25,7 +27,12 @@
|
||||
-- * @{AI.AI_Cargo_APC} - Cargo transportation using APCs and other vehicles between zones.
|
||||
-- * @{AI.AI_Cargo_Helicopter} - Cargo transportation using helicopters between zones.
|
||||
-- * @{AI.AI_Cargo_Airplane} - Cargo transportation using airplanes to and from airbases.
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- @field #AI_CARGO
|
||||
AI_CARGO = {
|
||||
ClassName = "AI_CARGO",
|
||||
@@ -542,7 +549,7 @@ function AI_CARGO:onafterUnloaded( Carrier, From, Event, To, Cargo, CarrierUnit,
|
||||
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
|
||||
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
|
||||
local IsEmpty = CarrierUnit:IsCargoEmpty()
|
||||
self:I({ IsEmpty = IsEmpty })
|
||||
self:T({ IsEmpty = IsEmpty })
|
||||
if not IsEmpty then
|
||||
AllUnloaded = false
|
||||
break
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
--- 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.
|
||||
--
|
||||
-- The AI_CARGO_APC class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||
@@ -75,7 +77,12 @@
|
||||
-- Using the @{#AI_CARGO_APC.Pickup}() method, you are able to direct the APCs towards a point on the battlefield to board/load the cargo at the specific coordinate.
|
||||
-- The APCs will follow nearby roads as much as possible, to ensure fast and clean cargo transportation between the objects and villages in the simulation environment.
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
--
|
||||
-- @field #AI_CARGO_APC
|
||||
AI_CARGO_APC = {
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
|
||||
--- 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.
|
||||
--
|
||||
@@ -41,7 +43,12 @@
|
||||
-- marginal impact on the overall battlefield simulation. Fortunately, the firing strength of infantry is limited, and thus, respacing healthy infantry every
|
||||
-- time is not so much of an issue ...
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- @field #AI_CARGO_AIRPLANE
|
||||
AI_CARGO_AIRPLANE = {
|
||||
ClassName = "AI_CARGO_AIRPLANE",
|
||||
@@ -435,7 +442,7 @@ function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed, Height, Uncontrolled
|
||||
|
||||
-- To point.
|
||||
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["speed_locked"] = true
|
||||
|
||||
@@ -18,10 +18,12 @@
|
||||
--
|
||||
-- Test missions can be located on the main GITHUB site.
|
||||
--
|
||||
-- [FlightControl-Master/MOOSE_MISSIONS/AID - AI Dispatching/AID-CGO - AI Cargo Dispatching/](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/AID%20-%20AI%20Dispatching/AID-CGO%20-%20AI%20Cargo%20Dispatching)
|
||||
-- [FlightControl-Master/MOOSE_MISSIONS/AID - AI Dispatching/AID-CGO - AI Cargo Dispatching/](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_Cargo_Dispatcher)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The dispatcher concept.
|
||||
--
|
||||
-- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
@@ -100,7 +102,12 @@
|
||||
--
|
||||
-- Yes, please ensure that the zones are declared using the @{Core.Zone} classes.
|
||||
-- Possible zones that function at the moment are ZONE, ZONE_GROUP, ZONE_UNIT, ZONE_POLYGON.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
@@ -111,7 +118,7 @@
|
||||
-- @image AI_Cargo_Dispatcher.JPG
|
||||
|
||||
|
||||
--- @type AI_CARGO_DISPATCHER
|
||||
-- @type AI_CARGO_DISPATCHER
|
||||
-- @field Core.Set#SET_GROUP CarrierSet The set of @{Wrapper.Group#GROUP} objects of carriers that will transport the cargo.
|
||||
-- @field Core.Set#SET_CARGO CargoSet The set of @{Cargo.Cargo#CARGO} objects, which can be CARGO_GROUP, CARGO_CRATE, CARGO_SLINGLOAD objects.
|
||||
-- @field Core.Zone#SET_ZONE PickupZoneSet The set of pickup zones, which are used to where the cargo can be picked up by the carriers. If nil, then cargo can be picked up everywhere.
|
||||
@@ -567,7 +574,7 @@
|
||||
-- A home zone can be specified to where the Carriers will move when there isn't any cargo left for pickup.
|
||||
-- Use @{#AI_CARGO_DISPATCHER.SetHomeZone}() to specify the home zone.
|
||||
--
|
||||
-- If no home zone is specified, the carriers will wait near the deploy zone for a new pickup command.
|
||||
-- If no home zone is specified, the carriers will wait near the deploy zone for a new pickup command.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -578,10 +585,12 @@ AI_CARGO_DISPATCHER = {
|
||||
PickupCargo = {}
|
||||
}
|
||||
|
||||
--- @field #list
|
||||
--- List of AI_Cargo
|
||||
-- @field #list
|
||||
AI_CARGO_DISPATCHER.AI_Cargo = {}
|
||||
|
||||
--- @field #list
|
||||
--- List of PickupCargo
|
||||
-- @field #list
|
||||
AI_CARGO_DISPATCHER.PickupCargo = {}
|
||||
|
||||
|
||||
@@ -1154,7 +1163,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
|
||||
else
|
||||
local text=string.format("WARNING: Cargo %s is too heavy to be loaded into transport. Cargo weight %.1f > %.1f load capacity of carrier %s.",
|
||||
tostring(Cargo:GetName()), Cargo:GetWeight(), LargestLoadCapacity, tostring(Carrier:GetName()))
|
||||
self:I(text)
|
||||
self:T(text)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
--- 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.
|
||||
--
|
||||
-- The AI_CARGO_DISPATCHER_APC module is derived from the AI_CARGO_DISPATCHER module.
|
||||
@@ -137,7 +139,12 @@
|
||||
-- Use @{#AI_CARGO_DISPATCHER_APC.SetHomeZone}() to specify the home zone.
|
||||
--
|
||||
-- If no home zone is specified, the APCs will wait near the deploy zone for a new pickup command.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CARGO_DISPATCHER_APC
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Planes.
|
||||
--- **AI** - Models the intelligent transportation of infantry and other cargo using Planes.
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
--- Brings a dynamic cargo handling capability for AI groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
@@ -108,7 +110,12 @@
|
||||
--
|
||||
-- **There are a lot of templates available that allows you to quickly setup an event handler for a specific event type!**
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
--
|
||||
-- @field #AI_CARGO_DISPATCHER_AIRPLANE
|
||||
AI_CARGO_DISPATCHER_AIRPLANE = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- (2.4) - Models the intelligent transportation of infantry and other cargo using Helicopters.
|
||||
--- **AI** - Models the intelligent transportation of infantry and other cargo using Helicopters.
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
--- A dynamic cargo handling capability for AI helicopter groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
--
|
||||
--
|
||||
@@ -140,7 +142,12 @@
|
||||
-- Use @{#AI_CARGO_DISPATCHER_HELICOPTER.SetHomeZone}() to specify the home zone.
|
||||
--
|
||||
-- If no home zone is specified, the helicopters will wait near the deploy zone for a new pickup command.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CARGO_DISPATCHER_HELICOPTER
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- (2.5.1) - Models the intelligent transportation of infantry and other cargo using Ships
|
||||
--- **AI** - Models the intelligent transportation of infantry and other cargo using Ships.
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
--- A dynamic cargo transportation capability for AI groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
@@ -37,14 +39,14 @@
|
||||
--
|
||||
-- This will be particularly helpful in order to determine how to **Tailor the different cargo handling events**.
|
||||
--
|
||||
-- The AI_CARGO_DISPATCHER_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framwork.
|
||||
-- The AI_CARGO_DISPATCHER_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||
-- Also ensure that you fully understand how to declare and setup Cargo objects within the MOOSE framework before using this class.
|
||||
-- CARGO derived objects must generally be declared within the mission to make the AI_CARGO_DISPATCHER_SHIP object recognize the cargo.
|
||||
--
|
||||
--
|
||||
-- # 1) AI_CARGO_DISPATCHER_SHIP constructor.
|
||||
--
|
||||
-- * @{AI_CARGO_DISPATCHER_SHIP.New}(): Creates a new AI_CARGO_DISPATCHER_SHIP object.
|
||||
-- * @{#AI_CARGO_DISPATCHER_SHIP.New}(): Creates a new AI_CARGO_DISPATCHER_SHIP object.
|
||||
--
|
||||
-- ---
|
||||
--
|
||||
@@ -130,7 +132,12 @@
|
||||
-- Use @{#AI_CARGO_DISPATCHER_SHIP.SetHomeZone}() to specify the home zone.
|
||||
--
|
||||
-- If no home zone is specified, the Ship will wait near the deploy zone for a new pickup command.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CARGO_DISPATCHER_SHIP
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
--- 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.
|
||||
--
|
||||
-- The AI_CARGO_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||
@@ -41,7 +43,12 @@
|
||||
-- marginal impact on the overall battlefield simulation. Fortunately, the firing strength of infantry is limited, and thus, respacing healthy infantry every
|
||||
-- time is not so much of an issue ...
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CARGO_HELICOPTER
|
||||
@@ -362,8 +369,8 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina
|
||||
-- local CoordinateFrom = Helicopter:GetCoordinate()
|
||||
-- local WaypointFrom = CoordinateFrom:WaypointAir(
|
||||
-- "RADIO",
|
||||
-- POINT_VEC3.RoutePointType.TurningPoint,
|
||||
-- POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
-- COORDINATE.WaypointType.TurningPoint,
|
||||
-- COORDINATE.WaypointAction.TurningPoint,
|
||||
-- Speed,
|
||||
-- true
|
||||
-- )
|
||||
@@ -375,8 +382,8 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina
|
||||
|
||||
local WaypointTo = CoordinateTo:WaypointAir(
|
||||
"RADIO",
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
50,
|
||||
true
|
||||
)
|
||||
@@ -422,7 +429,7 @@ function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordina
|
||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||
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
|
||||
|
||||
local Tasks = {}
|
||||
@@ -491,14 +498,14 @@ function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordin
|
||||
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||
|
||||
--- 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.
|
||||
local CoordinateTo = Coordinate
|
||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||
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] = WaypointTo
|
||||
@@ -558,7 +565,7 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin
|
||||
|
||||
--- Create a route point of type air.
|
||||
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
|
||||
|
||||
@@ -568,7 +575,7 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin
|
||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||
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
|
||||
@@ -626,7 +633,7 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
|
||||
--- Create a route point of type air.
|
||||
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
|
||||
|
||||
--- Create a route point of type air.
|
||||
@@ -634,7 +641,7 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
|
||||
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||
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
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- (R2.5.1) - Models the intelligent transportation of infantry and other cargo.
|
||||
--- **AI** - Models the intelligent transportation of infantry and other cargo.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
--- 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.
|
||||
-- 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.
|
||||
@@ -46,15 +48,20 @@
|
||||
--
|
||||
-- ## Cargo deployment.
|
||||
--
|
||||
-- Using the @{AI_CARGO_SHIP.Deploy}() method, you are able to direct the Ship towards a Deploy zone to unboard/unload the cargo at the
|
||||
-- Using the @{#AI_CARGO_SHIP.Deploy}() method, you are able to direct the Ship towards a Deploy zone to unboard/unload the cargo at the
|
||||
-- specified coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
|
||||
--
|
||||
-- ## Cargo pickup.
|
||||
--
|
||||
-- Using the @{AI_CARGO_SHIP.Pickup}() method, you are able to direct the Ship towards a Pickup zone to board/load the cargo at the specified
|
||||
-- Using the @{#AI_CARGO_SHIP.Pickup}() method, you are able to direct the Ship towards a Pickup zone to board/load the cargo at the specified
|
||||
-- coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- @field #AI_CARGO_SHIP
|
||||
AI_CARGO_SHIP = {
|
||||
ClassName = "AI_CARGO_SHIP",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Taking the lead of AI escorting your flight or of other AI.
|
||||
--- **AI** - Taking the lead of AI escorting your flight or of other AI.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -19,12 +19,14 @@
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [ESC - Escorting](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/ESC%20-%20Escorting)
|
||||
-- [ESC - Escorting](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_Escort)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 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).
|
||||
--
|
||||
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
||||
@@ -147,8 +149,8 @@
|
||||
-- @image Escorting.JPG
|
||||
|
||||
|
||||
|
||||
--- @type AI_ESCORT
|
||||
---
|
||||
-- @type AI_ESCORT
|
||||
-- @extends AI.AI_Formation#AI_FORMATION
|
||||
|
||||
|
||||
@@ -168,10 +170,17 @@
|
||||
--
|
||||
-- -- First find the GROUP object and the CLIENT object.
|
||||
-- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
|
||||
-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
|
||||
-- local EscortGroup = SET_GROUP:New():FilterPrefixes("Escort"):FilterOnce() -- The the group name of the escorts contains "Escort".
|
||||
--
|
||||
-- -- Now use these 2 objects to construct the new EscortPlanes object.
|
||||
-- EscortPlanes = AI_ESCORT:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
|
||||
-- EscortPlanes:MenusAirplanes() -- create menus for airplanes
|
||||
-- EscortPlanes:__Start(2)
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- @field #AI_ESCORT
|
||||
AI_ESCORT = {
|
||||
@@ -189,16 +198,9 @@ AI_ESCORT = {
|
||||
TaskPoints = {}
|
||||
}
|
||||
|
||||
--- @field Functional.Detection#DETECTION_AREAS
|
||||
-- @field Functional.Detection#DETECTION_AREAS
|
||||
AI_ESCORT.Detection = nil
|
||||
|
||||
--- MENUPARAM type
|
||||
-- @type MENUPARAM
|
||||
-- @field #AI_ESCORT ParamSelf
|
||||
-- @field #Distance ParamDistance
|
||||
-- @field #function ParamFunction
|
||||
-- @field #string ParamMessage
|
||||
|
||||
--- AI_ESCORT class constructor for an AI group
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param Wrapper.Client#CLIENT EscortUnit The client escorted by the EscortGroup.
|
||||
@@ -211,10 +213,14 @@ AI_ESCORT.Detection = nil
|
||||
--
|
||||
-- -- First find the GROUP object and the CLIENT object.
|
||||
-- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
|
||||
-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
|
||||
-- local EscortGroup = SET_GROUP:New():FilterPrefixes("Escort"):FilterOnce() -- The the group name of the escorts contains "Escort".
|
||||
--
|
||||
-- -- Now use these 2 objects to construct the new EscortPlanes object.
|
||||
-- EscortPlanes = AI_ESCORT:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
|
||||
-- EscortPlanes:MenusAirplanes() -- create menus for airplanes
|
||||
-- EscortPlanes:__Start(2)
|
||||
--
|
||||
--
|
||||
function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
|
||||
|
||||
local self = BASE:Inherit( self, AI_FORMATION:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) ) -- #AI_ESCORT
|
||||
@@ -227,10 +233,17 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
|
||||
self.EscortGroupSet = EscortGroupSet
|
||||
|
||||
self.EscortGroupSet:SetSomeIteratorLimit( 8 )
|
||||
|
||||
|
||||
self.EscortBriefing = EscortBriefing
|
||||
|
||||
self.Menu = {}
|
||||
self.Menu.HoldAtEscortPosition = self.Menu.HoldAtEscortPosition or {}
|
||||
self.Menu.HoldAtLeaderPosition = self.Menu.HoldAtLeaderPosition or {}
|
||||
self.Menu.Flare = self.Menu.Flare or {}
|
||||
self.Menu.Smoke = self.Menu.Smoke or {}
|
||||
self.Menu.Targets = self.Menu.Targets or {}
|
||||
self.Menu.ROE = self.Menu.ROE or {}
|
||||
self.Menu.ROT = self.Menu.ROT or {}
|
||||
|
||||
-- if not EscortBriefing then
|
||||
-- EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " ..
|
||||
@@ -250,7 +263,7 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
|
||||
|
||||
|
||||
EscortGroupSet:ForEachGroup(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
-- Set EscortGroup known at EscortUnit.
|
||||
if not self.PlayerUnit._EscortGroups then
|
||||
@@ -325,14 +338,14 @@ function AI_ESCORT:_InitEscortRoute( EscortGroup )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_ESCORT self
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param Core.Set#SET_GROUP EscortGroupSet
|
||||
function AI_ESCORT:onafterStart( EscortGroupSet )
|
||||
|
||||
self:F()
|
||||
|
||||
EscortGroupSet:ForEachGroup(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
EscortGroup:WayPointInitialize()
|
||||
|
||||
@@ -370,7 +383,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
|
||||
self:_InitFlightMenus()
|
||||
|
||||
self.EscortGroupSet:ForSomeGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
|
||||
self:_InitEscortMenus( EscortGroup )
|
||||
@@ -378,7 +391,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
|
||||
|
||||
self:SetFlightModeFormation( EscortGroup )
|
||||
|
||||
--- @param #AI_ESCORT self
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function EscortGroup:OnEventDeadOrCrash( EventData )
|
||||
self:F( { "EventDead", EventData } )
|
||||
@@ -394,14 +407,14 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_ESCORT self
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param Core.Set#SET_GROUP EscortGroupSet
|
||||
function AI_ESCORT:onafterStop( EscortGroupSet )
|
||||
|
||||
self:F()
|
||||
|
||||
EscortGroupSet:ForEachGroup(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
EscortGroup:WayPointInitialize()
|
||||
|
||||
@@ -443,9 +456,9 @@ end
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||
-- @param #number ZLevels The amount of levels on the Z-axis.
|
||||
-- @return #AI_ESCORT
|
||||
@@ -493,9 +506,9 @@ end
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||
-- @param #number ZLevels The amount of levels on the Z-axis.
|
||||
-- @return #AI_ESCORT
|
||||
@@ -545,12 +558,12 @@ function AI_ESCORT:SetFlightMenuFormation( Formation )
|
||||
|
||||
if MenuFormation then
|
||||
local Arguments = MenuFormation.Arguments
|
||||
--self:I({Arguments=unpack(Arguments)})
|
||||
--self:T({Arguments=unpack(Arguments)})
|
||||
local FlightMenuFormation = MENU_GROUP:New( self.PlayerGroup, "Formation", self.MainMenu )
|
||||
local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation,
|
||||
function ( self, Formation, ... )
|
||||
self.EscortGroupSet:ForSomeGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup, self, Formation, Arguments )
|
||||
if EscortGroup:IsAir() then
|
||||
self:E({FormationID=FormationID})
|
||||
@@ -580,7 +593,7 @@ end
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @return #AI_ESCORT
|
||||
function AI_ESCORT:MenuFormationTrail( XStart, XSpace, YStart )
|
||||
|
||||
@@ -594,7 +607,7 @@ end
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||
-- @return #AI_ESCORT
|
||||
function AI_ESCORT:MenuFormationStack( XStart, XSpace, YStart, YSpace )
|
||||
@@ -609,8 +622,8 @@ end
|
||||
-- This menu will appear under **Formation**.
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||
-- @return #AI_ESCORT
|
||||
function AI_ESCORT:MenuFormationLeftLine( XStart, YStart, ZStart, ZSpace )
|
||||
@@ -625,8 +638,8 @@ end
|
||||
-- This menu will appear under **Formation**.
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||
-- @return #AI_ESCORT
|
||||
function AI_ESCORT:MenuFormationRightLine( XStart, YStart, ZStart, ZSpace )
|
||||
@@ -642,8 +655,8 @@ end
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||
-- @return #AI_ESCORT
|
||||
function AI_ESCORT:MenuFormationLeftWing( XStart, XSpace, YStart, ZStart, ZSpace )
|
||||
@@ -659,8 +672,8 @@ end
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||
-- @return #AI_ESCORT
|
||||
function AI_ESCORT:MenuFormationRightWing( XStart, XSpace, YStart, ZStart, ZSpace )
|
||||
@@ -676,9 +689,9 @@ end
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||
-- @return #AI_ESCORT
|
||||
function AI_ESCORT:MenuFormationCenterWing( XStart, XSpace, YStart, YSpace, ZStart, ZSpace )
|
||||
@@ -694,9 +707,9 @@ end
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||
-- @return #AI_ESCORT
|
||||
function AI_ESCORT:MenuFormationVic( XStart, XSpace, YStart, YSpace, ZStart, ZSpace )
|
||||
@@ -712,9 +725,9 @@ end
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||
-- @param #number ZLevels The amount of levels on the Z-axis.
|
||||
-- @return #AI_ESCORT
|
||||
@@ -764,7 +777,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetFlightMenuHoldAtEscortPosition()
|
||||
|
||||
for _, MenuHoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do
|
||||
for _, MenuHoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition or {} ) do
|
||||
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
|
||||
|
||||
local FlightMenuHoldPosition = MENU_GROUP_COMMAND
|
||||
@@ -785,7 +798,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetEscortMenuHoldAtEscortPosition( EscortGroup )
|
||||
|
||||
for _, HoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do
|
||||
for _, HoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition or {}) do
|
||||
if EscortGroup:IsAir() then
|
||||
local EscortGroupName = EscortGroup:GetName()
|
||||
local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu )
|
||||
@@ -853,7 +866,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetFlightMenuHoldAtLeaderPosition()
|
||||
|
||||
for _, MenuHoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition ) do
|
||||
for _, MenuHoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition or {}) do
|
||||
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
|
||||
|
||||
local FlightMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND
|
||||
@@ -874,7 +887,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetEscortMenuHoldAtLeaderPosition( EscortGroup )
|
||||
|
||||
for _, HoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition ) do
|
||||
for _, HoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition or {}) do
|
||||
if EscortGroup:IsAir() then
|
||||
|
||||
local EscortGroupName = EscortGroup:GetName()
|
||||
@@ -999,7 +1012,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetFlightMenuFlare()
|
||||
|
||||
for _, MenuFlare in pairs( self.Menu.Flare) do
|
||||
for _, MenuFlare in pairs( self.Menu.Flare or {}) do
|
||||
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
|
||||
local FlightMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuFlare.MenuText, FlightMenuReportNavigation )
|
||||
|
||||
@@ -1014,7 +1027,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetEscortMenuFlare( EscortGroup )
|
||||
|
||||
for _, MenuFlare in pairs( self.Menu.Flare) do
|
||||
for _, MenuFlare in pairs( self.Menu.Flare or {}) do
|
||||
if EscortGroup:IsAir() then
|
||||
|
||||
local EscortGroupName = EscortGroup:GetName()
|
||||
@@ -1059,7 +1072,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetFlightMenuSmoke()
|
||||
|
||||
for _, MenuSmoke in pairs( self.Menu.Smoke) do
|
||||
for _, MenuSmoke in pairs( self.Menu.Smoke or {}) do
|
||||
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
|
||||
local FlightMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuSmoke.MenuText, FlightMenuReportNavigation )
|
||||
|
||||
@@ -1076,7 +1089,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetEscortMenuSmoke( EscortGroup )
|
||||
|
||||
for _, MenuSmoke in pairs( self.Menu.Smoke) do
|
||||
for _, MenuSmoke in pairs( self.Menu.Smoke or {}) do
|
||||
if EscortGroup:IsAir() then
|
||||
|
||||
local EscortGroupName = EscortGroup:GetName()
|
||||
@@ -1169,7 +1182,7 @@ function AI_ESCORT:SetFlightMenuTargets()
|
||||
local FlightMenuAttackNearbyAir = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Attack nearest airborne targets", self.FlightMenuAttack, AI_ESCORT._FlightAttackNearestTarget, self, self.__Enum.ReportType.Air ):SetTag( "Attack" )
|
||||
local FlightMenuAttackNearbyGround = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Attack nearest ground targets", self.FlightMenuAttack, AI_ESCORT._FlightAttackNearestTarget, self, self.__Enum.ReportType.Ground ):SetTag( "Attack" )
|
||||
|
||||
for _, MenuTargets in pairs( self.Menu.Targets) do
|
||||
for _, MenuTargets in pairs( self.Menu.Targets or {}) do
|
||||
MenuTargets.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, MenuTargets.Interval, MenuTargets.Interval )
|
||||
end
|
||||
|
||||
@@ -1179,7 +1192,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetEscortMenuTargets( EscortGroup )
|
||||
|
||||
for _, MenuTargets in pairs( self.Menu.Targets) do
|
||||
for _, MenuTargets in pairs( self.Menu.Targets or {} or {}) do
|
||||
if EscortGroup:IsAir() then
|
||||
local EscortGroupName = EscortGroup:GetName()
|
||||
--local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu )
|
||||
@@ -1231,7 +1244,7 @@ function AI_ESCORT:MenuAssistedAttack()
|
||||
self:F()
|
||||
|
||||
self.EscortGroupSet:ForSomeGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if not EscortGroup:IsAir() then
|
||||
-- Request assistance from other escorts.
|
||||
@@ -1246,7 +1259,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetFlightMenuROE()
|
||||
|
||||
for _, MenuROE in pairs( self.Menu.ROE) do
|
||||
for _, MenuROE in pairs( self.Menu.ROE or {}) do
|
||||
local FlightMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", self.FlightMenu )
|
||||
|
||||
local FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", FlightMenuROE, AI_ESCORT._FlightROEHoldFire, self, "Holding weapons!" )
|
||||
@@ -1261,7 +1274,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetEscortMenuROE( EscortGroup )
|
||||
|
||||
for _, MenuROE in pairs( self.Menu.ROE) do
|
||||
for _, MenuROE in pairs( self.Menu.ROE or {}) do
|
||||
if EscortGroup:IsAir() then
|
||||
|
||||
local EscortGroupName = EscortGroup:GetName()
|
||||
@@ -1302,7 +1315,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetFlightMenuROT()
|
||||
|
||||
for _, MenuROT in pairs( self.Menu.ROT) do
|
||||
for _, MenuROT in pairs( self.Menu.ROT or {}) do
|
||||
local FlightMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", self.FlightMenu )
|
||||
|
||||
local FlightMenuROTNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", FlightMenuROT, AI_ESCORT._FlightROTNoReaction, self, "Fighting until death!" )
|
||||
@@ -1317,7 +1330,7 @@ end
|
||||
|
||||
function AI_ESCORT:SetEscortMenuROT( EscortGroup )
|
||||
|
||||
for _, MenuROT in pairs( self.Menu.ROT) do
|
||||
for _, MenuROT in pairs( self.Menu.ROT or {}) do
|
||||
if EscortGroup:IsAir() then
|
||||
|
||||
local EscortGroupName = EscortGroup:GetName()
|
||||
@@ -1375,7 +1388,7 @@ function AI_ESCORT:SetEscortMenuResumeMission( EscortGroup )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_ESCORT self
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param Wrapper.Group#GROUP OrbitGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param #number OrbitHeight
|
||||
@@ -1419,7 +1432,7 @@ function AI_ESCORT:_HoldPosition( OrbitGroup, EscortGroup, OrbitHeight, OrbitSec
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_ESCORT self
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param Wrapper.Group#GROUP OrbitGroup
|
||||
-- @param #number OrbitHeight
|
||||
-- @param #number OrbitSeconds
|
||||
@@ -1428,7 +1441,7 @@ function AI_ESCORT:_FlightHoldPosition( OrbitGroup, OrbitHeight, OrbitSeconds )
|
||||
local EscortUnit = self.PlayerUnit
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup, OrbitGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
if OrbitGroup == nil then
|
||||
@@ -1456,7 +1469,7 @@ end
|
||||
function AI_ESCORT:_FlightJoinUp()
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_JoinUp( EscortGroup )
|
||||
@@ -1471,7 +1484,7 @@ end
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||
-- @return #AI_ESCORT
|
||||
function AI_ESCORT:_EscortFormationTrail( EscortGroup, XStart, XSpace, YStart )
|
||||
|
||||
@@ -1483,7 +1496,7 @@ end
|
||||
function AI_ESCORT:_FlightFormationTrail( XStart, XSpace, YStart )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_EscortFormationTrail( EscortGroup, XStart, XSpace, YStart )
|
||||
@@ -1510,7 +1523,7 @@ end
|
||||
function AI_ESCORT:_FlightFormationStack( XStart, XSpace, YStart, YSpace )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_EscortFormationStack( EscortGroup, XStart, XSpace, YStart, YSpace )
|
||||
@@ -1533,7 +1546,7 @@ end
|
||||
function AI_ESCORT:_FlightFlare( Color, Message )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_Flare( EscortGroup, Color, Message )
|
||||
@@ -1556,7 +1569,7 @@ end
|
||||
function AI_ESCORT:_FlightSmoke( Color, Message )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_Smoke( EscortGroup, Color, Message )
|
||||
@@ -1587,7 +1600,7 @@ end
|
||||
function AI_ESCORT:_FlightSwitchReportNearbyTargets( ReportTargets )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_EscortSwitchReportNearbyTargets( EscortGroup, ReportTargets )
|
||||
@@ -1679,7 +1692,7 @@ function AI_ESCORT:_ScanTargets( ScanDuration )
|
||||
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param #AI_ESCORT self
|
||||
function AI_ESCORT.___Resume( EscortGroup, self )
|
||||
|
||||
@@ -1701,7 +1714,7 @@ function AI_ESCORT.___Resume( EscortGroup, self )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_ESCORT self
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param #number WayPoint
|
||||
function AI_ESCORT:_ResumeMission( EscortGroup, WayPoint )
|
||||
@@ -1723,7 +1736,7 @@ function AI_ESCORT:_ResumeMission( EscortGroup, WayPoint )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_ESCORT self
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param Wrapper.Group#GROUP EscortGroup The escort group that will attack the detected item.
|
||||
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
||||
function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem )
|
||||
@@ -1743,7 +1756,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem )
|
||||
local AttackUnitTasks = {}
|
||||
|
||||
DetectedSet:ForEachUnit(
|
||||
--- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
-- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
function( DetectedUnit, Tasks )
|
||||
if DetectedUnit:IsAlive() then
|
||||
AttackUnitTasks[#AttackUnitTasks+1] = EscortGroup:TaskAttackUnit( DetectedUnit )
|
||||
@@ -1767,7 +1780,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem )
|
||||
local Tasks = {}
|
||||
|
||||
DetectedSet:ForEachUnit(
|
||||
--- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
-- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
function( DetectedUnit, Tasks )
|
||||
if DetectedUnit:IsAlive() then
|
||||
Tasks[#Tasks+1] = EscortGroup:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 )
|
||||
@@ -1795,7 +1808,7 @@ end
|
||||
function AI_ESCORT:_FlightAttackTarget( DetectedItem )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup, DetectedItem )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_AttackTarget( EscortGroup, DetectedItem )
|
||||
@@ -1842,7 +1855,7 @@ end
|
||||
|
||||
|
||||
---
|
||||
--- @param #AI_ESCORT self
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param Wrapper.Group#GROUP EscortGroup The escort group that will attack the detected item.
|
||||
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
||||
function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem )
|
||||
@@ -1854,7 +1867,7 @@ function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem )
|
||||
local Tasks = {}
|
||||
|
||||
DetectedSet:ForEachUnit(
|
||||
--- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
-- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
function( DetectedUnit, Tasks )
|
||||
if DetectedUnit:IsAlive() then
|
||||
Tasks[#Tasks+1] = EscortGroup:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 )
|
||||
@@ -1881,7 +1894,7 @@ end
|
||||
|
||||
function AI_ESCORT:_FlightROEHoldFire( EscortROEMessage )
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
self:_ROE( EscortGroup, EscortGroup.OptionROEHoldFire, EscortROEMessage )
|
||||
end
|
||||
@@ -1890,7 +1903,7 @@ end
|
||||
|
||||
function AI_ESCORT:_FlightROEOpenFire( EscortROEMessage )
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
self:_ROE( EscortGroup, EscortGroup.OptionROEOpenFire, EscortROEMessage )
|
||||
end
|
||||
@@ -1899,7 +1912,7 @@ end
|
||||
|
||||
function AI_ESCORT:_FlightROEReturnFire( EscortROEMessage )
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
self:_ROE( EscortGroup, EscortGroup.OptionROEReturnFire, EscortROEMessage )
|
||||
end
|
||||
@@ -1908,7 +1921,7 @@ end
|
||||
|
||||
function AI_ESCORT:_FlightROEWeaponFree( EscortROEMessage )
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
self:_ROE( EscortGroup, EscortGroup.OptionROEWeaponFree, EscortROEMessage )
|
||||
end
|
||||
@@ -1924,7 +1937,7 @@ end
|
||||
|
||||
function AI_ESCORT:_FlightROTNoReaction( EscortROTMessage )
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
self:_ROT( EscortGroup, EscortGroup.OptionROTNoReaction, EscortROTMessage )
|
||||
end
|
||||
@@ -1933,7 +1946,7 @@ end
|
||||
|
||||
function AI_ESCORT:_FlightROTPassiveDefense( EscortROTMessage )
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
self:_ROT( EscortGroup, EscortGroup.OptionROTPassiveDefense, EscortROTMessage )
|
||||
end
|
||||
@@ -1942,7 +1955,7 @@ end
|
||||
|
||||
function AI_ESCORT:_FlightROTEvadeFire( EscortROTMessage )
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
self:_ROT( EscortGroup, EscortGroup.OptionROTEvadeFire, EscortROTMessage )
|
||||
end
|
||||
@@ -1951,7 +1964,7 @@ end
|
||||
|
||||
function AI_ESCORT:_FlightROTVertical( EscortROTMessage )
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
self:_ROT( EscortGroup, EscortGroup.OptionROTVertical, EscortROTMessage )
|
||||
end
|
||||
@@ -2178,5 +2191,3 @@ function AI_ESCORT:_FlightReportTargetsScheduler()
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -15,12 +15,19 @@
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
|
||||
--- @type AI_ESCORT_DISPATCHER
|
||||
-- @type AI_ESCORT_DISPATCHER
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
--- Models the automatic assignment of AI escorts to player flights.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_ESCORT_DISPATCHER
|
||||
@@ -28,7 +35,7 @@ AI_ESCORT_DISPATCHER = {
|
||||
ClassName = "AI_ESCORT_DISPATCHER",
|
||||
}
|
||||
|
||||
--- @field #list
|
||||
-- @field #list
|
||||
AI_ESCORT_DISPATCHER.AI_Escorts = {}
|
||||
|
||||
|
||||
@@ -97,7 +104,7 @@ function AI_ESCORT_DISPATCHER:onafterStart( From, Event, To )
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_ESCORT_DISPATCHER self
|
||||
-- @param #AI_ESCORT_DISPATCHER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_ESCORT_DISPATCHER:OnEventExit( EventData )
|
||||
|
||||
@@ -105,11 +112,11 @@ function AI_ESCORT_DISPATCHER:OnEventExit( EventData )
|
||||
local PlayerGroup = EventData.IniGroup
|
||||
local PlayerUnit = EventData.IniUnit
|
||||
|
||||
self:I({EscortAirbase= self.EscortAirbase } )
|
||||
self:I({PlayerGroupName = PlayerGroupName } )
|
||||
self:I({PlayerGroup = PlayerGroup})
|
||||
self:I({FirstGroup = self.CarrierSet:GetFirst()})
|
||||
self:I({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
|
||||
self:T({EscortAirbase= self.EscortAirbase } )
|
||||
self:T({PlayerGroupName = PlayerGroupName } )
|
||||
self:T({PlayerGroup = PlayerGroup})
|
||||
self:T({FirstGroup = self.CarrierSet:GetFirst()})
|
||||
self:T({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
|
||||
|
||||
if self.CarrierSet:FindGroup( PlayerGroupName ) then
|
||||
if self.AI_Escorts[PlayerGroupName] then
|
||||
@@ -120,7 +127,7 @@ function AI_ESCORT_DISPATCHER:OnEventExit( EventData )
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_ESCORT_DISPATCHER self
|
||||
-- @param #AI_ESCORT_DISPATCHER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_ESCORT_DISPATCHER:OnEventBirth( EventData )
|
||||
|
||||
@@ -128,17 +135,17 @@ function AI_ESCORT_DISPATCHER:OnEventBirth( EventData )
|
||||
local PlayerGroup = EventData.IniGroup
|
||||
local PlayerUnit = EventData.IniUnit
|
||||
|
||||
self:I({EscortAirbase= self.EscortAirbase } )
|
||||
self:I({PlayerGroupName = PlayerGroupName } )
|
||||
self:I({PlayerGroup = PlayerGroup})
|
||||
self:I({FirstGroup = self.CarrierSet:GetFirst()})
|
||||
self:I({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
|
||||
self:T({EscortAirbase= self.EscortAirbase } )
|
||||
self:T({PlayerGroupName = PlayerGroupName } )
|
||||
self:T({PlayerGroup = PlayerGroup})
|
||||
self:T({FirstGroup = self.CarrierSet:GetFirst()})
|
||||
self:T({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
|
||||
|
||||
if self.CarrierSet:FindGroup( PlayerGroupName ) then
|
||||
if not self.AI_Escorts[PlayerGroupName] then
|
||||
local LeaderUnit = PlayerUnit
|
||||
local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Hot )
|
||||
self:I({EscortGroup = EscortGroup})
|
||||
self:T({EscortGroup = EscortGroup})
|
||||
|
||||
self:ScheduleOnce( 1,
|
||||
function( EscortGroup )
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_ESCORT_DISPATCHER_REQUEST
|
||||
-- @module AI.AI_Escort_Dispatcher_Request
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
|
||||
@@ -20,7 +20,14 @@
|
||||
|
||||
|
||||
--- Models the assignment of AI escorts to player flights upon request using the radio menu.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_ESCORT_DISPATCHER_REQUEST
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Taking the lead of AI escorting your flight or of other AI, upon request using the menu.
|
||||
--- **AI** - Taking the lead of AI escorting your flight or of other AI, upon request using the menu.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -19,12 +19,14 @@
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [ESC - Escorting](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/ESC%20-%20Escorting)
|
||||
-- [ESC - Escorting](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_Escort)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 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).
|
||||
--
|
||||
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
||||
@@ -137,13 +139,18 @@
|
||||
-- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint.
|
||||
-- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: **FlightControl**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module AI.AI_Escort
|
||||
-- @module AI.AI_Escort_Request
|
||||
-- @image Escorting.JPG
|
||||
|
||||
|
||||
@@ -292,7 +299,7 @@ function AI_ESCORT_REQUEST:onafterStop( EscortGroupSet )
|
||||
self:F()
|
||||
|
||||
EscortGroupSet:ForEachGroup(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
EscortGroup:WayPointInitialize()
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- Build large airborne formations of aircraft.
|
||||
--- **AI** - Build large airborne formations of aircraft.
|
||||
--
|
||||
-- **Features:**
|
||||
--
|
||||
@@ -7,13 +7,13 @@
|
||||
-- * Assign a group leader that will guide the large formation path.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/FOR%20-%20Formation)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0bFIJ9jIdYM22uaWmIN4oz)
|
||||
--
|
||||
--
|
||||
-- ## Additional Material:
|
||||
--
|
||||
-- * **Demo Missions:** [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_Formation)
|
||||
-- * **YouTube videos:** [Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0bFIJ9jIdYM22uaWmIN4oz)
|
||||
-- * **Guides:** None
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
@@ -31,17 +31,19 @@
|
||||
-- @field Core.Set#SET_GROUP FollowGroupSet
|
||||
-- @field #string FollowName
|
||||
-- @field #AI_FORMATION.MODE FollowMode The mode the escort is in.
|
||||
-- @field Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
|
||||
-- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
|
||||
-- @field #number FollowDistance The current follow distance.
|
||||
-- @field #boolean ReportTargets If true, nearby targets are reported.
|
||||
-- @Field DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the FollowGroup.
|
||||
-- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup.
|
||||
-- @field DCS#AI.Option.Air.val.ROE OptionROE Which ROE is set to the FollowGroup.
|
||||
-- @field DCS#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup.
|
||||
-- @field #number dtFollow Time step between position updates.
|
||||
|
||||
|
||||
--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- AI_FORMATION makes AI @{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 purpose of the class is to:
|
||||
--
|
||||
@@ -92,7 +94,12 @@
|
||||
-- local LargeFormation = AI_FORMATION:New( LeaderUnit, FollowGroupSet, "Center Wing Formation", "Briefing" )
|
||||
-- LargeFormation:FormationCenterWing( 500, 50, 0, 250, 250 )
|
||||
-- LargeFormation:__Start( 1 )
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- @field #AI_FORMATION
|
||||
AI_FORMATION = {
|
||||
ClassName = "AI_FORMATION",
|
||||
@@ -153,21 +160,11 @@ AI_FORMATION.__Enum.Mode = {
|
||||
-- @field #number GroundRadar
|
||||
-- @field #number Ground
|
||||
AI_FORMATION.__Enum.ReportType = {
|
||||
Airborne = "*",
|
||||
Airborne = "A",
|
||||
GroundRadar = "R",
|
||||
Ground = "G",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- MENUPARAM type
|
||||
-- @type MENUPARAM
|
||||
-- @field #AI_FORMATION ParamSelf
|
||||
-- @field #number ParamDistance
|
||||
-- @field #function ParamFunction
|
||||
-- @field #string ParamMessage
|
||||
|
||||
--- AI_FORMATION class constructor for an AI group
|
||||
-- @param #AI_FORMATION self
|
||||
-- @param Wrapper.Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet.
|
||||
@@ -729,7 +726,7 @@ function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, X
|
||||
|
||||
for FollowID, FollowGroup in pairs( FollowSet ) do
|
||||
|
||||
local PointVec3 = POINT_VEC3:New()
|
||||
local PointVec3 = COORDINATE:New()
|
||||
PointVec3:SetX( XStart + i * XSpace )
|
||||
PointVec3:SetY( YStart + i * YSpace )
|
||||
PointVec3:SetZ( ZStart + i * ZSpace )
|
||||
@@ -881,7 +878,7 @@ function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event ,
|
||||
|
||||
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 Row = i / 2 + 1
|
||||
@@ -940,7 +937,7 @@ function AI_FORMATION:onafterFormationBox( FollowGroupSet, From , Event , To, XS
|
||||
|
||||
for FollowID, FollowGroup in pairs( FollowSet ) do
|
||||
|
||||
local PointVec3 = POINT_VEC3:New()
|
||||
local PointVec3 = COORDINATE:New()
|
||||
|
||||
local ZIndex = i % ZLevels
|
||||
local XIndex = math.floor( i / ZLevels )
|
||||
@@ -1000,7 +997,7 @@ function AI_FORMATION:SetFlightModeMission( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
|
||||
else
|
||||
self.FollowGroupSet:ForSomeGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
|
||||
@@ -1024,7 +1021,7 @@ function AI_FORMATION:SetFlightModeAttack( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack )
|
||||
else
|
||||
self.FollowGroupSet:ForSomeGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack )
|
||||
@@ -1048,7 +1045,7 @@ function AI_FORMATION:SetFlightModeFormation( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
|
||||
else
|
||||
self.FollowGroupSet:ForSomeGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
|
||||
@@ -1226,7 +1223,6 @@ function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2)
|
||||
local CVI = {
|
||||
x = CV2.x + CS * 10 * math.sin(Ca),
|
||||
y = GH2.y + Inclination, -- + FollowFormation.y,
|
||||
y = GH2.y,
|
||||
z = CV2.z + CS * 10 * math.cos(Ca),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **AI** -- Perform Air Patrolling for airplanes.
|
||||
--- **AI** - Perform Air Patrolling for airplanes.
|
||||
--
|
||||
-- **Features:**
|
||||
--
|
||||
@@ -16,7 +16,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/PAT%20-%20Patrolling)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_Patrol)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -27,8 +27,8 @@
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
|
||||
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Testing and API concept review.
|
||||
-- * **Dutch_Baron**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
|
||||
-- * **Pikey**: Testing and API concept review.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -38,7 +38,7 @@
|
||||
--- AI_PATROL_ZONE class
|
||||
-- @type AI_PATROL_ZONE
|
||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
||||
-- @field Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @field Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @field DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @field DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @field DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||
@@ -46,7 +46,9 @@
|
||||
-- @field Core.Spawn#SPAWN CoordTest
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
|
||||
--- Implements the core functions to patrol a @{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}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
@@ -135,16 +137,21 @@
|
||||
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
|
||||
-- while a new AI is targetted to the AI_PATROL_ZONE.
|
||||
-- while a new AI is targeted to the AI_PATROL_ZONE.
|
||||
-- Once the time is finished, the old AI will return to the base.
|
||||
-- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this proces in place.
|
||||
-- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this process in place.
|
||||
--
|
||||
-- ## 7. Manage "damage" behaviour of the AI in the AI_PATROL_ZONE
|
||||
--
|
||||
-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on.
|
||||
-- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
|
||||
-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this proces in place.
|
||||
-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this process in place.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_PATROL_ZONE
|
||||
@@ -154,7 +161,7 @@ AI_PATROL_ZONE = {
|
||||
|
||||
--- Creates a new AI_PATROL_ZONE object
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||
@@ -170,27 +177,27 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_PATROL_ZONE
|
||||
|
||||
|
||||
|
||||
|
||||
self.PatrolZone = PatrolZone
|
||||
self.PatrolFloorAltitude = PatrolFloorAltitude
|
||||
self.PatrolCeilingAltitude = PatrolCeilingAltitude
|
||||
self.PatrolMinSpeed = PatrolMinSpeed
|
||||
self.PatrolMaxSpeed = PatrolMaxSpeed
|
||||
|
||||
|
||||
-- defafult PatrolAltType to "BARO" if not specified
|
||||
self.PatrolAltType = PatrolAltType or "BARO"
|
||||
|
||||
|
||||
self:SetRefreshTimeInterval( 30 )
|
||||
|
||||
|
||||
self.CheckStatus = true
|
||||
|
||||
|
||||
self:ManageFuel( .2, 60 )
|
||||
self:ManageDamage( 1 )
|
||||
|
||||
|
||||
|
||||
self.DetectedUnits = {} -- This table contains the targets detected during patrol.
|
||||
|
||||
|
||||
self:SetStartState( "None" )
|
||||
|
||||
self:AddTransition( "*", "Stop", "Stopped" )
|
||||
@@ -228,7 +235,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event Stop.
|
||||
-- @function [parent=#AI_PATROL_ZONE] Stop
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
@@ -256,7 +263,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event Start.
|
||||
-- @function [parent=#AI_PATROL_ZONE] Start
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
@@ -329,7 +336,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event Status.
|
||||
-- @function [parent=#AI_PATROL_ZONE] Status
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
@@ -413,7 +420,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
|
||||
--- Synchronous Event Trigger for Event RTB.
|
||||
-- @function [parent=#AI_PATROL_ZONE] RTB
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
@@ -441,11 +448,11 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
||||
-- @param #string To The To State string.
|
||||
|
||||
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROL_ZONE.
|
||||
|
||||
|
||||
self:AddTransition( "*", "Eject", "*" )
|
||||
self:AddTransition( "*", "Crash", "Crashed" )
|
||||
self:AddTransition( "*", "PilotDead", "*" )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -459,7 +466,7 @@ end
|
||||
-- @return #AI_PATROL_ZONE self
|
||||
function AI_PATROL_ZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
|
||||
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
|
||||
|
||||
|
||||
self.PatrolMinSpeed = PatrolMinSpeed
|
||||
self.PatrolMaxSpeed = PatrolMaxSpeed
|
||||
end
|
||||
@@ -473,7 +480,7 @@ end
|
||||
-- @return #AI_PATROL_ZONE self
|
||||
function AI_PATROL_ZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
||||
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
|
||||
|
||||
|
||||
self.PatrolFloorAltitude = PatrolFloorAltitude
|
||||
self.PatrolCeilingAltitude = PatrolCeilingAltitude
|
||||
end
|
||||
@@ -582,7 +589,7 @@ end
|
||||
|
||||
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROL_ZONE.
|
||||
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targeted to the AI_PATROL_ZONE.
|
||||
-- Once the time is finished, the old AI will return to the base.
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param #number PatrolFuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
||||
@@ -592,7 +599,7 @@ function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFu
|
||||
|
||||
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
|
||||
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -609,28 +616,28 @@ function AI_PATROL_ZONE:ManageDamage( PatrolDamageThreshold )
|
||||
|
||||
self.PatrolManageDamage = true
|
||||
self.PatrolDamageThreshold = PatrolDamageThreshold
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
||||
--- Defines a new patrol route using the @{#AI_PATROL_ZONE} parameters and settings.
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @return #AI_PATROL_ZONE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @return #AI_PATROL_ZONE self
|
||||
function AI_PATROL_ZONE:onafterStart( Controllable, From, Event, To )
|
||||
self:F2()
|
||||
|
||||
self:__Route( 1 ) -- Route to the patrol point. The asynchronous trigger is important, because a spawned group and units takes at least one second to come live.
|
||||
self:__Status( 60 ) -- Check status status every 30 seconds.
|
||||
self:SetDetectionActivated()
|
||||
|
||||
|
||||
self:HandleEvent( EVENTS.PilotDead, self.OnPilotDead )
|
||||
self:HandleEvent( EVENTS.Crash, self.OnCrash )
|
||||
self:HandleEvent( EVENTS.Ejection, self.OnEjection )
|
||||
|
||||
|
||||
Controllable:OptionROEHoldFire()
|
||||
Controllable:OptionROTVertical()
|
||||
|
||||
@@ -647,15 +654,15 @@ function AI_PATROL_ZONE:onafterStart( Controllable, From, Event, To )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_PATROL_ZONE self
|
||||
--- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable+
|
||||
function AI_PATROL_ZONE:onbeforeDetect( Controllable, From, Event, To )
|
||||
|
||||
return self.DetectOn and self.DetectActivated
|
||||
end
|
||||
|
||||
--- @param #AI_PATROL_ZONE self
|
||||
--- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
|
||||
|
||||
local Detected = false
|
||||
@@ -667,12 +674,12 @@ function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
|
||||
if TargetObject and TargetObject:isExist() and TargetObject.id_ < 50000000 then
|
||||
|
||||
local TargetUnit = UNIT:Find( TargetObject )
|
||||
|
||||
|
||||
-- Check that target is alive due to issue https://github.com/FlightControl-Master/MOOSE/issues/1234
|
||||
if TargetUnit and TargetUnit:IsAlive() then
|
||||
|
||||
|
||||
local TargetUnitName = TargetUnit:GetName()
|
||||
|
||||
|
||||
if self.DetectionZone then
|
||||
if TargetUnit:IsInZone( self.DetectionZone ) then
|
||||
self:T( {"Detected ", TargetUnit } )
|
||||
@@ -687,21 +694,21 @@ function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
|
||||
end
|
||||
Detected = true
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:__Detect( -self.DetectInterval )
|
||||
|
||||
|
||||
if Detected == true then
|
||||
self:__Detected( 1.5 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
|
||||
-- This statis method is called from the route path within the last task at the last waaypoint of the Controllable.
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE AIControllable
|
||||
-- This static method is called from the route path within the last task at the last waypoint of the Controllable.
|
||||
-- Note that this method is required, as triggers the next route when patrolling for the Controllable.
|
||||
function AI_PATROL_ZONE:_NewPatrolRoute( AIControllable )
|
||||
|
||||
@@ -710,7 +717,7 @@ function AI_PATROL_ZONE:_NewPatrolRoute( AIControllable )
|
||||
end
|
||||
|
||||
|
||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
||||
--- Defines a new patrol route using the @{#AI_PATROL_ZONE} parameters and settings.
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
@@ -729,7 +736,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
if self.Controllable:IsAlive() and life > 1 then
|
||||
-- Determine if the AIControllable is within the PatrolZone.
|
||||
-- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point.
|
||||
|
||||
|
||||
local PatrolRoute = {}
|
||||
|
||||
-- Calculate the current route point of the controllable as the start point of the route.
|
||||
@@ -746,12 +753,12 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
if not CurrentVec2 then return end
|
||||
--Done: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
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 CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TakeOffParking,
|
||||
POINT_VEC3.RoutePointAction.FromParkingArea,
|
||||
COORDINATE.WaypointType.TakeOffParking,
|
||||
COORDINATE.WaypointAction.FromParkingArea,
|
||||
ToPatrolZoneSpeed,
|
||||
true
|
||||
)
|
||||
@@ -762,12 +769,12 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
if not CurrentVec2 then return end
|
||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
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 CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
ToPatrolZoneSpeed,
|
||||
true
|
||||
)
|
||||
@@ -775,7 +782,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
end
|
||||
|
||||
|
||||
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
|
||||
--- Define a random point in the @{Core.Zone}. The AI will fly to that point within the zone.
|
||||
|
||||
--- Find a random 2D point in PatrolZone.
|
||||
local ToTargetVec2 = self.PatrolZone:GetRandomVec2()
|
||||
@@ -787,13 +794,13 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
|
||||
|
||||
--- 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.
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
@@ -817,13 +824,13 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_PATROL_ZONE self
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
function AI_PATROL_ZONE:onbeforeStatus()
|
||||
|
||||
return self.CheckStatus
|
||||
end
|
||||
|
||||
--- @param #AI_PATROL_ZONE self
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
function AI_PATROL_ZONE:onafterStatus()
|
||||
self:F2()
|
||||
|
||||
@@ -833,7 +840,7 @@ function AI_PATROL_ZONE:onafterStatus()
|
||||
|
||||
local Fuel = self.Controllable:GetFuelMin()
|
||||
if Fuel < self.PatrolFuelThresholdPercentage then
|
||||
self:I( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
|
||||
self:T( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
|
||||
local OldAIControllable = self.Controllable
|
||||
|
||||
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
||||
@@ -841,16 +848,25 @@ function AI_PATROL_ZONE:onafterStatus()
|
||||
OldAIControllable:SetTask( TimedOrbitTask, 10 )
|
||||
|
||||
RTB = true
|
||||
else
|
||||
end
|
||||
|
||||
-- TODO: Check GROUP damage function.
|
||||
local Damage = self.Controllable:GetLife()
|
||||
if Damage <= self.PatrolDamageThreshold then
|
||||
self:I( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" )
|
||||
self:T( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" )
|
||||
RTB = true
|
||||
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
|
||||
self:RTB()
|
||||
else
|
||||
@@ -859,7 +875,7 @@ function AI_PATROL_ZONE:onafterStatus()
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_PATROL_ZONE self
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
function AI_PATROL_ZONE:onafterRTB()
|
||||
self:F2()
|
||||
|
||||
@@ -876,12 +892,12 @@ function AI_PATROL_ZONE:onafterRTB()
|
||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
--local CurrentAltitude = self.Controllable:GetUnit(1):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 CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
COORDINATE.WaypointType.TurningPoint,
|
||||
COORDINATE.WaypointAction.TurningPoint,
|
||||
ToPatrolZoneSpeed,
|
||||
true
|
||||
)
|
||||
@@ -898,13 +914,13 @@ function AI_PATROL_ZONE:onafterRTB()
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_PATROL_ZONE self
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
function AI_PATROL_ZONE:onafterDead()
|
||||
self:SetDetectionOff()
|
||||
self:SetStatusOff()
|
||||
end
|
||||
|
||||
--- @param #AI_PATROL_ZONE self
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_PATROL_ZONE:OnCrash( EventData )
|
||||
|
||||
@@ -915,7 +931,7 @@ function AI_PATROL_ZONE:OnCrash( EventData )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_PATROL_ZONE self
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_PATROL_ZONE:OnEjection( EventData )
|
||||
|
||||
@@ -924,7 +940,7 @@ function AI_PATROL_ZONE:OnEjection( EventData )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_PATROL_ZONE self
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_PATROL_ZONE:OnPilotDead( EventData )
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occuring on @{Wrapper.Unit}s.
|
||||
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs.
|
||||
--
|
||||
-- 
|
||||
-- 
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module Actions.Account
|
||||
-- @module Actions.Act_Account
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
do -- ACT_ACCOUNT
|
||||
|
||||
|
||||
--- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## ACT_ACCOUNT state machine:
|
||||
--
|
||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||
@@ -20,7 +22,7 @@ do -- ACT_ACCOUNT
|
||||
--
|
||||
-- ### ACT_ACCOUNT States
|
||||
--
|
||||
-- * **Asigned**: The player is assigned.
|
||||
-- * **Assigned**: The player is assigned.
|
||||
-- * **Waiting**: Waiting for an event.
|
||||
-- * **Report**: Reporting.
|
||||
-- * **Account**: Account for an event.
|
||||
@@ -54,6 +56,11 @@ do -- ACT_ACCOUNT
|
||||
-- The state transition method needs to start with the name **OnAfter + the name of the state**.
|
||||
-- These state transition methods need to provide a return value, which is specified at the function description.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- @type ACT_ACCOUNT
|
||||
-- @field Core.Set#SET_UNIT TargetSetUnit
|
||||
-- @extends Core.Fsm#FSM_PROCESS
|
||||
@@ -104,7 +111,6 @@ do -- ACT_ACCOUNT
|
||||
self:__Wait( 1 )
|
||||
end
|
||||
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ACCOUNT self
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
@@ -129,7 +135,7 @@ do -- ACT_ACCOUNT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To, Event )
|
||||
function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To )
|
||||
|
||||
self:__NoMore( 1 )
|
||||
end
|
||||
@@ -138,10 +144,10 @@ end -- ACT_ACCOUNT
|
||||
|
||||
do -- ACT_ACCOUNT_DEADS
|
||||
|
||||
--- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Core.Fsm.Account#ACT_ACCOUNT}
|
||||
--- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{#ACT_ACCOUNT}
|
||||
--
|
||||
-- The ACT_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units.
|
||||
-- The process is given a @{Set} of units that will be tracked upon successful destruction.
|
||||
-- The process is given a @{Core.Set} of units that will be tracked upon successful destruction.
|
||||
-- The process will end after each target has been successfully destroyed.
|
||||
-- Each successful dead will trigger an Account state transition that can be scored, modified or administered.
|
||||
--
|
||||
@@ -157,7 +163,6 @@ do -- ACT_ACCOUNT_DEADS
|
||||
ClassName = "ACT_ACCOUNT_DEADS",
|
||||
}
|
||||
|
||||
|
||||
--- Creates a new DESTROY process.
|
||||
-- @param #ACT_ACCOUNT_DEADS self
|
||||
-- @param Core.Set#SET_UNIT TargetSetUnit
|
||||
@@ -195,7 +200,6 @@ do -- ACT_ACCOUNT_DEADS
|
||||
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||
end
|
||||
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ACCOUNT_DEADS self
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
@@ -270,7 +274,6 @@ do -- ACT_ACCOUNT_DEADS
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- DCS Events
|
||||
|
||||
--- @param #ACT_ACCOUNT_DEADS self
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
--- (SP) (MP) (FSM) Accept or reject process for player (task) assignments.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS}
|
||||
--
|
||||
@@ -52,9 +54,14 @@
|
||||
-- The state transition method needs to start with the name **OnAfter + the name of the state**.
|
||||
-- These state transition methods need to provide a return value, which is specified at the function description.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Core.Fsm.Assign#ACT_ASSIGN}
|
||||
-- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Core.Fsm#ACT_ASSIGN}
|
||||
--
|
||||
-- The ACT_ASSIGN_ACCEPT class accepts by default a task for a player. No player intervention is allowed to reject the task.
|
||||
--
|
||||
@@ -64,7 +71,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Core.Fsm.Assign#ACT_ASSIGN}
|
||||
-- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Core.Fsm#ACT_ASSIGN}
|
||||
--
|
||||
-- The ACT_ASSIGN_MENU_ACCEPT class accepts a task when the player accepts the task through an added menu option.
|
||||
-- This assignment type is useful to conditionally allow the player to choose whether or not he would accept the task.
|
||||
@@ -77,7 +84,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module Actions.Assign
|
||||
-- @module Actions.Act_Assign
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
|
||||
--
|
||||
-- 
|
||||
-- ## ACT_ASSIST state machine:
|
||||
--
|
||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||
@@ -48,9 +49,9 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Core.Fsm.Route#ACT_ASSIST}
|
||||
-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{#ACT_ASSIST}
|
||||
--
|
||||
-- The ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Zone}.
|
||||
-- The ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Core.Zone}.
|
||||
-- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour.
|
||||
-- At random intervals, a new target is smoked.
|
||||
--
|
||||
@@ -58,9 +59,14 @@
|
||||
--
|
||||
-- * @{#ACT_ASSIST_SMOKE_TARGETS_ZONE.New}(): Creates a new ACT_ASSIST_SMOKE_TARGETS_ZONE object.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module Actions.Assist
|
||||
-- @module Actions.Act_Assist
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||
--
|
||||
-- ## ACT_ROUTE state machine:
|
||||
@@ -60,9 +62,9 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Core.Fsm.Route#ACT_ROUTE}
|
||||
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{#ACT_ROUTE}
|
||||
--
|
||||
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Zone}.
|
||||
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Core.Zone}.
|
||||
-- The player receives on perioding times messages with the coordinates of the route to follow.
|
||||
-- Upon arrival at the zone, a confirmation of arrival is sent, and the process will be ended.
|
||||
--
|
||||
@@ -70,9 +72,14 @@
|
||||
--
|
||||
-- * @{#ACT_ROUTE_ZONE.New}(): Creates a new ACT_ROUTE_ZONE object.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module Actions.Route
|
||||
-- @module Actions.Act_Route
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object.
|
||||
--- **Cargo** - Management of single cargo crates, which are based on a STATIC object.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -22,6 +22,9 @@ do -- CARGO_CRATE
|
||||
-- @type CARGO_CRATE
|
||||
-- @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.
|
||||
-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers.
|
||||
--
|
||||
@@ -36,7 +39,12 @@ do -- CARGO_CRATE
|
||||
--
|
||||
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players.
|
||||
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #CARGO_CRATE
|
||||
@@ -54,7 +62,7 @@ do -- CARGO_CRATE
|
||||
-- @return #CARGO_CRATE
|
||||
function CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
|
||||
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_CRATE
|
||||
self:F( { Type, Name, NearRadius } )
|
||||
self:T( { Type, Name, NearRadius } )
|
||||
|
||||
self.CargoObject = CargoStatic -- Wrapper.Static#STATIC
|
||||
|
||||
@@ -109,9 +117,9 @@ do -- CARGO_CRATE
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2
|
||||
-- @param Core.Point#COORDINATE
|
||||
function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 )
|
||||
--self:F( { ToPointVec2, From, Event, To } )
|
||||
--self:T( { ToPointVec2, From, Event, To } )
|
||||
|
||||
local Angle = 180
|
||||
local Speed = 10
|
||||
@@ -148,7 +156,7 @@ do -- CARGO_CRATE
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function CARGO_CRATE:onenterLoaded( From, Event, To, CargoCarrier )
|
||||
--self:F( { From, Event, To, CargoCarrier } )
|
||||
--self:T( { From, Event, To, CargoCarrier } )
|
||||
|
||||
self.CargoCarrier = CargoCarrier
|
||||
|
||||
@@ -185,7 +193,7 @@ do -- CARGO_CRATE
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean true if the Cargo Crate is within the report radius.
|
||||
function CARGO_CRATE:IsInReportRadius( Coordinate )
|
||||
--self:F( { Coordinate, LoadRadius = self.LoadRadius } )
|
||||
--self:T( { Coordinate, LoadRadius = self.LoadRadius } )
|
||||
|
||||
local Distance = 0
|
||||
if self:IsUnLoaded() then
|
||||
@@ -205,7 +213,7 @@ do -- CARGO_CRATE
|
||||
-- @param Core.Point#Coordinate Coordinate
|
||||
-- @return #boolean true if the Cargo Crate is within the loading radius.
|
||||
function CARGO_CRATE:IsInLoadRadius( Coordinate )
|
||||
--self:F( { Coordinate, LoadRadius = self.NearRadius } )
|
||||
--self:T( { Coordinate, LoadRadius = self.NearRadius } )
|
||||
|
||||
local Distance = 0
|
||||
if self:IsUnLoaded() then
|
||||
@@ -226,7 +234,7 @@ do -- CARGO_CRATE
|
||||
-- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup.
|
||||
-- @return #nil There is no valid Cargo in the CargoGroup.
|
||||
function CARGO_CRATE:GetCoordinate()
|
||||
--self:F()
|
||||
--self:T()
|
||||
|
||||
return self.CargoObject:GetCoordinate()
|
||||
end
|
||||
@@ -256,7 +264,7 @@ do -- CARGO_CRATE
|
||||
-- @param #CARGO_CRATE self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
function CARGO_CRATE:RouteTo( Coordinate )
|
||||
self:F( {Coordinate = Coordinate } )
|
||||
self:T( {Coordinate = Coordinate } )
|
||||
|
||||
end
|
||||
|
||||
@@ -269,7 +277,7 @@ do -- CARGO_CRATE
|
||||
-- @return #boolean The Cargo is near to the Carrier.
|
||||
-- @return #nil The Cargo is not near to the Carrier.
|
||||
function CARGO_CRATE:IsNear( CargoCarrier, NearRadius )
|
||||
self:F( {NearRadius = NearRadius } )
|
||||
self:T( {NearRadius = NearRadius } )
|
||||
|
||||
return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius )
|
||||
end
|
||||
@@ -278,7 +286,7 @@ do -- CARGO_CRATE
|
||||
-- @param #CARGO_CRATE self
|
||||
function CARGO_CRATE:Respawn()
|
||||
|
||||
self:F( { "Respawning crate " .. self:GetName() } )
|
||||
self:T( { "Respawning crate " .. self:GetName() } )
|
||||
|
||||
|
||||
-- Respawn the group...
|
||||
@@ -295,7 +303,7 @@ do -- CARGO_CRATE
|
||||
-- @param #CARGO_CRATE self
|
||||
function CARGO_CRATE:onafterReset()
|
||||
|
||||
self:F( { "Reset crate " .. self:GetName() } )
|
||||
self:T( { "Reset crate " .. self:GetName() } )
|
||||
|
||||
|
||||
-- Respawn the group...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Cargo** - Management of grouped cargo logistics, which are based on a @{Wrapper.Group} object.
|
||||
--- **Cargo** - Management of grouped cargo logistics, which are based on a GROUP object.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -22,9 +22,12 @@ do -- CARGO_GROUP
|
||||
--- @type CARGO_GROUP
|
||||
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
|
||||
-- @field #string GroupName The name of the CargoGroup.
|
||||
-- @field Wrapper.Group#GROUÜ CargoCarrier The carrier group.
|
||||
-- @extends Cargo.Cargo#CARGO_REPORTABLE
|
||||
|
||||
--- 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 above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo:
|
||||
@@ -38,7 +41,12 @@ do -- CARGO_GROUP
|
||||
--
|
||||
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players.
|
||||
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- @field #CARGO_GROUP CARGO_GROUP
|
||||
--
|
||||
CARGO_GROUP = {
|
||||
@@ -47,7 +55,7 @@ do -- CARGO_GROUP
|
||||
|
||||
--- CARGO_GROUP constructor.
|
||||
-- This make a new CARGO_GROUP from a @{Wrapper.Group} object.
|
||||
-- It will "ungroup" the group object within the sim, and will create a @{Set} of individual Unit objects.
|
||||
-- It will "ungroup" the group object within the sim, and will create a @{Core.Set} of individual Unit objects.
|
||||
-- @param #CARGO_GROUP self
|
||||
-- @param Wrapper.Group#GROUP CargoGroup Group to be transported as cargo.
|
||||
-- @param #string Type Cargo type, e.g. "Infantry". This is the type used in SET_CARGO:New():FilterTypes("Infantry") to define the valid cargo groups of the set.
|
||||
@@ -59,7 +67,7 @@ do -- CARGO_GROUP
|
||||
|
||||
-- Inherit CAROG_REPORTABLE
|
||||
local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_GROUP
|
||||
self:F( { Type, Name, LoadRadius } )
|
||||
self:T( { Type, Name, LoadRadius } )
|
||||
|
||||
self.CargoSet = SET_CARGO:New()
|
||||
self.CargoGroup = CargoGroup
|
||||
@@ -141,7 +149,7 @@ do -- CARGO_GROUP
|
||||
-- @param #CARGO_GROUP self
|
||||
function CARGO_GROUP:Respawn()
|
||||
|
||||
self:F( { "Respawning" } )
|
||||
self:T( { "Respawning" } )
|
||||
|
||||
for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do
|
||||
local Cargo = CargoData -- Cargo.Cargo#CARGO
|
||||
@@ -222,7 +230,7 @@ do -- CARGO_GROUP
|
||||
-- @param #CARGO_GROUP self
|
||||
function CARGO_GROUP:Regroup()
|
||||
|
||||
self:F("Regroup")
|
||||
self:T("Regroup")
|
||||
|
||||
if self.Grouped == false then
|
||||
|
||||
@@ -236,7 +244,7 @@ do -- CARGO_GROUP
|
||||
for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do
|
||||
local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT
|
||||
|
||||
self:F( { CargoUnit:GetName(), UnLoaded = CargoUnit:IsUnLoaded() } )
|
||||
self:T( { CargoUnit:GetName(), UnLoaded = CargoUnit:IsUnLoaded() } )
|
||||
|
||||
if CargoUnit:IsUnLoaded() then
|
||||
|
||||
@@ -253,7 +261,7 @@ do -- CARGO_GROUP
|
||||
-- Then we register the new group in the database
|
||||
self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID )
|
||||
|
||||
self:F( { "Regroup", GroupTemplate } )
|
||||
self:T( { "Regroup", GroupTemplate } )
|
||||
|
||||
-- Now we spawn the new group based on the template created.
|
||||
self.CargoObject = _DATABASE:Spawn( GroupTemplate )
|
||||
@@ -266,7 +274,7 @@ do -- CARGO_GROUP
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function CARGO_GROUP:OnEventCargoDead( EventData )
|
||||
|
||||
self:E(EventData)
|
||||
self:T(EventData)
|
||||
|
||||
local Destroyed = false
|
||||
|
||||
@@ -291,7 +299,7 @@ do -- CARGO_GROUP
|
||||
|
||||
if Destroyed then
|
||||
self:Destroyed()
|
||||
self:E( { "Cargo group destroyed" } )
|
||||
self:T( { "Cargo group destroyed" } )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -304,14 +312,14 @@ do -- CARGO_GROUP
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||
function CARGO_GROUP:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
|
||||
self:F( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } )
|
||||
self:T( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } )
|
||||
|
||||
NearRadius = NearRadius or self.NearRadius
|
||||
|
||||
-- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2
|
||||
self.CargoSet:ForEach(
|
||||
function( Cargo, ... )
|
||||
self:F( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } )
|
||||
self:T( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } )
|
||||
local CargoGroup = Cargo.CargoObject --Wrapper.Group#GROUP
|
||||
CargoGroup:OptionAlarmStateGreen()
|
||||
Cargo:__Board( 1, CargoCarrier, NearRadius, ... )
|
||||
@@ -329,7 +337,7 @@ do -- CARGO_GROUP
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function CARGO_GROUP:onafterLoad( From, Event, To, CargoCarrier, ... )
|
||||
--self:F( { From, Event, To, CargoCarrier, ...} )
|
||||
--self:T( { From, Event, To, CargoCarrier, ...} )
|
||||
|
||||
if From == "UnLoaded" then
|
||||
-- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier.
|
||||
@@ -354,7 +362,7 @@ do -- CARGO_GROUP
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||
function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
|
||||
--self:F( { CargoCarrier.UnitName, From, Event, To } )
|
||||
--self:T( { CargoCarrier.UnitName, From, Event, To } )
|
||||
|
||||
local Boarded = true
|
||||
local Cancelled = false
|
||||
@@ -388,7 +396,7 @@ do -- CARGO_GROUP
|
||||
if not Boarded then
|
||||
self:__Boarding( -5, CargoCarrier, NearRadius, ... )
|
||||
else
|
||||
self:F("Group Cargo is loaded")
|
||||
self:T("Group Cargo is loaded")
|
||||
self:__Load( 1, CargoCarrier, ... )
|
||||
end
|
||||
else
|
||||
@@ -405,10 +413,10 @@ do -- CARGO_GROUP
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @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.
|
||||
function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... )
|
||||
self:F( {From, Event, To, ToPointVec2, NearRadius } )
|
||||
self:T( {From, Event, To, ToPointVec2, NearRadius } )
|
||||
|
||||
NearRadius = NearRadius or 25
|
||||
|
||||
@@ -448,10 +456,10 @@ do -- CARGO_GROUP
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @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.
|
||||
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
|
||||
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
--self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
|
||||
--local NearRadius = NearRadius or 25
|
||||
|
||||
@@ -486,9 +494,9 @@ do -- CARGO_GROUP
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... )
|
||||
--self:F( { From, Event, To, ToPointVec2 } )
|
||||
--self:T( { From, Event, To, ToPointVec2 } )
|
||||
|
||||
if From == "Loaded" then
|
||||
|
||||
@@ -606,7 +614,7 @@ do -- CARGO_GROUP
|
||||
-- @param #CARGO_GROUP self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
function CARGO_GROUP:RouteTo( Coordinate )
|
||||
--self:F( {Coordinate = Coordinate } )
|
||||
--self:T( {Coordinate = Coordinate } )
|
||||
|
||||
-- For each Cargo within the CargoSet, route each object to the Coordinate
|
||||
self.CargoSet:ForEach(
|
||||
@@ -624,13 +632,13 @@ do -- CARGO_GROUP
|
||||
-- @param #number NearRadius
|
||||
-- @return #boolean The Cargo is near to the Carrier or #nil if the Cargo is not near to the Carrier.
|
||||
function CARGO_GROUP:IsNear( CargoCarrier, NearRadius )
|
||||
self:F( {NearRadius = NearRadius } )
|
||||
self:T( {NearRadius = NearRadius } )
|
||||
|
||||
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||
if Cargo:IsAlive() then
|
||||
if Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) then
|
||||
self:F( "Near" )
|
||||
self:T( "Near" )
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -644,7 +652,7 @@ do -- CARGO_GROUP
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean true if the Cargo Group is within the load radius.
|
||||
function CARGO_GROUP:IsInLoadRadius( Coordinate )
|
||||
--self:F( { Coordinate } )
|
||||
--self:T( { Coordinate } )
|
||||
|
||||
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||
|
||||
@@ -664,7 +672,7 @@ do -- CARGO_GROUP
|
||||
return false
|
||||
end
|
||||
|
||||
self:F( { Distance = Distance, LoadRadius = self.LoadRadius } )
|
||||
self:T( { Distance = Distance, LoadRadius = self.LoadRadius } )
|
||||
if Distance <= self.LoadRadius then
|
||||
return true
|
||||
else
|
||||
@@ -682,12 +690,12 @@ do -- CARGO_GROUP
|
||||
-- @param Core.Point#Coordinate Coordinate
|
||||
-- @return #boolean true if the Cargo Group is within the report radius.
|
||||
function CARGO_GROUP:IsInReportRadius( Coordinate )
|
||||
--self:F( { Coordinate } )
|
||||
--self:T( { Coordinate } )
|
||||
|
||||
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||
|
||||
if Cargo then
|
||||
self:F( { Cargo } )
|
||||
self:T( { Cargo } )
|
||||
local Distance = 0
|
||||
if Cargo:IsUnLoaded() then
|
||||
Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() )
|
||||
@@ -727,13 +735,13 @@ do -- CARGO_GROUP
|
||||
end
|
||||
end
|
||||
|
||||
--- Check if the first element of the CargoGroup is the given @{Zone}.
|
||||
--- Check if the first element of the CargoGroup is the given @{Core.Zone}.
|
||||
-- @param #CARGO_GROUP self
|
||||
-- @param Core.Zone#ZONE_BASE Zone
|
||||
-- @return #boolean **true** if the first element of the CargoGroup is in the Zone
|
||||
-- @return #boolean **false** if there is no element of the CargoGroup in the Zone.
|
||||
function CARGO_GROUP:IsInZone( Zone )
|
||||
--self:F( { Zone } )
|
||||
--self:T( { Zone } )
|
||||
|
||||
local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO
|
||||
|
||||
@@ -766,3 +774,4 @@ do -- CARGO_GROUP
|
||||
|
||||
|
||||
end -- CARGO_GROUP
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. The cargo can only be slingloaded.
|
||||
--- **Cargo** - Management of single cargo crates, which are based on a STATIC object. The cargo can only be slingloaded.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -29,7 +29,14 @@ do -- CARGO_SLINGLOAD
|
||||
--
|
||||
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players.
|
||||
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #CARGO_SLINGLOAD
|
||||
@@ -47,7 +54,7 @@ do -- CARGO_SLINGLOAD
|
||||
-- @return #CARGO_SLINGLOAD
|
||||
function CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
|
||||
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_SLINGLOAD
|
||||
self:F( { Type, Name, NearRadius } )
|
||||
self:T( { Type, Name, NearRadius } )
|
||||
|
||||
self.CargoObject = CargoStatic
|
||||
|
||||
@@ -125,7 +132,7 @@ do -- CARGO_SLINGLOAD
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean true if the Cargo Crate is within the report radius.
|
||||
function CARGO_SLINGLOAD:IsInReportRadius( Coordinate )
|
||||
--self:F( { Coordinate, LoadRadius = self.LoadRadius } )
|
||||
--self:T( { Coordinate, LoadRadius = self.LoadRadius } )
|
||||
|
||||
local Distance = 0
|
||||
if self:IsUnLoaded() then
|
||||
@@ -144,7 +151,7 @@ do -- CARGO_SLINGLOAD
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean true if the Cargo Slingload is within the loading radius.
|
||||
function CARGO_SLINGLOAD:IsInLoadRadius( Coordinate )
|
||||
--self:F( { Coordinate } )
|
||||
--self:T( { Coordinate } )
|
||||
|
||||
local Distance = 0
|
||||
if self:IsUnLoaded() then
|
||||
@@ -164,7 +171,7 @@ do -- CARGO_SLINGLOAD
|
||||
-- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup.
|
||||
-- @return #nil There is no valid Cargo in the CargoGroup.
|
||||
function CARGO_SLINGLOAD:GetCoordinate()
|
||||
--self:F()
|
||||
--self:T()
|
||||
|
||||
return self.CargoObject:GetCoordinate()
|
||||
end
|
||||
@@ -194,7 +201,7 @@ do -- CARGO_SLINGLOAD
|
||||
-- @param #CARGO_SLINGLOAD self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
function CARGO_SLINGLOAD:RouteTo( Coordinate )
|
||||
--self:F( {Coordinate = Coordinate } )
|
||||
--self:T( {Coordinate = Coordinate } )
|
||||
|
||||
end
|
||||
|
||||
@@ -207,7 +214,7 @@ do -- CARGO_SLINGLOAD
|
||||
-- @return #boolean The Cargo is near to the Carrier.
|
||||
-- @return #nil The Cargo is not near to the Carrier.
|
||||
function CARGO_SLINGLOAD:IsNear( CargoCarrier, NearRadius )
|
||||
--self:F( {NearRadius = NearRadius } )
|
||||
--self:T( {NearRadius = NearRadius } )
|
||||
|
||||
return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius )
|
||||
end
|
||||
@@ -217,7 +224,7 @@ do -- CARGO_SLINGLOAD
|
||||
-- @param #CARGO_SLINGLOAD self
|
||||
function CARGO_SLINGLOAD:Respawn()
|
||||
|
||||
--self:F( { "Respawning slingload " .. self:GetName() } )
|
||||
--self:T( { "Respawning slingload " .. self:GetName() } )
|
||||
|
||||
|
||||
-- Respawn the group...
|
||||
@@ -234,7 +241,7 @@ do -- CARGO_SLINGLOAD
|
||||
-- @param #CARGO_SLINGLOAD self
|
||||
function CARGO_SLINGLOAD:onafterReset()
|
||||
|
||||
--self:F( { "Reset slingload " .. self:GetName() } )
|
||||
--self:T( { "Reset slingload " .. self:GetName() } )
|
||||
|
||||
|
||||
-- Respawn the group...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Cargo** - Management of single cargo logistics, which are based on a @{Wrapper.Unit} object.
|
||||
--- **Cargo** - Management of single cargo logistics, which are based on a UNIT object.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -27,7 +27,14 @@ do -- CARGO_UNIT
|
||||
-- Note that ground forces behave in a group, and thus, act in formation, regardless if one unit is commanded to move.
|
||||
--
|
||||
-- This class is used in CARGO_GROUP, and is not meant to be used by mission designers individually.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #CARGO_UNIT CARGO_UNIT
|
||||
@@ -67,10 +74,10 @@ do -- CARGO_UNIT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
-- @param #number NearRadius (optional) Defaut 25 m.
|
||||
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||
self:F( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
|
||||
local Angle = 180
|
||||
local Speed = 60
|
||||
@@ -109,7 +116,7 @@ do -- CARGO_UNIT
|
||||
else
|
||||
self.CargoObject:ReSpawnAt( FromPointVec2, CargoDeployHeading )
|
||||
end
|
||||
self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } )
|
||||
self:T( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } )
|
||||
self.CargoCarrier = nil
|
||||
|
||||
local Points = {}
|
||||
@@ -140,10 +147,10 @@ do -- CARGO_UNIT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
-- @param #number NearRadius (optional) Defaut 100 m.
|
||||
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||
self:F( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
|
||||
local Angle = 180
|
||||
local Speed = 10
|
||||
@@ -166,10 +173,10 @@ do -- CARGO_UNIT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||
-- @param Core.Point#COORDINATE ToPointVec2
|
||||
-- @param #number NearRadius (optional) Defaut 100 m.
|
||||
function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||
self:F( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
self:T( { From, Event, To, ToPointVec2, NearRadius } )
|
||||
|
||||
self.CargoInAir = self.CargoObject:InAir()
|
||||
|
||||
@@ -192,9 +199,9 @@ do -- CARGO_UNIT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Core.Point#POINT_VEC2
|
||||
-- @param Core.Point#COORDINATE
|
||||
function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
|
||||
self:F( { ToPointVec2, From, Event, To } )
|
||||
self:T( { ToPointVec2, From, Event, To } )
|
||||
|
||||
local Angle = 180
|
||||
local Speed = 10
|
||||
@@ -231,7 +238,7 @@ do -- CARGO_UNIT
|
||||
-- @param Wrapper.Group#GROUP CargoCarrier
|
||||
-- @param #number NearRadius
|
||||
function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
|
||||
self:F( { From, Event, To, CargoCarrier, NearRadius = NearRadius } )
|
||||
self:T( { From, Event, To, CargoCarrier, NearRadius = NearRadius } )
|
||||
|
||||
self.CargoInAir = self.CargoObject:InAir()
|
||||
|
||||
@@ -239,7 +246,7 @@ do -- CARGO_UNIT
|
||||
local MaxSpeed = Desc.speedMaxOffRoad
|
||||
local TypeName = Desc.typeName
|
||||
|
||||
--self:F({Unit=self.CargoObject:GetName()})
|
||||
--self:T({Unit=self.CargoObject:GetName()})
|
||||
|
||||
-- A cargo unit can only be boarded if it is not dead
|
||||
|
||||
@@ -293,9 +300,9 @@ do -- CARGO_UNIT
|
||||
-- @param Wrapper.Client#CLIENT CargoCarrier
|
||||
-- @param #number NearRadius Default 25 m.
|
||||
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
|
||||
self:F( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } )
|
||||
self:T( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } )
|
||||
|
||||
self:F( { IsAlive=self.CargoObject:IsAlive() } )
|
||||
self:T( { IsAlive=self.CargoObject:IsAlive() } )
|
||||
|
||||
if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then
|
||||
if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then
|
||||
@@ -316,7 +323,7 @@ do -- CARGO_UNIT
|
||||
local Angle = 180
|
||||
local Distance = 0
|
||||
|
||||
--self:F({Unit=self.CargoObject:GetName()})
|
||||
--self:T({Unit=self.CargoObject:GetName()})
|
||||
|
||||
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
|
||||
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
||||
@@ -343,7 +350,7 @@ do -- CARGO_UNIT
|
||||
self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) )
|
||||
end
|
||||
else
|
||||
self:E("Something is wrong")
|
||||
self:T("Something is wrong")
|
||||
end
|
||||
|
||||
end
|
||||
@@ -356,11 +363,11 @@ do -- CARGO_UNIT
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier )
|
||||
self:F( { From, Event, To, CargoCarrier } )
|
||||
self:T( { From, Event, To, CargoCarrier } )
|
||||
|
||||
self.CargoCarrier = CargoCarrier
|
||||
|
||||
--self:F({Unit=self.CargoObject:GetName()})
|
||||
--self:T({Unit=self.CargoObject:GetName()})
|
||||
|
||||
-- Only destroy the CargoObject if there is a CargoObject (packages don't have CargoObjects).
|
||||
if self.CargoObject then
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
--
|
||||
-- # Calculate the Path
|
||||
--
|
||||
-- Finally, we have to calculate the path. This is done by the @{ASTAR.GetPath}(*ExcludeStart, ExcludeEnd*) function. This function returns a table of nodes, which
|
||||
-- Finally, we have to calculate the path. This is done by the @{#GetPath}(*ExcludeStart, ExcludeEnd*) function. This function returns a table of nodes, which
|
||||
-- describe the optimal path from the start node to the end node.
|
||||
--
|
||||
-- By default, the start and end node are include in the table that is returned.
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
-- @module Core.Base
|
||||
-- @image Core_Base.JPG
|
||||
|
||||
local _TraceOnOff = true
|
||||
local _TraceOnOff = false -- default to no tracing
|
||||
local _TraceLevel = 1
|
||||
local _TraceAll = false
|
||||
local _TraceClass = {}
|
||||
@@ -34,10 +34,12 @@ local _TraceClassMethod = {}
|
||||
|
||||
local _ClassID = 0
|
||||
|
||||
--- @type BASE
|
||||
-- @field ClassName The name of the class.
|
||||
-- @field ClassID The ID number of the class.
|
||||
-- @field ClassNameAndID The name of the class concatenated with the ID number of the class.
|
||||
--- Base class of everything
|
||||
-- @type BASE
|
||||
-- @field #string ClassName The name of the class.
|
||||
-- @field #number ClassID 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
|
||||
--
|
||||
@@ -157,7 +159,7 @@ local _ClassID = 0
|
||||
-- self:SmokeBlue()
|
||||
-- end
|
||||
--
|
||||
-- See the @{Event} module for more information about event handling.
|
||||
-- See the @{Core.Event} module for more information about event handling.
|
||||
--
|
||||
-- # 4. Class identification methods.
|
||||
--
|
||||
@@ -199,24 +201,17 @@ BASE = {
|
||||
States = {},
|
||||
Debug = debug,
|
||||
Scheduler = nil,
|
||||
Properties = {},
|
||||
}
|
||||
|
||||
--- @field #BASE.__
|
||||
-- @field #BASE.__
|
||||
BASE.__ = {}
|
||||
|
||||
--- @field #BASE._
|
||||
-- @field #BASE._
|
||||
BASE._ = {
|
||||
Schedules = {}, --- Contains the Schedulers Active
|
||||
}
|
||||
|
||||
--- The Formation Class
|
||||
-- @type FORMATION
|
||||
-- @field Cone A cone formation.
|
||||
FORMATION = {
|
||||
Cone = "Cone",
|
||||
Vee = "Vee",
|
||||
}
|
||||
|
||||
--- BASE constructor.
|
||||
--
|
||||
-- This is an example how to use the BASE:New() constructor in a new class definition when inheriting from BASE.
|
||||
@@ -229,7 +224,7 @@ FORMATION = {
|
||||
-- @param #BASE self
|
||||
-- @return #BASE
|
||||
function BASE:New()
|
||||
--local self = routines.utils.deepCopy( self ) -- Create a new self instance
|
||||
--local self = UTILS.DeepCopy( self ) -- Create a new self instance
|
||||
local self = UTILS.DeepCopy(self)
|
||||
|
||||
_ClassID = _ClassID + 1
|
||||
@@ -252,7 +247,7 @@ end
|
||||
function BASE:Inherit( Child, Parent )
|
||||
|
||||
-- Create child.
|
||||
local Child = routines.utils.deepCopy( Child )
|
||||
local Child = UTILS.DeepCopy( Child )
|
||||
|
||||
if Child ~= nil then
|
||||
|
||||
@@ -412,20 +407,20 @@ do -- Event Handling
|
||||
return _EVENTDISPATCHER
|
||||
end
|
||||
|
||||
--- Get the Class @{Event} processing Priority.
|
||||
--- Get the Class @{Core.Event} processing Priority.
|
||||
-- The Event processing Priority is a number from 1 to 10,
|
||||
-- reflecting the order of the classes subscribed to the Event to be processed.
|
||||
-- @param #BASE self
|
||||
-- @return #number The @{Event} processing Priority.
|
||||
-- @return #number The @{Core.Event} processing Priority.
|
||||
function BASE:GetEventPriority()
|
||||
return self._.EventPriority or 5
|
||||
end
|
||||
|
||||
--- Set the Class @{Event} processing Priority.
|
||||
--- Set the Class @{Core.Event} processing Priority.
|
||||
-- The Event processing Priority is a number from 1 to 10,
|
||||
-- reflecting the order of the classes subscribed to the Event to be processed.
|
||||
-- @param #BASE self
|
||||
-- @param #number EventPriority The @{Event} processing Priority.
|
||||
-- @param #number EventPriority The @{Core.Event} processing Priority.
|
||||
-- @return #BASE self
|
||||
function BASE:SetEventPriority( EventPriority )
|
||||
self._.EventPriority = EventPriority
|
||||
@@ -464,16 +459,16 @@ do -- Event Handling
|
||||
return self
|
||||
end
|
||||
|
||||
-- Event handling function prototypes - Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Event handling function prototypes - Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
|
||||
--- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or autocannon based weapon, those are handled by EVENT.ShootingStart.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventShot
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs whenever an object is hit by a weapon.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit object the fired the weapon
|
||||
-- weapon: Weapon object that hit the target
|
||||
-- target: The Object that was hit.
|
||||
@@ -482,7 +477,7 @@ do -- Event Handling
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when an aircraft takes off from an airbase, farp, or ship.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that tookoff
|
||||
-- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships
|
||||
-- @function [parent=#BASE] OnEventTakeoff
|
||||
@@ -490,7 +485,7 @@ do -- Event Handling
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when an aircraft lands at an airbase, farp or ship
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that has landed
|
||||
-- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships
|
||||
-- @function [parent=#BASE] OnEventLand
|
||||
@@ -498,49 +493,49 @@ do -- Event Handling
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any aircraft crashes into the ground and is completely destroyed.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that has crashed
|
||||
-- @function [parent=#BASE] OnEventCrash
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a pilot ejects from an aircraft
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that has ejected
|
||||
-- @function [parent=#BASE] OnEventEjection
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when an aircraft connects with a tanker and begins taking on fuel.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that is receiving fuel.
|
||||
-- @function [parent=#BASE] OnEventRefueling
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when an object is dead.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that is dead.
|
||||
-- @function [parent=#BASE] OnEventDead
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when an Event for an object is triggered.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that triggered the event.
|
||||
-- @function [parent=#BASE] OnEvent
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when the pilot of an aircraft is killed. Can occur either if the player is alive and crashes or if a weapon kills the pilot without completely destroying the plane.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that the pilot has died in.
|
||||
-- @function [parent=#BASE] OnEventPilotDead
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a ground unit captures either an airbase or a farp.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that captured the base
|
||||
-- place: The airbase that was captured, can be a FARP or Airbase. When calling place:getCoalition() the faction will already be the new owning faction.
|
||||
-- @function [parent=#BASE] OnEventBaseCaptured
|
||||
@@ -548,68 +543,68 @@ do -- Event Handling
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a mission starts
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventMissionStart
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a mission ends
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventMissionEnd
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when an aircraft is finished taking fuel.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that was receiving fuel.
|
||||
-- @function [parent=#BASE] OnEventRefuelingStop
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any object is spawned into the mission.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that was spawned
|
||||
-- @function [parent=#BASE] OnEventBirth
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any system fails on a human controlled aircraft.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that had the failure
|
||||
-- @function [parent=#BASE] OnEventHumanFailure
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any aircraft starts its engines.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that is starting its engines.
|
||||
-- @function [parent=#BASE] OnEventEngineStartup
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any aircraft shuts down its engines.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that is stopping its engines.
|
||||
-- @function [parent=#BASE] OnEventEngineShutdown
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any player assumes direct control of a unit. Note - not Mulitplayer safe. Use PlayerEnterAircraft.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that is being taken control of.
|
||||
-- @function [parent=#BASE] OnEventPlayerEnterUnit
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any player relieves control of a unit to the AI.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that the player left.
|
||||
-- @function [parent=#BASE] OnEventPlayerLeaveUnit
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), autocannons, and machine guns.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that is doing the shooting.
|
||||
-- target: The unit that is being targeted.
|
||||
-- @function [parent=#BASE] OnEventShootingStart
|
||||
@@ -617,28 +612,28 @@ do -- Event Handling
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any unit stops firing its weapon. Event will always correspond with a shooting start event.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- initiator : The unit that was doing the shooting.
|
||||
-- @function [parent=#BASE] OnEventShootingEnd
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a new mark was added.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- MarkID: ID of the mark.
|
||||
-- @function [parent=#BASE] OnEventMarkAdded
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a mark was removed.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- MarkID: ID of the mark.
|
||||
-- @function [parent=#BASE] OnEventMarkRemoved
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a mark text was changed.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- MarkID: ID of the mark.
|
||||
-- @function [parent=#BASE] OnEventMarkChange
|
||||
-- @param #BASE self
|
||||
@@ -654,13 +649,13 @@ do -- Event Handling
|
||||
|
||||
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
|
||||
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventScore
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs on the death of a unit. Contains more and different information. Similar to unit_lost it will occur for aircraft before the aircraft crash event occurs.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
--
|
||||
-- * initiator: The unit that killed the target
|
||||
-- * target: Target Object
|
||||
@@ -672,13 +667,13 @@ do -- Event Handling
|
||||
|
||||
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
|
||||
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventScore
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when the game thinks an object is destroyed.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
--
|
||||
-- * initiator: The unit that is was destroyed.
|
||||
--
|
||||
@@ -687,7 +682,7 @@ do -- Event Handling
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs shortly after the landing animation of an ejected pilot touching the ground and standing up. Event does not occur if the pilot lands in the water and sub combs to Davey Jones Locker.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
--
|
||||
-- * initiator: Static object representing the ejected pilot. Place : Aircraft that the pilot ejected from.
|
||||
-- * place: may not return as a valid object if the aircraft has crashed into the ground and no longer exists.
|
||||
@@ -698,49 +693,73 @@ do -- Event Handling
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Paratrooper landing.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventParatrooperLanding
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Discard chair after ejection.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventDiscardChairAfterEjection
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Weapon add. Fires when entering a mission per pylon with the name of the weapon (double pylons not counted, infinite wep reload not counted.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventParatrooperLanding
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Trigger zone.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventTriggerZone
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Landing quality mark.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventLandingQualityMark
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- BDA.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- @function [parent=#BASE] OnEventBDA
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a player enters a slot and takes control of an aircraft.
|
||||
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||
-- **NOTE**: This is a workaround of a long standing DCS bug with the PLAYER_ENTER_UNIT event.
|
||||
-- initiator : The unit that is being taken control of.
|
||||
-- @function [parent=#BASE] OnEventPlayerEnterAircraft
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
|
||||
--- Occurs when a player creates a dynamic cargo object from the F8 ground crew menu.
|
||||
-- *** NOTE *** this is a workarounf for DCS not creating these events as of Aug 2024.
|
||||
-- @function [parent=#BASE] OnEventNewDynamicCargo
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a player loads a dynamic cargo object with the F8 ground crew menu into a helo.
|
||||
-- *** NOTE *** this is a workarounf for DCS not creating these events as of Aug 2024.
|
||||
-- @function [parent=#BASE] OnEventDynamicCargoLoaded
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a player unloads a dynamic cargo object with the F8 ground crew menu from a helo.
|
||||
-- *** NOTE *** this is a workarounf for DCS not creating these events as of Aug 2024.
|
||||
-- @function [parent=#BASE] OnEventDynamicCargoUnloaded
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a dynamic cargo crate is removed.
|
||||
-- *** NOTE *** this is a workarounf for DCS not creating these events as of Aug 2024.
|
||||
-- @function [parent=#BASE] OnEventDynamicCargoRemoved
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
end
|
||||
|
||||
--- Creation of a Birth Event.
|
||||
@@ -861,6 +880,62 @@ end
|
||||
|
||||
world.onEvent(Event)
|
||||
end
|
||||
|
||||
--- Creation of a S_EVENT_NEW_DYNAMIC_CARGO event.
|
||||
-- @param #BASE self
|
||||
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
|
||||
function BASE:CreateEventNewDynamicCargo(DynamicCargo)
|
||||
self:F({DynamicCargo})
|
||||
local Event = {
|
||||
id = EVENTS.NewDynamicCargo,
|
||||
time = timer.getTime(),
|
||||
dynamiccargo = DynamicCargo,
|
||||
initiator = DynamicCargo:GetDCSObject(),
|
||||
}
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a S_EVENT_DYNAMIC_CARGO_LOADED event.
|
||||
-- @param #BASE self
|
||||
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
|
||||
function BASE:CreateEventDynamicCargoLoaded(DynamicCargo)
|
||||
self:F({DynamicCargo})
|
||||
local Event = {
|
||||
id = EVENTS.DynamicCargoLoaded,
|
||||
time = timer.getTime(),
|
||||
dynamiccargo = DynamicCargo,
|
||||
initiator = DynamicCargo:GetDCSObject(),
|
||||
}
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a S_EVENT_DYNAMIC_CARGO_UNLOADED event.
|
||||
-- @param #BASE self
|
||||
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
|
||||
function BASE:CreateEventDynamicCargoUnloaded(DynamicCargo)
|
||||
self:F({DynamicCargo})
|
||||
local Event = {
|
||||
id = EVENTS.DynamicCargoUnloaded,
|
||||
time = timer.getTime(),
|
||||
dynamiccargo = DynamicCargo,
|
||||
initiator = DynamicCargo:GetDCSObject(),
|
||||
}
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a S_EVENT_DYNAMIC_CARGO_REMOVED event.
|
||||
-- @param #BASE self
|
||||
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
|
||||
function BASE:CreateEventDynamicCargoRemoved(DynamicCargo)
|
||||
self:F({DynamicCargo})
|
||||
local Event = {
|
||||
id = EVENTS.DynamicCargoRemoved,
|
||||
time = timer.getTime(),
|
||||
dynamiccargo = DynamicCargo,
|
||||
initiator = DynamicCargo:GetDCSObject(),
|
||||
}
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- The main event handling function... This function captures all events generated for the class.
|
||||
-- @param #BASE self
|
||||
@@ -899,7 +974,7 @@ do -- Scheduling
|
||||
-- @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 #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.
|
||||
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
||||
|
||||
@@ -1035,6 +1110,31 @@ function BASE:ClearState( Object, StateName )
|
||||
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
|
||||
|
||||
-- Log a trace (only shown when trace is on)
|
||||
@@ -1143,6 +1243,28 @@ function BASE:TraceClassMethod( Class, Method )
|
||||
self:I( "Tracing method " .. Method .. " of class " .. Class )
|
||||
end
|
||||
|
||||
--- (Internal) Serialize arguments
|
||||
-- @param #BASE self
|
||||
-- @param #table Arguments
|
||||
-- @return #string Text
|
||||
function BASE:_Serialize(Arguments)
|
||||
local text = UTILS.PrintTableToLog({Arguments}, 0, true)
|
||||
text = string.gsub(text,"(\n+)","")
|
||||
text = string.gsub(text,"%(%(","%(")
|
||||
text = string.gsub(text,"%)%)","%)")
|
||||
text = string.gsub(text,"(%s+)"," ")
|
||||
return text
|
||||
end
|
||||
|
||||
----- (Internal) Serialize arguments
|
||||
---- @param #BASE self
|
||||
---- @param #table Arguments
|
||||
---- @return #string Text
|
||||
--function BASE:_Serialize(Arguments)
|
||||
-- local text=UTILS.BasicSerialize(Arguments)
|
||||
-- return text
|
||||
--end
|
||||
|
||||
--- Trace a function call. This function is private.
|
||||
-- @param #BASE self
|
||||
-- @param Arguments A #table or any field.
|
||||
@@ -1167,7 +1289,7 @@ function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
||||
if DebugInfoFrom then
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, BASE:_Serialize(Arguments) ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1177,7 +1299,7 @@ end
|
||||
-- @param Arguments A #table or any field.
|
||||
function BASE:F( Arguments )
|
||||
|
||||
if BASE.Debug and _TraceOnOff then
|
||||
if BASE.Debug and _TraceOnOff == true then
|
||||
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||
|
||||
@@ -1192,7 +1314,7 @@ end
|
||||
-- @param Arguments A #table or any field.
|
||||
function BASE:F2( Arguments )
|
||||
|
||||
if BASE.Debug and _TraceOnOff then
|
||||
if BASE.Debug and _TraceOnOff == true and _TraceLevel >= 2 then
|
||||
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||
|
||||
@@ -1207,7 +1329,7 @@ end
|
||||
-- @param Arguments A #table or any field.
|
||||
function BASE:F3( Arguments )
|
||||
|
||||
if BASE.Debug and _TraceOnOff then
|
||||
if BASE.Debug and _TraceOnOff == true and _TraceLevel >= 3 then
|
||||
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||
|
||||
@@ -1241,7 +1363,7 @@ function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
||||
if DebugInfoFrom then
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s", LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s", LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, BASE:_Serialize(Arguments) ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1251,7 +1373,7 @@ end
|
||||
-- @param Arguments A #table or any field.
|
||||
function BASE:T( Arguments )
|
||||
|
||||
if BASE.Debug and _TraceOnOff then
|
||||
if BASE.Debug and _TraceOnOff == true then
|
||||
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||
|
||||
@@ -1266,7 +1388,7 @@ end
|
||||
-- @param Arguments A #table or any field.
|
||||
function BASE:T2( Arguments )
|
||||
|
||||
if BASE.Debug and _TraceOnOff then
|
||||
if BASE.Debug and _TraceOnOff == true and _TraceLevel >= 2 then
|
||||
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||
|
||||
@@ -1281,7 +1403,7 @@ end
|
||||
-- @param Arguments A #table or any field.
|
||||
function BASE:T3( Arguments )
|
||||
|
||||
if BASE.Debug and _TraceOnOff then
|
||||
if BASE.Debug and _TraceOnOff == true and _TraceLevel >= 3 then
|
||||
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||
|
||||
@@ -1311,9 +1433,9 @@ function BASE:E( Arguments )
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
||||
else
|
||||
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, UTILS.BasicSerialize(Arguments) ) )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1338,41 +1460,9 @@ function BASE:I( Arguments )
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
||||
else
|
||||
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, UTILS.BasicSerialize(Arguments)) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- old stuff
|
||||
|
||||
-- function BASE:_Destructor()
|
||||
-- --self:E("_Destructor")
|
||||
--
|
||||
-- --self:EventRemoveAll()
|
||||
-- end
|
||||
|
||||
-- THIS IS WHY WE NEED LUA 5.2 ...
|
||||
-- function BASE:_SetDestructor()
|
||||
--
|
||||
-- -- TODO: Okay, this is really technical...
|
||||
-- -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
|
||||
-- -- Therefore, I am parking this logic until I've properly discussed all this with the community.
|
||||
--
|
||||
-- local proxy = newproxy(true)
|
||||
-- local proxyMeta = getmetatable(proxy)
|
||||
--
|
||||
-- proxyMeta.__gc = function ()
|
||||
-- env.info("In __gc for " .. self:GetClassNameAndID() )
|
||||
-- if self._Destructor then
|
||||
-- self:_Destructor()
|
||||
-- end
|
||||
-- end
|
||||
--
|
||||
-- -- keep the userdata from newproxy reachable until the object
|
||||
-- -- table is about to be garbage-collected - then the __gc hook
|
||||
-- -- will be invoked and the destructor called
|
||||
-- rawset( self, '__proxy', proxy )
|
||||
--
|
||||
-- end
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Core/Beacon)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: Hugues "Grey_Echo" Bousquet, funkyfranky
|
||||
--
|
||||
-- @module Core.Beacon
|
||||
@@ -17,8 +21,8 @@
|
||||
--
|
||||
-- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
|
||||
-- There are two types of BEACONs available : the (aircraft) TACAN Beacon and the general purpose Radio Beacon.
|
||||
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very usefull to simulate the battery time if your BEACON is
|
||||
-- attach to a cargo crate, for exemple.
|
||||
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very useful to simulate the battery time if your BEACON is
|
||||
-- attach to a cargo crate, for example.
|
||||
--
|
||||
-- ## Aircraft TACAN Beacon usage
|
||||
--
|
||||
@@ -33,12 +37,14 @@
|
||||
--
|
||||
-- @type BEACON
|
||||
-- @field #string ClassName Name of the class "BEACON".
|
||||
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will receive radio capabilities.
|
||||
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{Wrapper.Controllable#CONTROLLABLE} that will receive radio capabilities.
|
||||
-- @field #number UniqueName Counter to make the unique naming work.
|
||||
-- @extends Core.Base#BASE
|
||||
BEACON = {
|
||||
ClassName = "BEACON",
|
||||
Positionable = nil,
|
||||
name = nil,
|
||||
UniqueName = 0,
|
||||
}
|
||||
|
||||
--- Beacon types supported by DCS.
|
||||
@@ -72,12 +78,12 @@ BEACON.Type={
|
||||
TACAN = 4,
|
||||
VORTAC = 5,
|
||||
RSBN = 128,
|
||||
BROADCAST_STATION = 1024,
|
||||
BROADCAST_STATION = 1024,
|
||||
HOMER = 8,
|
||||
AIRPORT_HOMER = 4104,
|
||||
AIRPORT_HOMER_WITH_MARKER = 4136,
|
||||
AIRPORT_HOMER = 4104,
|
||||
AIRPORT_HOMER_WITH_MARKER = 4136,
|
||||
ILS_FAR_HOMER = 16408,
|
||||
ILS_NEAR_HOMER = 16424,
|
||||
ILS_NEAR_HOMER = 16424,
|
||||
ILS_LOCALIZER = 16640,
|
||||
ILS_GLIDESLOPE = 16896,
|
||||
PRMG_LOCALIZER = 33024,
|
||||
@@ -108,13 +114,13 @@ BEACON.Type={
|
||||
-- @field #number ICLS_LOCALIZER Carrier landing system.
|
||||
-- @field #number ICLS_GLIDESLOPE Carrier landing system.
|
||||
BEACON.System={
|
||||
PAR_10 = 1,
|
||||
RSBN_5 = 2,
|
||||
TACAN = 3,
|
||||
PAR_10 = 1,
|
||||
RSBN_5 = 2,
|
||||
TACAN = 3,
|
||||
TACAN_TANKER_X = 4,
|
||||
TACAN_TANKER_Y = 5,
|
||||
VOR = 6,
|
||||
ILS_LOCALIZER = 7,
|
||||
VOR = 6,
|
||||
ILS_LOCALIZER = 7,
|
||||
ILS_GLIDESLOPE = 8,
|
||||
PRMG_LOCALIZER = 9,
|
||||
PRMG_GLIDESLOPE = 10,
|
||||
@@ -130,16 +136,16 @@ BEACON.System={
|
||||
--- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.ActivateTACAN} etc.
|
||||
-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead.
|
||||
-- @param #BEACON self
|
||||
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
||||
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Wrapper.Positionable} that will receive radio capabilities.
|
||||
-- @return #BEACON Beacon object or #nil if the positionable is invalid.
|
||||
function BEACON:New(Positionable)
|
||||
|
||||
-- Inherit BASE.
|
||||
local self=BASE:Inherit(self, BASE:New()) --#BEACON
|
||||
|
||||
|
||||
-- Debug.
|
||||
self:F(Positionable)
|
||||
|
||||
|
||||
-- Set positionable.
|
||||
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
|
||||
self.Positionable = Positionable
|
||||
@@ -147,12 +153,11 @@ function BEACON:New(Positionable)
|
||||
self:I(string.format("New BEACON %s", tostring(self.name)))
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
self:E({"The passed positionable is invalid, no BEACON created", Positionable})
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Activates a TACAN BEACON.
|
||||
-- @param #BEACON self
|
||||
-- @param #number Channel TACAN channel, i.e. the "10" part in "10Y".
|
||||
@@ -169,28 +174,28 @@ end
|
||||
-- myBeacon:ActivateTACAN(20, "Y", "TEXACO", true) -- Activate the beacon
|
||||
function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
|
||||
self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration})
|
||||
|
||||
|
||||
Mode=Mode or "Y"
|
||||
|
||||
|
||||
-- Get frequency.
|
||||
local Frequency=UTILS.TACANToFrequency(Channel, Mode)
|
||||
|
||||
|
||||
-- Check.
|
||||
if not Frequency then
|
||||
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"})
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
-- Beacon type.
|
||||
local Type=BEACON.Type.TACAN
|
||||
|
||||
|
||||
-- Beacon system.
|
||||
local System=BEACON.System.TACAN
|
||||
|
||||
|
||||
-- Check if unit is an aircraft and set system accordingly.
|
||||
local AA=self.Positionable:IsAir()
|
||||
|
||||
|
||||
|
||||
|
||||
if AA then
|
||||
System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
|
||||
-- Check if "Y" mode is selected for aircraft.
|
||||
@@ -201,21 +206,21 @@ function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
|
||||
System=BEACON.System.TACAN_TANKER_Y
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Attached unit.
|
||||
local UnitID=self.Positionable:GetID()
|
||||
|
||||
|
||||
-- Debug.
|
||||
self:I({string.format("BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring(self.name), Channel, Mode, Message, tostring(Bearing), tostring(Duration))})
|
||||
|
||||
|
||||
-- Start beacon.
|
||||
self.Positionable:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing)
|
||||
|
||||
|
||||
-- Stop scheduler.
|
||||
if Duration then
|
||||
self.Positionable:DeactivateBeacon(Duration)
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -227,21 +232,21 @@ end
|
||||
-- @return #BEACON self
|
||||
function BEACON:ActivateICLS(Channel, Callsign, Duration)
|
||||
self:F({Channel=Channel, Callsign=Callsign, Duration=Duration})
|
||||
|
||||
|
||||
-- Attached unit.
|
||||
local UnitID=self.Positionable:GetID()
|
||||
|
||||
|
||||
-- Debug
|
||||
self:T2({"ICLS BEACON started!"})
|
||||
|
||||
|
||||
-- Start beacon.
|
||||
self.Positionable:CommandActivateICLS(Channel, UnitID, Callsign)
|
||||
|
||||
|
||||
-- Stop scheduler
|
||||
if Duration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
self.Positionable:DeactivateBeacon(Duration)
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -253,25 +258,25 @@ end
|
||||
-- @return #BEACON self
|
||||
function BEACON:ActivateLink4(Frequency, Morse, Duration)
|
||||
self:F({Frequency=Frequency, Morse=Morse, Duration=Duration})
|
||||
|
||||
|
||||
-- Attached unit.
|
||||
local UnitID=self.Positionable:GetID()
|
||||
|
||||
|
||||
-- Debug
|
||||
self:T2({"LINK4 BEACON started!"})
|
||||
|
||||
|
||||
-- Start beacon.
|
||||
self.Positionable:CommandActivateLink4(Frequency,UnitID,Morse)
|
||||
|
||||
|
||||
-- Stop sheduler
|
||||
if Duration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
self.Positionable:CommandDeactivateLink4(Duration)
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- DEPRECATED: Please use @{BEACON:ActivateTACAN}() instead.
|
||||
--- DEPRECATED: Please use @{#BEACON.ActivateTACAN}() instead.
|
||||
-- Activates a TACAN BEACON on an Aircraft.
|
||||
-- @param #BEACON self
|
||||
-- @param #number TACANChannel (the "10" part in "10Y"). Note that AA TACAN are only available on Y Channels
|
||||
@@ -287,20 +292,21 @@ end
|
||||
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
||||
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||
self:F({TACANChannel, Message, Bearing, BeaconDuration})
|
||||
|
||||
self:E("This method is DEPRECATED! Please use ActivateTACAN() instead.")
|
||||
|
||||
local IsValid = true
|
||||
|
||||
|
||||
if not self.Positionable:IsAir() then
|
||||
self:E({"The POSITIONABLE you want to attach the AA Tacan Beacon is not an aircraft ! The BEACON is not emitting", self.Positionable})
|
||||
IsValid = false
|
||||
end
|
||||
|
||||
|
||||
local Frequency = self:_TACANToFrequency(TACANChannel, "Y")
|
||||
if not Frequency then
|
||||
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"})
|
||||
IsValid = false
|
||||
end
|
||||
|
||||
|
||||
-- I'm using the beacon type 4 (BEACON_TYPE_TACAN). For System, I'm using 5 (TACAN_TANKER_MODE_Y) if the bearing shows its bearing or 14 (TACAN_AA_MODE_Y) if it does not
|
||||
local System
|
||||
if Bearing then
|
||||
@@ -308,7 +314,7 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||
else
|
||||
System = BEACON.System.TACAN_AA_MODE_Y
|
||||
end
|
||||
|
||||
|
||||
if IsValid then -- Starts the BEACON
|
||||
self:T2({"AA TACAN BEACON started !"})
|
||||
self.Positionable:SetCommand({
|
||||
@@ -323,7 +329,7 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||
modeChannel = "Y",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
SCHEDULER:New(nil,
|
||||
function()
|
||||
@@ -331,7 +337,7 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||
end, {}, BeaconDuration)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -351,7 +357,6 @@ function BEACON:StopAATACAN()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Activates a general purpose Radio Beacon
|
||||
-- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency.
|
||||
-- Although any frequency could be used, only a few DCS Modules can home on radio beacons at the time of writing, i.e. the Mi-8, Huey, Gazelle etc.
|
||||
@@ -382,6 +387,8 @@ function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDurati
|
||||
self:F({FileName, Frequency, Modulation, Power, BeaconDuration})
|
||||
local IsValid = false
|
||||
|
||||
Modulation = Modulation or radio.modulation.AM
|
||||
|
||||
-- Check the filename
|
||||
if type(FileName) == "string" then
|
||||
if FileName:find(".ogg") or FileName:find(".wav") then
|
||||
@@ -392,41 +399,44 @@ function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDurati
|
||||
end
|
||||
end
|
||||
if not IsValid then
|
||||
self:E({"File name invalid. Maybe something wrong with the extension ? ", FileName})
|
||||
self:E({"File name invalid. Maybe something wrong with the extension? ", FileName})
|
||||
end
|
||||
|
||||
|
||||
-- Check the Frequency
|
||||
if type(Frequency) ~= "number" and IsValid then
|
||||
self:E({"Frequency invalid. ", Frequency})
|
||||
IsValid = false
|
||||
end
|
||||
Frequency = Frequency * 1000000 -- Conversion to Hz
|
||||
|
||||
|
||||
-- Check the modulation
|
||||
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then --TODO Maybe make this future proof if ED decides to add an other modulation ?
|
||||
self:E({"Modulation is invalid. Use DCS's enum radio.modulation.", Modulation})
|
||||
IsValid = false
|
||||
end
|
||||
|
||||
|
||||
-- Check the Power
|
||||
if type(Power) ~= "number" and IsValid then
|
||||
self:E({"Power is invalid. ", Power})
|
||||
IsValid = false
|
||||
end
|
||||
Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that
|
||||
|
||||
|
||||
if IsValid then
|
||||
self:T2({"Activating Beacon on ", Frequency, Modulation})
|
||||
-- Note that this is looped. I have to give this transmission a unique name, I use the class ID
|
||||
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring(self.ID))
|
||||
|
||||
BEACON.UniqueName = BEACON.UniqueName + 1
|
||||
self.BeaconName = "MooseBeacon"..tostring(BEACON.UniqueName)
|
||||
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, self.BeaconName)
|
||||
|
||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
SCHEDULER:New( nil,
|
||||
function()
|
||||
self:StopRadioBeacon()
|
||||
end, {}, BeaconDuration)
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stops the Radio Beacon
|
||||
@@ -435,7 +445,7 @@ end
|
||||
function BEACON:StopRadioBeacon()
|
||||
self:F()
|
||||
-- The unique name of the transmission is the class ID
|
||||
trigger.action.stopRadioTransmission(tostring(self.ID))
|
||||
trigger.action.stopRadioTransmission(self.BeaconName)
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -453,16 +463,16 @@ function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
|
||||
return nil -- error in arguments
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
|
||||
-- I have no idea what it does but it seems to work
|
||||
local A = 1151 -- 'X', channel >= 64
|
||||
local B = 64 -- channel >= 64
|
||||
|
||||
|
||||
if TACANChannel < 64 then
|
||||
B = 1
|
||||
end
|
||||
|
||||
|
||||
if TACANMode == 'Y' then
|
||||
A = 1025
|
||||
if TACANChannel < 64 then
|
||||
@@ -473,6 +483,6 @@ function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
|
||||
A = 962
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return (A + TACANChannel - B) * 1000000
|
||||
end
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
--
|
||||
-- ## Example Missions:
|
||||
--
|
||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Operation).
|
||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Core/Condition).
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -17,17 +17,21 @@
|
||||
--
|
||||
-- ===
|
||||
-- @module Core.Condition
|
||||
-- @image Core_Conditon.png
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
--- CONDITON class.
|
||||
-- @type CONDITION
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #string name Name of the condition.
|
||||
-- @field #boolean isAny General functions are evaluated as any condition.
|
||||
-- @field #boolean negateResult Negeate result of evaluation.
|
||||
-- @field #boolean negateResult Negate result of evaluation.
|
||||
-- @field #boolean noneResult Boolean that is returned if no condition functions at all were specified.
|
||||
-- @field #table functionsGen General condition functions.
|
||||
-- @field #table functionsAny Any condition functions.
|
||||
-- @field #table functionsAll All condition functions.
|
||||
-- @field #number functionCounter Running number to determine the unique ID of condition functions.
|
||||
-- @field #boolean defaultPersist Default persistence of condition functions.
|
||||
--
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
@@ -41,27 +45,34 @@
|
||||
--
|
||||
-- @field #CONDITION
|
||||
CONDITION = {
|
||||
ClassName = "CONDITION",
|
||||
lid = nil,
|
||||
functionsGen = {},
|
||||
functionsAny = {},
|
||||
functionsAll = {},
|
||||
ClassName = "CONDITION",
|
||||
lid = nil,
|
||||
functionsGen = {},
|
||||
functionsAny = {},
|
||||
functionsAll = {},
|
||||
functionCounter = 0,
|
||||
defaultPersist = false,
|
||||
}
|
||||
|
||||
--- Condition function.
|
||||
-- @type CONDITION.Function
|
||||
-- @field #function func Callback function to check for a condition. Should return a `#boolean`.
|
||||
-- @field #number uid Unique ID of the condition function.
|
||||
-- @field #string type Type of the condition function: "gen", "any", "all".
|
||||
-- @field #boolean persistence If `true`, this is persistent.
|
||||
-- @field #function func Callback function to check for a condition. Must return a `#boolean`.
|
||||
-- @field #table arg (Optional) Arguments passed to the condition callback function if any.
|
||||
|
||||
--- CONDITION class version.
|
||||
-- @field #string version
|
||||
CONDITION.version="0.1.0"
|
||||
CONDITION.version="0.3.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Make FSM.
|
||||
-- TODO: Make FSM. No sure if really necessary.
|
||||
-- DONE: Option to remove condition functions.
|
||||
-- DONE: Persistence option for condition functions.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@@ -78,6 +89,8 @@ function CONDITION:New(Name)
|
||||
|
||||
self.name=Name or "Condition X"
|
||||
|
||||
self:SetNoneResult(false)
|
||||
|
||||
self.lid=string.format("%s | ", self.name)
|
||||
|
||||
return self
|
||||
@@ -101,6 +114,28 @@ function CONDITION:SetNegateResult(Negate)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set whether `true` or `false` is returned, if no conditions at all were specified. By default `false` is returned.
|
||||
-- @param #CONDITION self
|
||||
-- @param #boolean ReturnValue Returns this boolean.
|
||||
-- @return #CONDITION self
|
||||
function CONDITION:SetNoneResult(ReturnValue)
|
||||
if not ReturnValue then
|
||||
self.noneResult=false
|
||||
else
|
||||
self.noneResult=true
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set whether condition functions are persistent, *i.e.* are removed.
|
||||
-- @param #CONDITION self
|
||||
-- @param #boolean IsPersistent If `true`, condition functions are persistent.
|
||||
-- @return #CONDITION self
|
||||
function CONDITION:SetDefaultPersistence(IsPersistent)
|
||||
self.defaultPersist=IsPersistent
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
|
||||
-- @param #CONDITION self
|
||||
-- @param #function Function The function to call.
|
||||
@@ -113,47 +148,109 @@ end
|
||||
--
|
||||
-- myCondition:AddFunction(isAequalB, a, b)
|
||||
--
|
||||
-- @return #CONDITION self
|
||||
-- @return #CONDITION.Function Condition function table.
|
||||
function CONDITION:AddFunction(Function, ...)
|
||||
|
||||
-- Condition function.
|
||||
local condition=self:_CreateCondition(Function, ...)
|
||||
local condition=self:_CreateCondition(0, Function, ...)
|
||||
|
||||
-- Add to table.
|
||||
table.insert(self.functionsGen, condition)
|
||||
|
||||
return self
|
||||
return condition
|
||||
end
|
||||
|
||||
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
|
||||
-- @param #CONDITION self
|
||||
-- @param #function Function The function to call.
|
||||
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||
-- @return #CONDITION self
|
||||
-- @return #CONDITION.Function Condition function table.
|
||||
function CONDITION:AddFunctionAny(Function, ...)
|
||||
|
||||
-- Condition function.
|
||||
local condition=self:_CreateCondition(Function, ...)
|
||||
local condition=self:_CreateCondition(1, Function, ...)
|
||||
|
||||
-- Add to table.
|
||||
table.insert(self.functionsAny, condition)
|
||||
|
||||
return self
|
||||
return condition
|
||||
end
|
||||
|
||||
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
|
||||
-- @param #CONDITION self
|
||||
-- @param #function Function The function to call.
|
||||
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||
-- @return #CONDITION self
|
||||
-- @return #CONDITION.Function Condition function table.
|
||||
function CONDITION:AddFunctionAll(Function, ...)
|
||||
|
||||
-- Condition function.
|
||||
local condition=self:_CreateCondition(Function, ...)
|
||||
local condition=self:_CreateCondition(2, Function, ...)
|
||||
|
||||
-- Add to table.
|
||||
table.insert(self.functionsAll, condition)
|
||||
|
||||
return condition
|
||||
end
|
||||
|
||||
--- Remove a condition function.
|
||||
-- @param #CONDITION self
|
||||
-- @param #CONDITION.Function ConditionFunction The condition function to be removed.
|
||||
-- @return #CONDITION self
|
||||
function CONDITION:RemoveFunction(ConditionFunction)
|
||||
|
||||
if ConditionFunction then
|
||||
|
||||
local data=nil
|
||||
if ConditionFunction.type==0 then
|
||||
data=self.functionsGen
|
||||
elseif ConditionFunction.type==1 then
|
||||
data=self.functionsAny
|
||||
elseif ConditionFunction.type==2 then
|
||||
data=self.functionsAll
|
||||
end
|
||||
|
||||
if data then
|
||||
for i=#data,1,-1 do
|
||||
local cf=data[i] --#CONDITION.Function
|
||||
if cf.uid==ConditionFunction.uid then
|
||||
self:T(self.lid..string.format("Removed ConditionFunction UID=%d", cf.uid))
|
||||
table.remove(data, i)
|
||||
return self
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove all non-persistant condition functions.
|
||||
-- @param #CONDITION self
|
||||
-- @return #CONDITION self
|
||||
function CONDITION:RemoveNonPersistant()
|
||||
|
||||
for i=#self.functionsGen,1,-1 do
|
||||
local cf=self.functionsGen[i] --#CONDITION.Function
|
||||
if not cf.persistence then
|
||||
table.remove(self.functionsGen, i)
|
||||
end
|
||||
end
|
||||
|
||||
for i=#self.functionsAll,1,-1 do
|
||||
local cf=self.functionsAll[i] --#CONDITION.Function
|
||||
if not cf.persistence then
|
||||
table.remove(self.functionsAll, i)
|
||||
end
|
||||
end
|
||||
|
||||
for i=#self.functionsAny,1,-1 do
|
||||
local cf=self.functionsAny[i] --#CONDITION.Function
|
||||
if not cf.persistence then
|
||||
table.remove(self.functionsAny, i)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -166,11 +263,7 @@ function CONDITION:Evaluate(AnyTrue)
|
||||
|
||||
-- Check if at least one function was given.
|
||||
if #self.functionsAll + #self.functionsAny + #self.functionsAll == 0 then
|
||||
if self.negateResult then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
return self.noneResult
|
||||
end
|
||||
|
||||
-- Any condition for gen.
|
||||
@@ -206,6 +299,10 @@ function CONDITION:Evaluate(AnyTrue)
|
||||
return result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Private Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Check if all given condition are true.
|
||||
-- @param #CONDITION self
|
||||
-- @param #table functions Functions to evaluate.
|
||||
@@ -275,13 +372,20 @@ end
|
||||
|
||||
--- Create conditon function object.
|
||||
-- @param #CONDITION self
|
||||
-- @param #number Ftype Function type: 0=Gen, 1=All, 2=Any.
|
||||
-- @param #function Function The function to call.
|
||||
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||
-- @return #CONDITION.Function Condition function.
|
||||
function CONDITION:_CreateCondition(Function, ...)
|
||||
function CONDITION:_CreateCondition(Ftype, Function, ...)
|
||||
|
||||
-- Increase counter.
|
||||
self.functionCounter=self.functionCounter+1
|
||||
|
||||
local condition={} --#CONDITION.Function
|
||||
|
||||
condition.uid=self.functionCounter
|
||||
condition.type=Ftype or 0
|
||||
condition.persistence=self.defaultPersist
|
||||
condition.func=Function
|
||||
condition.arg={}
|
||||
if arg then
|
||||
@@ -290,6 +394,71 @@ function CONDITION:_CreateCondition(Function, ...)
|
||||
|
||||
return condition
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Global Condition Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Condition to check if time is greater than a given threshold time.
|
||||
-- @param #number Time Time in seconds.
|
||||
-- @param #boolean Absolute If `true`, abs. mission time from `timer.getAbsTime()` is checked. Default is relative mission time from `timer.getTime()`.
|
||||
-- @return #boolean Returns `true` if time is greater than give the time.
|
||||
function CONDITION.IsTimeGreater(Time, Absolute)
|
||||
|
||||
local Tnow=nil
|
||||
|
||||
if Absolute then
|
||||
Tnow=timer.getAbsTime()
|
||||
else
|
||||
Tnow=timer.getTime()
|
||||
end
|
||||
|
||||
if Tnow>Time then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Function that returns `true` (success) with a certain probability. For example, if you specify `Probability=80` there is an 80% chance that `true` is returned.
|
||||
-- Technically, a random number between 0 and 100 is created. If the given success probability is less then this number, `true` is returned.
|
||||
-- @param #number Probability Success probability in percent. Default 50 %.
|
||||
-- @return #boolean Returns `true` for success and `false` otherwise.
|
||||
function CONDITION.IsRandomSuccess(Probability)
|
||||
|
||||
Probability=Probability or 50
|
||||
|
||||
-- Create some randomness.
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
-- Number between 0 and 100.
|
||||
local N=math.random()*100
|
||||
|
||||
if N<Probability then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Function that returns always `true`
|
||||
-- @return #boolean Returns `true` unconditionally.
|
||||
function CONDITION.ReturnTrue()
|
||||
return true
|
||||
end
|
||||
|
||||
--- Function that returns always `false`
|
||||
-- @return #boolean Returns `false` unconditionally.
|
||||
function CONDITION.ReturnFalse()
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@
|
||||
-- There are 5 types/levels of objects that the _EVENTDISPATCHER services:
|
||||
--
|
||||
-- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database.
|
||||
-- * SET_ derived classes: These are subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority.
|
||||
-- * SET_ derived classes: These are subsets of the global _DATABASE object (an instance of @{Core.Database#DATABASE}). These subsets are updated by the _EVENTDISPATCHER as the second priority.
|
||||
-- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed UNIT object.
|
||||
-- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object.
|
||||
-- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object.
|
||||
@@ -52,7 +52,7 @@
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The actual event subscribing and handling is not facilitated through the _EVENTDISPATCHER, but it is done through the @{BASE} class, @{UNIT} class and @{GROUP} class.
|
||||
-- The actual event subscribing and handling is not facilitated through the _EVENTDISPATCHER, but it is done through the @{Core.Base#BASE} class, @{Wrapper.Unit#UNIT} class and @{Wrapper.Group#GROUP} class.
|
||||
-- The _EVENTDISPATCHER is a component that is quietly working in the background of MOOSE.
|
||||
--
|
||||
-- 
|
||||
@@ -173,7 +173,8 @@
|
||||
-- @image Core_Event.JPG
|
||||
|
||||
|
||||
--- @type EVENT
|
||||
---
|
||||
-- @type EVENT
|
||||
-- @field #EVENT.Events Events
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
@@ -193,6 +194,11 @@ world.event.S_EVENT_NEW_ZONE_GOAL = world.event.S_EVENT_MAX + 1004
|
||||
world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
|
||||
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
|
||||
world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007
|
||||
-- dynamic cargo
|
||||
world.event.S_EVENT_NEW_DYNAMIC_CARGO = world.event.S_EVENT_MAX + 1008
|
||||
world.event.S_EVENT_DYNAMIC_CARGO_LOADED = world.event.S_EVENT_MAX + 1009
|
||||
world.event.S_EVENT_DYNAMIC_CARGO_UNLOADED = world.event.S_EVENT_MAX + 1010
|
||||
world.event.S_EVENT_DYNAMIC_CARGO_REMOVED = world.event.S_EVENT_MAX + 1011
|
||||
|
||||
|
||||
--- The different types of events supported by MOOSE.
|
||||
@@ -248,8 +254,41 @@ EVENTS = {
|
||||
TriggerZone = world.event.S_EVENT_TRIGGER_ZONE or -1,
|
||||
LandingQualityMark = world.event.S_EVENT_LANDING_QUALITY_MARK or -1,
|
||||
BDA = world.event.S_EVENT_BDA or -1,
|
||||
-- Added with DCS 2.8.0
|
||||
AIAbortMission = world.event.S_EVENT_AI_ABORT_MISSION or -1,
|
||||
DayNight = world.event.S_EVENT_DAYNIGHT or -1,
|
||||
FlightTime = world.event.S_EVENT_FLIGHT_TIME or -1,
|
||||
SelfKillPilot = world.event.S_EVENT_PLAYER_SELF_KILL_PILOT or -1,
|
||||
PlayerCaptureAirfield = world.event.S_EVENT_PLAYER_CAPTURE_AIRFIELD or -1,
|
||||
EmergencyLanding = world.event.S_EVENT_EMERGENCY_LANDING or -1,
|
||||
UnitCreateTask = world.event.S_EVENT_UNIT_CREATE_TASK or -1,
|
||||
UnitDeleteTask = world.event.S_EVENT_UNIT_DELETE_TASK or -1,
|
||||
SimulationStart = world.event.S_EVENT_SIMULATION_START or -1,
|
||||
WeaponRearm = world.event.S_EVENT_WEAPON_REARM or -1,
|
||||
WeaponDrop = world.event.S_EVENT_WEAPON_DROP or -1,
|
||||
-- Added with DCS 2.9.x
|
||||
--UnitTaskTimeout = world.event.S_EVENT_UNIT_TASK_TIMEOUT or -1,
|
||||
UnitTaskComplete = world.event.S_EVENT_UNIT_TASK_COMPLETE or -1,
|
||||
UnitTaskStage = world.event.S_EVENT_UNIT_TASK_STAGE or -1,
|
||||
--MacSubtaskScore = world.event.S_EVENT_MAC_SUBTASK_SCORE or -1,
|
||||
MacExtraScore = world.event.S_EVENT_MAC_EXTRA_SCORE or -1,
|
||||
MissionRestart = world.event.S_EVENT_MISSION_RESTART or -1,
|
||||
MissionWinner = world.event.S_EVENT_MISSION_WINNER or -1,
|
||||
RunwayTakeoff = world.event.S_EVENT_RUNWAY_TAKEOFF or -1,
|
||||
RunwayTouch = world.event.S_EVENT_RUNWAY_TOUCH or -1,
|
||||
MacLMSRestart = world.event.S_EVENT_MAC_LMS_RESTART or -1,
|
||||
SimulationFreeze = world.event.S_EVENT_SIMULATION_FREEZE or -1,
|
||||
SimulationUnfreeze = world.event.S_EVENT_SIMULATION_UNFREEZE or -1,
|
||||
HumanAircraftRepairStart = world.event.S_EVENT_HUMAN_AIRCRAFT_REPAIR_START or -1,
|
||||
HumanAircraftRepairFinish = world.event.S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH or -1,
|
||||
-- dynamic cargo
|
||||
NewDynamicCargo = world.event.S_EVENT_NEW_DYNAMIC_CARGO or -1,
|
||||
DynamicCargoLoaded = world.event.S_EVENT_DYNAMIC_CARGO_LOADED or -1,
|
||||
DynamicCargoUnloaded = world.event.S_EVENT_DYNAMIC_CARGO_UNLOADED or -1,
|
||||
DynamicCargoRemoved = world.event.S_EVENT_DYNAMIC_CARGO_REMOVED or -1,
|
||||
}
|
||||
|
||||
|
||||
--- The Event structure
|
||||
-- Note that at the beginning of each field description, there is an indication which field will be populated depending on the object type involved in the Event:
|
||||
--
|
||||
@@ -270,6 +309,7 @@ EVENTS = {
|
||||
-- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Wrapper.Group#GROUP} of the initiator Group object.
|
||||
-- @field #string IniGroupName UNIT) The initiating GROUP name (same as IniDCSGroupName).
|
||||
-- @field #string IniPlayerName (UNIT) The name of the initiating player in case the Unit is a client or player slot.
|
||||
-- @field #string IniPlayerUCID (UNIT) The UCID of the initiating player in case the Unit is a client or player slot and on a multi-player server.
|
||||
-- @field DCS#coalition.side IniCoalition (UNIT) The coalition of the initiator.
|
||||
-- @field DCS#Unit.Category IniCategory (UNIT) The category of the initiator.
|
||||
-- @field #string IniTypeName (UNIT) The type name of the initiator.
|
||||
@@ -285,6 +325,7 @@ EVENTS = {
|
||||
-- @field Wrapper.Group#GROUP TgtGroup (UNIT) The target MOOSE wrapper @{Wrapper.Group#GROUP} of the target Group object.
|
||||
-- @field #string TgtGroupName (UNIT) The target GROUP name (same as TgtDCSGroupName).
|
||||
-- @field #string TgtPlayerName (UNIT) The name of the target player in case the Unit is a client or player slot.
|
||||
-- @field #string TgtPlayerUCID (UNIT) The UCID of the target player in case the Unit is a client or player slot and on a multi-player server.
|
||||
-- @field DCS#coalition.side TgtCoalition (UNIT) The coalition of the target.
|
||||
-- @field DCS#Unit.Category TgtCategory (UNIT) The category of the target.
|
||||
-- @field #string TgtTypeName (UNIT) The type name of the target.
|
||||
@@ -293,16 +334,19 @@ EVENTS = {
|
||||
-- @field Wrapper.Airbase#AIRBASE Place The MOOSE airbase object.
|
||||
-- @field #string PlaceName The name of the airbase.
|
||||
--
|
||||
-- @field #table weapon The weapon used during the event.
|
||||
-- @field #table Weapon
|
||||
-- @field DCS#Weapon weapon The weapon used during the event.
|
||||
-- @field DCS#Weapon Weapon The weapon used during the event.
|
||||
-- @field #string WeaponName Name of the weapon.
|
||||
-- @field DCS#Unit WeaponTgtDCSUnit Target DCS unit of the weapon.
|
||||
--
|
||||
-- @field Cargo.Cargo#CARGO Cargo The cargo object.
|
||||
-- @field #string CargoName The name of the cargo object.
|
||||
--
|
||||
-- @field Core.ZONE#ZONE Zone The zone object.
|
||||
-- @field Core.Zone#ZONE Zone The zone object.
|
||||
-- @field #string ZoneName The name of the zone.
|
||||
--
|
||||
-- @field Wrapper.DynamicCargo#DYNAMICCARGO IniDynamicCargo The dynamic cargo object.
|
||||
-- @field #string IniDynamicCargoName The dynamic cargo unit name.
|
||||
|
||||
|
||||
|
||||
@@ -560,6 +604,171 @@ local _EVENTMETA = {
|
||||
Event = "OnEventBDA",
|
||||
Text = "S_EVENT_BDA"
|
||||
},
|
||||
-- Added with DCS 2.8
|
||||
[EVENTS.AIAbortMission] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventAIAbortMission",
|
||||
Text = "S_EVENT_AI_ABORT_MISSION"
|
||||
},
|
||||
[EVENTS.DayNight] = {
|
||||
Order = 1,
|
||||
Event = "OnEventDayNight",
|
||||
Text = "S_EVENT_DAYNIGHT"
|
||||
},
|
||||
[EVENTS.FlightTime] = {
|
||||
Order = 1,
|
||||
Event = "OnEventFlightTime",
|
||||
Text = "S_EVENT_FLIGHT_TIME"
|
||||
},
|
||||
[EVENTS.SelfKillPilot] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventSelfKillPilot",
|
||||
Text = "S_EVENT_PLAYER_SELF_KILL_PILOT"
|
||||
},
|
||||
[EVENTS.PlayerCaptureAirfield] = {
|
||||
Order = 1,
|
||||
Event = "OnEventPlayerCaptureAirfield",
|
||||
Text = "S_EVENT_PLAYER_CAPTURE_AIRFIELD"
|
||||
},
|
||||
[EVENTS.EmergencyLanding] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventEmergencyLanding",
|
||||
Text = "S_EVENT_EMERGENCY_LANDING"
|
||||
},
|
||||
[EVENTS.UnitCreateTask] = {
|
||||
Order = 1,
|
||||
Event = "OnEventUnitCreateTask",
|
||||
Text = "S_EVENT_UNIT_CREATE_TASK"
|
||||
},
|
||||
[EVENTS.UnitDeleteTask] = {
|
||||
Order = 1,
|
||||
Event = "OnEventUnitDeleteTask",
|
||||
Text = "S_EVENT_UNIT_DELETE_TASK"
|
||||
},
|
||||
[EVENTS.SimulationStart] = {
|
||||
Order = 1,
|
||||
Event = "OnEventSimulationStart",
|
||||
Text = "S_EVENT_SIMULATION_START"
|
||||
},
|
||||
[EVENTS.WeaponRearm] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventWeaponRearm",
|
||||
Text = "S_EVENT_WEAPON_REARM"
|
||||
},
|
||||
[EVENTS.WeaponDrop] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventWeaponDrop",
|
||||
Text = "S_EVENT_WEAPON_DROP"
|
||||
},
|
||||
-- DCS 2.9
|
||||
--[EVENTS.UnitTaskTimeout] = {
|
||||
-- Order = 1,
|
||||
-- Side = "I",
|
||||
-- Event = "OnEventUnitTaskTimeout",
|
||||
-- Text = "S_EVENT_UNIT_TASK_TIMEOUT "
|
||||
--},
|
||||
[EVENTS.UnitTaskStage] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventUnitTaskStage",
|
||||
Text = "S_EVENT_UNIT_TASK_STAGE "
|
||||
},
|
||||
--[EVENTS.MacSubtaskScore] = {
|
||||
-- Order = 1,
|
||||
--Side = "I",
|
||||
--Event = "OnEventMacSubtaskScore",
|
||||
--Text = "S_EVENT_MAC_SUBTASK_SCORE"
|
||||
--},
|
||||
[EVENTS.MacExtraScore] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventMacExtraScore",
|
||||
Text = "S_EVENT_MAC_EXTRA_SCOREP"
|
||||
},
|
||||
[EVENTS.MissionRestart] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventMissionRestart",
|
||||
Text = "S_EVENT_MISSION_RESTART"
|
||||
},
|
||||
[EVENTS.MissionWinner] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventMissionWinner",
|
||||
Text = "S_EVENT_MISSION_WINNER"
|
||||
},
|
||||
[EVENTS.RunwayTakeoff] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventRunwayTakeoff",
|
||||
Text = "S_EVENT_RUNWAY_TAKEOFF"
|
||||
},
|
||||
[EVENTS.RunwayTouch] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventRunwayTouch",
|
||||
Text = "S_EVENT_RUNWAY_TOUCH"
|
||||
},
|
||||
[EVENTS.MacLMSRestart] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventMacLMSRestart",
|
||||
Text = "S_EVENT_MAC_LMS_RESTART"
|
||||
},
|
||||
[EVENTS.SimulationFreeze] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventSimulationFreeze",
|
||||
Text = "S_EVENT_SIMULATION_FREEZE"
|
||||
},
|
||||
[EVENTS.SimulationUnfreeze] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventSimulationUnfreeze",
|
||||
Text = "S_EVENT_SIMULATION_UNFREEZE"
|
||||
},
|
||||
[EVENTS.HumanAircraftRepairStart] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventHumanAircraftRepairStart",
|
||||
Text = "S_EVENT_HUMAN_AIRCRAFT_REPAIR_START"
|
||||
},
|
||||
[EVENTS.HumanAircraftRepairFinish] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventHumanAircraftRepairFinish",
|
||||
Text = "S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH"
|
||||
},
|
||||
-- dynamic cargo
|
||||
[EVENTS.NewDynamicCargo] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventNewDynamicCargo",
|
||||
Text = "S_EVENT_NEW_DYNAMIC_CARGO"
|
||||
},
|
||||
[EVENTS.DynamicCargoLoaded] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventDynamicCargoLoaded",
|
||||
Text = "S_EVENT_DYNAMIC_CARGO_LOADED"
|
||||
},
|
||||
[EVENTS.DynamicCargoUnloaded] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventDynamicCargoUnloaded",
|
||||
Text = "S_EVENT_DYNAMIC_CARGO_UNLOADED"
|
||||
},
|
||||
[EVENTS.DynamicCargoRemoved] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventDynamicCargoRemoved",
|
||||
Text = "S_EVENT_DYNAMIC_CARGO_REMOVED"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -916,7 +1125,7 @@ do -- Event Creation
|
||||
|
||||
--- Creation of a New ZoneGoal Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Core.Functional#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
-- @param Functional.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
function EVENT:CreateEventNewZoneGoal( ZoneGoal )
|
||||
self:F( { ZoneGoal } )
|
||||
|
||||
@@ -932,7 +1141,7 @@ do -- Event Creation
|
||||
|
||||
--- Creation of a ZoneGoal Deletion Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
-- @param Functional.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
function EVENT:CreateEventDeleteZoneGoal( ZoneGoal )
|
||||
self:F( { ZoneGoal } )
|
||||
|
||||
@@ -975,7 +1184,63 @@ do -- Event Creation
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
|
||||
--- Creation of a S_EVENT_NEW_DYNAMIC_CARGO event.
|
||||
-- @param #EVENT self
|
||||
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
|
||||
function EVENT:CreateEventNewDynamicCargo(DynamicCargo)
|
||||
self:F({DynamicCargo})
|
||||
local Event = {
|
||||
id = EVENTS.NewDynamicCargo,
|
||||
time = timer.getTime(),
|
||||
dynamiccargo = DynamicCargo,
|
||||
initiator = DynamicCargo:GetDCSObject(),
|
||||
}
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a S_EVENT_DYNAMIC_CARGO_LOADED event.
|
||||
-- @param #EVENT self
|
||||
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
|
||||
function EVENT:CreateEventDynamicCargoLoaded(DynamicCargo)
|
||||
self:F({DynamicCargo})
|
||||
local Event = {
|
||||
id = EVENTS.DynamicCargoLoaded,
|
||||
time = timer.getTime(),
|
||||
dynamiccargo = DynamicCargo,
|
||||
initiator = DynamicCargo:GetDCSObject(),
|
||||
}
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a S_EVENT_DYNAMIC_CARGO_UNLOADED event.
|
||||
-- @param #EVENT self
|
||||
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
|
||||
function EVENT:CreateEventDynamicCargoUnloaded(DynamicCargo)
|
||||
self:F({DynamicCargo})
|
||||
local Event = {
|
||||
id = EVENTS.DynamicCargoUnloaded,
|
||||
time = timer.getTime(),
|
||||
dynamiccargo = DynamicCargo,
|
||||
initiator = DynamicCargo:GetDCSObject(),
|
||||
}
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a S_EVENT_DYNAMIC_CARGO_REMOVED event.
|
||||
-- @param #EVENT self
|
||||
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
|
||||
function EVENT:CreateEventDynamicCargoRemoved(DynamicCargo)
|
||||
self:F({DynamicCargo})
|
||||
local Event = {
|
||||
id = EVENTS.DynamicCargoRemoved,
|
||||
time = timer.getTime(),
|
||||
dynamiccargo = DynamicCargo,
|
||||
initiator = DynamicCargo:GetDCSObject(),
|
||||
}
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Main event function.
|
||||
@@ -1008,9 +1273,9 @@ function EVENT:onEvent( Event )
|
||||
|
||||
if Event.initiator then
|
||||
|
||||
Event.IniObjectCategory = Event.initiator:getCategory()
|
||||
Event.IniObjectCategory = Object.getCategory(Event.initiator)
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.STATIC then
|
||||
if Event.IniObjectCategory == Object.Category.STATIC then
|
||||
---
|
||||
-- Static
|
||||
---
|
||||
@@ -1046,10 +1311,9 @@ function EVENT:onEvent( Event )
|
||||
local Unit=UNIT:FindByName(Event.IniDCSUnitName)
|
||||
if Unit then
|
||||
Event.IniObjectCategory = Object.Category.UNIT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.UNIT then
|
||||
elseif Event.IniObjectCategory == Object.Category.UNIT then
|
||||
---
|
||||
-- Unit
|
||||
---
|
||||
@@ -1058,13 +1322,14 @@ function EVENT:onEvent( Event )
|
||||
Event.IniUnitName = Event.IniDCSUnitName
|
||||
Event.IniDCSGroup = Event.IniDCSUnit:getGroup()
|
||||
Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName )
|
||||
|
||||
|
||||
if not Event.IniUnit then
|
||||
-- Unit can be a CLIENT. Most likely this will be the case ...
|
||||
Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true )
|
||||
end
|
||||
|
||||
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
|
||||
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
|
||||
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
||||
@@ -1072,38 +1337,49 @@ function EVENT:onEvent( Event )
|
||||
end
|
||||
|
||||
Event.IniPlayerName = Event.IniDCSUnit:getPlayerName()
|
||||
if Event.IniPlayerName then
|
||||
-- get UUCID
|
||||
local PID = NET.GetPlayerIDByName(nil,Event.IniPlayerName)
|
||||
if PID then
|
||||
Event.IniPlayerUCID = net.get_player_info(tonumber(PID), 'ucid')
|
||||
--env.info("Event.IniPlayerUCID="..tostring(Event.IniPlayerUCID),false)
|
||||
end
|
||||
end
|
||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
end
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.CARGO then
|
||||
elseif Event.IniObjectCategory == Object.Category.CARGO then
|
||||
---
|
||||
-- Cargo
|
||||
---
|
||||
Event.IniDCSUnit = Event.initiator
|
||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||
Event.IniUnitName = Event.IniDCSUnitName
|
||||
Event.IniUnit = CARGO:FindByName( Event.IniDCSUnitName )
|
||||
if string.match(Event.IniUnitName,".+|%d%d:%d%d|PKG%d+") then
|
||||
Event.IniDynamicCargo = DYNAMICCARGO:FindByName(Event.IniUnitName)
|
||||
Event.IniDynamicCargoName = Event.IniUnitName
|
||||
Event.IniPlayerName = string.match(Event.IniUnitName,"^(.+)|%d%d:%d%d|PKG%d+")
|
||||
else
|
||||
Event.IniUnit = CARGO:FindByName( Event.IniDCSUnitName )
|
||||
end
|
||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||
end
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.SCENERY then
|
||||
elseif Event.IniObjectCategory == Object.Category.SCENERY then
|
||||
---
|
||||
-- Scenery
|
||||
---
|
||||
|
||||
---
|
||||
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.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY"
|
||||
end
|
||||
Event.IniCategory = (Event.IniDCSUnit and Event.IniDCSUnit.getDesc ) and Event.IniDCSUnit:getDesc().category
|
||||
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"
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.BASE then
|
||||
elseif Event.IniObjectCategory == Object.Category.BASE then
|
||||
---
|
||||
-- Base Object
|
||||
---
|
||||
@@ -1114,6 +1390,12 @@ function EVENT:onEvent( Event )
|
||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||
|
||||
-- If the airbase does not exist in the DB, we add it (e.g. when FARPS are spawned).
|
||||
if not Event.IniUnit then
|
||||
_DATABASE:_RegisterAirbase(Event.initiator)
|
||||
Event.IniUnit = AIRBASE:FindByName(Event.IniDCSUnitName)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1124,9 +1406,12 @@ function EVENT:onEvent( Event )
|
||||
---
|
||||
|
||||
-- Target category.
|
||||
Event.TgtObjectCategory = Event.target:getCategory()
|
||||
Event.TgtObjectCategory = Object.getCategory(Event.target)
|
||||
|
||||
if Event.TgtObjectCategory == Object.Category.UNIT then
|
||||
---
|
||||
-- UNIT
|
||||
---
|
||||
Event.TgtDCSUnit = Event.target
|
||||
Event.TgtDCSGroup = Event.TgtDCSUnit:getGroup()
|
||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
||||
@@ -1139,21 +1424,33 @@ function EVENT:onEvent( Event )
|
||||
Event.TgtGroupName = Event.TgtDCSGroupName
|
||||
end
|
||||
Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName()
|
||||
if Event.TgtPlayerName then
|
||||
-- get UUCID
|
||||
local PID = NET.GetPlayerIDByName(nil,Event.TgtPlayerName)
|
||||
if PID then
|
||||
Event.TgtPlayerUCID = net.get_player_info(tonumber(PID), 'ucid')
|
||||
--env.info("Event.TgtPlayerUCID="..tostring(Event.TgtPlayerUCID),false)
|
||||
end
|
||||
end
|
||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
end
|
||||
|
||||
if Event.TgtObjectCategory == Object.Category.STATIC then
|
||||
-- get base data
|
||||
elseif Event.TgtObjectCategory == Object.Category.STATIC then
|
||||
---
|
||||
-- STATIC
|
||||
---
|
||||
Event.TgtDCSUnit = Event.target
|
||||
if Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object
|
||||
if Event.target.isExist and Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object, check that isExist exists (Kiowa Hellfire issue, Special K)
|
||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
|
||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
-- Workaround for borked target info on cruise missiles
|
||||
if Event.TgtDCSUnitName and Event.TgtDCSUnitName ~= "" then
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
|
||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
end
|
||||
else
|
||||
Event.TgtDCSUnitName = string.format("No target object for Event ID %s", tostring(Event.id))
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
@@ -1172,27 +1469,32 @@ function EVENT:onEvent( Event )
|
||||
Event.TgtTypeName = "Static"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Event.TgtObjectCategory == Object.Category.SCENERY then
|
||||
elseif Event.TgtObjectCategory == Object.Category.SCENERY then
|
||||
---
|
||||
-- SCENERY
|
||||
---
|
||||
Event.TgtDCSUnit = Event.target
|
||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
Event.TgtDCSUnitName = Event.TgtDCSUnit.getName and Event.TgtDCSUnit.getName() or nil
|
||||
if Event.TgtDCSUnitName~=nil then
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Weapon.
|
||||
if Event.weapon then
|
||||
if Event.weapon and type(Event.weapon) == "table" and Event.weapon.isExist and Event.weapon:isExist() then
|
||||
Event.Weapon = Event.weapon
|
||||
Event.WeaponName = Event.Weapon:getTypeName()
|
||||
Event.WeaponName = Event.weapon:isExist() and Event.weapon:getTypeName() or "Unknown Weapon"
|
||||
Event.WeaponUNIT = CLIENT:Find( Event.Weapon, '', true ) -- Sometimes, the weapon is a player unit!
|
||||
Event.WeaponPlayerName = Event.WeaponUNIT and Event.Weapon:getPlayerName()
|
||||
Event.WeaponCoalition = Event.WeaponUNIT and Event.Weapon:getCoalition()
|
||||
Event.WeaponCategory = Event.WeaponUNIT and Event.Weapon:getDesc().category
|
||||
Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon:getTypeName()
|
||||
Event.WeaponPlayerName = Event.WeaponUNIT and Event.Weapon.getPlayerName and Event.Weapon:getPlayerName()
|
||||
--Event.WeaponPlayerName = Event.WeaponUNIT and Event.Weapon:getPlayerName()
|
||||
Event.WeaponCoalition = Event.WeaponUNIT and Event.Weapon.getCoalition and Event.Weapon:getCoalition()
|
||||
Event.WeaponCategory = Event.WeaponUNIT and Event.Weapon.getDesc and Event.Weapon:getDesc().category
|
||||
Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon.getTypeName and Event.Weapon:getTypeName()
|
||||
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
|
||||
end
|
||||
|
||||
@@ -1203,9 +1505,11 @@ function EVENT:onEvent( Event )
|
||||
--local name=Event.place:getName() -- This returns a DCS error "Airbase doesn't exit" :(
|
||||
-- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground.
|
||||
--Event.Place=UNIT:Find(Event.place)
|
||||
else
|
||||
Event.Place=AIRBASE:Find(Event.place)
|
||||
Event.PlaceName=Event.Place:GetName()
|
||||
else
|
||||
if Event.place:isExist() and Object.getCategory(Event.place) ~= Object.Category.SCENERY then
|
||||
Event.Place=AIRBASE:Find(Event.place)
|
||||
Event.PlaceName=Event.Place:GetName()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1216,6 +1520,7 @@ function EVENT:onEvent( Event )
|
||||
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
|
||||
Event.MarkText=Event.text
|
||||
Event.MarkCoalition=Event.coalition
|
||||
Event.IniCoalition=Event.coalition
|
||||
Event.MarkGroupID = Event.groupID
|
||||
end
|
||||
|
||||
@@ -1224,6 +1529,15 @@ function EVENT:onEvent( Event )
|
||||
Event.Cargo = Event.cargo
|
||||
Event.CargoName = Event.cargo.Name
|
||||
end
|
||||
|
||||
-- Dynamic cargo Object
|
||||
if Event.dynamiccargo then
|
||||
Event.IniDynamicCargo = Event.dynamiccargo
|
||||
Event.IniDynamicCargoName = Event.IniDynamicCargo.StaticName
|
||||
if Event.IniDynamicCargo.Owner or Event.IniUnitName then
|
||||
Event.IniPlayerName = Event.IniDynamicCargo.Owner or string.match(Event.IniUnitName or "None|00:00|PKG00","^(.+)|%d%d:%d%d|PKG%d+")
|
||||
end
|
||||
end
|
||||
|
||||
-- Zone object.
|
||||
if Event.zone then
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
|
||||
-- Each of these FSM implementation classes start either with:
|
||||
--
|
||||
-- * an acronym **AI\_**, which indicates a FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
|
||||
-- * an acronym **TASK\_**, which indicates a FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
|
||||
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
|
||||
-- * an acronym **AI\_**, which indicates a FSM implementation directing **AI controlled** @{Wrapper.Group#GROUP} and/or @{Wrapper.Unit#UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
|
||||
-- * an acronym **TASK\_**, which indicates a FSM implementation executing a @{Tasking.Task#TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
|
||||
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{Tasking.Task#TASK}, seated in a @{Wrapper.Client#CLIENT} (slot) or a @{Wrapper.Unit#UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
|
||||
--
|
||||
-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections.
|
||||
--
|
||||
@@ -61,10 +61,10 @@
|
||||
--
|
||||
-- The following derived classes are available in the MOOSE framework, that implement a specialized form of a FSM:
|
||||
--
|
||||
-- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s.
|
||||
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s.
|
||||
-- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s.
|
||||
-- * @{#FSM_SET}: Models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here
|
||||
-- * @{#FSM_TASK}: Models Finite State Machines for @{Tasking.Task}s.
|
||||
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Tasking.Task} actions, which control @{Wrapper.Client}s.
|
||||
-- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Wrapper.Client}s.
|
||||
-- * @{#FSM_SET}: Models Finite State Machines for @{Core.Set}s. Note that these FSMs control multiple objects!!! So State concerns here
|
||||
-- for multiple objects or the position of the state machine in the process.
|
||||
--
|
||||
-- ===
|
||||
@@ -119,9 +119,9 @@ do -- FSM
|
||||
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
|
||||
-- Each of these FSM implementation classes start either with:
|
||||
--
|
||||
-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
|
||||
-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
|
||||
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
|
||||
-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{Wrapper.Group#GROUP} and/or @{Wrapper.Unit#UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
|
||||
-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{Tasking.Task#TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
|
||||
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{Tasking.Task#TASK}, seated in a @{Wrapper.Client#CLIENT} (slot) or a @{Wrapper.Unit#UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
@@ -249,7 +249,7 @@ do -- FSM
|
||||
--
|
||||
-- ### Linear Transition Example
|
||||
--
|
||||
-- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua)
|
||||
-- This example is fully implemented in the MOOSE test mission on GitHub: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Core/FSM/FSM-100%20-%20Transition%20Explanation)
|
||||
--
|
||||
-- It models a unit standing still near Batumi, and flaring every 5 seconds while switching between a Green flare and a Red flare.
|
||||
-- The purpose of this example is not to show how exciting flaring is, but it demonstrates how a Linear Transition FSM can be build.
|
||||
@@ -418,7 +418,7 @@ do -- FSM
|
||||
return self._Transitions or {}
|
||||
end
|
||||
|
||||
--- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Wrapper.Controllable} by the task.
|
||||
--- Set the default @{#FSM_PROCESS} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Wrapper.Controllable} by the task.
|
||||
-- @param #FSM self
|
||||
-- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states.
|
||||
-- @param #string Event The Event name.
|
||||
@@ -953,7 +953,7 @@ do -- FSM_CONTROLLABLE
|
||||
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s.
|
||||
--- Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Wrapper.Client}s.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -1086,7 +1086,7 @@ do -- FSM_PROCESS
|
||||
-- @field Tasking.Task#TASK Task
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
|
||||
--- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s.
|
||||
--- FSM_PROCESS class models Finite State Machines for @{Tasking.Task} actions, which control @{Wrapper.Client}s.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -1241,7 +1241,7 @@ do -- FSM_PROCESS
|
||||
|
||||
-- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP.
|
||||
|
||||
--- Send a message of the @{Task} to the Group of the Unit.
|
||||
--- Send a message of the @{Tasking.Task} to the Group of the Unit.
|
||||
-- @param #FSM_PROCESS self
|
||||
function FSM_PROCESS:Message( Message )
|
||||
self:F( { Message = Message } )
|
||||
@@ -1260,7 +1260,7 @@ do -- FSM_PROCESS
|
||||
|
||||
--- Assign the process to a @{Wrapper.Unit} and activate the process.
|
||||
-- @param #FSM_PROCESS self
|
||||
-- @param Task.Tasking#TASK Task
|
||||
-- @param Tasking.Task#TASK Task
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @return #FSM_PROCESS self
|
||||
function FSM_PROCESS:Assign( ProcessUnit, Task )
|
||||
@@ -1382,7 +1382,7 @@ do -- FSM_SET
|
||||
-- @field Core.Set#SET_BASE Set
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here
|
||||
--- FSM_SET class models Finite State Machines for @{Core.Set}s. Note that these FSMs control multiple objects!!! So State concerns here
|
||||
-- for multiple objects or the position of the state machine in the process.
|
||||
--
|
||||
-- ===
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
--- **Core** - MarkerOps_Base.
|
||||
--- **Core** - Tap into markers added to the F10 map by users.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Create an easy way to tap into markers added to the F10 map by users.
|
||||
-- * Recognize own tag and list of keywords.
|
||||
-- * Matched keywords are handed down to functions.
|
||||
-- ##Listen for your tag
|
||||
-- myMarker = MARKEROPS_BASE:New("tag", {}, false)
|
||||
-- function myMarker:OnAfterMarkChanged(From, Event, To, Text, Keywords, Coord, idx)
|
||||
--
|
||||
-- end
|
||||
-- Make sure to use the "MarkChanged" event as "MarkAdded" comes in right after the user places a blank marker and your callback will never be called.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Applevangelist**
|
||||
--
|
||||
-- Date: 5 May 2021
|
||||
-- Last Update: Sep 2022
|
||||
-- Last Update: Mar 2023
|
||||
--
|
||||
-- ===
|
||||
---
|
||||
@@ -44,7 +50,7 @@ MARKEROPS_BASE = {
|
||||
ClassName = "MARKEROPS",
|
||||
Tag = "mytag",
|
||||
Keywords = {},
|
||||
version = "0.1.0",
|
||||
version = "0.1.4",
|
||||
debug = false,
|
||||
Casesensitive = true,
|
||||
}
|
||||
@@ -102,23 +108,31 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
||||
--- On after "MarkAdded" event. Triggered when a Marker is added to the F10 map.
|
||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded
|
||||
-- @param #MARKEROPS_BASE self
|
||||
-- @param #string From The From state
|
||||
-- @param #string Event The Event called
|
||||
-- @param #string To The To state
|
||||
-- @param #string Text The text on the marker
|
||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||
-- @param #string From The From state.
|
||||
-- @param #string Event The Event called.
|
||||
-- @param #string To The To state.
|
||||
-- @param #string Text The text on the marker.
|
||||
-- @param #table Keywords Table of matching keywords found in the Event text.
|
||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||
-- @param #number MarkerID Id of this marker.
|
||||
-- @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.
|
||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
|
||||
-- @param #MARKEROPS_BASE self
|
||||
-- @param #string From The From state
|
||||
-- @param #string Event The Event called
|
||||
-- @param #string To The To state
|
||||
-- @param #string Text The text on the marker
|
||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||
-- @param #string From The From state.
|
||||
-- @param #string Event The Event called.
|
||||
-- @param #string To The To state.
|
||||
-- @param #string Text The text on the marker.
|
||||
-- @param #table Keywords Table of matching keywords found in the Event text.
|
||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||
|
||||
-- @param #number MarkerID Id of this marker.
|
||||
-- @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.
|
||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
|
||||
-- @param #MARKEROPS_BASE self
|
||||
@@ -126,7 +140,7 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
||||
-- @param #string Event The Event called
|
||||
-- @param #string To The To state
|
||||
|
||||
--- "Stop" trigger. Used to stop the function an unhandle events
|
||||
--- "Stop" trigger. Used to stop the function an unhandle events
|
||||
-- @function [parent=#MARKEROPS_BASE] Stop
|
||||
|
||||
end
|
||||
@@ -140,37 +154,43 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
self:E("Skipping onEvent. Event or Event.idx unknown.")
|
||||
return true
|
||||
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
|
||||
-- decision
|
||||
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
||||
self:T({event="S_EVENT_MARK_ADDED", carrier=self.groupname, vec3=Event.pos})
|
||||
self:T({event="S_EVENT_MARK_ADDED", carrier=Event.IniGroupName, vec3=Event.pos})
|
||||
-- Handle event
|
||||
local Eventtext = tostring(Event.text)
|
||||
if Eventtext~=nil then
|
||||
if self:_MatchTag(Eventtext) then
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkAdded(Eventtext,matchtable,coord)
|
||||
local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z})
|
||||
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
|
||||
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
||||
self:T({event="S_EVENT_MARK_CHANGE", carrier=self.groupname, vec3=Event.pos})
|
||||
self:T({event="S_EVENT_MARK_CHANGE", carrier=Event.IniGroupName, vec3=Event.pos})
|
||||
-- Handle event.
|
||||
local Eventtext = tostring(Event.text)
|
||||
if Eventtext~=nil then
|
||||
if self:_MatchTag(Eventtext) then
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkChanged(Eventtext,matchtable,coord)
|
||||
local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z})
|
||||
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
|
||||
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||
self:T({event="S_EVENT_MARK_REMOVED", carrier=self.groupname, vec3=Event.pos})
|
||||
self:T({event="S_EVENT_MARK_REMOVED", carrier=Event.IniGroupName, vec3=Event.pos})
|
||||
-- Hande event.
|
||||
local Eventtext = tostring(Event.text)
|
||||
if Eventtext~=nil then
|
||||
@@ -223,8 +243,10 @@ end
|
||||
-- @param #string To The To state
|
||||
-- @param #string Text The text on the marker
|
||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||
-- @param #number MarkerID Id of this marker
|
||||
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||
function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord)
|
||||
function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord,MarkerID,CoalitionNumber)
|
||||
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
||||
end
|
||||
|
||||
@@ -235,8 +257,10 @@ end
|
||||
-- @param #string To The To state
|
||||
-- @param #string Text The text on the marker
|
||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||
-- @param #number MarkerID Id of this marker
|
||||
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||
function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord)
|
||||
function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord,MarkerID,CoalitionNumber)
|
||||
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
||||
end
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,7 @@
|
||||
--
|
||||
-- Messages are sent:
|
||||
--
|
||||
-- * To a @{Client} using @{#MESSAGE.ToClient}().
|
||||
-- * To a @{Wrapper.Client} using @{#MESSAGE.ToClient}().
|
||||
-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}()
|
||||
-- * To a @{Wrapper.Unit} using @{#MESSAGE.ToUnit}()
|
||||
-- * To a coalition using @{#MESSAGE.ToCoalition}().
|
||||
@@ -52,7 +52,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
-- ### Contributions: **Applevangelist**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -73,37 +73,39 @@ MESSAGE.Type = {
|
||||
Detailed = "Detailed Report",
|
||||
}
|
||||
|
||||
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{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 #string MessageText 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 #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 Text is the text of the Message.
|
||||
-- @param #number Duration Duration in seconds how long the message text is shown.
|
||||
-- @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.
|
||||
-- @return #MESSAGE
|
||||
-- @return #MESSAGE self
|
||||
-- @usage
|
||||
--
|
||||
-- -- Create a series of new Messages.
|
||||
-- -- 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".
|
||||
-- -- 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".
|
||||
-- -- Create a series of new Messages.
|
||||
-- -- 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".
|
||||
-- -- 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" )
|
||||
-- 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" )
|
||||
-- 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() )
|
||||
self:F( { MessageText, MessageDuration, MessageCategory } )
|
||||
|
||||
self:F( { Text, Duration, Category } )
|
||||
|
||||
self.MessageType = nil
|
||||
|
||||
-- When no MessageCategory is given, we don't show it as a title...
|
||||
if MessageCategory and MessageCategory ~= "" then
|
||||
if MessageCategory:sub( -1 ) ~= "\n" then
|
||||
self.MessageCategory = MessageCategory .. ": "
|
||||
-- When no MessageCategory is given, we don't show it as a title...
|
||||
if Category and Category ~= "" then
|
||||
if Category:sub( -1 ) ~= "\n" then
|
||||
self.MessageCategory = Category .. ": "
|
||||
else
|
||||
self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n"
|
||||
self.MessageCategory = Category:sub( 1, -2 ) .. ":\n"
|
||||
end
|
||||
else
|
||||
self.MessageCategory = ""
|
||||
@@ -114,9 +116,9 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen
|
||||
self.ClearScreen = ClearScreen
|
||||
end
|
||||
|
||||
self.MessageDuration = MessageDuration or 5
|
||||
self.MessageDuration = Duration or 5
|
||||
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.MessageGroup = false
|
||||
@@ -127,8 +129,8 @@ end
|
||||
|
||||
--- Creates a new MESSAGE object of a certain type.
|
||||
-- Note that these MESSAGE objects are not yet displayed on the display panel.
|
||||
-- You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
|
||||
-- The message display times are automatically defined based on the timing settings in the @{Settings} menu.
|
||||
-- You must use the functions @{Core.Message#ToClient} or @{Core.Message#ToCoalition} or @{Core.Message#ToAll} to send these Messages to the respective recipients.
|
||||
-- The message display times are automatically defined based on the timing settings in the @{Core.Settings} menu.
|
||||
-- @param self
|
||||
-- @param #string MessageText is the text of the Message.
|
||||
-- @param #MESSAGE.Type MessageType The type of the message.
|
||||
@@ -171,57 +173,40 @@ end
|
||||
--- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player".
|
||||
-- @param #MESSAGE self
|
||||
-- @param Wrapper.Client#CLIENT Client is the Group of the Client.
|
||||
-- @param Core.Settings#SETTINGS Settings Settings used to display the message.
|
||||
-- @param Core.Settings#SETTINGS Settings used to display the message.
|
||||
-- @return #MESSAGE
|
||||
-- @usage
|
||||
--
|
||||
-- -- Send the 2 messages created with the @{New} method to the Client Group.
|
||||
-- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1.
|
||||
-- ClientGroup = Group.getByName( "ClientGroup" )
|
||||
-- Client = CLIENT:FindByName("NameOfClientUnit")
|
||||
--
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" ):ToClient( Client )
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score" ):ToClient( Client )
|
||||
-- or
|
||||
-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score"):ToClient( Client )
|
||||
-- MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score"):ToClient( Client )
|
||||
-- or
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" )
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
|
||||
-- MessageClient1:ToClient( ClientGroup )
|
||||
-- MessageClient2:ToClient( ClientGroup )
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score")
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
|
||||
-- MessageClient1:ToClient( Client )
|
||||
-- MessageClient2:ToClient( Client )
|
||||
--
|
||||
function MESSAGE:ToClient( Client, Settings )
|
||||
self:F( Client )
|
||||
|
||||
if Client and Client:GetClientGroupID() then
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
|
||||
local Unit = Client:GetClient()
|
||||
|
||||
if self.MessageDuration ~= 0 then
|
||||
local ClientGroupID = Client:GetClientGroupID()
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
--trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
self:ToUnit(Client,Settings)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a MESSAGE to a Group.
|
||||
-- @param #MESSAGE self
|
||||
-- @param Wrapper.Group#GROUP Group to which the message is displayed.
|
||||
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
|
||||
-- @return #MESSAGE Message object.
|
||||
function MESSAGE:ToGroup( Group, Settings )
|
||||
self:F( Group.GroupName )
|
||||
|
||||
if Group then
|
||||
if Group and Group:IsAlive() then
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
@@ -241,11 +226,12 @@ end
|
||||
--- Sends a MESSAGE to a Unit.
|
||||
-- @param #MESSAGE self
|
||||
-- @param Wrapper.Unit#UNIT Unit to which the message is displayed.
|
||||
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
|
||||
-- @return #MESSAGE Message object.
|
||||
function MESSAGE:ToUnit( Unit, Settings )
|
||||
self:F( Unit.IdentifiableName )
|
||||
|
||||
if Unit then
|
||||
if Unit and Unit:IsAlive() then
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
@@ -255,6 +241,7 @@ function MESSAGE:ToUnit( Unit, Settings )
|
||||
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
local ID = Unit:GetID()
|
||||
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||
end
|
||||
end
|
||||
@@ -262,27 +249,38 @@ function MESSAGE:ToUnit( Unit, Settings )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a MESSAGE to a Unit.
|
||||
--- Sends a MESSAGE to a Country.
|
||||
-- @param #MESSAGE self
|
||||
-- @param Wrapper.Unit#UNIT Unit to which the message is displayed.
|
||||
-- @param #number Country to which the message is displayed, e.g. country.id.GERMANY. For all country numbers see here: [Hoggit Wiki](https://wiki.hoggitworld.com/view/DCS_enum_country)
|
||||
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
|
||||
-- @return #MESSAGE Message object.
|
||||
function MESSAGE:ToUnit( Unit, Settings )
|
||||
self:F( Unit.IdentifiableName )
|
||||
|
||||
if Unit then
|
||||
|
||||
function MESSAGE:ToCountry( Country, Settings )
|
||||
self:F(Country )
|
||||
if Country then
|
||||
if self.MessageType then
|
||||
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||
trigger.action.outTextForCountry( Country, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a MESSAGE to a Country.
|
||||
-- @param #MESSAGE self
|
||||
-- @param #number Country to which the message is displayed, , e.g. country.id.GERMANY. For all country numbers see here: [Hoggit Wiki](https://wiki.hoggitworld.com/view/DCS_enum_country)
|
||||
-- @param #boolean Condition Sends the message only if the condition is true.
|
||||
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
|
||||
-- @return #MESSAGE Message object.
|
||||
function MESSAGE:ToCountryIf( Country, Condition, Settings )
|
||||
self:F(Country )
|
||||
if Country and Condition == true then
|
||||
self:ToCountry( Country, Settings )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -292,11 +290,11 @@ end
|
||||
-- @usage
|
||||
--
|
||||
-- -- Send a message created with the @{New} method to the BLUE coalition.
|
||||
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
|
||||
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", 25, "Penalty"):ToBlue()
|
||||
-- or
|
||||
-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
|
||||
-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", 25, "Penalty"):ToBlue()
|
||||
-- or
|
||||
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
|
||||
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", 25, "Penalty")
|
||||
-- MessageBLUE:ToBlue()
|
||||
--
|
||||
function MESSAGE:ToBlue()
|
||||
@@ -313,11 +311,11 @@ end
|
||||
-- @usage
|
||||
--
|
||||
-- -- Send a message created with the @{New} method to the RED coalition.
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty"):ToRed()
|
||||
-- or
|
||||
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
|
||||
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty"):ToRed()
|
||||
-- or
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty")
|
||||
-- MessageRED:ToRed()
|
||||
--
|
||||
function MESSAGE:ToRed()
|
||||
@@ -330,17 +328,17 @@ end
|
||||
|
||||
--- Sends a MESSAGE to a Coalition.
|
||||
-- @param #MESSAGE self
|
||||
-- @param #DCS.coalition.side CoalitionSide @{#DCS.coalition.side} to which the message is displayed.
|
||||
-- @param DCS#coalition.side CoalitionSide @{#DCS.coalition.side} to which the message is displayed.
|
||||
-- @param Core.Settings#SETTINGS Settings (Optional) Settings for message display.
|
||||
-- @return #MESSAGE Message object.
|
||||
-- @usage
|
||||
--
|
||||
-- -- Send a message created with the @{New} method to the RED coalition.
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty"):ToCoalition( coalition.side.RED )
|
||||
-- or
|
||||
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
|
||||
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty"):ToCoalition( coalition.side.RED )
|
||||
-- or
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty")
|
||||
-- MessageRED:ToCoalition( coalition.side.RED )
|
||||
--
|
||||
function MESSAGE:ToCoalition( CoalitionSide, Settings )
|
||||
@@ -355,16 +353,18 @@ function MESSAGE:ToCoalition( CoalitionSide, Settings )
|
||||
if CoalitionSide then
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
||||
trigger.action.outTextForCoalition( CoalitionSide, self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self.CoalitionSide = CoalitionSide
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a MESSAGE to a Coalition if the given Condition is true.
|
||||
-- @param #MESSAGE self
|
||||
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}.
|
||||
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{#DCS.coalition.side}.
|
||||
-- @param #boolean Condition Sends the message only if the condition is true.
|
||||
-- @return #MESSAGE self
|
||||
function MESSAGE:ToCoalitionIf( CoalitionSide, Condition )
|
||||
@@ -380,29 +380,36 @@ end
|
||||
--- Sends a MESSAGE to all players.
|
||||
-- @param #MESSAGE self
|
||||
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
|
||||
-- @return #MESSAGE
|
||||
-- @param #number Delay (Optional) Delay in seconds before the message is send. Default instantly (`nil`).
|
||||
-- @return #MESSAGE self
|
||||
-- @usage
|
||||
--
|
||||
-- -- Send a message created to all players.
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission"):ToAll()
|
||||
-- or
|
||||
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
|
||||
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission"):ToAll()
|
||||
-- or
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" )
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission")
|
||||
-- MessageAll:ToAll()
|
||||
--
|
||||
function MESSAGE:ToAll( Settings )
|
||||
function MESSAGE:ToAll( Settings, Delay )
|
||||
self:F()
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
if Delay and Delay>0 then
|
||||
self:ScheduleOnce(Delay, MESSAGE.ToAll, self, Settings, 0)
|
||||
else
|
||||
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
|
||||
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
||||
if self.MessageType then
|
||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
|
||||
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -410,6 +417,7 @@ end
|
||||
|
||||
--- Sends a MESSAGE to all players if the given Condition is true.
|
||||
-- @param #MESSAGE self
|
||||
-- @param #boolean Condition
|
||||
-- @return #MESSAGE
|
||||
function MESSAGE:ToAllIf( Condition )
|
||||
|
||||
@@ -419,3 +427,195 @@ function MESSAGE:ToAllIf( Condition )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a MESSAGE to DCS log file.
|
||||
-- @param #MESSAGE self
|
||||
-- @return #MESSAGE self
|
||||
function MESSAGE:ToLog()
|
||||
|
||||
env.info(self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ))
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a MESSAGE to DCS log file if the given Condition is true.
|
||||
-- @param #MESSAGE self
|
||||
-- @return #MESSAGE self
|
||||
function MESSAGE:ToLogIf( Condition )
|
||||
|
||||
if Condition and Condition == true then
|
||||
env.info(self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ))
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
_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.
|
||||
-- @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 #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 Modulation Modulation, i.e. radio.modulation.AM or radio.modulation.FM. Can also be given as a #table of modulations.
|
||||
-- @param #string Gender (optional) Gender, i.e. "male" or "female", defaults to "female" or your configuration file setting.
|
||||
-- @param #string Culture (optional) Culture, e.g. "en-US", defaults to "en-GB" or your configuration file setting.
|
||||
-- @param #string Voice (optional) Voice. Will override gender and culture settings, e.g. MSRS.Voices.Microsoft.Hazel or MSRS.Voices.Google.Standard.de_DE_Standard_D. Hint on Microsoft voices - working voices are limited to Hedda, Hazel, David, Zira and Hortense. **Must** be installed on your Desktop or Server!
|
||||
-- @param #number Coalition (optional) Coalition, can be coalition.side.RED, coalition.side.BLUE or coalition.side.NEUTRAL. Defaults to coalition.side.NEUTRAL.
|
||||
-- @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 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
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- 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
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||
--
|
||||
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\\ExternalAudio"
|
||||
|
||||
_MESSAGESRS.frequency = Frequency or MSRS.frequencies or 243
|
||||
_MESSAGESRS.modulation = Modulation or MSRS.modulations or radio.modulation.AM
|
||||
|
||||
_MESSAGESRS.MSRS = MSRS:New(_MESSAGESRS.PathToSRS,_MESSAGESRS.frequency, _MESSAGESRS.modulation)
|
||||
|
||||
_MESSAGESRS.coalition = Coalition or MSRS.coalition or coalition.side.NEUTRAL
|
||||
_MESSAGESRS.MSRS:SetCoalition(_MESSAGESRS.coalition)
|
||||
|
||||
_MESSAGESRS.coordinate = Coordinate
|
||||
|
||||
if Coordinate then
|
||||
_MESSAGESRS.MSRS:SetCoordinate(Coordinate)
|
||||
end
|
||||
|
||||
if Backend then
|
||||
_MESSAGESRS.MSRS:SetBackend(Backend)
|
||||
end
|
||||
|
||||
_MESSAGESRS.Culture = Culture or MSRS.culture or "en-GB"
|
||||
_MESSAGESRS.MSRS:SetCulture(Culture)
|
||||
|
||||
_MESSAGESRS.Gender = Gender or MSRS.gender or "female"
|
||||
_MESSAGESRS.MSRS:SetGender(Gender)
|
||||
|
||||
if PathToCredentials then
|
||||
_MESSAGESRS.MSRS:SetProviderOptionsGoogle(PathToCredentials)
|
||||
_MESSAGESRS.MSRS:SetProvider(MSRS.Provider.GOOGLE)
|
||||
end
|
||||
|
||||
_MESSAGESRS.label = Label or MSRS.Label or "MESSAGE"
|
||||
_MESSAGESRS.MSRS:SetLabel(_MESSAGESRS.label)
|
||||
|
||||
_MESSAGESRS.port = Port or MSRS.port or 5002
|
||||
_MESSAGESRS.MSRS:SetPort(_MESSAGESRS.port)
|
||||
|
||||
_MESSAGESRS.volume = Volume or MSRS.volume or 1
|
||||
_MESSAGESRS.MSRS:SetVolume(_MESSAGESRS.volume)
|
||||
|
||||
if Voice then _MESSAGESRS.MSRS:SetVoice(Voice) end
|
||||
|
||||
_MESSAGESRS.voice = Voice or MSRS.voice --or MSRS.Voices.Microsoft.Hedda
|
||||
|
||||
_MESSAGESRS.SRSQ = MSRSQUEUE:New(_MESSAGESRS.label)
|
||||
end
|
||||
|
||||
--- Sends a message via SRS. `ToSRS()` will try to use as many attributes configured with @{Core.Message#MESSAGE.SetMSRS}() and @{Sound.SRS#MSRS.LoadConfigFile}() as possible.
|
||||
-- @param #MESSAGE self
|
||||
-- @param #number frequency (optional) Frequency in MHz. Can also be given as a #table of frequencies. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting.
|
||||
-- @param #number modulation (optional) Modulation, i.e. radio.modulation.AM or radio.modulation.FM. Can also be given as a #table of modulations. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting.
|
||||
-- @param #string gender (optional) Gender, i.e. "male" or "female". Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string culture (optional) Culture, e.g. "en-US". Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string voice (optional) Voice. Will override gender and culture settings. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #number coalition (optional) Coalition, can be coalition.side.RED, coalition.side.BLUE or coalition.side.NEUTRAL. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #number volume (optional) Volume, can be between 0.0 and 1.0 (loudest). Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param Core.Point#COORDINATE coordinate (optional) Coordinate this messages originates from. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @return #MESSAGE self
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- 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
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||
--
|
||||
function MESSAGE:ToSRS(frequency,modulation,gender,culture,voice,coalition,volume,coordinate)
|
||||
local tgender = gender or _MESSAGESRS.Gender
|
||||
if _MESSAGESRS.SRSQ then
|
||||
if voice then
|
||||
_MESSAGESRS.MSRS:SetVoice(voice or _MESSAGESRS.voice)
|
||||
end
|
||||
if coordinate then
|
||||
_MESSAGESRS.MSRS:SetCoordinate(coordinate)
|
||||
end
|
||||
local category = string.gsub(self.MessageCategory,":","")
|
||||
_MESSAGESRS.SRSQ:NewTransmission(self.MessageText,nil,_MESSAGESRS.MSRS,0.5,1,nil,nil,nil,frequency or _MESSAGESRS.frequency,modulation or _MESSAGESRS.modulation, gender or _MESSAGESRS.Gender,culture or _MESSAGESRS.Culture,nil,volume or _MESSAGESRS.volume,category,coordinate or _MESSAGESRS.coordinate)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a message via SRS on the blue coalition side.
|
||||
-- @param #MESSAGE self
|
||||
-- @param #number frequency (optional) Frequency in MHz. Can also be given as a #table of frequencies. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting.
|
||||
-- @param #number modulation (optional) Modulation, i.e. radio.modulation.AM or radio.modulation.FM. Can also be given as a #table of modulations. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting.
|
||||
-- @param #string gender (optional) Gender, i.e. "male" or "female". Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string culture (optional) Culture, e.g. "en-US. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string voice (optional) Voice. Will override gender and culture settings. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #number volume (optional) Volume, can be between 0.0 and 1.0 (loudest). Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param Core.Point#COORDINATE coordinate (optional) Coordinate this messages originates from. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @return #MESSAGE self
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- 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
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSBlue()
|
||||
--
|
||||
function MESSAGE:ToSRSBlue(frequency,modulation,gender,culture,voice,volume,coordinate)
|
||||
self:ToSRS(frequency,modulation,gender,culture,voice,coalition.side.BLUE,volume,coordinate)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a message via SRS on the red coalition side.
|
||||
-- @param #MESSAGE self
|
||||
-- @param #number frequency (optional) Frequency in MHz. Can also be given as a #table of frequencies. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting.
|
||||
-- @param #number modulation (optional) Modulation, i.e. radio.modulation.AM or radio.modulation.FM. Can also be given as a #table of modulations. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting.
|
||||
-- @param #string gender (optional) Gender, i.e. "male" or "female". Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string culture (optional) Culture, e.g. "en-US. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string voice (optional) Voice. Will override gender and culture settings. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #number volume (optional) Volume, can be between 0.0 and 1.0 (loudest). Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param Core.Point#COORDINATE coordinate (optional) Coordinate this messages originates from. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @return #MESSAGE self
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- 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
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSRed()
|
||||
--
|
||||
function MESSAGE:ToSRSRed(frequency,modulation,gender,culture,voice,volume,coordinate)
|
||||
self:ToSRS(frequency,modulation,gender,culture,voice,coalition.side.RED,volume,coordinate)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a message via SRS to all - via the neutral coalition side.
|
||||
-- @param #MESSAGE self
|
||||
-- @param #number frequency (optional) Frequency in MHz. Can also be given as a #table of frequencies. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting.
|
||||
-- @param #number modulation (optional) Modulation, i.e. radio.modulation.AM or radio.modulation.FM. Can also be given as a #table of modulations. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting.
|
||||
-- @param #string gender (optional) Gender, i.e. "male" or "female". Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string culture (optional) Culture, e.g. "en-US. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string voice (optional) Voice. Will override gender and culture settings. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #number volume (optional) Volume, can be between 0.0 and 1.0 (loudest). Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param Core.Point#COORDINATE coordinate (optional) Coordinate this messages originates from. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @return #MESSAGE self
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- 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
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSAll()
|
||||
--
|
||||
function MESSAGE:ToSRSAll(frequency,modulation,gender,culture,voice,volume,coordinate)
|
||||
self:ToSRS(frequency,modulation,gender,culture,voice,coalition.side.NEUTRAL,volume,coordinate)
|
||||
return self
|
||||
end
|
||||
|
||||
371
Moose Development/Moose/Core/Pathline.lua
Normal file
371
Moose Development/Moose/Core/Pathline.lua
Normal file
@@ -0,0 +1,371 @@
|
||||
--- **Core** - Path from A to B.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Path from A to B
|
||||
-- * Arbitrary number of points
|
||||
-- * Automatically from lines drawtool
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ===
|
||||
-- @module Core.Pathline
|
||||
-- @image CORE_Pathline.png
|
||||
|
||||
|
||||
--- PATHLINE class.
|
||||
-- @type PATHLINE
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #string name Name of the path line.
|
||||
-- @field #table points List of 3D points defining the path.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- *The shortest distance between two points is a straight line.* -- Archimedes
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # The PATHLINE Concept
|
||||
--
|
||||
-- List of points defining a path from A to B. The pathline can consist of multiple points. Each point holds the information of its position, the surface type, the land height
|
||||
-- and the water depth (if over sea).
|
||||
--
|
||||
-- Line drawings created in the mission editor are automatically registered as pathlines and stored in the MOOSE database.
|
||||
-- They can be accessed with the @{#PATHLINE.FindByName) function.
|
||||
--
|
||||
-- # Constructor
|
||||
--
|
||||
-- The @{PATHLINE.New) function creates a new PATHLINE object. This does not hold any points. Points can be added with the @{#PATHLINE.AddPointFromVec2} and @{#PATHLINE.AddPointFromVec3}
|
||||
--
|
||||
-- For a given table of 2D or 3D positions, a new PATHLINE object can be created with the @{#PATHLINE.NewFromVec2Array} or @{#PATHLINE.NewFromVec3Array}, respectively.
|
||||
--
|
||||
-- # Line Drawings
|
||||
--
|
||||
-- The most convenient way to create a pathline is the draw panel feature in the DCS mission editor. You can select "Line" and then "Segments", "Segment" or "Free" to draw your lines.
|
||||
-- These line drawings are then automatically added to the MOOSE database as PATHLINE objects and can be retrieved with the @{#PATHLINE.FindByName) function, where the name is the one
|
||||
-- you specify in the draw panel.
|
||||
--
|
||||
-- # Mark on F10 map
|
||||
--
|
||||
-- The ponints of the PATHLINE can be marked on the F10 map with the @{#PATHLINE.MarkPoints}(`true`) function. The mark points contain information of the surface type, land height and
|
||||
-- water depth.
|
||||
--
|
||||
-- To remove the marks, use @{#PATHLINE.MarkPoints}(`false`).
|
||||
--
|
||||
-- @field #PATHLINE
|
||||
PATHLINE = {
|
||||
ClassName = "PATHLINE",
|
||||
lid = nil,
|
||||
points = {},
|
||||
}
|
||||
|
||||
--- Point of line.
|
||||
-- @type PATHLINE.Point
|
||||
-- @field DCS#Vec3 vec3 3D position.
|
||||
-- @field DCS#Vec2 vec2 2D position.
|
||||
-- @field #number surfaceType Surface type.
|
||||
-- @field #number landHeight Land height in meters.
|
||||
-- @field #number depth Water depth in meters.
|
||||
-- @field #number markerID Marker ID.
|
||||
|
||||
|
||||
--- PATHLINE class version.
|
||||
-- @field #string version
|
||||
PATHLINE.version="0.1.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot...
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new PATHLINE object. Points need to be added later.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #string Name Name of the path.
|
||||
-- @return #PATHLINE self
|
||||
function PATHLINE:New(Name)
|
||||
|
||||
-- Inherit everything from INTEL class.
|
||||
local self=BASE:Inherit(self, BASE:New()) --#PATHLINE
|
||||
|
||||
self.name=Name or "Unknown Path"
|
||||
|
||||
self.lid=string.format("PATHLINE %s | ", Name)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new PATHLINE object from a given list of 2D points.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #string Name Name of the pathline.
|
||||
-- @param #table Vec2Array List of DCS#Vec2 points.
|
||||
-- @return #PATHLINE self
|
||||
function PATHLINE:NewFromVec2Array(Name, Vec2Array)
|
||||
|
||||
local self=PATHLINE:New(Name)
|
||||
|
||||
for i=1,#Vec2Array do
|
||||
self:AddPointFromVec2(Vec2Array[i])
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new PATHLINE object from a given list of 3D points.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #string Name Name of the pathline.
|
||||
-- @param #table Vec3Array List of DCS#Vec3 points.
|
||||
-- @return #PATHLINE self
|
||||
function PATHLINE:NewFromVec3Array(Name, Vec3Array)
|
||||
|
||||
local self=PATHLINE:New(Name)
|
||||
|
||||
for i=1,#Vec3Array do
|
||||
self:AddPointFromVec3(Vec3Array[i])
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Find a pathline in the database.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #string Name The name of the pathline.
|
||||
-- @return #PATHLINE self
|
||||
function PATHLINE:FindByName(Name)
|
||||
local pathline = _DATABASE:FindPathline(Name)
|
||||
return pathline
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Add a point to the path from a given 2D position. The third dimension is determined from the land height.
|
||||
-- @param #PATHLINE self
|
||||
-- @param DCS#Vec2 Vec2 The 2D vector (x,y) to add.
|
||||
-- @return #PATHLINE self
|
||||
function PATHLINE:AddPointFromVec2(Vec2)
|
||||
|
||||
if Vec2 then
|
||||
|
||||
local point=self:_CreatePoint(Vec2)
|
||||
|
||||
table.insert(self.points, point)
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a point to the path from a given 3D position.
|
||||
-- @param #PATHLINE self
|
||||
-- @param DCS#Vec3 Vec3 The 3D vector (x,y) to add.
|
||||
-- @return #PATHLINE self
|
||||
function PATHLINE:AddPointFromVec3(Vec3)
|
||||
|
||||
if Vec3 then
|
||||
|
||||
local point=self:_CreatePoint(Vec3)
|
||||
|
||||
table.insert(self.points, point)
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get name of pathline.
|
||||
-- @param #PATHLINE self
|
||||
-- @return #string Name of the pathline.
|
||||
function PATHLINE:GetName()
|
||||
return self.name
|
||||
end
|
||||
|
||||
--- Get number of points.
|
||||
-- @param #PATHLINE self
|
||||
-- @return #number Number of points.
|
||||
function PATHLINE:GetNumberOfPoints()
|
||||
local N=#self.points
|
||||
return N
|
||||
end
|
||||
|
||||
--- Get points of pathline. Not that points are tables, that contain more information as just the 2D or 3D position but also the surface type etc.
|
||||
-- @param #PATHLINE self
|
||||
-- @return #list <#PATHLINE.Point> List of points.
|
||||
function PATHLINE:GetPoints()
|
||||
return self.points
|
||||
end
|
||||
|
||||
--- Get 3D points of pathline.
|
||||
-- @param #PATHLINE self
|
||||
-- @return <DCS#Vec3> List of DCS#Vec3 points.
|
||||
function PATHLINE:GetPoints3D()
|
||||
|
||||
local vecs={}
|
||||
|
||||
for _,_point in pairs(self.points) do
|
||||
local point=_point --#PATHLINE.Point
|
||||
table.insert(vecs, point.vec3)
|
||||
end
|
||||
|
||||
return vecs
|
||||
end
|
||||
|
||||
--- Get 2D points of pathline.
|
||||
-- @param #PATHLINE self
|
||||
-- @return <DCS#Vec2> List of DCS#Vec2 points.
|
||||
function PATHLINE:GetPoints2D()
|
||||
|
||||
local vecs={}
|
||||
|
||||
for _,_point in pairs(self.points) do
|
||||
local point=_point --#PATHLINE.Point
|
||||
table.insert(vecs, point.vec2)
|
||||
end
|
||||
|
||||
return vecs
|
||||
end
|
||||
|
||||
--- Get COORDINATES of pathline. Note that COORDINATE objects are created when calling this function. That does involve deep copy calls and can have an impact on performance if done too often.
|
||||
-- @param #PATHLINE self
|
||||
-- @return <Core.Point#COORDINATE> List of COORDINATES points.
|
||||
function PATHLINE:GetCoordinates()
|
||||
|
||||
local vecs={}
|
||||
|
||||
for _,_point in pairs(self.points) do
|
||||
local point=_point --#PATHLINE.Point
|
||||
local coord=COORDINATE:NewFromVec3(point.vec3)
|
||||
table.insert(vecs,coord)
|
||||
end
|
||||
|
||||
return vecs
|
||||
end
|
||||
|
||||
--- Get the n-th point of the pathline.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #number n The index of the point. Default is the first point.
|
||||
-- @return #PATHLINE.Point Point.
|
||||
function PATHLINE:GetPointFromIndex(n)
|
||||
|
||||
local N=self:GetNumberOfPoints()
|
||||
|
||||
n=n or 1
|
||||
|
||||
local point=nil --#PATHLINE.Point
|
||||
|
||||
if n>=1 and n<=N then
|
||||
point=self.points[n]
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: No point in pathline for N=%s", tostring(n)))
|
||||
end
|
||||
|
||||
return point
|
||||
end
|
||||
|
||||
--- Get the 3D position of the n-th point.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #number n The n-th point.
|
||||
-- @return DCS#VEC3 Position in 3D.
|
||||
function PATHLINE:GetPoint3DFromIndex(n)
|
||||
|
||||
local point=self:GetPointFromIndex(n)
|
||||
|
||||
if point then
|
||||
return point.vec3
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get the 2D position of the n-th point.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #number n The n-th point.
|
||||
-- @return DCS#VEC2 Position in 3D.
|
||||
function PATHLINE:GetPoint2DFromIndex(n)
|
||||
|
||||
local point=self:GetPointFromIndex(n)
|
||||
|
||||
if point then
|
||||
return point.vec2
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Mark points on F10 map.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #boolean Switch If `true` or nil, set marks. If `false`, remove marks.
|
||||
-- @return <DCS#Vec3> List of DCS#Vec3 points.
|
||||
function PATHLINE:MarkPoints(Switch)
|
||||
for i,_point in pairs(self.points) do
|
||||
local point=_point --#PATHLINE.Point
|
||||
if Switch==false then
|
||||
|
||||
if point.markerID then
|
||||
UTILS.RemoveMark(point.markerID, Delay)
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
if point.markerID then
|
||||
UTILS.RemoveMark(point.markerID)
|
||||
end
|
||||
|
||||
point.markerID=UTILS.GetMarkID()
|
||||
|
||||
local text=string.format("Pathline %s: Point #%d\nSurface Type=%d\nHeight=%.1f m\nDepth=%.1f m", self.name, i, point.surfaceType, point.landHeight, point.depth)
|
||||
|
||||
trigger.action.markToAll(point.markerID, text, point.vec3, "")
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Private functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Get 3D points of pathline.
|
||||
-- @param #PATHLINE self
|
||||
-- @param DCS#Vec3 Vec Position vector. Can also be a DCS#Vec2 in which case the altitude at landheight is taken.
|
||||
-- @return #PATHLINE.Point
|
||||
function PATHLINE:_CreatePoint(Vec)
|
||||
|
||||
local point={} --#PATHLINE.Point
|
||||
|
||||
if Vec.z then
|
||||
-- Given vec is 3D
|
||||
point.vec3=UTILS.DeepCopy(Vec)
|
||||
point.vec2={x=Vec.x, y=Vec.z}
|
||||
else
|
||||
-- Given vec is 2D
|
||||
point.vec2=UTILS.DeepCopy(Vec)
|
||||
point.vec3={x=Vec.x, y=land.getHeight(Vec), z=Vec.y}
|
||||
end
|
||||
|
||||
-- Get surface type.
|
||||
point.surfaceType=land.getSurfaceType(point.vec2)
|
||||
|
||||
-- Get land height and depth.
|
||||
point.landHeight, point.depth=land.getSurfaceHeightWithSeabed(point.vec2)
|
||||
|
||||
point.markerID=nil
|
||||
|
||||
return point
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
--- **Core** -- SCHEDULEDISPATCHER dispatches the different schedules.
|
||||
--- **Core** - SCHEDULEDISPATCHER dispatches the different schedules.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -326,7 +326,7 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
||||
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.
|
||||
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 ) ) )
|
||||
|
||||
|
||||
@@ -14,17 +14,13 @@
|
||||
--
|
||||
-- # Demo Missions
|
||||
--
|
||||
-- ### [SCHEDULER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
|
||||
--
|
||||
-- ### [SCHEDULER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
|
||||
--
|
||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
||||
-- ### [SCHEDULER Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Core/Scheduler)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # YouTube Channel
|
||||
--
|
||||
-- ### [SCHEDULER YouTube Channel (none)]()
|
||||
-- ### None
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -52,7 +48,7 @@
|
||||
--
|
||||
-- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**.
|
||||
-- The ScheduleID is returned when the method @{#SCHEDULER.Schedule}() is called.
|
||||
-- It is recommended to store the ScheduleID in a variable, as it is used in the methods @{SCHEDULER.Start}() and @{SCHEDULER.Stop}(),
|
||||
-- It is recommended to store the ScheduleID in a variable, as it is used in the methods @{#SCHEDULER.Start}() and @{#SCHEDULER.Stop}(),
|
||||
-- which can start and stop specific repeating schedules respectively within a SCHEDULER object.
|
||||
--
|
||||
-- ## SCHEDULER constructor
|
||||
@@ -208,7 +204,7 @@ SCHEDULER = {
|
||||
-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat.
|
||||
-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped.
|
||||
-- @return #SCHEDULER self.
|
||||
-- @return #table The ScheduleID of the planned schedule.
|
||||
-- @return #string The ScheduleID of the planned schedule.
|
||||
function SCHEDULER:New( MasterObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #SCHEDULER
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
--- **Core** - Manages various settings for running missions, consumed by moose classes and provides a menu system for players to tweak settings in running missions.
|
||||
--- **Core** - Manages various settings for missions, providing a menu for players to tweak settings in running missions.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -29,7 +29,9 @@
|
||||
-- @module Core.Settings
|
||||
-- @image Core_Settings.JPG
|
||||
|
||||
--- @type SETTINGS
|
||||
|
||||
---
|
||||
-- @type SETTINGS
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- Takes care of various settings that influence the behavior of certain functionalities and classes within the MOOSE framework.
|
||||
@@ -91,7 +93,7 @@
|
||||
--
|
||||
-- Will customize which display format is used to indicate A2G coordinates in text as part of the Command Center communications.
|
||||
--
|
||||
-- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_(navigation)).
|
||||
-- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_\(navigation\)).
|
||||
-- - A2G MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
|
||||
-- - A2G LL DMS: Latitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
|
||||
-- - A2G LL DDM: Latitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
|
||||
@@ -105,9 +107,9 @@
|
||||
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
|
||||
--
|
||||
-- - @{#SETTINGS.SetA2G_BR}(): Enable the BR display formatting by default.
|
||||
-- - @{#SETTINGS.SetA2G_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2G_MGRS}(): Enable the MGRS display formatting by default. Use @{#SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
--
|
||||
-- ### 3.1.4) A2G coordinates setting - additional notes
|
||||
--
|
||||
@@ -120,7 +122,7 @@
|
||||
--
|
||||
-- Will customize which display format is used to indicate A2A coordinates in text as part of the Command Center communications.
|
||||
--
|
||||
-- - A2A BRAA: [Bearing Range Altitude Aspect](https://en.wikipedia.org/wiki/Bearing_(navigation)).
|
||||
-- - A2A BRAA: [Bearing Range Altitude Aspect](https://en.wikipedia.org/wiki/Bearing_\(navigation\)).
|
||||
-- - A2A MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
|
||||
-- - A2A LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
|
||||
-- - A2A LL DDM: Lattitude Longitude [Decimal Degrees and Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
|
||||
@@ -135,9 +137,9 @@
|
||||
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
|
||||
--
|
||||
-- - @{#SETTINGS.SetA2A_BRAA}(): Enable the BR display formatting by default.
|
||||
-- - @{#SETTINGS.SetA2A_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_MGRS}(): Enable the MGRS display formatting by default. Use @{#SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_BULLS}(): Enable the BULLSeye display formatting by default.
|
||||
--
|
||||
-- ### 3.2.4) A2A coordinates settings - additional notes
|
||||
@@ -190,8 +192,8 @@
|
||||
--
|
||||
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
|
||||
--
|
||||
-- - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
-- - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
-- - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Core.Message#MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
-- - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Core.Message#MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
--
|
||||
-- ## 3.5) **Era** of the battle
|
||||
--
|
||||
@@ -218,7 +220,8 @@ SETTINGS = {
|
||||
|
||||
SETTINGS.__Enum = {}
|
||||
|
||||
--- @type SETTINGS.__Enum.Era
|
||||
---
|
||||
-- @type SETTINGS.__Enum.Era
|
||||
-- @field #number WWII
|
||||
-- @field #number Korea
|
||||
-- @field #number Cold
|
||||
@@ -283,21 +286,21 @@ do -- SETTINGS
|
||||
function SETTINGS:SetMetric()
|
||||
self.Metric = true
|
||||
end
|
||||
|
||||
|
||||
--- Sets the SETTINGS default text locale.
|
||||
-- @param #SETTINGS self
|
||||
-- @param #string Locale
|
||||
function SETTINGS:SetLocale(Locale)
|
||||
self.Locale = Locale or "en"
|
||||
end
|
||||
|
||||
|
||||
--- Gets the SETTINGS text locale.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #string
|
||||
function SETTINGS:GetLocale()
|
||||
return self.Locale or _SETTINGS:GetLocale()
|
||||
end
|
||||
|
||||
|
||||
--- Gets if the SETTINGS is metric.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if metric.
|
||||
@@ -335,7 +338,7 @@ do -- SETTINGS
|
||||
|
||||
--- Sets the SETTINGS MGRS accuracy.
|
||||
-- @param #SETTINGS self
|
||||
-- @param #number MGRS_Accuracy
|
||||
-- @param #number MGRS_Accuracy 0 to 5
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetMGRS_Accuracy( MGRS_Accuracy )
|
||||
self.MGRS_Accuracy = MGRS_Accuracy
|
||||
@@ -737,14 +740,14 @@ do -- SETTINGS
|
||||
if _SETTINGS.ShowPlayerMenu == true then
|
||||
|
||||
local PlayerGroup = PlayerUnit:GetGroup()
|
||||
local PlayerName = PlayerUnit:GetPlayerName()
|
||||
local PlayerNames = PlayerGroup:GetPlayerNames()
|
||||
local PlayerName = PlayerUnit:GetPlayerName() or "None"
|
||||
--local PlayerNames = PlayerGroup:GetPlayerNames()
|
||||
|
||||
local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' )
|
||||
|
||||
self.PlayerMenu = PlayerMenu
|
||||
|
||||
self:I( string.format( "Setting menu for player %s", tostring( PlayerName ) ) )
|
||||
self:T( string.format( "Setting menu for player %s", tostring( PlayerName ) ) )
|
||||
|
||||
local submenu = MENU_GROUP:New( PlayerGroup, "LL Accuracy", PlayerMenu )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 0 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 )
|
||||
@@ -989,7 +992,7 @@ do -- SETTINGS
|
||||
do
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem )
|
||||
BASE:E( { self, PlayerUnit:GetName(), A2GSystem } )
|
||||
--BASE:E( {PlayerUnit:GetName(), A2GSystem } )
|
||||
self.A2GSystem = A2GSystem
|
||||
MESSAGE:New( string.format( "Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if _SETTINGS.MenuStatic == false then
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +1,36 @@
|
||||
--- **Core** - Spawn statics.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
--
|
||||
-- * Spawn new statics from a static already defined in the mission editor.
|
||||
-- * Spawn new statics from a given template.
|
||||
-- * Spawn new statics from a given type.
|
||||
-- * Spawn with a custom heading and location.
|
||||
-- * Spawn within a zone.
|
||||
-- * Spawn statics linked to units, .e.g on aircraft carriers.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # Demo Missions
|
||||
--
|
||||
-- ## [SPAWNSTATIC Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPS%20-%20Spawning%20Statics)
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- # Demo Missions
|
||||
--
|
||||
-- ## [SPAWNSTATIC Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Core/SpawnStatic)
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # YouTube Channel
|
||||
--
|
||||
-- ## [SPAWNSTATIC YouTube Channel]() [No videos yet!]
|
||||
--
|
||||
--
|
||||
-- ## No videos yet!
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions: **funkyfranky**
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- @module Core.SpawnStatic
|
||||
-- @image Core_Spawnstatic.JPG
|
||||
|
||||
@@ -57,38 +57,38 @@
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
--- Allows to spawn dynamically new @{Static}s into your mission.
|
||||
--
|
||||
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc),
|
||||
--- Allows to spawn dynamically new @{Wrapper.Static}s into your mission.
|
||||
--
|
||||
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc),
|
||||
-- and "copy" these properties to create a new static object and place it at the desired coordinate.
|
||||
--
|
||||
-- New spawned @{Static}s get **the same name** as the name of the template Static, or gets the given name when a new name is provided at the Spawn method.
|
||||
-- By default, spawned @{Static}s will follow a naming convention at run-time:
|
||||
--
|
||||
-- * Spawned @{Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**, and _nnn_ is a **counter from 0 to 99999**.
|
||||
--
|
||||
--
|
||||
-- New spawned @{Wrapper.Static}s get **the same name** as the name of the template Static, or gets the given name when a new name is provided at the Spawn method.
|
||||
-- By default, spawned @{Wrapper.Static}s will follow a naming convention at run-time:
|
||||
--
|
||||
-- * Spawned @{Wrapper.Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**, and _nnn_ is a **counter from 0 to 99999**.
|
||||
--
|
||||
-- # SPAWNSTATIC Constructors
|
||||
--
|
||||
--
|
||||
-- Firstly, we need to create a SPAWNSTATIC object that will be used to spawn new statics into the mission. There are three ways to do this.
|
||||
--
|
||||
--
|
||||
-- ## Use another Static
|
||||
--
|
||||
--
|
||||
-- A new SPAWNSTATIC object can be created using another static by the @{#SPAWNSTATIC.NewFromStatic}() function. All parameters such as position, heading, country will be initialized
|
||||
-- from the static.
|
||||
--
|
||||
--
|
||||
-- ## From a Template
|
||||
--
|
||||
--
|
||||
-- A SPAWNSTATIC object can also be created from a template table using the @{#SPAWNSTATIC.NewFromTemplate}(SpawnTemplate, CountryID) function. All parameters are taken from the template.
|
||||
--
|
||||
--
|
||||
-- ## From a Type
|
||||
--
|
||||
--
|
||||
-- A very basic method is to create a SPAWNSTATIC object by just giving the type of the static. All parameters must be initialized from the InitXYZ functions described below. Otherwise default values
|
||||
-- are used. For example, if no spawn coordinate is given, the static will be created at the origin of the map.
|
||||
--
|
||||
--
|
||||
-- # Setting Parameters
|
||||
--
|
||||
--
|
||||
-- Parameters such as the spawn position, heading, country etc. can be set via :Init*XYZ* functions. Note that these functions must be given before the actual spawn command!
|
||||
--
|
||||
--
|
||||
-- * @{#SPAWNSTATIC.InitCoordinate}(Coordinate) Sets the coordinate where the static is spawned. Statics are always spawnd on the ground.
|
||||
-- * @{#SPAWNSTATIC.InitHeading}(Heading) sets the orientation of the static.
|
||||
-- * @{#SPAWNSTATIC.InitLivery}(LiveryName) sets the livery of the static. Not all statics support this.
|
||||
@@ -99,17 +99,17 @@
|
||||
-- * @{#SPAWNSTATIC.InitLinkToUnit}(Unit, OffsetX, OffsetY, OffsetAngle) links the static to a unit, e.g. to an aircraft carrier.
|
||||
--
|
||||
-- # Spawning the Statics
|
||||
--
|
||||
--
|
||||
-- Once the SPAWNSTATIC object is created and parameters are initialized, the spawn command can be given. There are different methods where some can be used to directly set parameters
|
||||
-- such as position and heading.
|
||||
--
|
||||
--
|
||||
-- * @{#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.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.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Zone}. 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**!
|
||||
--
|
||||
-- @field #SPAWNSTATIC SPAWNSTATIC
|
||||
--
|
||||
--
|
||||
SPAWNSTATIC = {
|
||||
ClassName = "SPAWNSTATIC",
|
||||
SpawnIndex = 0,
|
||||
@@ -131,7 +131,7 @@ SPAWNSTATIC = {
|
||||
-- @field #number mass Cargo mass in kg.
|
||||
-- @field #boolean canCargo Static can be a cargo.
|
||||
|
||||
--- Creates the main object to spawn a @{Static} defined in the mission editor (ME).
|
||||
--- Creates the main object to spawn a @{Wrapper.Static} defined in the mission editor (ME).
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #string SpawnTemplateName Name of the static object in the ME. Each new static will have the name starting with this prefix.
|
||||
-- @param DCS#country.id SpawnCountryID (Optional) The ID of the country.
|
||||
@@ -139,9 +139,9 @@ SPAWNSTATIC = {
|
||||
function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
||||
|
||||
|
||||
local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate(SpawnTemplateName)
|
||||
|
||||
|
||||
if TemplateStatic then
|
||||
self.SpawnTemplatePrefix = SpawnTemplateName
|
||||
self.TemplateStaticUnit = UTILS.DeepCopy(TemplateStatic.units[1])
|
||||
@@ -149,6 +149,7 @@ function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
||||
self.CategoryID = CategoryID
|
||||
self.CoalitionID = CoalitionID
|
||||
self.SpawnIndex = 0
|
||||
self.StaticCopyFrom = SpawnTemplateName
|
||||
else
|
||||
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. tostring(SpawnTemplateName) .. "'" )
|
||||
end
|
||||
@@ -158,7 +159,7 @@ function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates the main object to spawn a @{Static} given a template table.
|
||||
--- Creates the main object to spawn a @{Wrapper.Static} given a template table.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #table SpawnTemplate Template used for spawning.
|
||||
-- @param DCS#country.id CountryID The ID of the country. Default `country.id.USA`.
|
||||
@@ -166,15 +167,15 @@ end
|
||||
function SPAWNSTATIC:NewFromTemplate(SpawnTemplate, CountryID)
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
||||
|
||||
|
||||
self.TemplateStaticUnit = UTILS.DeepCopy(SpawnTemplate)
|
||||
self.SpawnTemplatePrefix = SpawnTemplate.name
|
||||
self.CountryID = CountryID or country.id.USA
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates the main object to spawn a @{Static} from a given type.
|
||||
--- Creates the main object to spawn a @{Wrapper.Static} from a given type.
|
||||
-- NOTE that you have to init many other parameters as spawn coordinate etc.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #string StaticType Type of the static.
|
||||
@@ -189,13 +190,69 @@ function SPAWNSTATIC:NewFromType(StaticType, StaticCategory, CountryID)
|
||||
self.InitStaticCategory=StaticCategory
|
||||
self.CountryID=CountryID or country.id.USA
|
||||
self.SpawnTemplatePrefix=self.InitStaticType
|
||||
|
||||
self.TemplateStaticUnit = {}
|
||||
|
||||
self.InitStaticCoordinate=COORDINATE:New(0, 0, 0)
|
||||
self.InitStaticHeading=0
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- (Internal/Cargo) Init the resource table for STATIC object that should be spawned containing storage objects.
|
||||
-- NOTE that you have to init many other parameters as the resources.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #number CombinedWeight The weight this cargo object should have (some have fixed weights!), defaults to 1kg.
|
||||
-- @return #SPAWNSTATIC self
|
||||
function SPAWNSTATIC:_InitResourceTable(CombinedWeight)
|
||||
if not self.TemplateStaticUnit.resourcePayload then
|
||||
self.TemplateStaticUnit.resourcePayload = {
|
||||
["weapons"] = {},
|
||||
["aircrafts"] = {},
|
||||
["gasoline"] = 0,
|
||||
["diesel"] = 0,
|
||||
["methanol_mixture"] = 0,
|
||||
["jet_fuel"] = 0,
|
||||
}
|
||||
end
|
||||
self:InitCargo(true)
|
||||
self:InitCargoMass(CombinedWeight or 1)
|
||||
return self
|
||||
end
|
||||
|
||||
--- (User/Cargo) Add to resource table for STATIC object that should be spawned containing storage objects. Inits the object table if necessary and sets it to be cargo for helicopters.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #string Type Type of cargo. Known types are: STORAGE.Type.WEAPONS, STORAGE.Type.LIQUIDS, STORAGE.Type.AIRCRAFT. Liquids are fuel.
|
||||
-- @param #string Name Name of the cargo type. Liquids can be STORAGE.LiquidName.JETFUEL, STORAGE.LiquidName.GASOLINE, STORAGE.LiquidName.MW50 and STORAGE.LiquidName.DIESEL. The currently available weapon items are available in the `ENUMS.Storage.weapons`, e.g. `ENUMS.Storage.weapons.bombs.Mk_82Y`. Aircraft go by their typename.
|
||||
-- @param #number Amount of tons (liquids) or number (everything else) to add.
|
||||
-- @param #number CombinedWeight Combined weight to be set to this static cargo object. NOTE - some static cargo objects have fixed weights!
|
||||
-- @return #SPAWNSTATIC self
|
||||
function SPAWNSTATIC:AddCargoResource(Type,Name,Amount,CombinedWeight)
|
||||
if not self.TemplateStaticUnit.resourcePayload then
|
||||
self:_InitResourceTable(CombinedWeight)
|
||||
end
|
||||
if Type == STORAGE.Type.LIQUIDS and type(Name) == "string" then
|
||||
self.TemplateStaticUnit.resourcePayload[Name] = Amount
|
||||
else
|
||||
self.TemplateStaticUnit.resourcePayload[Type] = {
|
||||
[Name] = {
|
||||
["amount"] = Amount,
|
||||
}
|
||||
}
|
||||
end
|
||||
UTILS.PrintTableToLog(self.TemplateStaticUnit)
|
||||
return self
|
||||
end
|
||||
|
||||
--- (User/Cargo) Resets resource table to zero for STATIC object that should be spawned containing storage objects. Inits the object table if necessary and sets it to be cargo for helicopters.
|
||||
-- Handy if you spawn from cargo statics which have resources already set.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @return #SPAWNSTATIC self
|
||||
function SPAWNSTATIC:ResetCargoResources()
|
||||
self.TemplateStaticUnit.resourcePayload = nil
|
||||
self:_InitResourceTable()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Initialize heading of the spawned static.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param Core.Point#COORDINATE Coordinate Position where the static is spawned.
|
||||
@@ -246,12 +303,16 @@ end
|
||||
-- @param #number CallsignID Callsign ID. Default 1 (="London").
|
||||
-- @param #number Frequency Frequency in MHz. Default 127.5 MHz.
|
||||
-- @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
|
||||
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation)
|
||||
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation, DynamicSpawns,DynamicHotStarts)
|
||||
self.InitFarp=true
|
||||
self.InitFarpCallsignID=CallsignID or 1
|
||||
self.InitFarpFreq=Frequency or 127.5
|
||||
self.InitFarpModu=Modulation or 0
|
||||
self.InitFarpDynamicSpawns = DynamicSpawns
|
||||
self.InitFarpDynamicHotStarts = (DynamicSpawns == true and DynamicHotStarts == true) and true or nil
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -275,7 +336,7 @@ end
|
||||
|
||||
--- Initialize as dead.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #boolean IsCargo If true, this static is dead.
|
||||
-- @param #boolean IsDead If true, this static is dead.
|
||||
-- @return #SPAWNSTATIC self
|
||||
function SPAWNSTATIC:InitDead(IsDead)
|
||||
self.InitStaticDead=IsDead
|
||||
@@ -291,7 +352,7 @@ function SPAWNSTATIC:InitCountry(CountryID)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Initialize name prefix statics get. This will be appended by "#0001", "#0002" etc.
|
||||
--- Initialize name prefix statics get. This will be appended by "#0001", "#0002" etc.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #string NamePrefix Name prefix of statics spawned. Will append #0001, etc to the name.
|
||||
-- @return #SPAWNSTATIC self
|
||||
@@ -317,6 +378,25 @@ function SPAWNSTATIC:InitLinkToUnit(Unit, OffsetX, OffsetY, OffsetAngle)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Allows to place a CallFunction hook when a new static spawns.
|
||||
-- The provided method will be called when a new group is spawned, including its given parameters.
|
||||
-- The first parameter of the SpawnFunction is the @{Wrapper.Static#STATIC} that was spawned.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #function SpawnCallBackFunction The function to be called when a group spawns.
|
||||
-- @param SpawnFunctionArguments A random amount of arguments to be provided to the function when the group spawns.
|
||||
-- @return #SPAWNSTATIC self
|
||||
function SPAWNSTATIC:OnSpawnStatic( SpawnCallBackFunction, ... )
|
||||
self:F( "OnSpawnStatic" )
|
||||
|
||||
self.SpawnFunctionHook = SpawnCallBackFunction
|
||||
self.SpawnFunctionArguments = {}
|
||||
if arg then
|
||||
self.SpawnFunctionArguments = arg
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Spawn a new STATIC object.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #number Heading (Optional) The heading of the static, which is a number in degrees from 0 to 360. Default is the heading of the template.
|
||||
@@ -327,18 +407,18 @@ function SPAWNSTATIC:Spawn(Heading, NewName)
|
||||
if Heading then
|
||||
self.InitStaticHeading=Heading
|
||||
end
|
||||
|
||||
|
||||
if NewName then
|
||||
self.InitStaticName=NewName
|
||||
end
|
||||
|
||||
return self:_SpawnStatic(self.TemplateStaticUnit, self.CountryID)
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- Creates a new @{Static} from a POINT_VEC2.
|
||||
--- Creates a new @{Wrapper.Static} from a COORDINATE.
|
||||
-- @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 #string NewName (Optional) The name of the new static.
|
||||
-- @return Wrapper.Static#STATIC The static spawned.
|
||||
@@ -347,12 +427,12 @@ function SPAWNSTATIC:SpawnFromPointVec2(PointVec2, Heading, NewName)
|
||||
local vec2={x=PointVec2:GetX(), y=PointVec2:GetY()}
|
||||
|
||||
local Coordinate=COORDINATE:NewFromVec2(vec2)
|
||||
|
||||
|
||||
return self:SpawnFromCoordinate(Coordinate, Heading, NewName)
|
||||
end
|
||||
|
||||
|
||||
--- Creates a new @{Static} from a COORDINATE.
|
||||
--- Creates a new @{Wrapper.Static} from a COORDINATE.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param Core.Point#COORDINATE Coordinate The 3D coordinate where to spawn the static.
|
||||
-- @param #number Heading (Optional) Heading The heading of the static in degrees. Default is 0 degrees.
|
||||
@@ -362,11 +442,11 @@ function SPAWNSTATIC:SpawnFromCoordinate(Coordinate, Heading, NewName)
|
||||
|
||||
-- Set up coordinate.
|
||||
self.InitStaticCoordinate=Coordinate
|
||||
|
||||
|
||||
if Heading then
|
||||
self.InitStaticHeading=Heading
|
||||
end
|
||||
|
||||
|
||||
if NewName then
|
||||
self.InitStaticName=NewName
|
||||
end
|
||||
@@ -375,7 +455,7 @@ function SPAWNSTATIC:SpawnFromCoordinate(Coordinate, Heading, NewName)
|
||||
end
|
||||
|
||||
|
||||
--- Creates a new @{Static} from a @{Zone}.
|
||||
--- Creates a new @{Wrapper.Static} from a @{Core.Zone}.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static.
|
||||
-- @param #number Heading (Optional)The heading of the static in degrees. Default is the heading of the template.
|
||||
@@ -384,8 +464,9 @@ end
|
||||
function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName)
|
||||
|
||||
-- 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
|
||||
end
|
||||
|
||||
@@ -399,45 +480,45 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
Template=Template or {}
|
||||
|
||||
local CountryID=CountryID or self.CountryID
|
||||
|
||||
|
||||
if self.InitStaticType then
|
||||
Template.type=self.InitStaticType
|
||||
end
|
||||
|
||||
|
||||
if self.InitStaticCategory then
|
||||
Template.category=self.InitStaticCategory
|
||||
end
|
||||
|
||||
if self.InitStaticCoordinate then
|
||||
Template.x = self.InitStaticCoordinate.x
|
||||
|
||||
if self.InitStaticCoordinate then
|
||||
Template.x = self.InitStaticCoordinate.x
|
||||
Template.y = self.InitStaticCoordinate.z
|
||||
Template.alt = self.InitStaticCoordinate.y
|
||||
Template.alt = self.InitStaticCoordinate.y
|
||||
end
|
||||
|
||||
|
||||
if self.InitStaticHeading then
|
||||
Template.heading = math.rad(self.InitStaticHeading)
|
||||
Template.heading = math.rad(self.InitStaticHeading)
|
||||
end
|
||||
|
||||
if self.InitStaticShape then
|
||||
Template.shape_name=self.InitStaticShape
|
||||
end
|
||||
|
||||
|
||||
if self.InitStaticLivery then
|
||||
Template.livery_id=self.InitStaticLivery
|
||||
end
|
||||
|
||||
|
||||
if self.InitStaticDead~=nil then
|
||||
Template.dead=self.InitStaticDead
|
||||
end
|
||||
|
||||
|
||||
if self.InitStaticCargo~=nil then
|
||||
Template.canCargo=self.InitStaticCargo
|
||||
end
|
||||
|
||||
|
||||
if self.InitStaticCargoMass~=nil then
|
||||
Template.mass=self.InitStaticCargoMass
|
||||
end
|
||||
|
||||
|
||||
if self.InitLinkUnit then
|
||||
Template.linkUnit=self.InitLinkUnit:GetID()
|
||||
Template.linkOffset=true
|
||||
@@ -446,52 +527,100 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
Template.offsets.x=self.InitOffsetX
|
||||
Template.offsets.angle=self.InitOffsetAngle and math.rad(self.InitOffsetAngle) or 0
|
||||
end
|
||||
|
||||
|
||||
if self.InitFarp then
|
||||
Template.heliport_callsign_id = self.InitFarpCallsignID
|
||||
Template.heliport_frequency = self.InitFarpFreq
|
||||
Template.heliport_modulation = self.InitFarpModu
|
||||
Template.unitId=nil
|
||||
end
|
||||
|
||||
|
||||
-- Increase spawn index counter.
|
||||
self.SpawnIndex = self.SpawnIndex + 1
|
||||
|
||||
|
||||
-- Name of the spawned static.
|
||||
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.
|
||||
local Static=nil
|
||||
|
||||
local Static=nil --DCS#StaticObject
|
||||
|
||||
if self.InitFarp then
|
||||
|
||||
local TemplateGroup={}
|
||||
|
||||
local TemplateGroup={}
|
||||
TemplateGroup.units={}
|
||||
TemplateGroup.units[1]=Template
|
||||
|
||||
|
||||
TemplateGroup.visible=true
|
||||
TemplateGroup.hidden=false
|
||||
TemplateGroup.x=Template.x
|
||||
TemplateGroup.y=Template.y
|
||||
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({TemplateGroup=TemplateGroup})
|
||||
|
||||
|
||||
-- ED's dirty way to spawn FARPS.
|
||||
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
||||
else
|
||||
self:T("Spawning Static")
|
||||
self:T2({Template=Template})
|
||||
Static=coalition.addStaticObject(CountryID, Template)
|
||||
end
|
||||
--Static=coalition.addStaticObject(CountryID, Template)
|
||||
|
||||
-- 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
|
||||
local Event = {
|
||||
id = EVENTS.Birth,
|
||||
time = timer.getTime(),
|
||||
initiator = Static
|
||||
}
|
||||
-- Create BIRTH event.
|
||||
world.onEvent(Event)
|
||||
|
||||
else
|
||||
self:T("Spawning Static")
|
||||
self:T2({Template=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
|
||||
|
||||
-- Add and register the new static.
|
||||
local mystatic=_DATABASE:AddStatic(Template.name)
|
||||
|
||||
-- If there is a SpawnFunction hook defined, call it.
|
||||
if self.SpawnFunctionHook then
|
||||
-- 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))
|
||||
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
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
-- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to:
|
||||
--
|
||||
-- * Spot for a defined duration.
|
||||
-- * Updates of laer spot position every 0.2 seconds for moving targets.
|
||||
-- * Updates of laser spot position every 0.2 seconds for moving targets.
|
||||
-- * Wiggle the spot at the target.
|
||||
-- * Provide a @{Wrapper.Unit} as a target, instead of a point.
|
||||
-- * Implement a status machine, LaseOn, LaseOff.
|
||||
@@ -13,27 +13,17 @@
|
||||
-- ===
|
||||
--
|
||||
-- # Demo Missions
|
||||
--
|
||||
-- ### [SPOT Demo Missions source code]()
|
||||
--
|
||||
-- ### [SPOT Demo Missions, only for beta testers]()
|
||||
--
|
||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # YouTube Channel
|
||||
--
|
||||
-- ### [SPOT YouTube Channel]()
|
||||
-- ### [Demo Missions on GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * [**Ciribob**](https://forums.eagle.ru/member.php?u=112175): Showing the way how to lase targets + how laser codes work!!! Explained the autolase script.
|
||||
-- * [**EasyEB**](https://forums.eagle.ru/member.php?u=112055): Ideas and Beta Testing
|
||||
-- * [**Wingthor**](https://forums.eagle.ru/member.php?u=123698): Beta Testing
|
||||
-- * **Ciribob**: Showing the way how to lase targets + how laser codes work!!! Explained the autolase script.
|
||||
-- * **EasyEB**: Ideas and Beta Testing
|
||||
-- * **Wingthor**: Beta Testing
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -43,21 +33,22 @@
|
||||
|
||||
do
|
||||
|
||||
--- @type SPOT
|
||||
---
|
||||
-- @type SPOT
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
--- Implements the target spotting or marking functionality, but adds additional luxury to be able to:
|
||||
--
|
||||
-- * Mark targets for a defined duration.
|
||||
-- * Updates of laer spot position every 0.2 seconds for moving targets.
|
||||
-- * Updates of laser spot position every 0.25 seconds for moving targets.
|
||||
-- * Wiggle the spot at the target.
|
||||
-- * Provide a @{Wrapper.Unit} as a target, instead of a point.
|
||||
-- * Implement a status machine, LaseOn, LaseOff.
|
||||
--
|
||||
-- ## 1. SPOT constructor
|
||||
--
|
||||
-- * @{#SPOT.New}(..\Presentations\SPOT\Dia2.JPG): Creates a new SPOT object.
|
||||
-- * @{#SPOT.New}(): Creates a new SPOT object.
|
||||
--
|
||||
-- ## 2. SPOT is a FSM
|
||||
--
|
||||
@@ -217,6 +208,8 @@ do
|
||||
|
||||
|
||||
self.Recce = Recce
|
||||
|
||||
self.RecceName = self.Recce:GetName()
|
||||
|
||||
self.LaseScheduler = SCHEDULER:New( self )
|
||||
|
||||
@@ -236,21 +229,27 @@ do
|
||||
-- @param #number LaserCode Laser code.
|
||||
-- @param #number Duration Duration of lasing in seconds.
|
||||
function SPOT:onafterLaseOn( From, Event, To, Target, LaserCode, Duration )
|
||||
self:F( { "LaseOn", Target, LaserCode, Duration } )
|
||||
self:T({From, Event, To})
|
||||
self:T2( { "LaseOn", Target, LaserCode, Duration } )
|
||||
|
||||
local function StopLase( self )
|
||||
self:LaseOff()
|
||||
end
|
||||
|
||||
self.Target = Target
|
||||
|
||||
self.TargetName = Target:GetName()
|
||||
|
||||
self.LaserCode = LaserCode
|
||||
|
||||
self.Lasing = true
|
||||
|
||||
local RecceDcsUnit = self.Recce:GetDCSObject()
|
||||
|
||||
self.SpotIR = Spot.createInfraRed( RecceDcsUnit, { x = 0, y = 2, z = 0 }, Target:GetPointVec3():AddY(1):GetVec3() )
|
||||
self.SpotLaser = Spot.createLaser( RecceDcsUnit, { x = 0, y = 2, z = 0 }, Target:GetPointVec3():AddY(1):GetVec3(), LaserCode )
|
||||
local relativespot = self.relstartpos or { x = 0, y = 2, z = 0 }
|
||||
|
||||
self.SpotIR = Spot.createInfraRed( RecceDcsUnit, relativespot, Target:GetPointVec3():AddY(1):GetVec3() )
|
||||
self.SpotLaser = Spot.createLaser( RecceDcsUnit, relativespot, Target:GetPointVec3():AddY(1):GetVec3(), LaserCode )
|
||||
|
||||
if Duration then
|
||||
self.ScheduleID = self.LaseScheduler:Schedule( self, StopLase, {self}, Duration )
|
||||
@@ -259,6 +258,8 @@ do
|
||||
self:HandleEvent( EVENTS.Dead )
|
||||
|
||||
self:__Lasing( -1 )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@@ -271,7 +272,7 @@ do
|
||||
-- @param #number LaserCode Laser code.
|
||||
-- @param #number Duration Duration of lasing in seconds.
|
||||
function SPOT:onafterLaseOnCoordinate(From, Event, To, Coordinate, LaserCode, Duration)
|
||||
self:F( { "LaseOnCoordinate", Coordinate, LaserCode, Duration } )
|
||||
self:T2( { "LaseOnCoordinate", Coordinate, LaserCode, Duration } )
|
||||
|
||||
local function StopLase( self )
|
||||
self:LaseOff()
|
||||
@@ -293,55 +294,72 @@ do
|
||||
end
|
||||
|
||||
self:__Lasing(-1)
|
||||
return self
|
||||
end
|
||||
|
||||
--- @param #SPOT self
|
||||
|
||||
---
|
||||
-- @param #SPOT self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function SPOT:OnEventDead(EventData)
|
||||
self:F( { Dead = EventData.IniDCSUnitName, Target = self.Target } )
|
||||
self:T2( { Dead = EventData.IniDCSUnitName, Target = self.Target } )
|
||||
if self.Target then
|
||||
if EventData.IniDCSUnitName == self.Target:GetName() then
|
||||
self:F( {"Target dead ", self.Target:GetName() } )
|
||||
if EventData.IniDCSUnitName == self.TargetName then
|
||||
self:F( {"Target dead ", self.TargetName } )
|
||||
self:Destroyed()
|
||||
self:LaseOff()
|
||||
end
|
||||
end
|
||||
if self.Recce then
|
||||
if EventData.IniDCSUnitName == self.RecceName then
|
||||
self:F( {"Recce dead ", self.RecceName } )
|
||||
self:LaseOff()
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- @param #SPOT self
|
||||
---
|
||||
-- @param #SPOT self
|
||||
-- @param From
|
||||
-- @param Event
|
||||
-- @param To
|
||||
function SPOT:onafterLasing( From, Event, To )
|
||||
|
||||
if self.Target and self.Target:IsAlive() then
|
||||
self.SpotIR:setPoint( self.Target:GetPointVec3():AddY(1):AddY(math.random(-100,100)/100):AddX(math.random(-100,100)/100):GetVec3() )
|
||||
self.SpotLaser:setPoint( self.Target:GetPointVec3():AddY(1):GetVec3() )
|
||||
self:__Lasing( -0.2 )
|
||||
elseif self.TargetCoord then
|
||||
self:T({From, Event, To})
|
||||
|
||||
-- Wiggle the IR spot a bit.
|
||||
local irvec3={x=self.TargetCoord.x+math.random(-100,100)/100, y=self.TargetCoord.y+math.random(-100,100)/100, z=self.TargetCoord.z} --#DCS.Vec3
|
||||
local lsvec3={x=self.TargetCoord.x, y=self.TargetCoord.y, z=self.TargetCoord.z} --#DCS.Vec3
|
||||
if self.Lasing then
|
||||
if self.Target and self.Target:IsAlive() then
|
||||
|
||||
self.SpotIR:setPoint( self.Target:GetPointVec3():AddY(1):AddY(math.random(-100,100)/200):AddX(math.random(-100,100)/200):GetVec3() )
|
||||
self.SpotLaser:setPoint( self.Target:GetPointVec3():AddY(1):GetVec3() )
|
||||
|
||||
self:__Lasing(0.2)
|
||||
elseif self.TargetCoord then
|
||||
|
||||
self.SpotIR:setPoint(irvec3)
|
||||
self.SpotLaser:setPoint(lsvec3)
|
||||
|
||||
self:__Lasing(-0.25)
|
||||
else
|
||||
self:F( { "Target is not alive", self.Target:IsAlive() } )
|
||||
-- Wiggle the IR spot a bit.
|
||||
local irvec3={x=self.TargetCoord.x+math.random(-100,100)/200, y=self.TargetCoord.y+math.random(-100,100)/200, z=self.TargetCoord.z} --#DCS.Vec3
|
||||
local lsvec3={x=self.TargetCoord.x, y=self.TargetCoord.y, z=self.TargetCoord.z} --#DCS.Vec3
|
||||
|
||||
self.SpotIR:setPoint(irvec3)
|
||||
self.SpotLaser:setPoint(lsvec3)
|
||||
|
||||
self:__Lasing(0.2)
|
||||
else
|
||||
self:F( { "Target is not alive", self.Target:IsAlive() } )
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- @param #SPOT self
|
||||
|
||||
---
|
||||
-- @param #SPOT self
|
||||
-- @param From
|
||||
-- @param Event
|
||||
-- @param To
|
||||
-- @return #SPOT
|
||||
function SPOT:onafterLaseOff( From, Event, To )
|
||||
|
||||
self:F( {"Stopped lasing for ", self.Target and self.Target:GetName() or "coord", SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
|
||||
self:T({From, Event, To})
|
||||
|
||||
self:T2( {"Stopped lasing for ", self.Target and self.Target:GetName() or "coord", SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
|
||||
|
||||
self.Lasing = false
|
||||
|
||||
@@ -368,4 +386,16 @@ do
|
||||
return self.Lasing
|
||||
end
|
||||
|
||||
end
|
||||
--- Set laser start position relative to the lasing unit.
|
||||
-- @param #SPOT self
|
||||
-- @param #table position Start position of the laser relative to the lasing unit. Default is { x = 0, y = 2, z = 0 }
|
||||
-- @return #SPOT self
|
||||
-- @usage
|
||||
-- -- Set lasing position to be the position of the optics of the Gazelle M:
|
||||
-- myspot:SetRelativeStartPosition({ x = 1.7, y = 1.2, z = 0 })
|
||||
function SPOT:SetRelativeStartPosition(position)
|
||||
self.relstartpos = position or { x = 0, y = 2, z = 0 }
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Core** - TEXTANDSOUND (MOOSE gettext) system
|
||||
--- **Core** - A Moose GetText system.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
|
||||
@@ -107,7 +107,7 @@ _TIMERID=0
|
||||
|
||||
--- TIMER class version.
|
||||
-- @field #string version
|
||||
TIMER.version="0.1.2"
|
||||
TIMER.version="0.2.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -155,7 +155,7 @@ function TIMER:New(Function, ...)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new TIMER object.
|
||||
--- Start TIMER object.
|
||||
-- @param #TIMER self
|
||||
-- @param #number Tstart Relative start time in seconds.
|
||||
-- @param #number dT Interval between function calls in seconds. If not specified `nil`, the function is called only once.
|
||||
@@ -192,6 +192,20 @@ function TIMER:Start(Tstart, dT, Duration)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Start TIMER object if a condition is met. Useful for e.g. debugging.
|
||||
-- @param #TIMER self
|
||||
-- @param #boolean Condition Must be true for the TIMER to start
|
||||
-- @param #number Tstart Relative start time in seconds.
|
||||
-- @param #number dT Interval between function calls in seconds. If not specified `nil`, the function is called only once.
|
||||
-- @param #number Duration Time in seconds for how long the timer is running. If not specified `nil`, the timer runs forever or until stopped manually by the `TIMER:Stop()` function.
|
||||
-- @return #TIMER self
|
||||
function TIMER:StartIf(Condition,Tstart, dT, Duration)
|
||||
if Condition then
|
||||
self:Start(Tstart, dT, Duration)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stop the timer by removing the timer function.
|
||||
-- @param #TIMER self
|
||||
-- @param #number Delay (Optional) Delay in seconds, before the timer is stopped.
|
||||
@@ -208,7 +222,20 @@ function TIMER:Stop(Delay)
|
||||
|
||||
-- Remove timer function.
|
||||
self:T(self.lid..string.format("Stopping timer by removing timer function after %d calls!", self.ncalls))
|
||||
timer.removeFunction(self.tid)
|
||||
|
||||
-- We use a pcall here because if the DCS timer does not exist any more, it crashes the whole script!
|
||||
local status=pcall(
|
||||
function ()
|
||||
timer.removeFunction(self.tid)
|
||||
end
|
||||
)
|
||||
|
||||
-- Debug messages.
|
||||
if status then
|
||||
self:T2(self.lid..string.format("Stopped timer!"))
|
||||
else
|
||||
self:E(self.lid..string.format("WARNING: Could not remove timer function! isrunning=%s", tostring(self.isrunning)))
|
||||
end
|
||||
|
||||
-- Not running any more.
|
||||
self.isrunning=false
|
||||
|
||||
@@ -35,13 +35,13 @@ do -- UserFlag
|
||||
ClassName = "USERFLAG",
|
||||
UserFlagName = nil,
|
||||
}
|
||||
|
||||
|
||||
--- USERFLAG Constructor.
|
||||
-- @param #USERFLAG self
|
||||
-- @param #string UserFlagName The name of the userflag, which is a free text string.
|
||||
-- @return #USERFLAG
|
||||
function USERFLAG:New( UserFlagName ) --R2.3
|
||||
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #USERFLAG
|
||||
|
||||
self.UserFlagName = UserFlagName
|
||||
@@ -52,13 +52,13 @@ do -- UserFlag
|
||||
--- Get the userflag name.
|
||||
-- @param #USERFLAG self
|
||||
-- @return #string Name of the user flag.
|
||||
function USERFLAG:GetName()
|
||||
function USERFLAG:GetName()
|
||||
return self.UserFlagName
|
||||
end
|
||||
|
||||
--- Set the userflag to a given Number.
|
||||
-- @param #USERFLAG self
|
||||
-- @param #number Number The number value to be checked if it is the same as the userflag.
|
||||
-- @param #number Number The number value to set the flag to.
|
||||
-- @param #number Delay Delay in seconds, before the flag is set.
|
||||
-- @return #USERFLAG The userflag instance.
|
||||
-- @usage
|
||||
@@ -66,18 +66,17 @@ do -- UserFlag
|
||||
-- BlueVictory:Set( 100 ) -- Set the UserFlag VictoryBlue to 100.
|
||||
--
|
||||
function USERFLAG:Set( Number, Delay ) --R2.3
|
||||
|
||||
|
||||
if Delay and Delay>0 then
|
||||
self:ScheduleOnce(Delay, USERFLAG.Set, self, Number)
|
||||
else
|
||||
--env.info(string.format("Setting flag \"%s\" to %d at T=%.1f", self.UserFlagName, Number, timer.getTime()))
|
||||
trigger.action.setUserFlag( self.UserFlagName, Number )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the userflag Number.
|
||||
-- @param #USERFLAG self
|
||||
-- @return #number Number The number value to be checked if it is the same as the userflag.
|
||||
@@ -86,12 +85,10 @@ do -- UserFlag
|
||||
-- local BlueVictoryValue = BlueVictory:Get() -- Get the UserFlag VictoryBlue value.
|
||||
--
|
||||
function USERFLAG:Get() --R2.3
|
||||
|
||||
return trigger.misc.getUserFlag( self.UserFlagName )
|
||||
end
|
||||
|
||||
|
||||
|
||||
return trigger.misc.getUserFlag( self.UserFlagName )
|
||||
end
|
||||
|
||||
--- Check if the userflag has a value of Number.
|
||||
-- @param #USERFLAG self
|
||||
-- @param #number Number The number value to be checked if it is the same as the userflag.
|
||||
@@ -102,9 +99,9 @@ do -- UserFlag
|
||||
-- return "Blue has won"
|
||||
-- end
|
||||
function USERFLAG:Is( Number ) --R2.3
|
||||
|
||||
return trigger.misc.getUserFlag( self.UserFlagName ) == Number
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
return trigger.misc.getUserFlag( self.UserFlagName ) == Number
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -54,7 +54,7 @@ do -- Velocity
|
||||
self.Velocity = VelocityMps
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Get the velocity in Mps (meters per second).
|
||||
-- @param #VELOCITY self
|
||||
-- @return #number The velocity in meters per second.
|
||||
@@ -70,12 +70,12 @@ do -- Velocity
|
||||
self.Velocity = UTILS.KmphToMps( VelocityKmph )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Get the velocity in Kmph (kilometers per hour).
|
||||
-- @param #VELOCITY self
|
||||
-- @return #number The velocity in kilometers per hour.
|
||||
function VELOCITY:GetKmph()
|
||||
|
||||
|
||||
return UTILS.MpsToKmph( self.Velocity )
|
||||
end
|
||||
|
||||
@@ -87,7 +87,7 @@ do -- Velocity
|
||||
self.Velocity = UTILS.MiphToMps( VelocityMiph )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Get the velocity in Miph (miles per hour).
|
||||
-- @param #VELOCITY self
|
||||
-- @return #number The velocity in miles per hour.
|
||||
@@ -95,8 +95,7 @@ do -- Velocity
|
||||
return UTILS.MpsToMiph( self.Velocity )
|
||||
end
|
||||
|
||||
|
||||
--- Get the velocity in text, according the player @{Settings}.
|
||||
--- Get the velocity in text, according the player @{Core.Settings}.
|
||||
-- @param #VELOCITY self
|
||||
-- @param Core.Settings#SETTINGS Settings
|
||||
-- @return #string The velocity in text.
|
||||
@@ -113,11 +112,11 @@ do -- Velocity
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the velocity in text, according the player or default @{Settings}.
|
||||
--- Get the velocity in text, according the player or default @{Core.Settings}.
|
||||
-- @param #VELOCITY self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @param Core.Settings#SETTINGS Settings
|
||||
-- @return #string The velocity in text according the player or default @{Settings}
|
||||
-- @return #string The velocity in text according the player or default @{Core.Settings}
|
||||
function VELOCITY:ToString( VelocityGroup, Settings ) -- R2.3
|
||||
self:F( { Group = VelocityGroup and VelocityGroup:GetName() } )
|
||||
local Settings = Settings or ( VelocityGroup and _DATABASE:GetPlayerSettings( VelocityGroup:GetPlayerName() ) ) or _SETTINGS
|
||||
@@ -134,7 +133,7 @@ do -- VELOCITY_POSITIONABLE
|
||||
|
||||
--- # VELOCITY_POSITIONABLE class, extends @{Core.Base#BASE}
|
||||
--
|
||||
-- VELOCITY_POSITIONABLE monitors the speed of an @{Positionable} in the simulation, which can be expressed in various formats according the Settings.
|
||||
-- @{#VELOCITY_POSITIONABLE} monitors the speed of a @{Wrapper.Positionable#POSITIONABLE} in the simulation, which can be expressed in various formats according the Settings.
|
||||
--
|
||||
-- ## 1. VELOCITY_POSITIONABLE constructor
|
||||
--
|
||||
@@ -167,7 +166,7 @@ do -- VELOCITY_POSITIONABLE
|
||||
-- @param #VELOCITY_POSITIONABLE self
|
||||
-- @return #number The velocity in kilometers per hour.
|
||||
function VELOCITY_POSITIONABLE:GetKmph()
|
||||
|
||||
|
||||
return UTILS.MpsToKmph( self.Positionable:GetVelocityMPS() or 0)
|
||||
end
|
||||
|
||||
@@ -178,9 +177,9 @@ do -- VELOCITY_POSITIONABLE
|
||||
return UTILS.MpsToMiph( self.Positionable:GetVelocityMPS() or 0 )
|
||||
end
|
||||
|
||||
--- Get the velocity in text, according the player or default @{Settings}.
|
||||
--- Get the velocity in text, according the player or default @{Core.Settings}.
|
||||
-- @param #VELOCITY_POSITIONABLE self
|
||||
-- @return #string The velocity in text according the player or default @{Settings}
|
||||
-- @return #string The velocity in text according the player or default @{Core.Settings}
|
||||
function VELOCITY_POSITIONABLE:ToString() -- R2.3
|
||||
self:F( { Group = self.Positionable and self.Positionable:GetName() } )
|
||||
local Settings = Settings or ( self.Positionable and _DATABASE:GetPlayerSettings( self.Positionable:GetPlayerName() ) ) or _SETTINGS
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,8 @@
|
||||
--- **Core** - The ZONE_DETECTION class, defined by a zone name, a detection object and a radius.
|
||||
-- @module Core.Zone_Detection
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
--- The ZONE_DETECTION class, defined by a zone name, a detection object and a radius.
|
||||
---
|
||||
-- @type ZONE_DETECTION
|
||||
-- @field DCS#Vec2 Vec2 The current location of the zone.
|
||||
-- @field DCS#Distance Radius The radius of the zone.
|
||||
@@ -29,7 +32,7 @@ function ZONE_DETECTION:New( ZoneName, Detection, Radius )
|
||||
|
||||
self.Detection = Detection
|
||||
self.Radius = Radius
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -48,15 +51,14 @@ function ZONE_DETECTION:BoundZone( Points, CountryID, UnBound )
|
||||
|
||||
local Angle
|
||||
local RadialBase = math.pi*2
|
||||
|
||||
--
|
||||
|
||||
for Angle = 0, 360, (360 / Points ) do
|
||||
local Radial = Angle * RadialBase / 360
|
||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||
|
||||
|
||||
local CountryName = _DATABASE.COUNTRY_NAME[CountryID]
|
||||
|
||||
|
||||
local Tire = {
|
||||
["country"] = CountryName,
|
||||
["category"] = "Fortifications",
|
||||
@@ -105,7 +107,7 @@ function ZONE_DETECTION:SmokeZone( SmokeColor, Points, AddHeight, AngleOffset )
|
||||
local Radial = ( Angle + AngleOffset ) * RadialBase / 360
|
||||
Point.x = Vec2.x + math.cos( 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
|
||||
|
||||
return self
|
||||
@@ -136,7 +138,7 @@ function ZONE_DETECTION:FlareZone( FlareColor, Points, Azimuth, AddHeight )
|
||||
local Radial = Angle * RadialBase / 360
|
||||
Point.x = Vec2.x + math.cos( 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
|
||||
|
||||
return self
|
||||
@@ -200,4 +202,3 @@ function ZONE_DETECTION:IsVec3InZone( Vec3 )
|
||||
|
||||
return InZone
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
--- **DCS API** Prototypes
|
||||
--- **DCS API** Prototypes.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- See the [Simulator Scripting Engine Documentation](https://wiki.hoggitworld.com/view/Simulator_Scripting_Engine_Documentation) on Hoggit for further explanation and examples.
|
||||
--
|
||||
@@ -12,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.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.weather weather Weather functions for fog etc.
|
||||
|
||||
--- The world singleton contains functions centered around two different but extremely useful functions.
|
||||
-- * Events and event handlers are all governed within world.
|
||||
@@ -23,38 +26,68 @@ do -- world
|
||||
|
||||
--- [https://wiki.hoggitworld.com/view/DCS_enum_world](https://wiki.hoggitworld.com/view/DCS_enum_world)
|
||||
-- @type world.event
|
||||
-- @field S_EVENT_INVALID
|
||||
-- @field S_EVENT_SHOT [https://wiki.hoggitworld.com/view/DCS_event_shot](https://wiki.hoggitworld.com/view/DCS_event_shot)
|
||||
-- @field S_EVENT_HIT [https://wiki.hoggitworld.com/view/DCS_event_hit](https://wiki.hoggitworld.com/view/DCS_event_hit)
|
||||
-- @field S_EVENT_TAKEOFF [https://wiki.hoggitworld.com/view/DCS_event_takeoff](https://wiki.hoggitworld.com/view/DCS_event_takeoff)
|
||||
-- @field S_EVENT_LAND [https://wiki.hoggitworld.com/view/DCS_event_land](https://wiki.hoggitworld.com/view/DCS_event_land)
|
||||
-- @field S_EVENT_CRASH [https://wiki.hoggitworld.com/view/DCS_event_crash](https://wiki.hoggitworld.com/view/DCS_event_crash)
|
||||
-- @field S_EVENT_EJECTION [https://wiki.hoggitworld.com/view/DCS_event_ejection](https://wiki.hoggitworld.com/view/DCS_event_ejection)
|
||||
-- @field S_EVENT_REFUELING [https://wiki.hoggitworld.com/view/DCS_event_refueling](https://wiki.hoggitworld.com/view/DCS_event_refueling)
|
||||
-- @field S_EVENT_DEAD [https://wiki.hoggitworld.com/view/DCS_event_dead](https://wiki.hoggitworld.com/view/DCS_event_dead)
|
||||
-- @field S_EVENT_PILOT_DEAD [https://wiki.hoggitworld.com/view/DCS_event_pilot_dead](https://wiki.hoggitworld.com/view/DCS_event_pilot_dead)
|
||||
-- @field S_EVENT_BASE_CAPTURED [https://wiki.hoggitworld.com/view/DCS_event_base_captured](https://wiki.hoggitworld.com/view/DCS_event_base_captured)
|
||||
-- @field S_EVENT_MISSION_START [https://wiki.hoggitworld.com/view/DCS_event_mission_start](https://wiki.hoggitworld.com/view/DCS_event_mission_start)
|
||||
-- @field S_EVENT_MISSION_END [https://wiki.hoggitworld.com/view/DCS_event_mission_end](https://wiki.hoggitworld.com/view/DCS_event_mission_end)
|
||||
-- @field S_EVENT_TOOK_CONTROL
|
||||
-- @field S_EVENT_REFUELING_STOP [https://wiki.hoggitworld.com/view/DCS_event_refueling_stop](https://wiki.hoggitworld.com/view/DCS_event_refueling_stop)
|
||||
-- @field S_EVENT_BIRTH [https://wiki.hoggitworld.com/view/DCS_event_birth](https://wiki.hoggitworld.com/view/DCS_event_birth)
|
||||
-- @field S_EVENT_HUMAN_FAILURE [https://wiki.hoggitworld.com/view/DCS_event_human_failure](https://wiki.hoggitworld.com/view/DCS_event_human_failure)
|
||||
-- @field S_EVENT_ENGINE_STARTUP [https://wiki.hoggitworld.com/view/DCS_event_engine_startup](https://wiki.hoggitworld.com/view/DCS_event_engine_startup)
|
||||
-- @field S_EVENT_ENGINE_SHUTDOWN [https://wiki.hoggitworld.com/view/DCS_event_engine_shutdown](https://wiki.hoggitworld.com/view/DCS_event_engine_shutdown)
|
||||
-- @field S_EVENT_PLAYER_ENTER_UNIT [https://wiki.hoggitworld.com/view/DCS_event_player_enter_unit](https://wiki.hoggitworld.com/view/DCS_event_player_enter_unit)
|
||||
-- @field S_EVENT_PLAYER_LEAVE_UNIT [https://wiki.hoggitworld.com/view/DCS_event_player_leave_unit](https://wiki.hoggitworld.com/view/DCS_event_player_leave_unit)
|
||||
-- @field S_EVENT_PLAYER_COMMENT
|
||||
-- @field S_EVENT_SHOOTING_START [https://wiki.hoggitworld.com/view/DCS_event_shooting_start](https://wiki.hoggitworld.com/view/DCS_event_shooting_start)
|
||||
-- @field S_EVENT_SHOOTING_END [https://wiki.hoggitworld.com/view/DCS_event_shooting_end](https://wiki.hoggitworld.com/view/DCS_event_shooting_end)
|
||||
-- @field S_EVENT_MARK ADDED [https://wiki.hoggitworld.com/view/DCS_event_mark_added](https://wiki.hoggitworld.com/view/DCS_event_mark_added) DCS>=2.5.1
|
||||
-- @field S_EVENT_MARK CHANGE [https://wiki.hoggitworld.com/view/DCS_event_mark_change](https://wiki.hoggitworld.com/view/DCS_event_mark_change) DCS>=2.5.1
|
||||
-- @field S_EVENT_MARK REMOVE [https://wiki.hoggitworld.com/view/DCS_event_mark_remove](https://wiki.hoggitworld.com/view/DCS_event_mark_remove) DCS>=2.5.1
|
||||
-- @field S_EVENT_KILL [https://wiki.hoggitworld.com/view/DCS_event_kill](https://wiki.hoggitworld.com/view/DCS_event_kill) DCS>=2.5.6
|
||||
-- @field S_EVENT_SCORE [https://wiki.hoggitworld.com/view/DCS_event_score](https://wiki.hoggitworld.com/view/DCS_event_score) DCS>=2.5.6
|
||||
-- @field S_EVENT_UNIT_LOST [https://wiki.hoggitworld.com/view/DCS_event_unit_lost](https://wiki.hoggitworld.com/view/DCS_event_unit_lost) DCS>=2.5.6
|
||||
-- @field S_EVENT_LANDING_AFTER_EJECTION [https://wiki.hoggitworld.com/view/DCS_event_landing_after_ejection](https://wiki.hoggitworld.com/view/DCS_event_landing_after_ejection) DCS>=2.5.6
|
||||
-- @field S_EVENT_MAX
|
||||
-- @field S_EVENT_INVALID = 0
|
||||
-- @field S_EVENT_SHOT = 1
|
||||
-- @field S_EVENT_HIT = 2
|
||||
-- @field S_EVENT_TAKEOFF = 3
|
||||
-- @field S_EVENT_LAND = 4
|
||||
-- @field S_EVENT_CRASH = 5
|
||||
-- @field S_EVENT_EJECTION = 6
|
||||
-- @field S_EVENT_REFUELING = 7
|
||||
-- @field S_EVENT_DEAD = 8
|
||||
-- @field S_EVENT_PILOT_DEAD = 9
|
||||
-- @field S_EVENT_BASE_CAPTURED = 10
|
||||
-- @field S_EVENT_MISSION_START = 11
|
||||
-- @field S_EVENT_MISSION_END = 12
|
||||
-- @field S_EVENT_TOOK_CONTROL = 13
|
||||
-- @field S_EVENT_REFUELING_STOP = 14
|
||||
-- @field S_EVENT_BIRTH = 15
|
||||
-- @field S_EVENT_HUMAN_FAILURE = 16
|
||||
-- @field S_EVENT_DETAILED_FAILURE = 17
|
||||
-- @field S_EVENT_ENGINE_STARTUP = 18
|
||||
-- @field S_EVENT_ENGINE_SHUTDOWN = 19
|
||||
-- @field S_EVENT_PLAYER_ENTER_UNIT = 20
|
||||
-- @field S_EVENT_PLAYER_LEAVE_UNIT = 21
|
||||
-- @field S_EVENT_PLAYER_COMMENT = 22
|
||||
-- @field S_EVENT_SHOOTING_START = 23
|
||||
-- @field S_EVENT_SHOOTING_END = 24
|
||||
-- @field S_EVENT_MARK_ADDED = 25
|
||||
-- @field S_EVENT_MARK_CHANGE = 26
|
||||
-- @field S_EVENT_MARK_REMOVED = 27
|
||||
-- @field S_EVENT_KILL = 28
|
||||
-- @field S_EVENT_SCORE = 29
|
||||
-- @field S_EVENT_UNIT_LOST = 30
|
||||
-- @field S_EVENT_LANDING_AFTER_EJECTION = 31
|
||||
-- @field S_EVENT_PARATROOPER_LENDING = 32 -- who's lending whom what? ;)
|
||||
-- @field S_EVENT_DISCARD_CHAIR_AFTER_EJECTION = 33
|
||||
-- @field S_EVENT_WEAPON_ADD = 34
|
||||
-- @field S_EVENT_TRIGGER_ZONE = 35
|
||||
-- @field S_EVENT_LANDING_QUALITY_MARK = 36
|
||||
-- @field S_EVENT_BDA = 37 -- battle damage assessment
|
||||
-- @field S_EVENT_AI_ABORT_MISSION = 38
|
||||
-- @field S_EVENT_DAYNIGHT = 39
|
||||
-- @field S_EVENT_FLIGHT_TIME = 40
|
||||
-- @field S_EVENT_PLAYER_SELF_KILL_PILOT = 41
|
||||
-- @field S_EVENT_PLAYER_CAPTURE_AIRFIELD = 42
|
||||
-- @field S_EVENT_EMERGENCY_LANDING = 43
|
||||
-- @field S_EVENT_UNIT_CREATE_TASK = 44
|
||||
-- @field S_EVENT_UNIT_DELETE_TASK = 45
|
||||
-- @field S_EVENT_SIMULATION_START = 46
|
||||
-- @field S_EVENT_WEAPON_REARM = 47
|
||||
-- @field S_EVENT_WEAPON_DROP = 48
|
||||
-- @field S_EVENT_UNIT_TASK_COMPLETE = 49
|
||||
-- @field S_EVENT_UNIT_TASK_STAGE = 50
|
||||
-- @field S_EVENT_MAC_EXTRA_SCORE= 51 -- not sure what this is
|
||||
-- @field S_EVENT_MISSION_RESTART= 52
|
||||
-- @field S_EVENT_MISSION_WINNER = 53
|
||||
-- @field S_EVENT_RUNWAY_TAKEOFF= 54
|
||||
-- @field S_EVENT_RUNWAY_TOUCH= 55
|
||||
-- @field S_EVENT_MAC_LMS_RESTART= 56 -- not sure what this is
|
||||
-- @field S_EVENT_SIMULATION_FREEZE = 57
|
||||
-- @field S_EVENT_SIMULATION_UNFREEZE = 58
|
||||
-- @field S_EVENT_HUMAN_AIRCRAFT_REPAIR_START = 59
|
||||
-- @field S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH = 60
|
||||
-- @field S_EVENT_MAX = 61
|
||||
|
||||
--- The birthplace enumerator is used to define where an aircraft or helicopter has spawned in association with birth events.
|
||||
-- @type world.BirthPlace
|
||||
@@ -100,6 +133,36 @@ do -- world
|
||||
-- @function [parent=#world] getAirbases
|
||||
-- @param #number coalitionId The coalition side number ID. Default is all airbases are returned.
|
||||
-- @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
|
||||
|
||||
@@ -133,6 +196,22 @@ do -- env
|
||||
|
||||
end -- env
|
||||
|
||||
do -- radio
|
||||
|
||||
--@type radio
|
||||
-- @field #radio.modulation modulation
|
||||
|
||||
---
|
||||
-- @type radio.modulation
|
||||
-- @field AM
|
||||
-- @field FM
|
||||
|
||||
radio = {}
|
||||
radio.modulation = {}
|
||||
radio.modulation.AM = 0
|
||||
radio.modulation.FM = 1
|
||||
|
||||
end
|
||||
|
||||
do -- timer
|
||||
|
||||
@@ -191,21 +270,29 @@ do -- land
|
||||
|
||||
--- [Type of surface enumerator](https://wiki.hoggitworld.com/view/DCS_singleton_land)
|
||||
-- @type land.SurfaceType
|
||||
-- @field LAND
|
||||
-- @field SHALLOW_WATER
|
||||
-- @field WATER
|
||||
-- @field ROAD
|
||||
-- @field RUNWAY
|
||||
-- @field LAND Land=1
|
||||
-- @field SHALLOW_WATER Shallow water=2
|
||||
-- @field WATER Water=3
|
||||
-- @field ROAD Road=4
|
||||
-- @field RUNWAY Runway=5
|
||||
|
||||
--- Returns altitude MSL of the point.
|
||||
--- Returns the distance from sea level (y-axis) of a given vec2 point.
|
||||
-- @function [parent=#land] getHeight
|
||||
-- @param #Vec2 point point on the ground.
|
||||
-- @return #Distance
|
||||
-- @param #Vec2 point Point on the ground.
|
||||
-- @return #number Height in meters.
|
||||
|
||||
--- Returns the surface height and depth of a point. Useful for checking if the path is deep enough to support a given ship.
|
||||
-- Both values are positive. When checked over water at sea level the first value is always zero.
|
||||
-- When checked over water at altitude, for example the reservoir of the Inguri Dam, the first value is the corresponding altitude the water level is at.
|
||||
-- @function [parent=#land] getSurfaceHeightWithSeabed
|
||||
-- @param #Vec2 point Position where to check.
|
||||
-- @return #number Height in meters.
|
||||
-- @return #number Depth in meters.
|
||||
|
||||
--- returns surface type at the given point.
|
||||
--- Returns surface type at the given point.
|
||||
-- @function [parent=#land] getSurfaceType
|
||||
-- @param #Vec2 point Point on the land.
|
||||
-- @return #land.SurfaceType
|
||||
-- @return #number Enumerator value from `land.SurfaceType` (LAND=1, SHALLOW_WATER=2, WATER=3, ROAD=4, RUNWAY=5)
|
||||
|
||||
--- [DCS Singleton land](https://wiki.hoggitworld.com/view/DCS_singleton_land)
|
||||
land = {} --#land
|
||||
@@ -306,6 +393,11 @@ do -- country
|
||||
-- @field Argentinia
|
||||
-- @field Cyprus
|
||||
-- @field Slovenia
|
||||
-- @field BOLIVIA
|
||||
-- @field GHANA
|
||||
-- @field NIGERIA
|
||||
-- @field PERU
|
||||
-- @field ECUADOR
|
||||
|
||||
country = {} --#country
|
||||
|
||||
@@ -314,11 +406,11 @@ end -- country
|
||||
|
||||
do -- Command
|
||||
|
||||
--- @type Command
|
||||
-- @type Command
|
||||
-- @field #string id
|
||||
-- @field #Command.params params
|
||||
|
||||
--- @type Command.params
|
||||
-- @type Command.params
|
||||
|
||||
end -- Command
|
||||
|
||||
@@ -334,9 +426,23 @@ do -- coalition
|
||||
-- @field RED
|
||||
-- @field BLUE
|
||||
|
||||
--- @function [parent=#coalition] getCountryCoalition
|
||||
-- @param #number countryId
|
||||
-- @return #number coalitionId
|
||||
--- Get country coalition.
|
||||
-- @function [parent=#coalition] getCountryCoalition
|
||||
-- @param #number countryId Country ID.
|
||||
-- @return #number coalitionId Coalition ID.
|
||||
|
||||
--- Dynamically spawns a group. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addGroup)
|
||||
-- @function [parent=#coalition] addGroup
|
||||
-- @param #number countryId Id of the country.
|
||||
-- @param #number groupCategory Group category. Set -1 for spawning FARPS.
|
||||
-- @param #table groupData Group data table.
|
||||
-- @return DCS#Group The spawned Group object.
|
||||
|
||||
--- Dynamically spawns a static object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addStaticObject)
|
||||
-- @function [parent=#coalition] addStaticObject
|
||||
-- @param #number countryId Id of the country.
|
||||
-- @param #table groupData Group data table.
|
||||
-- @return DCS#Static The spawned static object.
|
||||
|
||||
coalition = {} -- #coalition
|
||||
|
||||
@@ -345,7 +451,8 @@ end -- coalition
|
||||
|
||||
do -- Types
|
||||
|
||||
--- @type Desc
|
||||
--- Descriptors.
|
||||
-- @type Desc
|
||||
-- @field #number speedMax0 Max speed in meters/second at zero altitude.
|
||||
-- @field #number massEmpty Empty mass in kg.
|
||||
-- @field #number tankerType Type of refueling system: 0=boom, 1=probe.
|
||||
@@ -406,8 +513,8 @@ do -- Types
|
||||
--- Vec3 type is a 3D-vector.
|
||||
-- DCS world has 3-dimensional coordinate system. DCS ground is an infinite plain.
|
||||
-- @type Vec3
|
||||
-- @field #Distance x is directed to the north
|
||||
-- @field #Distance z is directed to the east
|
||||
-- @field #Distance x is directed to the North
|
||||
-- @field #Distance z is directed to the East
|
||||
-- @field #Distance y is directed up
|
||||
|
||||
--- Vec2 is a 2D-vector for the ground plane as a reference plane.
|
||||
@@ -442,16 +549,16 @@ do -- Types
|
||||
-- @type AttributeNameArray
|
||||
-- @list <#AttributeName>
|
||||
|
||||
--- @type Zone
|
||||
-- @type Zone
|
||||
-- @field DCSVec3#Vec3 point
|
||||
-- @field #number radius
|
||||
|
||||
Zone = {}
|
||||
|
||||
--- @type ModelTime
|
||||
-- @type ModelTime
|
||||
-- @extends #number
|
||||
|
||||
--- @type Time
|
||||
-- @type Time
|
||||
-- @extends #number
|
||||
|
||||
--- A task descriptor (internal structure for DCS World). See [https://wiki.hoggitworld.com/view/Category:Tasks](https://wiki.hoggitworld.com/view/Category:Tasks).
|
||||
@@ -460,7 +567,7 @@ do -- Types
|
||||
-- @field #string id
|
||||
-- @field #Task.param param
|
||||
|
||||
--- @type Task.param
|
||||
-- @type Task.param
|
||||
|
||||
--- List of @{#Task}
|
||||
-- @type TaskArray
|
||||
@@ -507,7 +614,7 @@ do -- Object
|
||||
-- @field SCENERY
|
||||
-- @field CARGO
|
||||
|
||||
--- @type Object.Desc
|
||||
-- @type Object.Desc
|
||||
-- @extends #Desc
|
||||
-- @field #number life initial life level
|
||||
-- @field #Box3 box bounding box of collision geometry
|
||||
@@ -523,9 +630,13 @@ do -- Object
|
||||
--- @function [parent=#Object] destroy
|
||||
-- @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
|
||||
-- @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.
|
||||
-- @function [parent=#Object] getTypeName
|
||||
@@ -658,10 +769,11 @@ do -- Weapon
|
||||
|
||||
--- Weapon.Category enum that stores weapon categories.
|
||||
-- @type Weapon.Category
|
||||
-- @field SHELL
|
||||
-- @field MISSILE
|
||||
-- @field ROCKET
|
||||
-- @field BOMB
|
||||
-- @field #number SHELL Shell.
|
||||
-- @field #number MISSILE Missile
|
||||
-- @field #number ROCKET Rocket.
|
||||
-- @field #number BOMB Bomb.
|
||||
-- @field #number TORPEDO Torpedo.
|
||||
|
||||
|
||||
--- Weapon.GuidanceType enum that stores guidance methods. Available only for guided weapon (Weapon.Category.MISSILE and some Weapon.Category.BOMB).
|
||||
@@ -763,11 +875,118 @@ do -- Airbase
|
||||
-- @function [parent=#Airbase] getDesc
|
||||
-- @param self
|
||||
-- @return #Airbase.Desc
|
||||
|
||||
|
||||
--- Returns the warehouse object associated with the airbase object. Can then be used to call the warehouse class functions to modify the contents of the warehouse.
|
||||
-- @function [parent=#Airbase] getWarehouse
|
||||
-- @param self
|
||||
-- @return #Warehouse The DCS warehouse object of this airbase.
|
||||
|
||||
--- Enables or disables the airbase and FARP auto capture game mechanic where ownership of a base can change based on the presence of ground forces or the
|
||||
-- default setting assigned in the editor.
|
||||
-- @function [parent=#Airbase] autoCapture
|
||||
-- @param self
|
||||
-- @param #boolean setting `true` : enables autoCapture behavior, `false` : disables autoCapture behavior
|
||||
|
||||
--- Returns the current autoCapture setting for the passed base.
|
||||
-- @function [parent=#Airbase] autoCaptureIsOn
|
||||
-- @param self
|
||||
-- @return #boolean `true` if autoCapture behavior is enabled and `false` otherwise.
|
||||
|
||||
--- Changes the passed airbase object's coalition to the set value. Must be used with Airbase.autoCapture to disable auto capturing of the base,
|
||||
-- otherwise the base can revert back to a different coalition depending on the situation and built in game capture rules.
|
||||
-- @function [parent=#Airbase] setCoalition
|
||||
-- @param self
|
||||
-- @param #number coa The new owner coalition: 0=neutra, 1=red, 2=blue.
|
||||
|
||||
--- Returns the wsType of every object that exists in DCS. A wsType is a table consisting of 4 entries indexed numerically.
|
||||
-- It can be used to broadly categorize object types. The table can be broken down as: {mainCategory, subCat1, subCat2, index}
|
||||
-- @function [parent=#Airbase] getResourceMap
|
||||
-- @param self
|
||||
-- @return #table wsType of every object that exists in DCS.
|
||||
|
||||
Airbase = {} --#Airbase
|
||||
|
||||
end -- Airbase
|
||||
|
||||
|
||||
do -- Warehouse
|
||||
|
||||
--- [DCS Class Warehouse](https://wiki.hoggitworld.com/view/DCS_Class_Warehouse)
|
||||
-- The warehouse class gives control over warehouses that exist in airbase objects. These warehouses can limit the aircraft, munitions, and fuel available to coalition aircraft.
|
||||
-- @type Warehouse
|
||||
|
||||
|
||||
--- Get a warehouse by passing its name.
|
||||
-- @function [parent=#Warehouse] getByName
|
||||
-- @param #string Name Name of the warehouse.
|
||||
-- @return #Warehouse The warehouse object.
|
||||
|
||||
--- Adds the passed amount of a given item to the warehouse.
|
||||
-- itemName is the typeName associated with the item: "weapons.missiles.AIM_54C_Mk47"
|
||||
-- A wsType table can also be used, however the last digit with wsTypes has been known to change. {4, 4, 7, 322}
|
||||
-- @function [parent=#Warehouse] addItem
|
||||
-- @param self
|
||||
-- @param #string itemName Name of the item.
|
||||
-- @param #number count Number of items to add.
|
||||
|
||||
--- Returns the number of the passed type of item currently in a warehouse object.
|
||||
-- @function [parent=#Warehouse] getItemCount
|
||||
-- @param self
|
||||
-- @param #string itemName Name of the item.
|
||||
|
||||
--- Sets the passed amount of a given item to the warehouse.
|
||||
-- @function [parent=#Warehouse] setItem
|
||||
-- @param self
|
||||
-- @param #string itemName Name of the item.
|
||||
-- @param #number count Number of items to add.
|
||||
|
||||
--- Removes the amount of the passed item from the warehouse.
|
||||
-- @function [parent=#Warehouse] removeItem
|
||||
-- @param self
|
||||
-- @param #string itemName Name of the item.
|
||||
-- @param #number count Number of items to be removed.
|
||||
|
||||
--- Adds the passed amount of a liquid fuel into the warehouse inventory.
|
||||
-- @function [parent=#Warehouse] addLiquid
|
||||
-- @param self
|
||||
-- @param #number liquidType Type of liquid to add: 0=jetfuel, 1=aviation gasoline, 2=MW50, 3=Diesel.
|
||||
-- @param #number count Amount of liquid to add.
|
||||
|
||||
--- Returns the amount of the passed liquid type within a given warehouse.
|
||||
-- @function [parent=#Warehouse] getLiquidAmount
|
||||
-- @param self
|
||||
-- @param #number liquidType Type of liquid to add: 0=jetfuel, 1=aviation gasoline, 2=MW50, 3=Diesel.
|
||||
-- @return #number Amount of liquid.
|
||||
|
||||
--- Sets the passed amount of a liquid fuel into the warehouse inventory.
|
||||
-- @function [parent=#Warehouse] setLiquidAmount
|
||||
-- @param self
|
||||
-- @param #number liquidType Type of liquid to add: 0=jetfuel, 1=aviation gasoline, 2=MW50, 3=Diesel.
|
||||
-- @param #number count Amount of liquid.
|
||||
|
||||
--- Removes the set amount of liquid from the inventory in a warehouse.
|
||||
-- @function [parent=#Warehouse] setLiquidAmount
|
||||
-- @param self
|
||||
-- @param #number liquidType Type of liquid to add: 0=jetfuel, 1=aviation gasoline, 2=MW50, 3=Diesel.
|
||||
-- @param #number count Amount of liquid.
|
||||
|
||||
--- Returns the airbase object associated with the warehouse object.
|
||||
-- @function [parent=#Warehouse] getOwner
|
||||
-- @param self
|
||||
-- @return #Airbase The airbase object owning this warehouse.
|
||||
|
||||
--- Returns a full itemized list of everything currently in a warehouse. If a category is set to unlimited then the table will be returned empty.
|
||||
-- Aircraft and weapons are indexed by strings. Liquids are indexed by number.
|
||||
-- @function [parent=#Warehouse] getInventory
|
||||
-- @param self
|
||||
-- @param #string itemName Name of the item.
|
||||
-- @return #table Itemized list of everything currently in a warehouse
|
||||
|
||||
|
||||
Warehouse = {} --#Warehouse
|
||||
|
||||
end
|
||||
|
||||
do -- Spot
|
||||
|
||||
--- [DCS Class Spot](https://wiki.hoggitworld.com/view/DCS_Class_Spot)
|
||||
@@ -830,14 +1049,16 @@ do -- Spot
|
||||
end -- Spot
|
||||
|
||||
do -- Controller
|
||||
--- Controller is an object that performs A.I.-routines. 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:
|
||||
--
|
||||
-- * 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
|
||||
-- @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.
|
||||
-- Note: Now it works only for ground / naval groups!
|
||||
@@ -896,18 +1117,18 @@ do -- Controller
|
||||
|
||||
-- Detection
|
||||
|
||||
--- Enum contains identifiers of surface types.
|
||||
--- Enum containing detection types.
|
||||
-- @type Controller.Detection
|
||||
-- @field VISUAL
|
||||
-- @field OPTIC
|
||||
-- @field RADAR
|
||||
-- @field IRST
|
||||
-- @field RWR
|
||||
-- @field DLINK
|
||||
-- @field #number VISUAL Visual detection. Numeric value 1.
|
||||
-- @field #number OPTIC Optical detection. Numeric value 2.
|
||||
-- @field #number RADAR Radar detection. Numeric value 4.
|
||||
-- @field #number IRST Infra-red search and track detection. Numeric value 8.
|
||||
-- @field #number RWR Radar Warning Receiver detection. Numeric value 16.
|
||||
-- @field #number DLINK Data link detection. Numeric value 32.
|
||||
|
||||
--- Detected target.
|
||||
-- @type DetectedTarget
|
||||
-- @field Wrapper.Object#Object object The target
|
||||
-- @type Controller.DetectedTarget
|
||||
-- @field DCS#Object object The target
|
||||
-- @field #boolean visible The target is visible
|
||||
-- @field #boolean type The target type is known
|
||||
-- @field #boolean distance Distance to the target is known
|
||||
@@ -920,9 +1141,9 @@ do -- Controller
|
||||
-- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
|
||||
-- @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 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 #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 lastVel Has effect only if visible is false. Last velocity of the target when it was seen.
|
||||
|
||||
@@ -948,7 +1169,8 @@ end -- Controller
|
||||
|
||||
do -- Unit
|
||||
|
||||
--- @type Unit
|
||||
--- Unit.
|
||||
-- @type Unit
|
||||
-- @extends #CoalitionObject
|
||||
-- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically.
|
||||
-- @field #Unit.Category Category
|
||||
@@ -980,8 +1202,8 @@ do -- Unit
|
||||
|
||||
--- Enum that stores aircraft refueling system types.
|
||||
-- @type Unit.RefuelingSystem
|
||||
-- @field BOOM_AND_RECEPTACLE
|
||||
-- @field PROBE_AND_DROGUE
|
||||
-- @field BOOM_AND_RECEPTACLE Tanker with a boom.
|
||||
-- @field PROBE_AND_DROGUE Tanker with a probe.
|
||||
|
||||
--- Enum that stores sensor types.
|
||||
-- @type Unit.SensorType
|
||||
@@ -1063,15 +1285,18 @@ do -- Unit
|
||||
-- @field #Distance detectionDistanceHRM detection distance for RCS=1m^2 in high-resolution mapping mode, nil if radar has no HRM
|
||||
-- @field #Unit.Radar.detectionDistanceAir detectionDistanceAir detection distance for RCS=1m^2 airborne target, nil if radar doesn't support air search
|
||||
|
||||
--- @type Unit.Radar.detectionDistanceAir
|
||||
--- A radar.
|
||||
-- @type Unit.Radar.detectionDistanceAir
|
||||
-- @field #Unit.Radar.detectionDistanceAir.upperHemisphere upperHemisphere
|
||||
-- @field #Unit.Radar.detectionDistanceAir.lowerHemisphere lowerHemisphere
|
||||
|
||||
--- @type Unit.Radar.detectionDistanceAir.upperHemisphere
|
||||
--- A radar.
|
||||
-- @type Unit.Radar.detectionDistanceAir.upperHemisphere
|
||||
-- @field #Distance headOn
|
||||
-- @field #Distance tailOn
|
||||
|
||||
--- @type Unit.Radar.detectionDistanceAir.lowerHemisphere
|
||||
--- A radar.
|
||||
-- @type Unit.Radar.detectionDistanceAir.lowerHemisphere
|
||||
-- @field #Distance headOn
|
||||
-- @field #Distance tailOn
|
||||
|
||||
@@ -1287,6 +1512,42 @@ do -- Group
|
||||
|
||||
end -- Group
|
||||
|
||||
do -- StaticObject
|
||||
|
||||
--- Represents a static object.
|
||||
-- @type StaticObject
|
||||
-- @extends DCS#Object
|
||||
|
||||
--- Returns the static object.
|
||||
-- @function [parent=#StaticObject] getByName
|
||||
-- @param #string name Name of the static object.
|
||||
-- @return #StaticObject
|
||||
|
||||
StaticObject = {} --#StaticObject
|
||||
|
||||
end
|
||||
|
||||
do --Event
|
||||
|
||||
--- Event structure. Note that present fields depend on type of event.
|
||||
-- @type Event
|
||||
-- @field #number id Event ID.
|
||||
-- @field #number time Mission time in seconds.
|
||||
-- @field DCS#Unit initiator Unit initiating the event.
|
||||
-- @field DCS#Unit target Target unit.
|
||||
-- @field DCS#Airbase place Airbase.
|
||||
-- @field number subPlace Subplace. Unknown and often just 0.
|
||||
-- @field #string weapon_name Weapoin name.
|
||||
-- @field #number idx Mark ID.
|
||||
-- @field #number coalition Coalition ID.
|
||||
-- @field #number groupID Group ID, *e.g.* of group that added mark point.
|
||||
-- @field #string text Text, *e.g.* of mark point.
|
||||
-- @field DCS#Vec3 pos Position vector, *e.g.* of mark point.
|
||||
-- @field #string comment Comment, *e.g.* LSO score.
|
||||
|
||||
Event={} --#Event
|
||||
|
||||
end
|
||||
|
||||
do -- AI
|
||||
|
||||
@@ -1337,22 +1598,26 @@ do -- AI
|
||||
-- @field IR_POINTER
|
||||
-- @field LASER
|
||||
|
||||
--- @type AI.Task.WaypointType
|
||||
---
|
||||
-- @type AI.Task.WaypointType
|
||||
-- @field TAKEOFF
|
||||
-- @field TAKEOFF_PARKING
|
||||
-- @field TURNING_POINT
|
||||
-- @field TAKEOFF_PARKING_HOT
|
||||
-- @field LAND
|
||||
|
||||
--- @type AI.Task.TurnMethod
|
||||
---
|
||||
-- @type AI.Task.TurnMethod
|
||||
-- @field FLY_OVER_POINT
|
||||
-- @field FIN_POINT
|
||||
|
||||
--- @type AI.Task.AltitudeType
|
||||
---
|
||||
-- @type AI.Task.AltitudeType
|
||||
-- @field BARO
|
||||
-- @field RADIO
|
||||
|
||||
--- @type AI.Task.VehicleFormation
|
||||
---
|
||||
-- @type AI.Task.VehicleFormation
|
||||
-- @field OFF_ROAD
|
||||
-- @field ON_ROAD
|
||||
-- @field RANK
|
||||
@@ -1362,27 +1627,30 @@ do -- AI
|
||||
-- @field ECHELON_LEFT
|
||||
-- @field ECHELON_RIGHT
|
||||
|
||||
--- @type AI.Option
|
||||
---
|
||||
-- @type AI.Option
|
||||
-- @field #AI.Option.Air Air
|
||||
-- @field #AI.Option.Ground Ground
|
||||
-- @field #AI.Option.Naval Naval
|
||||
|
||||
--- @type AI.Option.Air
|
||||
---
|
||||
-- @type AI.Option.Air
|
||||
-- @field #AI.Option.Air.id id
|
||||
-- @field #AI.Option.Air.val val
|
||||
|
||||
--- @type AI.Option.Ground
|
||||
---
|
||||
-- @type AI.Option.Ground
|
||||
-- @field #AI.Option.Ground.id id
|
||||
-- @field #AI.Option.Ground.val val
|
||||
-- @field #AI.Option.Ground.mid mid
|
||||
-- @field #AI.Option.Ground.mval mval
|
||||
--
|
||||
--- @type AI.Option.Naval
|
||||
-- @type AI.Option.Naval
|
||||
-- @field #AI.Option.Naval.id id
|
||||
-- @field #AI.Option.Naval.val val
|
||||
|
||||
|
||||
--- @type AI.Option.Air.id
|
||||
---
|
||||
-- @type AI.Option.Air.id
|
||||
-- @field NO_OPTION
|
||||
-- @field ROE
|
||||
-- @field REACTION_ON_THREAT
|
||||
@@ -1404,73 +1672,61 @@ do -- AI
|
||||
-- @field OPTION_RADIO_USAGE_KILL
|
||||
-- @field JETT_TANKS_IF_EMPTY
|
||||
-- @field FORCED_ATTACK
|
||||
|
||||
--- @type AI.Option.Air.id.FORMATION
|
||||
-- @field LINE_ABREAST
|
||||
-- @field TRAIL
|
||||
-- @field WEDGE
|
||||
-- @field ECHELON_RIGHT
|
||||
-- @field ECHELON_LEFT
|
||||
-- @field FINGER_FOUR
|
||||
-- @field SPREAD_FOUR
|
||||
-- @field WW2_BOMBER_ELEMENT
|
||||
-- @field WW2_BOMBER_ELEMENT_HEIGHT
|
||||
-- @field WW2_FIGHTER_VIC
|
||||
-- @field HEL_WEDGE
|
||||
-- @field HEL_ECHELON
|
||||
-- @field HEL_FRONT
|
||||
-- @field HEL_COLUMN
|
||||
-- @field COMBAT_BOX
|
||||
-- @field JAVELIN_DOWN
|
||||
|
||||
|
||||
--- @type AI.Option.Air.val
|
||||
---
|
||||
-- @type AI.Option.Air.val
|
||||
-- @field #AI.Option.Air.val.ROE ROE
|
||||
-- @field #AI.Option.Air.val.REACTION_ON_THREAT REACTION_ON_THREAT
|
||||
-- @field #AI.Option.Air.val.RADAR_USING RADAR_USING
|
||||
-- @field #AI.Option.Air.val.FLARE_USING FLARE_USING
|
||||
|
||||
--- @type AI.Option.Air.val.ROE
|
||||
---
|
||||
-- @type AI.Option.Air.val.ROE
|
||||
-- @field WEAPON_FREE
|
||||
-- @field OPEN_FIRE_WEAPON_FREE
|
||||
-- @field OPEN_FIRE
|
||||
-- @field RETURN_FIRE
|
||||
-- @field WEAPON_HOLD
|
||||
|
||||
--- @type AI.Option.Air.val.REACTION_ON_THREAT
|
||||
|
||||
---
|
||||
-- @type AI.Option.Air.val.REACTION_ON_THREAT
|
||||
-- @field NO_REACTION
|
||||
-- @field PASSIVE_DEFENCE
|
||||
-- @field EVADE_FIRE
|
||||
-- @field BYPASS_AND_ESCAPE
|
||||
-- @field ALLOW_ABORT_MISSION
|
||||
|
||||
--- @type AI.Option.Air.val.RADAR_USING
|
||||
---
|
||||
-- @type AI.Option.Air.val.RADAR_USING
|
||||
-- @field NEVER
|
||||
-- @field FOR_ATTACK_ONLY
|
||||
-- @field FOR_SEARCH_IF_REQUIRED
|
||||
-- @field FOR_CONTINUOUS_SEARCH
|
||||
|
||||
--- @type AI.Option.Air.val.FLARE_USING
|
||||
---
|
||||
-- @type AI.Option.Air.val.FLARE_USING
|
||||
-- @field NEVER
|
||||
-- @field AGAINST_FIRED_MISSILE
|
||||
-- @field WHEN_FLYING_IN_SAM_WEZ
|
||||
-- @field WHEN_FLYING_NEAR_ENEMIES
|
||||
|
||||
--- @type AI.Option.Air.val.ECM_USING
|
||||
|
||||
---
|
||||
-- @type AI.Option.Air.val.ECM_USING
|
||||
-- @field NEVER_USE
|
||||
-- @field USE_IF_ONLY_LOCK_BY_RADAR
|
||||
-- @field USE_IF_DETECTED_LOCK_BY_RADAR
|
||||
-- @field ALWAYS_USE
|
||||
|
||||
--- @type AI.Option.Air.val.MISSILE_ATTACK
|
||||
|
||||
---
|
||||
-- @type AI.Option.Air.val.MISSILE_ATTACK
|
||||
-- @field MAX_RANGE
|
||||
-- @field NEZ_RANGE
|
||||
-- @field HALF_WAY_RMAX_NEZ
|
||||
-- @field TARGET_THREAT_EST
|
||||
-- @field RANDOM_RANGE
|
||||
|
||||
|
||||
--- @type AI.Option.Ground.id
|
||||
---
|
||||
-- @type AI.Option.Ground.id
|
||||
-- @field NO_OPTION
|
||||
-- @field ROE @{#AI.Option.Ground.val.ROE}
|
||||
-- @field FORMATION
|
||||
@@ -1478,43 +1734,53 @@ do -- AI
|
||||
-- @field ALARM_STATE @{#AI.Option.Ground.val.ALARM_STATE}
|
||||
-- @field ENGAGE_AIR_WEAPONS
|
||||
-- @field AC_ENGAGEMENT_RANGE_RESTRICTION
|
||||
-- @field EVASION_OF_ARM
|
||||
|
||||
--- @type AI.Option.Ground.mid -- Moose added
|
||||
---
|
||||
-- @type AI.Option.Ground.mid -- Moose added
|
||||
-- @field RESTRICT_AAA_MIN 27
|
||||
-- @field RESTRICT_AAA_MAX 29
|
||||
-- @field RESTRICT_TARGETS @{#AI.Option.Ground.mval.ENGAGE_TARGETS} 28
|
||||
|
||||
--- @type AI.Option.Ground.val
|
||||
---
|
||||
-- @type AI.Option.Ground.val
|
||||
-- @field #AI.Option.Ground.val.ROE ROE
|
||||
-- @field #AI.Option.Ground.val.ALARM_STATE ALARM_STATE
|
||||
-- @field #AI.Option.Ground.val.ENGAGE_TARGETS RESTRICT_TARGETS
|
||||
|
||||
--- @type AI.Option.Ground.val.ROE
|
||||
---
|
||||
-- @type AI.Option.Ground.val.ROE
|
||||
-- @field OPEN_FIRE
|
||||
-- @field RETURN_FIRE
|
||||
-- @field WEAPON_HOLD
|
||||
|
||||
--- @type AI.Option.Ground.mval -- Moose added
|
||||
---
|
||||
-- @type AI.Option.Ground.mval -- Moose added
|
||||
-- @field #AI.Option.Ground.mval.ENGAGE_TARGETS ENGAGE_TARGETS
|
||||
|
||||
--- @type AI.Option.Ground.mval.ENGAGE_TARGETS -- Moose added
|
||||
---
|
||||
-- @type AI.Option.Ground.mval.ENGAGE_TARGETS -- Moose added
|
||||
-- @field ANY_TARGET -- 0
|
||||
-- @field AIR_UNITS_ONLY -- 1
|
||||
-- @field GROUND_UNITS_ONLY -- 2
|
||||
|
||||
--- @type AI.Option.Ground.val.ALARM_STATE
|
||||
---
|
||||
-- @type AI.Option.Ground.val.ALARM_STATE
|
||||
-- @field AUTO
|
||||
-- @field GREEN
|
||||
-- @field RED
|
||||
|
||||
--- @type AI.Option.Naval.id
|
||||
---
|
||||
-- @type AI.Option.Naval.id
|
||||
-- @field NO_OPTION
|
||||
-- @field ROE
|
||||
|
||||
--- @type AI.Option.Naval.val
|
||||
---
|
||||
-- @type AI.Option.Naval.val
|
||||
-- @field #AI.Option.Naval.val.ROE ROE
|
||||
|
||||
--- @type AI.Option.Naval.val.ROE
|
||||
---
|
||||
-- @type AI.Option.Naval.val.ROE
|
||||
-- @field OPEN_FIRE
|
||||
-- @field RETURN_FIRE
|
||||
-- @field WEAPON_HOLD
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Monitor airbase traffic and regulate speed while taxiing.
|
||||
--- **Functional** - Monitor airbase traffic and regulate speed while taxiing.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -10,9 +10,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [ABP - Airbase Police](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/ABP%20-%20Airbase%20Police)
|
||||
-- ## Missions: None
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -20,13 +18,15 @@
|
||||
-- ### Author: FlightControl - Framework Design & Programming
|
||||
-- ### Refactoring to use the Runway auto-detection: Applevangelist
|
||||
-- @date August 2022
|
||||
-- Last Update Feb 2025
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module Functional.ATC_Ground
|
||||
-- @image Air_Traffic_Control_Ground_Operations.JPG
|
||||
|
||||
--- @type ATC_GROUND
|
||||
---
|
||||
-- @type ATC_GROUND
|
||||
-- @field Core.Set#SET_CLIENT SetClient
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
@@ -39,7 +39,8 @@ ATC_GROUND = {
|
||||
AirbaseNames = nil,
|
||||
}
|
||||
|
||||
--- @type ATC_GROUND.AirbaseNames
|
||||
---
|
||||
-- @type ATC_GROUND.AirbaseNames
|
||||
-- @list <#string>
|
||||
|
||||
|
||||
@@ -51,7 +52,7 @@ function ATC_GROUND:New( Airbases, AirbaseList )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #ATC_GROUND
|
||||
self:E( { self.ClassName, Airbases } )
|
||||
self:T( { self.ClassName, Airbases } )
|
||||
|
||||
self.Airbases = Airbases
|
||||
self.AirbaseList = AirbaseList
|
||||
@@ -82,7 +83,7 @@ function ATC_GROUND:New( Airbases, AirbaseList )
|
||||
end
|
||||
|
||||
self.SetClient:ForEachClient(
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
function( Client )
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0)
|
||||
@@ -246,11 +247,11 @@ function ATC_GROUND:SetMaximumKickSpeedMiph( MaximumKickSpeedMiph, Airbase )
|
||||
return self
|
||||
end
|
||||
|
||||
--- @param #ATC_GROUND self
|
||||
-- @param #ATC_GROUND self
|
||||
function ATC_GROUND:_AirbaseMonitor()
|
||||
|
||||
self.SetClient:ForEachClient(
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
function( Client )
|
||||
|
||||
if Client:IsAlive() then
|
||||
@@ -258,7 +259,7 @@ function ATC_GROUND:_AirbaseMonitor()
|
||||
local IsOnGround = Client:InAir() == false
|
||||
|
||||
for AirbaseID, AirbaseMeta in pairs( self.Airbases ) do
|
||||
self:E( AirbaseID, AirbaseMeta.KickSpeed )
|
||||
self:T( AirbaseID, AirbaseMeta.KickSpeed )
|
||||
|
||||
if AirbaseMeta.Monitor == true and Client:IsInZone( AirbaseMeta.ZoneBoundary ) then
|
||||
|
||||
@@ -271,7 +272,7 @@ function ATC_GROUND:_AirbaseMonitor()
|
||||
|
||||
if IsOnGround then
|
||||
local Taxi = Client:GetState( self, "Taxi" )
|
||||
self:E( Taxi )
|
||||
self:T( Taxi )
|
||||
if Taxi == false then
|
||||
local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed )
|
||||
Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " ..
|
||||
@@ -331,7 +332,7 @@ function ATC_GROUND:_AirbaseMonitor()
|
||||
Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
|
||||
else
|
||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
Client:Destroy()
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0 )
|
||||
@@ -363,7 +364,7 @@ function ATC_GROUND:_AirbaseMonitor()
|
||||
Client:SetState( self, "OffRunwayWarnings", OffRunwayWarnings + 1 )
|
||||
else
|
||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
Client:Destroy()
|
||||
Client:SetState( self, "IsOffRunway", false )
|
||||
Client:SetState( self, "OffRunwayWarnings", 0 )
|
||||
@@ -415,7 +416,7 @@ end
|
||||
-- @field #ATC_GROUND_UNIVERSAL
|
||||
ATC_GROUND_UNIVERSAL = {
|
||||
ClassName = "ATC_GROUND_UNIVERSAL",
|
||||
Version = "0.0.1",
|
||||
Version = "0.0.2",
|
||||
SetClient = nil,
|
||||
Airbases = nil,
|
||||
AirbaseList = nil,
|
||||
@@ -424,22 +425,44 @@ ATC_GROUND_UNIVERSAL = {
|
||||
|
||||
--- Creates a new ATC\_GROUND\_UNIVERSAL object. This works on any map.
|
||||
-- @param #ATC_GROUND_UNIVERSAL self
|
||||
-- @param AirbaseList (Optional) A table of Airbase Names.
|
||||
-- @param AirbaseList A table of Airbase Names. Leave empty to cover **all** airbases of the map.
|
||||
-- @return #ATC_GROUND_UNIVERSAL self
|
||||
-- @usage
|
||||
-- -- define monitoring for one airbase
|
||||
-- local atc=ATC_GROUND_UNIVERSAL:New({AIRBASE.Syria.Gecitkale})
|
||||
-- -- set kick speed
|
||||
-- atc:SetKickSpeed(UTILS.KnotsToMps(20))
|
||||
-- -- start monitoring evey 10 secs
|
||||
-- atc:Start(10)
|
||||
function ATC_GROUND_UNIVERSAL:New(AirbaseList)
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #ATC_GROUND
|
||||
self:E( { self.ClassName } )
|
||||
self:T( { self.ClassName } )
|
||||
|
||||
self.Airbases = {}
|
||||
|
||||
for _name,_ in pairs(_DATABASE.AIRBASES) do
|
||||
self.Airbases[_name]={}
|
||||
end
|
||||
|
||||
self.AirbaseList = AirbaseList
|
||||
|
||||
if not self.AirbaseList then
|
||||
self.AirbaseList = {}
|
||||
for _name,_base in pairs(_DATABASE.AIRBASES) do
|
||||
-- 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
|
||||
|
||||
self.SetClient = SET_CLIENT:New():FilterCategories( "plane" ):FilterStart()
|
||||
|
||||
|
||||
@@ -460,8 +483,9 @@ function ATC_GROUND_UNIVERSAL:New(AirbaseList)
|
||||
self.Airbases[AirbaseName].Monitor = true
|
||||
end
|
||||
|
||||
|
||||
self.SetClient:ForEachClient(
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
function( Client )
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0)
|
||||
@@ -679,9 +703,10 @@ end
|
||||
-- @param #ATC_GROUND_UNIVERSAL self
|
||||
-- @return #ATC_GROUND_UNIVERSAL self
|
||||
function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
|
||||
self:I("_AirbaseMonitor")
|
||||
self.SetClient:ForEachClient(
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
--- Nameless function
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
function( Client )
|
||||
|
||||
if Client:IsAlive() then
|
||||
@@ -689,7 +714,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
local IsOnGround = Client:InAir() == false
|
||||
|
||||
for AirbaseID, AirbaseMeta in pairs( self.Airbases ) do
|
||||
self:E( AirbaseID, AirbaseMeta.KickSpeed )
|
||||
self:T( AirbaseID, AirbaseMeta.KickSpeed )
|
||||
|
||||
if AirbaseMeta.Monitor == true and Client:IsInZone( AirbaseMeta.ZoneBoundary ) then
|
||||
|
||||
@@ -704,14 +729,18 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
|
||||
if NotInRunwayZone then
|
||||
|
||||
local Taxi = Client:GetState( self, "Taxi" )
|
||||
|
||||
if IsOnGround then
|
||||
local Taxi = Client:GetState( self, "Taxi" )
|
||||
self:E( Taxi )
|
||||
|
||||
self:T( Taxi )
|
||||
if Taxi == false then
|
||||
local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed )
|
||||
Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " ..
|
||||
Velocity:ToString() , 20, "ATC" )
|
||||
Client:SetState( self, "Taxi", true )
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0 )
|
||||
end
|
||||
|
||||
-- TODO: GetVelocityKMH function usage
|
||||
@@ -720,7 +749,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
local IsAboveRunway = Client:IsAboveRunway()
|
||||
self:T( {IsAboveRunway, IsOnGround, Velocity:Get() })
|
||||
|
||||
if IsOnGround then
|
||||
if IsOnGround and not Taxi then
|
||||
local Speeding = false
|
||||
if AirbaseMeta.MaximumKickSpeed then
|
||||
if Velocity:Get() > AirbaseMeta.MaximumKickSpeed then
|
||||
@@ -732,15 +761,17 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
end
|
||||
end
|
||||
if Speeding == true then
|
||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
|
||||
" has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
Client:Destroy()
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0 )
|
||||
--MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
|
||||
-- " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
--Client:Destroy()
|
||||
Client:SetState( self, "Speeding", true )
|
||||
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
|
||||
|
||||
|
||||
|
||||
if IsOnGround then
|
||||
|
||||
local Speeding = false
|
||||
@@ -766,7 +797,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
|
||||
else
|
||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
Client:Destroy()
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0 )
|
||||
@@ -798,7 +829,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
Client:SetState( self, "OffRunwayWarnings", OffRunwayWarnings + 1 )
|
||||
else
|
||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
Client:Destroy()
|
||||
Client:SetState( self, "IsOffRunway", false )
|
||||
Client:SetState( self, "OffRunwayWarnings", 0 )
|
||||
@@ -838,15 +869,16 @@ end
|
||||
|
||||
--- Start SCHEDULER for ATC_GROUND_UNIVERSAL object.
|
||||
-- @param #ATC_GROUND_UNIVERSAL self
|
||||
-- @param RepeatScanSeconds Time in second for defining occurency of alerts.
|
||||
-- @param RepeatScanSeconds Time in second for defining schedule of alerts.
|
||||
-- @return #ATC_GROUND_UNIVERSAL self
|
||||
function ATC_GROUND_UNIVERSAL:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
return self
|
||||
end
|
||||
|
||||
--- @type ATC_GROUND_CAUCASUS
|
||||
---
|
||||
-- @type ATC_GROUND_CAUCASUS
|
||||
-- @extends #ATC_GROUND
|
||||
|
||||
--- # ATC\_GROUND\_CAUCASUS, extends @{#ATC_GROUND_UNIVERSAL}
|
||||
@@ -981,12 +1013,12 @@ end
|
||||
-- @return nothing
|
||||
function ATC_GROUND_CAUCASUS:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @type ATC_GROUND_NEVADA
|
||||
---
|
||||
-- @type ATC_GROUND_NEVADA
|
||||
-- @extends #ATC_GROUND
|
||||
|
||||
|
||||
@@ -1017,23 +1049,23 @@ end
|
||||
-- The following airbases are monitored at the Nevada region.
|
||||
-- Use the @{Wrapper.Airbase#AIRBASE.Nevada} enumeration to select the airbases to be monitored.
|
||||
--
|
||||
-- * `AIRBASE.Nevada.Beatty_Airport`
|
||||
-- * `AIRBASE.Nevada.Boulder_City_Airport`
|
||||
-- * `AIRBASE.Nevada.Creech_AFB`
|
||||
-- * `AIRBASE.Nevada.Beatty`
|
||||
-- * `AIRBASE.Nevada.Boulder_City`
|
||||
-- * `AIRBASE.Nevada.Creech`
|
||||
-- * `AIRBASE.Nevada.Echo_Bay`
|
||||
-- * `AIRBASE.Nevada.Groom_Lake_AFB`
|
||||
-- * `AIRBASE.Nevada.Henderson_Executive_Airport`
|
||||
-- * `AIRBASE.Nevada.Jean_Airport`
|
||||
-- * `AIRBASE.Nevada.Laughlin_Airport`
|
||||
-- * `AIRBASE.Nevada.Groom_Lake`
|
||||
-- * `AIRBASE.Nevada.Henderson_Executive`
|
||||
-- * `AIRBASE.Nevada.Jean`
|
||||
-- * `AIRBASE.Nevada.Laughlin`
|
||||
-- * `AIRBASE.Nevada.Lincoln_County`
|
||||
-- * `AIRBASE.Nevada.McCarran_International_Airport`
|
||||
-- * `AIRBASE.Nevada.McCarran_International`
|
||||
-- * `AIRBASE.Nevada.Mesquite`
|
||||
-- * `AIRBASE.Nevada.Mina_Airport`
|
||||
-- * `AIRBASE.Nevada.Nellis_AFB`
|
||||
-- * `AIRBASE.Nevada.Mina`
|
||||
-- * `AIRBASE.Nevada.Nellis`
|
||||
-- * `AIRBASE.Nevada.North_Las_Vegas`
|
||||
-- * `AIRBASE.Nevada.Pahute_Mesa_Airstrip`
|
||||
-- * `AIRBASE.Nevada.Tonopah_Airport`
|
||||
-- * `AIRBASE.Nevada.Tonopah_Test_Range_Airfield`
|
||||
-- * `AIRBASE.Nevada.Pahute_Mesa`
|
||||
-- * `AIRBASE.Nevada.Tonopah`
|
||||
-- * `AIRBASE.Nevada.Tonopah_Test_Range`
|
||||
--
|
||||
-- # Installation
|
||||
--
|
||||
@@ -1070,10 +1102,10 @@ end
|
||||
--
|
||||
-- -- Monitor specific airbases.
|
||||
-- ATC_Ground = ATC_GROUND_NEVADA:New(
|
||||
-- { AIRBASE.Nevada.Laughlin_Airport,
|
||||
-- { AIRBASE.Nevada.Laughlin,
|
||||
-- AIRBASE.Nevada.Lincoln_County,
|
||||
-- AIRBASE.Nevada.North_Las_Vegas,
|
||||
-- AIRBASE.Nevada.McCarran_International_Airport
|
||||
-- AIRBASE.Nevada.McCarran_International
|
||||
-- }
|
||||
-- )
|
||||
--
|
||||
@@ -1120,11 +1152,11 @@ end
|
||||
-- @return nothing
|
||||
function ATC_GROUND_NEVADA:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
end
|
||||
|
||||
|
||||
--- @type ATC_GROUND_NORMANDY
|
||||
---
|
||||
-- @type ATC_GROUND_NORMANDY
|
||||
-- @extends #ATC_GROUND
|
||||
|
||||
|
||||
@@ -1277,10 +1309,11 @@ end
|
||||
-- @return nothing
|
||||
function ATC_GROUND_NORMANDY:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
end
|
||||
|
||||
--- @type ATC_GROUND_PERSIANGULF
|
||||
---
|
||||
-- @type ATC_GROUND_PERSIANGULF
|
||||
-- @extends #ATC_GROUND
|
||||
|
||||
|
||||
@@ -1311,33 +1344,33 @@ end
|
||||
-- The following airbases are monitored at the PersianGulf region.
|
||||
-- Use the @{Wrapper.Airbase#AIRBASE.PersianGulf} enumeration to select the airbases to be monitored.
|
||||
--
|
||||
-- * `AIRBASE.PersianGulf.Abu_Musa_Island_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Al_Dhafra_AB`
|
||||
-- * `AIRBASE.PersianGulf.Abu_Musa_Island`
|
||||
-- * `AIRBASE.PersianGulf.Al_Dhafra_AFB`
|
||||
-- * `AIRBASE.PersianGulf.Al_Maktoum_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Al_Minhad_AB`
|
||||
-- * `AIRBASE.PersianGulf.Al_Minhad_AFB`
|
||||
-- * `AIRBASE.PersianGulf.Bandar_Abbas_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Bandar_Lengeh`
|
||||
-- * `AIRBASE.PersianGulf.Dubai_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Fujairah_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Havadarya`
|
||||
-- * `AIRBASE.PersianGulf.Kerman_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Kerman`
|
||||
-- * `AIRBASE.PersianGulf.Khasab`
|
||||
-- * `AIRBASE.PersianGulf.Lar_Airbase`
|
||||
-- * `AIRBASE.PersianGulf.Lar`
|
||||
-- * `AIRBASE.PersianGulf.Qeshm_Island`
|
||||
-- * `AIRBASE.PersianGulf.Sharjah_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Shiraz_International_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Shiraz_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Sir_Abu_Nuayr`
|
||||
-- * `AIRBASE.PersianGulf.Sirri_Island`
|
||||
-- * `AIRBASE.PersianGulf.Tunb_Island_AFB`
|
||||
-- * `AIRBASE.PersianGulf.Tunb_Kochak`
|
||||
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Bandar_e_Jask_airfield`
|
||||
-- * `AIRBASE.PersianGulf.Abu_Dhabi_International_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Al_Bateen_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Kish_International_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Al_Ain_International_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Lavan_Island_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Jiroft_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel`
|
||||
-- * `AIRBASE.PersianGulf.Bandar_e_Jask`
|
||||
-- * `AIRBASE.PersianGulf.Abu_Dhabi_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Al_Bateen`
|
||||
-- * `AIRBASE.PersianGulf.Kish_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Al_Ain_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Lavan_Island`
|
||||
-- * `AIRBASE.PersianGulf.Jiroft`
|
||||
--
|
||||
-- # Installation
|
||||
--
|
||||
@@ -1372,8 +1405,8 @@ end
|
||||
-- AirbasePoliceCaucasus = ATC_GROUND_PERSIANGULF:New()
|
||||
--
|
||||
-- ATC_Ground = ATC_GROUND_PERSIANGULF:New(
|
||||
-- { AIRBASE.PersianGulf.Kerman_Airport,
|
||||
-- AIRBASE.PersianGulf.Al_Minhad_AB
|
||||
-- { AIRBASE.PersianGulf.Kerman,
|
||||
-- AIRBASE.PersianGulf.Al_Minhad_AFB
|
||||
-- }
|
||||
-- )
|
||||
--
|
||||
@@ -1419,14 +1452,13 @@ end
|
||||
-- @return nothing
|
||||
function ATC_GROUND_PERSIANGULF:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
end
|
||||
|
||||
|
||||
--- @type ATC_GROUND_MARIANAISLANDS
|
||||
---
|
||||
-- @type ATC_GROUND_MARIANAISLANDS
|
||||
-- @extends #ATC_GROUND
|
||||
|
||||
|
||||
|
||||
--- # ATC\_GROUND\_MARIANA, extends @{#ATC_GROUND}
|
||||
--
|
||||
@@ -1517,7 +1549,7 @@ end
|
||||
-- * @{#ATC_GROUND.SetMaximumKickSpeedKmph}(): Set the maximum speed allowed at an airbase in kilometers per hour.
|
||||
-- * @{#ATC_GROUND.SetMaximumKickSpeedMiph}(): Set the maximum speed allowed at an airbase in miles per hour.
|
||||
--
|
||||
---- @field #ATC_GROUND_MARIANAISLANDS
|
||||
-- @field #ATC_GROUND_MARIANAISLANDS
|
||||
ATC_GROUND_MARIANAISLANDS = {
|
||||
ClassName = "ATC_GROUND_MARIANAISLANDS",
|
||||
}
|
||||
@@ -1529,7 +1561,7 @@ ATC_GROUND_MARIANAISLANDS = {
|
||||
function ATC_GROUND_MARIANAISLANDS:New( AirbaseNames )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, ATC_GROUND_UNIVERSAL:New( self.Airbases, AirbaseNames ) )
|
||||
local self = BASE:Inherit( self, ATC_GROUND_UNIVERSAL:New( AirbaseNames ) )
|
||||
|
||||
self:SetKickSpeedKmph( 50 )
|
||||
self:SetMaximumKickSpeedKmph( 150 )
|
||||
@@ -1543,5 +1575,5 @@ end
|
||||
-- @return nothing
|
||||
function ATC_GROUND_MARIANAISLANDS:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
end
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
|
||||
-- ### Contributions: FlightControl
|
||||
--
|
||||
-- ====
|
||||
-- @module Functional.Arty
|
||||
-- @module Functional.Artillery
|
||||
-- @image Artillery.JPG
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -45,6 +45,7 @@
|
||||
-- @field #table currentMove Holds the current commanded move, if there is one assigned.
|
||||
-- @field #number Nammo0 Initial amount total ammunition (shells+rockets+missiles) of the whole group.
|
||||
-- @field #number Nshells0 Initial amount of shells of the whole group.
|
||||
-- @field #number Narty0 Initial amount of artillery shells of the whole group.
|
||||
-- @field #number Nrockets0 Initial amount of rockets of the whole group.
|
||||
-- @field #number Nmissiles0 Initial amount of missiles of the whole group.
|
||||
-- @field #number Nukes0 Initial amount of tactical nukes of the whole group. Default is 0.
|
||||
@@ -103,12 +104,13 @@
|
||||
-- @field #number coalition The coalition of the arty group.
|
||||
-- @field #boolean respawnafterdeath Respawn arty group after all units are dead.
|
||||
-- @field #number respawndelay Respawn delay in seconds.
|
||||
-- @field #number dtTrack Time interval in seconds for weapon tracking.
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
|
||||
--- Enables mission designers easily to assign targets for artillery units. Since the implementation is based on a Finite State Model (FSM), the mission designer can
|
||||
-- interact with the process at certain events or states.
|
||||
--
|
||||
-- A new ARTY object can be created with the @{#ARTY.New}(*group*) contructor.
|
||||
-- A new ARTY object can be created with the @{#ARTY.New}(*group*) constructor.
|
||||
-- The parameter *group* has to be a MOOSE Group object and defines ARTY group.
|
||||
--
|
||||
-- The ARTY FSM process can be started by the @{#ARTY.Start}() command.
|
||||
@@ -146,7 +148,7 @@
|
||||
-- When a new target is assigned via the @{#ARTY.AssignTargetCoord}() function (see below), the **NewTarget** event is triggered.
|
||||
--
|
||||
-- ## Assigning Targets
|
||||
-- Assigning targets is a central point of the ARTY class. Multiple targets can be assigned simultanioulsly and are put into a queue.
|
||||
-- Assigning targets is a central point of the ARTY class. Multiple targets can be assigned simultaneously and are put into a queue.
|
||||
-- Of course, targets can be added at any time during the mission. For example, once they are detected by a reconnaissance unit.
|
||||
--
|
||||
-- In order to add a target, the function @{#ARTY.AssignTargetCoord}(*coord*, *prio*, *radius*, *nshells*, *maxengage*, *time*, *weapontype*, *name*) has to be used.
|
||||
@@ -161,7 +163,7 @@
|
||||
-- * *maxengage*: Number of times a target is engaged.
|
||||
-- * *time*: Time of day the engagement is schedule in the format "hh:mm:ss" for hh=hours, mm=minutes, ss=seconds.
|
||||
-- For example "10:15:35". In the case the attack will be executed at a quarter past ten in the morning at the day the mission started.
|
||||
-- If the engagement should start on the following day the format can be specified as "10:15:35+1", where the +1 denots the following day.
|
||||
-- If the engagement should start on the following day the format can be specified as "10:15:35+1", where the +1 denotes the following day.
|
||||
-- This is useful for longer running missions or if the mission starts at 23:00 hours and the attack should be scheduled at 01:00 hours on the following day.
|
||||
-- Of course, later days are also possible by appending "+2", "+3", etc.
|
||||
-- **Note** that the time has to be given as a string. So the enclosing quotation marks "" are important.
|
||||
@@ -179,7 +181,7 @@
|
||||
-- Let's first consider the case that none of the targets is scheduled to be executed at a certain time (*time*=nil).
|
||||
-- The ARTY group will first engage the target with higher priority (*prio*=10). After the engagement is finished, the target with lower priority is attacked.
|
||||
-- This is because the target with lower prio has been attacked one time less. After the attack on the lower priority task is finished and both targets
|
||||
-- have been engaged equally often, the target with the higher priority is engaged again. This coninues until a target has engaged three times.
|
||||
-- have been engaged equally often, the target with the higher priority is engaged again. This continues until a target has engaged three times.
|
||||
-- Once the maximum number of engagements is reached, the target is deleted from the queue.
|
||||
--
|
||||
-- In other words, the queue is first sorted with respect to the number of engagements and targets with the same number of engagements are sorted with
|
||||
@@ -190,7 +192,7 @@
|
||||
-- As mentioned above, targets can be engaged at a specific time of the day via the *time* parameter.
|
||||
--
|
||||
-- If the *time* parameter is specified for a target, the first engagement of that target will happen at that time of the day and not before.
|
||||
-- This also applies when multiple engagements are requested via the *maxengage* parameter. The first attack will not happen before the specifed time.
|
||||
-- This also applies when multiple engagements are requested via the *maxengage* parameter. The first attack will not happen before the specified time.
|
||||
-- When that timed attack is finished, the *time* parameter is deleted and the remaining engagements are carried out in the same manner as for untimed targets (described above).
|
||||
--
|
||||
-- Of course, it can happen that a scheduled task should be executed at a time, when another target is already under attack.
|
||||
@@ -201,7 +203,7 @@
|
||||
--
|
||||
-- ## Determining the Amount of Ammo
|
||||
--
|
||||
-- In order to determin when a unit is out of ammo and possible initiate the rearming process it is necessary to know which types of weapons have to be counted.
|
||||
-- In order to determine when a unit is out of ammo and possible initiate the rearming process it is necessary to know which types of weapons have to be counted.
|
||||
-- For most artillery unit types, this is simple because they only have one type of weapon and hence ammunition.
|
||||
--
|
||||
-- However, there are more complex scenarios. For example, naval units carry a big arsenal of different ammunition types ranging from various cannon shell types
|
||||
@@ -217,7 +219,7 @@
|
||||
-- **Note** that the default parameters "weapons.shells", "weapons.nurs", "weapons.missiles" **should in priciple** capture all the corresponding ammo types.
|
||||
-- However, the logic searches for the string "weapon.missies" in the ammo type. Especially for missiles, this string is often not contained in the ammo type descriptor.
|
||||
--
|
||||
-- One way to determin which types of ammo the unit carries, one can use the debug mode of the arty class via @{#ARTY.SetDebugON}().
|
||||
-- One way to determine which types of ammo the unit carries, one can use the debug mode of the arty class via @{#ARTY.SetDebugON}().
|
||||
-- In debug mode, the all ammo types of the group are printed to the monitor as message and can be found in the DCS.log file.
|
||||
--
|
||||
-- ## Employing Selected Weapons
|
||||
@@ -274,7 +276,7 @@
|
||||
--
|
||||
-- ## Simulated Weapons
|
||||
--
|
||||
-- In addtion to the standard weapons a group has available some special weapon types that are not possible to use in the native DCS environment are simulated.
|
||||
-- In addition to the standard weapons a group has available some special weapon types that are not possible to use in the native DCS environment are simulated.
|
||||
--
|
||||
-- ### Tactical Nukes
|
||||
--
|
||||
@@ -283,30 +285,30 @@
|
||||
--
|
||||
-- By default, they group does not have any nukes available. To give the group the ability the function @{#ARTY.SetTacNukeShells}(*n*) can be used.
|
||||
-- This supplies the group with *n* nuclear shells, where *n* is restricted to the number of conventional shells the group can carry.
|
||||
-- Note that the group must always have convenctional shells left in order to fire a nuclear shell.
|
||||
-- Note that the group must always have conventional shells left in order to fire a nuclear shell.
|
||||
--
|
||||
-- The default explostion strength is 0.075 kilo tons TNT. The can be changed with the @{#ARTY.SetTacNukeWarhead}(*strength*), where *strength* is given in kilo tons TNT.
|
||||
-- The default explosion strength is 0.075 kilo tons TNT. The can be changed with the @{#ARTY.SetTacNukeWarhead}(*strength*), where *strength* is given in kilo tons TNT.
|
||||
--
|
||||
-- ### Illumination Shells
|
||||
--
|
||||
-- ARTY groups that possess shells can fire shells with illumination bombs. First, the group needs to be equipped with this weapon. This is done by the
|
||||
-- function @{ARTY.SetIlluminationShells}(*n*, *power*), where *n* is the number of shells the group has available and *power* the illumination power in mega candela (mcd).
|
||||
-- function @{#ARTY.SetIlluminationShells}(*n*, *power*), where *n* is the number of shells the group has available and *power* the illumination power in mega candela (mcd).
|
||||
--
|
||||
-- In order to execute an engagement with illumination shells one has to use the weapon type *ARTY.WeaponType.IlluminationShells* in the
|
||||
-- @{#ARTY.AssignTargetCoord}() function.
|
||||
--
|
||||
-- In the simulation, the explosive shell that is fired is destroyed once it gets close to the target point but before it can actually impact.
|
||||
-- At this position an illumination bomb is triggered at a random altitude between 500 and 1000 meters. This interval can be set by the function
|
||||
-- @{ARTY.SetIlluminationMinMaxAlt}(*minalt*, *maxalt*).
|
||||
-- @{#ARTY.SetIlluminationMinMaxAlt}(*minalt*, *maxalt*).
|
||||
--
|
||||
-- ### Smoke Shells
|
||||
--
|
||||
-- In a similar way to illumination shells, ARTY groups can also employ smoke shells. The numer of smoke shells the group has available is set by the function
|
||||
-- In a similar way to illumination shells, ARTY groups can also employ smoke shells. The number of smoke shells the group has available is set by the function
|
||||
-- @{#ARTY.SetSmokeShells}(*n*, *color*), where *n* is the number of shells and *color* defines the smoke color. Default is SMOKECOLOR.Red.
|
||||
--
|
||||
-- The weapon type to be used in the @{#ARTY.AssignTargetCoord}() function is *ARTY.WeaponType.SmokeShells*.
|
||||
--
|
||||
-- The explosive shell the group fired is destroyed shortly before its impact on the ground and smoke of the speficied color is triggered at that position.
|
||||
-- The explosive shell the group fired is destroyed shortly before its impact on the ground and smoke of the specified color is triggered at that position.
|
||||
--
|
||||
--
|
||||
-- ## Assignments via Markers on F10 Map
|
||||
@@ -320,15 +322,15 @@
|
||||
-- ### Target Assignments
|
||||
-- A new target can be assigned by writing **arty engage** in the marker text.
|
||||
-- This is followed by a **comma separated list** of (optional) keywords and parameters.
|
||||
-- First, it is important to address the ARTY group or groups that should engage. This can be done in numrous ways. The keywords are *battery*, *alias*, *cluster*.
|
||||
-- First, it is important to address the ARTY group or groups that should engage. This can be done in numerous ways. The keywords are *battery*, *alias*, *cluster*.
|
||||
-- It is also possible to address all ARTY groups by the keyword *everyone* or *allbatteries*. These two can be used synonymously.
|
||||
-- **Note that**, if no battery is assigned nothing will happen.
|
||||
--
|
||||
-- * *everyone* or *allbatteries* The target is assigned to all batteries.
|
||||
-- * *battery* Name of the ARTY group that the target is assigned to. Note that **the name is case sensitive** and has to be given in quotation marks. Default is all ARTY groups of the right coalition.
|
||||
-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks.
|
||||
-- * *cluster* The cluster of ARTY groups that is addessed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
|
||||
-- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement.
|
||||
-- * *cluster* The cluster of ARTY groups that is addressed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
|
||||
-- * *key* A number to authorize the target assignment. Only specifying the correct number will trigger an engagement.
|
||||
-- * *time* Time for which which the engagement is schedules, e.g. 08:42. Default is as soon as possible.
|
||||
-- * *prio* Priority of the engagement as number between 1 (high prio) and 100 (low prio). Default is 50, i.e. medium priority.
|
||||
-- * *shots* Number of shots (shells, rockets or missiles) fired at each engagement. Default is 5.
|
||||
@@ -353,8 +355,8 @@
|
||||
-- arty engage, battery "Paladin Alpha", weapon nukes, shots 1, time 20:15
|
||||
-- arty engage, battery "Horwitzer 1", lldms 41:51:00N 41:47:58E
|
||||
--
|
||||
-- Note that the keywords and parameters are *case insensitve*. Only exception are the battery, alias and cluster names.
|
||||
-- These must be exactly the same as the names of the goups defined in the mission editor or the aliases and cluster names defined in the script.
|
||||
-- Note that the keywords and parameters are *case insensitive*. Only exception are the battery, alias and cluster names.
|
||||
-- These must be exactly the same as the names of the groups defined in the mission editor or the aliases and cluster names defined in the script.
|
||||
--
|
||||
-- ### Relocation Assignments
|
||||
--
|
||||
@@ -363,11 +365,11 @@
|
||||
-- * *time* Time for which which the relocation/move is schedules, e.g. 08:42. Default is as soon as possible.
|
||||
-- * *speed* The speed in km/h the group will drive at. Default is 70% of its max possible speed.
|
||||
-- * *on road* Group will use mainly roads. Default is off, i.e. it will go in a straight line from its current position to the assigned coordinate.
|
||||
-- * *canceltarget* Group will cancel all running firing engagements and immidiately start to move. Default is that group will wait until is current assignment is over.
|
||||
-- * *canceltarget* Group will cancel all running firing engagements and immediately start to move. Default is that group will wait until is current assignment is over.
|
||||
-- * *battery* Name of the ARTY group that the relocation is assigned to.
|
||||
-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks.
|
||||
-- * *cluster* The cluster of ARTY groups that is addessed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
|
||||
-- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement.
|
||||
-- * *cluster* The cluster of ARTY groups that is addressed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
|
||||
-- * *key* A number to authorize the target assignment. Only specifying the correct number will trigger an engagement.
|
||||
-- * *lldms* Specify the coordinates in Lat/Long degrees, minutes and seconds format. The actual location of the marker is unimportant. The group will move to the coordinates given in the lldms keyword.
|
||||
-- Format is DD:MM:SS[N,S] DD:MM:SS[W,E]. See example below.
|
||||
-- * *readonly* Marker cannot be deleted by users any more. Hence, assignment cannot be cancelled by removing the marker.
|
||||
@@ -410,12 +412,12 @@
|
||||
--
|
||||
-- A few options can be set by marks. The corresponding keyword is **arty set**. This can be used to define the rearming place and group for a battery.
|
||||
--
|
||||
-- To set the reamring place of a group at the marker position type
|
||||
-- To set the rearming place of a group at the marker position type
|
||||
-- arty set, battery "Paladin Alpha", rearming place
|
||||
--
|
||||
-- Setting the rearming group is independent of the position of the mark. Just create one anywhere on the map and type
|
||||
-- arty set, battery "Mortar Bravo", rearming group "Ammo Truck M818"
|
||||
-- Note that the name of the rearming group has to be given in quotation marks and spellt exactly as the group name defined in the mission editor.
|
||||
-- arty set, battery "Mortar Bravo", rearming group "Ammo Truck M939"
|
||||
-- Note that the name of the rearming group has to be given in quotation marks and spelt exactly as the group name defined in the mission editor.
|
||||
--
|
||||
-- ## Transporting
|
||||
--
|
||||
@@ -452,7 +454,7 @@
|
||||
-- -- Creat a new ARTY object from a Paladin group.
|
||||
-- paladin=ARTY:New(GROUP:FindByName("Blue Paladin"))
|
||||
--
|
||||
-- -- Define a rearming group. This is a Transport M818 truck.
|
||||
-- -- Define a rearming group. This is a Transport M939 truck.
|
||||
-- paladin:SetRearmingGroup(GROUP:FindByName("Blue Ammo Truck"))
|
||||
--
|
||||
-- -- Set the max firing range. A Paladin unit has a range of 20 km.
|
||||
@@ -617,63 +619,148 @@ ARTY.WeaponType={
|
||||
}
|
||||
|
||||
--- 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
|
||||
ARTY.db={
|
||||
["2B11 mortar"] = { -- type "2B11 mortar"
|
||||
minrange = 500, -- correct?
|
||||
maxrange = 7000, -- 7 km
|
||||
reloadtime = 30, -- 30 sec
|
||||
["LeFH_18-40-105"] = {
|
||||
displayname = "FH LeFH-18 105mm", -- name displayed in the ME
|
||||
minrange = 500, -- min range (green circle) in meters
|
||||
maxrange = 10500, -- max range (red circle) in meters
|
||||
reloadtime = nil, -- reload time in seconds
|
||||
},
|
||||
["SPH 2S1 Gvozdika"] = { -- type "SAU Gvozdika"
|
||||
minrange = 300, -- correct?
|
||||
maxrange = 15000, -- 15 km
|
||||
reloadtime = nil, -- unknown
|
||||
["M2A1-105"] = {
|
||||
displayname = "FH M2A1 105mm",
|
||||
minrange = 500,
|
||||
maxrange = 11500,
|
||||
reloadtime = nil,
|
||||
},
|
||||
["SPH 2S19 Msta"] = { --type "SAU Msta", alias "2S19 Msta"
|
||||
minrange = 300, -- correct?
|
||||
maxrange = 23500, -- 23.5 km
|
||||
reloadtime = nil, -- unknown
|
||||
["Pak40"] = {
|
||||
displayname = "FH Pak 40 75mm",
|
||||
minrange = 500,
|
||||
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"
|
||||
minrange = 300, -- correct?
|
||||
maxrange = 17000, -- 17 km
|
||||
reloadtime = nil, -- unknown
|
||||
["Smerch"] = {
|
||||
displayname = "MLRS 9A52 Smerch CM 300mm",
|
||||
minrange = 20000,
|
||||
maxrange = 70000,
|
||||
reloadtime = 2160,
|
||||
},
|
||||
["SPH 2S9 Nona"] = { --type "SAU 2-C9"
|
||||
minrange = 500, -- correct?
|
||||
maxrange = 7000, -- 7 km
|
||||
reloadtime = nil, -- unknown
|
||||
["Smerch_HE"] = {
|
||||
displayname = "MLRS 9A52 Smerch HE 300mm",
|
||||
minrange = 20000,
|
||||
maxrange = 70000,
|
||||
reloadtime = 2160,
|
||||
},
|
||||
["SPH M109 Paladin"] = { -- type "M-109", alias "M109"
|
||||
minrange = 300, -- correct?
|
||||
maxrange = 22000, -- 22 km
|
||||
reloadtime = nil, -- unknown
|
||||
["Uragan_BM-27"] = {
|
||||
displayname = "MLRS 9K57 Uragan BM-27 220mm",
|
||||
minrange = 11500,
|
||||
maxrange = 35800,
|
||||
reloadtime = 840,
|
||||
},
|
||||
["SpGH Dana"] = { -- type "SpGH_Dana"
|
||||
minrange = 300, -- correct?
|
||||
maxrange = 18700, -- 18.7 km
|
||||
reloadtime = nil, -- unknown
|
||||
["Grad-URAL"] = {
|
||||
displayname = "MLRS BM-21 Grad 122mm",
|
||||
minrange = 5000,
|
||||
maxrange = 19000,
|
||||
reloadtime = 420,
|
||||
},
|
||||
["MLRS BM-21 Grad"] = { --type "Grad-URAL", alias "MLRS BM-21 Grad"
|
||||
minrange = 5000, -- 5 km
|
||||
maxrange = 19000, -- 19 km
|
||||
reloadtime = 420, -- 7 min
|
||||
["HL_B8M1"] = {
|
||||
displayname = "MLRS HL with B8M1 80mm",
|
||||
minrange = 500,
|
||||
maxrange = 5000,
|
||||
reloadtime = nil,
|
||||
},
|
||||
["MLRS 9K57 Uragan BM-27"] = { -- type "Uragan_BM-27"
|
||||
minrange = 11500, -- 11.5 km
|
||||
maxrange = 35800, -- 35.8 km
|
||||
reloadtime = 840, -- 14 min
|
||||
["tt_B8M1"] = {
|
||||
displayname = "MLRS LC with B8M1 80mm",
|
||||
minrange = 500,
|
||||
maxrange = 5000,
|
||||
reloadtime = nil,
|
||||
},
|
||||
["MLRS 9A52 Smerch"] = { -- type "Smerch"
|
||||
minrange = 20000, -- 20 km
|
||||
maxrange = 70000, -- 70 km
|
||||
reloadtime = 2160, -- 36 min
|
||||
["MLRS"] = {
|
||||
displayname = "MLRS M270 227mm",
|
||||
minrange = 10000,
|
||||
maxrange = 32000,
|
||||
reloadtime = 540,
|
||||
},
|
||||
["MLRS M270"] = { --type "MRLS", alias "M270 MRLS"
|
||||
minrange = 10000, -- 10 km
|
||||
maxrange = 32000, -- 32 km
|
||||
reloadtime = 540, -- 9 min
|
||||
["2B11 mortar"] = {
|
||||
displayname = "Mortar 2B11 120mm",
|
||||
minrange = 500,
|
||||
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.
|
||||
@@ -693,7 +780,7 @@ ARTY.db={
|
||||
|
||||
--- Arty script version.
|
||||
-- @field #string version
|
||||
ARTY.version="1.2.0"
|
||||
ARTY.version="1.3.3"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -706,7 +793,7 @@ ARTY.version="1.2.0"
|
||||
-- DONE: Add user defined rearm weapon types.
|
||||
-- DONE: Check if target is in range. Maybe this requires a data base with the ranges of all arty units. <solved by user function>
|
||||
-- DONE: Make ARTY move to rearming position.
|
||||
-- DONE: Check that right rearming vehicle is specified. Blue M818, Red Ural-375. Are there more? <user needs to know!>
|
||||
-- DONE: Check that right rearming vehicle is specified. Blue M939, Red Ural-375. Are there more? <user needs to know!>
|
||||
-- DONE: Check if ARTY group is still alive.
|
||||
-- DONE: Handle dead events.
|
||||
-- DONE: Abort firing task if no shooting event occured with 5(?) minutes. Something went wrong then. Min/max range for example.
|
||||
@@ -795,12 +882,15 @@ function ARTY:New(group, alias)
|
||||
-- Maximum speed in km/h.
|
||||
self.SpeedMax=group:GetSpeedMax()
|
||||
|
||||
-- Group is mobile or not (e.g. mortars).
|
||||
if self.SpeedMax>1 then
|
||||
-- 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>3.6 then
|
||||
self.ismobile=true
|
||||
else
|
||||
self.ismobile=false
|
||||
end
|
||||
|
||||
-- Set track time interval.
|
||||
self.dtTrack=0.2
|
||||
|
||||
-- Set speed to 0.7 of maximum.
|
||||
self.Speed=self.SpeedMax * 0.7
|
||||
@@ -1497,6 +1587,15 @@ function ARTY:SetStatusInterval(interval)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set time interval for weapon tracking.
|
||||
-- @param #ARTY self
|
||||
-- @param #number interval Time interval in seconds. Default 0.2 seconds.
|
||||
-- @return self
|
||||
function ARTY:SetTrackInterval(interval)
|
||||
self.dtTrack=interval or 0.2
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set time how it is waited a unit the first shot event happens. If no shot is fired after this time, the task to fire is aborted and the target removed.
|
||||
-- @param #ARTY self
|
||||
-- @param #number waittime Time in seconds. Default 300 seconds.
|
||||
@@ -1519,7 +1618,7 @@ end
|
||||
|
||||
--- Assign a group, which is responsible for rearming the ARTY group. If the group is too far away from the ARTY group it will be guided towards the ARTY group.
|
||||
-- @param #ARTY self
|
||||
-- @param Wrapper.Group#GROUP group Group that is supposed to rearm the ARTY group. For the blue coalition, this is often a unarmed M818 transport whilst for red an unarmed Ural-375 transport can be used.
|
||||
-- @param Wrapper.Group#GROUP group Group that is supposed to rearm the ARTY group. For the blue coalition, this is often a unarmed M939 transport whilst for red an unarmed Ural-375 transport can be used.
|
||||
-- @return self
|
||||
function ARTY:SetRearmingGroup(group)
|
||||
self:F({group=group})
|
||||
@@ -1874,7 +1973,7 @@ function ARTY:onafterStart(Controllable, From, Event, To)
|
||||
MESSAGE:New(text, 5):ToAllIf(self.Debug)
|
||||
|
||||
-- Get Ammo.
|
||||
self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0=self:GetAmmo(self.Debug)
|
||||
self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0, self.Narty0=self:GetAmmo(self.Debug)
|
||||
|
||||
-- Init nuclear explosion parameters if they were not set by user.
|
||||
if self.nukerange==nil then
|
||||
@@ -1909,7 +2008,7 @@ function ARTY:onafterStart(Controllable, From, Event, To)
|
||||
end
|
||||
|
||||
-- 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})
|
||||
if _dbproperties~=nil then
|
||||
for property,value in pairs(_dbproperties) do
|
||||
@@ -1955,8 +2054,8 @@ function ARTY:onafterStart(Controllable, From, Event, To)
|
||||
text=text..string.format("Type = %s\n", self.Type)
|
||||
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("Speed max = %d km/h\n", self.SpeedMax)
|
||||
text=text..string.format("Speed default = %d km/h\n", self.Speed)
|
||||
text=text..string.format("Speed max = %.1f km/h\n", self.SpeedMax)
|
||||
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 cargo = %s\n", tostring(self.iscargo))
|
||||
text=text..string.format("Min range = %.1f km\n", self.minrange/1000)
|
||||
@@ -2080,7 +2179,7 @@ function ARTY:_StatusReport(display)
|
||||
end
|
||||
|
||||
-- Get Ammo.
|
||||
local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo()
|
||||
local Nammo, Nshells, Nrockets, Nmissiles, Narty=self:GetAmmo()
|
||||
local Nnukes=self.Nukes
|
||||
local Nillu=self.Nillu
|
||||
local Nsmoke=self.Nsmoke
|
||||
@@ -2093,7 +2192,7 @@ function ARTY:_StatusReport(display)
|
||||
text=text..string.format("Clock = %s\n", Clock)
|
||||
text=text..string.format("FSM state = %s\n", self:GetState())
|
||||
text=text..string.format("Total ammo count = %d\n", Nammo)
|
||||
text=text..string.format("Number of shells = %d\n", Nshells)
|
||||
text=text..string.format("Number of shells = %d\n", Narty)
|
||||
text=text..string.format("Number of rockets = %d\n", Nrockets)
|
||||
text=text..string.format("Number of missiles = %d\n", Nmissiles)
|
||||
text=text..string.format("Number of nukes = %d\n", Nnukes)
|
||||
@@ -2129,6 +2228,95 @@ end
|
||||
-- Event Handling
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Function called during tracking of weapon.
|
||||
-- @param Wrapper.Weapon#WEAPON weapon Weapon object.
|
||||
-- @param #ARTY self ARTY object.
|
||||
-- @param #ARTY.Target target Target of the weapon.
|
||||
function ARTY._FuncTrack(weapon, self, target)
|
||||
|
||||
-- Coordinate and distance to target.
|
||||
local _coord=weapon.coordinate
|
||||
local _dist=_coord:Get2DDistance(target.coord)
|
||||
local _destroyweapon=false
|
||||
|
||||
-- Debug
|
||||
self:T3(self.lid..string.format("ARTY %s weapon to target dist = %d m", self.groupname,_dist))
|
||||
|
||||
if target.weapontype==ARTY.WeaponType.IlluminationShells then
|
||||
|
||||
-- Check if within distace.
|
||||
if _dist<target.radius then
|
||||
|
||||
-- Get random coordinate within certain radius of the target.
|
||||
local _cr=target.coord:GetRandomCoordinateInRadius(target.radius)
|
||||
|
||||
-- Get random altitude over target.
|
||||
local _alt=_cr:GetLandHeight()+math.random(self.illuMinalt, self.illuMaxalt)
|
||||
|
||||
-- Adjust explosion height of coordinate.
|
||||
local _ci=COORDINATE:New(_cr.x,_alt,_cr.z)
|
||||
|
||||
-- Create illumination flare.
|
||||
_ci:IlluminationBomb(self.illuPower)
|
||||
|
||||
-- Destroy actual shell.
|
||||
_destroyweapon=true
|
||||
end
|
||||
|
||||
elseif target.weapontype==ARTY.WeaponType.SmokeShells then
|
||||
|
||||
if _dist<target.radius then
|
||||
|
||||
-- Get random coordinate within a certain radius.
|
||||
local _cr=_coord:GetRandomCoordinateInRadius(_data.target.radius)
|
||||
|
||||
-- Fire smoke at this coordinate.
|
||||
_cr:Smoke(self.smokeColor)
|
||||
|
||||
-- Destroy actual shell.
|
||||
_destroyweapon=true
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if _destroyweapon then
|
||||
|
||||
self:T2(self.lid..string.format("ARTY %s destroying shell, stopping timer.", self.groupname))
|
||||
|
||||
-- Destroy weapon and stop timer.
|
||||
weapon:Destroy()
|
||||
|
||||
-- No more tracking.
|
||||
weapon.tracking=false
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Function called after impact of weapon.
|
||||
-- @param Wrapper.Weapon#WEAPON weapon Weapon object.
|
||||
-- @param #ARTY self ARTY object.
|
||||
-- @param #ARTY.Target target Target of the weapon.
|
||||
function ARTY._FuncImpact(weapon, self, target)
|
||||
|
||||
-- Debug info.
|
||||
self:I(self.lid..string.format("ARTY %s weapon NOT ALIVE any more.", self.groupname))
|
||||
|
||||
-- Get impact coordinate.
|
||||
local _impactcoord=weapon:GetImpactCoordinate()
|
||||
|
||||
-- Create a "nuclear" explosion and blast at the impact point.
|
||||
if target.weapontype==ARTY.WeaponType.TacticalNukes then
|
||||
self:T(self.lid..string.format("ARTY %s triggering nuclear explosion in one second.", self.groupname))
|
||||
--SCHEDULER:New(nil, ARTY._NuclearBlast, {self,_impactcoord}, 1.0)
|
||||
self:ScheduleOnce(1.0, ARTY._NuclearBlast, self, _impactcoord)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Eventhandler for shot event.
|
||||
-- @param #ARTY self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
@@ -2162,132 +2350,36 @@ function ARTY:OnEventShot(EventData)
|
||||
self:T(self.lid..text)
|
||||
MESSAGE:New(text, 5):Clear():ToAllIf(self.report or self.Debug)
|
||||
|
||||
-- Last known position of the weapon fired.
|
||||
local _lastpos={x=0, y=0, z=0}
|
||||
|
||||
--- Track the position of the weapon if it is supposed to model a tac nuke, illumination or smoke shell.
|
||||
-- @param #table _weapon
|
||||
local function _TrackWeapon(_data)
|
||||
|
||||
-- When the pcall status returns false the weapon has hit.
|
||||
local _weaponalive,_currpos = pcall(
|
||||
function()
|
||||
return _data.weapon:getPoint()
|
||||
end)
|
||||
|
||||
-- Debug
|
||||
self:T3(self.lid..string.format("ARTY %s: Weapon still in air: %s", self.groupname, tostring(_weaponalive)))
|
||||
|
||||
-- Destroy weapon before impact.
|
||||
local _destroyweapon=false
|
||||
|
||||
if _weaponalive then
|
||||
|
||||
-- Update last position.
|
||||
_lastpos={x=_currpos.x, y=_currpos.y, z=_currpos.z}
|
||||
|
||||
-- Coordinate and distance to target.
|
||||
local _coord=COORDINATE:NewFromVec3(_lastpos)
|
||||
local _dist=_coord:Get2DDistance(_data.target.coord)
|
||||
|
||||
-- Debug
|
||||
self:T3(self.lid..string.format("ARTY %s weapon to target dist = %d m", self.groupname,_dist))
|
||||
|
||||
if _data.target.weapontype==ARTY.WeaponType.IlluminationShells then
|
||||
|
||||
-- Check if within distace.
|
||||
if _dist<_data.target.radius then
|
||||
|
||||
-- Get random coordinate within certain radius of the target.
|
||||
local _cr=_data.target.coord:GetRandomCoordinateInRadius(_data.target.radius)
|
||||
|
||||
-- Get random altitude over target.
|
||||
local _alt=_cr:GetLandHeight()+math.random(self.illuMinalt, self.illuMaxalt)
|
||||
|
||||
-- Adjust explosion height of coordinate.
|
||||
local _ci=COORDINATE:New(_cr.x,_alt,_cr.z)
|
||||
|
||||
-- Create illumination flare.
|
||||
_ci:IlluminationBomb(self.illuPower)
|
||||
|
||||
-- Destroy actual shell.
|
||||
_destroyweapon=true
|
||||
end
|
||||
|
||||
elseif _data.target.weapontype==ARTY.WeaponType.SmokeShells then
|
||||
|
||||
if _dist<_data.target.radius then
|
||||
|
||||
-- Get random coordinate within a certain radius.
|
||||
local _cr=_coord:GetRandomCoordinateInRadius(_data.target.radius)
|
||||
|
||||
-- Fire smoke at this coordinate.
|
||||
_cr:Smoke(self.smokeColor)
|
||||
|
||||
-- Destroy actual shell.
|
||||
_destroyweapon=true
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if _destroyweapon then
|
||||
|
||||
self:T2(self.lid..string.format("ARTY %s destroying shell, stopping timer.", self.groupname))
|
||||
|
||||
-- Destroy weapon and stop timer.
|
||||
_data.weapon:destroy()
|
||||
return nil
|
||||
|
||||
else
|
||||
|
||||
-- TODO: Make dt input parameter.
|
||||
local dt=0.02
|
||||
|
||||
self:T3(self.lid..string.format("ARTY %s tracking weapon again in %.3f seconds", self.groupname, dt))
|
||||
|
||||
-- Check again in 0.05 seconds.
|
||||
return timer.getTime() + dt
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
-- Get impact coordinate.
|
||||
local _impactcoord=COORDINATE:NewFromVec3(_lastpos)
|
||||
|
||||
self:I(self.lid..string.format("ARTY %s weapon NOT ALIVE any more.", self.groupname))
|
||||
|
||||
-- Create a "nuclear" explosion and blast at the impact point.
|
||||
if _data.target.weapontype==ARTY.WeaponType.TacticalNukes then
|
||||
self:T(self.lid..string.format("ARTY %s triggering nuclear explosion in one second.", self.groupname))
|
||||
SCHEDULER:New(nil, ARTY._NuclearBlast, {self,_impactcoord}, 1.0)
|
||||
end
|
||||
|
||||
-- Stop timer.
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Start track the shell if we want to model a tactical nuke.
|
||||
local _tracknuke = self.currentTarget.weapontype==ARTY.WeaponType.TacticalNukes and self.Nukes>0
|
||||
local _trackillu = self.currentTarget.weapontype==ARTY.WeaponType.IlluminationShells and self.Nillu>0
|
||||
local _tracksmoke = self.currentTarget.weapontype==ARTY.WeaponType.SmokeShells and self.Nsmoke>0
|
||||
|
||||
|
||||
if _tracknuke or _trackillu or _tracksmoke then
|
||||
|
||||
self:T(self.lid..string.format("ARTY %s: Tracking of weapon starts in two seconds.", self.groupname))
|
||||
|
||||
local _peter={}
|
||||
_peter.weapon=EventData.weapon
|
||||
_peter.target=UTILS.DeepCopy(self.currentTarget)
|
||||
|
||||
timer.scheduleFunction(_TrackWeapon, _peter, timer.getTime() + 2.0)
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("ARTY %s: Tracking of weapon starts in two seconds.", self.groupname))
|
||||
|
||||
-- Create a weapon object.
|
||||
local weapon=WEAPON:New(EventData.weapon)
|
||||
|
||||
-- Set time step for tracking.
|
||||
weapon:SetTimeStepTrack(self.dtTrack)
|
||||
|
||||
-- Copy target. We need a copy because it might already be overwritten with the next target during flight of weapon.
|
||||
local target=UTILS.DeepCopy(self.currentTarget)
|
||||
|
||||
-- Set callback functions.
|
||||
weapon:SetFuncTrack(ARTY._FuncTrack, self, target)
|
||||
weapon:SetFuncImpact(ARTY._FuncImpact, self, target)
|
||||
|
||||
-- Start tracking in 2 sec (arty ammo should fly a bit).
|
||||
weapon:StartTrack(2)
|
||||
end
|
||||
|
||||
-- Get current ammo.
|
||||
local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo()
|
||||
local _nammo,_nshells,_nrockets,_nmissiles,_narty=self:GetAmmo()
|
||||
|
||||
-- Decrease available nukes because we just fired one.
|
||||
if self.currentTarget.weapontype==ARTY.WeaponType.TacticalNukes then
|
||||
@@ -2317,7 +2409,7 @@ function ARTY:OnEventShot(EventData)
|
||||
|
||||
-- Weapon type name for current target.
|
||||
local _weapontype=self:_WeaponTypeName(self.currentTarget.weapontype)
|
||||
self:T(self.lid..string.format("Group %s ammo: total=%d, shells=%d, rockets=%d, missiles=%d", self.groupname, _nammo, _nshells, _nrockets, _nmissiles))
|
||||
self:T(self.lid..string.format("Group %s ammo: total=%d, shells=%d, rockets=%d, missiles=%d", self.groupname, _nammo, _narty, _nrockets, _nmissiles))
|
||||
self:T(self.lid..string.format("Group %s uses weapontype %s for current target.", self.groupname, _weapontype))
|
||||
|
||||
-- Default switches for cease fire and relocation.
|
||||
@@ -2765,7 +2857,7 @@ function ARTY:onafterStatus(Controllable, From, Event, To)
|
||||
self:_EventFromTo("onafterStatus", Event, From, To)
|
||||
|
||||
-- Get ammo.
|
||||
local nammo, nshells, nrockets, nmissiles=self:GetAmmo()
|
||||
local nammo, nshells, nrockets, nmissiles, narty=self:GetAmmo()
|
||||
|
||||
-- We have a cargo group ==> check if group was loaded into a carrier.
|
||||
if self.iscargo and self.cargogroup then
|
||||
@@ -2782,7 +2874,7 @@ function ARTY:onafterStatus(Controllable, From, Event, To)
|
||||
|
||||
-- FSM state.
|
||||
local fsmstate=self:GetState()
|
||||
self:T(self.lid..string.format("Status %s, Ammo total=%d: shells=%d [smoke=%d, illu=%d, nukes=%d*%.3f kT], rockets=%d, missiles=%d", fsmstate, nammo, nshells, self.Nsmoke, self.Nillu, self.Nukes, self.nukewarhead/1000000, nrockets, nmissiles))
|
||||
self:T(self.lid..string.format("Status %s, Ammo total=%d: shells=%d [smoke=%d, illu=%d, nukes=%d*%.3f kT], rockets=%d, missiles=%d", fsmstate, nammo, narty, self.Nsmoke, self.Nillu, self.Nukes, self.nukewarhead/1000000, nrockets, nmissiles))
|
||||
|
||||
if self.Controllable and self.Controllable:IsAlive() then
|
||||
|
||||
@@ -2865,20 +2957,19 @@ function ARTY:onafterStatus(Controllable, From, Event, To)
|
||||
if self.currentTarget then
|
||||
self:CeaseFire(self.currentTarget)
|
||||
end
|
||||
|
||||
-- Open fire on timed target.
|
||||
self:OpenFire(_timedTarget)
|
||||
|
||||
|
||||
if self:is("CombatReady") then
|
||||
-- Open fire on timed target.
|
||||
self:OpenFire(_timedTarget)
|
||||
end
|
||||
elseif _normalTarget then
|
||||
|
||||
-- Open fire on normal target.
|
||||
self:OpenFire(_normalTarget)
|
||||
|
||||
|
||||
if self:is("CombatReady") then
|
||||
-- Open fire on normal target.
|
||||
self:OpenFire(_normalTarget)
|
||||
end
|
||||
end
|
||||
|
||||
-- Get ammo.
|
||||
--local nammo, nshells, nrockets, nmissiles=self:GetAmmo()
|
||||
|
||||
-- Check if we have a target in the queue for which weapons are still available.
|
||||
local gotsome=false
|
||||
if #self.targets>0 then
|
||||
@@ -3039,14 +3130,14 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target)
|
||||
local range=Controllable:GetCoordinate():Get2DDistance(target.coord)
|
||||
|
||||
-- Get ammo.
|
||||
local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo()
|
||||
local nfire=Nammo
|
||||
local Nammo, Nshells, Nrockets, Nmissiles, Narty=self:GetAmmo()
|
||||
local nfire=Narty
|
||||
local _type="shots"
|
||||
if target.weapontype==ARTY.WeaponType.Auto then
|
||||
nfire=Nammo
|
||||
nfire=Nammo -- We take everything that is available
|
||||
_type="shots"
|
||||
elseif target.weapontype==ARTY.WeaponType.Cannon then
|
||||
nfire=Nshells
|
||||
nfire=Narty
|
||||
_type="shells"
|
||||
elseif target.weapontype==ARTY.WeaponType.TacticalNukes then
|
||||
nfire=self.Nukes
|
||||
@@ -3064,6 +3155,8 @@ function ARTY:onafterOpenFire(Controllable, From, Event, To, target)
|
||||
nfire=Nmissiles
|
||||
_type="cruise missiles"
|
||||
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.
|
||||
target.nshells=math.min(target.nshells, nfire)
|
||||
@@ -3331,7 +3424,7 @@ function ARTY:_CheckRearmed()
|
||||
self:F2()
|
||||
|
||||
-- Get current ammo.
|
||||
local nammo,nshells,nrockets,nmissiles=self:GetAmmo()
|
||||
local nammo,nshells,nrockets,nmissiles,narty=self:GetAmmo()
|
||||
|
||||
-- Number of units still alive.
|
||||
local units=self.Controllable:GetUnits()
|
||||
@@ -3422,7 +3515,7 @@ function ARTY:onafterMove(Controllable, From, Event, To, move)
|
||||
-- Set current move.
|
||||
self.currentMove=move
|
||||
|
||||
-- Route group to coodinate.
|
||||
-- Route group to coordinate.
|
||||
self:_Move(self.Controllable, move.coord, move.speed, move.onroad)
|
||||
|
||||
end
|
||||
@@ -3540,9 +3633,7 @@ end
|
||||
-- @param #string To To state.
|
||||
function ARTY:onafterRespawn(Controllable, From, Event, To)
|
||||
self:_EventFromTo("onafterRespawn", Event, From, To)
|
||||
|
||||
env.info("FF Respawning arty group")
|
||||
|
||||
self:I("Respawning arty group")
|
||||
local group=self.Controllable --Wrapper.Group#GROUP
|
||||
|
||||
-- Respawn group.
|
||||
@@ -3599,7 +3690,11 @@ function ARTY:_FireAtCoord(coord, radius, nshells, weapontype)
|
||||
if weapontype==ARTY.WeaponType.TacticalNukes or weapontype==ARTY.WeaponType.IlluminationShells or weapontype==ARTY.WeaponType.SmokeShells then
|
||||
weapontype=ARTY.WeaponType.Cannon
|
||||
end
|
||||
|
||||
|
||||
if group:HasTask() then
|
||||
group:ClearTasks()
|
||||
end
|
||||
|
||||
-- Set ROE to weapon free.
|
||||
group:OptionROEOpenFire()
|
||||
|
||||
@@ -3610,7 +3705,7 @@ function ARTY:_FireAtCoord(coord, radius, nshells, weapontype)
|
||||
local fire=group:TaskFireAtPoint(vec2, radius, nshells, weapontype)
|
||||
|
||||
-- Execute task.
|
||||
group:SetTask(fire)
|
||||
group:SetTask(fire,1)
|
||||
end
|
||||
|
||||
--- Set task for attacking a group.
|
||||
@@ -3627,7 +3722,11 @@ function ARTY:_AttackGroup(target)
|
||||
if weapontype==ARTY.WeaponType.TacticalNukes or weapontype==ARTY.WeaponType.IlluminationShells or weapontype==ARTY.WeaponType.SmokeShells then
|
||||
weapontype=ARTY.WeaponType.Cannon
|
||||
end
|
||||
|
||||
|
||||
if group:HasTask() then
|
||||
group:ClearTasks()
|
||||
end
|
||||
|
||||
-- Set ROE to weapon free.
|
||||
group:OptionROEOpenFire()
|
||||
|
||||
@@ -3638,7 +3737,7 @@ function ARTY:_AttackGroup(target)
|
||||
local fire=group:TaskAttackGroup(targetgroup, weapontype, AI.Task.WeaponExpend.ONE, 1)
|
||||
|
||||
-- Execute task.
|
||||
group:SetTask(fire)
|
||||
group:SetTask(fire,1)
|
||||
end
|
||||
|
||||
|
||||
@@ -3911,6 +4010,7 @@ end
|
||||
-- @return #number Number of shells the group has left.
|
||||
-- @return #number Number of rockets the group has left.
|
||||
-- @return #number Number of missiles the group has left.
|
||||
-- @return #number Number of artillery shells the group has left.
|
||||
function ARTY:GetAmmo(display)
|
||||
self:F3({display=display})
|
||||
|
||||
@@ -3924,6 +4024,7 @@ function ARTY:GetAmmo(display)
|
||||
local nshells=0
|
||||
local nrockets=0
|
||||
local nmissiles=0
|
||||
local nartyshells=0
|
||||
|
||||
-- Get all units.
|
||||
local units=self.Controllable:GetUnits()
|
||||
@@ -3931,9 +4032,10 @@ function ARTY:GetAmmo(display)
|
||||
return nammo, nshells, nrockets, nmissiles
|
||||
end
|
||||
|
||||
for _,unit in pairs(units) do
|
||||
for _,_unit in pairs(units) do
|
||||
local unit=_unit --Wrapper.Unit#UNIT
|
||||
|
||||
if unit and unit:IsAlive() then
|
||||
if unit then
|
||||
|
||||
-- Output.
|
||||
local text=string.format("ARTY group %s - unit %s:\n", self.groupname, unit:GetName())
|
||||
@@ -4025,7 +4127,8 @@ function ARTY:GetAmmo(display)
|
||||
|
||||
-- Add up all shells.
|
||||
nshells=nshells+Nammo
|
||||
|
||||
local _,_,_,_,_,shells = unit:GetAmmunition()
|
||||
nartyshells=nartyshells+shells
|
||||
-- Debug info.
|
||||
text=text..string.format("- %d shells of type %s\n", Nammo, _weaponName)
|
||||
|
||||
@@ -4071,7 +4174,7 @@ function ARTY:GetAmmo(display)
|
||||
-- Total amount of ammunition.
|
||||
nammo=nshells+nrockets+nmissiles
|
||||
|
||||
return nammo, nshells, nrockets, nmissiles
|
||||
return nammo, nshells, nrockets, nmissiles, nartyshells
|
||||
end
|
||||
|
||||
--- Returns a name of a missile category.
|
||||
@@ -4822,7 +4925,10 @@ function ARTY:_CheckShootingStarted()
|
||||
|
||||
-- Check if we waited long enough and no shot was fired.
|
||||
--if dt > self.WaitForShotTime and self.Nshots==0 then
|
||||
if dt > self.WaitForShotTime and (self.Nshots==0 or self.currentTarget.nshells >= self.Nshots) then --https://github.com/FlightControl-Master/MOOSE/issues/1356
|
||||
|
||||
self:T(string.format("dt = %d WaitTime = %d | shots = %d TargetShells = %d",dt,self.WaitForShotTime,self.Nshots,self.currentTarget.nshells))
|
||||
|
||||
if (dt > self.WaitForShotTime and self.Nshots==0) or (self.currentTarget.nshells <= self.Nshots) then --https://github.com/FlightControl-Master/MOOSE/issues/1356
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("%s, no shot event after %d seconds. Removing current target %s from list.", self.groupname, self.WaitForShotTime, name))
|
||||
@@ -4884,7 +4990,7 @@ end
|
||||
function ARTY:_CheckOutOfAmmo(targets)
|
||||
|
||||
-- Get current ammo.
|
||||
local _nammo,_nshells,_nrockets,_nmissiles=self:GetAmmo()
|
||||
local _nammo,_nshells,_nrockets,_nmissiles,_narty=self:GetAmmo()
|
||||
|
||||
-- Special weapon type requested ==> Check if corresponding ammo is empty.
|
||||
local _partlyoutofammo=false
|
||||
@@ -4896,7 +5002,7 @@ function ARTY:_CheckOutOfAmmo(targets)
|
||||
self:T(self.lid..string.format("Group %s, auto weapon requested for target %s but all ammo is empty.", self.groupname, Target.name))
|
||||
_partlyoutofammo=true
|
||||
|
||||
elseif Target.weapontype==ARTY.WeaponType.Cannon and _nshells==0 then
|
||||
elseif Target.weapontype==ARTY.WeaponType.Cannon and _narty==0 then
|
||||
|
||||
self:T(self.lid..string.format("Group %s, cannons requested for target %s but shells empty.", self.groupname, Target.name))
|
||||
_partlyoutofammo=true
|
||||
@@ -4940,14 +5046,14 @@ end
|
||||
function ARTY:_CheckWeaponTypeAvailable(target)
|
||||
|
||||
-- Get current ammo of group.
|
||||
local Nammo, Nshells, Nrockets, Nmissiles=self:GetAmmo()
|
||||
local Nammo, Nshells, Nrockets, Nmissiles, Narty=self:GetAmmo()
|
||||
|
||||
-- Check if enough ammo is there for the selected weapon type.
|
||||
local nfire=Nammo
|
||||
if target.weapontype==ARTY.WeaponType.Auto then
|
||||
nfire=Nammo
|
||||
elseif target.weapontype==ARTY.WeaponType.Cannon then
|
||||
nfire=Nshells
|
||||
nfire=Narty
|
||||
elseif target.weapontype==ARTY.WeaponType.TacticalNukes then
|
||||
nfire=self.Nukes
|
||||
elseif target.weapontype==ARTY.WeaponType.IlluminationShells then
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Keep airbases clean of crashing or colliding airplanes, and kill missiles when being fired at airbases.
|
||||
--- **Functional** - Keep airbases clean of crashing or colliding airplanes, and kill missiles when being fired at airbases.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -14,7 +14,7 @@
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [CLA - CleanUp Airbase](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CLA%20-%20CleanUp%20Airbase)
|
||||
-- [CLA - CleanUp Airbase](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Functional/CleanUp)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -354,7 +354,7 @@ function CLEANUP_AIRBASE.__:EventAddForCleanUp( 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:IsInAirbase( Event.IniUnit:GetVec2() ) then
|
||||
self:AddForCleanUp( Event.IniUnit, Event.IniDCSUnitName )
|
||||
@@ -362,7 +362,7 @@ function CLEANUP_AIRBASE.__:EventAddForCleanUp( Event )
|
||||
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:IsInAirbase( Event.TgtUnit:GetVec2() ) then
|
||||
self:AddForCleanUp( Event.TgtUnit, Event.TgtDCSUnitName )
|
||||
@@ -384,7 +384,7 @@ function CLEANUP_AIRBASE.__:CleanUpSchedule()
|
||||
local CleanUpUnit = CleanUpListData.CleanUpUnit -- Wrapper.Unit#UNIT
|
||||
local CleanUpGroupName = CleanUpListData.CleanUpGroupName
|
||||
|
||||
if CleanUpUnit:IsAlive() ~= nil then
|
||||
if CleanUpUnit and CleanUpUnit:IsAlive() ~= nil then
|
||||
|
||||
if self:IsInAirbase( CleanUpUnit:GetVec2() ) then
|
||||
|
||||
@@ -411,7 +411,7 @@ function CLEANUP_AIRBASE.__:CleanUpSchedule()
|
||||
end
|
||||
end
|
||||
-- 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()
|
||||
if CleanUpUnitVelocity < 1 then
|
||||
if CleanUpListData.CleanUpMoved then
|
||||
|
||||
687
Moose Development/Moose/Functional/ClientWatch.lua
Normal file
687
Moose Development/Moose/Functional/ClientWatch.lua
Normal file
@@ -0,0 +1,687 @@
|
||||
--- **Functional** - Manage and track client slots easily to add your own client-based menus and modules to.
|
||||
--
|
||||
-- The @{#CLIENTWATCH} class adds a simplified way to create scripts and menus for individual clients. Instead of creating large algorithms and juggling multiple event handlers, you can simply provide one or more prefixes to the class and use the callback functions on spawn, despawn, and any aircraft related events to script to your hearts content.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
-- * Find clients by prefixes or by providing a Wrapper.CLIENT object
|
||||
-- * Trigger functions when the client spawns and despawns
|
||||
-- * Create multiple client instances without overwriting event handlers between instances
|
||||
-- * More reliable aircraft lost events for when DCS thinks the aircraft id dead but a dead event fails to trigger
|
||||
-- * Easily manage clients spawned in dynamic slots
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ### Author: **Statua**
|
||||
--
|
||||
-- ### Contributions: **FlightControl**: Wrapper.CLIENT
|
||||
--
|
||||
-- ====
|
||||
-- @module Functional.ClientWatch
|
||||
-- @image clientwatch.jpg
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
--- CLIENTWATCH class
|
||||
-- @type CLIENTWATCH
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #boolean Debug Write Debug messages to DCS log file and send Debug messages to all players.
|
||||
-- @field #string lid String for DCS log file.
|
||||
-- @field #number FilterCoalition If not nil, will only activate for aircraft of the given coalition value.
|
||||
-- @field #number FilterCategory If not nil, will only activate for aircraft of the given category value.
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
|
||||
--- Manage and track client slots easily to add your own client-based menus and modules to.
|
||||
--
|
||||
-- ## Creating a new instance
|
||||
--
|
||||
-- To start, you must first create a new instance of the client manager and provide it with either a Wrapper.Client#CLIENT object, a string prefix of the unit name, or a table of string prefixes for unit names. These are used to capture the client unit when it spawns and apply your scripted functions to it. Only fixed wing and rotary wing aircraft controlled by players can be used by this class.
|
||||
-- **This will not work if the client aircraft is alive!**
|
||||
--
|
||||
-- ### Examples
|
||||
--
|
||||
-- -- Create an instance with a Wrapper.Client#CLIENT object
|
||||
-- local heliClient = CLIENT:FindByName('Rotary1-1')
|
||||
-- local clientInstance = CLIENTWATCH:New(heliClient)
|
||||
--
|
||||
-- -- Create an instance with part of the unit name in the Mission Editor
|
||||
-- local clientInstance = CLIENTWATCH:New("Rotary")
|
||||
--
|
||||
-- -- Create an instance using prefixes for a few units as well as a FARP name for any dynamic spawns coming out of it
|
||||
-- local clientInstance = CLIENTWATCH:New({"Rescue","UH-1H","FARP ALPHA"})
|
||||
--
|
||||
-- ## Applying functions and methods to client aircraft when they spawn
|
||||
--
|
||||
-- Once the instance is created, it will watch for birth events. If the unit name of the client aircraft matches the one provided in the instance, the callback method @{#CLIENTWATCH:OnAfterSpawn}() can be used to apply functions and methods to the client object.
|
||||
--
|
||||
-- In the OnAfterSpawn() callback method are four values. From, Event, To, and ClientObject. From,Event,To are standard FSM strings for the state changes. ClientObject is where the magic happens. This is a special object which you can use to access all the data of the client aircraft. The following entries in ClientObject are available for you to use:
|
||||
--
|
||||
-- * **ClientObject.Unit**: The Moose @{Wrapper.Unit#UNIT} of the client aircraft
|
||||
-- * **ClientObject.Group**: The Moose @{Wrapper.Group#GRUP} of the client aircraft
|
||||
-- * **ClientObject.Client**: The Moose @{Wrapper.Client#CLIENT} of the client aircraft
|
||||
-- * **ClientObject.PlayerName**: A #string of the player controlling the aircraft
|
||||
-- * **ClientObject.UnitName**: A #string of the client aircraft unit.
|
||||
-- * **ClientObject.GroupName**: A #string of the client aircraft group.
|
||||
--
|
||||
-- ### Examples
|
||||
--
|
||||
-- -- Create an instance with a client unit prefix and send them a message when they spawn
|
||||
-- local clientInstance = CLIENTWATCH:New("Rotary")
|
||||
-- function clientInstance:OnAfterSpawn(From,Event,To,ClientObject,EventData)
|
||||
-- MESSAGE:New("Welcome to your aircraft!",10):ToUnit(ClientObject.Unit)
|
||||
-- end
|
||||
--
|
||||
-- ## Using event callbacks
|
||||
--
|
||||
-- In a normal setting, you can only use a callback function for a specific option in one location. If you have multiple scripts that rely on the same callback from the same object, this can get quite messy. With the ClientWatch module, these callbacks are isolated t the instances and therefore open the possibility to use many instances with the same callback doing different things. ClientWatch instances subscribe to all events that are applicable to player controlled aircraft and provides callbacks for each, forwarding the EventData in the callback function.
|
||||
--
|
||||
-- The following event callbacks can be used inside the OnAfterSpawn() callback:
|
||||
--
|
||||
-- * **:OnAfterDespawn(From,Event,To)**: Triggers whenever DCS no longer sees the aircraft as 'alive'. No event data is given in this callback as it is derived from other events
|
||||
-- * **:OnAfterHit(From,Event,To,EventData)**: Triggers every time the aircraft takes damage or is struck by a weapon/explosion
|
||||
-- * **:OnAfterKill(From,Event,To,EventData)**: Triggers after the aircraft kills something with its weapons
|
||||
-- * **:OnAfterScore(From,Event,To,EventData)**: Triggers after accumulating score
|
||||
-- * **:OnAfterShot(From,Event,To,EventData)**: Triggers after a single-shot weapon is released
|
||||
-- * **:OnAfterShootingStart(From,Event,To,EventData)**: Triggers when an automatic weapon begins firing
|
||||
-- * **:OnAfterShootingEnd(From,Event,To,EventData)**: Triggers when an automatic weapon stops firing
|
||||
-- * **:OnAfterLand(From,Event,To,EventData)**: Triggers when an aircraft transitions from being airborne to on the ground
|
||||
-- * **:OnAfterTakeoff(From,Event,To,EventData)**: Triggers when an aircraft transitions from being on the ground to airborne
|
||||
-- * **:OnAfterRunwayTakeoff(From,Event,To,EventData)**: Triggers after lifting off from a runway
|
||||
-- * **:OnAfterRunwayTouch(From,Event,To,EventData)**: Triggers when an aircraft's gear makes contact with a runway
|
||||
-- * **:OnAfterRefueling(From,Event,To,EventData)**: Triggers when an aircraft begins taking on fuel
|
||||
-- * **:OnAfterRefuelingStop(From,Event,To,EventData)**: Triggers when an aircraft stops taking on fuel
|
||||
-- * **:OnAfterPlayerLeaveUnit(From,Event,To,EventData)**: Triggers when a player leaves an operational aircraft
|
||||
-- * **:OnAfterCrash(From,Event,To,EventData)**: Triggers when an aircraft is destroyed (may fail to trigger if the aircraft is only partially destroyed)
|
||||
-- * **:OnAfterDead(From,Event,To,EventData)**: Triggers when an aircraft is considered dead (may fail to trigger if the aircraft was partially destroyed first)
|
||||
-- * **:OnAfterPilotDead(From,Event,To,EventData)**: Triggers when the pilot is killed (may fail to trigger if the aircraft was partially destroyed first)
|
||||
-- * **:OnAfterUnitLost(From,Event,To,EventData)**: Triggers when an aircraft is lost for any reason (may fail to trigger if the aircraft was partially destroyed first)
|
||||
-- * **:OnAfterEjection(From,Event,To,EventData)**: Triggers when a pilot ejects from an aircraft
|
||||
-- * **:OnAfterHumanFailure(From,Event,To,EventData)**: Triggers when an aircraft or system is damaged from any source or action by the player
|
||||
-- * **:OnAfterHumanAircraftRepairStart(From,Event,To,EventData)**: Triggers when an aircraft repair is started
|
||||
-- * **:OnAfterHumanAircraftRepairFinish(From,Event,To,EventData)**: Triggers when an aircraft repair is completed
|
||||
-- * **:OnAfterEngineStartup(From,Event,To,EventData)**: Triggers when the engine enters what DCS considers to be a started state. Parameters vary by aircraft
|
||||
-- * **:OnAfterEngineShutdown(From,Event,To,EventData)**: Triggers when the engine enters what DCS considers to be a stopped state. Parameters vary by aircraft
|
||||
-- * **:OnAfterWeaponAdd(From,Event,To,EventData)**: Triggers when an item is added to an aircraft's payload
|
||||
-- * **:OnAfterWeaponDrop(From,Event,To,EventData)**: Triggers when an item is jettisoned or dropped from an aircraft (unconfirmed)
|
||||
-- * **:OnAfterWeaponRearm(From,Event,To,EventData)**: Triggers when an item with internal supply is restored (unconfirmed)
|
||||
--
|
||||
-- ### Examples
|
||||
--
|
||||
-- -- Show a message to player when they take damage from a weapon
|
||||
-- local clientInstance = CLIENTWATCH:New("Rotary")
|
||||
-- function clientInstance:OnAfterSpawn(From,Event,To,ClientObject,EventData)
|
||||
-- function ClientObject:OnAfterHit(From,Event,To,EventData)
|
||||
-- local typeShooter = EventData.IniTypeName
|
||||
-- local nameWeapon = EventData.weapon_name
|
||||
-- MESSAGE:New("A "..typeShooter.." hit you with a "..nameWeapon,20):ToUnit(ClientObject.Unit)
|
||||
-- end
|
||||
-- end
|
||||
--
|
||||
-- @field #CLIENTWATCH
|
||||
CLIENTWATCH = {}
|
||||
CLIENTWATCH.ClassName = "CLIENTWATCH"
|
||||
CLIENTWATCH.Debug = false
|
||||
CLIENTWATCH.DebugEventData = false
|
||||
CLIENTWATCH.lid = nil
|
||||
|
||||
-- @type CLIENTWATCHTools
|
||||
-- @field #table Unit Wrapper.UNIT of the cient object
|
||||
-- @field #table Group Wrapper.GROUP of the cient object
|
||||
-- @field #table Client Wrapper.CLIENT of the cient object
|
||||
-- @field #string PlayerName Name of the player controlling the client object
|
||||
-- @field #string UnitName Name of the unit that is the client object
|
||||
-- @field #string GroupName Name of the group the client object belongs to
|
||||
CLIENTWATCHTools = {}
|
||||
|
||||
--- CLIENTWATCH version
|
||||
-- @field #string version
|
||||
CLIENTWATCH.version="1.0.1"
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Creates a new instance of CLIENTWATCH to add scripts to. Can be used multiple times with the same client/prefixes if you need it for multiple scripts.
|
||||
-- @param #CLIENTWATCH self
|
||||
-- @param #string Will watch for clients whos UNIT NAME or GROUP NAME matches part of the #string as a prefix.
|
||||
-- @param #table Put strings in a table to use multiple prefixes for the above method.
|
||||
-- @param Wrapper.Client#CLIENT Provide a Moose CLIENT object to apply to that specific aircraft slot (static slots only!)
|
||||
-- @param #nil Leave blank to activate for ALL CLIENTS
|
||||
-- @return #CLIENTWATCH self
|
||||
function CLIENTWATCH:New(client)
|
||||
--Init FSM
|
||||
local self=BASE:Inherit(self, FSM:New())
|
||||
self:SetStartState( "Idle" )
|
||||
self:AddTransition( "*", "Spawn", "*" )
|
||||
|
||||
self.FilterCoalition = nil
|
||||
self.FilterCategory = nil
|
||||
|
||||
--- User function for OnAfter "Spawn" event.
|
||||
-- @function [parent=#CLIENTWATCH] OnAfterSpawn
|
||||
-- @param #CLIENTWATCH self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #table clientObject Custom object that handles events and stores Moose object data. See top documentation for more details.
|
||||
-- @param #table eventdata Data from EVENTS.Birth.
|
||||
|
||||
--Set up spawn tracking
|
||||
if not client then
|
||||
if self.Debug then self:I({"New client instance created. ClientType = All clients"}) end
|
||||
self:HandleEvent(EVENTS.Birth)
|
||||
function self:OnEventBirth(eventdata)
|
||||
if (eventdata.IniCategory == 0 or eventdata.IniCategory == 1) and eventdata.IniPlayerName
|
||||
and (not self.FilterCoalition or self.FilterCoalition == eventdata.IniCoalition)
|
||||
and (not self.FilterCategory or self.FilterCategory == eventdata.IniCategory) then
|
||||
if self.Debug then
|
||||
self:I({"Client spawned in.",IniCategory = eventdata.IniCategory})
|
||||
end
|
||||
local clientWatchDebug = self.Debug
|
||||
local clientObject = CLIENTWATCHTools:_newClient(clientWatchDebug,eventdata)
|
||||
self:Spawn(clientObject,eventdata)
|
||||
end
|
||||
end
|
||||
elseif type(client) == "table" or type(client) == "string" then
|
||||
if type(client) == "table" then
|
||||
|
||||
--CLIENT TABLE
|
||||
if client.ClassName == "CLIENT" then
|
||||
if self.Debug then self:I({"New client instance created. ClientType = Wrapper.CLIENT",client}) end
|
||||
self.ClientName = client:GetName()
|
||||
self:HandleEvent(EVENTS.Birth)
|
||||
function self:OnEventBirth(eventdata)
|
||||
if (eventdata.IniCategory == 0 or eventdata.IniCategory == 1) and eventdata.IniPlayerName
|
||||
and (not self.FilterCoalition or self.FilterCoalition == eventdata.IniCoalition)
|
||||
and (not self.FilterCategory or self.FilterCategory == eventdata.IniCategory) then
|
||||
if self.ClientName == eventdata.IniUnitName then
|
||||
if self.Debug then
|
||||
self:I({"Client spawned in.",IniCategory = eventdata.IniCategory})
|
||||
end
|
||||
local clientWatchDebug = self.Debug
|
||||
local clientObject = CLIENTWATCHTools:_newClient(clientWatchDebug,eventdata)
|
||||
self:Spawn(clientObject,eventdata)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--STRING TABLE
|
||||
else
|
||||
if self.Debug then self:I({"New client instance created. ClientType = Multiple Prefixes",client}) end
|
||||
local tableValid = true
|
||||
for _,entry in pairs(client) do
|
||||
if type(entry) ~= "string" then
|
||||
tableValid = false
|
||||
self:E({"The base handler failed to start because at least one entry in param1's table is not a string!",InvalidEntry = entry})
|
||||
return nil
|
||||
end
|
||||
end
|
||||
if tableValid then
|
||||
self:HandleEvent(EVENTS.Birth)
|
||||
function self:OnEventBirth(eventdata)
|
||||
for _,entry in pairs(client) do
|
||||
if (eventdata.IniCategory == 0 or eventdata.IniCategory == 1) and eventdata.IniPlayerName
|
||||
and (not self.FilterCoalition or self.FilterCoalition == eventdata.IniCoalition)
|
||||
and (not self.FilterCategory or self.FilterCategory == eventdata.IniCategory) then
|
||||
if string.match(eventdata.IniUnitName,entry) or string.match(eventdata.IniGroupName,entry) then
|
||||
if self.Debug then
|
||||
self:I({"Client spawned in.",IniCategory = eventdata.IniCategory})
|
||||
end
|
||||
local clientWatchDebug = self.Debug
|
||||
local clientObject = CLIENTWATCHTools:_newClient(clientWatchDebug,eventdata)
|
||||
self:Spawn(clientObject,eventdata)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if self.Debug then self:I({"New client instance created. ClientType = Single Prefix",client}) end
|
||||
|
||||
--SOLO STRING
|
||||
self:HandleEvent(EVENTS.Birth)
|
||||
function self:OnEventBirth(eventdata)
|
||||
if (eventdata.IniCategory == 0 or eventdata.IniCategory == 1) and eventdata.IniPlayerName
|
||||
and (not self.FilterCoalition or self.FilterCoalition == eventdata.IniCoalition)
|
||||
and (not self.FilterCategory or self.FilterCategory == eventdata.IniCategory) then
|
||||
if string.match(eventdata.IniUnitName,client) or string.match(eventdata.IniGroupName,client) then
|
||||
if self.Debug then
|
||||
self:I({"Client spawned in.",IniCategory = eventdata.IniCategory})
|
||||
end
|
||||
local clientWatchDebug = self.Debug
|
||||
local clientObject = CLIENTWATCHTools:_newClient(clientWatchDebug,eventdata)
|
||||
self:Spawn(clientObject,eventdata)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E({"The base handler failed to start because param1 is not a CLIENT object or a prefix string!",param1 = client})
|
||||
return nil
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Filter out all clients not belonging to the provided coalition
|
||||
-- @param #CLIENTWATCH self
|
||||
-- @param #number Coalition number (1 = red, 2 = blue)
|
||||
-- @param #string Coalition string ('red' or 'blue')
|
||||
function CLIENTWATCH:FilterByCoalition(value)
|
||||
if value == 1 or value == "red" then
|
||||
self.FilterCoalition = 1
|
||||
else
|
||||
self.FilterCoalition = 2
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Filter out all clients that are not of the given category
|
||||
-- @param #CLIENTWATCH self
|
||||
-- @param #number Category number (0 = airplane, 1 = helicopter)
|
||||
-- @param #string Category string ('airplane' or 'helicopter')
|
||||
function CLIENTWATCH:FilterByCategory(value)
|
||||
if value == 1 or value == "helicopter" then
|
||||
self.FilterCategory = 1
|
||||
else
|
||||
self.FilterCategory = 0
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Internal function for creating a new client on birth. Do not use!!!.
|
||||
-- @param #CLIENTWATCHTools self
|
||||
-- @param #EVENTS.Birth EventData
|
||||
-- @return #CLIENTWATCHTools self
|
||||
function CLIENTWATCHTools:_newClient(clientWatchDebug,eventdata)
|
||||
--Init FSM
|
||||
local self=BASE:Inherit(self, FSM:New())
|
||||
self:SetStartState( "Alive" )
|
||||
self:AddTransition( "Alive", "Despawn", "Dead" )
|
||||
|
||||
self.Unit = eventdata.IniUnit
|
||||
self.Group = self.Unit:GetGroup()
|
||||
self.Client = self.Unit:GetClient()
|
||||
self.PlayerName = self.Unit:GetPlayerName()
|
||||
self.UnitName = self.Unit:GetName()
|
||||
self.GroupName = self.Group:GetName()
|
||||
|
||||
--Event events
|
||||
self:AddTransition( "*", "Hit", "*" )
|
||||
self:AddTransition( "*", "Kill", "*" )
|
||||
self:AddTransition( "*", "Score", "*" )
|
||||
self:AddTransition( "*", "Shot", "*" )
|
||||
self:AddTransition( "*", "ShootingStart", "*" )
|
||||
self:AddTransition( "*", "ShootingEnd", "*" )
|
||||
self:AddTransition( "*", "Land", "*" )
|
||||
self:AddTransition( "*", "Takeoff", "*" )
|
||||
self:AddTransition( "*", "RunwayTakeoff", "*" )
|
||||
self:AddTransition( "*", "RunwayTouch", "*" )
|
||||
self:AddTransition( "*", "Refueling", "*" )
|
||||
self:AddTransition( "*", "RefuelingStop", "*" )
|
||||
self:AddTransition( "*", "PlayerLeaveUnit", "*" )
|
||||
self:AddTransition( "*", "Crash", "*" )
|
||||
self:AddTransition( "*", "Dead", "*" )
|
||||
self:AddTransition( "*", "PilotDead", "*" )
|
||||
self:AddTransition( "*", "UnitLost", "*" )
|
||||
self:AddTransition( "*", "Ejection", "*" )
|
||||
self:AddTransition( "*", "HumanFailure", "*" )
|
||||
self:AddTransition( "*", "HumanAircraftRepairFinish", "*" )
|
||||
self:AddTransition( "*", "HumanAircraftRepairStart", "*" )
|
||||
self:AddTransition( "*", "EngineShutdown", "*" )
|
||||
self:AddTransition( "*", "EngineStartup", "*" )
|
||||
self:AddTransition( "*", "WeaponAdd", "*" )
|
||||
self:AddTransition( "*", "WeaponDrop", "*" )
|
||||
self:AddTransition( "*", "WeaponRearm", "*" )
|
||||
|
||||
--Event Handlers
|
||||
self:HandleEvent( EVENTS.Hit )
|
||||
self:HandleEvent( EVENTS.Kill )
|
||||
self:HandleEvent( EVENTS.Score )
|
||||
self:HandleEvent( EVENTS.Shot )
|
||||
self:HandleEvent( EVENTS.ShootingStart )
|
||||
self:HandleEvent( EVENTS.ShootingEnd )
|
||||
self:HandleEvent( EVENTS.Land )
|
||||
self:HandleEvent( EVENTS.Takeoff )
|
||||
self:HandleEvent( EVENTS.RunwayTakeoff )
|
||||
self:HandleEvent( EVENTS.RunwayTouch )
|
||||
self:HandleEvent( EVENTS.Refueling )
|
||||
self:HandleEvent( EVENTS.RefuelingStop )
|
||||
self:HandleEvent( EVENTS.PlayerLeaveUnit )
|
||||
self:HandleEvent( EVENTS.Crash )
|
||||
self:HandleEvent( EVENTS.Dead )
|
||||
self:HandleEvent( EVENTS.PilotDead )
|
||||
self:HandleEvent( EVENTS.UnitLost )
|
||||
self:HandleEvent( EVENTS.Ejection )
|
||||
self:HandleEvent( EVENTS.HumanFailure )
|
||||
self:HandleEvent( EVENTS.HumanAircraftRepairFinish )
|
||||
self:HandleEvent( EVENTS.HumanAircraftRepairStart )
|
||||
self:HandleEvent( EVENTS.EngineShutdown )
|
||||
self:HandleEvent( EVENTS.EngineStartup )
|
||||
self:HandleEvent( EVENTS.WeaponAdd )
|
||||
self:HandleEvent( EVENTS.WeaponDrop )
|
||||
self:HandleEvent( EVENTS.WeaponRearm )
|
||||
|
||||
function self:OnEventHit(EventData)
|
||||
if EventData.TgtUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered hit event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:Hit(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventKill(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered kill event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:Kill(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventScore(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered score event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:Score(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventShot(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered shot event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:Shot(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventShootingStart(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered shooting start event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:ShootingStart(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventShootingEnd(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered shooting end event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:ShootingEnd(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventLand(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered land event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:Land(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventTakeoff(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered takeoff event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:Takeoff(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventRunwayTakeoff(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered runway takeoff event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:RunwayTakeoff(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventRunwayTouch(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered runway touch event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:RunwayTouch(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventRefueling(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered refueling event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:Refueling(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventRefuelingStop(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered refueling event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:RefuelingStop(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventPlayerLeaveUnit(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered leave unit event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:PlayerLeaveUnit(EventData)
|
||||
self._deadRoutine()
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventCrash(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered crash event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:Crash(EventData)
|
||||
self._deadRoutine()
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventDead(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered dead event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:Dead(EventData)
|
||||
self._deadRoutine()
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventPilotDead(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered pilot dead event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:PilotDead(EventData)
|
||||
self._deadRoutine()
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventUnitLost(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered unit lost event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:UnitLost(EventData)
|
||||
self._deadRoutine()
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventEjection(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered ejection event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:Ejection(EventData)
|
||||
self._deadRoutine()
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventHumanFailure(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered human failure event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:HumanFailure(EventData)
|
||||
if not self.Unit:IsAlive() then
|
||||
self._deadRoutine()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventHumanAircraftRepairFinish(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered repair finished event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:HumanAircraftRepairFinish(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventHumanAircraftRepairStart(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered repair start event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:HumanAircraftRepairStart(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventEngineShutdown(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered engine shutdown event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:EngineShutdown(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventEngineStartup(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered engine startup event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:EngineStartup(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventWeaponAdd(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered weapon add event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:WeaponAdd(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventWeaponDrop(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered weapon drop event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:WeaponDrop(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
function self:OnEventWeaponRearm(EventData)
|
||||
if EventData.IniUnitName == self.UnitName then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client triggered weapon rearm event.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
|
||||
end
|
||||
self:WeaponRearm(EventData)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--Fallback timer
|
||||
self.FallbackTimer = TIMER:New(function()
|
||||
if not self.Unit:IsAlive() then
|
||||
if clientWatchDebug then
|
||||
self:I({"Client is registered as dead without an event trigger. Running fallback dead routine.",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName})
|
||||
end
|
||||
self._deadRoutine()
|
||||
end
|
||||
end)
|
||||
self.FallbackTimer:Start(5,5)
|
||||
|
||||
--Stop event handlers and trigger Despawn
|
||||
function self._deadRoutine()
|
||||
if clientWatchDebug then self:I({"Client dead routine triggered. Shutting down tracking...",Player = self.PlayerName,Group = self.GroupName,Unit = self.UnitName}) end
|
||||
self:UnHandleEvent( EVENTS.Hit )
|
||||
self:UnHandleEvent( EVENTS.Kill )
|
||||
self:UnHandleEvent( EVENTS.Score )
|
||||
self:UnHandleEvent( EVENTS.Shot )
|
||||
self:UnHandleEvent( EVENTS.ShootingStart )
|
||||
self:UnHandleEvent( EVENTS.ShootingEnd )
|
||||
self:UnHandleEvent( EVENTS.Land )
|
||||
self:UnHandleEvent( EVENTS.Takeoff )
|
||||
self:UnHandleEvent( EVENTS.RunwayTakeoff )
|
||||
self:UnHandleEvent( EVENTS.RunwayTouch )
|
||||
self:UnHandleEvent( EVENTS.Refueling )
|
||||
self:UnHandleEvent( EVENTS.RefuelingStop )
|
||||
self:UnHandleEvent( EVENTS.PlayerLeaveUnit )
|
||||
self:UnHandleEvent( EVENTS.Crash )
|
||||
self:UnHandleEvent( EVENTS.Dead )
|
||||
self:UnHandleEvent( EVENTS.PilotDead )
|
||||
self:UnHandleEvent( EVENTS.UnitLost )
|
||||
self:UnHandleEvent( EVENTS.Ejection )
|
||||
self:UnHandleEvent( EVENTS.HumanFailure )
|
||||
self:UnHandleEvent( EVENTS.HumanAircraftRepairFinish )
|
||||
self:UnHandleEvent( EVENTS.HumanAircraftRepairStart )
|
||||
self:UnHandleEvent( EVENTS.EngineShutdown )
|
||||
self:UnHandleEvent( EVENTS.EngineStartup )
|
||||
self:UnHandleEvent( EVENTS.WeaponAdd )
|
||||
self:UnHandleEvent( EVENTS.WeaponDrop )
|
||||
self:UnHandleEvent( EVENTS.WeaponRearm )
|
||||
self.FallbackTimer:Stop()
|
||||
self:Despawn()
|
||||
end
|
||||
|
||||
self:I({"Detected client spawn and applied internal functions and events.", PlayerName = self.PlayerName, UnitName = self.UnitName, GroupName = self.GroupName})
|
||||
return self
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Management of target **Designation**. Lase, smoke and illuminate targets.
|
||||
--- **Functional** - Management of target **Designation**. Lase, smoke and illuminate targets.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -15,10 +15,12 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [DES - Designation](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/DES%20-%20Designation)
|
||||
--
|
||||
-- ## Additional Material:
|
||||
--
|
||||
-- * **Demo Missions:** [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Functional/Designate)
|
||||
-- * **YouTube videos:** None
|
||||
-- * **Guides:** None
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- Targets detected by recce will be communicated to a group of attacking players.
|
||||
@@ -48,7 +50,7 @@
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- A typical mission setup would require Recce (a @{Set} of Recce) to be detecting potential targets.
|
||||
-- A typical mission setup would require Recce (a @{Core.Set} of Recce) to be detecting potential targets.
|
||||
-- The DetectionObject will group the detected targets based on the detection method being used.
|
||||
-- Possible detection methods could be by Area, by Type or by Unit.
|
||||
-- Each grouping will result in a **TargetGroup**, for terminology and clarity we will use this term throughout the document.
|
||||
@@ -167,9 +169,9 @@
|
||||
--
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * [**Ciribob**](https://forums.eagle.ru/member.php?u=112175): Showing the way how to lase targets + how laser codes work!!! Explained the autolase script.
|
||||
-- * [**EasyEB**](https://forums.eagle.ru/member.php?u=112055): Ideas and Beta Testing
|
||||
-- * [**Wingthor**](https://forums.eagle.ru/member.php?u=123698): Beta Testing
|
||||
-- * **Ciribob**: Showing the way how to lase targets + how laser codes work!!! Explained the autolase script.
|
||||
-- * **EasyEB**: Ideas and Beta Testing
|
||||
-- * **Wingthor**: Beta Testing
|
||||
--
|
||||
-- ### Authors:
|
||||
--
|
||||
@@ -182,7 +184,7 @@
|
||||
|
||||
do -- DESIGNATE
|
||||
|
||||
--- @type DESIGNATE
|
||||
-- @type DESIGNATE
|
||||
-- @extends Core.Fsm#FSM_PROCESS
|
||||
|
||||
--- Manage the designation of detected targets.
|
||||
@@ -276,7 +278,7 @@ do -- DESIGNATE
|
||||
-- # 7. Designate Menu Location for a Mission
|
||||
--
|
||||
-- You can make DESIGNATE work for a @{Tasking.Mission#MISSION} object. In this way, the designate menu will not appear in the root of the radio menu, but in the menu of the Mission.
|
||||
-- Use the method @{#DESIGNATE.SetMission}() to set the @{Mission} object for the designate function.
|
||||
-- Use the method @{#DESIGNATE.SetMission}() to set the @{Tasking.Mission} object for the designate function.
|
||||
--
|
||||
-- # 8. Status Report
|
||||
--
|
||||
@@ -523,7 +525,7 @@ do -- DESIGNATE
|
||||
|
||||
self.AttackSet:ForEachGroupAlive(
|
||||
|
||||
--- @param Wrapper.Group#GROUP AttackGroup
|
||||
-- @param Wrapper.Group#GROUP AttackGroup
|
||||
function( AttackGroup )
|
||||
self.FlashStatusMenu[AttackGroup] = FlashMenu
|
||||
end
|
||||
@@ -552,7 +554,7 @@ do -- DESIGNATE
|
||||
|
||||
self.AttackSet:ForEachGroupAlive(
|
||||
|
||||
--- @param Wrapper.Group#GROUP AttackGroup
|
||||
-- @param Wrapper.Group#GROUP AttackGroup
|
||||
function( AttackGroup )
|
||||
self.FlashDetectionMessage[AttackGroup] = FlashDetectionMessage
|
||||
end
|
||||
@@ -824,7 +826,7 @@ do -- DESIGNATE
|
||||
-- This Detection is obsolete, remove from the designate scope
|
||||
self.Designating[DesignateIndex] = nil
|
||||
self.AttackSet:ForEachGroupAlive(
|
||||
--- @param Wrapper.Group#GROUP AttackGroup
|
||||
-- @param Wrapper.Group#GROUP AttackGroup
|
||||
function( AttackGroup )
|
||||
if AttackGroup:IsAlive() == true then
|
||||
local DetectionText = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup ):Text( ", " )
|
||||
@@ -901,7 +903,7 @@ do -- DESIGNATE
|
||||
|
||||
self.AttackSet:ForEachGroupAlive(
|
||||
|
||||
--- @param Wrapper.Group#GROUP GroupReport
|
||||
-- @param Wrapper.Group#GROUP GroupReport
|
||||
function( AttackGroup )
|
||||
|
||||
if self.FlashStatusMenu[AttackGroup] or ( MenuAttackGroup and ( AttackGroup:GetName() == MenuAttackGroup:GetName() ) ) then
|
||||
@@ -1058,7 +1060,7 @@ do -- DESIGNATE
|
||||
|
||||
self.AttackSet:ForEachGroupAlive(
|
||||
|
||||
--- @param Wrapper.Group#GROUP GroupReport
|
||||
-- @param Wrapper.Group#GROUP GroupReport
|
||||
function( AttackGroup )
|
||||
|
||||
self:ScheduleOnce( Delay, self.SetMenu, self, AttackGroup )
|
||||
@@ -1196,7 +1198,7 @@ do -- DESIGNATE
|
||||
--local ReportTypes = REPORT:New()
|
||||
--local ReportLaserCodes = REPORT:New()
|
||||
|
||||
TargetSetUnit:Flush( self )
|
||||
--TargetSetUnit:Flush( self )
|
||||
|
||||
--self:F( { Recces = self.Recces } )
|
||||
for TargetUnit, RecceData in pairs( self.Recces ) do
|
||||
@@ -1227,10 +1229,12 @@ do -- DESIGNATE
|
||||
end
|
||||
end
|
||||
|
||||
if TargetSetUnit == nil then return end
|
||||
|
||||
if self.AutoLase or ( not self.AutoLase and ( self.LaseStart + Duration >= timer.getTime() ) ) then
|
||||
|
||||
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
||||
--- @param Wrapper.Unit#UNIT SmokeUnit
|
||||
-- @param Wrapper.Unit#UNIT SmokeUnit
|
||||
function( TargetUnit )
|
||||
|
||||
self:F( { TargetUnit = TargetUnit:GetName() } )
|
||||
@@ -1251,7 +1255,7 @@ do -- DESIGNATE
|
||||
|
||||
local RecceUnit = UnitData -- Wrapper.Unit#UNIT
|
||||
local RecceUnitDesc = RecceUnit:GetDesc()
|
||||
--self:F( { RecceUnit = RecceUnit:GetName(), RecceDescription = RecceUnitDesc } )
|
||||
--self:F( { RecceUnit = RecceUnit:GetName(), RecceDescription = RecceUnitDesc } )x
|
||||
|
||||
if RecceUnit:IsLasing() == false then
|
||||
--self:F( { IsDetected = RecceUnit:IsDetected( TargetUnit ), IsLOS = RecceUnit:IsLOS( TargetUnit ) } )
|
||||
@@ -1273,9 +1277,10 @@ do -- DESIGNATE
|
||||
local Spot = RecceUnit:LaseUnit( TargetUnit, LaserCode, Duration )
|
||||
local AttackSet = self.AttackSet
|
||||
local DesignateName = self.DesignateName
|
||||
local typename = TargetUnit:GetTypeName()
|
||||
|
||||
function Spot:OnAfterDestroyed( From, Event, To )
|
||||
self.Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() .. " destroyed. " .. TargetSetUnit:Count() .. " targets left.",
|
||||
self.Recce:MessageToSetGroup( "Target " ..typename .. " destroyed. " .. TargetSetUnit:CountAlive() .. " targets left.",
|
||||
5, AttackSet, self.DesignateName )
|
||||
end
|
||||
|
||||
@@ -1283,7 +1288,7 @@ do -- DESIGNATE
|
||||
-- OK. We have assigned for the Recce a TargetUnit. We can exit the function.
|
||||
MarkingCount = MarkingCount + 1
|
||||
local TargetUnitType = TargetUnit:GetTypeName()
|
||||
RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.",
|
||||
RecceUnit:MessageToSetGroup( "Marking " .. TargetUnitType .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.",
|
||||
10, self.AttackSet, DesignateName )
|
||||
if not MarkedTypes[TargetUnitType] then
|
||||
MarkedTypes[TargetUnitType] = true
|
||||
@@ -1390,7 +1395,7 @@ do -- DESIGNATE
|
||||
local MarkedCount = 0
|
||||
|
||||
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
||||
--- @param Wrapper.Unit#UNIT SmokeUnit
|
||||
-- @param Wrapper.Unit#UNIT SmokeUnit
|
||||
function( SmokeUnit )
|
||||
|
||||
if MarkedCount < self.MaximumMarkings then
|
||||
@@ -1455,9 +1460,10 @@ do -- DESIGNATE
|
||||
-- @param #DESIGNATE self
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:onafterDoneSmoking( From, Event, To, Index )
|
||||
|
||||
self.Designating[Index] = string.gsub( self.Designating[Index], "S", "" )
|
||||
self:SetDesignateMenu()
|
||||
if self.Designating[Index] ~= nil then
|
||||
self.Designating[Index] = string.gsub( self.Designating[Index], "S", "" )
|
||||
self:SetDesignateMenu()
|
||||
end
|
||||
end
|
||||
|
||||
--- DoneIlluminating
|
||||
@@ -1470,5 +1476,3 @@ do -- DESIGNATE
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Models the detection of enemy units by FACs or RECCEs and group them according various methods.
|
||||
--- **Functional** - Models the detection of enemy units by FACs or RECCEs and group them according various methods.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -15,7 +15,7 @@
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [DET - Detection](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/DET%20-%20Detection)
|
||||
-- [DET - Detection](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Functional/Detection)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -38,9 +38,10 @@
|
||||
-- @image Detection.JPG
|
||||
|
||||
do -- DETECTION_BASE
|
||||
|
||||
--- @type DETECTION_BASE
|
||||
-- @field Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
||||
|
||||
---
|
||||
-- @type DETECTION_BASE
|
||||
-- @field Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
|
||||
-- @field DCS#Distance DetectionRange The range till which targets are accepted to be detected.
|
||||
-- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects.
|
||||
-- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified.
|
||||
@@ -91,6 +92,11 @@ do -- DETECTION_BASE
|
||||
--
|
||||
-- DetectionObject:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
|
||||
--
|
||||
--
|
||||
-- ## Radar Blur - use to make the radar less exact, e.g. for WWII scenarios
|
||||
--
|
||||
-- * @{#DETECTION_BASE.SetRadarBlur}(): Set the radar blur to be used.
|
||||
--
|
||||
-- ## **DETECTION_ derived classes** group the detected units into a **DetectedItems[]** list
|
||||
--
|
||||
-- DETECTION_BASE derived classes build a list called DetectedItems[], which is essentially a first later
|
||||
@@ -268,11 +274,13 @@ do -- DETECTION_BASE
|
||||
DetectedItems = {},
|
||||
DetectedItemsByIndex = {},
|
||||
}
|
||||
|
||||
--- @type DETECTION_BASE.DetectedObjects
|
||||
|
||||
---
|
||||
-- @type DETECTION_BASE.DetectedObjects
|
||||
-- @list <#DETECTION_BASE.DetectedObject>
|
||||
|
||||
--- @type DETECTION_BASE.DetectedObject
|
||||
---
|
||||
-- @type DETECTION_BASE.DetectedObject
|
||||
-- @field #string Name
|
||||
-- @field #boolean IsVisible
|
||||
-- @field #boolean KnowType
|
||||
@@ -283,8 +291,9 @@ do -- DETECTION_BASE
|
||||
-- @field #number LastTime
|
||||
-- @field #boolean LastPos
|
||||
-- @field #number LastVelocity
|
||||
|
||||
--- @type DETECTION_BASE.DetectedItems
|
||||
|
||||
---
|
||||
-- @type DETECTION_BASE.DetectedItems
|
||||
-- @list <#DETECTION_BASE.DetectedItem>
|
||||
|
||||
--- Detected item data structure.
|
||||
@@ -318,7 +327,7 @@ do -- DETECTION_BASE
|
||||
|
||||
--- DETECTION constructor.
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param Core.Set#SET_GROUP DetectionSet The @{Set} of @{Group}s that is used to detect the units.
|
||||
-- @param Core.Set#SET_GROUP DetectionSet The @{Core.Set} of @{Wrapper.Group}s that is used to detect the units.
|
||||
-- @return #DETECTION_BASE self
|
||||
function DETECTION_BASE:New( DetectionSet )
|
||||
|
||||
@@ -474,7 +483,7 @@ do -- DETECTION_BASE
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @param #table DetectedItem The DetectedItem.
|
||||
-- @param #DetectedItem DetectedItem The DetectedItem data structure.
|
||||
|
||||
self:AddTransition( "*", "Stop", "Stopped" )
|
||||
|
||||
@@ -522,7 +531,7 @@ do -- DETECTION_BASE
|
||||
|
||||
do -- State Transition Handling
|
||||
|
||||
--- @param #DETECTION_BASE self
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -530,13 +539,13 @@ do -- DETECTION_BASE
|
||||
self:__Detect( 1 )
|
||||
end
|
||||
|
||||
--- @param #DETECTION_BASE self
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
function DETECTION_BASE:onafterDetect( From, Event, To )
|
||||
|
||||
local DetectDelay = 0.1
|
||||
local DetectDelay = 0.15
|
||||
self.DetectionCount = 0
|
||||
self.DetectionRun = 0
|
||||
self:UnIdentifyAllDetectedObjects() -- Resets the DetectedObjectsIdentified table
|
||||
@@ -570,7 +579,7 @@ do -- DETECTION_BASE
|
||||
|
||||
end
|
||||
|
||||
--- @param #DETECTION_BASE self
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #number The amount of alive recce.
|
||||
function DETECTION_BASE:CountAliveRecce()
|
||||
|
||||
@@ -578,7 +587,7 @@ do -- DETECTION_BASE
|
||||
|
||||
end
|
||||
|
||||
--- @param #DETECTION_BASE self
|
||||
-- @param #DETECTION_BASE self
|
||||
function DETECTION_BASE:ForEachAliveRecce( IteratorFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
@@ -586,8 +595,9 @@ do -- DETECTION_BASE
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- @param #DETECTION_BASE self
|
||||
|
||||
---
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -595,7 +605,7 @@ do -- DETECTION_BASE
|
||||
-- @param #number DetectionTimeStamp Time stamp of detection event.
|
||||
function DETECTION_BASE:onafterDetection( From, Event, To, Detection, DetectionTimeStamp )
|
||||
|
||||
-- self:F( { DetectedObjects = self.DetectedObjects } )
|
||||
self:T( { DetectedObjects = self.DetectedObjects } )
|
||||
|
||||
self.DetectionRun = self.DetectionRun + 1
|
||||
|
||||
@@ -603,14 +613,14 @@ do -- DETECTION_BASE
|
||||
|
||||
if Detection and Detection:IsAlive() then
|
||||
|
||||
-- self:T( { "DetectionGroup is Alive", DetectionGroup:GetName() } )
|
||||
self:T( { "DetectionGroup is Alive", Detection:GetName() } )
|
||||
|
||||
local DetectionGroupName = Detection:GetName()
|
||||
local DetectionUnit = Detection:GetUnit( 1 )
|
||||
local DetectionUnit = Detection:GetFirstUnitAlive()
|
||||
|
||||
local DetectedUnits = {}
|
||||
|
||||
local DetectedTargets = Detection:GetDetectedTargets(
|
||||
local DetectedTargets = DetectionUnit:GetDetectedTargets(
|
||||
self.DetectVisual,
|
||||
self.DetectOptical,
|
||||
self.DetectRadar,
|
||||
@@ -619,28 +629,30 @@ do -- DETECTION_BASE
|
||||
self.DetectDLINK
|
||||
)
|
||||
|
||||
self:F( { DetectedTargets = DetectedTargets } )
|
||||
|
||||
for DetectionObjectID, Detection in pairs( DetectedTargets ) do
|
||||
--self:T( { DetectedTargets = DetectedTargets } )
|
||||
--self:T(UTILS.PrintTableToLog(DetectedTargets))
|
||||
|
||||
|
||||
for DetectionObjectID, Detection in pairs( DetectedTargets or {}) do
|
||||
local DetectedObject = Detection.object -- DCS#Object
|
||||
|
||||
if DetectedObject and DetectedObject:isExist() and DetectedObject.id_ < 50000000 then -- and ( DetectedObject:getCategory() == Object.Category.UNIT or DetectedObject:getCategory() == Object.Category.STATIC ) then
|
||||
local DetectedObjectName = DetectedObject:getName()
|
||||
if not self.DetectedObjects[DetectedObjectName] then
|
||||
self.DetectedObjects[DetectedObjectName] = self.DetectedObjects[DetectedObjectName] or {}
|
||||
self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName
|
||||
self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName
|
||||
self.DetectedObjects[DetectedObjectName].Object = DetectedObject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for DetectionObjectName, DetectedObjectData in pairs( self.DetectedObjects ) do
|
||||
for DetectionObjectName, DetectedObjectData in pairs( self.DetectedObjects or {}) do
|
||||
|
||||
local DetectedObject = DetectedObjectData.Object
|
||||
|
||||
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,
|
||||
self.DetectVisual,
|
||||
self.DetectOptical,
|
||||
@@ -712,6 +724,31 @@ do -- DETECTION_BASE
|
||||
end
|
||||
end
|
||||
|
||||
-- Calculate radar blur probability
|
||||
|
||||
if self.RadarBlur then
|
||||
MESSAGE:New("Radar Blur",10):ToLogIf(self.debug):ToAllIf(self.verbose)
|
||||
local minheight = self.RadarBlurMinHeight or 250 -- meters
|
||||
local thresheight = self.RadarBlurThresHeight or 90 -- 10% chance to find a low flying group
|
||||
local thresblur = self.RadarBlurThresBlur or 85 -- 25% chance to escape the radar overall
|
||||
local dist = math.floor(Distance)
|
||||
if dist <= self.RadarBlurClosing then
|
||||
thresheight = (((dist*dist)/self.RadarBlurClosingSquare)*thresheight)
|
||||
thresblur = (((dist*dist)/self.RadarBlurClosingSquare)*thresblur)
|
||||
end
|
||||
local fheight = math.floor(math.random(1,10000)/100)
|
||||
local fblur = math.floor(math.random(1,10000)/100)
|
||||
local unit = UNIT:FindByName(DetectedObjectName)
|
||||
if unit and unit:IsAlive() then
|
||||
local AGL = unit:GetAltitude(true)
|
||||
MESSAGE:New("Unit "..DetectedObjectName.." is at "..math.floor(AGL).."m. Distance "..math.floor(Distance).."km.",10):ToLogIf(self.debug):ToAllIf(self.verbose)
|
||||
MESSAGE:New(string.format("fheight = %d/%d | fblur = %d/%d",fheight,thresheight,fblur,thresblur),10):ToLogIf(self.debug):ToAllIf(self.verbose)
|
||||
if fblur > thresblur then DetectionAccepted = false end
|
||||
if AGL <= minheight and fheight < thresheight then DetectionAccepted = false end
|
||||
MESSAGE:New("Detection Accepted = "..tostring(DetectionAccepted),10):ToLogIf(self.debug):ToAllIf(self.verbose)
|
||||
end
|
||||
end
|
||||
|
||||
-- Calculate additional probabilities
|
||||
|
||||
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.DistanceProbability then
|
||||
@@ -1011,7 +1048,24 @@ do -- DETECTION_BASE
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Method to make the radar detection less accurate, e.g. for WWII scenarios.
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #number minheight Minimum flight height to be detected, in meters AGL (above ground)
|
||||
-- @param #number thresheight Threshold to escape the radar if flying below minheight, defaults to 90 (90% escape chance)
|
||||
-- @param #number thresblur Threshold to be detected by the radar overall, defaults to 85 (85% chance to be found)
|
||||
-- @param #number closing Closing-in in km - the limit of km from which on it becomes increasingly difficult to escape radar detection if flying towards the radar position. Should be about 1/3 of the radar detection radius in kilometers, defaults to 20.
|
||||
-- @return #DETECTION_BASE self
|
||||
function DETECTION_BASE:SetRadarBlur(minheight,thresheight,thresblur,closing)
|
||||
self.RadarBlur = true
|
||||
self.RadarBlurMinHeight = minheight or 250 -- meters
|
||||
self.RadarBlurThresHeight = thresheight or 90 -- 10% chance to find a low flying group
|
||||
self.RadarBlurThresBlur = thresblur or 85 -- 25% chance to escape the radar overall
|
||||
self.RadarBlurClosing = closing or 20 -- 20km
|
||||
self.RadarBlurClosingSquare = self.RadarBlurClosing * self.RadarBlurClosing
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do
|
||||
@@ -1354,7 +1408,7 @@ do -- DETECTION_BASE
|
||||
}
|
||||
}
|
||||
|
||||
--- @param DCS#Unit FoundDCSUnit
|
||||
-- @param DCS#Unit FoundDCSUnit
|
||||
-- @param Wrapper.Group#GROUP ReportGroup
|
||||
-- @param Core.Set#SET_GROUP ReportSetGroup
|
||||
local FindNearByFriendlies = function( FoundDCSUnit, ReportGroupData )
|
||||
@@ -1419,7 +1473,7 @@ do -- DETECTION_BASE
|
||||
DetectedItem.PlayersNearBy = nil
|
||||
|
||||
_DATABASE:ForEachPlayer(
|
||||
--- @param Wrapper.Unit#UNIT PlayerUnit
|
||||
-- @param Wrapper.Unit#UNIT PlayerUnit
|
||||
function( PlayerUnitName )
|
||||
local PlayerUnit = UNIT:FindByName( PlayerUnitName )
|
||||
|
||||
@@ -1975,14 +2029,15 @@ do -- DETECTION_BASE
|
||||
end
|
||||
|
||||
do -- DETECTION_UNITS
|
||||
|
||||
--- @type DETECTION_UNITS
|
||||
|
||||
---
|
||||
-- @type DETECTION_UNITS
|
||||
-- @field DCS#Distance DetectionRange The range till which targets are detected.
|
||||
-- @extends Functional.Detection#DETECTION_BASE
|
||||
|
||||
--- Will detect units within the battle zone.
|
||||
--
|
||||
-- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference.
|
||||
-- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{Wrapper.Unit#UNIT} object reference.
|
||||
-- Beware that when the amount of units detected is large, the DetectedItems list will be large also.
|
||||
--
|
||||
-- @field #DETECTION_UNITS
|
||||
@@ -1993,7 +2048,7 @@ do -- DETECTION_UNITS
|
||||
|
||||
--- DETECTION_UNITS constructor.
|
||||
-- @param Functional.Detection#DETECTION_UNITS self
|
||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
|
||||
-- @return Functional.Detection#DETECTION_UNITS self
|
||||
function DETECTION_UNITS:New( DetectionSetGroup )
|
||||
|
||||
@@ -2231,13 +2286,14 @@ do -- DETECTION_UNITS
|
||||
end
|
||||
|
||||
do -- DETECTION_TYPES
|
||||
|
||||
--- @type DETECTION_TYPES
|
||||
|
||||
---
|
||||
-- @type DETECTION_TYPES
|
||||
-- @extends Functional.Detection#DETECTION_BASE
|
||||
|
||||
--- Will detect units within the battle zone.
|
||||
-- It will build a DetectedItems[] list filled with DetectedItems, grouped by the type of units detected.
|
||||
-- Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference.
|
||||
-- Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{Wrapper.Unit#UNIT} object reference.
|
||||
-- Beware that when the amount of different types detected is large, the DetectedItems[] list will be large also.
|
||||
--
|
||||
-- @field #DETECTION_TYPES
|
||||
@@ -2248,7 +2304,7 @@ do -- DETECTION_TYPES
|
||||
|
||||
--- DETECTION_TYPES constructor.
|
||||
-- @param Functional.Detection#DETECTION_TYPES self
|
||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Recce role.
|
||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Recce role.
|
||||
-- @return Functional.Detection#DETECTION_TYPES self
|
||||
function DETECTION_TYPES:New( DetectionSetGroup )
|
||||
|
||||
@@ -2354,6 +2410,7 @@ do -- DETECTION_TYPES
|
||||
if not DetectedItem then
|
||||
DetectedItem = self:AddDetectedItem( "TYPE", DetectedTypeName )
|
||||
DetectedItem.TypeName = DetectedTypeName
|
||||
DetectedItem.Name = DetectedUnitName -- fix by @Nocke
|
||||
end
|
||||
|
||||
DetectedItem.Set:AddUnit( DetectedUnit )
|
||||
@@ -2433,10 +2490,11 @@ do -- DETECTION_TYPES
|
||||
end
|
||||
|
||||
do -- DETECTION_AREAS
|
||||
|
||||
--- @type DETECTION_AREAS
|
||||
|
||||
---
|
||||
-- @type DETECTION_AREAS
|
||||
-- @field DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
||||
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
|
||||
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Core.Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
|
||||
-- @extends Functional.Detection#DETECTION_BASE
|
||||
|
||||
--- Detect units within the battle zone for a list of @{Wrapper.Group}s detecting targets following (a) detection method(s),
|
||||
@@ -2451,7 +2509,7 @@ do -- DETECTION_AREAS
|
||||
--
|
||||
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
|
||||
--
|
||||
-- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZones}().
|
||||
-- Retrieve the formed @{Core.Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZones}().
|
||||
-- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZoneCount}().
|
||||
-- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZoneByID}() with a given index.
|
||||
--
|
||||
@@ -2477,15 +2535,15 @@ do -- DETECTION_AREAS
|
||||
|
||||
--- DETECTION_AREAS constructor.
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
||||
-- @param DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
|
||||
-- @param #number DetectionZoneRange The range in meters within which targets are grouped upon the first detected target. Default 5000m.
|
||||
-- @return #DETECTION_AREAS
|
||||
function DETECTION_AREAS:New( DetectionSetGroup, DetectionZoneRange )
|
||||
|
||||
-- Inherits from DETECTION_BASE
|
||||
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetGroup ) )
|
||||
|
||||
self.DetectionZoneRange = DetectionZoneRange
|
||||
self.DetectionZoneRange = DetectionZoneRange or 5000
|
||||
|
||||
self._SmokeDetectedUnits = false
|
||||
self._FlareDetectedUnits = false
|
||||
@@ -2498,7 +2556,7 @@ do -- DETECTION_AREAS
|
||||
|
||||
--- Retrieve set of detected zones.
|
||||
-- @param #DETECTION_AREAS self
|
||||
-- @return Core.Set#SET_ZONE The @{Set} of ZONE_UNIT objects detected.
|
||||
-- @return Core.Set#SET_ZONE The @{Core.Set} of ZONE_UNIT objects detected.
|
||||
function DETECTION_AREAS:GetDetectionZones()
|
||||
local zoneset = SET_ZONE:New()
|
||||
for _ID,_Item in pairs (self.DetectedItems) do
|
||||
@@ -2960,7 +3018,7 @@ do -- DETECTION_AREAS
|
||||
|
||||
-- DetectedSet:Flush( self )
|
||||
|
||||
DetectedSet:ForEachUnit( --- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
DetectedSet:ForEachUnit( -- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
function( DetectedUnit )
|
||||
if DetectedUnit:IsAlive() then
|
||||
-- self:T( "Detected Set #" .. DetectedItem.ID .. ":" .. DetectedUnit:GetName() )
|
||||
@@ -2988,4 +3046,3 @@ do -- DETECTION_AREAS
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
--- **Functional** - Captures the class DETECTION_ZONES.
|
||||
-- @module Functional.DetectionZones
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
do -- DETECTION_ZONES
|
||||
|
||||
--- @type DETECTION_ZONES
|
||||
-- @field DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
||||
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
|
||||
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Core.Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
|
||||
-- @extends Functional.Detection#DETECTION_BASE
|
||||
|
||||
--- (old, to be revised ) Detect units within the battle zone for a list of @{Core.Zone}s detecting targets following (a) detection method(s),
|
||||
@@ -17,7 +21,7 @@ do -- DETECTION_ZONES
|
||||
--
|
||||
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
|
||||
--
|
||||
-- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZones}().
|
||||
-- Retrieve the formed @{Core.Zone#ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZones}().
|
||||
-- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZoneCount}().
|
||||
-- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZone}() with a given index.
|
||||
--
|
||||
@@ -40,27 +44,27 @@ do -- DETECTION_ZONES
|
||||
ClassName = "DETECTION_ZONES",
|
||||
DetectionZoneRange = nil,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
--- DETECTION_ZONES constructor.
|
||||
-- @param #DETECTION_ZONES self
|
||||
-- @param Core.Set#SET_ZONE DetectionSetZone The @{Set} of ZONE_RADIUS.
|
||||
-- @param Core.Set#SET_ZONE DetectionSetZone The @{Core.Set} of ZONE_RADIUS.
|
||||
-- @param DCS#Coalition.side DetectionCoalition The coalition of the detection.
|
||||
-- @return #DETECTION_ZONES
|
||||
function DETECTION_ZONES:New( DetectionSetZone, DetectionCoalition )
|
||||
|
||||
|
||||
-- Inherits from DETECTION_BASE
|
||||
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetZone ) ) -- #DETECTION_ZONES
|
||||
|
||||
|
||||
self.DetectionSetZone = DetectionSetZone -- Core.Set#SET_ZONE
|
||||
self.DetectionCoalition = DetectionCoalition
|
||||
|
||||
|
||||
self._SmokeDetectedUnits = false
|
||||
self._FlareDetectedUnits = false
|
||||
self._SmokeDetectedZones = false
|
||||
self._FlareDetectedZones = false
|
||||
self._BoundDetectedZones = false
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Taking the lead of AI escorting your flight.
|
||||
--- **Functional** - Taking the lead of AI escorting your flight.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -16,11 +16,13 @@
|
||||
-- * Escort tactical situation reporting.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [ESC - Escorting](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/ESC%20-%20Escorting)
|
||||
--
|
||||
--
|
||||
-- ## Additional Material:
|
||||
--
|
||||
-- * **Demo Missions:** [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Functional/Escort)
|
||||
-- * **YouTube videos:** None
|
||||
-- * **Guides:** None
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- Allows you to interact with escorting AI on your flight and take the lead.
|
||||
@@ -108,8 +110,8 @@
|
||||
-- @image Escorting.JPG
|
||||
|
||||
|
||||
|
||||
--- @type ESCORT
|
||||
---
|
||||
-- @type ESCORT
|
||||
-- @extends Core.Base#BASE
|
||||
-- @field Wrapper.Client#CLIENT EscortClient
|
||||
-- @field Wrapper.Group#GROUP EscortGroup
|
||||
@@ -252,7 +254,7 @@ end
|
||||
--- Set a Detection method for the EscortClient to be reported upon.
|
||||
-- Detection methods are based on the derived classes from DETECTION_BASE.
|
||||
-- @param #ESCORT self
|
||||
-- @param Function.Detection#DETECTION_BASE Detection
|
||||
-- @param Functional.Detection#DETECTION_BASE Detection
|
||||
function ESCORT:SetDetection( Detection )
|
||||
|
||||
self.Detection = Detection
|
||||
@@ -600,7 +602,7 @@ function ESCORT:MenuReportTargets( Seconds )
|
||||
self.EscortMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortClient:GetGroup(), "Attack targets", self.EscortMenu )
|
||||
|
||||
|
||||
self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds )
|
||||
self.ReportTargetsScheduler, self.ReportTargetsSchedulerID = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -693,7 +695,7 @@ function ESCORT:MenuResumeMission()
|
||||
end
|
||||
|
||||
|
||||
--- @param #MENUPARAM MenuParam
|
||||
-- @param #MENUPARAM MenuParam
|
||||
function ESCORT:_HoldPosition( OrbitGroup, OrbitHeight, OrbitSeconds )
|
||||
|
||||
local EscortGroup = self.EscortGroup
|
||||
@@ -733,7 +735,7 @@ function ESCORT:_HoldPosition( OrbitGroup, OrbitHeight, OrbitSeconds )
|
||||
|
||||
end
|
||||
|
||||
--- @param #MENUPARAM MenuParam
|
||||
-- @param #MENUPARAM MenuParam
|
||||
function ESCORT:_JoinUpAndFollow( Distance )
|
||||
|
||||
local EscortGroup = self.EscortGroup
|
||||
@@ -766,7 +768,7 @@ function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance )
|
||||
EscortGroup:MessageToClient( "Rejoining and Following at " .. Distance .. "!", 30, EscortClient )
|
||||
end
|
||||
|
||||
--- @param #MENUPARAM MenuParam
|
||||
-- @param #MENUPARAM MenuParam
|
||||
function ESCORT:_Flare( Color, Message )
|
||||
|
||||
local EscortGroup = self.EscortGroup
|
||||
@@ -776,7 +778,7 @@ function ESCORT:_Flare( Color, Message )
|
||||
EscortGroup:MessageToClient( Message, 10, EscortClient )
|
||||
end
|
||||
|
||||
--- @param #MENUPARAM MenuParam
|
||||
-- @param #MENUPARAM MenuParam
|
||||
function ESCORT:_Smoke( Color, Message )
|
||||
|
||||
local EscortGroup = self.EscortGroup
|
||||
@@ -787,7 +789,7 @@ function ESCORT:_Smoke( Color, Message )
|
||||
end
|
||||
|
||||
|
||||
--- @param #MENUPARAM MenuParam
|
||||
-- @param #MENUPARAM MenuParam
|
||||
function ESCORT:_ReportNearbyTargetsNow()
|
||||
|
||||
local EscortGroup = self.EscortGroup
|
||||
@@ -809,12 +811,12 @@ function ESCORT:_SwitchReportNearbyTargets( ReportTargets )
|
||||
self.ReportTargetsScheduler:Schedule( self, self._ReportTargetsScheduler, {}, 1, 30 )
|
||||
end
|
||||
else
|
||||
routines.removeFunction( self.ReportTargetsScheduler )
|
||||
self.ReportTargetsScheduler:Remove(self.ReportTargetsSchedulerID)
|
||||
self.ReportTargetsScheduler = nil
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #MENUPARAM MenuParam
|
||||
-- @param #MENUPARAM MenuParam
|
||||
function ESCORT:_ScanTargets( ScanDuration )
|
||||
|
||||
local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP
|
||||
@@ -844,7 +846,7 @@ function ESCORT:_ScanTargets( ScanDuration )
|
||||
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function _Resume( EscortGroup )
|
||||
env.info( '_Resume' )
|
||||
|
||||
@@ -856,7 +858,7 @@ function _Resume( EscortGroup )
|
||||
|
||||
end
|
||||
|
||||
--- @param #ESCORT self
|
||||
-- @param #ESCORT self
|
||||
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
||||
function ESCORT:_AttackTarget( DetectedItem )
|
||||
|
||||
@@ -877,7 +879,7 @@ function ESCORT:_AttackTarget( DetectedItem )
|
||||
local Tasks = {}
|
||||
|
||||
DetectedSet:ForEachUnit(
|
||||
--- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
-- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
function( DetectedUnit, Tasks )
|
||||
if DetectedUnit:IsAlive() then
|
||||
Tasks[#Tasks+1] = EscortGroup:TaskAttackUnit( DetectedUnit )
|
||||
@@ -900,7 +902,7 @@ function ESCORT:_AttackTarget( DetectedItem )
|
||||
local Tasks = {}
|
||||
|
||||
DetectedSet:ForEachUnit(
|
||||
--- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
-- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
function( DetectedUnit, Tasks )
|
||||
if DetectedUnit:IsAlive() then
|
||||
Tasks[#Tasks+1] = EscortGroup:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 )
|
||||
@@ -921,7 +923,7 @@ function ESCORT:_AttackTarget( DetectedItem )
|
||||
end
|
||||
|
||||
---
|
||||
--- @param #ESCORT self
|
||||
-- @param #ESCORT self
|
||||
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
||||
function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
|
||||
|
||||
@@ -939,7 +941,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
|
||||
local Tasks = {}
|
||||
|
||||
DetectedSet:ForEachUnit(
|
||||
--- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
-- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
function( DetectedUnit, Tasks )
|
||||
if DetectedUnit:IsAlive() then
|
||||
Tasks[#Tasks+1] = EscortGroupAttack:TaskAttackUnit( DetectedUnit )
|
||||
@@ -961,7 +963,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
|
||||
local Tasks = {}
|
||||
|
||||
DetectedSet:ForEachUnit(
|
||||
--- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
-- @param Wrapper.Unit#UNIT DetectedUnit
|
||||
function( DetectedUnit, Tasks )
|
||||
if DetectedUnit:IsAlive() then
|
||||
Tasks[#Tasks+1] = EscortGroupAttack:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 )
|
||||
@@ -981,7 +983,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
|
||||
|
||||
end
|
||||
|
||||
--- @param #MENUPARAM MenuParam
|
||||
-- @param #MENUPARAM MenuParam
|
||||
function ESCORT:_ROE( EscortROEFunction, EscortROEMessage )
|
||||
|
||||
local EscortGroup = self.EscortGroup
|
||||
@@ -991,7 +993,7 @@ function ESCORT:_ROE( EscortROEFunction, EscortROEMessage )
|
||||
EscortGroup:MessageToClient( EscortROEMessage, 10, EscortClient )
|
||||
end
|
||||
|
||||
--- @param #MENUPARAM MenuParam
|
||||
-- @param #MENUPARAM MenuParam
|
||||
function ESCORT:_ROT( EscortROTFunction, EscortROTMessage )
|
||||
|
||||
local EscortGroup = self.EscortGroup
|
||||
@@ -1001,7 +1003,7 @@ function ESCORT:_ROT( EscortROTFunction, EscortROTMessage )
|
||||
EscortGroup:MessageToClient( EscortROTMessage, 10, EscortClient )
|
||||
end
|
||||
|
||||
--- @param #MENUPARAM MenuParam
|
||||
-- @param #MENUPARAM MenuParam
|
||||
function ESCORT:_ResumeMission( WayPoint )
|
||||
|
||||
local EscortGroup = self.EscortGroup
|
||||
@@ -1036,7 +1038,7 @@ function ESCORT:RegisterRoute()
|
||||
return TaskPoints
|
||||
end
|
||||
|
||||
--- @param Functional.Escort#ESCORT self
|
||||
-- @param Functional.Escort#ESCORT self
|
||||
function ESCORT:_FollowScheduler()
|
||||
self:F( { self.FollowDistance } )
|
||||
|
||||
@@ -1152,8 +1154,6 @@ function ESCORT:_ReportTargetsScheduler()
|
||||
|
||||
if self.EscortGroup:IsAlive() and self.EscortClient:IsAlive() then
|
||||
|
||||
if true then
|
||||
|
||||
local EscortGroupName = self.EscortGroup:GetName()
|
||||
|
||||
self.EscortMenuAttackNearbyTargets:RemoveSubMenus()
|
||||
@@ -1224,177 +1224,6 @@ function ESCORT:_ReportTargetsScheduler()
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
return false
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Train missile defence and deflection.
|
||||
--- **Functional** - Train missile defence and deflection.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -14,7 +14,7 @@
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [MIT - Missile Trainer](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/MIT%20-%20Missile%20Trainer)
|
||||
-- [MIT - Missile Trainer](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Functional/MissileTrainer)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -28,14 +28,14 @@
|
||||
-- * **Messages Off**: Disable all messages.
|
||||
-- * **Tracking**: Menu to configure missile tracking messages.
|
||||
-- * **To All**: Shows missile tracking messages to all players.
|
||||
-- * **To Target**: Shows missile tracking messages only to the player where the missile is targetted at.
|
||||
-- * **To Target**: Shows missile tracking messages only to the player where the missile is targeted at.
|
||||
-- * **Tracking On**: Show missile tracking messages.
|
||||
-- * **Tracking Off**: Disable missile tracking messages.
|
||||
-- * **Frequency Increase**: Increases the missile tracking message frequency with one second.
|
||||
-- * **Frequency Decrease**: Decreases the missile tracking message frequency with one second.
|
||||
-- * **Alerts**: Menu to configure alert messages.
|
||||
-- * **To All**: Shows alert messages to all players.
|
||||
-- * **To Target**: Shows alert messages only to the player where the missile is (was) targetted at.
|
||||
-- * **To Target**: Shows alert messages only to the player where the missile is (was) targeted at.
|
||||
-- * **Hits On**: Show missile hit alert messages.
|
||||
-- * **Hits Off**: Disable missile hit alert messages.
|
||||
-- * **Launches On**: Show missile launch messages.
|
||||
@@ -50,6 +50,13 @@
|
||||
-- * **100 meter**: Destroys the missile when the distance to the aircraft is below or equal to 100 meter.
|
||||
-- * **150 meter**: Destroys the missile when the distance to the aircraft is below or equal to 150 meter.
|
||||
-- * **200 meter**: Destroys the missile when the distance to the aircraft is below or equal to 200 meter.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -67,8 +74,8 @@
|
||||
-- @module Functional.MissileTrainer
|
||||
-- @image Missile_Trainer.JPG
|
||||
|
||||
|
||||
--- @type MISSILETRAINER
|
||||
---
|
||||
-- @type MISSILETRAINER
|
||||
-- @field Core.Set#SET_CLIENT DBClients
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
@@ -88,7 +95,7 @@
|
||||
-- A MISSILETRAINER object will behave differently based on the usage of initialization methods:
|
||||
--
|
||||
-- * @{#MISSILETRAINER.InitMessagesOnOff}: Sets by default the display of any message to be ON or OFF.
|
||||
-- * @{#MISSILETRAINER.InitTrackingToAll}: Sets by default the missile tracking report for all players or only for those missiles targetted to you.
|
||||
-- * @{#MISSILETRAINER.InitTrackingToAll}: Sets by default the missile tracking report for all players or only for those missiles targeted to you.
|
||||
-- * @{#MISSILETRAINER.InitTrackingOnOff}: Sets by default the display of missile tracking report to be ON or OFF.
|
||||
-- * @{#MISSILETRAINER.InitTrackingFrequency}: Increases, decreases the missile tracking message display frequency with the provided time interval in seconds.
|
||||
-- * @{#MISSILETRAINER.InitAlertsToAll}: Sets by default the display of alerts to be shown to all players or only to you.
|
||||
@@ -97,6 +104,11 @@
|
||||
-- * @{#MISSILETRAINER.InitRangeOnOff}: Sets by default the display of range information of missiles ON of OFF.
|
||||
-- * @{#MISSILETRAINER.InitBearingOnOff}: Sets by default the display of bearing information of missiles ON of OFF.
|
||||
-- * @{#MISSILETRAINER.InitMenusOnOff}: Allows to configure the options through the radio menu.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- @field #MISSILETRAINER
|
||||
MISSILETRAINER = {
|
||||
@@ -205,7 +217,7 @@ function MISSILETRAINER:New( Distance, Briefing )
|
||||
|
||||
|
||||
-- self.DB:ForEachClient(
|
||||
-- --- @param Wrapper.Client#CLIENT Client
|
||||
-- -- @param Wrapper.Client#CLIENT Client
|
||||
-- function( Client )
|
||||
--
|
||||
-- ... actions ...
|
||||
@@ -256,7 +268,7 @@ function MISSILETRAINER:InitMessagesOnOff( MessagesOnOff )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets by default the missile tracking report for all players or only for those missiles targetted to you.
|
||||
--- Sets by default the missile tracking report for all players or only for those missiles targeted to you.
|
||||
-- @param #MISSILETRAINER self
|
||||
-- @param #boolean TrackingToAll true or false
|
||||
-- @return #MISSILETRAINER self
|
||||
@@ -555,7 +567,7 @@ function MISSILETRAINER:_AddBearing( Client, TrainerWeapon )
|
||||
|
||||
local DirectionVector = { x = PositionMissile.x - TargetVec3.x, y = PositionMissile.y - TargetVec3.y, z = PositionMissile.z - TargetVec3.z }
|
||||
local DirectionRadians = math.atan2( DirectionVector.z, DirectionVector.x )
|
||||
--DirectionRadians = DirectionRadians + routines.getNorthCorrection( PositionTarget )
|
||||
|
||||
if DirectionRadians < 0 then
|
||||
DirectionRadians = DirectionRadians + 2 * math.pi
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Limit the movement of simulaneous moving ground vehicles.
|
||||
--- **Functional** - Limit the movement of simulaneous moving ground vehicles.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -10,7 +10,8 @@
|
||||
-- @module Functional.Movement
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
--- @type MOVEMENT
|
||||
---
|
||||
-- @type MOVEMENT
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
---
|
||||
@@ -30,23 +31,23 @@ MOVEMENT = {
|
||||
function MOVEMENT:New( MovePrefixes, MoveMaximum )
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #MOVEMENT
|
||||
self:F( { MovePrefixes, MoveMaximum } )
|
||||
|
||||
|
||||
if type( MovePrefixes ) == 'table' then
|
||||
self.MovePrefixes = MovePrefixes
|
||||
else
|
||||
self.MovePrefixes = { MovePrefixes }
|
||||
end
|
||||
self.MoveCount = 0 -- The internal counter of the amount of Moveing the has happened since MoveStart.
|
||||
self.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move...
|
||||
self.AliveUnits = 0 -- Contains the counter how many units are currently alive
|
||||
self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not.
|
||||
|
||||
self.MoveCount = 0 -- The internal counter of the amount of Moving the has happened since MoveStart.
|
||||
self.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move.
|
||||
self.AliveUnits = 0 -- Contains the counter how many units are currently alive.
|
||||
self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not.
|
||||
|
||||
self:HandleEvent( EVENTS.Birth )
|
||||
|
||||
|
||||
-- self:AddEvent( world.event.S_EVENT_BIRTH, self.OnBirth )
|
||||
--
|
||||
-- self:EnableEvents()
|
||||
|
||||
|
||||
self:ScheduleStart()
|
||||
|
||||
return self
|
||||
@@ -55,7 +56,6 @@ end
|
||||
--- Call this function to start the MOVEMENT scheduling.
|
||||
function MOVEMENT:ScheduleStart()
|
||||
self:F()
|
||||
--self.MoveFunction = routines.scheduleFunction( self._Scheduler, { self }, timer.getTime() + 1, 120 )
|
||||
self.MoveFunction = SCHEDULER:New( self, self._Scheduler, {}, 1, 120 )
|
||||
end
|
||||
|
||||
@@ -67,7 +67,7 @@ function MOVEMENT:ScheduleStop()
|
||||
end
|
||||
|
||||
--- Captures the birth events when new Units were spawned.
|
||||
-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration.
|
||||
-- @todo This method should become obsolete. The global _DATABASE object (an instance of @{Core.Database#DATABASE}) will handle the collection administration.
|
||||
-- @param #MOVEMENT self
|
||||
-- @param Core.Event#EVENTDATA self
|
||||
function MOVEMENT:OnEventBirth( EventData )
|
||||
@@ -86,14 +86,14 @@ function MOVEMENT:OnEventBirth( EventData )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
EventData.IniUnit:HandleEvent( EVENTS.DEAD, self.OnDeadOrCrash )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Captures the Dead or Crash events when Units crash or are destroyed.
|
||||
-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration.
|
||||
-- @todo This method should become obsolete. The global _DATABASE object (an instance of @{Core.Database#DATABASE}) will handle the collection administration.
|
||||
function MOVEMENT:OnDeadOrCrash( Event )
|
||||
self:F( { Event } )
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** - Rudimentary ATC.
|
||||
--- **Functional** - Basic ATC.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
@@ -26,9 +26,9 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
|
||||
-- ### Contributions: FlightControl, Applevangelist
|
||||
--
|
||||
-- ====
|
||||
-- @module Functional.PseudoATC
|
||||
@@ -44,7 +44,8 @@
|
||||
-- @field #number mrefresh Interval in seconds after which the F10 menu is refreshed. E.g. by the closest airports. Default is 120 sec.
|
||||
-- @field #number talt Interval in seconds between reporting altitude until touchdown. Default 3 sec.
|
||||
-- @field #boolean chatty Display some messages on events like take-off and touchdown.
|
||||
-- @field #boolean eventsmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler.
|
||||
-- @field #boolean eventsmoose [Deprecated] If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler.
|
||||
-- @field #boolean reportplayername If true, use playername not callsign on callouts
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- Adds some rudimentary ATC functionality via the radio menu.
|
||||
@@ -88,6 +89,7 @@ PSEUDOATC={
|
||||
talt=3,
|
||||
chatty=true,
|
||||
eventsmoose=true,
|
||||
reportplayername = false,
|
||||
}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -98,13 +100,14 @@ PSEUDOATC.id="PseudoATC | "
|
||||
|
||||
--- PSEUDOATC version.
|
||||
-- @field #number version
|
||||
PSEUDOATC.version="0.9.2"
|
||||
PSEUDOATC.version="0.10.5"
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO list
|
||||
-- DONE: Add takeoff event.
|
||||
-- DONE: Add user functions.
|
||||
-- DONE: Refactor to use Moose event handling only
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -129,23 +132,14 @@ function PSEUDOATC:Start()
|
||||
self:F()
|
||||
|
||||
-- Debug info
|
||||
self:E(PSEUDOATC.id.."Starting PseudoATC")
|
||||
self:I(PSEUDOATC.id.."Starting PseudoATC")
|
||||
|
||||
-- Handle events.
|
||||
if self.eventsmoose then
|
||||
self:T(PSEUDOATC.id.."Events are handled by MOOSE.")
|
||||
self:HandleEvent(EVENTS.Birth, self._OnBirth)
|
||||
self:HandleEvent(EVENTS.Land, self._PlayerLanded)
|
||||
self:HandleEvent(EVENTS.Takeoff, self._PlayerTakeOff)
|
||||
self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft)
|
||||
self:HandleEvent(EVENTS.Crash, self._PlayerLeft)
|
||||
--self:HandleEvent(EVENTS.Ejection, self._PlayerLeft)
|
||||
--self:HandleEvent(EVENTS.PilotDead, self._PlayerLeft)
|
||||
else
|
||||
self:T(PSEUDOATC.id.."Events are handled by DCS.")
|
||||
-- Events are handled directly by DCS.
|
||||
world.addEventHandler(self)
|
||||
end
|
||||
self:HandleEvent(EVENTS.Birth, self._OnBirth)
|
||||
self:HandleEvent(EVENTS.Land, self._PlayerLanded)
|
||||
self:HandleEvent(EVENTS.Takeoff, self._PlayerTakeOff)
|
||||
self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft)
|
||||
self:HandleEvent(EVENTS.Crash, self._PlayerLeft)
|
||||
|
||||
end
|
||||
|
||||
@@ -183,6 +177,13 @@ function PSEUDOATC:SetMessageDuration(duration)
|
||||
self.mdur=duration or 30
|
||||
end
|
||||
|
||||
--- Use player name, not call sign, in callouts
|
||||
-- @param #PSEUDOATC self
|
||||
function PSEUDOATC:SetReportPlayername()
|
||||
self.reportplayername = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set time interval after which the F10 radio menu is refreshed.
|
||||
-- @param #PSEUDOATC self
|
||||
-- @param #number interval Interval in seconds. Default is every 120 sec.
|
||||
@@ -190,7 +191,7 @@ function PSEUDOATC:SetMenuRefresh(interval)
|
||||
self.mrefresh=interval or 120
|
||||
end
|
||||
|
||||
--- Enable/disable event handling by MOOSE or DCS.
|
||||
--- [Deprecated] Enable/disable event handling by MOOSE or DCS.
|
||||
-- @param #PSEUDOATC self
|
||||
-- @param #boolean switch If true, events are handled by MOOSE (default). If false, events are handled directly by DCS.
|
||||
function PSEUDOATC:SetEventsMoose(switch)
|
||||
@@ -207,84 +208,6 @@ end
|
||||
-----------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Event Handling
|
||||
|
||||
--- Event handler for suppressed groups.
|
||||
--@param #PSEUDOATC self
|
||||
--@param #table Event Event data table. Holds event.id, event.initiator and event.target etc.
|
||||
function PSEUDOATC:onEvent(Event)
|
||||
if Event == nil or Event.initiator == nil or Unit.getByName(Event.initiator:getName()) == nil then
|
||||
return true
|
||||
end
|
||||
|
||||
local DCSiniunit = Event.initiator
|
||||
local DCSplace = Event.place
|
||||
local DCSsubplace = Event.subplace
|
||||
|
||||
local EventData={}
|
||||
local _playerunit=nil
|
||||
local _playername=nil
|
||||
|
||||
if Event.initiator then
|
||||
EventData.IniUnitName = Event.initiator:getName()
|
||||
EventData.IniDCSGroup = Event.initiator:getGroup()
|
||||
EventData.IniGroupName = Event.initiator:getGroup():getName()
|
||||
-- Get player unit and name. This returns nil,nil if the event was not fired by a player unit. And these are the only events we are interested in.
|
||||
_playerunit, _playername = self:_GetPlayerUnitAndName(EventData.IniUnitName)
|
||||
end
|
||||
|
||||
if Event.place then
|
||||
EventData.Place=Event.place
|
||||
EventData.PlaceName=Event.place:getName()
|
||||
end
|
||||
if Event.subplace then
|
||||
EventData.SubPlace=Event.subplace
|
||||
EventData.SubPlaceName=Event.subplace:getName()
|
||||
end
|
||||
|
||||
-- Event info.
|
||||
self:T3(PSEUDOATC.id..string.format("EVENT: Event in onEvent with ID = %s", tostring(Event.id)))
|
||||
self:T3(PSEUDOATC.id..string.format("EVENT: Ini unit = %s" , tostring(EventData.IniUnitName)))
|
||||
self:T3(PSEUDOATC.id..string.format("EVENT: Ini group = %s" , tostring(EventData.IniGroupName)))
|
||||
self:T3(PSEUDOATC.id..string.format("EVENT: Ini player = %s" , tostring(_playername)))
|
||||
self:T3(PSEUDOATC.id..string.format("EVENT: Place = %s" , tostring(EventData.PlaceName)))
|
||||
self:T3(PSEUDOATC.id..string.format("EVENT: SubPlace = %s" , tostring(EventData.SubPlaceName)))
|
||||
|
||||
-- Event birth.
|
||||
if Event.id == world.event.S_EVENT_BIRTH and _playername then
|
||||
self:_OnBirth(EventData)
|
||||
end
|
||||
|
||||
-- Event takeoff.
|
||||
if Event.id == world.event.S_EVENT_TAKEOFF and _playername and EventData.Place then
|
||||
self:_PlayerTakeOff(EventData)
|
||||
end
|
||||
|
||||
-- Event land.
|
||||
if Event.id == world.event.S_EVENT_LAND and _playername and EventData.Place then
|
||||
self:_PlayerLanded(EventData)
|
||||
end
|
||||
|
||||
-- Event player left unit
|
||||
if Event.id == world.event.S_EVENT_PLAYER_LEAVE_UNIT and _playername then
|
||||
self:_PlayerLeft(EventData)
|
||||
end
|
||||
|
||||
-- Event crash ==> player left unit
|
||||
if Event.id == world.event.S_EVENT_CRASH and _playername then
|
||||
self:_PlayerLeft(EventData)
|
||||
end
|
||||
|
||||
--[[
|
||||
-- Event eject ==> player left unit
|
||||
if Event.id == world.event.S_EVENT_EJECTION and _playername then
|
||||
self:_PlayerLeft(EventData)
|
||||
end
|
||||
|
||||
-- Event pilot dead ==> player left unit
|
||||
if Event.id == world.event.S_EVENT_PILOT_DEAD and _playername then
|
||||
self:_PlayerLeft(EventData)
|
||||
end
|
||||
]]
|
||||
end
|
||||
|
||||
--- Function called my MOOSE event handler when a player enters a unit.
|
||||
-- @param #PSEUDOATC self
|
||||
@@ -294,7 +217,9 @@ function PSEUDOATC:_OnBirth(EventData)
|
||||
|
||||
-- Get unit and player.
|
||||
local _unitName=EventData.IniUnitName
|
||||
local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
|
||||
--local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
|
||||
local _unit = EventData.IniUnit
|
||||
local _playername = EventData.IniPlayerName
|
||||
|
||||
-- Check if a player entered.
|
||||
if _unit and _playername then
|
||||
@@ -311,7 +236,10 @@ function PSEUDOATC:_PlayerLeft(EventData)
|
||||
|
||||
-- Get unit and player.
|
||||
local _unitName=EventData.IniUnitName
|
||||
local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
|
||||
--local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
|
||||
|
||||
local _unit = EventData.IniUnit
|
||||
local _playername = EventData.IniPlayerName
|
||||
|
||||
-- Check if a player left.
|
||||
if _unit and _playername then
|
||||
@@ -326,18 +254,16 @@ function PSEUDOATC:_PlayerLanded(EventData)
|
||||
self:F({EventData=EventData})
|
||||
|
||||
-- Get unit, player and place.
|
||||
local _unitName=EventData.IniUnitName
|
||||
local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
|
||||
local _unitName=EventData.IniUnitName
|
||||
local _unit = EventData.IniUnit
|
||||
local _playername = EventData.IniPlayerName
|
||||
--local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
|
||||
local _base=nil
|
||||
local _baseName=nil
|
||||
if EventData.place then
|
||||
_base=EventData.place
|
||||
_baseName=EventData.place:getName()
|
||||
end
|
||||
-- if EventData.subplace then
|
||||
-- local _subPlace=EventData.subplace
|
||||
-- local _subPlaceName=EventData.subplace:getName()
|
||||
-- end
|
||||
|
||||
-- Call landed function.
|
||||
if _unit and _playername and _base then
|
||||
@@ -352,8 +278,10 @@ function PSEUDOATC:_PlayerTakeOff(EventData)
|
||||
self:F({EventData=EventData})
|
||||
|
||||
-- Get unit, player and place.
|
||||
local _unitName=EventData.IniUnitName
|
||||
local _unit,_playername=self:_GetPlayerUnitAndName(_unitName)
|
||||
local _unitName=EventData.IniUnitName
|
||||
local _unit = EventData.IniUnit
|
||||
local _playername = EventData.IniPlayerName
|
||||
--local _unit,_playername=self:_GetPlayerUnitAndName(_unitName)
|
||||
local _base=nil
|
||||
local _baseName=nil
|
||||
if EventData.place then
|
||||
@@ -441,14 +369,15 @@ function PSEUDOATC:PlayerLanded(unit, place)
|
||||
local group=unit:GetGroup()
|
||||
local GID=group:GetID()
|
||||
local UID=unit:GetDCSObject():getID()
|
||||
local PlayerName=self.group[GID].player[UID].playername
|
||||
local UnitName=self.group[GID].player[UID].unitname
|
||||
local GroupName=self.group[GID].player[UID].groupname
|
||||
|
||||
-- Debug message.
|
||||
local text=string.format("Player %s in unit %s of group %s (id=%d) landed at %s.", PlayerName, UnitName, GroupName, GID, place)
|
||||
self:T(PSEUDOATC.id..text)
|
||||
MESSAGE:New(text, 30):ToAllIf(self.Debug)
|
||||
local PlayerName = unit:GetPlayerName() or "Ghost"
|
||||
local UnitName = unit:GetName() or "Ghostplane"
|
||||
local GroupName = group:GetName() or "Ghostgroup"
|
||||
if self.Debug then
|
||||
-- Debug message.
|
||||
local text=string.format("Player %s in unit %s of group %s landed at %s.", PlayerName, UnitName, GroupName, place)
|
||||
self:T(PSEUDOATC.id..text)
|
||||
MESSAGE:New(text, 30):ToAllIf(self.Debug)
|
||||
end
|
||||
|
||||
-- Stop altitude reporting timer if its activated.
|
||||
self:AltitudeTimerStop(GID,UID)
|
||||
@@ -470,21 +399,22 @@ function PSEUDOATC:PlayerTakeOff(unit, place)
|
||||
|
||||
-- Gather some information.
|
||||
local group=unit:GetGroup()
|
||||
local GID=group:GetID()
|
||||
local UID=unit:GetDCSObject():getID()
|
||||
local PlayerName=self.group[GID].player[UID].playername
|
||||
local CallSign=self.group[GID].player[UID].callsign
|
||||
local UnitName=self.group[GID].player[UID].unitname
|
||||
local GroupName=self.group[GID].player[UID].groupname
|
||||
|
||||
-- Debug message.
|
||||
local text=string.format("Player %s in unit %s of group %s (id=%d) took off at %s.", PlayerName, UnitName, GroupName, GID, place)
|
||||
self:T(PSEUDOATC.id..text)
|
||||
MESSAGE:New(text, 30):ToAllIf(self.Debug)
|
||||
|
||||
local PlayerName = unit:GetPlayerName() or "Ghost"
|
||||
local UnitName = unit:GetName() or "Ghostplane"
|
||||
local GroupName = group:GetName() or "Ghostgroup"
|
||||
local CallSign = unit:GetCallsign() or "Ghost11"
|
||||
if self.Debug then
|
||||
-- Debug message.
|
||||
local text=string.format("Player %s in unit %s of group %s took off at %s.", PlayerName, UnitName, GroupName, place)
|
||||
self:T(PSEUDOATC.id..text)
|
||||
MESSAGE:New(text, 30):ToAllIf(self.Debug)
|
||||
end
|
||||
-- Bye-Bye message.
|
||||
if place and self.chatty then
|
||||
local text=string.format("%s, %s, you are airborne. Have a safe trip!", place, CallSign)
|
||||
if self.reportplayername then
|
||||
text=string.format("%s, %s, you are airborne. Have a safe trip!", place, PlayerName)
|
||||
end
|
||||
MESSAGE:New(text, self.mdur):ToGroup(group)
|
||||
end
|
||||
|
||||
@@ -501,7 +431,7 @@ function PSEUDOATC:PlayerLeft(unit)
|
||||
local GID=group:GetID()
|
||||
local UID=unit:GetDCSObject():getID()
|
||||
|
||||
if self.group[GID].player[UID] then
|
||||
if self.group[GID] and self.group[GID].player and self.group[GID].player[UID] then
|
||||
local PlayerName=self.group[GID].player[UID].playername
|
||||
local CallSign=self.group[GID].player[UID].callsign
|
||||
local UnitName=self.group[GID].player[UID].unitname
|
||||
@@ -687,7 +617,9 @@ function PSEUDOATC:MenuWaypoints(GID, UID)
|
||||
-- Position of Waypoint
|
||||
local pos=COORDINATE:New(wp.x, wp.alt, wp.y)
|
||||
local name=string.format("Waypoint %d", i-1)
|
||||
|
||||
if wp.name and wp.name ~= "" then
|
||||
name = string.format("Waypoint %s",wp.name)
|
||||
end
|
||||
-- "F10/PseudoATC/Waypoints/Waypoint X"
|
||||
local submenu=missionCommands.addSubMenuForGroup(GID, name, self.group[GID].player[UID].menu_waypoints)
|
||||
|
||||
@@ -844,7 +776,8 @@ function PSEUDOATC:ReportHeight(GID, UID, dt, _clear)
|
||||
local position=unit:GetCoordinate()
|
||||
local height=get_AGL(position)
|
||||
local callsign=unit:GetCallsign()
|
||||
|
||||
local PlayerName=self.group[GID].player[UID].playername
|
||||
|
||||
-- Settings.
|
||||
local settings=_DATABASE:GetPlayerSettings(self.group[GID].player[UID].playername) or _SETTINGS --Core.Settings#SETTINGS
|
||||
|
||||
@@ -856,7 +789,9 @@ function PSEUDOATC:ReportHeight(GID, UID, dt, _clear)
|
||||
|
||||
-- Message text.
|
||||
local _text=string.format("%s, your altitude is %s AGL.", callsign, Hs)
|
||||
|
||||
if self.reportplayername then
|
||||
_text=string.format("%s, your altitude is %s AGL.", PlayerName, Hs)
|
||||
end
|
||||
-- Append flight level.
|
||||
if _clear==false then
|
||||
_text=_text..string.format(" FL%03d.", position.y/30.48)
|
||||
@@ -901,7 +836,7 @@ function PSEUDOATC:AltitudeTimeStart(GID, UID)
|
||||
self:T(PSEUDOATC.id..string.format("Starting altitude report timer for player ID %d.", UID))
|
||||
|
||||
-- Start timer. Altitude is reported every ~3 seconds.
|
||||
self.group[GID].player[UID].altimer, self.group[GID].player[UID].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, GID, UID, 0.1, true}, 1, 3)
|
||||
self.group[GID].player[UID].altimer, self.group[GID].player[UID].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, GID, UID, 1, true}, 1, 3)
|
||||
end
|
||||
|
||||
--- Stop/destroy DCS scheduler function for reporting altitude.
|
||||
|
||||
@@ -33,25 +33,20 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Missions:
|
||||
-- ## Additional Material:
|
||||
--
|
||||
-- ### [RAT - Random Air Traffic](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/RAT%20-%20Random%20Air%20Traffic)
|
||||
-- * **Demo Missions:** [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Functional/RAT)
|
||||
-- * **YouTube videos:** [Random Air Traffic](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0u4Zxywtg-mx_ov4vi68CO)
|
||||
-- * **Guides:** None
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # YouTube Channel
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ### [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg)
|
||||
-- ### [MOOSE - RAT - Random Air Traffic](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0u4Zxywtg-mx_ov4vi68CO)
|
||||
-- ### Contributions: FlightControl
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
||||
--
|
||||
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
|
||||
--
|
||||
-- ===
|
||||
-- @module Functional.Rat
|
||||
-- @module Functional.RAT
|
||||
-- @image RAT.JPG
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -170,7 +165,7 @@
|
||||
--
|
||||
-- * A specific departure and/or destination airport can be chosen.
|
||||
-- * Valid coalitions can be set, e.g. only red, blue or neutral, all three "colours".
|
||||
-- * It is possible to start in air within a zone defined in the mission editor or within a zone above an airport of the map.
|
||||
-- * It is possible to start in air within a zone or within a zone above an airport of the map.
|
||||
--
|
||||
-- ## Flight Plan
|
||||
--
|
||||
@@ -225,7 +220,7 @@
|
||||
--
|
||||
-- * Landing: When an aircraft tries to land at an airport where it does not have a valid parking spot, it is immidiately despawned the moment its wheels touch the runway, i.e.
|
||||
-- when a landing event is triggered. This leads to the loss of the RAT aircraft. On possible way to circumvent the this problem is to let another RAT aircraft spawn at landing
|
||||
-- and not when it shuts down its engines. See the @{RAT.RespawnAfterLanding}() function.
|
||||
-- and not when it shuts down its engines. See the @{#RAT.RespawnAfterLanding}() function.
|
||||
-- * Spawning: When a big aircraft is dynamically spawned on a small airbase a few things can go wrong. For example, it could be spawned at a parking spot with a shelter.
|
||||
-- Or it could be damaged by a scenery object when it is taxiing out to the runway, or it could overlap with other aircraft on parking spots near by.
|
||||
--
|
||||
@@ -1179,13 +1174,13 @@ function RAT:SetTakeoffAir()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set possible departure ports. This can be an airport or a zone defined in the mission editor.
|
||||
--- Set possible departure ports. This can be an airport or a zone.
|
||||
-- @param #RAT self
|
||||
-- @param #string departurenames Name or table of names of departure airports or zones.
|
||||
-- @return #RAT RAT self object.
|
||||
-- @usage RAT:SetDeparture("Sochi-Adler") will spawn RAT objects at Sochi-Adler airport.
|
||||
-- @usage RAT:SetDeparture({"Sochi-Adler", "Gudauta"}) will spawn RAT aircraft radomly at Sochi-Adler or Gudauta airport.
|
||||
-- @usage RAT:SetDeparture({"Zone A", "Gudauta"}) will spawn RAT aircraft in air randomly within Zone A, which has to be defined in the mission editor, or within a zone around Gudauta airport. Note that this also requires RAT:takeoff("air") to be set.
|
||||
-- @usage RAT:SetDeparture({"Zone A", "Gudauta"}) will spawn RAT aircraft in air randomly within Zone A, or within a zone around Gudauta airport. Note that this also requires RAT:takeoff("air") to be set.
|
||||
function RAT:SetDeparture(departurenames)
|
||||
self:F2(departurenames)
|
||||
|
||||
@@ -2057,6 +2052,10 @@ function RAT:_InitAircraft(DCSgroup)
|
||||
self.aircraft.length=16
|
||||
self.aircraft.height=5
|
||||
self.aircraft.width=9
|
||||
elseif DCStype == "Saab340" then -- <- These lines added
|
||||
self.aircraft.length=19.73 -- <- These lines added
|
||||
self.aircraft.height=6.97 -- <- These lines added
|
||||
self.aircraft.width=21.44 -- <- These lines added
|
||||
end
|
||||
self.aircraft.box=math.max(self.aircraft.length,self.aircraft.width)
|
||||
|
||||
@@ -2474,11 +2473,11 @@ end
|
||||
-- @param #RAT self
|
||||
-- @param #number takeoff Takeoff type. Could also be air start.
|
||||
-- @param #number landing Landing type. Could also be a destination in air.
|
||||
-- @param Wrapper.Airport#AIRBASE _departure (Optional) Departure airbase.
|
||||
-- @param Wrapper.Airport#AIRBASE _destination (Optional) Destination airbase.
|
||||
-- @param Wrapper.Airbase#AIRBASE _departure (Optional) Departure airbase.
|
||||
-- @param Wrapper.Airbase#AIRBASE _destination (Optional) Destination airbase.
|
||||
-- @param #table _waypoint Initial waypoint.
|
||||
-- @return Wrapper.Airport#AIRBASE Departure airbase.
|
||||
-- @return Wrapper.Airport#AIRBASE Destination airbase.
|
||||
-- @return Wrapper.Airbase#AIRBASE Departure airbase.
|
||||
-- @return Wrapper.Airbase#AIRBASE Destination airbase.
|
||||
-- @return #table Table of flight plan waypoints.
|
||||
-- @return #nil If no valid departure or destination airport could be found.
|
||||
function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint)
|
||||
@@ -2537,7 +2536,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint)
|
||||
end
|
||||
elseif self:_ZoneExists(_departure) then
|
||||
-- If it's not an airport, check whether it's a zone.
|
||||
departure=ZONE:New(_departure)
|
||||
departure=ZONE:FindByName(_departure)
|
||||
else
|
||||
local text=string.format("ERROR! Specified departure airport %s does not exist for %s.", _departure, self.alias)
|
||||
self:E(RAT.id..text)
|
||||
@@ -2635,7 +2634,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint)
|
||||
end
|
||||
|
||||
elseif self:_ZoneExists(_destination) then
|
||||
destination=ZONE:New(_destination)
|
||||
destination=ZONE:FindByName(_destination)
|
||||
else
|
||||
local text=string.format("ERROR: Specified destination airport/zone %s does not exist for %s!", _destination, self.alias)
|
||||
self:E(RAT.id.."ERROR: "..text)
|
||||
@@ -3142,7 +3141,7 @@ function RAT:_PickDeparture(takeoff)
|
||||
end
|
||||
elseif self:_ZoneExists(name) then
|
||||
if takeoff==RAT.wp.air then
|
||||
dep=ZONE:New(name)
|
||||
dep=ZONE:FindByName(name)
|
||||
else
|
||||
self:E(RAT.id..string.format("ERROR! Takeoff is not in air. Cannot use %s as departure.", name))
|
||||
end
|
||||
@@ -3254,7 +3253,7 @@ function RAT:_PickDestination(departure, q, minrange, maxrange, random, landing)
|
||||
end
|
||||
elseif self:_ZoneExists(name) then
|
||||
if landing==RAT.wp.air then
|
||||
dest=ZONE:New(name)
|
||||
dest=ZONE:FindByName(name)
|
||||
else
|
||||
self:E(RAT.id..string.format("ERROR! Landing is not in air. Cannot use zone %s as destination!", name))
|
||||
end
|
||||
@@ -3483,7 +3482,7 @@ function RAT:Status(message, forID)
|
||||
-- Get group.
|
||||
local group=ratcraft.group --Wrapper.Group#GROUP
|
||||
|
||||
if group and group:IsAlive() then
|
||||
if group and group:IsAlive() and (group:GetCoordinate() or group:GetVec3()) then
|
||||
nalive=nalive+1
|
||||
|
||||
-- Gather some information.
|
||||
@@ -3491,8 +3490,11 @@ function RAT:Status(message, forID)
|
||||
local life=self:_GetLife(group)
|
||||
local fuel=group:GetFuel()*100.0
|
||||
local airborne=group:InAir()
|
||||
local coords=group:GetCoordinate()
|
||||
local alt=coords.y
|
||||
local coords=group:GetCoordinate() or group:GetVec3()
|
||||
local alt=1000
|
||||
if coords then
|
||||
alt=coords.y or 1000
|
||||
end
|
||||
--local vel=group:GetVelocityKMH()
|
||||
local departure=ratcraft.departure:GetName()
|
||||
local destination=ratcraft.destination:GetName()
|
||||
@@ -4602,7 +4604,7 @@ function RAT:_TaskHolding(P1, Altitude, Speed, Duration)
|
||||
end
|
||||
|
||||
--- Function which is called after passing every waypoint. Info on waypoint is given and special functions are executed.
|
||||
-- @param Core.Group#GROUP group Group of aircraft.
|
||||
-- @param Wrapper.Group#GROUP group Group of aircraft.
|
||||
-- @param #RAT rat RAT object.
|
||||
-- @param #number wp Waypoint index. Running number of the waypoints. Determines the actions to be executed.
|
||||
function RAT._WaypointFunction(group, rat, wp)
|
||||
@@ -4927,12 +4929,12 @@ function RAT:_AirportExists(name)
|
||||
return false
|
||||
end
|
||||
|
||||
--- Test if a trigger zone defined in the mission editor exists.
|
||||
--- Test if a zone exists.
|
||||
-- @param #RAT self
|
||||
-- @param #string name
|
||||
-- @return #boolean True if zone exsits, false otherwise.
|
||||
function RAT:_ZoneExists(name)
|
||||
local z=trigger.misc.getZone(name)
|
||||
local z=ZONE:FindByName(name) --trigger.misc.getZone(name) as suggested by @Viking on MOOSE discord #rat
|
||||
if z then
|
||||
return true
|
||||
end
|
||||
@@ -5443,7 +5445,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take
|
||||
SpawnTemplate.units[UnitID]["onboard_num"] = string.format("%s%d%02d", self.onboardnum, (self.SpawnIndex-1)%10, (self.onboardnum0-1)+UnitID)
|
||||
end
|
||||
|
||||
-- Modify coaltion and country of template.
|
||||
-- Modify coalition and country of template.
|
||||
SpawnTemplate.CoalitionID=self.coalition
|
||||
if self.country then
|
||||
SpawnTemplate.CountryID=self.country
|
||||
@@ -5490,7 +5492,7 @@ function RAT:_ATCInit(airports_map)
|
||||
if not RAT.ATC.init then
|
||||
local text
|
||||
text="Starting RAT ATC.\nSimultanious = "..RAT.ATC.Nclearance.."\n".."Delay = "..RAT.ATC.delay
|
||||
BASE:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
RAT.ATC.init=true
|
||||
for _,ap in pairs(airports_map) do
|
||||
local name=ap:GetName()
|
||||
@@ -5671,6 +5673,9 @@ function RAT:_ATCClearForLanding(airport, flight)
|
||||
|
||||
-- Debug message.
|
||||
local text1=string.format("ATC %s: Flight %s cleared for landing (flag=%d).", airport, flight, flagvalue)
|
||||
if string.find(flight,"#") then
|
||||
flight = string.match(flight,"^(.+)#")
|
||||
end
|
||||
local text2=string.format("ATC %s: Flight %s you are cleared for landing.", airport, flight)
|
||||
BASE:T( RAT.id..text1)
|
||||
MESSAGE:New(text2, 10):ToAllIf(RAT.ATC.messages)
|
||||
@@ -5713,6 +5718,9 @@ function RAT:_ATCFlightLanded(name)
|
||||
local text1=string.format("ATC %s: Flight %s landed. Tholding = %i:%02d, Tfinal = %i:%02d.", dest, name, Thold/60, Thold%60, Tfinal/60, Tfinal%60)
|
||||
local text2=string.format("ATC %s: Number of flights still on final %d.", dest, RAT.ATC.airport[dest].Nonfinal)
|
||||
local text3=string.format("ATC %s: Traffic report: Number of planes landed in total %d. Flights/hour = %3.2f.", dest, RAT.ATC.airport[dest].traffic, TrafficPerHour)
|
||||
if string.find(name,"#") then
|
||||
name = string.match(name,"^(.+)#")
|
||||
end
|
||||
local text4=string.format("ATC %s: Flight %s landed. Welcome to %s.", dest, name, dest)
|
||||
BASE:T(RAT.id..text1)
|
||||
BASE:T(RAT.id..text2)
|
||||
@@ -5826,6 +5834,7 @@ RATMANAGER={
|
||||
rat={},
|
||||
name={},
|
||||
alive={},
|
||||
planned={},
|
||||
min={},
|
||||
nrat=0,
|
||||
ntot=nil,
|
||||
@@ -5874,6 +5883,7 @@ function RATMANAGER:Add(ratobject,min)
|
||||
|
||||
self.rat[self.nrat]=ratobject
|
||||
self.alive[self.nrat]=0
|
||||
self.planned[self.nrat]=0
|
||||
self.name[self.nrat]=ratobject.alias
|
||||
self.min[self.nrat]=min or 1
|
||||
|
||||
@@ -6014,11 +6024,25 @@ function RATMANAGER:_Manage()
|
||||
for i=1,self.nrat do
|
||||
for j=1,N[i] do
|
||||
time=time+self.dTspawn
|
||||
SCHEDULER:New(nil, RAT._SpawnWithRoute, {self.rat[i]}, time)
|
||||
self.planned[i]=self.planned[i]+1
|
||||
SCHEDULER:New(nil, RATMANAGER._Spawn, {self, i}, time)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Instantly starts the RAT manager and spawns the initial random number RAT groups for each RAT object.
|
||||
-- @param #RATMANAGER self
|
||||
-- @param #RATMANAGER RATMANAGER self object.
|
||||
-- @param #number i Index.
|
||||
function RATMANAGER:_Spawn(i)
|
||||
|
||||
local rat=self.rat[i] --#RAT
|
||||
|
||||
rat:_SpawnWithRoute()
|
||||
self.planned[i]=self.planned[i]-1
|
||||
|
||||
end
|
||||
|
||||
--- Counts the number of alive RAT objects.
|
||||
-- @param #RATMANAGER self
|
||||
function RATMANAGER:_Count()
|
||||
@@ -6047,7 +6071,7 @@ function RATMANAGER:_Count()
|
||||
ntotal=ntotal+n
|
||||
|
||||
-- Debug output.
|
||||
local text=string.format("Number of alive groups of %s = %d", self.name[i], n)
|
||||
local text=string.format("Number of alive groups of %s = %d, planned=%d", self.name[i], n, self.planned[i])
|
||||
self:T(RATMANAGER.id..text)
|
||||
end
|
||||
|
||||
@@ -6077,9 +6101,10 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
|
||||
local M={}
|
||||
local P={}
|
||||
for i=1,nrat do
|
||||
local a=alive[i]+self.planned[i]
|
||||
N[#N+1]=0
|
||||
M[#M+1]=math.max(alive[i], min[i])
|
||||
P[#P+1]=math.max(min[i]-alive[i],0)
|
||||
M[#M+1]=math.max(a, min[i])
|
||||
P[#P+1]=math.max(min[i]-a,0)
|
||||
end
|
||||
|
||||
-- Min/max group arrays.
|
||||
@@ -6096,7 +6121,7 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
|
||||
-- Number of new groups to be added.
|
||||
local nnew=ntot
|
||||
for i=1,nrat do
|
||||
nnew=nnew-alive[i]
|
||||
nnew=nnew-alive[i]-self.planned[i]
|
||||
end
|
||||
|
||||
for i=1,nrat-1 do
|
||||
@@ -6128,7 +6153,7 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
|
||||
end
|
||||
|
||||
-- Debug info
|
||||
self:T3(string.format("RATMANAGER: i=%d, alive=%d, min=%d, mini=%d, maxi=%d, add=%d, sumN=%d, sumP=%d", j, alive[j], min[j], mini[j], maxi[j], N[j],sN, sP))
|
||||
self:T3(string.format("RATMANAGER: i=%d, alive=%d, planned=%d, min=%d, mini=%d, maxi=%d, add=%d, sumN=%d, sumP=%d", j, alive[j], self.planned[i], min[j], mini[j], maxi[j], N[j],sN, sP))
|
||||
|
||||
end
|
||||
|
||||
@@ -6143,7 +6168,7 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
|
||||
-- Debug info
|
||||
local text=RATMANAGER.id.."\n"
|
||||
for i=1,nrat do
|
||||
text=text..string.format("%s: i=%d, alive=%d, min=%d, mini=%d, maxi=%d, add=%d\n", self.name[i], i, alive[i], min[i], mini[i], maxi[i], N[i])
|
||||
text=text..string.format("%s: i=%d, alive=%d, planned=%d, min=%d, mini=%d, maxi=%d, add=%d\n", self.name[i], i, alive[i], self.planned[i], min[i], mini[i], maxi[i], N[i])
|
||||
end
|
||||
text=text..string.format("Total # of groups to add = %d", sum(N, done))
|
||||
self:T(text)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
--- **Functional** - Administer the scoring of player achievements, and create a CSV file logging the scoring events for use at team or squadron websites.
|
||||
--- **Functional** - Administer the scoring of player achievements, file and log the scoring events for use at websites.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -12,14 +12,14 @@
|
||||
-- * Score the hits and destroys of units.
|
||||
-- * Score the hits and destroys of statics.
|
||||
-- * Score the hits and destroys of scenery.
|
||||
-- * Log scores into a CSV file.
|
||||
-- * (optional) Log scores into a CSV file.
|
||||
-- * Connect to a remote server using JSON and IP.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [SCO - Scoring](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCO%20-%20Scoring)
|
||||
-- [SCO - Scoring](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Functional/Scoring)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -27,7 +27,7 @@
|
||||
-- and creates a CSV file logging the scoring events and results for use at team or squadron websites.
|
||||
--
|
||||
-- SCORING automatically calculates the threat level of the objects hit and destroyed by players,
|
||||
-- which can be @{Wrapper.Unit}, @{Static) and @{Scenery} objects.
|
||||
-- which can be @{Wrapper.Unit}, @{Wrapper.Static) and @{Scenery} objects.
|
||||
--
|
||||
-- Positive score points are granted when enemy or neutral targets are destroyed.
|
||||
-- Negative score points or penalties are given when a friendly target is hit or destroyed.
|
||||
@@ -59,7 +59,7 @@
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Various @{Zone}s can be defined for which scores are also granted when objects in that @{Zone} are destroyed.
|
||||
-- Various @{Core.Zone}s can be defined for which scores are also granted when objects in that @{Core.Zone} are destroyed.
|
||||
-- This is **specifically useful** to designate **scenery targets on the map** that will generate points when destroyed.
|
||||
--
|
||||
-- With a small change in MissionScripting.lua, the scoring results can also be logged in a **CSV file**.
|
||||
@@ -78,10 +78,11 @@
|
||||
-- ### Authors: **FlightControl**
|
||||
--
|
||||
-- ### Contributions:
|
||||
--
|
||||
--
|
||||
-- * **Applevangelist**: Additional functionality, fixes.
|
||||
-- * **Wingthor (TAW)**: Testing & Advice.
|
||||
-- * **Dutch-Baron (TAW)**: Testing & Advice.
|
||||
-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing and Advice.
|
||||
-- * **Whisper**: Testing and Advice.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -115,12 +116,14 @@
|
||||
--
|
||||
-- Special targets can be set that will give extra scores to the players when these are destroyed.
|
||||
-- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Wrapper.Unit}s.
|
||||
-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Static}s.
|
||||
-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Wrapper.Group}s.
|
||||
-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Wrapper.Static}s.
|
||||
-- Use the method @{#SCORING.AddScoreSetGroup}() to specify a special additional score for a specific @{Wrapper.Group}s gathered in a @{Core.Set#SET_GROUP}.
|
||||
--
|
||||
-- local Scoring = SCORING:New( "Scoring File" )
|
||||
-- Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 )
|
||||
-- Scoring:AddStaticScore( STATIC:FindByName( "Static #1" ), 100 )
|
||||
-- local GroupSet = SET_GROUP:New():FilterPrefixes("RAT"):FilterStart()
|
||||
-- Scoring:AddScoreSetGroup( GroupSet, 100)
|
||||
--
|
||||
-- The above grants an additional score of 200 points for Unit #001 and an additional 100 points of Static #1 if these are destroyed.
|
||||
-- Note that later in the mission, one can remove these scores set, for example, when the a goal achievement time limit is over.
|
||||
@@ -131,11 +134,11 @@
|
||||
-- # Define destruction zones that will give extra scores:
|
||||
--
|
||||
-- Define zones of destruction. Any object destroyed within the zone of the given category will give extra points.
|
||||
-- Use the method @{#SCORING.AddZoneScore}() to add a @{Zone} for additional scoring.
|
||||
-- Use the method @{#SCORING.RemoveZoneScore}() to remove a @{Zone} for additional scoring.
|
||||
-- There are interesting variations that can be achieved with this functionality. For example, if the @{Zone} is a @{Core.Zone#ZONE_UNIT},
|
||||
-- then the zone is a moving zone, and anything destroyed within that @{Zone} will generate points.
|
||||
-- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Zone},
|
||||
-- Use the method @{#SCORING.AddZoneScore}() to add a @{Core.Zone} for additional scoring.
|
||||
-- Use the method @{#SCORING.RemoveZoneScore}() to remove a @{Core.Zone} for additional scoring.
|
||||
-- There are interesting variations that can be achieved with this functionality. For example, if the @{Core.Zone} is a @{Core.Zone#ZONE_UNIT},
|
||||
-- then the zone is a moving zone, and anything destroyed within that @{Core.Zone} will generate points.
|
||||
-- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Core.Zone},
|
||||
-- just large enough around that building.
|
||||
--
|
||||
-- # Add extra Goal scores upon an event or a condition:
|
||||
@@ -225,6 +228,8 @@ SCORING = {
|
||||
ClassName = "SCORING",
|
||||
ClassID = 0,
|
||||
Players = {},
|
||||
AutoSave = true,
|
||||
version = "1.18.4"
|
||||
}
|
||||
|
||||
local _SCORINGCoalition = {
|
||||
@@ -243,13 +248,15 @@ local _SCORINGCategory = {
|
||||
--- Creates a new SCORING object to administer the scoring achieved by players.
|
||||
-- @param #SCORING self
|
||||
-- @param #string GameName The name of the game. This name is also logged in the CSV score file.
|
||||
-- @param #string SavePath (Optional) Path where to save the CSV file, defaults to your **<User>\\Saved Games\\DCS\\Logs** folder.
|
||||
-- @param #boolean AutoSave (Optional) If passed as `false`, then swith autosave off.
|
||||
-- @return #SCORING self
|
||||
-- @usage
|
||||
--
|
||||
-- -- Define a new scoring object for the mission Gori Valley.
|
||||
-- ScoringObject = SCORING:New( "Gori Valley" )
|
||||
--
|
||||
function SCORING:New( GameName )
|
||||
function SCORING:New( GameName, SavePath, AutoSave )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #SCORING
|
||||
@@ -274,9 +281,15 @@ function SCORING:New( GameName )
|
||||
self:SetMessagesZone( true )
|
||||
|
||||
-- Scales
|
||||
|
||||
self:SetScaleDestroyScore( 10 )
|
||||
self:SetScaleDestroyPenalty( 30 )
|
||||
|
||||
-- Hitting a target multiple times before destoying it should not result in a higger score
|
||||
-- Multiple hits is typically a results of bombs/missles missing their target but still inflict some spash damage
|
||||
-- Making this configurable to anyone can enable this anyway if they want
|
||||
self:SetScoreIncrementOnHit(0)
|
||||
|
||||
-- Default fratricide penalty level (maximum penalty that can be assigned to a player before he gets kicked).
|
||||
self:SetFratricide( self.ScaleDestroyPenalty * 3 )
|
||||
self.penaltyonfratricide = true
|
||||
@@ -306,6 +319,8 @@ function SCORING:New( GameName )
|
||||
end )
|
||||
|
||||
-- Create the CSV file.
|
||||
self.AutoSavePath = SavePath
|
||||
self.AutoSave = AutoSave or true
|
||||
self:OpenCSV( GameName )
|
||||
|
||||
return self
|
||||
@@ -373,11 +388,11 @@ function SCORING:RemoveUnitScore( ScoreUnit )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a @{Static} for additional scoring when the @{Static} is destroyed.
|
||||
-- Note that if there was already a @{Static} declared within the scoring with the same name,
|
||||
-- then the old @{Static} will be replaced with the new @{Static}.
|
||||
--- Add a @{Wrapper.Static} for additional scoring when the @{Wrapper.Static} is destroyed.
|
||||
-- Note that if there was already a @{Wrapper.Static} declared within the scoring with the same name,
|
||||
-- then the old @{Wrapper.Static} will be replaced with the new @{Wrapper.Static}.
|
||||
-- @param #SCORING self
|
||||
-- @param Wrapper.Static#UNIT ScoreStatic The @{Static} for which the Score needs to be given.
|
||||
-- @param Wrapper.Static#UNIT ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
|
||||
-- @param #number Score The Score value.
|
||||
-- @return #SCORING
|
||||
function SCORING:AddStaticScore( ScoreStatic, Score )
|
||||
@@ -389,9 +404,9 @@ function SCORING:AddStaticScore( ScoreStatic, Score )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Removes a @{Static} for additional scoring when the @{Static} is destroyed.
|
||||
--- Removes a @{Wrapper.Static} for additional scoring when the @{Wrapper.Static} is destroyed.
|
||||
-- @param #SCORING self
|
||||
-- @param Wrapper.Static#UNIT ScoreStatic The @{Static} for which the Score needs to be given.
|
||||
-- @param Wrapper.Static#UNIT ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
|
||||
-- @return #SCORING
|
||||
function SCORING:RemoveStaticScore( ScoreStatic )
|
||||
|
||||
@@ -419,11 +434,36 @@ function SCORING:AddScoreGroup( ScoreGroup, Score )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a @{Zone} to define additional scoring when any object is destroyed in that zone.
|
||||
-- Note that if a @{Zone} with the same name is already within the scoring added, the @{Zone} (type) and Score will be replaced!
|
||||
--- Specify a special additional score for a @{Core.Set#SET_GROUP}.
|
||||
-- @param #SCORING self
|
||||
-- @param Core.Set#SET_GROUP Set The @{Core.Set#SET_GROUP} for which each @{Wrapper.Unit} in each Group a Score is given.
|
||||
-- @param #number Score The Score value.
|
||||
-- @return #SCORING
|
||||
function SCORING:AddScoreSetGroup(Set, Score)
|
||||
local set = Set:GetSetObjects()
|
||||
|
||||
for _,_group in pairs (set) do
|
||||
if _group and _group:IsAlive() then
|
||||
self:AddScoreGroup(_group,Score)
|
||||
end
|
||||
end
|
||||
|
||||
local function AddScore(group)
|
||||
self:AddScoreGroup(group,Score)
|
||||
end
|
||||
|
||||
function Set:OnAfterAdded(From,Event,To,ObjectName,Object)
|
||||
AddScore(Object)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a @{Core.Zone} to define additional scoring when any object is destroyed in that zone.
|
||||
-- Note that if a @{Core.Zone} with the same name is already within the scoring added, the @{Core.Zone} (type) and Score will be replaced!
|
||||
-- This allows for a dynamic destruction zone evolution within your mission.
|
||||
-- @param #SCORING self
|
||||
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters.
|
||||
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Core.Zone} which defines the destruction score perimeters.
|
||||
-- Note that a zone can be a polygon or a moving zone.
|
||||
-- @param #number Score The Score value.
|
||||
-- @return #SCORING
|
||||
@@ -438,11 +478,11 @@ function SCORING:AddZoneScore( ScoreZone, Score )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove a @{Zone} for additional scoring.
|
||||
-- The scoring will search if any @{Zone} is added with the given name, and will remove that zone from the scoring.
|
||||
--- Remove a @{Core.Zone} for additional scoring.
|
||||
-- The scoring will search if any @{Core.Zone} is added with the given name, and will remove that zone from the scoring.
|
||||
-- This allows for a dynamic destruction zone evolution within your mission.
|
||||
-- @param #SCORING self
|
||||
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters.
|
||||
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Core.Zone} which defines the destruction score perimeters.
|
||||
-- Note that a zone can be a polygon or a moving zone.
|
||||
-- @return #SCORING
|
||||
function SCORING:RemoveZoneScore( ScoreZone )
|
||||
@@ -464,6 +504,16 @@ function SCORING:SetMessagesHit( OnOff )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Configure to increment score after a target has been hit.
|
||||
-- @param #SCORING self
|
||||
-- @param #number score amount of point to inclement score on each hit
|
||||
-- @return #SCORING
|
||||
function SCORING:SetScoreIncrementOnHit( score )
|
||||
|
||||
self.ScoreIncrementOnHit = score
|
||||
return self
|
||||
end
|
||||
|
||||
--- If to send messages after a target has been hit.
|
||||
-- @param #SCORING self
|
||||
-- @return #boolean
|
||||
@@ -657,7 +707,7 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
||||
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + self.CoalitionChangePenalty or 50
|
||||
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] ..
|
||||
"(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). ".. self.CoalitionChangePenalty .."Penalty points added.",
|
||||
"(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). ".. self.CoalitionChangePenalty .." penalty points added.",
|
||||
MESSAGE.Type.Information
|
||||
):ToAll()
|
||||
self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -1*self.CoalitionChangePenalty, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType,
|
||||
@@ -713,11 +763,11 @@ function SCORING:AddGoalScorePlayer( PlayerName, GoalTag, Text, Score )
|
||||
PlayerData.Goals[GoalTag] = PlayerData.Goals[GoalTag] or { Score = 0 }
|
||||
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
|
||||
PlayerData.Score = PlayerData.Score + Score
|
||||
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
|
||||
MESSAGE.Type.Information )
|
||||
:ToAll()
|
||||
|
||||
if Text then
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
|
||||
MESSAGE.Type.Information )
|
||||
:ToAll()
|
||||
end
|
||||
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, nil )
|
||||
end
|
||||
end
|
||||
@@ -736,7 +786,7 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score )
|
||||
|
||||
local PlayerName = PlayerUnit:GetPlayerName()
|
||||
|
||||
self:F( { PlayerUnit.UnitName, PlayerName, GoalTag, Text, Score } )
|
||||
self:T2( { PlayerUnit.UnitName, PlayerName, GoalTag, Text, Score } )
|
||||
|
||||
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
|
||||
if PlayerName then
|
||||
@@ -745,11 +795,12 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score )
|
||||
PlayerData.Goals[GoalTag] = PlayerData.Goals[GoalTag] or { Score = 0 }
|
||||
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
|
||||
PlayerData.Score = PlayerData.Score + Score
|
||||
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
|
||||
|
||||
if Text then
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
|
||||
MESSAGE.Type.Information )
|
||||
:ToAll()
|
||||
|
||||
end
|
||||
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() )
|
||||
end
|
||||
end
|
||||
@@ -782,11 +833,12 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
|
||||
|
||||
PlayerData.Score = self.Players[PlayerName].Score + Score
|
||||
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
|
||||
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score,
|
||||
MESSAGE.Type.Information )
|
||||
:ToAll()
|
||||
|
||||
|
||||
if Text then
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score,
|
||||
MESSAGE.Type.Information )
|
||||
:ToAll()
|
||||
end
|
||||
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
|
||||
end
|
||||
end
|
||||
@@ -818,9 +870,11 @@ function SCORING:_AddMissionGoalScore( Mission, PlayerName, Text, Score )
|
||||
|
||||
PlayerData.Score = self.Players[PlayerName].Score + Score
|
||||
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
|
||||
|
||||
MESSAGE:NewType( string.format( "%s%s: %s! Player %s receives %d score!", self.DisplayMessagePrefix, Mission:GetText(), Text, PlayerName, Score ), MESSAGE.Type.Information ):ToAll()
|
||||
|
||||
|
||||
if Text then
|
||||
MESSAGE:NewType( string.format( "%s%s: %s! Player %s receives %d score!", self.DisplayMessagePrefix, Mission:GetText(), Text, PlayerName, Score ), MESSAGE.Type.Information ):ToAll()
|
||||
end
|
||||
|
||||
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score )
|
||||
end
|
||||
end
|
||||
@@ -845,11 +899,12 @@ function SCORING:_AddMissionScore( Mission, Text, Score )
|
||||
|
||||
PlayerData.Score = PlayerData.Score + Score
|
||||
PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score
|
||||
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in " .. Mission:GetText() .. ". " .. Score .. " mission score!",
|
||||
|
||||
if Text then
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in " .. Mission:GetText() .. ". " .. Score .. " mission score!",
|
||||
MESSAGE.Type.Information )
|
||||
:ToAll()
|
||||
|
||||
end
|
||||
self:ScoreCSV( PlayerName, "", "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score )
|
||||
end
|
||||
end
|
||||
@@ -871,10 +926,13 @@ end
|
||||
function SCORING:OnEventBirth( Event )
|
||||
|
||||
if Event.IniUnit then
|
||||
Event.IniUnit.ThreatLevel, Event.IniUnit.ThreatType = Event.IniUnit:GetThreatLevel()
|
||||
if Event.IniObjectCategory == 1 then
|
||||
local PlayerName = Event.IniUnit:GetPlayerName()
|
||||
Event.IniUnit.BirthTime = timer.getTime()
|
||||
if PlayerName then
|
||||
self:_AddPlayerFromUnit( Event.IniUnit )
|
||||
self.Players[PlayerName].PlayerKills = 0
|
||||
self:SetScoringMenu( Event.IniGroup )
|
||||
end
|
||||
end
|
||||
@@ -1003,8 +1061,19 @@ function SCORING:_EventOnHit( Event )
|
||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
||||
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
||||
PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
|
||||
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
||||
|
||||
-- After an instant kill we can't compute the threat level anymore. To fix this we compute at OnEventBirth
|
||||
if PlayerHit.UNIT.ThreatType == nil then
|
||||
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
||||
-- if this fails for some reason, set a good default value
|
||||
if PlayerHit.ThreatType == nil or PlayerHit.ThreatType == "" then
|
||||
PlayerHit.ThreatLevel = 1
|
||||
PlayerHit.ThreatType = "Unknown"
|
||||
end
|
||||
else
|
||||
PlayerHit.ThreatLevel = PlayerHit.UNIT.ThreatLevel
|
||||
PlayerHit.ThreatType = PlayerHit.UNIT.ThreatType
|
||||
end
|
||||
|
||||
-- Only grant hit scores if there was more than one second between the last hit.
|
||||
if timer.getTime() - PlayerHit.TimeStamp > 1 then
|
||||
PlayerHit.TimeStamp = timer.getTime()
|
||||
@@ -1019,27 +1088,28 @@ function SCORING:_EventOnHit( Event )
|
||||
|
||||
if InitCoalition then -- A coalition object was hit.
|
||||
if InitCoalition == TargetCoalition then
|
||||
Player.Penalty = Player.Penalty + 10
|
||||
PlayerHit.Penalty = PlayerHit.Penalty + 10
|
||||
local Penalty = 10
|
||||
Player.Penalty = Player.Penalty + Penalty
|
||||
PlayerHit.Penalty = PlayerHit.Penalty + Penalty
|
||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1
|
||||
|
||||
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
|
||||
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
"Penalty: -" .. Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Update )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
else
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
|
||||
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
"Penalty: -" .. Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Update )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
end
|
||||
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||
else
|
||||
Player.Score = Player.Score + 1
|
||||
PlayerHit.Score = PlayerHit.Score + 1
|
||||
Player.Score = Player.Score + self.ScoreIncrementOnHit
|
||||
PlayerHit.Score = PlayerHit.Score + self.ScoreIncrementOnHit
|
||||
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
||||
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
||||
@@ -1102,7 +1172,18 @@ function SCORING:_EventOnHit( Event )
|
||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
||||
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
||||
PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
|
||||
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
||||
-- After an instant kill we can't compute the threat level anymore. To fix this we compute at OnEventBirth
|
||||
if PlayerHit.UNIT.ThreatType == nil then
|
||||
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
||||
-- if this fails for some reason, set a good default value
|
||||
if PlayerHit.ThreatType == nil then
|
||||
PlayerHit.ThreatLevel = 1
|
||||
PlayerHit.ThreatType = "Unknown"
|
||||
end
|
||||
else
|
||||
PlayerHit.ThreatLevel = PlayerHit.UNIT.ThreatLevel
|
||||
PlayerHit.ThreatType = PlayerHit.UNIT.ThreatType
|
||||
end
|
||||
|
||||
-- Only grant hit scores if there was more than one second between the last hit.
|
||||
if timer.getTime() - PlayerHit.TimeStamp > 1 then
|
||||
@@ -1113,25 +1194,26 @@ function SCORING:_EventOnHit( Event )
|
||||
if InitCoalition then -- A coalition object was hit, probably a static.
|
||||
if InitCoalition == TargetCoalition then
|
||||
-- TODO: Penalty according scale
|
||||
Player.Penalty = Player.Penalty + 10 --* self.ScaleDestroyPenalty
|
||||
PlayerHit.Penalty = PlayerHit.Penalty + 10 --* self.ScaleDestroyPenalty
|
||||
local Penalty = 10
|
||||
Player.Penalty = Player.Penalty + Penalty --* self.ScaleDestroyPenalty
|
||||
PlayerHit.Penalty = PlayerHit.Penalty + Penalty --* self.ScaleDestroyPenalty
|
||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 * self.ScaleDestroyPenalty
|
||||
|
||||
MESSAGE
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
|
||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
||||
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||
"Penalty: -" .. Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Update
|
||||
)
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||
else
|
||||
Player.Score = Player.Score + 1
|
||||
PlayerHit.Score = PlayerHit.Score + 1
|
||||
Player.Score = Player.Score + self.ScoreIncrementOnHit
|
||||
PlayerHit.Score = PlayerHit.Score + self.ScoreIncrementOnHit
|
||||
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
||||
"Score: +" .. PlayerHit.Score .. " = " .. Player.Score - Player.Penalty,
|
||||
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Update )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
@@ -1209,7 +1291,7 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
||||
local Destroyed = false
|
||||
|
||||
-- What is the player destroying?
|
||||
if Player and Player.Hit and Player.Hit[TargetCategory] and Player.Hit[TargetCategory][TargetUnitName] and Player.Hit[TargetCategory][TargetUnitName].TimeStamp ~= 0 then -- Was there a hit for this unit for this player before registered???
|
||||
if Player and Player.Hit and Player.Hit[TargetCategory] and Player.Hit[TargetCategory][TargetUnitName] and Player.Hit[TargetCategory][TargetUnitName].TimeStamp ~= 0 and (TargetUnit.BirthTime == nil or Player.Hit[TargetCategory][TargetUnitName].TimeStamp > TargetUnit.BirthTime) then -- Was there a hit for this unit for this player before registered???
|
||||
|
||||
local TargetThreatLevel = Player.Hit[TargetCategory][TargetUnitName].ThreatLevel
|
||||
local TargetThreatType = Player.Hit[TargetCategory][TargetUnitName].ThreatType
|
||||
@@ -1236,15 +1318,20 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
||||
TargetDestroy.Penalty = TargetDestroy.Penalty + ThreatPenalty
|
||||
TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1
|
||||
|
||||
|
||||
--self:OnKillPvP(PlayerName, TargetPlayerName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty)
|
||||
|
||||
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
||||
self:OnKillPvP(PlayerName, TargetPlayerName, true)
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||
"Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Information )
|
||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||
else
|
||||
self:OnKillPvE(PlayerName, TargetUnitName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty)
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||
"Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Information )
|
||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||
@@ -1265,14 +1352,21 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
||||
TargetDestroy.Score = TargetDestroy.Score + ThreatScore
|
||||
TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1
|
||||
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
||||
if Player.PlayerKills ~= nil then
|
||||
Player.PlayerKills = Player.PlayerKills + 1
|
||||
else
|
||||
Player.PlayerKills = 1
|
||||
end
|
||||
self:OnKillPvP(PlayerName, TargetPlayerName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore)
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
|
||||
"Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Information )
|
||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||
else
|
||||
self:OnKillPvE(PlayerName, TargetUnitName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore)
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
|
||||
"Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Information )
|
||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||
@@ -1383,7 +1477,7 @@ function SCORING:ReportDetailedPlayerHits( PlayerName )
|
||||
Penalty = Penalty + UnitData.Penalty
|
||||
PenaltyHit = UnitData.PenaltyHit
|
||||
end
|
||||
local ScoreMessageHit = string.format( "%s:%d ", CategoryName, Score - Penalty )
|
||||
local ScoreMessageHit = string.format( "%s: %d ", CategoryName, Score - Penalty )
|
||||
self:T( ScoreMessageHit )
|
||||
ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit
|
||||
PlayerScore = PlayerScore + Score
|
||||
@@ -1439,7 +1533,7 @@ function SCORING:ReportDetailedPlayerDestroys( PlayerName )
|
||||
end
|
||||
end
|
||||
|
||||
local ScoreMessageDestroy = string.format( " %s:%d ", CategoryName, Score - Penalty )
|
||||
local ScoreMessageDestroy = string.format( " %s: %d ", CategoryName, Score - Penalty )
|
||||
self:T( ScoreMessageDestroy )
|
||||
ScoreMessageDestroys = ScoreMessageDestroys .. ScoreMessageDestroy
|
||||
|
||||
@@ -1730,9 +1824,9 @@ function SCORING:SecondsToClock( sSeconds )
|
||||
-- return nil;
|
||||
return "00:00:00";
|
||||
else
|
||||
nHours = string.format( "%02.f", math.floor( nSeconds / 3600 ) );
|
||||
nMins = string.format( "%02.f", math.floor( nSeconds / 60 - (nHours * 60) ) );
|
||||
nSecs = string.format( "%02.f", math.floor( nSeconds - nHours * 3600 - nMins * 60 ) );
|
||||
local nHours = string.format( "%02.f", math.floor( nSeconds / 3600 ) );
|
||||
local nMins = string.format( "%02.f", math.floor( nSeconds / 60 - (nHours * 60) ) );
|
||||
local nSecs = string.format( "%02.f", math.floor( nSeconds - nHours * 3600 - nMins * 60 ) );
|
||||
return nHours .. ":" .. nMins .. ":" .. nSecs
|
||||
end
|
||||
end
|
||||
@@ -1748,10 +1842,11 @@ end
|
||||
function SCORING:OpenCSV( ScoringCSV )
|
||||
self:F( ScoringCSV )
|
||||
|
||||
if lfs and io and os then
|
||||
if lfs and io and os and self.AutoSave == true then
|
||||
if ScoringCSV then
|
||||
self.ScoringCSV = ScoringCSV
|
||||
local fdir = lfs.writedir() .. [[Logs\]] .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv"
|
||||
local path = self.AutoSavePath or lfs.writedir() .. [[Logs\]]
|
||||
local fdir = path .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv"
|
||||
|
||||
self.CSVFile, self.err = io.open( fdir, "w+" )
|
||||
if not self.CSVFile then
|
||||
@@ -1828,7 +1923,7 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
|
||||
TargetUnitType = TargetUnitType or ""
|
||||
TargetUnitName = TargetUnitName or ""
|
||||
|
||||
if lfs and io and os then
|
||||
if lfs and io and os and self.AutoSave then
|
||||
self.CSVFile:write(
|
||||
'"' .. self.GameName .. '"' .. ',' ..
|
||||
'"' .. self.RunTime .. '"' .. ',' ..
|
||||
@@ -1852,9 +1947,43 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
|
||||
end
|
||||
end
|
||||
|
||||
--- Close CSV file
|
||||
-- @param #SCORING self
|
||||
-- @return #SCORING self
|
||||
function SCORING:CloseCSV()
|
||||
if lfs and io and os then
|
||||
if lfs and io and os and self.AutoSave then
|
||||
self.CSVFile:close()
|
||||
end
|
||||
end
|
||||
|
||||
--- Registers a score for a player.
|
||||
-- @param #SCORING self
|
||||
-- @param #boolean OnOff Switch saving to CSV on = true or off = false
|
||||
-- @return #SCORING self
|
||||
function SCORING:SwitchAutoSave(OnOff)
|
||||
self.AutoSave = OnOff
|
||||
return self
|
||||
end
|
||||
|
||||
--- Handles the event when one player kill another player
|
||||
-- @param #SCORING self
|
||||
-- @param #string PlayerName The attacking player
|
||||
-- @param #string TargetPlayerName The name of the killed player
|
||||
-- @param #boolean IsTeamKill true if this kill was a team kill
|
||||
-- @param #number TargetThreatLevel Threat level of the target
|
||||
-- @param #number PlayerThreatLevel Threat level of the player
|
||||
-- @param #number Score The score based on both threat levels
|
||||
function SCORING:OnKillPvP(PlayerName, TargetPlayerName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score)
|
||||
|
||||
end
|
||||
--- Handles the event when one player kill another player
|
||||
-- @param #SCORING self
|
||||
-- @param #string PlayerName The attacking player
|
||||
-- @param #string TargetUnitName the name of the killed unit
|
||||
-- @param #boolean IsTeamKill true if this kill was a team kill
|
||||
-- @param #number TargetThreatLevel Threat level of the target
|
||||
-- @param #number PlayerThreatLevel Threat level of the player
|
||||
-- @param #number Score The score based on both threat levels
|
||||
function SCORING:OnKillPvE(PlayerName, TargetUnitName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score)
|
||||
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Make SAM sites execute evasive and defensive behaviour when being fired upon.
|
||||
--- **Functional** - Make SAM sites evasive and execute defensive behaviour when being fired upon.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -13,13 +13,13 @@
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [SEV - SEAD Evasion](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SEV%20-%20SEAD%20Evasion)
|
||||
-- [SEV - SEAD Evasion](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Functional/Sead)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: **FlightControl**, **applevangelist**
|
||||
-- ### Authors: **applevangelist**, **FlightControl**
|
||||
--
|
||||
-- Last Update: Feb 2022
|
||||
-- Last Update: Dec 2024
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -28,13 +28,23 @@
|
||||
|
||||
---
|
||||
-- @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
|
||||
|
||||
--- Make SAM sites execute evasive and defensive behaviour when being fired upon.
|
||||
--
|
||||
-- This class is very easy to use. Just setup a SEAD object by using @{#SEAD.New}() and SAMs will evade and take defensive action when being fired upon.
|
||||
-- Once a HARM attack is detected, SEAD will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
|
||||
-- vehicles around (*if* they are drivable, that is). There's a component of randomness in detection and evasion, which is based on the
|
||||
-- vehicles around (*if* they are driveable, that is). There's a component of randomness in detection and evasion, which is based on the
|
||||
-- skill set of the SAM set (the higher the skill, the more likely). When a missile is fired from far away, the SAM will stay active for a
|
||||
-- period of time to stay defensive, before it takes evasive actions.
|
||||
--
|
||||
@@ -56,20 +66,21 @@ SEAD = {
|
||||
SEADGroupPrefixes = {},
|
||||
SuppressedGroups = {},
|
||||
EngagementRange = 75, -- default 75% engagement range Feature Request #1355
|
||||
Padding = 10,
|
||||
Padding = 15,
|
||||
CallBack = nil,
|
||||
UseCallBack = false,
|
||||
debug = false,
|
||||
WeaponTrack = false,
|
||||
}
|
||||
|
||||
--- Missile enumerators
|
||||
-- @field Harms
|
||||
SEAD.Harms = {
|
||||
["AGM_88"] = "AGM_88",
|
||||
["AGM_45"] = "AGM_45",
|
||||
["AGM_122"] = "AGM_122",
|
||||
["AGM_84"] = "AGM_84",
|
||||
["AGM_45"] = "AGM_45",
|
||||
["AGM_65"] = "AGM_65",
|
||||
["ALARM"] = "ALARM",
|
||||
["LD-10"] = "LD-10",
|
||||
["X_58"] = "X_58",
|
||||
@@ -80,6 +91,7 @@ SEAD = {
|
||||
["BGM_109"] = "BGM_109",
|
||||
["AGM_154"] = "AGM_154",
|
||||
["HY-2"] = "HY-2",
|
||||
["ADM_141A"] = "ADM_141A",
|
||||
}
|
||||
|
||||
--- Missile enumerators - from DCS ME and Wikipedia
|
||||
@@ -88,6 +100,7 @@ SEAD = {
|
||||
-- km and mach
|
||||
["AGM_88"] = { 150, 3},
|
||||
["AGM_45"] = { 12, 2},
|
||||
["AGM_65"] = { 16, 0.9},
|
||||
["AGM_122"] = { 16.5, 2.3},
|
||||
["AGM_84"] = { 280, 0.8},
|
||||
["ALARM"] = { 45, 2},
|
||||
@@ -100,6 +113,7 @@ SEAD = {
|
||||
["BGM_109"] = {460, 0.705}, --in-game ~465kn
|
||||
["AGM_154"] = {130, 0.61},
|
||||
["HY-2"] = {90,1},
|
||||
["ADM_141A"] = {126,0.6},
|
||||
}
|
||||
|
||||
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
||||
@@ -143,7 +157,7 @@ function SEAD:New( SEADGroupPrefixes, Padding )
|
||||
self:AddTransition("*", "ManageEvasion", "*")
|
||||
self:AddTransition("*", "CalculateHitZone", "*")
|
||||
|
||||
self:I("*** SEAD - Started Version 0.4.3")
|
||||
self:I("*** SEAD - Started Version 0.4.9")
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -203,7 +217,7 @@ function SEAD:SwitchEmissions(Switch)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add an object to call back when going evasive.
|
||||
--- Set an object to call back when going evasive.
|
||||
-- @param #SEAD self
|
||||
-- @param #table Object The object to call. Needs to have object functions as follows:
|
||||
-- `:SeadSuppressionPlanned(Group, Name, SuppressionStartTime, SuppressionEndTime)`
|
||||
@@ -319,9 +333,6 @@ function SEAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADG
|
||||
end
|
||||
|
||||
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterZones({targetzone}):FilterOnce()
|
||||
local tgtcoord = targetzone:GetRandomPointVec2()
|
||||
--if tgtcoord and tgtcoord.ClassName == "COORDINATE" then
|
||||
--local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local tgtgrp = seadset:GetRandom()
|
||||
local _targetgroup = nil
|
||||
local _targetgroupname = "none"
|
||||
@@ -348,8 +359,9 @@ end
|
||||
-- @param #string SEADWeaponName
|
||||
-- @param Wrapper.Group#GROUP SEADGroup Attacker Group
|
||||
-- @param #number timeoffset Offset for tti calc
|
||||
-- @param Wrapper.Weapon#WEAPON Weapon
|
||||
-- @return #SEAD self
|
||||
function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,timeoffset)
|
||||
function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,timeoffset,Weapon)
|
||||
local timeoffset = timeoffset or 0
|
||||
if _targetskill == "Random" then -- when skill is random, choose a skill
|
||||
local Skills = { "Average", "Good", "High", "Excellent" }
|
||||
@@ -369,9 +381,13 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
|
||||
local reach = 10
|
||||
if hit then
|
||||
local wpndata = SEAD.HarmData[data]
|
||||
reach = wpndata[1] * 1,1
|
||||
reach = wpndata[1] * 1.1
|
||||
local mach = wpndata[2]
|
||||
wpnspeed = math.floor(mach * 340.29)
|
||||
if Weapon and Weapon:GetSpeed() > 0 then
|
||||
wpnspeed = Weapon:GetSpeed()
|
||||
self:T(string.format("*** SEAD - Weapon Speed from WEAPON: %f m/s",wpnspeed))
|
||||
end
|
||||
end
|
||||
-- time to impact
|
||||
local _tti = math.floor(_distance / wpnspeed) - timeoffset -- estimated impact time
|
||||
@@ -395,7 +411,7 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
|
||||
grp:EnableEmission(false)
|
||||
end
|
||||
grp:OptionAlarmStateGreen() -- needed else we cannot move around
|
||||
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond")
|
||||
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond",true)
|
||||
if self.UseCallBack then
|
||||
local object = self.CallBack
|
||||
object:SeadSuppressionStart(grp,name,attacker)
|
||||
@@ -405,7 +421,7 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
|
||||
local function SuppressionStop(args)
|
||||
self:T(string.format("*** SEAD - %s Radar On",args[2]))
|
||||
local grp = args[1] -- Wrapper.Group#GROUP
|
||||
local name = args[2] -- #string Group Nam
|
||||
local name = args[2] -- #string Group Name
|
||||
if self.UseEmissionsOnOff then
|
||||
grp:EnableEmission(true)
|
||||
end
|
||||
@@ -424,7 +440,7 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
|
||||
if _tti > 600 then delay = _tti - 90 end -- shot from afar, 600 is default shorad ontime
|
||||
|
||||
local SuppressionStartTime = timer.getTime() + delay
|
||||
local SuppressionEndTime = timer.getTime() + _tti + self.Padding
|
||||
local SuppressionEndTime = timer.getTime() + delay + _tti + self.Padding + delay
|
||||
local _targetgroupname = _targetgroup:GetName()
|
||||
if not self.SuppressedGroups[_targetgroupname] then
|
||||
self:T(string.format("*** SEAD - %s | Parameters TTI %ds | Switch-Off in %ds",_targetgroupname,_tti,delay))
|
||||
@@ -449,33 +465,45 @@ end
|
||||
-- @return #SEAD self
|
||||
function SEAD:HandleEventShot( EventData )
|
||||
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
|
||||
|
||||
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
||||
--self:T({ SEADWeapon })
|
||||
|
||||
local SEADWeaponName = EventData.WeaponName or "None" -- return weapon type
|
||||
|
||||
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' )
|
||||
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 _targetgroupname = "none"
|
||||
local _target = EventData.Weapon:getTarget() -- Identify target
|
||||
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"))
|
||||
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 fheight = SEADPlane:GetHeight()
|
||||
self:__CalculateHitZone(20,SEADWeapon,pos0,fheight,SEADGroup,SEADWeaponName)
|
||||
end
|
||||
return self
|
||||
end
|
||||
local targetcat = _target:getCategory() -- Identify category
|
||||
local targetcat = Object.getCategory(_target) -- Identify category
|
||||
local _targetUnit = nil -- Wrapper.Unit#UNIT
|
||||
local _targetgroup = nil -- Wrapper.Group#GROUP
|
||||
self:T(string.format("*** Targetcat = %d",targetcat))
|
||||
@@ -513,7 +541,11 @@ function SEAD:HandleEventShot( EventData )
|
||||
end
|
||||
end
|
||||
if SEADGroupFound == true then -- yes we are being attacked
|
||||
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup)
|
||||
if string.find(SEADWeaponName,"ADM_141",1,true) then
|
||||
self:__ManageEvasion(2,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,2,WeaponWrapper)
|
||||
else
|
||||
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
--- **Functional** -- Short Range Air Defense System
|
||||
--- **Functional** - Short Range Air Defense System.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
-- **SHORAD** - Short Range Air Defense System
|
||||
-- Controls a network of short range air/missile defense groups.
|
||||
-- * Short Range Air Defense System
|
||||
-- * Controls a network of short range air/missile defense groups.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- ### [SHORAD - Short Range Air Defense](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SRD%20-%20SHORAD%20Defense)
|
||||
-- ### [SHORAD - Short Range Air Defense](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Functional/Shorad)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -19,6 +21,7 @@
|
||||
-- @image Functional.Shorad.jpg
|
||||
--
|
||||
-- Date: Nov 2021
|
||||
-- Last Update: Jan 2025
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **SHORAD** class, extends Core.Base#BASE
|
||||
@@ -37,8 +40,15 @@
|
||||
-- @field #boolean DefendHarms Default true, intercept incoming HARMS
|
||||
-- @field #boolean DefendMavs Default true, intercept incoming AG-Missiles
|
||||
-- @field #number DefenseLowProb Default 70, minimum detection limit
|
||||
-- @field #number DefenseHighProb Default 90, maximim detection limit
|
||||
-- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green.
|
||||
-- @field #number DefenseHighProb Default 90, maximum detection limit
|
||||
-- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green
|
||||
-- @field #boolean shootandscoot If true, shoot and scoot between zones
|
||||
-- @field #number SkateNumber Number of zones to consider
|
||||
-- @field Core.Set#SET_ZONE SkateZones Zones in this set are considered
|
||||
-- @field #number minscootdist Min distance of the next zone
|
||||
-- @field #number maxscootdist Max distance of the next zone
|
||||
-- @field #boolean scootrandomcoord If true, use a random coordinate in the zone and not the center
|
||||
-- @field #string scootformation Formation to take for scooting, e.g. "Vee" or "Cone"
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
@@ -71,14 +81,15 @@
|
||||
--
|
||||
-- `myshorad = SHORAD:New("RedShorad", "Red SHORAD", SamSet, 25000, 600, "red")`
|
||||
--
|
||||
-- ## Customize options
|
||||
-- ## Customization options
|
||||
--
|
||||
-- * SHORAD:SwitchDebug(debug)
|
||||
-- * SHORAD:SwitchHARMDefense(onoff)
|
||||
-- * SHORAD:SwitchAGMDefense(onoff)
|
||||
-- * SHORAD:SetDefenseLimits(low,high)
|
||||
-- * SHORAD:SetActiveTimer(seconds)
|
||||
-- * SHORAD:SetDefenseRadius(meters)
|
||||
-- * myshorad:SwitchDebug(debug)
|
||||
-- * myshorad:SwitchHARMDefense(onoff)
|
||||
-- * myshorad:SwitchAGMDefense(onoff)
|
||||
-- * myshorad:SetDefenseLimits(low,high)
|
||||
-- * myshorad:SetActiveTimer(seconds)
|
||||
-- * myshorad:SetDefenseRadius(meters)
|
||||
-- * myshorad:AddScootZones(ZoneSet,Number,Random,Formation)
|
||||
--
|
||||
-- @field #SHORAD
|
||||
SHORAD = {
|
||||
@@ -97,7 +108,13 @@ SHORAD = {
|
||||
DefendMavs = true,
|
||||
DefenseLowProb = 70,
|
||||
DefenseHighProb = 90,
|
||||
UseEmOnOff = false,
|
||||
UseEmOnOff = true,
|
||||
shootandscoot = false,
|
||||
SkateNumber = 3,
|
||||
SkateZones = nil,
|
||||
minscootdist = 100,
|
||||
maxscootdist = 3000,
|
||||
scootrandomcoord = false,
|
||||
}
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
@@ -110,7 +127,6 @@ do
|
||||
-- @field Harms
|
||||
SHORAD.Harms = {
|
||||
["AGM_88"] = "AGM_88",
|
||||
["AGM_45"] = "AGM_45",
|
||||
["AGM_122"] = "AGM_122",
|
||||
["AGM_84"] = "AGM_84",
|
||||
["AGM_45"] = "AGM_45",
|
||||
@@ -121,6 +137,8 @@ do
|
||||
["X_25"] = "X_25",
|
||||
["X_31"] = "X_31",
|
||||
["Kh25"] = "Kh25",
|
||||
["HY-2"] = "HY-2",
|
||||
["ADM_141A"] = "ADM_141A",
|
||||
}
|
||||
|
||||
--- TODO complete list?
|
||||
@@ -132,7 +150,6 @@ do
|
||||
["Kh29"] = "Kh29",
|
||||
["Kh31"] = "Kh31",
|
||||
["Kh66"] = "Kh66",
|
||||
--["BGM_109"] = "BGM_109",
|
||||
}
|
||||
|
||||
--- Instantiates a new SHORAD object
|
||||
@@ -144,7 +161,7 @@ do
|
||||
-- @param #number ActiveTimer Determines how many seconds the systems stay on red alert after wake-up call
|
||||
-- @param #string Coalition Coalition, i.e. "blue", "red", or "neutral"
|
||||
-- @param #boolean UseEmOnOff Use Emissions On/Off rather than Alarm State Red/Green (default: use Emissions switch)
|
||||
-- @retunr #SHORAD self
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:New(Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition, UseEmOnOff)
|
||||
local self = BASE:Inherit( self, FSM:New() )
|
||||
self:T({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition})
|
||||
@@ -163,8 +180,9 @@ do
|
||||
self.DefendMavs = true
|
||||
self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin
|
||||
self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin
|
||||
self.UseEmOnOff = UseEmOnOff or false -- Decide if we are using Emission on/off (default) or AlarmState red/green
|
||||
self:I("*** SHORAD - Started Version 0.3.1")
|
||||
self.UseEmOnOff = true -- Decide if we are using Emission on/off (default) or AlarmState red/green
|
||||
if UseEmOnOff == false then self.UseEmOnOff = UseEmOnOff end
|
||||
self:I("*** SHORAD - Started Version 0.3.4")
|
||||
-- Set the string id for output to DCS.log file.
|
||||
self.lid=string.format("SHORAD %s | ", self.name)
|
||||
self:_InitState()
|
||||
@@ -174,12 +192,14 @@ do
|
||||
self:SetStartState("Running")
|
||||
self:AddTransition("*", "WakeUpShorad", "*")
|
||||
self:AddTransition("*", "CalculateHitZone", "*")
|
||||
self:AddTransition("*", "ShootAndScoot", "*")
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Initially set all groups to alarm state GREEN
|
||||
-- @param #SHORAD self
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:_InitState()
|
||||
self:T(self.lid .. " _InitState")
|
||||
local table = {}
|
||||
@@ -203,21 +223,40 @@ do
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a SET_ZONE of zones for Shoot&Scoot
|
||||
-- @param #SHORAD self
|
||||
-- @param Core.Set#SET_ZONE ZoneSet Set of zones to be used. Units will move around to the next (random) zone between 100m and 3000m away.
|
||||
-- @param #number Number Number of closest zones to be considered, defaults to 3.
|
||||
-- @param #boolean Random If true, use a random coordinate inside the next zone to scoot to.
|
||||
-- @param #string Formation Formation to use, defaults to "Cone". See mission editor dropdown for options.
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:AddScootZones(ZoneSet, Number, Random, Formation)
|
||||
self:T(self.lid .. " AddScootZones")
|
||||
self.SkateZones = ZoneSet
|
||||
self.SkateNumber = Number or 3
|
||||
self.shootandscoot = true
|
||||
self.scootrandomcoord = Random
|
||||
self.scootformation = Formation or "Cone"
|
||||
return self
|
||||
end
|
||||
|
||||
--- Switch debug state on
|
||||
-- @param #SHORAD self
|
||||
-- @param #boolean debug Switch debug on (true) or off (false)
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SwitchDebug(onoff)
|
||||
self:T( { onoff } )
|
||||
if onoff then
|
||||
self:SwitchDebugOn()
|
||||
else
|
||||
self.SwitchDebugOff()
|
||||
self:SwitchDebugOff()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Switch debug state on
|
||||
-- @param #SHORAD self
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SwitchDebugOn()
|
||||
self.debug = true
|
||||
--tracing
|
||||
@@ -228,6 +267,7 @@ do
|
||||
|
||||
--- Switch debug state off
|
||||
-- @param #SHORAD self
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SwitchDebugOff()
|
||||
self.debug = false
|
||||
BASE:TraceOff()
|
||||
@@ -237,6 +277,7 @@ do
|
||||
--- Switch defense for HARMs
|
||||
-- @param #SHORAD self
|
||||
-- @param #boolean onoff
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SwitchHARMDefense(onoff)
|
||||
self:T( { onoff } )
|
||||
local onoff = onoff or true
|
||||
@@ -247,6 +288,7 @@ do
|
||||
--- Switch defense for AGMs
|
||||
-- @param #SHORAD self
|
||||
-- @param #boolean onoff
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SwitchAGMDefense(onoff)
|
||||
self:T( { onoff } )
|
||||
local onoff = onoff or true
|
||||
@@ -258,6 +300,7 @@ do
|
||||
-- @param #SHORAD self
|
||||
-- @param #number low Minimum detection limit, integer 1-100
|
||||
-- @param #number high Maximum detection limit integer 1-100
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SetDefenseLimits(low,high)
|
||||
self:T( { low, high } )
|
||||
local low = low or 70
|
||||
@@ -276,6 +319,7 @@ do
|
||||
--- Set the number of seconds a SHORAD site will stay active
|
||||
-- @param #SHORAD self
|
||||
-- @param #number seconds Number of seconds systems stay active
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SetActiveTimer(seconds)
|
||||
self:T(self.lid .. " SetActiveTimer")
|
||||
local timer = seconds or 600
|
||||
@@ -289,6 +333,7 @@ do
|
||||
--- Set the number of meters for the SHORAD defense zone
|
||||
-- @param #SHORAD self
|
||||
-- @param #number meters Radius of the defense search zone in meters. #SHORADs in this range around a targeted group will go active
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SetDefenseRadius(meters)
|
||||
self:T(self.lid .. " SetDefenseRadius")
|
||||
local radius = meters or 20000
|
||||
@@ -302,6 +347,7 @@ do
|
||||
--- Set using Emission on/off instead of changing alarm state
|
||||
-- @param #SHORAD self
|
||||
-- @param #boolean switch Decide if we are changing alarm state or AI state
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SetUsingEmOnOff(switch)
|
||||
self:T(self.lid .. " SetUsingEmOnOff")
|
||||
self.UseEmOnOff = switch or false
|
||||
@@ -373,11 +419,11 @@ do
|
||||
local shorad = self.Groupset
|
||||
local shoradset = shorad:GetAliveSet() --#table
|
||||
local returnname = false
|
||||
--local TDiff = 1
|
||||
for _,_groups in pairs (shoradset) do
|
||||
local groupname = _groups:GetName()
|
||||
if string.find(groupname, tgtgrp, 1, true) then
|
||||
returnname = true
|
||||
--_groups:RelocateGroundRandomInRadius(7,100,false,false) -- be a bit evasive
|
||||
end
|
||||
end
|
||||
return returnname
|
||||
@@ -397,7 +443,9 @@ do
|
||||
for _,_groups in pairs (shoradset) do
|
||||
local groupname = _groups:GetName()
|
||||
if string.find(groupname, tgtgrp, 1, true) then
|
||||
returnname = true
|
||||
if _groups:IsSAM() then
|
||||
returnname = true
|
||||
end
|
||||
end
|
||||
end
|
||||
return returnname
|
||||
@@ -424,6 +472,8 @@ do
|
||||
-- @param #number Radius Radius of the #ZONE
|
||||
-- @param #number ActiveTimer Number of seconds to stay active
|
||||
-- @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
|
||||
-- @usage Use this function to integrate with other systems, example
|
||||
--
|
||||
-- local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()
|
||||
@@ -432,7 +482,7 @@ do
|
||||
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
||||
-- mymantis:AddShorad(myshorad,720)
|
||||
-- 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({TargetGroup, Radius, ActiveTimer, TargetCat})
|
||||
local targetcat = TargetCat or Object.Category.UNIT
|
||||
@@ -450,120 +500,187 @@ do
|
||||
local targetzone = ZONE_RADIUS:New("Shorad",targetvec2,Radius) -- create a defense zone to check
|
||||
local groupset = self.Groupset --Core.Set#SET_GROUP
|
||||
local shoradset = groupset:GetAliveSet() --#table
|
||||
|
||||
-- local function to switch off shorad again
|
||||
local function SleepShorad(group)
|
||||
local groupname = group:GetName()
|
||||
self.ActiveGroups[groupname] = nil
|
||||
if self.UseEmOnOff then
|
||||
group:EnableEmission(false)
|
||||
--group:SetAIOff()
|
||||
else
|
||||
group:OptionAlarmStateGreen()
|
||||
if group and group:IsAlive() then
|
||||
local groupname = group:GetName()
|
||||
self.ActiveGroups[groupname] = nil
|
||||
if self.UseEmOnOff then
|
||||
group:EnableEmission(false)
|
||||
else
|
||||
group:OptionAlarmStateGreen()
|
||||
end
|
||||
local text = string.format("Sleeping SHORAD %s", 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
|
||||
end
|
||||
local text = string.format("Sleeping SHORAD %s", group:GetName())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
end
|
||||
|
||||
-- go through set and find the one(s) to activate
|
||||
local TDiff = 4
|
||||
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())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
if self.UseEmOnOff then
|
||||
--_group:SetAIOn()
|
||||
_group:EnableEmission(true)
|
||||
end
|
||||
_group:OptionAlarmStateRed()
|
||||
local groupname = _group:GetName()
|
||||
if self.ActiveGroups[groupname] == nil then -- no timer yet for this group
|
||||
self.ActiveGroups[groupname] = { Timing = ActiveTimer }
|
||||
local endtime = timer.getTime() + (ActiveTimer * math.random(75,100) / 100 ) -- randomize wakeup a bit
|
||||
timer.scheduleFunction(SleepShorad, _group, endtime)
|
||||
self.ActiveGroups[groupname].Timer = TIMER:New(SleepShorad,_group):Start(endtime)
|
||||
--Shoot and Scoot
|
||||
if self.shootandscoot then
|
||||
self:__ShootAndScoot(TDiff,_group)
|
||||
TDiff=TDiff+1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- (Internal) Calculate hit zone of an AGM-88
|
||||
-- @param #SHORAD self
|
||||
-- @param #table SEADWeapon DCS.Weapon object
|
||||
-- @param Core.Point#COORDINATE pos0 Position of the plane when it fired
|
||||
-- @param #number height Height when the missile was fired
|
||||
-- @param Wrapper.Group#GROUP SEADGroup Attacker group
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADGroup)
|
||||
self:T("**** Calculating hit zone")
|
||||
if SEADWeapon and SEADWeapon:isExist() then
|
||||
--local pos = SEADWeapon:getPoint()
|
||||
--- (Internal) Calculate hit zone of an AGM-88
|
||||
-- @param #SHORAD self
|
||||
-- @param #table SEADWeapon DCS.Weapon object
|
||||
-- @param Core.Point#COORDINATE pos0 Position of the plane when it fired
|
||||
-- @param #number height Height when the missile was fired
|
||||
-- @param Wrapper.Group#GROUP SEADGroup Attacker group
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADGroup)
|
||||
self:T("**** Calculating hit zone")
|
||||
if SEADWeapon and SEADWeapon:isExist() then
|
||||
--local pos = SEADWeapon:getPoint()
|
||||
|
||||
-- postion and height
|
||||
local position = SEADWeapon:getPosition()
|
||||
local mheight = height
|
||||
-- heading
|
||||
local wph = math.atan2(position.x.z, position.x.x)
|
||||
if wph < 0 then
|
||||
wph=wph+2*math.pi
|
||||
end
|
||||
wph=math.deg(wph)
|
||||
|
||||
-- velocity
|
||||
local wpndata = SEAD.HarmData["AGM_88"]
|
||||
local mveloc = math.floor(wpndata[2] * 340.29)
|
||||
local c1 = (2*mheight*9.81)/(mveloc^2)
|
||||
local c2 = (mveloc^2) / 9.81
|
||||
local Ropt = c2 * math.sqrt(c1+1)
|
||||
if height <= 5000 then
|
||||
Ropt = Ropt * 0.72
|
||||
elseif height <= 7500 then
|
||||
Ropt = Ropt * 0.82
|
||||
elseif height <= 10000 then
|
||||
Ropt = Ropt * 0.87
|
||||
elseif height <= 12500 then
|
||||
Ropt = Ropt * 0.98
|
||||
end
|
||||
|
||||
-- look at a couple of zones across the trajectory
|
||||
for n=1,3 do
|
||||
local dist = Ropt - ((n-1)*20000)
|
||||
local predpos= pos0:Translate(dist,wph)
|
||||
if predpos then
|
||||
|
||||
-- postion and height
|
||||
local position = SEADWeapon:getPosition()
|
||||
local mheight = height
|
||||
-- heading
|
||||
local wph = math.atan2(position.x.z, position.x.x)
|
||||
if wph < 0 then
|
||||
wph=wph+2*math.pi
|
||||
end
|
||||
wph=math.deg(wph)
|
||||
|
||||
-- velocity
|
||||
local wpndata = SEAD.HarmData["AGM_88"]
|
||||
local mveloc = math.floor(wpndata[2] * 340.29)
|
||||
local c1 = (2*mheight*9.81)/(mveloc^2)
|
||||
local c2 = (mveloc^2) / 9.81
|
||||
local Ropt = c2 * math.sqrt(c1+1)
|
||||
if height <= 5000 then
|
||||
Ropt = Ropt * 0.72
|
||||
elseif height <= 7500 then
|
||||
Ropt = Ropt * 0.82
|
||||
elseif height <= 10000 then
|
||||
Ropt = Ropt * 0.87
|
||||
elseif height <= 12500 then
|
||||
Ropt = Ropt * 0.98
|
||||
local targetzone = ZONE_RADIUS:New("Target Zone",predpos:GetVec2(),20000)
|
||||
|
||||
if self.debug then
|
||||
predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%ddeg | Ropt=%dm",mheight,wph,mveloc,Ropt),false)
|
||||
targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
|
||||
end
|
||||
|
||||
local seadset = self.Groupset
|
||||
local tgtcoord = targetzone:GetRandomPointVec2()
|
||||
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local _targetgroup = nil
|
||||
local _targetgroupname = "none"
|
||||
local _targetskill = "Random"
|
||||
if tgtgrp and tgtgrp:IsAlive() then
|
||||
_targetgroup = tgtgrp
|
||||
_targetgroupname = tgtgrp:GetName() -- group name
|
||||
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||
self:T("*** Found Target = ".. _targetgroupname)
|
||||
self:WakeUpShorad(_targetgroupname, self.Radius, self.ActiveTimer, Object.Category.UNIT,true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- look at a couple of zones across the trajectory
|
||||
for n=1,3 do
|
||||
local dist = Ropt - ((n-1)*20000)
|
||||
local predpos= pos0:Translate(dist,wph)
|
||||
if predpos then
|
||||
return self
|
||||
end
|
||||
|
||||
local targetzone = ZONE_RADIUS:New("Target Zone",predpos:GetVec2(),20000)
|
||||
|
||||
if self.debug then
|
||||
predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%ddeg | Ropt=%dm",mheight,wph,mveloc,Ropt),false)
|
||||
targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
|
||||
end
|
||||
|
||||
local seadset = self.Groupset
|
||||
local tgtcoord = targetzone:GetRandomPointVec2()
|
||||
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local _targetgroup = nil
|
||||
local _targetgroupname = "none"
|
||||
local _targetskill = "Random"
|
||||
if tgtgrp and tgtgrp:IsAlive() then
|
||||
_targetgroup = tgtgrp
|
||||
_targetgroupname = tgtgrp:GetName() -- group name
|
||||
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||
self:T("*** Found Target = ".. _targetgroupname)
|
||||
self:WakeUpShorad(_targetgroupname, self.Radius, self.ActiveTimer, Object.Category.UNIT)
|
||||
--- (Internal) Shoot and Scoot
|
||||
-- @param #SHORAD self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Group#GROUP Shorad Shorad group
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:onafterShootAndScoot(From,Event,To,Shorad)
|
||||
self:T( { From,Event,To } )
|
||||
local possibleZones = {}
|
||||
local mindist = self.minscootdist or 100
|
||||
local maxdist = self.maxscootdist or 3000
|
||||
if Shorad and Shorad:IsAlive() then
|
||||
local NowCoord = Shorad:GetCoordinate()
|
||||
for _,_zone in pairs(self.SkateZones.Set) do
|
||||
local zone = _zone -- Core.Zone#ZONE_RADIUS
|
||||
local dist = NowCoord:Get2DDistance(zone:GetCoordinate())
|
||||
if dist >= mindist and dist <= maxdist then
|
||||
possibleZones[#possibleZones+1] = zone
|
||||
if #possibleZones == self.SkateNumber then break end
|
||||
end
|
||||
end
|
||||
end
|
||||
if #possibleZones > 0 and Shorad:GetVelocityKMH() < 2 then
|
||||
local rand = math.floor(math.random(1,#possibleZones*1000)/1000+0.5)
|
||||
if rand == 0 then rand = 1 end
|
||||
self:T(self.lid .. " ShootAndScoot to zone "..rand)
|
||||
local ToCoordinate = possibleZones[rand]:GetCoordinate()
|
||||
if self.scootrandomcoord then
|
||||
ToCoordinate = possibleZones[rand]:GetRandomCoordinate(nil,nil,{land.SurfaceType.LAND,land.SurfaceType.ROAD})
|
||||
end
|
||||
local formation = self.scootformation or "Cone"
|
||||
Shorad:RouteGroundTo(ToCoordinate,20,formation,1)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Main function - work on the EventData
|
||||
-- @param #SHORAD self
|
||||
-- @param Core.Event#EVENTDATA EventData The event details table data set
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:HandleEventShot( EventData )
|
||||
self:T( { EventData } )
|
||||
self:T(self.lid .. " HandleEventShot")
|
||||
--local ShootingUnit = EventData.IniDCSUnit
|
||||
--local ShootingUnitName = EventData.IniDCSUnitName
|
||||
local ShootingWeapon = EventData.Weapon -- Identify the weapon fired
|
||||
local ShootingWeaponName = EventData.WeaponName -- return weapon type
|
||||
-- get firing coalition
|
||||
@@ -594,27 +711,18 @@ end
|
||||
return self
|
||||
end
|
||||
|
||||
local targetcat = targetdata:getCategory() -- Identify category
|
||||
local targetcat = Object.getCategory(targetdata) -- Identify category
|
||||
self:T(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat)))
|
||||
self:T({targetdata})
|
||||
local targetunit = nil
|
||||
if targetcat == Object.Category.UNIT then -- UNIT
|
||||
targetunit = UNIT:Find(targetdata)
|
||||
elseif targetcat == Object.Category.STATIC then -- STATIC
|
||||
--self:T("Static Target Data")
|
||||
--self:T({targetdata:isExist()})
|
||||
--self:T({targetdata:getPoint()})
|
||||
local tgtcoord = COORDINATE:NewFromVec3(targetdata:getPoint())
|
||||
--tgtcoord:MarkToAll("Missile Target",true)
|
||||
|
||||
local tgtgrp1 = self.Samset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local tgtgrp1 = self.Samset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local tgtcoord1 = tgtgrp1:GetCoordinate()
|
||||
--tgtcoord1:MarkToAll("Close target SAM",true)
|
||||
|
||||
local tgtgrp2 = self.Groupset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local tgtcoord2 = tgtgrp2:GetCoordinate()
|
||||
--tgtcoord2:MarkToAll("Close target SHORAD",true)
|
||||
|
||||
local dist1 = tgtcoord:Get2DDistance(tgtcoord1)
|
||||
local dist2 = tgtcoord:Get2DDistance(tgtcoord2)
|
||||
|
||||
@@ -626,10 +734,8 @@ end
|
||||
targetcat = Object.Category.UNIT
|
||||
end
|
||||
end
|
||||
--local targetunitname = Unit.getName(targetdata) -- Unit name
|
||||
if targetunit and targetunit:IsAlive() then
|
||||
local targetunitname = targetunit:GetName()
|
||||
--local targetgroup = Unit.getGroup(Weapon.getTarget(ShootingWeapon)) --targeted group
|
||||
local targetgroup = nil
|
||||
local targetgroupname = "none"
|
||||
if targetcat == Object.Category.UNIT then
|
||||
@@ -647,13 +753,12 @@ end
|
||||
self:T( text )
|
||||
local m = MESSAGE:New(text,10,"Info"):ToAllIf(self.debug)
|
||||
-- check if we or a SAM site are the target
|
||||
--local TargetGroup = EventData.TgtGroup -- Wrapper.Group#GROUP
|
||||
local shotatus = self:_CheckShotAtShorad(targetgroupname) --#boolean
|
||||
local shotatsams = self:_CheckShotAtSams(targetgroupname) --#boolean
|
||||
-- if being shot at, find closest SHORADs to activate
|
||||
if shotatsams or shotatus then
|
||||
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
|
||||
@@ -664,4 +769,4 @@ end
|
||||
end
|
||||
-----------------------------------------------------------------------
|
||||
-- SHORAD end
|
||||
-----------------------------------------------------------------------
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
@@ -33,9 +33,9 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
|
||||
-- ### Contributions: FlightControl
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -85,6 +85,7 @@
|
||||
-- @field #boolean eventmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. Default true.
|
||||
-- @field Core.Zone#ZONE BattleZone
|
||||
-- @field #boolean AutoEngage
|
||||
-- @field #table waypoints Waypoints of the group as defined in the ME.
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
--
|
||||
|
||||
@@ -265,6 +266,7 @@ SUPPRESSION={
|
||||
DefaultAlarmState = "Auto",
|
||||
DefaultROE = "Weapon Free",
|
||||
eventmoose = true,
|
||||
waypoints = {},
|
||||
}
|
||||
|
||||
--- Enumerator of possible rules of engagement.
|
||||
@@ -295,7 +297,7 @@ SUPPRESSION.MenuF10=nil
|
||||
|
||||
--- PSEUDOATC version.
|
||||
-- @field #number version
|
||||
SUPPRESSION.version="0.9.3"
|
||||
SUPPRESSION.version="0.9.4"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -309,7 +311,7 @@ SUPPRESSION.version="0.9.3"
|
||||
--- Creates a new AI_suppression object.
|
||||
-- @param #SUPPRESSION self
|
||||
-- @param Wrapper.Group#GROUP group The GROUP object for which suppression should be applied.
|
||||
-- @return #SUPPRESSION SUPPRESSION object or *nil* if group does not exist or is not a ground group.
|
||||
-- @return #SUPPRESSION self
|
||||
function SUPPRESSION:New(group)
|
||||
|
||||
-- Inherits from FSM_CONTROLLABLE
|
||||
@@ -320,7 +322,7 @@ function SUPPRESSION:New(group)
|
||||
self.lid=string.format("SUPPRESSION %s | ", tostring(group:GetName()))
|
||||
self:T(self.lid..string.format("SUPPRESSION version %s. Activating suppressive fire for group %s", SUPPRESSION.version, group:GetName()))
|
||||
else
|
||||
self:E(self.lid.."SUPPRESSION | Requested group does not exist! (Has to be a MOOSE group.)")
|
||||
self:E("SUPPRESSION | Requested group does not exist! (Has to be a MOOSE group)")
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1186,6 +1188,16 @@ function SUPPRESSION:onafterFightBack(Controllable, From, Event, To)
|
||||
-- Set ROE and alarm state back to default.
|
||||
self:_SetROE()
|
||||
self:_SetAlarmState()
|
||||
|
||||
local group=Controllable --Wrapper.Group#GROUP
|
||||
|
||||
local Waypoints = group:GetTemplateRoutePoints()
|
||||
|
||||
-- env.info("FF waypoints",showMessageBox)
|
||||
-- self:I(Waypoints)
|
||||
|
||||
group:Route(Waypoints, 5)
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1251,7 +1263,7 @@ function SUPPRESSION:onafterFallBack(Controllable, From, Event, To, AttackUnit)
|
||||
self:_SetROE(SUPPRESSION.ROE.Hold)
|
||||
|
||||
-- Set alarm state to GREEN and let the unit run away.
|
||||
self:_SetAlarmState(SUPPRESSION.AlarmState.Green)
|
||||
self:_SetAlarmState(SUPPRESSION.AlarmState.Auto)
|
||||
|
||||
-- Make the group run away.
|
||||
self:_Run(Coord, self.Speed, self.Formation, self.FallbackWait)
|
||||
@@ -1537,7 +1549,7 @@ end
|
||||
-- @param #SUPPRESSION self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function SUPPRESSION:_OnEventHit(EventData)
|
||||
self:F(EventData)
|
||||
self:F3(EventData)
|
||||
|
||||
local GroupNameSelf=self.Controllable:GetName()
|
||||
local GroupNameTgt=EventData.TgtGroupName
|
||||
@@ -1676,15 +1688,15 @@ end
|
||||
function SUPPRESSION:_Run(fin, speed, formation, wait)
|
||||
|
||||
speed=speed or 20
|
||||
formation=formation or "Off road"
|
||||
formation=formation or ENUMS.Formation.Vehicle.OffRoad
|
||||
wait=wait or 30
|
||||
|
||||
local group=self.Controllable -- Wrapper.Controllable#CONTROLLABLE
|
||||
local group=self.Controllable -- Wrapper.Group#GROUP
|
||||
|
||||
if group and group:IsAlive() then
|
||||
|
||||
-- Clear all tasks.
|
||||
group:ClearTasks()
|
||||
--group:ClearTasks()
|
||||
|
||||
-- Current coordinates of group.
|
||||
local ini=group:GetCoordinate()
|
||||
@@ -1694,57 +1706,18 @@ function SUPPRESSION:_Run(fin, speed, formation, wait)
|
||||
|
||||
-- Heading from ini to fin.
|
||||
local heading=self:_Heading(ini, fin)
|
||||
|
||||
-- Number of waypoints.
|
||||
local nx
|
||||
if dist <= 50 then
|
||||
nx=2
|
||||
elseif dist <= 100 then
|
||||
nx=3
|
||||
elseif dist <= 500 then
|
||||
nx=4
|
||||
else
|
||||
nx=5
|
||||
end
|
||||
|
||||
-- Number of intermediate waypoints.
|
||||
local dx=dist/(nx-1)
|
||||
|
||||
|
||||
-- Waypoint and task arrays.
|
||||
local wp={}
|
||||
local tasks={}
|
||||
|
||||
-- First waypoint is the current position of the group.
|
||||
wp[1]=ini:WaypointGround(speed, formation)
|
||||
tasks[1]=group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, 1, false)
|
||||
|
||||
if self.Debug then
|
||||
local MarkerID=ini:MarkToAll(string.format("Waypoing %d of group %s (initial)", #wp, self.Controllable:GetName()))
|
||||
end
|
||||
|
||||
self:T2(self.lid..string.format("Number of waypoints %d", nx))
|
||||
for i=1,nx-2 do
|
||||
|
||||
local x=dx*i
|
||||
local coord=ini:Translate(x, heading)
|
||||
|
||||
wp[#wp+1]=coord:WaypointGround(speed, formation)
|
||||
tasks[#tasks+1]=group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, #wp, false)
|
||||
|
||||
self:T2(self.lid..string.format("%d x = %4.1f", i, x))
|
||||
if self.Debug then
|
||||
local MarkerID=coord:MarkToAll(string.format("Waypoing %d of group %s", #wp, self.Controllable:GetName()))
|
||||
end
|
||||
|
||||
end
|
||||
self:T2(self.lid..string.format("Total distance: %4.1f", dist))
|
||||
|
||||
-- Final waypoint.
|
||||
wp[#wp+1]=fin:WaypointGround(speed, formation)
|
||||
if self.Debug then
|
||||
local MarkerID=fin:MarkToAll(string.format("Waypoing %d of group %s (final)", #wp, self.Controllable:GetName()))
|
||||
end
|
||||
|
||||
-- Task to hold.
|
||||
local ConditionWait=group:TaskCondition(nil, nil, nil, nil, wait, nil)
|
||||
local TaskHold = group:TaskHold()
|
||||
@@ -1753,25 +1726,15 @@ function SUPPRESSION:_Run(fin, speed, formation, wait)
|
||||
local TaskComboFin = {}
|
||||
TaskComboFin[#TaskComboFin+1] = group:TaskFunction("SUPPRESSION._Passing_Waypoint", self, #wp, true)
|
||||
TaskComboFin[#TaskComboFin+1] = group:TaskControlled(TaskHold, ConditionWait)
|
||||
|
||||
-- Add final task.
|
||||
tasks[#tasks+1]=group:TaskCombo(TaskComboFin)
|
||||
|
||||
-- Original waypoints of the group.
|
||||
local Waypoints = group:GetTemplateRoutePoints()
|
||||
|
||||
-- New points are added to the default route.
|
||||
for i,p in ipairs(wp) do
|
||||
table.insert(Waypoints, i, wp[i])
|
||||
end
|
||||
|
||||
-- Set task for all waypoints.
|
||||
for i,wp in ipairs(Waypoints) do
|
||||
group:SetTaskWaypoint(Waypoints[i], tasks[i])
|
||||
end
|
||||
-- Final waypoint.
|
||||
wp[#wp+1]=fin:WaypointGround(speed, formation, TaskComboFin)
|
||||
if self.Debug then
|
||||
local MarkerID=fin:MarkToAll(string.format("Waypoing %d of group %s (final)", #wp, self.Controllable:GetName()))
|
||||
end
|
||||
|
||||
-- Submit task and route group along waypoints.
|
||||
group:Route(Waypoints)
|
||||
group:Route(wp)
|
||||
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: Group is not alive!"))
|
||||
@@ -1790,7 +1753,7 @@ function SUPPRESSION._Passing_Waypoint(group, Fsm, i, final)
|
||||
local text=string.format("Group %s passing waypoint %d (final=%s)", group:GetName(), i, tostring(final))
|
||||
MESSAGE:New(text,10):ToAllIf(Fsm.Debug)
|
||||
if Fsm.Debug then
|
||||
env.info(self.lid..text)
|
||||
env.info(Fsm.lid..text)
|
||||
end
|
||||
|
||||
if final then
|
||||
@@ -1891,7 +1854,7 @@ function SUPPRESSION:_GetLife()
|
||||
|
||||
local groupstrength=#units/self.IniGroupStrength*100
|
||||
|
||||
self.T2(self.lid..string.format("Group %s _GetLife nunits = %d", self.Controllable:GetName(), #units))
|
||||
self:T2(self.lid..string.format("Group %s _GetLife nunits = %d", self.Controllable:GetName(), #units))
|
||||
|
||||
for _,unit in pairs(units) do
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
-- @field #number respawndelay Delay before respawn in seconds.
|
||||
-- @field #number runwaydestroyed Time stamp timer.getAbsTime() when the runway was destroyed.
|
||||
-- @field #number runwayrepairtime Time in seconds until runway will be repaired after it was destroyed. Default is 3600 sec (one hour).
|
||||
-- @field Ops.FlightControl#FLIGHTCONTROL flightcontrol Flight control of this warehouse.
|
||||
-- @field OPS.FlightControl#FLIGHTCONTROL flightcontrol Flight control of this warehouse.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- Have your assets at the right place at the right time - or not!
|
||||
@@ -302,8 +302,8 @@
|
||||
--
|
||||
-- Initial Spawn states is as follows:
|
||||
-- GROUND: ROE, "Return Fire" Alarm, "Green"
|
||||
-- AIR: ROE, "Return Fire" Reaction to Threat, "Passive Defense"
|
||||
-- NAVAL ROE, "Return Fire" Alarm,"N/A"
|
||||
-- AIR: ROE, "Return Fire" Reaction to Threat, "Passive Defense"
|
||||
-- NAVAL ROE, "Return Fire" Alarm,"N/A"
|
||||
--
|
||||
-- A request can be added by the @{#WAREHOUSE.AddRequest}(*warehouse*, *AssetDescriptor*, *AssetDescriptorValue*, *nAsset*, *TransportType*, *nTransport*, *Prio*, *Assignment*) function.
|
||||
-- The parameters are
|
||||
@@ -742,7 +742,7 @@
|
||||
--
|
||||
-- ## Save Assets
|
||||
--
|
||||
-- Saving asset data to file is achieved by the @{WAREHOUSE.Save}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
|
||||
-- Saving asset data to file is achieved by the @{#WAREHOUSE.Save}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
|
||||
-- warehouse data is saved. If you do not specify a path, the file is saved your the DCS installation root directory.
|
||||
-- The parameter *filename* is optional and defines the name of the saved file. By default this is automatically created from the warehouse id and name, for example
|
||||
-- "Warehouse-1234_Batumi.txt".
|
||||
@@ -753,13 +753,13 @@
|
||||
--
|
||||
-- ### Automatic Save at Mission End
|
||||
--
|
||||
-- The assets can be saved automatically when the mission is ended via the @{WAREHOUSE.SetSaveOnMissionEnd}(*path*, *filename*) function, i.e.
|
||||
-- The assets can be saved automatically when the mission is ended via the @{#WAREHOUSE.SetSaveOnMissionEnd}(*path*, *filename*) function, i.e.
|
||||
--
|
||||
-- warehouseBatumi:SetSaveOnMissionEnd("D:\\My Warehouse Data\\")
|
||||
--
|
||||
-- ## Load Assets
|
||||
--
|
||||
-- Loading assets data from file is achieved by the @{WAREHOUSE.Load}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
|
||||
-- Loading assets data from file is achieved by the @{#WAREHOUSE.Load}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
|
||||
-- warehouse data is loaded from. If you do not specify a path, the file is loaded from your the DCS installation root directory.
|
||||
-- The parameter *filename* is optional and defines the name of the file to load. By default this is automatically generated from the warehouse id and name, for example
|
||||
-- "Warehouse-1234_Batumi.txt".
|
||||
@@ -1274,7 +1274,7 @@
|
||||
--
|
||||
-- ## Example 13: Battlefield Air Interdiction
|
||||
--
|
||||
-- This example show how to couple the WAREHOUSE class with the @{AI.AI_Bai} class.
|
||||
-- This example show how to couple the WAREHOUSE class with the @{AI.AI_BAI} class.
|
||||
-- Four enemy targets have been located at the famous Kobuleti X. All three available Viggen 2-ship flights are assigned to kill at least one of the BMPs to complete their mission.
|
||||
--
|
||||
-- -- Start Warehouse at Kobuleti.
|
||||
@@ -1629,7 +1629,7 @@ WAREHOUSE = {
|
||||
-- @field #boolean arrived If true, asset arrived at its destination.
|
||||
--
|
||||
-- @field #number damage Damage of asset group in percent.
|
||||
-- @field Ops.AirWing#AIRWING.Payload payload The payload of the asset.
|
||||
-- @field Ops.Airwing#AIRWING.Payload payload The payload of the asset.
|
||||
-- @field Ops.OpsGroup#OPSGROUP flightgroup The flightgroup object.
|
||||
-- @field Ops.Cohort#COHORT cohort The cohort this asset belongs to.
|
||||
-- @field Ops.Legion#LEGION legion The legion this asset belonts to.
|
||||
@@ -1798,7 +1798,7 @@ _WAREHOUSEDB = {
|
||||
|
||||
--- Warehouse class version.
|
||||
-- @field #string version
|
||||
WAREHOUSE.version="1.0.2"
|
||||
WAREHOUSE.version="1.0.2a"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO: Warehouse todo list.
|
||||
@@ -2647,6 +2647,13 @@ function WAREHOUSE:SetWarehouseZone(zone)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the warehouse zone.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return Core.Zone#ZONE The warehouse zone.
|
||||
function WAREHOUSE:GetWarehouseZone()
|
||||
return self.zone
|
||||
end
|
||||
|
||||
--- Set auto defence on. When the warehouse is under attack, all ground assets are spawned automatically and will defend the warehouse zone.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return #WAREHOUSE self
|
||||
@@ -3146,7 +3153,7 @@ end
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return Core.Point#COORDINATE The coordinate of the warehouse.
|
||||
function WAREHOUSE:GetCoordinate()
|
||||
return self.warehouse:GetCoordinate()
|
||||
return self.warehouse:GetCoord()
|
||||
end
|
||||
|
||||
--- Get 3D vector of warehouse static.
|
||||
@@ -3407,7 +3414,7 @@ end
|
||||
-- FSM states
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- On after Start event. Starts the warehouse. Addes event handlers and schedules status updates of reqests and queue.
|
||||
--- On after Start event. Starts the warehouse. Adds event handlers and schedules status updates of reqests and queue.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
@@ -3588,6 +3595,7 @@ function WAREHOUSE:onafterStatus(From, Event, To)
|
||||
local Trepair=self:GetRunwayRepairtime()
|
||||
self:I(self.lid..string.format("Runway destroyed! Will be repaired in %d sec", Trepair))
|
||||
if Trepair==0 then
|
||||
self.runwaydestroyed = nil
|
||||
self:RunwayRepaired()
|
||||
end
|
||||
end
|
||||
@@ -3609,9 +3617,10 @@ function WAREHOUSE:onafterStatus(From, Event, To)
|
||||
end
|
||||
|
||||
-- Print queue after processing requests.
|
||||
self:_PrintQueue(self.queue, "Queue waiting")
|
||||
self:_PrintQueue(self.pending, "Queue pending")
|
||||
|
||||
if self.verbosity > 2 then
|
||||
self:_PrintQueue(self.queue, "Queue waiting")
|
||||
self:_PrintQueue(self.pending, "Queue pending")
|
||||
end
|
||||
-- Check fuel for all assets.
|
||||
--self:_CheckFuel()
|
||||
|
||||
@@ -4094,9 +4103,9 @@ function WAREHOUSE:_RegisterAsset(group, ngroups, forceattribute, forcecargobay,
|
||||
-- Get the size of an object.
|
||||
local function _GetObjectSize(DCSdesc)
|
||||
if DCSdesc.box then
|
||||
local x=DCSdesc.box.max.x+math.abs(DCSdesc.box.min.x) --length
|
||||
local y=DCSdesc.box.max.y+math.abs(DCSdesc.box.min.y) --height
|
||||
local z=DCSdesc.box.max.z+math.abs(DCSdesc.box.min.z) --width
|
||||
local x=DCSdesc.box.max.x-DCSdesc.box.min.x --length
|
||||
local y=DCSdesc.box.max.y-DCSdesc.box.min.y --height
|
||||
local z=DCSdesc.box.max.z-DCSdesc.box.min.z --width
|
||||
return math.max(x,z), x , y, z
|
||||
end
|
||||
return 0,0,0,0
|
||||
@@ -4554,7 +4563,8 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request)
|
||||
self:_ErrorMessage("ERROR: Cargo transport by train not supported yet!")
|
||||
return
|
||||
|
||||
elseif Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.NAVALCARRIER then
|
||||
elseif Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.NAVALCARRIER
|
||||
or Request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or Request.transporttype==WAREHOUSE.TransportType.WARSHIP then
|
||||
|
||||
-- Spawn Ship in port zone
|
||||
spawngroup=self:_SpawnAssetGroundNaval(_alias, _assetitem, Request, self.portzone)
|
||||
@@ -5383,7 +5393,8 @@ function WAREHOUSE:onafterRunwayDestroyed(From, Event, To)
|
||||
self:_InfoMessage(text)
|
||||
|
||||
self.runwaydestroyed=timer.getAbsTime()
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- On after "RunwayRepaired" event.
|
||||
@@ -5398,7 +5409,8 @@ function WAREHOUSE:onafterRunwayRepaired(From, Event, To)
|
||||
self:_InfoMessage(text)
|
||||
|
||||
self.runwaydestroyed=nil
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@@ -5490,8 +5502,13 @@ function WAREHOUSE:onafterAssetDead(From, Event, To, asset, request)
|
||||
---
|
||||
|
||||
-- Remove dead group from cargo group set.
|
||||
request.cargogroupset:Remove(groupname, NoTriggerEvent)
|
||||
self:T(self.lid..string.format("Removed selfpropelled cargo %s: ncargo=%d.", groupname, request.cargogroupset:Count()))
|
||||
if request.cargogroupset then
|
||||
-- cargogroupset was nil for user case. Difficult to reproduce so we add a nil check.
|
||||
request.cargogroupset:Remove(groupname, NoTriggerEvent)
|
||||
self:T(self.lid..string.format("Removed selfpropelled cargo %s: ncargo=%d.", groupname, request.cargogroupset:Count()))
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: cargogroupset is nil for request ID=%s!", tostring(request.uid)))
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
@@ -5810,6 +5827,7 @@ function WAREHOUSE:_SpawnAssetRequest(Request)
|
||||
-- Now we try to find all parking spots for all cargo groups in advance. Due to the for loop, the parking spots do not get updated while spawning.
|
||||
local Parking={}
|
||||
if Request.cargocategory==Group.Category.AIRPLANE or Request.cargocategory==Group.Category.HELICOPTER then
|
||||
--TODO: Check for airstart. Should be a request property.
|
||||
Parking=self:_FindParkingForAssets(self.airbase, cargoassets) or {}
|
||||
end
|
||||
|
||||
@@ -5821,62 +5839,65 @@ function WAREHOUSE:_SpawnAssetRequest(Request)
|
||||
|
||||
-- Get stock item.
|
||||
local asset=cargoassets[i] --#WAREHOUSE.Assetitem
|
||||
|
||||
if not asset.spawned then
|
||||
|
||||
-- Set asset status to not spawned until we capture its birth event.
|
||||
asset.spawned=false
|
||||
asset.iscargo=true
|
||||
|
||||
-- Set request ID.
|
||||
asset.rid=Request.uid
|
||||
|
||||
-- Spawn group name.
|
||||
local _alias=asset.spawngroupname
|
||||
|
||||
--Request add asset by id.
|
||||
Request.assets[asset.uid]=asset
|
||||
|
||||
-- Spawn an asset group.
|
||||
local _group=nil --Wrapper.Group#GROUP
|
||||
if asset.category==Group.Category.GROUND then
|
||||
|
||||
-- Spawn ground troops.
|
||||
_group=self:_SpawnAssetGroundNaval(_alias, asset, Request, self.spawnzone, Request.lateActivation)
|
||||
|
||||
elseif asset.category==Group.Category.AIRPLANE or asset.category==Group.Category.HELICOPTER then
|
||||
|
||||
-- Spawn air units.
|
||||
if Parking[asset.uid] then
|
||||
_group=self:_SpawnAssetAircraft(_alias, asset, Request, Parking[asset.uid], UnControlled, Request.lateActivation)
|
||||
else
|
||||
_group=self:_SpawnAssetAircraft(_alias, asset, Request, nil, UnControlled, Request.lateActivation)
|
||||
end
|
||||
|
||||
elseif asset.category==Group.Category.TRAIN then
|
||||
|
||||
-- Spawn train.
|
||||
if self.rail then
|
||||
--TODO: Rail should only get one asset because they would spawn on top!
|
||||
|
||||
-- Spawn naval assets.
|
||||
-- Set asset status to not spawned until we capture its birth event.
|
||||
asset.iscargo=true
|
||||
|
||||
-- Set request ID.
|
||||
asset.rid=Request.uid
|
||||
|
||||
-- Spawn group name.
|
||||
local _alias=asset.spawngroupname
|
||||
|
||||
--Request add asset by id.
|
||||
Request.assets[asset.uid]=asset
|
||||
|
||||
-- Spawn an asset group.
|
||||
local _group=nil --Wrapper.Group#GROUP
|
||||
if asset.category==Group.Category.GROUND then
|
||||
|
||||
-- Spawn ground troops.
|
||||
_group=self:_SpawnAssetGroundNaval(_alias, asset, Request, self.spawnzone, Request.lateActivation)
|
||||
|
||||
elseif asset.category==Group.Category.AIRPLANE or asset.category==Group.Category.HELICOPTER then
|
||||
|
||||
-- Spawn air units.
|
||||
if Parking[asset.uid] then
|
||||
_group=self:_SpawnAssetAircraft(_alias, asset, Request, Parking[asset.uid], UnControlled, Request.lateActivation)
|
||||
else
|
||||
_group=self:_SpawnAssetAircraft(_alias, asset, Request, nil, UnControlled, Request.lateActivation)
|
||||
end
|
||||
|
||||
elseif asset.category==Group.Category.TRAIN then
|
||||
|
||||
-- Spawn train.
|
||||
if self.rail then
|
||||
--TODO: Rail should only get one asset because they would spawn on top!
|
||||
|
||||
-- Spawn naval assets.
|
||||
_group=self:_SpawnAssetGroundNaval(_alias, asset, Request, self.spawnzone, Request.lateActivation)
|
||||
end
|
||||
|
||||
--self:E(self.lid.."ERROR: Spawning of TRAIN assets not possible yet!")
|
||||
|
||||
elseif asset.category==Group.Category.SHIP then
|
||||
|
||||
-- Spawn naval assets.
|
||||
_group=self:_SpawnAssetGroundNaval(_alias, asset, Request, self.portzone, Request.lateActivation)
|
||||
|
||||
else
|
||||
self:E(self.lid.."ERROR: Unknown asset category!")
|
||||
end
|
||||
|
||||
--self:E(self.lid.."ERROR: Spawning of TRAIN assets not possible yet!")
|
||||
|
||||
elseif asset.category==Group.Category.SHIP then
|
||||
|
||||
-- Spawn naval assets.
|
||||
_group=self:_SpawnAssetGroundNaval(_alias, asset, Request, self.portzone, Request.lateActivation)
|
||||
|
||||
else
|
||||
self:E(self.lid.."ERROR: Unknown asset category!")
|
||||
|
||||
-- Trigger event.
|
||||
if _group then
|
||||
self:__AssetSpawned(0.01, _group, asset, Request)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Trigger event.
|
||||
if _group then
|
||||
self:__AssetSpawned(0.01, _group, asset, Request)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -6026,7 +6047,7 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
|
||||
|
||||
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)
|
||||
self:_DebugMessage(text)
|
||||
return nil
|
||||
@@ -6068,8 +6089,10 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
|
||||
terminal=parking[i].TerminalID
|
||||
end
|
||||
|
||||
if self.Debug then
|
||||
coord:MarkToAll(string.format("Spawnplace unit %s terminal %d.", unit.name, terminal))
|
||||
if self.Debug and terminal then
|
||||
local text=string.format("Spawnplace unit %s terminal %d.", unit.name, terminal)
|
||||
coord:MarkToAll(text)
|
||||
env.info(text)
|
||||
end
|
||||
|
||||
unit.x=coord.x
|
||||
@@ -6657,7 +6680,13 @@ function WAREHOUSE:_OnEventCrashOrDead(EventData)
|
||||
self:Destroyed()
|
||||
end
|
||||
if self.airbase and self.airbasename and self.airbasename==EventData.IniUnitName then
|
||||
self:RunwayDestroyed()
|
||||
if self:IsRunwayOperational() then
|
||||
-- Trigger RunwayDestroyed event (only if it is not destroyed already)
|
||||
self:RunwayDestroyed()
|
||||
else
|
||||
-- Reset the time stamp.
|
||||
self.runwaydestroyed=timer.getAbsTime()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6703,7 +6732,7 @@ end
|
||||
-- @param Wrapper.Group#GROUP deadgroup Group of unit that died.
|
||||
-- @param #WAREHOUSE.Pendingitem request Request that needs to be updated.
|
||||
function WAREHOUSE:_UnitDead(deadunit, deadgroup, request)
|
||||
self:F(self.lid.."FF unit dead "..deadunit:GetName())
|
||||
--self:F(self.lid.."FF unit dead "..deadunit:GetName())
|
||||
|
||||
-- Find opsgroup.
|
||||
local opsgroup=_DATABASE:FindOpsGroup(deadgroup)
|
||||
@@ -6747,7 +6776,7 @@ function WAREHOUSE:_UnitDead(deadunit, deadgroup, request)
|
||||
-- Dont trigger a Remove event for the group sets.
|
||||
local NoTriggerEvent=true
|
||||
|
||||
if not request.transporttype==WAREHOUSE.TransportType.SELFPROPELLED then
|
||||
if request.transporttype~=WAREHOUSE.TransportType.SELFPROPELLED then
|
||||
|
||||
---
|
||||
-- Complicated case: Dead unit could be:
|
||||
@@ -6814,7 +6843,7 @@ function WAREHOUSE:_OnEventBaseCaptured(EventData)
|
||||
self:AirbaseRecaptured(NewCoalitionAirbase)
|
||||
end
|
||||
else
|
||||
-- Captured airbase belongs to this warehouse but was captured by other coaltion.
|
||||
-- Captured airbase belongs to this warehouse but was captured by other coalition.
|
||||
if NewCoalitionAirbase ~= self:GetCoalition() then
|
||||
self:AirbaseCaptured(NewCoalitionAirbase)
|
||||
end
|
||||
@@ -6864,7 +6893,7 @@ function WAREHOUSE:_CheckConquered()
|
||||
for _,_unit in pairs(units) do
|
||||
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.
|
||||
if unit:IsGround() and unit:IsAlive() and distance <= radius then
|
||||
@@ -7007,7 +7036,7 @@ function WAREHOUSE:_CheckRequestConsistancy(queue)
|
||||
|
||||
-- Request from enemy coalition?
|
||||
if self:GetCoalition()~=request.warehouse:GetCoalition() then
|
||||
self:E(self.lid..string.format("ERROR: INVALID request. Requesting warehouse is of wrong coaltion! Own coalition %s != %s of requesting warehouse.", self:GetCoalitionName(), request.warehouse:GetCoalitionName()))
|
||||
self:E(self.lid..string.format("ERROR: INVALID request. Requesting warehouse is of wrong coalition! Own coalition %s != %s of requesting warehouse.", self:GetCoalitionName(), request.warehouse:GetCoalitionName()))
|
||||
valid=false
|
||||
end
|
||||
|
||||
@@ -7374,29 +7403,52 @@ function WAREHOUSE:_CheckRequestNow(request)
|
||||
local _transports
|
||||
local _assetattribute
|
||||
local _assetcategory
|
||||
local _assetairstart=false
|
||||
|
||||
-- Check if at least one (cargo) asset is available.
|
||||
if _nassets>0 then
|
||||
|
||||
local asset=_assets[1] --#WAREHOUSE.Assetitem
|
||||
|
||||
-- Get the attibute of the requested asset.
|
||||
_assetattribute=_assets[1].attribute
|
||||
_assetcategory=_assets[1].category
|
||||
_assetairstart=_assets[1].takeoffType and _assets[1].takeoffType==COORDINATE.WaypointType.TurningPoint or false
|
||||
|
||||
-- Check available parking for air asset units.
|
||||
if _assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER then
|
||||
|
||||
if self.airbase and self.airbase:GetCoalition()==self:GetCoalition() then
|
||||
|
||||
if self:IsRunwayOperational() then
|
||||
|
||||
local Parking=self:_FindParkingForAssets(self.airbase,_assets)
|
||||
|
||||
--if Parking==nil and not (self.category==Airbase.Category.HELIPAD) then
|
||||
if Parking==nil then
|
||||
local text=string.format("Warehouse %s: Request denied! Not enough free parking spots for all requested assets at the moment.", self.alias)
|
||||
self:_InfoMessage(text, 5)
|
||||
|
||||
-- Check if DCS warehouse of airbase has enough assets
|
||||
if self.airbase.storage then
|
||||
local nS=self.airbase.storage:GetAmount(asset.unittype)
|
||||
local nA=asset.nunits*request.nasset -- Number of units requested
|
||||
if nS<nA then
|
||||
local text=string.format("Warehouse %s: Request denied! DCS Warehouse has only %d assets of type %s ==> NOT enough to spawn the requested %d asset units (%d groups)",
|
||||
self.alias, nS, asset.unittype, nA, request.nasset)
|
||||
self:_InfoMessage(text, 5)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if self:IsRunwayOperational() or _assetairstart then
|
||||
|
||||
if _assetairstart then
|
||||
-- Airstart no need to check parking
|
||||
else
|
||||
|
||||
-- Check parking.
|
||||
local Parking=self:_FindParkingForAssets(self.airbase,_assets)
|
||||
|
||||
-- No parking?
|
||||
if Parking==nil then
|
||||
local text=string.format("Warehouse %s: Request denied! Not enough free parking spots for all requested assets at the moment.", self.alias)
|
||||
self:_InfoMessage(text, 5)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
-- Runway destroyed.
|
||||
@@ -7496,6 +7548,9 @@ function WAREHOUSE:_CheckRequestNow(request)
|
||||
self:_InfoMessage(text, 5)
|
||||
return false
|
||||
end
|
||||
|
||||
elseif _assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER then
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -7836,7 +7891,7 @@ function WAREHOUSE:_GetTerminal(_attribute, _category)
|
||||
-- Default terminal is "large".
|
||||
local _terminal=AIRBASE.TerminalType.OpenBig
|
||||
|
||||
if _attribute==WAREHOUSE.Attribute.AIR_FIGHTER then
|
||||
if _attribute==WAREHOUSE.Attribute.AIR_FIGHTER or _attribute==WAREHOUSE.Attribute.AIR_UAV then
|
||||
-- Fighter ==> small.
|
||||
_terminal=AIRBASE.TerminalType.FighterAircraft
|
||||
elseif _attribute==WAREHOUSE.Attribute.AIR_BOMBER or _attribute==WAREHOUSE.Attribute.AIR_TRANSPORTPLANE or _attribute==WAREHOUSE.Attribute.AIR_TANKER or _attribute==WAREHOUSE.Attribute.AIR_AWACS then
|
||||
@@ -7891,10 +7946,12 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets)
|
||||
local clients=_DATABASE.CLIENTS
|
||||
for clientname, client in pairs(clients) do
|
||||
local template=_DATABASE:GetGroupTemplateFromUnitName(clientname)
|
||||
local units=template.units
|
||||
for i,unit in pairs(units) do
|
||||
local coord=COORDINATE:New(unit.x, unit.alt, unit.y)
|
||||
coords[unit.name]=coord
|
||||
if template then
|
||||
local units=template.units
|
||||
for i,unit in pairs(units) do
|
||||
local coord=COORDINATE:New(unit.x, unit.alt, unit.y)
|
||||
coords[unit.name]=coord
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -7969,93 +8026,125 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets)
|
||||
-- Loop over all assets that need a parking psot.
|
||||
for _,asset in pairs(assets) do
|
||||
local _asset=asset --#WAREHOUSE.Assetitem
|
||||
|
||||
-- Get terminal type of this asset
|
||||
local terminaltype=asset.terminalType or self:_GetTerminal(asset.attribute, self:GetAirbaseCategory())
|
||||
|
||||
-- Asset specific parking.
|
||||
parking[_asset.uid]={}
|
||||
|
||||
-- Loop over all units - each one needs a spot.
|
||||
for i=1,_asset.nunits do
|
||||
|
||||
-- Asset name
|
||||
local assetname=_asset.spawngroupname.."-"..tostring(i)
|
||||
|
||||
-- Loop over all parking spots.
|
||||
local gotit=false
|
||||
for _,_parkingspot in pairs(parkingdata) do
|
||||
local parkingspot=_parkingspot --Wrapper.Airbase#AIRBASE.ParkingSpot
|
||||
|
||||
-- Check correct terminal type for asset. We don't want helos in shelters etc.
|
||||
if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) and self:_CheckParkingValid(parkingspot) and self:_CheckParkingAsset(parkingspot, asset) and airbase:_CheckParkingLists(parkingspot.TerminalID) then
|
||||
|
||||
-- Coordinate of the parking spot.
|
||||
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
|
||||
local _termid=parkingspot.TerminalID
|
||||
local free=true
|
||||
local problem=nil
|
||||
|
||||
-- Loop over all obstacles.
|
||||
for _,obstacle in pairs(obstacles) do
|
||||
|
||||
-- Check if aircraft overlaps with any obstacle.
|
||||
local dist=_spot:Get2DDistance(obstacle.coord)
|
||||
local safe=_overlap(_asset.size, obstacle.size, dist)
|
||||
|
||||
-- Spot is blocked.
|
||||
if not safe then
|
||||
self:T3(self.lid..string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is NOT SAFE", assetname, _asset.uid, _termid, dist))
|
||||
free=false
|
||||
problem=obstacle
|
||||
problem.dist=dist
|
||||
break
|
||||
else
|
||||
--env.info(string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is SAFE", assetname, _asset.uid, _termid, dist))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Check if spot is free
|
||||
if free then
|
||||
|
||||
-- Add parkingspot for this asset unit.
|
||||
table.insert(parking[_asset.uid], parkingspot)
|
||||
|
||||
-- Debug
|
||||
self:T(self.lid..string.format("Parking spot %d is free for asset %s [id=%d]!", _termid, assetname, _asset.uid))
|
||||
|
||||
-- Add the unit as obstacle so that this spot will not be available for the next unit.
|
||||
table.insert(obstacles, {coord=_spot, size=_asset.size, name=assetname, type="asset"})
|
||||
|
||||
gotit=true
|
||||
break
|
||||
if not _asset.spawned then
|
||||
|
||||
-- Get terminal type of this asset
|
||||
local terminaltype=asset.terminalType or self:_GetTerminal(asset.attribute, self:GetAirbaseCategory())
|
||||
|
||||
-- Asset specific parking.
|
||||
parking[_asset.uid]={}
|
||||
|
||||
-- Loop over all units - each one needs a spot.
|
||||
for i=1,_asset.nunits do
|
||||
|
||||
-- Asset name
|
||||
local assetname=_asset.spawngroupname.."-"..tostring(i)
|
||||
|
||||
-- Loop over all parking spots.
|
||||
local gotit=false
|
||||
for _,_parkingspot in pairs(parkingdata) do
|
||||
local parkingspot=_parkingspot --Wrapper.Airbase#AIRBASE.ParkingSpot
|
||||
|
||||
-- Parking valid?
|
||||
local valid=true
|
||||
|
||||
if asset.parkingIDs then
|
||||
-- If asset has assigned parking spots, we take these no matter what.
|
||||
valid=self:_CheckParkingAsset(parkingspot, asset)
|
||||
else
|
||||
|
||||
-- Debug output for occupied spots.
|
||||
if self.Debug then
|
||||
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)
|
||||
self:I(self.lid..text)
|
||||
coord:MarkToAll(string.format(text))
|
||||
else
|
||||
self:T(self.lid..string.format("Parking spot %d is occupied or not big enough!", _termid))
|
||||
end
|
||||
|
||||
|
||||
-- Valid terminal type depending on attribute.
|
||||
local validTerminal=AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype)
|
||||
|
||||
-- Valid parking list.
|
||||
local validParking=self:_CheckParkingValid(parkingspot)
|
||||
|
||||
-- Black and white list.
|
||||
local validBWlist=airbase:_CheckParkingLists(parkingspot.TerminalID)
|
||||
|
||||
-- Debug info.
|
||||
--env.info(string.format("FF validTerminal = %s", tostring(validTerminal)))
|
||||
--env.info(string.format("FF validParking = %s", tostring(validParking)))
|
||||
--env.info(string.format("FF validBWlist = %s", tostring(validBWlist)))
|
||||
|
||||
-- Check if all are true
|
||||
valid=validTerminal and validParking and validBWlist
|
||||
end
|
||||
|
||||
else
|
||||
self:T2(self.lid..string.format("Terminal ID=%d: type=%s not supported", parkingspot.TerminalID, parkingspot.TerminalType))
|
||||
end -- check terminal type
|
||||
end -- loop over parking spots
|
||||
|
||||
-- No parking spot for at least one asset :(
|
||||
if not gotit then
|
||||
self:I(self.lid..string.format("WARNING: No free parking spot for asset %s [id=%d]", assetname, _asset.uid))
|
||||
return nil
|
||||
end
|
||||
end -- loop over asset units
|
||||
|
||||
|
||||
-- Check correct terminal type for asset. We don't want helos in shelters etc.
|
||||
if valid then
|
||||
|
||||
-- Coordinate of the parking spot.
|
||||
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
|
||||
local _termid=parkingspot.TerminalID
|
||||
local free=true
|
||||
local problem=nil
|
||||
|
||||
-- Loop over all obstacles.
|
||||
for _,obstacle in pairs(obstacles) do
|
||||
|
||||
-- Check if aircraft overlaps with any obstacle.
|
||||
local dist=_spot:Get2DDistance(obstacle.coord)
|
||||
local safe=_overlap(_asset.size, obstacle.size, dist)
|
||||
|
||||
-- Spot is blocked.
|
||||
if not safe then
|
||||
self:T3(self.lid..string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is NOT SAFE", assetname, _asset.uid, _termid, dist))
|
||||
free=false
|
||||
problem=obstacle
|
||||
problem.dist=dist
|
||||
break
|
||||
else
|
||||
--env.info(string.format("FF asset=%s (id=%d): spot id=%d dist=%.1fm is SAFE", assetname, _asset.uid, _termid, dist))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Check if spot is free
|
||||
if free then
|
||||
|
||||
-- Add parkingspot for this asset unit.
|
||||
table.insert(parking[_asset.uid], parkingspot)
|
||||
|
||||
-- Debug
|
||||
self:T(self.lid..string.format("Parking spot %d is free for asset %s [id=%d]!", _termid, assetname, _asset.uid))
|
||||
|
||||
-- Add the unit as obstacle so that this spot will not be available for the next unit.
|
||||
table.insert(obstacles, {coord=_spot, size=_asset.size, name=assetname, type="asset"})
|
||||
|
||||
gotit=true
|
||||
break
|
||||
|
||||
else
|
||||
|
||||
-- Debug output for occupied spots.
|
||||
if self.Debug then
|
||||
local coord=problem.coord --Core.Point#COORDINATE
|
||||
if coord then
|
||||
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)
|
||||
self:I(self.lid..text)
|
||||
coord:MarkToAll(text)
|
||||
end
|
||||
else
|
||||
self:T(self.lid..string.format("Parking spot %d is occupied or not big enough!", _termid))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
self:T2(self.lid..string.format("Terminal ID=%d: type=%s not supported", parkingspot.TerminalID, parkingspot.TerminalType))
|
||||
end -- check terminal type
|
||||
end -- loop over parking spots
|
||||
|
||||
-- No parking spot for at least one asset :(
|
||||
if not gotit then
|
||||
self:I(self.lid..string.format("WARNING: No free parking spot for asset %s [id=%d]", assetname, _asset.uid))
|
||||
return nil
|
||||
end
|
||||
end -- loop over asset units
|
||||
end -- Asset spawned check
|
||||
end -- loop over asset groups
|
||||
|
||||
return parking
|
||||
@@ -8171,7 +8260,7 @@ end
|
||||
-- @return #number Request ID.
|
||||
function WAREHOUSE:_GetIDsFromGroupName(groupname)
|
||||
|
||||
---@param #string text The text to analyse.
|
||||
-- @param #string text The text to analyse.
|
||||
local function analyse(text)
|
||||
|
||||
-- Get rid of #0001 tail from spawn.
|
||||
@@ -8346,12 +8435,14 @@ function WAREHOUSE:_GetAttribute(group)
|
||||
local attribute=WAREHOUSE.Attribute.OTHER_UNKNOWN --#WAREHOUSE.Attribute
|
||||
|
||||
if group then
|
||||
|
||||
local groupCat=group:GetCategory()
|
||||
|
||||
-----------
|
||||
--- Air ---
|
||||
-----------
|
||||
-- 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 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")
|
||||
@@ -8506,7 +8597,6 @@ end
|
||||
-- @param #WAREHOUSE.Queueitem qitem Item of queue to be removed.
|
||||
-- @param #table queue The queue from which the item should be deleted.
|
||||
function WAREHOUSE:_DeleteQueueItem(qitem, queue)
|
||||
self:F({qitem=qitem, queue=queue})
|
||||
|
||||
for i=1,#queue do
|
||||
local _item=queue[i] --#WAREHOUSE.Queueitem
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Models the process to zone guarding and capturing.
|
||||
--- **Functional** - Models the process to zone guarding and capturing.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -12,7 +12,7 @@
|
||||
--
|
||||
-- ## Missions:
|
||||
--
|
||||
-- [CAZ - Capture Zones](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAZ%20-%20Capture%20Zones)
|
||||
-- [CAZ - Capture Zones](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Functional/ZoneCaptureCoalition)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -68,9 +68,9 @@ do -- ZONE_CAPTURE_COALITION
|
||||
--
|
||||
-- In order to use ZONE_CAPTURE_COALITION, you need to:
|
||||
--
|
||||
-- * Create a @{Zone} object from one of the ZONE_ classes.
|
||||
-- Note that ZONE_POLYGON_ classes are not yet functional.
|
||||
-- The only functional ZONE_ classses are those derived from a ZONE_RADIUS.
|
||||
-- * Create a @{Core.Zone} object from one of the ZONE_ classes.
|
||||
-- The functional ZONE_ classses are those derived from a ZONE_RADIUS.
|
||||
-- In order to use a ZONE_POLYGON, hand over the **GROUP name** of a late activated group forming a polygon with it's waypoints.
|
||||
-- * Set the state of the zone. Most of the time, Guarded would be the initial state.
|
||||
-- * Start the zone capturing **monitoring process**.
|
||||
-- This will check the presence of friendly and/or enemy units within the zone and will transition the state of the zone when the tactical situation changed.
|
||||
@@ -363,8 +363,8 @@ do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
--- ZONE_CAPTURE_COALITION Constructor.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved. Alternatively, can be handed as the name of late activated group describing a @{Core.Zone#ZONE_POLYGON} with its waypoints.
|
||||
-- @param #number Coalition The initial coalition owning the zone.
|
||||
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
|
||||
-- @param #table ObjectCategories Table of unit categories. See [DCS Class Object](https://wiki.hoggitworld.com/view/DCS_Class_Object). Default {Object.Category.UNIT, Object.Category.STATIC}, i.e. all UNITS and STATICS.
|
||||
-- @return #ZONE_CAPTURE_COALITION
|
||||
@@ -715,7 +715,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
local UnitHit = EventData.TgtUnit
|
||||
|
||||
if UnitHit.ClassName ~= "SCENERY" then
|
||||
if UnitHit and UnitHit.ClassName ~= "SCENERY" then
|
||||
-- Check if unit is inside the capture zone and that it is of the defending coalition.
|
||||
if UnitHit and UnitHit:IsInZone(self) and UnitHit:GetCoalition()==self.Coalition then
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone.
|
||||
--- **Functional** - Base class that models processes to achieve goals involving a Zone.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -8,7 +8,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions: **funkyfranky**
|
||||
-- ### Contributions: **funkyfranky**, **Applevangelist**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -26,7 +26,6 @@ do -- Zone
|
||||
-- @field #boolean SmokeZone If true, smoke zone.
|
||||
-- @extends Core.Zone#ZONE_RADIUS
|
||||
|
||||
|
||||
--- Models processes that have a Goal with a defined achievement involving a Zone.
|
||||
-- Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
@@ -53,21 +52,26 @@ do -- Zone
|
||||
SmokeColor = nil,
|
||||
SmokeZone = nil,
|
||||
}
|
||||
|
||||
|
||||
--- ZONE_GOAL Constructor.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param Core.Zone#ZONE_RADIUS Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @param Core.Zone#ZONE_RADIUS Zone A @{Core.Zone} object with the goal to be achieved. Alternatively, can be handed as the name of late activated group describing a ZONE_POLYGON with its waypoints.
|
||||
-- @return #ZONE_GOAL
|
||||
function ZONE_GOAL:New( Zone )
|
||||
|
||||
local self = BASE:Inherit( self, ZONE_RADIUS:New( Zone:GetName(), Zone:GetVec2(), Zone:GetRadius() ) ) -- #ZONE_GOAL
|
||||
self:F( { Zone = Zone } )
|
||||
|
||||
BASE:I({Zone=Zone})
|
||||
local self = BASE:Inherit( self, BASE:New())
|
||||
if type(Zone) == "string" then
|
||||
self = BASE:Inherit( self, ZONE_POLYGON:NewFromGroupName(Zone) )
|
||||
else
|
||||
self = BASE:Inherit( self, ZONE_RADIUS:New( Zone:GetName(), Zone:GetVec2(), Zone:GetRadius() ) ) -- #ZONE_GOAL
|
||||
self:F( { Zone = Zone } )
|
||||
end
|
||||
-- Goal object.
|
||||
self.Goal = GOAL:New()
|
||||
|
||||
self.SmokeTime = nil
|
||||
|
||||
|
||||
-- Set smoke ON.
|
||||
self:SetSmokeZone(true)
|
||||
|
||||
@@ -81,7 +85,7 @@ do -- Zone
|
||||
-- @function [parent=#ZONE_GOAL] __DestroyedUnit
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- DestroyedUnit Handler OnAfter for ZONE_GOAL
|
||||
-- @function [parent=#ZONE_GOAL] OnAfterDestroyedUnit
|
||||
-- @param #ZONE_GOAL self
|
||||
@@ -93,15 +97,15 @@ do -- Zone
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Get the Zone.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @return #ZONE_GOAL
|
||||
function ZONE_GOAL:GetZone()
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Get the name of the Zone.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @return #string
|
||||
@@ -109,7 +113,6 @@ do -- Zone
|
||||
return self:GetName()
|
||||
end
|
||||
|
||||
|
||||
--- Activate smoking of zone with the color or the current owner.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param #boolean switch If *true* or *nil* activate smoke. If *false* or *nil*, no smoke.
|
||||
@@ -131,11 +134,10 @@ do -- Zone
|
||||
-- @param DCS#SMOKECOLOR.Color SmokeColor
|
||||
function ZONE_GOAL:Smoke( SmokeColor )
|
||||
self:F( { SmokeColor = SmokeColor} )
|
||||
|
||||
|
||||
self.SmokeColor = SmokeColor
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Flare the zone boundary.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param DCS#SMOKECOLOR.Color FlareColor
|
||||
@@ -143,7 +145,6 @@ do -- Zone
|
||||
self:FlareZone( FlareColor, 30)
|
||||
end
|
||||
|
||||
|
||||
--- When started, check the Smoke and the Zone status.
|
||||
-- @param #ZONE_GOAL self
|
||||
function ZONE_GOAL:onafterGuard()
|
||||
@@ -155,17 +156,16 @@ do -- Zone
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Check status Smoke.
|
||||
-- @param #ZONE_GOAL self
|
||||
function ZONE_GOAL:StatusSmoke()
|
||||
self:F({self.SmokeTime, self.SmokeColor})
|
||||
|
||||
|
||||
if self.SmokeZone then
|
||||
|
||||
|
||||
-- Current time.
|
||||
local CurrentTime = timer.getTime()
|
||||
|
||||
|
||||
-- Restart smoke every 5 min.
|
||||
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
|
||||
if self.SmokeColor then
|
||||
@@ -173,11 +173,10 @@ do -- Zone
|
||||
self.SmokeTime = CurrentTime
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param #ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||
@@ -185,38 +184,37 @@ do -- Zone
|
||||
self:F( { "EventDead", EventData } )
|
||||
|
||||
self:F( { EventData.IniUnit } )
|
||||
|
||||
|
||||
if EventData.IniDCSUnit then
|
||||
|
||||
local Vec3 = EventData.IniDCSUnit:getPosition().p
|
||||
self:F( { Vec3 = Vec3 } )
|
||||
|
||||
|
||||
if Vec3 and self:IsVec3InZone(Vec3) then
|
||||
|
||||
|
||||
local PlayerHits = _DATABASE.HITS[EventData.IniUnitName]
|
||||
|
||||
|
||||
if PlayerHits then
|
||||
|
||||
|
||||
for PlayerName, PlayerHit in pairs( PlayerHits.Players or {} ) do
|
||||
self.Goal:AddPlayerContribution( PlayerName )
|
||||
self:DestroyedUnit( EventData.IniUnitName, PlayerName )
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Activate the event UnitDestroyed to be fired when a unit is destroyed in the zone.
|
||||
-- @param #ZONE_GOAL self
|
||||
function ZONE_GOAL:MonitorDestroyedUnits()
|
||||
|
||||
self:HandleEvent( EVENTS.Dead, self.__Destroyed )
|
||||
self:HandleEvent( EVENTS.Crash, self.__Destroyed )
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone and Cargo.
|
||||
--- **Functional** - Base class that models processes to achieve goals involving a Zone and Cargo.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ZONE_GOAL_CARGO models processes that have a Goal with a defined achievement involving a Zone and Cargo.
|
||||
-- Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
@@ -55,8 +62,8 @@ do -- ZoneGoal
|
||||
|
||||
--- ZONE_GOAL_CARGO Constructor.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved.
|
||||
-- @param #number Coalition The initial coalition owning the zone.
|
||||
-- @return #ZONE_GOAL_CARGO
|
||||
function ZONE_GOAL_CARGO:New( Zone, Coalition )
|
||||
|
||||
@@ -254,7 +261,7 @@ do -- ZoneGoal
|
||||
|
||||
--- Set the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition
|
||||
-- @param #number Coalition
|
||||
function ZONE_GOAL_CARGO:SetCoalition( Coalition )
|
||||
self.Coalition = Coalition
|
||||
end
|
||||
@@ -262,7 +269,7 @@ do -- ZoneGoal
|
||||
|
||||
--- Get the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||
-- @return #number Coalition.
|
||||
function ZONE_GOAL_CARGO:GetCoalition()
|
||||
return self.Coalition
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user