mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
953 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d4b773b48 | ||
|
|
ec9a5efdde | ||
|
|
8f6a3d5c49 | ||
|
|
d037614861 | ||
|
|
86fab3985b | ||
|
|
8c524f160e | ||
|
|
064111407b | ||
|
|
31207c3368 | ||
|
|
7e5495bcd8 | ||
|
|
a84f0e228a | ||
|
|
dc41852e45 | ||
|
|
3a8530227d | ||
|
|
ffee1b119b | ||
|
|
9637d0e545 | ||
|
|
2af52b294c | ||
|
|
a744e08a75 | ||
|
|
9bfbfcfd6a | ||
|
|
5becf001ba | ||
|
|
4625bc73a9 | ||
|
|
8fb1807ec0 | ||
|
|
f09443c949 | ||
|
|
2dc7ca0cb2 | ||
|
|
a76ea8f393 | ||
|
|
3275fd2e5b | ||
|
|
1d5ddb3928 | ||
|
|
7ab14e0bf9 | ||
|
|
98f51116bb | ||
|
|
159c3a21c0 | ||
|
|
51b6703b58 | ||
|
|
125dc09e4d | ||
|
|
49d2f5eef1 | ||
|
|
71415a9796 | ||
|
|
483c5deddd | ||
|
|
def7a1513e | ||
|
|
954ca31c79 | ||
|
|
762ce9a6b1 | ||
|
|
fd70ffc836 | ||
|
|
ddeb832f12 | ||
|
|
bef91cea35 | ||
|
|
163e42ee6e | ||
|
|
9ca61c680e | ||
|
|
d86419f893 | ||
|
|
6e67da1672 | ||
|
|
6b2e9fcb5f | ||
|
|
136a2ce5f2 | ||
|
|
e274ac3151 | ||
|
|
c8f2786611 | ||
|
|
8516cb349c | ||
|
|
fc5cbb7862 | ||
|
|
99b1532974 | ||
|
|
3625ad37b4 | ||
|
|
1345bdcb10 | ||
|
|
337e7eab53 | ||
|
|
f655e7e652 | ||
|
|
35e41570df | ||
|
|
bab1d21cc0 | ||
|
|
f5022a12f8 | ||
|
|
08fffb9004 | ||
|
|
02aff87b9f | ||
|
|
ab5f080191 | ||
|
|
3bf9198b6f | ||
|
|
e0c8d55a5d | ||
|
|
7cd40e2d2c | ||
|
|
ea851af6ea | ||
|
|
94c21db81c | ||
|
|
0275ba8b6b | ||
|
|
f4f942d8d4 | ||
|
|
85640c5884 | ||
|
|
6de86ac708 | ||
|
|
f8e1c21a13 | ||
|
|
14e1ab9497 | ||
|
|
98b427a26f | ||
|
|
f5a68db7ef | ||
|
|
a0502a12fa | ||
|
|
2d029c6405 | ||
|
|
8f08fd87be | ||
|
|
e16d6c0ca4 | ||
|
|
d9bcb8b168 | ||
|
|
f8f000eae5 | ||
|
|
47aaf6f6b2 | ||
|
|
88734fa9fc | ||
|
|
4ab94ecf26 | ||
|
|
06ff755702 | ||
|
|
c7c63b37fe | ||
|
|
7fa7f0fb79 | ||
|
|
fdfb5266b3 | ||
|
|
3b630be4f4 | ||
|
|
36aa36398c | ||
|
|
337b7a69b2 | ||
|
|
44866e6d58 | ||
|
|
80545fa208 | ||
|
|
956d4fa248 | ||
|
|
54ae3ed62b | ||
|
|
a6ea157b4f | ||
|
|
3d0f1faadc | ||
|
|
a0ac366bec | ||
|
|
d6cbd40575 | ||
|
|
b7644efea5 | ||
|
|
9c9633ba23 | ||
|
|
d5e2365bb3 | ||
|
|
9647a1a84e | ||
|
|
c1191e286a | ||
|
|
552718e303 | ||
|
|
85505f3feb | ||
|
|
cc9b695b68 | ||
|
|
64ed3a119f | ||
|
|
53ac9ca500 | ||
|
|
72538597ad | ||
|
|
5c5b9df470 | ||
|
|
7c3a8f448c | ||
|
|
bd1aec6deb | ||
|
|
492563d6f3 | ||
|
|
3ec2d525a9 | ||
|
|
dbd358be35 | ||
|
|
69934a8cae | ||
|
|
e13cf07999 | ||
|
|
0948229335 | ||
|
|
a0e77c04e0 | ||
|
|
718679b5dd | ||
|
|
107c2da635 | ||
|
|
c2064690f1 | ||
|
|
3f875ce276 | ||
|
|
703dac8251 | ||
|
|
5bd6f4901f | ||
|
|
5c29f48a88 | ||
|
|
012122e8da | ||
|
|
a039745b0f | ||
|
|
e97badd092 | ||
|
|
c160ecbce5 | ||
|
|
ea60e43584 | ||
|
|
ab19c696c3 | ||
|
|
da4664eff5 | ||
|
|
415b740196 | ||
|
|
7ab11d8fef | ||
|
|
01add98b7a | ||
|
|
31fba973e5 | ||
|
|
81b0c3a050 | ||
|
|
c790f71002 | ||
|
|
61a304f861 | ||
|
|
13451ed602 | ||
|
|
14bc7922d0 | ||
|
|
c9e44dd865 | ||
|
|
08cdb8b080 | ||
|
|
c1dee54493 | ||
|
|
ed3345b00a | ||
|
|
1097c02b06 | ||
|
|
8d41e4699c | ||
|
|
89051d5439 | ||
|
|
075fe729aa | ||
|
|
d51690a3cf | ||
|
|
97feeaeaf3 | ||
|
|
d4d05f4693 | ||
|
|
0ebbbde6c3 | ||
|
|
1ba84003d3 | ||
|
|
42b04dedaa | ||
|
|
6fbf584e81 | ||
|
|
8e6fc439ec | ||
|
|
25777afdd1 | ||
|
|
46edf5ce32 | ||
|
|
ae04196584 | ||
|
|
7b338ca9d0 | ||
|
|
daaedd24d2 | ||
|
|
a8d96d332f | ||
|
|
6b7a778eac | ||
|
|
2112915dd2 | ||
|
|
46cfcddf68 | ||
|
|
1aabb1bfbd | ||
|
|
8e16fbd000 | ||
|
|
a9a040626e | ||
|
|
508e35aec3 | ||
|
|
171f20e898 | ||
|
|
64355fb772 | ||
|
|
dffd66940d | ||
|
|
185c27013d | ||
|
|
d9a5618773 | ||
|
|
b8a83aadb2 | ||
|
|
5b7852ef6c | ||
|
|
76f34e448c | ||
|
|
743b595465 | ||
|
|
448110de08 | ||
|
|
7148fe0c12 | ||
|
|
b0ac01f25a | ||
|
|
4f38d8109d | ||
|
|
bf903c0cc7 | ||
|
|
c46d687990 | ||
|
|
64e67494b6 | ||
|
|
31a5bfee9e | ||
|
|
e40105495a | ||
|
|
f9b4eeef67 | ||
|
|
d1aa5d5de3 | ||
|
|
7a2dee4162 | ||
|
|
8bcdbef426 | ||
|
|
76ce28cdcc | ||
|
|
6c586d69ac | ||
|
|
a02d3c1950 | ||
|
|
5a2e1f01b4 | ||
|
|
22da329fca | ||
|
|
3ce59eee35 | ||
|
|
4e63bf6a22 | ||
|
|
7599459779 | ||
|
|
7a5aa3a4f9 | ||
|
|
9650129769 | ||
|
|
e4f8b5afc3 | ||
|
|
7e4c1d8d3d | ||
|
|
d21cee9358 | ||
|
|
4d7812b368 | ||
|
|
ab5b74cf31 | ||
|
|
74e9599df9 | ||
|
|
d91166c3c4 | ||
|
|
7f9f9b33fd | ||
|
|
195459d6d8 | ||
|
|
06688366c6 | ||
|
|
a2aa482bc1 | ||
|
|
498ec4f86b | ||
|
|
a14c2ef589 | ||
|
|
b438df27a4 | ||
|
|
009e38b6f7 | ||
|
|
b46c238dda | ||
|
|
a71c7dc181 | ||
|
|
86e4654474 | ||
|
|
891a725ccb | ||
|
|
aa53004ec8 | ||
|
|
321803730d | ||
|
|
d53c444c62 | ||
|
|
d3273b631f | ||
|
|
1ce55f3d3d | ||
|
|
e93f2c54b2 | ||
|
|
77f7826084 | ||
|
|
4a424dd3d8 | ||
|
|
f8b1056c98 | ||
|
|
52e69cb697 | ||
|
|
d4449f7913 | ||
|
|
e0564876f4 | ||
|
|
12be42ee2f | ||
|
|
5a034ecf4f | ||
|
|
9a6be14fab | ||
|
|
1146684144 | ||
|
|
12dc173aea | ||
|
|
0a68e7e2f1 | ||
|
|
849120a885 | ||
|
|
1dc6b91d37 | ||
|
|
e7f0aad920 | ||
|
|
fa785a06bb | ||
|
|
ef45e9b4c9 | ||
|
|
52f429a991 | ||
|
|
4dbcaf120f | ||
|
|
a09cd6e667 | ||
|
|
ea51622213 | ||
|
|
3526203ccb | ||
|
|
dc39107daa | ||
|
|
79cfe13035 | ||
|
|
6991550d1b | ||
|
|
c22d598b8f | ||
|
|
53c0599075 | ||
|
|
c7aa799378 | ||
|
|
b669ce6d98 | ||
|
|
267401a1f3 | ||
|
|
6d8b8f41ad | ||
|
|
6aa30f91e6 | ||
|
|
c60bb29303 | ||
|
|
72343bce29 | ||
|
|
258e3d2921 | ||
|
|
fda061d8c8 | ||
|
|
9e13ac3f68 | ||
|
|
9f644b65fd | ||
|
|
727aea604f | ||
|
|
1062d512d1 | ||
|
|
b3e62fbd50 | ||
|
|
fdb1db6f85 | ||
|
|
86633597b9 | ||
|
|
2faf7631cb | ||
|
|
8fb6fc8c6d | ||
|
|
8bee670bc9 | ||
|
|
5124b842f5 | ||
|
|
3c2ff2d7a1 | ||
|
|
61761c2fc8 | ||
|
|
7b1825aca5 | ||
|
|
ce6cb9c3e6 | ||
|
|
5d87672657 | ||
|
|
5e92b822d7 | ||
|
|
4452cbd2ab | ||
|
|
4bdb75245b | ||
|
|
e85c320844 | ||
|
|
1a4370d433 | ||
|
|
d46da07f61 | ||
|
|
c952f134d8 | ||
|
|
169dcfe3f6 | ||
|
|
a7afb43ab6 | ||
|
|
08ea3cd219 | ||
|
|
bfbdb37b65 | ||
|
|
f5eb77cbf5 | ||
|
|
3ed9555705 | ||
|
|
17e9538740 | ||
|
|
d6cdc098ce | ||
|
|
6b04237a3f | ||
|
|
07aff74126 | ||
|
|
ea89c6255b | ||
|
|
18450acea1 | ||
|
|
7d90a94927 | ||
|
|
82d40759b5 | ||
|
|
19197bf234 | ||
|
|
64c4d57a7b | ||
|
|
99963c28e9 | ||
|
|
9360513831 | ||
|
|
20c1f6bab4 | ||
|
|
6bdf0122e4 | ||
|
|
16b279c5db | ||
|
|
5290ad8b2e | ||
|
|
8c76314884 | ||
|
|
79d8113df3 | ||
|
|
601c00e637 | ||
|
|
58e5ffa283 | ||
|
|
ec0b32321a | ||
|
|
ca2eec8878 | ||
|
|
851c55e985 | ||
|
|
6c9c4432cc | ||
|
|
5c7312cd41 | ||
|
|
6bce3ebb8b | ||
|
|
89e67ba54d | ||
|
|
e5c481c161 | ||
|
|
3fee4a87da | ||
|
|
87a13f3784 | ||
|
|
d5d2de7577 | ||
|
|
8241f9de60 | ||
|
|
ba2d359af2 | ||
|
|
5ebf0b8d6c | ||
|
|
804b8a800e | ||
|
|
e8ff153427 | ||
|
|
403f22bd2b | ||
|
|
c6fc571c95 | ||
|
|
8b3d7ebf04 | ||
|
|
38a03f4cbc | ||
|
|
a2790f500c | ||
|
|
927ae59f75 | ||
|
|
8b667071b7 | ||
|
|
0a34cfdafa | ||
|
|
2d43af7c0d | ||
|
|
83fab80d88 | ||
|
|
6a71921270 | ||
|
|
8ff3530916 | ||
|
|
bd7c822def | ||
|
|
7b3f84f468 | ||
|
|
bf7523fa85 | ||
|
|
0d246d3f49 | ||
|
|
e9a055219e | ||
|
|
d9d53db53f | ||
|
|
e9473e9179 | ||
|
|
0b95930674 | ||
|
|
43a4052dc8 | ||
|
|
18098d402b | ||
|
|
f556077ff6 | ||
|
|
da452ed8ce | ||
|
|
9d62c60071 | ||
|
|
fd4d7f49a5 | ||
|
|
43b320ca90 | ||
|
|
ae4d4ca97d | ||
|
|
b6ac79a9df | ||
|
|
f03f9a3308 | ||
|
|
d4fead8294 | ||
|
|
1861e742b0 | ||
|
|
d11d4e09a4 | ||
|
|
8927504801 | ||
|
|
cb6673332d | ||
|
|
21ce0cac8d | ||
|
|
7ce20d92cb | ||
|
|
c5dcd63dea | ||
|
|
0553e4b14e | ||
|
|
6dc4a122f3 | ||
|
|
4941b5ee98 | ||
|
|
4c5d5a32dc | ||
|
|
073bfbf9c9 | ||
|
|
950c121f38 | ||
|
|
ad75a7ddb5 | ||
|
|
11516228fa | ||
|
|
d98f207bcf | ||
|
|
369ea08fd1 | ||
|
|
7013db0b67 | ||
|
|
5e2a5cf5e8 | ||
|
|
1b39f5d6e6 | ||
|
|
b560aaa147 | ||
|
|
9585959431 | ||
|
|
fe2f59660d | ||
|
|
e78cd56752 | ||
|
|
3d48dee23f | ||
|
|
51192f9a4c | ||
|
|
9dc329f151 | ||
|
|
6a4741d0dc | ||
|
|
25e4d171ab | ||
|
|
be48f7751c | ||
|
|
f7403758ce | ||
|
|
d8a189b1fd | ||
|
|
5bde59b7e3 | ||
|
|
adbbeafef9 | ||
|
|
3d5fbdf42d | ||
|
|
a408f45078 | ||
|
|
c1fb803780 | ||
|
|
0b378063c0 | ||
|
|
0d6117e5b4 | ||
|
|
cdecf4a4c9 | ||
|
|
d5d5d52bd5 | ||
|
|
d05973f487 | ||
|
|
623c907900 | ||
|
|
d07d063265 | ||
|
|
533b5d035e | ||
|
|
b82e85997f | ||
|
|
4309aa326f | ||
|
|
ac72e6fad2 | ||
|
|
48384ac758 | ||
|
|
7598a6ce5c | ||
|
|
0e0ab3507c | ||
|
|
000d7d3ce2 | ||
|
|
92a70d07d9 | ||
|
|
8db5351ad7 | ||
|
|
25a6cbcf6d | ||
|
|
ac7ae68ee8 | ||
|
|
230a803045 | ||
|
|
d61840d834 | ||
|
|
f74520afd3 | ||
|
|
74668bb7db | ||
|
|
bca964aca8 | ||
|
|
ad9e97f192 | ||
|
|
aac5efbf61 | ||
|
|
6b31ad9645 | ||
|
|
0097316333 | ||
|
|
a0adca43f1 | ||
|
|
6f0507ea7f | ||
|
|
1159d11a12 | ||
|
|
9ee21f80ac | ||
|
|
f9d7eea721 | ||
|
|
191fcb25be | ||
|
|
a1eb0ff4d9 | ||
|
|
0600c96282 | ||
|
|
95d7b8250d | ||
|
|
fc852e0386 | ||
|
|
9429ec66ca | ||
|
|
92c3b530cc | ||
|
|
dd636939bb | ||
|
|
6554fa55d1 | ||
|
|
3157a63b7e | ||
|
|
d9222c23cb | ||
|
|
16d4a65569 | ||
|
|
a2c12dc05e | ||
|
|
c36579f88a | ||
|
|
19b3dcec21 | ||
|
|
ba944444da | ||
|
|
f33856cddd | ||
|
|
57c5ab1ecd | ||
|
|
0cf4b8845e | ||
|
|
4fccfa38d4 | ||
|
|
531c1d7e90 | ||
|
|
810d900d7e | ||
|
|
274b44459e | ||
|
|
394b5f5b89 | ||
|
|
e5268a29cf | ||
|
|
b14a672b0e | ||
|
|
0ec3192fb7 | ||
|
|
33271edf78 | ||
|
|
441fba0830 | ||
|
|
7dbc9436ed | ||
|
|
c999389cda | ||
|
|
462564cd01 | ||
|
|
c2a968d2ef | ||
|
|
2297646873 | ||
|
|
af050629aa | ||
|
|
3757eb06d9 | ||
|
|
06b555a50a | ||
|
|
b9eab34d6a | ||
|
|
1444a613c5 | ||
|
|
ecf3434c3d | ||
|
|
5988ceec05 | ||
|
|
f01b2c9149 | ||
|
|
b33dd94fa0 | ||
|
|
47dd73a377 | ||
|
|
25ae0c3d15 | ||
|
|
3389c908d7 | ||
|
|
3e6017c0d5 | ||
|
|
fea2f55fbb | ||
|
|
dcc42b8e62 | ||
|
|
9cea486fdc | ||
|
|
faa934ffce | ||
|
|
1ae1b9abd7 | ||
|
|
ffe4d9a143 | ||
|
|
d5d0703502 | ||
|
|
fe3e91d1a0 | ||
|
|
1beb34231e | ||
|
|
a6889be676 | ||
|
|
4eb596f5bf | ||
|
|
01de126a8f | ||
|
|
86cc1f81b6 | ||
|
|
a95afe9956 | ||
|
|
8b8fcaaacd | ||
|
|
31f0bb9fef | ||
|
|
af23aa3b79 | ||
|
|
e606ab1b8a | ||
|
|
d792061df8 | ||
|
|
689f9fd8e9 | ||
|
|
303f5cb571 | ||
|
|
b1ecdc727c | ||
|
|
7735120f25 | ||
|
|
a247f56c7e | ||
|
|
718138abd6 | ||
|
|
269b52fd0e | ||
|
|
fd34bab65a | ||
|
|
e2df7f9732 | ||
|
|
ed0c5b2264 | ||
|
|
2ebd25d677 | ||
|
|
376eeb63c5 | ||
|
|
5971f6de09 | ||
|
|
a586d81f68 | ||
|
|
c60dda2545 | ||
|
|
45d1cb48bb | ||
|
|
0d995d1832 | ||
|
|
e094c8133a | ||
|
|
1f578d4ab5 | ||
|
|
ec973fcc76 | ||
|
|
25831db057 | ||
|
|
d0925ddfc1 | ||
|
|
a4d3089fdb | ||
|
|
a94e744028 | ||
|
|
b415039947 | ||
|
|
9de6993a4c | ||
|
|
b3facc6e88 | ||
|
|
10ebc0b1e7 | ||
|
|
1401bb29aa | ||
|
|
9688c606f0 | ||
|
|
c4ba2c0235 | ||
|
|
35f18d0d1f | ||
|
|
93640b1d8e | ||
|
|
75d179176d | ||
|
|
c37560275e | ||
|
|
812902b009 | ||
|
|
b29ce9b45e | ||
|
|
31a7a4e993 | ||
|
|
7a8881974c | ||
|
|
ea069455d3 | ||
|
|
f03807207d | ||
|
|
59bf7fdc96 | ||
|
|
6c26f2cd69 | ||
|
|
2caada0119 | ||
|
|
7a579a0ab5 | ||
|
|
cf6b7365af | ||
|
|
272308cf98 | ||
|
|
747777b297 | ||
|
|
20594ad294 | ||
|
|
b4b2034792 | ||
|
|
e22e7f2c58 | ||
|
|
12fcb99218 | ||
|
|
b1a1c6c552 | ||
|
|
61e2e8ca6b | ||
|
|
21a7bac4e0 | ||
|
|
12c4e142e9 | ||
|
|
9759640d52 | ||
|
|
395923eb07 | ||
|
|
727d64927b | ||
|
|
b6fc46fdd0 | ||
|
|
e7518d69e6 | ||
|
|
cce90b1f46 | ||
|
|
a15ef93e7c | ||
|
|
08cc4e3530 | ||
|
|
7d1d165a5a | ||
|
|
fa92615f5d | ||
|
|
c4f2446b92 | ||
|
|
7088c4c426 | ||
|
|
7963f04bdc | ||
|
|
ca32c57c52 | ||
|
|
bd4ad42fcf | ||
|
|
c4ff6d7bfd | ||
|
|
25659647a6 | ||
|
|
e2ffbba04d | ||
|
|
4bc1cd1b51 | ||
|
|
95eb88e67e | ||
|
|
089306b36d | ||
|
|
c59ed155e6 | ||
|
|
0d8f3d25e9 | ||
|
|
cbb800de02 | ||
|
|
52d783a0b7 | ||
|
|
7a4a3217df | ||
|
|
af2299d392 | ||
|
|
24a3298f2e | ||
|
|
5188c40701 | ||
|
|
e01a4fa18c | ||
|
|
de5a283e50 | ||
|
|
89e6672db1 | ||
|
|
fa15d170f7 | ||
|
|
2baa42e2bc | ||
|
|
44160dfa29 | ||
|
|
a283290c06 | ||
|
|
706aea01ca | ||
|
|
fc7e15521d | ||
|
|
7a5c8d54e7 | ||
|
|
136a7c2a5b | ||
|
|
eebd247fdd | ||
|
|
284a1853ff | ||
|
|
2b89a4b5b1 | ||
|
|
8c6482632b | ||
|
|
51c233956c | ||
|
|
c2e575ef20 | ||
|
|
7c2c6daf3e | ||
|
|
9d100e9bc1 | ||
|
|
7b5136eabf | ||
|
|
af7a87e5a0 | ||
|
|
a18d432141 | ||
|
|
011a5b94fd | ||
|
|
d672983c11 | ||
|
|
9be9277a08 | ||
|
|
5976b92281 | ||
|
|
0f18b29144 | ||
|
|
533689826e | ||
|
|
62eb36c456 | ||
|
|
34265720cc | ||
|
|
38d267b2bc | ||
|
|
251302839e | ||
|
|
285c05b6ba | ||
|
|
bdc66058ab | ||
|
|
df6bc598a4 | ||
|
|
c5c437fa50 | ||
|
|
650f16084b | ||
|
|
949178d698 | ||
|
|
e57d05fc91 | ||
|
|
92d4bad63f | ||
|
|
58b2802f3a | ||
|
|
e16eb38764 | ||
|
|
f5a2183808 | ||
|
|
2bc7a8c126 | ||
|
|
03ba031153 | ||
|
|
7fe333cc35 | ||
|
|
6f1e483fd7 | ||
|
|
01c18278fc | ||
|
|
5120088b66 | ||
|
|
f82a0c092a | ||
|
|
296d1dbc2b | ||
|
|
825f4f2fac | ||
|
|
53980423a9 | ||
|
|
fe01c03037 | ||
|
|
96ca3eeb44 | ||
|
|
309ba285b1 | ||
|
|
f2cb750aa2 | ||
|
|
3544f07169 | ||
|
|
75f5cf9ac5 | ||
|
|
a780f6635f | ||
|
|
ae2e99a560 | ||
|
|
34592a53be | ||
|
|
370278e643 | ||
|
|
778ab58eee | ||
|
|
bf9d6cbd75 | ||
|
|
6bcbffb37f | ||
|
|
68c701afc6 | ||
|
|
d11de24866 | ||
|
|
5c7caadab7 | ||
|
|
8bbff46efd | ||
|
|
0865390284 | ||
|
|
6dfba37fe9 | ||
|
|
0147c3a17c | ||
|
|
03c38356ce | ||
|
|
5e5dab99eb | ||
|
|
9f17382145 | ||
|
|
43336ae431 | ||
|
|
fed937c7b7 | ||
|
|
734f624a9e | ||
|
|
a518af1200 | ||
|
|
d3fc84fe8c | ||
|
|
a5e2309409 | ||
|
|
760bdd2016 | ||
|
|
733b4940f8 | ||
|
|
2620927146 | ||
|
|
96216494bb | ||
|
|
67b5d0ca1c | ||
|
|
296b06e0b0 | ||
|
|
4e28ed3ee6 | ||
|
|
08ad1a0bce | ||
|
|
d935cbaea2 | ||
|
|
f7a5fc7d92 | ||
|
|
6329ac9262 | ||
|
|
4649e2f823 | ||
|
|
06df068d6b | ||
|
|
0dd4676879 | ||
|
|
17fc554beb | ||
|
|
510cef1d59 | ||
|
|
dc8d9ddfdd | ||
|
|
ed0f84da61 | ||
|
|
e0aa16dbd5 | ||
|
|
7ff664b05d | ||
|
|
930768e2e3 | ||
|
|
c1278993aa | ||
|
|
7145fef233 | ||
|
|
0a118cf264 | ||
|
|
344871d727 | ||
|
|
43b2f8c3ff | ||
|
|
85f0fe758b | ||
|
|
bb2a1a82a8 | ||
|
|
b2a7c994bc | ||
|
|
83044af064 | ||
|
|
abcbbdfb79 | ||
|
|
dc75002723 | ||
|
|
3ce5d71fc9 | ||
|
|
0764affd49 | ||
|
|
8507a85915 | ||
|
|
0dcd414c24 | ||
|
|
5ab050b237 | ||
|
|
7eedd7cbf1 | ||
|
|
0e0b1f470b | ||
|
|
beba6ee751 | ||
|
|
2d1409dedb | ||
|
|
85cb0b40f8 | ||
|
|
eb9fc7589f | ||
|
|
a334511601 | ||
|
|
646958cc1a | ||
|
|
cd414a8129 | ||
|
|
857ebfab44 | ||
|
|
039491a3e1 | ||
|
|
051733ac97 | ||
|
|
f2774dbf71 | ||
|
|
6f6db6d26f | ||
|
|
f69f666deb | ||
|
|
5134de9f28 | ||
|
|
b3267c00e9 | ||
|
|
282bf8bd07 | ||
|
|
b52b5b78c9 | ||
|
|
9bca76ddcf | ||
|
|
77cddfaeb4 | ||
|
|
ee6a553b6b | ||
|
|
2e195e6dca | ||
|
|
f615d2c50a | ||
|
|
e54fad6c53 | ||
|
|
7b0c0a0c8b | ||
|
|
4efe03b07b | ||
|
|
030bd92148 | ||
|
|
0f4b3e0d88 | ||
|
|
abf0de49d1 | ||
|
|
e7d48f335c | ||
|
|
ee4f7e843d | ||
|
|
4157ede997 | ||
|
|
54450c9933 | ||
|
|
f545d5d31f | ||
|
|
8332ba5112 | ||
|
|
f35d78c11c | ||
|
|
93f03a1e8b | ||
|
|
c018a6e13f | ||
|
|
b8c1135b3b | ||
|
|
abbb59efb9 | ||
|
|
ce61e8d859 | ||
|
|
ee698722a6 | ||
|
|
be0856c9e1 | ||
|
|
e04b434fcb | ||
|
|
95112e8818 | ||
|
|
09d02e18cf | ||
|
|
2ce1057d71 | ||
|
|
e048ea995e | ||
|
|
d66b7b8c20 | ||
|
|
37dc49c14f | ||
|
|
ef1290015e | ||
|
|
02c671bd63 | ||
|
|
18a15332fe | ||
|
|
d733221317 | ||
|
|
e036ec0adf | ||
|
|
f18b18187b | ||
|
|
3135639557 | ||
|
|
5eeafd2fba | ||
|
|
0577e7ee70 | ||
|
|
d9a4c63011 | ||
|
|
7fd2500db4 | ||
|
|
822920e77e | ||
|
|
85e2811c79 | ||
|
|
757b2cb6a2 | ||
|
|
15c09d9880 | ||
|
|
64b6f52a2d | ||
|
|
27159c4234 | ||
|
|
d38c2540c2 | ||
|
|
901f460907 | ||
|
|
a2fa2c4fa2 | ||
|
|
76ea635b63 | ||
|
|
d2a7cc77cc | ||
|
|
c81e9e5a5e | ||
|
|
92c4507a55 | ||
|
|
967d608b94 | ||
|
|
14c075abfc | ||
|
|
ce449c37b1 | ||
|
|
09f5421612 | ||
|
|
3c8244b2aa | ||
|
|
057e528947 | ||
|
|
e9fe11e9b3 | ||
|
|
b7183023c9 | ||
|
|
dd58838983 | ||
|
|
ef5d69032a | ||
|
|
6dcbbec087 | ||
|
|
6c98cf3a09 | ||
|
|
5f6981d309 | ||
|
|
49d3e4e7da | ||
|
|
060a1b219f | ||
|
|
4db18a4846 | ||
|
|
42a9e4c60d | ||
|
|
f3bd097e6f | ||
|
|
1848e117aa | ||
|
|
131db74630 | ||
|
|
46e76a3833 | ||
|
|
7ff06b5ef8 | ||
|
|
f65238efe6 | ||
|
|
0a819f254a | ||
|
|
7c7722efe6 | ||
|
|
e229e2e381 | ||
|
|
ac0d2fa92c | ||
|
|
e9837acda3 | ||
|
|
2e049ccfd4 | ||
|
|
73a1c56532 | ||
|
|
5686f97565 | ||
|
|
c1910646e2 | ||
|
|
dab20a3b88 | ||
|
|
f82d07ebc0 | ||
|
|
e625aaf28c | ||
|
|
7bc0f103d9 | ||
|
|
6a0294e22b | ||
|
|
82fa9ae8b3 | ||
|
|
0c70a34561 | ||
|
|
4618e81039 | ||
|
|
84fee06196 | ||
|
|
f6f2695808 | ||
|
|
cbf0112bd7 | ||
|
|
97be67bae9 | ||
|
|
58a6c43c41 | ||
|
|
d564b0161c | ||
|
|
6e47fd0c46 | ||
|
|
9a90225d40 | ||
|
|
43b5926b74 | ||
|
|
86c7e64018 | ||
|
|
c66117464a | ||
|
|
6f0a254929 | ||
|
|
c495d0e5e9 | ||
|
|
bdf5c1e960 | ||
|
|
86ad985e0b | ||
|
|
abf84e121f | ||
|
|
212c674443 | ||
|
|
9965d8284e | ||
|
|
3ac649d6e8 | ||
|
|
0e4a5c02d5 | ||
|
|
8a4a37ac11 | ||
|
|
74951f4237 | ||
|
|
8aa14428dc | ||
|
|
8002febf09 | ||
|
|
7da932e048 | ||
|
|
6923cfe143 | ||
|
|
06283ad9e3 | ||
|
|
f4a0b83619 | ||
|
|
70e5ce30bb | ||
|
|
3b3017aa1d | ||
|
|
6c5dcb068b | ||
|
|
ea7d4e4ab8 | ||
|
|
a8c5ccd4ad | ||
|
|
e41b038730 | ||
|
|
172e51307c | ||
|
|
ccb4d7f7b5 | ||
|
|
140f81b695 | ||
|
|
81d724d881 | ||
|
|
b7528dad2e | ||
|
|
63ba44dca2 | ||
|
|
8ea8702140 | ||
|
|
b923159298 | ||
|
|
79afc5a856 | ||
|
|
4d8179ec70 | ||
|
|
224f0694d8 | ||
|
|
57b4838a5a | ||
|
|
a204dd2f4b | ||
|
|
7cab0ca22a | ||
|
|
3e16e5fa51 | ||
|
|
210ad2154c | ||
|
|
bce2e3b922 | ||
|
|
a8e77bddd4 | ||
|
|
d8eb7ce097 | ||
|
|
d0107d5cee | ||
|
|
a82be92577 | ||
|
|
730cd92d51 | ||
|
|
d3b5c77e5c | ||
|
|
f1b7ae7643 | ||
|
|
f952cd4bb5 | ||
|
|
32e61da588 | ||
|
|
c27197500c | ||
|
|
b5fbe6d55e | ||
|
|
291df87beb | ||
|
|
a661c6e711 | ||
|
|
e1d12cbd8e | ||
|
|
1e2a84608f | ||
|
|
88260ae4f3 | ||
|
|
3a8c1f97f1 | ||
|
|
0cc36b5ee2 | ||
|
|
d5c7d0028b | ||
|
|
3a0f60adc9 | ||
|
|
a575dfea7d | ||
|
|
515cf70295 | ||
|
|
fbabc54e03 | ||
|
|
059754fc28 | ||
|
|
cbc0579c79 | ||
|
|
da0bf650fa | ||
|
|
4de8bc742f | ||
|
|
93ba003e5b | ||
|
|
da476b29a6 | ||
|
|
5ee9633dc6 | ||
|
|
6d2e8d34fb | ||
|
|
a35e95a7dc | ||
|
|
126810a273 | ||
|
|
58e3e5293e | ||
|
|
8eff6493ec | ||
|
|
0227549207 | ||
|
|
ddf45d8485 | ||
|
|
6f151a6c5d | ||
|
|
9bfca83804 | ||
|
|
4b74d1b724 | ||
|
|
1067f16ce4 | ||
|
|
5896ebe9ca | ||
|
|
305cb3092e | ||
|
|
04c2a545f2 | ||
|
|
09fd43a3c9 | ||
|
|
d0c6a9756c | ||
|
|
b72f649b91 | ||
|
|
a78275814d | ||
|
|
c4fbdb32c4 | ||
|
|
4be4482957 | ||
|
|
8542823692 | ||
|
|
712b77b590 | ||
|
|
57cb31c86b | ||
|
|
7f04c98d61 | ||
|
|
15ea0bc63a | ||
|
|
50aaeb1465 | ||
|
|
a515385ae0 | ||
|
|
399021502f | ||
|
|
020f097584 | ||
|
|
5c56e75a60 | ||
|
|
f2afd524ef | ||
|
|
ea8ba2f9aa | ||
|
|
421541e88e | ||
|
|
84ddb3e380 | ||
|
|
ffc1c5d6ad | ||
|
|
0a325efeaf | ||
|
|
cd83a0b488 | ||
|
|
fe47783bfa | ||
|
|
6061883194 | ||
|
|
2d6b74ee9e | ||
|
|
feef4c148e | ||
|
|
6952401238 | ||
|
|
454c0e5543 | ||
|
|
1f5030fcbc | ||
|
|
78f4f532f7 | ||
|
|
18de424352 | ||
|
|
2224cc7593 | ||
|
|
5aad27edfc | ||
|
|
0b5d97bf3f | ||
|
|
e1aef42df8 | ||
|
|
f115630546 | ||
|
|
c6e86c494d | ||
|
|
cafcbfde90 | ||
|
|
632ce65bf5 | ||
|
|
b84d08f052 | ||
|
|
57eeefcf06 | ||
|
|
9227bbdfca | ||
|
|
a021967295 |
85
.appveyor/appveyor.yml
Normal file
85
.appveyor/appveyor.yml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
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:
|
||||||
|
# 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' )
|
||||||
|
{
|
||||||
|
$apiUrl = 'https://ci.appveyor.com/api'
|
||||||
|
$token = 'qts80b5kpq0ooj4x6vvw'
|
||||||
|
$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 = 'qts80b5kpq0ooj4x6vvw'
|
||||||
|
$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
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,4 +0,0 @@
|
|||||||
[submodule "Moose Development/Moose/Dcs"]
|
|
||||||
path = Moose Development/Moose/Dcs
|
|
||||||
url = https://github.com/FlightControl-Master/DCS-API.git
|
|
||||||
branch = master
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
rem This script will pull the latest changes from the remote repository, and update the submodules accordingly.
|
|
||||||
|
|
||||||
C:\Program Files (x86)\Git\bin\git pull
|
|
||||||
C:\Program Files (x86)\Git\bin\git submodule update --init
|
|
||||||
37
Moose Development/Debugger/MissionScripting.lua
Normal file
37
Moose Development/Debugger/MissionScripting.lua
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
--Initialization script for the Mission lua Environment (SSE)
|
||||||
|
|
||||||
|
dofile('Scripts/ScriptingSystem.lua')
|
||||||
|
|
||||||
|
-- Add LuaSocket to the LUAPATH, so that it can be found.
|
||||||
|
package.path = package.path..";.\\LuaSocket\\?.lua;"
|
||||||
|
|
||||||
|
-- Connect to the debugger, first require it.
|
||||||
|
local initconnection = require("debugger")
|
||||||
|
|
||||||
|
-- Now make the connection..
|
||||||
|
-- "127.0.0.1" is the localhost.
|
||||||
|
-- 10000 is the port. If you wanna use another port in LDT, change this number too!
|
||||||
|
-- "dcsserver" is the name of the server. If you wanna use another name, change the name here too!
|
||||||
|
-- nil (is for transport protocol, but not using this)
|
||||||
|
-- "win" don't touch. But is important to indicate that we are in a windows environment to the debugger script.
|
||||||
|
initconnection( "127.0.0.1", 10000, "dcsserver", nil, "win", "" )
|
||||||
|
|
||||||
|
|
||||||
|
--Sanitize Mission Scripting environment
|
||||||
|
--This makes unavailable some unsecure functions.
|
||||||
|
--Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions.
|
||||||
|
--You can remove the code below and make availble these functions at your own risk.
|
||||||
|
|
||||||
|
local function sanitizeModule(name)
|
||||||
|
_G[name] = nil
|
||||||
|
package.loaded[name] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
sanitizeModule('os')
|
||||||
|
--sanitizeModule('io')
|
||||||
|
sanitizeModule('lfs')
|
||||||
|
require = nil
|
||||||
|
loadlib = nil
|
||||||
|
end
|
||||||
56
Moose Development/Debugger/READ.ME
Normal file
56
Moose Development/Debugger/READ.ME
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
-- If you want to use the debugger, add 3 lines of extra code into MissionScripting.lua of DCS world.
|
||||||
|
-- De-sanitize the io module. The debugger needs it.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- MissionScripting.lua modifications
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- --Initialization script for the Mission lua Environment (SSE)
|
||||||
|
--
|
||||||
|
-- dofile('Scripts/ScriptingSystem.lua')
|
||||||
|
--
|
||||||
|
-- package.path = package.path..";.\\LuaSocket\\?.lua;"
|
||||||
|
-- local initconnection = require("debugger")
|
||||||
|
-- initconnection( "127.0.0.1", 10000, "dcsserver", nil, "win", "" )
|
||||||
|
--
|
||||||
|
-- --Sanitize Mission Scripting environment
|
||||||
|
-- --This makes unavailable some unsecure functions.
|
||||||
|
-- --Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions.
|
||||||
|
-- --You can remove the code below and make availble these functions at your own risk.
|
||||||
|
--
|
||||||
|
-- local function sanitizeModule(name)
|
||||||
|
-- _G[name] = nil
|
||||||
|
-- package.loaded[name] = nil
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- do
|
||||||
|
-- sanitizeModule('os')
|
||||||
|
-- --sanitizeModule('io')
|
||||||
|
-- sanitizeModule('lfs')
|
||||||
|
-- require = nil
|
||||||
|
-- loadlib = nil
|
||||||
|
-- end
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- So for clarity, these are the three lines of code that matter!
|
||||||
|
|
||||||
|
-- Add LuaSocket to the LUAPATH, so that it can be found.
|
||||||
|
package.path = package.path..";.\\LuaSocket\\?.lua;"
|
||||||
|
|
||||||
|
-- Connect to the debugger, first require it.
|
||||||
|
local initconnection = require("debugger")
|
||||||
|
|
||||||
|
-- Now make the connection..
|
||||||
|
-- "127.0.0.1" is the localhost.
|
||||||
|
-- 10000 is the port. If you wanna use another port in LDT, change this number too!
|
||||||
|
-- "dcsserver" is the name of the server. Ensure the same name is used at the Debug Configuration panel!
|
||||||
|
-- nil (is for transport protocol, but not using this)
|
||||||
|
-- "win" don't touch. But is important to indicate that we are in a windows environment to the debugger script.
|
||||||
|
initconnection( "127.0.0.1", 10000, "dcsserver", nil, "win", "" )
|
||||||
|
|
||||||
3482
Moose Development/Debugger/debugger.lua
Normal file
3482
Moose Development/Debugger/debugger.lua
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
|
||||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
|
||||||
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
|
|
||||||
</listAttribute>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Utils/GenerateDocumentations.bat}"/>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="*.lua"/>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Utils}"/>
|
|
||||||
</launchConfiguration>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
|
||||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
|
||||||
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
|
|
||||||
</listAttribute>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Utils/Generate_Moose.bat}"/>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value=""Moose_Create.lua" "D" "${current_date}" "${workspace_loc:/Moose_Framework//Moose Development/Moose}" "${workspace_loc:/Moose_Framework/Moose Mission Setup}""/>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Moose Mission Setup}"/>
|
|
||||||
</launchConfiguration>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
|
||||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
|
||||||
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
|
|
||||||
</listAttribute>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Utils/Generate_Moose.bat}"/>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value=""Moose_Create.lua" "S" "${current_date}" "${workspace_loc:/Moose_Framework//Moose Development/Moose}" "${workspace_loc:/Moose_Framework/Moose Mission Setup}""/>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Moose Mission Setup}"/>
|
|
||||||
</launchConfiguration>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
|
||||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
|
||||||
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
|
|
||||||
</listAttribute>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat}"/>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Missions}"/>
|
|
||||||
</launchConfiguration>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
|
||||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
|
||||||
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
|
|
||||||
</listAttribute>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat}"/>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value=""${selected_resource_loc}""/>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Moose Mission Setup/Moose Mission Update}"/>
|
|
||||||
</launchConfiguration>
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,16 +1,13 @@
|
|||||||
--- **AI** -- **AI A2A Air Patrolling or Staging.**
|
--- **AI** -- (R2.2) - Models the process of air operations for airplanes.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- ### 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.
|
|
||||||
--
|
--
|
||||||
-- ====
|
-- @module AI.AI_A2A
|
||||||
--
|
-- @image AI_Air_To_Air_Dispatching.JPG
|
||||||
-- @module AI_A2A
|
|
||||||
|
|
||||||
--BASE:TraceClass("AI_A2A")
|
--BASE:TraceClass("AI_A2A")
|
||||||
|
|
||||||
@@ -18,9 +15,7 @@
|
|||||||
--- @type AI_A2A
|
--- @type AI_A2A
|
||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
--- # AI_A2A class, extends @{Fsm#FSM_CONTROLLABLE}
|
--- The AI_A2A class implements the core functions to operate an AI @{Wrapper.Group} A2A tasking.
|
||||||
--
|
|
||||||
-- The AI_A2A class implements the core functions to operate an AI @{Group} A2A tasking.
|
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ## AI_A2A constructor
|
-- ## AI_A2A constructor
|
||||||
@@ -297,8 +292,8 @@ end
|
|||||||
|
|
||||||
--- Sets (modifies) the minimum and maximum speed of the patrol.
|
--- Sets (modifies) the minimum and maximum speed of the patrol.
|
||||||
-- @param #AI_A2A self
|
-- @param #AI_A2A self
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @return #AI_A2A self
|
-- @return #AI_A2A self
|
||||||
function AI_A2A:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
|
function AI_A2A:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
|
||||||
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
|
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
|
||||||
@@ -310,8 +305,8 @@ end
|
|||||||
|
|
||||||
--- Sets the floor and ceiling altitude of the patrol.
|
--- Sets the floor and ceiling altitude of the patrol.
|
||||||
-- @param #AI_A2A self
|
-- @param #AI_A2A self
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @return #AI_A2A self
|
-- @return #AI_A2A self
|
||||||
function AI_A2A:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
function AI_A2A:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
||||||
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
|
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
|
||||||
@@ -372,7 +367,6 @@ end
|
|||||||
-- @return #AI_A2A self
|
-- @return #AI_A2A self
|
||||||
function AI_A2A:SetFuelThreshold( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
|
function AI_A2A:SetFuelThreshold( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
|
||||||
|
|
||||||
self.PatrolManageFuel = true
|
|
||||||
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
|
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
|
||||||
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
|
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
|
||||||
|
|
||||||
@@ -406,7 +400,6 @@ end
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
function AI_A2A:onafterStart( Controllable, From, Event, To )
|
function AI_A2A:onafterStart( Controllable, From, Event, To )
|
||||||
self:F2()
|
|
||||||
|
|
||||||
self:__Status( 10 ) -- Check status status every 30 seconds.
|
self:__Status( 10 ) -- Check status status every 30 seconds.
|
||||||
|
|
||||||
@@ -429,8 +422,6 @@ end
|
|||||||
--- @param #AI_A2A self
|
--- @param #AI_A2A self
|
||||||
function AI_A2A:onafterStatus()
|
function AI_A2A:onafterStatus()
|
||||||
|
|
||||||
self:F( " Checking Status" )
|
|
||||||
|
|
||||||
if self.Controllable and self.Controllable:IsAlive() then
|
if self.Controllable and self.Controllable:IsAlive() then
|
||||||
|
|
||||||
local RTB = false
|
local RTB = false
|
||||||
@@ -457,8 +448,8 @@ function AI_A2A:onafterStatus()
|
|||||||
|
|
||||||
|
|
||||||
if not self:Is( "Fuel" ) and not self:Is( "Home" ) then
|
if not self:Is( "Fuel" ) and not self:Is( "Home" ) then
|
||||||
local Fuel = self.Controllable:GetFuel()
|
local Fuel = self.Controllable:GetFuelMin()
|
||||||
self:F({Fuel=Fuel})
|
self:F({Fuel=Fuel, PatrolFuelThresholdPercentage=self.PatrolFuelThresholdPercentage})
|
||||||
if Fuel < self.PatrolFuelThresholdPercentage then
|
if Fuel < self.PatrolFuelThresholdPercentage then
|
||||||
if self.TankerName then
|
if self.TankerName then
|
||||||
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
|
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
|
||||||
|
|||||||
@@ -1,45 +1,24 @@
|
|||||||
--- **AI** -- **Execute Combat Air Patrol (CAP).**
|
--- **AI** -- (R2.2) - Models the process of Combat Air Patrol (CAP) for airplanes.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- AI CAP classes makes AI Groups execute a Combat Air Patrol.
|
-- ### Author: **FlightControl**
|
||||||
--
|
--
|
||||||
-- There are the following types of CAP classes defined:
|
-- ===
|
||||||
--
|
|
||||||
-- * @{#AI_A2A_CAP}: Perform a CAP in a zone.
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
|
||||||
--
|
|
||||||
-- ### Contributions:
|
|
||||||
--
|
--
|
||||||
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
-- @module AI.AI_A2A_Cap
|
||||||
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing.
|
-- @image AI_Combat_Air_Patrol.JPG
|
||||||
-- * **[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.
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- @module AI_A2A_Cap
|
|
||||||
|
|
||||||
--BASE:TraceClass("AI_A2A_CAP")
|
|
||||||
|
|
||||||
--- @type AI_A2A_CAP
|
--- @type AI_A2A_CAP
|
||||||
-- @extends AI.AI_A2A_Patrol#AI_A2A_PATROL
|
-- @extends AI.AI_A2A_Patrol#AI_A2A_PATROL
|
||||||
|
|
||||||
|
|
||||||
--- # AI_A2A_CAP class, extends @{AI_CAP#AI_PATROL_ZONE}
|
--- 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 @{Zone} by an AI @{Group} or @{Group}
|
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_A2A_CAP is assigned a @{Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event.
|
-- The AI_A2A_CAP is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -82,15 +61,15 @@
|
|||||||
--
|
--
|
||||||
-- ### 2.2 AI_A2A_CAP Events
|
-- ### 2.2 AI_A2A_CAP Events
|
||||||
--
|
--
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
||||||
-- * **@{#AI_A2A_CAP.Engage}**: Let the AI engage the bogeys.
|
-- * **@{#AI_A2A_CAP.Engage}**: Let the AI engage the bogeys.
|
||||||
-- * **@{#AI_A2A_CAP.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
-- * **@{#AI_A2A_CAP.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Unit}.
|
-- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{Unit}s assigned in the CAS task.
|
-- * **@{#AI_A2A_CAP.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 tresholds have been reached, the AI will RTB.
|
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Set the Range of Engagement
|
-- ## 3. Set the Range of Engagement
|
||||||
@@ -101,7 +80,7 @@
|
|||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- 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 can be beyond or smaller than the range of the Patrol Zone.
|
||||||
-- The range is applied at the position of the AI.
|
-- The range is applied at the position of the AI.
|
||||||
-- Use the method @{AI_CAP#AI_A2A_CAP.SetEngageRange}() to define that range.
|
-- Use the method @{AI.AI_CAP#AI_A2A_CAP.SetEngageRange}() to define that range.
|
||||||
--
|
--
|
||||||
-- ## 4. Set the Zone of Engagement
|
-- ## 4. Set the Zone of Engagement
|
||||||
--
|
--
|
||||||
@@ -109,7 +88,7 @@
|
|||||||
--
|
--
|
||||||
-- An optional @{Zone} can be set,
|
-- An optional @{Zone} can be set,
|
||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- Use the method @{AI_Cap#AI_A2A_CAP.SetEngageZone}() to define that Zone.
|
-- Use the method @{AI.AI_Cap#AI_A2A_CAP.SetEngageZone}() to define that Zone.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -122,13 +101,13 @@ AI_A2A_CAP = {
|
|||||||
-- @param #AI_A2A_CAP self
|
-- @param #AI_A2A_CAP self
|
||||||
-- @param Wrapper.Group#GROUP AICap
|
-- @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 @{Zone} where the patrol needs to be executed.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
|
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
|
||||||
-- @param Dcs.DCSTypes#Speed EngageMinSpeed The minimum speed of the @{Group} in km/h when engaging a target.
|
-- @param DCS#Speed EngageMinSpeed The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||||
-- @param Dcs.DCSTypes#Speed EngageMaxSpeed The maximum speed of the @{Group} in km/h when engaging a target.
|
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||||
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
||||||
-- @return #AI_A2A_CAP
|
-- @return #AI_A2A_CAP
|
||||||
function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
|
function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
|
||||||
|
|
||||||
@@ -303,13 +282,14 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- onafter State Transition for Event Patrol.
|
--- onafter State Transition for Event Patrol.
|
||||||
-- @param #AI_A2A_GCI self
|
-- @param #AI_A2A_CAP self
|
||||||
-- @param Wrapper.Group#GROUP AICap The AI Group managed by the FSM.
|
-- @param Wrapper.Group#GROUP AICap The AI Group managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
function AI_A2A_CAP:onafterStart( AICap, From, Event, To )
|
function AI_A2A_CAP:onafterStart( AICap, From, Event, To )
|
||||||
|
|
||||||
|
self:GetParent( self ).onafterStart( self, AICap, From, Event, To )
|
||||||
AICap:HandleEvent( EVENTS.Takeoff, nil, self )
|
AICap:HandleEvent( EVENTS.Takeoff, nil, self )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +1,24 @@
|
|||||||
--- **AI** - The AI_A2A_DISPATCHER creates an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.
|
--- **AI** - (R2.2) - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- Features:
|
||||||
|
--
|
||||||
|
-- * Setup quickly an A2A defense system for a coalition.
|
||||||
|
-- * Setup (CAP) Control Air Patrols at defined zones to enhance your A2A defenses.
|
||||||
|
-- * Setup (GCI) Ground Control Intercept at defined airbases to enhance your A2A defenses.
|
||||||
|
-- * Define and use an EWR (Early Warning Radar) network.
|
||||||
|
-- * Define squadrons at airbases.
|
||||||
|
-- * Enable airbases for A2A defenses.
|
||||||
|
-- * Add different plane types to different squadrons.
|
||||||
|
-- * Add multiple squadrons to different airbases.
|
||||||
|
-- * Define different ranges to engage upon intruders.
|
||||||
|
-- * Establish an automatic in air refuel process for CAP using refuel tankers.
|
||||||
|
-- * Setup default settings for all squadrons and A2A defenses.
|
||||||
|
-- * Setup specific settings for specific squadrons.
|
||||||
|
-- * Quickly setup an A2A defense system using @{#AI_A2A_GCICAP}.
|
||||||
|
-- * Setup a more advanced defense system using @{#AI_A2A_DISPATCHER}.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
--
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # QUICK START GUIDE
|
-- # QUICK START GUIDE
|
||||||
--
|
--
|
||||||
-- There are basically two classes available to model an A2A defense system.
|
-- There are basically two classes available to model an A2A defense system.
|
||||||
@@ -150,10 +165,11 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Authors: **Sven Van de Velde (FlightControl)** rework of GCICAP + introduction of new concepts (squadrons).
|
-- ### Authors: **FlightControl** rework of GCICAP + introduction of new concepts (squadrons).
|
||||||
-- ### Authors: **Stonehouse**, **SNAFU** in terms of the advice, documentation, and the original GCICAP script.
|
-- ### Authors: **Stonehouse**, **SNAFU** in terms of the advice, documentation, and the original GCICAP script.
|
||||||
--
|
--
|
||||||
-- @module AI_A2A_Dispatcher
|
-- @module AI.AI_A2A_Dispatcher
|
||||||
|
-- @image AI_Air_To_Air_Dispatching.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -163,19 +179,15 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- @type AI_A2A_DISPATCHER
|
-- @type AI_A2A_DISPATCHER
|
||||||
-- @extends Tasking.DetectionManager#DETECTION_MANAGER
|
-- @extends Tasking.DetectionManager#DETECTION_MANAGER
|
||||||
|
|
||||||
--- # AI\_A2A\_DISPATCHER class, extends @{Tasking#DETECTION_MANAGER}
|
--- Create an automatic air defence system for a coalition.
|
||||||
--
|
--
|
||||||
-- 
|
-- ===
|
||||||
--
|
|
||||||
-- The @{#AI_A2A_DISPATCHER} class is designed to create an automatic air defence system for a coalition.
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
--
|
||||||
-- # Demo Missions
|
-- # Demo Missions
|
||||||
--
|
--
|
||||||
-- ### [AI\_A2A\_DISPATCHER Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching)
|
-- ### [AI\_A2A\_DISPATCHER Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching)
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # YouTube Channel
|
-- # YouTube Channel
|
||||||
--
|
--
|
||||||
@@ -227,7 +239,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map.
|
-- therefore less CAP and GCI flights will spawn and this will tend to make just the border area active rather than a melee over the whole map.
|
||||||
-- It all depends on what the desired effect is.
|
-- It all depends on what the desired effect is.
|
||||||
--
|
--
|
||||||
-- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional#DETECTION_BASE} object that is given as the input parameter of the AI\_A2A\_DISPATCHER class.
|
-- EWR networks are **dynamically constructed**, that is, they form part of the @{Functional.Detection#DETECTION_BASE} object that is given as the input parameter of the AI\_A2A\_DISPATCHER class.
|
||||||
-- By defining in a **smart way the names or name prefixes of the groups** with EWR capable units, these groups will be **automatically added or deleted** from the EWR network,
|
-- By defining in a **smart way the names or name prefixes of the groups** with EWR capable units, these groups will be **automatically added or deleted** from the EWR network,
|
||||||
-- increasing or decreasing the radar coverage of the Early Warning System.
|
-- increasing or decreasing the radar coverage of the Early Warning System.
|
||||||
--
|
--
|
||||||
@@ -344,7 +356,7 @@ 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 @{Zone#ZONE_BASE}.
|
-- 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 a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than
|
-- 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.
|
-- 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.
|
-- In a hot war the borders are effectively defined by the ground based radar coverage of a coalition.
|
||||||
@@ -542,18 +554,18 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- * As the CAP flights wander around within the zone waiting to be tasked, these zones need to be large enough that the aircraft are not constantly turning
|
-- * As the CAP flights wander around within the zone waiting to be tasked, these zones need to be large enough that the aircraft are not constantly turning
|
||||||
-- but do not have to be big and numerous enough to completely cover a border.
|
-- but do not have to be big and numerous enough to completely cover a border.
|
||||||
--
|
--
|
||||||
-- * CAP zones can be of any type, and are derived from the @{Zone#ZONE_BASE} class. Zones can be @{Zone#ZONE}, @{Zone#ZONE_POLYGON}, @{Zone#ZONE_UNIT}, @{Zone#ZONE_GROUP}, etc.
|
-- * CAP zones can be of any type, and are derived from the @{Core.Zone#ZONE_BASE} class. Zones can be @{Core.Zone#ZONE}, @{Core.Zone#ZONE_POLYGON}, @{Core.Zone#ZONE_UNIT}, @{Core.Zone#ZONE_GROUP}, etc.
|
||||||
-- This allows to setup **static, moving and/or complex zones** wherein aircraft will perform the CAP.
|
-- This allows to setup **static, moving and/or complex zones** wherein aircraft will perform the CAP.
|
||||||
--
|
--
|
||||||
-- * Typically 20000-50000 metres width is used and they are spaced so that aircraft in the zone waiting for tasks don’t have to far to travel to protect their coalitions important targets.
|
-- * Typically 20000-50000 metres width is used and they are spaced so that aircraft in the zone waiting for tasks don't have to far to travel to protect their coalitions important targets.
|
||||||
-- These targets are chosen as part of the mission design and might be an important airfield or town etc.
|
-- These targets are chosen as part of the mission design and might be an important airfield or town etc.
|
||||||
-- Zone size is also determined somewhat by territory size, plane types
|
-- Zone size is also determined somewhat by territory size, plane types
|
||||||
-- (eg WW2 aircraft might mean smaller zones or more zones because they are slower and take longer to intercept enemy aircraft).
|
-- (eg WW2 aircraft might mean smaller zones or more zones because they are slower and take longer to intercept enemy aircraft).
|
||||||
--
|
--
|
||||||
-- * In a **cold war** it is important to make sure a CAP zone doesn’t intrude into enemy territory as otherwise CAP flights will likely cross borders
|
-- * In a **cold war** it is important to make sure a CAP zone doesn't intrude into enemy territory as otherwise CAP flights will likely cross borders
|
||||||
-- and spark a full scale conflict which will escalate rapidly.
|
-- and spark a full scale conflict which will escalate rapidly.
|
||||||
--
|
--
|
||||||
-- * CAP flights do not need to be in the CAP zone before they are “on station” and ready for tasking.
|
-- * CAP flights do not need to be in the CAP zone before they are "on station" and ready for tasking.
|
||||||
--
|
--
|
||||||
-- * Typically if a CAP flight is tasked and therefore leaves their zone empty while they go off and intercept their target another CAP flight will spawn to take their place.
|
-- * Typically if a CAP flight is tasked and therefore leaves their zone empty while they go off and intercept their target another CAP flight will spawn to take their place.
|
||||||
--
|
--
|
||||||
@@ -738,7 +750,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--
|
--
|
||||||
-- In the mission editor, setup a group with task Refuelling. A tanker unit of the correct coalition will be automatically selected.
|
-- In the mission editor, setup a group with task Refuelling. A tanker unit of the correct coalition will be automatically selected.
|
||||||
-- Then, use the method @{#AI_A2A_DISPATCHER.SetDefaultTanker}() to set the tanker for the dispatcher.
|
-- Then, use the method @{#AI_A2A_DISPATCHER.SetDefaultTanker}() to set the tanker for the dispatcher.
|
||||||
-- Use the method @{#AI_A2A_DISPATCHER.SetDefaultFuelTreshold}() to set the %-tage left in the defender airplane tanks when a refuel action is needed.
|
-- Use the method @{#AI_A2A_DISPATCHER.SetDefaultFuelThreshold}() to set the %-tage left in the defender airplane tanks when a refuel action is needed.
|
||||||
--
|
--
|
||||||
-- When the tanker specified is alive and in the air, the tanker will be used for refuelling.
|
-- When the tanker specified is alive and in the air, the tanker will be used for refuelling.
|
||||||
--
|
--
|
||||||
@@ -793,11 +805,11 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- For example because the mission calls for a EWR radar on the blue side the Ukraine might be chosen as a blue country
|
-- For example because the mission calls for a EWR radar on the blue side the Ukraine might be chosen as a blue country
|
||||||
-- so that the 55G6 EWR radar unit is available to blue.
|
-- so that the 55G6 EWR radar unit is available to blue.
|
||||||
-- Some countries assign different tasking to aircraft, for example Germany assigns the CAP task to F-4E Phantoms but the USA does not.
|
-- Some countries assign different tasking to aircraft, for example Germany assigns the CAP task to F-4E Phantoms but the USA does not.
|
||||||
-- Therefore if F4s are wanted as a coalition’s CAP or GCI aircraft Germany will need to be assigned to that coalition.
|
-- Therefore if F4s are wanted as a coalition's CAP or GCI aircraft Germany will need to be assigned to that coalition.
|
||||||
--
|
--
|
||||||
-- ### 11.2. Country, type, load out, skill and skins for CAP and GCI aircraft?
|
-- ### 11.2. Country, type, load out, skill and skins for CAP and GCI aircraft?
|
||||||
--
|
--
|
||||||
-- * Note these can be from any countries within the coalition but must be an aircraft with one of the main tasks being “CAP”.
|
-- * Note these can be from any countries within the coalition but must be an aircraft with one of the main tasks being "CAP".
|
||||||
-- * Obviously skins which are selected must be available to all players that join the mission otherwise they will see a default skin.
|
-- * Obviously skins which are selected must be available to all players that join the mission otherwise they will see a default skin.
|
||||||
-- * Load outs should be appropriate to a CAP mission eg perhaps drop tanks for CAP flights and extra missiles for GCI flights.
|
-- * Load outs should be appropriate to a CAP mission eg perhaps drop tanks for CAP flights and extra missiles for GCI flights.
|
||||||
-- * These decisions will eventually lead to template aircraft units being placed as late activation units that the script will use as templates for spawning CAP and GCI flights. Up to 4 different aircraft configurations can be chosen for each coalition. The spawned aircraft will inherit the characteristics of the template aircraft.
|
-- * These decisions will eventually lead to template aircraft units being placed as late activation units that the script will use as templates for spawning CAP and GCI flights. Up to 4 different aircraft configurations can be chosen for each coalition. The spawned aircraft will inherit the characteristics of the template aircraft.
|
||||||
@@ -828,7 +840,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
--- AI_A2A_DISPATCHER constructor.
|
--- AI_A2A_DISPATCHER constructor.
|
||||||
-- This is defining the A2A DISPATCHER for one coaliton.
|
-- This is defining the A2A DISPATCHER for one coaliton.
|
||||||
-- The Dispatcher works with a @{Functional#Detection} object that is taking of the detection of targets using the EWR units.
|
-- The Dispatcher works with a @{Functional.Detection#DETECTION_BASE} object that is taking of the detection of targets using the EWR units.
|
||||||
-- The Detection object is polymorphic, depending on the type of detection object choosen, the detection will work differently.
|
-- The Detection object is polymorphic, depending on the type of detection object choosen, the detection will work differently.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param Functional.Detection#DETECTION_BASE Detection The DETECTION object that will detects targets using the the Early Warning Radar network.
|
-- @param Functional.Detection#DETECTION_BASE Detection The DETECTION object that will detects targets using the the Early Warning Radar network.
|
||||||
@@ -981,6 +993,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
self:HandleEvent( EVENTS.Crash, self.OnEventCrashOrDead )
|
self:HandleEvent( EVENTS.Crash, self.OnEventCrashOrDead )
|
||||||
self:HandleEvent( EVENTS.Dead, self.OnEventCrashOrDead )
|
self:HandleEvent( EVENTS.Dead, self.OnEventCrashOrDead )
|
||||||
|
--self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCrashOrDead )
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Land )
|
self:HandleEvent( EVENTS.Land )
|
||||||
self:HandleEvent( EVENTS.EngineShutdown )
|
self:HandleEvent( EVENTS.EngineShutdown )
|
||||||
@@ -1001,7 +1014,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--- @param #AI_A2A_DISPATCHER self
|
--- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_A2A_DISPATCHER:OnEventLand( EventData )
|
function AI_A2A_DISPATCHER:OnEventLand( EventData )
|
||||||
self:E( "Landed" )
|
self:F( "Landed" )
|
||||||
local DefenderUnit = EventData.IniUnit
|
local DefenderUnit = EventData.IniUnit
|
||||||
local Defender = EventData.IniGroup
|
local Defender = EventData.IniGroup
|
||||||
local Squadron = self:GetSquadronFromDefender( Defender )
|
local Squadron = self:GetSquadronFromDefender( Defender )
|
||||||
@@ -1021,10 +1034,6 @@ do -- AI_A2A_DISPATCHER
|
|||||||
DefenderUnit:Destroy()
|
DefenderUnit:Destroy()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if DefenderUnit:GetFuel() <= self.DefenderDefault.FuelThreshold then
|
|
||||||
DefenderUnit:Destroy()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1037,7 +1046,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
if Squadron then
|
if Squadron then
|
||||||
self:F( { SquadronName = Squadron.Name } )
|
self:F( { SquadronName = Squadron.Name } )
|
||||||
local LandingMethod = self:GetSquadronLanding( Squadron.Name )
|
local LandingMethod = self:GetSquadronLanding( Squadron.Name )
|
||||||
if LandingMethod == AI_A2A_DISPATCHER.Landing.AtEngineShutdown then
|
if LandingMethod == AI_A2A_DISPATCHER.Landing.AtEngineShutdown and
|
||||||
|
not DefenderUnit:InAir() then
|
||||||
local DefenderSize = Defender:GetSize()
|
local DefenderSize = Defender:GetSize()
|
||||||
if DefenderSize == 1 then
|
if DefenderSize == 1 then
|
||||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
@@ -1140,7 +1150,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--- Define a border area to simulate a **cold war** scenario.
|
--- 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 **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.
|
-- 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 @{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 @{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
|
-- 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 #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.
|
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
|
||||||
@@ -1274,7 +1284,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--- Calculates which AI friendlies are nearby the area
|
--- Calculates which AI friendlies are nearby the area
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param DetectedItem
|
-- @param DetectedItem
|
||||||
-- @return #number, Core.CommandCenter#REPORT
|
-- @return #table A list of the friendlies nearby.
|
||||||
function AI_A2A_DISPATCHER:GetAIFriendliesNearBy( DetectedItem )
|
function AI_A2A_DISPATCHER:GetAIFriendliesNearBy( DetectedItem )
|
||||||
|
|
||||||
local FriendliesNearBy = self.Detection:GetFriendliesDistance( DetectedItem )
|
local FriendliesNearBy = self.Detection:GetFriendliesDistance( DetectedItem )
|
||||||
@@ -1421,11 +1431,11 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- You need to specify here EXACTLY the name of the airbase as you see it in the mission editor.
|
-- You need to specify here EXACTLY the name of the airbase as you see it in the mission editor.
|
||||||
-- Examples are `"Batumi"` or `"Tbilisi-Lochini"`.
|
-- Examples are `"Batumi"` or `"Tbilisi-Lochini"`.
|
||||||
-- EXACTLY the airbase name, between quotes `""`.
|
-- EXACTLY the airbase name, between quotes `""`.
|
||||||
-- To ease the airbase naming when using the LDT editor and IntelliSense, the @{Airbase#AIRBASE} class contains enumerations of the airbases of each map.
|
-- To ease the airbase naming when using the LDT editor and IntelliSense, the @{Wrapper.Airbase#AIRBASE} class contains enumerations of the airbases of each map.
|
||||||
--
|
--
|
||||||
-- * Caucasus: @{Airbase#AIRBASE.Caucaus}
|
-- * Caucasus: @{Wrapper.Airbase#AIRBASE.Caucaus}
|
||||||
-- * Nevada or NTTR: @{Airbase#AIRBASE.Nevada}
|
-- * Nevada or NTTR: @{Wrapper.Airbase#AIRBASE.Nevada}
|
||||||
-- * Normandy: @{Airbase#AIRBASE.Normandy}
|
-- * Normandy: @{Wrapper.Airbase#AIRBASE.Normandy}
|
||||||
--
|
--
|
||||||
-- @param #string TemplatePrefixes A string or an array of strings specifying the **prefix names of the templates** (not going to explain what is templates here again).
|
-- @param #string TemplatePrefixes A string or an array of strings specifying the **prefix names of the templates** (not going to explain what is templates here again).
|
||||||
-- Examples are `{ "104th", "105th" }` or `"104th"` or `"Template 1"` or `"BLUE PLANES"`.
|
-- Examples are `{ "104th", "105th" }` or `"104th"` or `"Template 1"` or `"BLUE PLANES"`.
|
||||||
@@ -1488,7 +1498,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
DefenderSquadron.Resources = Resources
|
DefenderSquadron.Resources = Resources
|
||||||
DefenderSquadron.TemplatePrefixes = TemplatePrefixes
|
DefenderSquadron.TemplatePrefixes = TemplatePrefixes
|
||||||
|
|
||||||
self:E( { Squadron = {SquadronName, AirbaseName, TemplatePrefixes, Resources } } )
|
self:F( { Squadron = {SquadronName, AirbaseName, TemplatePrefixes, Resources } } )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1510,7 +1520,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--- Set a CAP for a Squadron.
|
--- Set a CAP for a Squadron.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
|
-- @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 #number FloorAltitude The minimum altitude at which the cap can be executed.
|
-- @param #number FloorAltitude The minimum altitude at which the cap can be executed.
|
||||||
-- @param #number CeilingAltitude the maximum altitude at which the cap can be executed.
|
-- @param #number CeilingAltitude the maximum altitude at which the cap can be executed.
|
||||||
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
||||||
@@ -1554,7 +1564,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
self:SetSquadronCapInterval( SquadronName, self.DefenderDefault.CapLimit, self.DefenderDefault.CapMinSeconds, self.DefenderDefault.CapMaxSeconds, 1 )
|
self:SetSquadronCapInterval( SquadronName, self.DefenderDefault.CapLimit, self.DefenderDefault.CapMinSeconds, self.DefenderDefault.CapMaxSeconds, 1 )
|
||||||
|
|
||||||
self:E( { CAP = { SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType } } )
|
self:F( { CAP = { SquadronName, Zone, FloorAltitude, CeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, AltType } } )
|
||||||
|
|
||||||
-- Add the CAP to the EWR network.
|
-- Add the CAP to the EWR network.
|
||||||
|
|
||||||
@@ -1658,7 +1668,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local Cap = DefenderSquadron.Cap
|
local Cap = DefenderSquadron.Cap
|
||||||
if Cap then
|
if Cap then
|
||||||
local CapCount = self:CountCapAirborne( SquadronName )
|
local CapCount = self:CountCapAirborne( SquadronName )
|
||||||
self:E( { CapCount = CapCount } )
|
self:F( { CapCount = CapCount } )
|
||||||
if CapCount < Cap.CapLimit then
|
if CapCount < Cap.CapLimit then
|
||||||
local Probability = math.random()
|
local Probability = math.random()
|
||||||
if Probability <= Cap.Probability then
|
if Probability <= Cap.Probability then
|
||||||
@@ -1716,7 +1726,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
Intercept.EngageMinSpeed = EngageMinSpeed
|
Intercept.EngageMinSpeed = EngageMinSpeed
|
||||||
Intercept.EngageMaxSpeed = EngageMaxSpeed
|
Intercept.EngageMaxSpeed = EngageMaxSpeed
|
||||||
|
|
||||||
self:E( { GCI = { SquadronName, EngageMinSpeed, EngageMaxSpeed } } )
|
self:F( { GCI = { SquadronName, EngageMinSpeed, EngageMaxSpeed } } )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Defines the default amount of extra planes that will take-off as part of the defense system.
|
--- Defines the default amount of extra planes that will take-off as part of the defense system.
|
||||||
@@ -2355,7 +2365,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- A2ADispatcher = AI_A2A_DISPATCHER:New( Detection )
|
-- A2ADispatcher = AI_A2A_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default fuel treshold.
|
-- -- Now Setup the default fuel treshold.
|
||||||
-- A2ADispatcher:SetDefaultRefuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- A2ADispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
function AI_A2A_DISPATCHER:SetDefaultFuelThreshold( FuelThreshold )
|
function AI_A2A_DISPATCHER:SetDefaultFuelThreshold( FuelThreshold )
|
||||||
|
|
||||||
@@ -2389,7 +2399,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
--- Set the default tanker where defenders will Refuel in the air.
|
--- Set the default tanker where defenders will Refuel in the air.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param #strig TankerName A string defining the group name of the Tanker as defined within the Mission Editor.
|
-- @param #string TankerName A string defining the group name of the Tanker as defined within the Mission Editor.
|
||||||
-- @return #AI_A2A_DISPATCHER
|
-- @return #AI_A2A_DISPATCHER
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -2397,7 +2407,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- A2ADispatcher = AI_A2A_DISPATCHER:New( Detection )
|
-- A2ADispatcher = AI_A2A_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default fuel treshold.
|
-- -- Now Setup the default fuel treshold.
|
||||||
-- A2ADispatcher:SetDefaultRefuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- A2ADispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default tanker.
|
-- -- Now Setup the default tanker.
|
||||||
-- A2ADispatcher:SetDefaultTanker( "Tanker" ) -- The group name of the tanker is "Tanker" in the Mission Editor.
|
-- A2ADispatcher:SetDefaultTanker( "Tanker" ) -- The group name of the tanker is "Tanker" in the Mission Editor.
|
||||||
@@ -2412,7 +2422,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--- Set the squadron tanker where defenders will Refuel in the air.
|
--- Set the squadron tanker where defenders will Refuel in the air.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param #string SquadronName The name of the squadron.
|
-- @param #string SquadronName The name of the squadron.
|
||||||
-- @param #strig TankerName A string defining the group name of the Tanker as defined within the Mission Editor.
|
-- @param #string TankerName A string defining the group name of the Tanker as defined within the Mission Editor.
|
||||||
-- @return #AI_A2A_DISPATCHER
|
-- @return #AI_A2A_DISPATCHER
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -2443,7 +2453,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
if Squadron.Resources then
|
if Squadron.Resources then
|
||||||
Squadron.Resources = Squadron.Resources - Size
|
Squadron.Resources = Squadron.Resources - Size
|
||||||
end
|
end
|
||||||
self:E( { DefenderName = DefenderName, SquadronResources = Squadron.Resources } )
|
self:F( { DefenderName = DefenderName, SquadronResources = Squadron.Resources } )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_A2A_DISPATCHER self
|
--- @param #AI_A2A_DISPATCHER self
|
||||||
@@ -2468,7 +2478,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--- Creates an SWEEP task when there are targets for it.
|
--- Creates an SWEEP task when there are targets for it.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
||||||
-- @return Set#SET_UNIT TargetSetUnit: The target set of units.
|
-- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units.
|
||||||
-- @return #nil If there are no targets to be set.
|
-- @return #nil If there are no targets to be set.
|
||||||
function AI_A2A_DISPATCHER:EvaluateSWEEP( DetectedItem )
|
function AI_A2A_DISPATCHER:EvaluateSWEEP( DetectedItem )
|
||||||
self:F( { DetectedItem.ItemID } )
|
self:F( { DetectedItem.ItemID } )
|
||||||
@@ -2504,7 +2514,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
if AIGroup:IsAlive() then
|
if AIGroup:IsAlive() then
|
||||||
-- Check if the CAP is patrolling or engaging. If not, this is not a valid CAP, even if it is alive!
|
-- Check if the CAP is patrolling or engaging. If not, this is not a valid CAP, even if it is alive!
|
||||||
-- The CAP could be damaged, lost control, or out of fuel!
|
-- The CAP could be damaged, lost control, or out of fuel!
|
||||||
if DefenderTask.Fsm:Is( "Patrolling" ) or DefenderTask.Fsm:Is( "Engaging" ) or DefenderTask.Fsm:Is( "Refuelling" )then
|
if DefenderTask.Fsm:Is( "Patrolling" ) or DefenderTask.Fsm:Is( "Engaging" ) or DefenderTask.Fsm:Is( "Refuelling" )
|
||||||
|
or DefenderTask.Fsm:Is( "Started" ) then
|
||||||
CapCount = CapCount + 1
|
CapCount = CapCount + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2524,9 +2535,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- First, count the active AIGroups Units, targetting the DetectedSet
|
-- First, count the active AIGroups Units, targetting the DetectedSet
|
||||||
local DefenderCount = 0
|
local DefenderCount = 0
|
||||||
|
|
||||||
self:E( "Counting Defenders Engaged for Attacker:" )
|
|
||||||
local DetectedSet = AttackerDetection.Set
|
local DetectedSet = AttackerDetection.Set
|
||||||
DetectedSet:Flush()
|
--DetectedSet:Flush()
|
||||||
|
|
||||||
local DefenderTasks = self:GetDefenderTasks()
|
local DefenderTasks = self:GetDefenderTasks()
|
||||||
for DefenderGroup, DefenderTask in pairs( DefenderTasks ) do
|
for DefenderGroup, DefenderTask in pairs( DefenderTasks ) do
|
||||||
@@ -2539,8 +2549,12 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local SquadronOverhead = Squadron.Overhead or self.DefenderDefault.Overhead
|
local SquadronOverhead = Squadron.Overhead or self.DefenderDefault.Overhead
|
||||||
|
|
||||||
local DefenderSize = Defender:GetInitialSize()
|
local DefenderSize = Defender:GetInitialSize()
|
||||||
DefenderCount = DefenderCount + DefenderSize / SquadronOverhead
|
if DefenderSize then
|
||||||
self:F( "Defender Group Name: " .. Defender:GetName() .. ", Size: " .. DefenderSize )
|
DefenderCount = DefenderCount + DefenderSize / SquadronOverhead
|
||||||
|
self:F( "Defender Group Name: " .. Defender:GetName() .. ", Size: " .. DefenderSize )
|
||||||
|
else
|
||||||
|
DefenderCount = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2610,7 +2624,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
if Cap then
|
if Cap then
|
||||||
|
|
||||||
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Functional.Spawn#SPAWN
|
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Core.Spawn#SPAWN
|
||||||
local DefenderGrouping = DefenderSquadron.Grouping or self.DefenderDefault.Grouping
|
local DefenderGrouping = DefenderSquadron.Grouping or self.DefenderDefault.Grouping
|
||||||
Spawn:InitGrouping( DefenderGrouping )
|
Spawn:InitGrouping( DefenderGrouping )
|
||||||
|
|
||||||
@@ -2652,7 +2666,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
--- @param #AI_A2A_DISPATCHER self
|
--- @param #AI_A2A_DISPATCHER self
|
||||||
function Fsm:onafterHome( Defender, From, Event, To, Action )
|
function Fsm:onafterHome( Defender, From, Event, To, Action )
|
||||||
self:E({"CAP Home", Defender:GetName()})
|
self:F({"CAP Home", Defender:GetName()})
|
||||||
self:GetParent(self).onafterHome( self, Defender, From, Event, To )
|
self:GetParent(self).onafterHome( self, Defender, From, Event, To )
|
||||||
|
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
||||||
@@ -2783,7 +2797,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
while ( DefendersNeeded > 0 ) do
|
while ( DefendersNeeded > 0 ) do
|
||||||
|
|
||||||
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Functional.Spawn#SPAWN
|
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Core.Spawn#SPAWN
|
||||||
local DefenderGrouping = ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded
|
local DefenderGrouping = ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded
|
||||||
if DefenderGrouping then
|
if DefenderGrouping then
|
||||||
Spawn:InitGrouping( DefenderGrouping )
|
Spawn:InitGrouping( DefenderGrouping )
|
||||||
@@ -2793,7 +2807,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName )
|
local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName )
|
||||||
local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod, DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude ) -- Wrapper.Group#GROUP
|
local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod, DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude ) -- Wrapper.Group#GROUP
|
||||||
self:E( { GCIDefender = DefenderGCI:GetName() } )
|
self:F( { GCIDefender = DefenderGCI:GetName() } )
|
||||||
|
|
||||||
DefendersNeeded = DefendersNeeded - DefenderGrouping
|
DefendersNeeded = DefendersNeeded - DefenderGrouping
|
||||||
|
|
||||||
@@ -2888,8 +2902,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
--- Creates an ENGAGE task when there are human friendlies airborne near the targets.
|
--- Creates an ENGAGE task when there are human friendlies airborne near the targets.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem The detected item.
|
||||||
-- @return Set#SET_UNIT TargetSetUnit: The target set of units.
|
-- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units.
|
||||||
-- @return #nil If there are no targets to be set.
|
-- @return #nil If there are no targets to be set.
|
||||||
function AI_A2A_DISPATCHER:EvaluateENGAGE( DetectedItem )
|
function AI_A2A_DISPATCHER:EvaluateENGAGE( DetectedItem )
|
||||||
self:F( { DetectedItem.ItemID } )
|
self:F( { DetectedItem.ItemID } )
|
||||||
@@ -2915,8 +2929,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
--- Creates an GCI task when there are targets for it.
|
--- Creates an GCI task when there are targets for it.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem The detected item.
|
||||||
-- @return Set#SET_UNIT TargetSetUnit: The target set of units.
|
-- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units.
|
||||||
-- @return #nil If there are no targets to be set.
|
-- @return #nil If there are no targets to be set.
|
||||||
function AI_A2A_DISPATCHER:EvaluateGCI( DetectedItem )
|
function AI_A2A_DISPATCHER:EvaluateGCI( DetectedItem )
|
||||||
self:F( { DetectedItem.ItemID } )
|
self:F( { DetectedItem.ItemID } )
|
||||||
@@ -2942,7 +2956,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
--- Assigns A2A AI Tasks in relation to the detected items.
|
--- Assigns A2A AI Tasks in relation to the detected items.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Detection#DETECTION_BASE} derived object.
|
-- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object.
|
||||||
-- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop.
|
-- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop.
|
||||||
function AI_A2A_DISPATCHER:ProcessDetected( Detection )
|
function AI_A2A_DISPATCHER:ProcessDetected( Detection )
|
||||||
|
|
||||||
@@ -2957,13 +2971,13 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local AIGroup = AIGroup -- Wrapper.Group#GROUP
|
local AIGroup = AIGroup -- Wrapper.Group#GROUP
|
||||||
if not AIGroup:IsAlive() then
|
if not AIGroup:IsAlive() then
|
||||||
local DefenderTaskFsm = self:GetDefenderTaskFsm( AIGroup )
|
local DefenderTaskFsm = self:GetDefenderTaskFsm( AIGroup )
|
||||||
self:E( { Defender = AIGroup:GetName(), DefenderState = DefenderTaskFsm:GetState() } )
|
self:F( { Defender = AIGroup:GetName(), DefenderState = DefenderTaskFsm:GetState() } )
|
||||||
if not DefenderTaskFsm:Is( "Started" ) then
|
if not DefenderTaskFsm:Is( "Started" ) then
|
||||||
self:ClearDefenderTask( AIGroup )
|
self:ClearDefenderTask( AIGroup )
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if DefenderTask.Target then
|
if DefenderTask.Target then
|
||||||
local AttackerItem = Detection:GetDetectedItem( DefenderTask.Target.Index )
|
local AttackerItem = Detection:GetDetectedItemByIndex( DefenderTask.Target.Index )
|
||||||
if not AttackerItem then
|
if not AttackerItem then
|
||||||
self:F( { "Removing obsolete Target:", DefenderTask.Target.Index } )
|
self:F( { "Removing obsolete Target:", DefenderTask.Target.Index } )
|
||||||
self:ClearDefenderTaskTarget( AIGroup )
|
self:ClearDefenderTaskTarget( AIGroup )
|
||||||
@@ -2982,6 +2996,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
local Report = REPORT:New( "\nTactical Overview" )
|
local Report = REPORT:New( "\nTactical Overview" )
|
||||||
|
|
||||||
|
local DefenderGroupCount = 0
|
||||||
|
|
||||||
-- Now that all obsolete tasks are removed, loop through the detected targets.
|
-- Now that all obsolete tasks are removed, loop through the detected targets.
|
||||||
for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do
|
for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do
|
||||||
|
|
||||||
@@ -2991,7 +3007,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local DetectedZone = DetectedItem.Zone
|
local DetectedZone = DetectedItem.Zone
|
||||||
|
|
||||||
self:F( { "Target ID", DetectedItem.ItemID } )
|
self:F( { "Target ID", DetectedItem.ItemID } )
|
||||||
DetectedSet:Flush()
|
DetectedSet:Flush( self )
|
||||||
|
|
||||||
local DetectedID = DetectedItem.ID
|
local DetectedID = DetectedItem.ID
|
||||||
local DetectionIndex = DetectedItem.Index
|
local DetectionIndex = DetectedItem.Index
|
||||||
@@ -3007,7 +3023,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
do
|
do
|
||||||
local DefendersMissing, Friendlies = self:EvaluateGCI( DetectedItem )
|
local DefendersMissing, Friendlies = self:EvaluateGCI( DetectedItem )
|
||||||
if DefendersMissing then
|
if DefendersMissing and DefendersMissing > 0 then
|
||||||
self:F( { DefendersMissing = DefendersMissing } )
|
self:F( { DefendersMissing = DefendersMissing } )
|
||||||
self:GCI( DetectedItem, DefendersMissing, Friendlies )
|
self:GCI( DetectedItem, DefendersMissing, Friendlies )
|
||||||
end
|
end
|
||||||
@@ -3019,16 +3035,19 @@ do -- AI_A2A_DISPATCHER
|
|||||||
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||||
local Defender = Defender -- Wrapper.Group#GROUP
|
local Defender = Defender -- Wrapper.Group#GROUP
|
||||||
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
||||||
local Fuel = Defender:GetFuel() * 100
|
if Defender:IsAlive() then
|
||||||
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
|
DefenderGroupCount = DefenderGroupCount + 1
|
||||||
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
|
local Fuel = Defender:GetFuelMin() * 100
|
||||||
Defender:GetName(),
|
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
|
||||||
DefenderTask.Type,
|
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
|
||||||
DefenderTask.Fsm:GetState(),
|
Defender:GetName(),
|
||||||
Defender:GetSize(),
|
DefenderTask.Type,
|
||||||
Fuel,
|
DefenderTask.Fsm:GetState(),
|
||||||
Damage,
|
Defender:GetSize(),
|
||||||
Defender:HasTask() == true and "Executing" or "Idle" ) )
|
Fuel,
|
||||||
|
Damage,
|
||||||
|
Defender:HasTask() == true and "Executing" or "Idle" ) )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3041,22 +3060,25 @@ do -- AI_A2A_DISPATCHER
|
|||||||
TaskCount = TaskCount + 1
|
TaskCount = TaskCount + 1
|
||||||
local Defender = Defender -- Wrapper.Group#GROUP
|
local Defender = Defender -- Wrapper.Group#GROUP
|
||||||
if not DefenderTask.Target then
|
if not DefenderTask.Target then
|
||||||
local DefenderHasTask = Defender:HasTask()
|
if Defender:IsAlive() then
|
||||||
local Fuel = Defender:GetFuel() * 100
|
local DefenderHasTask = Defender:HasTask()
|
||||||
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
|
local Fuel = Defender:GetFuelMin() * 100
|
||||||
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
|
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
|
||||||
Defender:GetName(),
|
DefenderGroupCount = DefenderGroupCount + 1
|
||||||
DefenderTask.Type,
|
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
|
||||||
DefenderTask.Fsm:GetState(),
|
Defender:GetName(),
|
||||||
Defender:GetSize(),
|
DefenderTask.Type,
|
||||||
Fuel,
|
DefenderTask.Fsm:GetState(),
|
||||||
Damage,
|
Defender:GetSize(),
|
||||||
Defender:HasTask() == true and "Executing" or "Idle" ) )
|
Fuel,
|
||||||
|
Damage,
|
||||||
|
Defender:HasTask() == true and "Executing" or "Idle" ) )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Report:Add( string.format( "\n - %d Tasks", TaskCount ) )
|
Report:Add( string.format( "\n - %d Tasks - %d Defender Groups", TaskCount, DefenderGroupCount ) )
|
||||||
|
|
||||||
self:E( Report:Text( "\n" ) )
|
self:F( Report:Text( "\n" ) )
|
||||||
trigger.action.outText( Report:Text( "\n" ), 25 )
|
trigger.action.outText( Report:Text( "\n" ), 25 )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3067,10 +3089,10 @@ end
|
|||||||
|
|
||||||
do
|
do
|
||||||
|
|
||||||
--- Calculates which HUMAN friendlies are nearby the area
|
--- Calculates which HUMAN friendlies are nearby the area.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param DetectedItem
|
-- @param DetectedItem The detected item.
|
||||||
-- @return #number, Core.CommandCenter#REPORT
|
-- @return #number, Core.Report#REPORT The amount of friendlies and a text string explaining which friendlies of which type.
|
||||||
function AI_A2A_DISPATCHER:GetPlayerFriendliesNearBy( DetectedItem )
|
function AI_A2A_DISPATCHER:GetPlayerFriendliesNearBy( DetectedItem )
|
||||||
|
|
||||||
local DetectedSet = DetectedItem.Set
|
local DetectedSet = DetectedItem.Set
|
||||||
@@ -3084,7 +3106,7 @@ do
|
|||||||
for PlayerUnitName, PlayerUnitData in pairs( PlayersNearBy ) do
|
for PlayerUnitName, PlayerUnitData in pairs( PlayersNearBy ) do
|
||||||
local PlayerUnit = PlayerUnitData -- Wrapper.Unit#UNIT
|
local PlayerUnit = PlayerUnitData -- Wrapper.Unit#UNIT
|
||||||
local PlayerName = PlayerUnit:GetPlayerName()
|
local PlayerName = PlayerUnit:GetPlayerName()
|
||||||
--self:E( { PlayerName = PlayerName, PlayerUnit = PlayerUnit } )
|
--self:F( { PlayerName = PlayerName, PlayerUnit = PlayerUnit } )
|
||||||
if PlayerUnit:IsAirPlane() and PlayerName ~= nil then
|
if PlayerUnit:IsAirPlane() and PlayerName ~= nil then
|
||||||
local FriendlyUnitThreatLevel = PlayerUnit:GetThreatLevel()
|
local FriendlyUnitThreatLevel = PlayerUnit:GetThreatLevel()
|
||||||
PlayersCount = PlayersCount + 1
|
PlayersCount = PlayersCount + 1
|
||||||
@@ -3097,7 +3119,7 @@ do
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--self:E( { PlayersCount = PlayersCount } )
|
--self:F( { PlayersCount = PlayersCount } )
|
||||||
|
|
||||||
local PlayerTypesReport = REPORT:New()
|
local PlayerTypesReport = REPORT:New()
|
||||||
|
|
||||||
@@ -3113,14 +3135,14 @@ do
|
|||||||
return PlayersCount, PlayerTypesReport
|
return PlayersCount, PlayerTypesReport
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Calculates which friendlies are nearby the area
|
--- Calculates which friendlies are nearby the area.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param DetectedItem
|
-- @param DetectedItem The detected item.
|
||||||
-- @return #number, Core.CommandCenter#REPORT
|
-- @return #number, Core.Report#REPORT The amount of friendlies and a text string explaining which friendlies of which type.
|
||||||
function AI_A2A_DISPATCHER:GetFriendliesNearBy( Target )
|
function AI_A2A_DISPATCHER:GetFriendliesNearBy( DetectedItem )
|
||||||
|
|
||||||
local DetectedSet = Target.Set
|
local DetectedSet = DetectedItem.Set
|
||||||
local FriendlyUnitsNearBy = self.Detection:GetFriendliesNearBy( Target )
|
local FriendlyUnitsNearBy = self.Detection:GetFriendliesNearBy( DetectedItem )
|
||||||
|
|
||||||
local FriendlyTypes = {}
|
local FriendlyTypes = {}
|
||||||
local FriendliesCount = 0
|
local FriendliesCount = 0
|
||||||
@@ -3141,7 +3163,7 @@ do
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--self:E( { FriendliesCount = FriendliesCount } )
|
--self:F( { FriendliesCount = FriendliesCount } )
|
||||||
|
|
||||||
local FriendlyTypesReport = REPORT:New()
|
local FriendlyTypesReport = REPORT:New()
|
||||||
|
|
||||||
@@ -3157,8 +3179,8 @@ do
|
|||||||
return FriendliesCount, FriendlyTypesReport
|
return FriendliesCount, FriendlyTypesReport
|
||||||
end
|
end
|
||||||
|
|
||||||
---
|
--- Schedules a new CAP for the given SquadronName.
|
||||||
-- @param AI_A2A_DISPATCHER
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
function AI_A2A_DISPATCHER:SchedulerCAP( SquadronName )
|
function AI_A2A_DISPATCHER:SchedulerCAP( SquadronName )
|
||||||
self:CAP( SquadronName )
|
self:CAP( SquadronName )
|
||||||
@@ -3171,14 +3193,10 @@ do
|
|||||||
--- @type AI_A2A_GCICAP
|
--- @type AI_A2A_GCICAP
|
||||||
-- @extends #AI_A2A_DISPATCHER
|
-- @extends #AI_A2A_DISPATCHER
|
||||||
|
|
||||||
--- # AI\_A2A\_GCICAP class, extends @{AI_A2A_Dispatcher#AI_A2A_DISPATCHER}
|
--- Create an automatic air defence system for a coalition setting up GCI and CAP air defenses.
|
||||||
|
-- The class derives from @{#AI_A2A_DISPATCHER} and thus, all the methods that are defined in the @{#AI_A2A_DISPATCHER} class, can be used also in AI\_A2A\_GCICAP.
|
||||||
--
|
--
|
||||||
-- 
|
-- ===
|
||||||
--
|
|
||||||
-- The AI_A2A_GCICAP class is designed to create an automatic air defence system for a coalition setting up GCI and CAP air defenses.
|
|
||||||
-- The class derives from @{AI#AI_A2A_DISPATCHER} and thus, all the methods that are defined in the @{AI#AI_A2A_DISPATCHER} class, can be used also in AI\_A2A\_GCICAP.
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
--
|
||||||
-- # Demo Missions
|
-- # Demo Missions
|
||||||
--
|
--
|
||||||
@@ -3188,7 +3206,7 @@ do
|
|||||||
--
|
--
|
||||||
-- ### [AI\_A2A\_GCICAP for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching)
|
-- ### [AI\_A2A\_GCICAP for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching)
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # YouTube Channel
|
-- # YouTube Channel
|
||||||
--
|
--
|
||||||
@@ -3218,7 +3236,7 @@ do
|
|||||||
--
|
--
|
||||||
-- In short it is a plug in very flexible and configurable air defence module for DCS World.
|
-- In short it is a plug in very flexible and configurable air defence module for DCS World.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # The following actions need to be followed when using AI\_A2A\_GCICAP in your mission:
|
-- # The following actions need to be followed when using AI\_A2A\_GCICAP in your mission:
|
||||||
--
|
--
|
||||||
@@ -3279,7 +3297,7 @@ do
|
|||||||
--
|
--
|
||||||
-- **The place of the helicopter is important, as the airbase closest to the helicopter will be the airbase from where the CAP planes will take off for CAP.**
|
-- **The place of the helicopter is important, as the airbase closest to the helicopter will be the airbase from where the CAP planes will take off for CAP.**
|
||||||
--
|
--
|
||||||
-- ## 2) There are a lot of defaults set, which can be further modified using the methods in @{AI#AI_A2A_DISPATCHER}:
|
-- ## 2) There are a lot of defaults set, which can be further modified using the methods in @{#AI_A2A_DISPATCHER}:
|
||||||
--
|
--
|
||||||
-- ### 2.1) Planes are taking off in the air from the airbases.
|
-- ### 2.1) Planes are taking off in the air from the airbases.
|
||||||
--
|
--
|
||||||
@@ -3551,22 +3569,23 @@ do
|
|||||||
|
|
||||||
-- Setup squadrons
|
-- Setup squadrons
|
||||||
|
|
||||||
self:F( { Airbases = AirbaseNames } )
|
self:I( { Airbases = AirbaseNames } )
|
||||||
self.Templates:Flush()
|
|
||||||
|
self:I( "Defining Templates for Airbases ..." )
|
||||||
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
||||||
local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE
|
local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE
|
||||||
local AirbaseName = Airbase:GetName()
|
local AirbaseName = Airbase:GetName()
|
||||||
local AirbaseCoord = Airbase:GetCoordinate()
|
local AirbaseCoord = Airbase:GetCoordinate()
|
||||||
local AirbaseZone = ZONE_RADIUS:New( "Airbase", AirbaseCoord:GetVec2(), 3000 )
|
local AirbaseZone = ZONE_RADIUS:New( "Airbase", AirbaseCoord:GetVec2(), 3000 )
|
||||||
local Templates = nil
|
local Templates = nil
|
||||||
|
self:I( { Airbase = AirbaseName } )
|
||||||
for TemplateID, Template in pairs( self.Templates:GetSet() ) do
|
for TemplateID, Template in pairs( self.Templates:GetSet() ) do
|
||||||
local Template = Template -- Wrapper.Group#GROUP
|
local Template = Template -- Wrapper.Group#GROUP
|
||||||
self:F( { Template = Template:GetName() } )
|
|
||||||
local TemplateCoord = Template:GetCoordinate()
|
local TemplateCoord = Template:GetCoordinate()
|
||||||
if AirbaseZone:IsVec2InZone( TemplateCoord:GetVec2() ) then
|
if AirbaseZone:IsVec2InZone( TemplateCoord:GetVec2() ) then
|
||||||
Templates = Templates or {}
|
Templates = Templates or {}
|
||||||
table.insert( Templates, Template:GetName() )
|
table.insert( Templates, Template:GetName() )
|
||||||
|
self:I( { Template = Template:GetName() } )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if Templates then
|
if Templates then
|
||||||
@@ -3582,11 +3601,13 @@ do
|
|||||||
self.CAPTemplates:FilterPrefixes( CapPrefixes )
|
self.CAPTemplates:FilterPrefixes( CapPrefixes )
|
||||||
self.CAPTemplates:FilterOnce()
|
self.CAPTemplates:FilterOnce()
|
||||||
|
|
||||||
|
self:I( "Setting up CAP ..." )
|
||||||
for CAPID, CAPTemplate in pairs( self.CAPTemplates:GetSet() ) do
|
for CAPID, CAPTemplate in pairs( self.CAPTemplates:GetSet() ) do
|
||||||
local CAPZone = ZONE_POLYGON:New( CAPTemplate:GetName(), CAPTemplate )
|
local CAPZone = ZONE_POLYGON:New( CAPTemplate:GetName(), CAPTemplate )
|
||||||
-- Now find the closest airbase from the ZONE (start or center)
|
-- Now find the closest airbase from the ZONE (start or center)
|
||||||
local AirbaseDistance = 99999999
|
local AirbaseDistance = 99999999
|
||||||
local AirbaseClosest = nil -- Wrapper.Airbase#AIRBASE
|
local AirbaseClosest = nil -- Wrapper.Airbase#AIRBASE
|
||||||
|
self:I( { CAPZoneGroup = CAPID } )
|
||||||
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
||||||
local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE
|
local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE
|
||||||
local AirbaseName = Airbase:GetName()
|
local AirbaseName = Airbase:GetName()
|
||||||
@@ -3594,6 +3615,7 @@ do
|
|||||||
local Squadron = self.DefenderSquadrons[AirbaseName]
|
local Squadron = self.DefenderSquadrons[AirbaseName]
|
||||||
if Squadron then
|
if Squadron then
|
||||||
local Distance = AirbaseCoord:Get2DDistance( CAPZone:GetCoordinate() )
|
local Distance = AirbaseCoord:Get2DDistance( CAPZone:GetCoordinate() )
|
||||||
|
self:I( { AirbaseDistance = Distance } )
|
||||||
if Distance < AirbaseDistance then
|
if Distance < AirbaseDistance then
|
||||||
AirbaseDistance = Distance
|
AirbaseDistance = Distance
|
||||||
AirbaseClosest = Airbase
|
AirbaseClosest = Airbase
|
||||||
@@ -3601,6 +3623,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if AirbaseClosest then
|
if AirbaseClosest then
|
||||||
|
self:I( { CAPAirbase = AirbaseClosest:GetName() } )
|
||||||
self:SetSquadronCap( AirbaseClosest:GetName(), CAPZone, 6000, 10000, 500, 800, 800, 1200, "RADIO" )
|
self:SetSquadronCap( AirbaseClosest:GetName(), CAPZone, 6000, 10000, 500, 800, 800, 1200, "RADIO" )
|
||||||
self:SetSquadronCapInterval( AirbaseClosest:GetName(), CapLimit, 300, 600, 1 )
|
self:SetSquadronCapInterval( AirbaseClosest:GetName(), CapLimit, 300, 600, 1 )
|
||||||
end
|
end
|
||||||
@@ -3608,11 +3631,14 @@ do
|
|||||||
|
|
||||||
-- Setup GCI.
|
-- Setup GCI.
|
||||||
-- GCI is setup for all Squadrons.
|
-- GCI is setup for all Squadrons.
|
||||||
|
self:I( "Setting up GCI ..." )
|
||||||
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
||||||
local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE
|
local Airbase = _DATABASE:FindAirbase( AirbaseName ) -- Wrapper.Airbase#AIRBASE
|
||||||
local AirbaseName = Airbase:GetName()
|
local AirbaseName = Airbase:GetName()
|
||||||
local Squadron = self.DefenderSquadrons[AirbaseName]
|
local Squadron = self.DefenderSquadrons[AirbaseName]
|
||||||
|
self:F( { Airbase = AirbaseName } )
|
||||||
if Squadron then
|
if Squadron then
|
||||||
|
self:I( { GCIAirbase = AirbaseName } )
|
||||||
self:SetSquadronGci( AirbaseName, 800, 1200 )
|
self:SetSquadronGci( AirbaseName, 800, 1200 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3621,6 +3647,7 @@ do
|
|||||||
|
|
||||||
self:HandleEvent( EVENTS.Crash, self.OnEventCrashOrDead )
|
self:HandleEvent( EVENTS.Crash, self.OnEventCrashOrDead )
|
||||||
self:HandleEvent( EVENTS.Dead, self.OnEventCrashOrDead )
|
self:HandleEvent( EVENTS.Dead, self.OnEventCrashOrDead )
|
||||||
|
--self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCrashOrDead )
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Land )
|
self:HandleEvent( EVENTS.Land )
|
||||||
self:HandleEvent( EVENTS.EngineShutdown )
|
self:HandleEvent( EVENTS.EngineShutdown )
|
||||||
|
|||||||
@@ -1,40 +1,27 @@
|
|||||||
--- **AI** -- **Execute Ground Controlled Interception (GCI).**
|
--- **AI** -- (R2.2) - Models the process of Ground Controlled Interception (GCI) for airplanes.
|
||||||
--
|
--
|
||||||
-- 
|
-- This is a class used in the @{AI_A2A_Dispatcher}.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- AI A2A_INTEREPT class makes AI Groups execute an Intercept.
|
-- ### Author: **FlightControl**
|
||||||
--
|
--
|
||||||
-- There are the following types of GCI classes defined:
|
-- ===
|
||||||
--
|
|
||||||
-- * @{#AI_A2A_GCI}: Perform a GCI in a zone.
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
|
||||||
--
|
|
||||||
-- ### Contributions:
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
--
|
||||||
-- @module AI_A2A_GCI
|
-- @module AI.AI_A2A_GCI
|
||||||
|
-- @image AI_Ground_Control_Intercept.JPG
|
||||||
|
|
||||||
|
|
||||||
--BASE:TraceClass("AI_A2A_GCI")
|
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_A2A_GCI
|
--- @type AI_A2A_GCI
|
||||||
-- @extends AI.AI_A2A#AI_A2A
|
-- @extends AI.AI_A2A#AI_A2A
|
||||||
|
|
||||||
|
|
||||||
--- # AI_A2A_GCI class, extends @{AI_A2A#AI_A2A}
|
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
|
||||||
-- The AI_A2A_GCI class implements the core functions to intercept intruders. The Engage function will intercept intruders.
|
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_A2A_GCI is assigned a @{Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event.
|
-- The AI_A2A_GCI is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -77,15 +64,15 @@
|
|||||||
--
|
--
|
||||||
-- ### 2.2 AI_A2A_GCI Events
|
-- ### 2.2 AI_A2A_GCI Events
|
||||||
--
|
--
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
||||||
-- * **@{#AI_A2A_GCI.Engage}**: Let the AI engage the bogeys.
|
-- * **@{#AI_A2A_GCI.Engage}**: Let the AI engage the bogeys.
|
||||||
-- * **@{#AI_A2A_GCI.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
-- * **@{#AI_A2A_GCI.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Unit}.
|
-- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Unit}s assigned in the CAS task.
|
-- * **@{#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 tresholds have been reached, the AI will RTB.
|
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Set the Range of Engagement
|
-- ## 3. Set the Range of Engagement
|
||||||
@@ -96,7 +83,7 @@
|
|||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- 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 can be beyond or smaller than the range of the Patrol Zone.
|
||||||
-- The range is applied at the position of the AI.
|
-- The range is applied at the position of the AI.
|
||||||
-- Use the method @{AI_GCI#AI_A2A_GCI.SetEngageRange}() to define that range.
|
-- Use the method @{AI.AI_GCI#AI_A2A_GCI.SetEngageRange}() to define that range.
|
||||||
--
|
--
|
||||||
-- ## 4. Set the Zone of Engagement
|
-- ## 4. Set the Zone of Engagement
|
||||||
--
|
--
|
||||||
@@ -104,7 +91,7 @@
|
|||||||
--
|
--
|
||||||
-- An optional @{Zone} can be set,
|
-- An optional @{Zone} can be set,
|
||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- Use the method @{AI_Cap#AI_A2A_GCI.SetEngageZone}() to define that Zone.
|
-- Use the method @{AI.AI_Cap#AI_A2A_GCI.SetEngageZone}() to define that Zone.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -303,6 +290,7 @@ end
|
|||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
function AI_A2A_GCI:onafterStart( AIIntercept, From, Event, To )
|
function AI_A2A_GCI:onafterStart( AIIntercept, From, Event, To )
|
||||||
|
|
||||||
|
self:GetParent( self ).onafterStart( self, AIIntercept, From, Event, To )
|
||||||
AIIntercept:HandleEvent( EVENTS.Takeoff, nil, self )
|
AIIntercept:HandleEvent( EVENTS.Takeoff, nil, self )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,54 +1,23 @@
|
|||||||
--- **AI** -- **Air Patrolling or Staging.**
|
--- **AI** -- (R2.2) - Models the process of air patrol of airplanes.
|
||||||
--
|
|
||||||
-- 
|
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- AI PATROL classes makes AI Groups execute an Patrol.
|
-- ### Author: **FlightControl**
|
||||||
--
|
--
|
||||||
-- There are the following types of PATROL classes defined:
|
-- ===
|
||||||
--
|
--
|
||||||
-- * @{#AI_A2A_PATROL}: Perform a PATROL in a zone.
|
-- @module AI.AI_A2A_Patrol
|
||||||
--
|
-- @image AI_Air_Patrolling.JPG
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # Demo Missions
|
|
||||||
--
|
|
||||||
-- ### [AI_PATROL Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
|
|
||||||
--
|
|
||||||
-- ### [AI_PATROL Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/PAT%20-%20Patrolling)
|
|
||||||
--
|
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # YouTube Channel
|
|
||||||
--
|
|
||||||
-- ### [AI_PATROL YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl35HvYZKA6G22WMt7iI3zky)
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- ### Author: **Sven Van de Velde (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.
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- @module AI_A2A_Patrol
|
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_A2A_PATROL
|
--- @type AI_A2A_PATROL
|
||||||
-- @extends AI.AI_A2A#AI_A2A
|
-- @extends AI.AI_A2A#AI_A2A
|
||||||
|
|
||||||
--- # AI_A2A_PATROL class, extends @{Fsm#FSM_CONTROLLABLE}
|
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
|
||||||
--
|
|
||||||
-- The AI_A2A_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Group} or @{Group}.
|
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_A2A_PATROL is assigned a @{Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event.
|
-- The AI_A2A_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -121,7 +90,7 @@
|
|||||||
-- * @{#AI_A2A_PATROL.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased.
|
-- * @{#AI_A2A_PATROL.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased.
|
||||||
--
|
--
|
||||||
-- The detection frequency can be set with @{#AI_A2A_PATROL.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
|
-- The detection frequency can be set with @{#AI_A2A_PATROL.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
|
||||||
-- Use the method @{#AI_A2A_PATROL.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI.
|
-- Use the method @{#AI_A2A_PATROL.GetDetectedUnits}() to obtain a list of the @{Wrapper.Unit}s detected by the AI.
|
||||||
--
|
--
|
||||||
-- The detection can be filtered to potential targets in a specific zone.
|
-- The detection can be filtered to potential targets in a specific zone.
|
||||||
-- Use the method @{#AI_A2A_PATROL.SetDetectionZone}() to set the zone where targets need to be detected.
|
-- Use the method @{#AI_A2A_PATROL.SetDetectionZone}() to set the zone where targets need to be detected.
|
||||||
@@ -154,11 +123,11 @@ AI_A2A_PATROL = {
|
|||||||
-- @param #AI_A2A_PATROL self
|
-- @param #AI_A2A_PATROL self
|
||||||
-- @param Wrapper.Group#GROUP AIPatrol
|
-- @param Wrapper.Group#GROUP AIPatrol
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
|
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
|
||||||
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
||||||
-- @return #AI_A2A_PATROL self
|
-- @return #AI_A2A_PATROL self
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Define a new AI_A2A_PATROL Object. This PatrolArea will patrol a Group within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
|
-- -- Define a new AI_A2A_PATROL Object. This PatrolArea will patrol a Group within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
|
||||||
@@ -264,8 +233,8 @@ end
|
|||||||
|
|
||||||
--- Sets (modifies) the minimum and maximum speed of the patrol.
|
--- Sets (modifies) the minimum and maximum speed of the patrol.
|
||||||
-- @param #AI_A2A_PATROL self
|
-- @param #AI_A2A_PATROL self
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
|
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
|
||||||
-- @return #AI_A2A_PATROL self
|
-- @return #AI_A2A_PATROL self
|
||||||
function AI_A2A_PATROL:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
|
function AI_A2A_PATROL:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
|
||||||
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
|
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
|
||||||
@@ -278,8 +247,8 @@ end
|
|||||||
|
|
||||||
--- Sets the floor and ceiling altitude of the patrol.
|
--- Sets the floor and ceiling altitude of the patrol.
|
||||||
-- @param #AI_A2A_PATROL self
|
-- @param #AI_A2A_PATROL self
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @return #AI_A2A_PATROL self
|
-- @return #AI_A2A_PATROL self
|
||||||
function AI_A2A_PATROL:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
function AI_A2A_PATROL:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
||||||
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
|
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
|
||||||
@@ -303,9 +272,8 @@ function AI_A2A_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
|||||||
|
|
||||||
self:__Route( 1 )
|
self:__Route( 1 )
|
||||||
|
|
||||||
self.AIPatrol:OnReSpawn(
|
AIPatrol:OnReSpawn(
|
||||||
function( PatrolGroup )
|
function( PatrolGroup )
|
||||||
self:E( "ReSpawn" )
|
|
||||||
self:__Reset( 1 )
|
self:__Reset( 1 )
|
||||||
self:__Route( 5 )
|
self:__Route( 5 )
|
||||||
end
|
end
|
||||||
@@ -387,7 +355,7 @@ function AI_A2A_PATROL.Resume( AIPatrol )
|
|||||||
|
|
||||||
AIPatrol:F( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } )
|
AIPatrol:F( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } )
|
||||||
if AIPatrol:IsAlive() then
|
if AIPatrol:IsAlive() then
|
||||||
local _AI_A2A = AIPatrol:GetState( AIPatrol, "AI_A2A" ) -- #AI_A2A
|
local _AI_A2A = AIPatrol:GetState( AIPatrol, "AI_A2A" ) -- AI.AI_A2A#AI_A2A
|
||||||
_AI_A2A:__Reset( 1 )
|
_AI_A2A:__Reset( 1 )
|
||||||
_AI_A2A:__Route( 5 )
|
_AI_A2A:__Route( 5 )
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,60 +1,48 @@
|
|||||||
--- **AI** -- **Provide Battlefield Air Interdiction (bombing).**
|
--- **AI** -- Peform Battlefield Area Interdiction (BAI) within an engagement zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- **Features:**
|
||||||
|
--
|
||||||
|
-- * Hold and standby within a patrol zone.
|
||||||
|
-- * Engage upon command the assigned targets within an engagement zone.
|
||||||
|
-- * Loop the zone until all targets are eliminated.
|
||||||
|
-- * Trigger different events upon the results achieved.
|
||||||
|
-- * After combat, return to the patrol zone and hold.
|
||||||
|
-- * RTB when commanded or after out of fuel.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BAI%20-%20Battlefield%20Air%20Interdiction)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- AI_BAI classes makes AI Controllables execute bombing tasks.
|
-- ### [YouTube Playlist]()
|
||||||
--
|
--
|
||||||
-- There are the following types of BAI classes defined:
|
-- ===
|
||||||
--
|
|
||||||
-- * @{#AI_BAI_ZONE}: Perform a BAI in a zone.
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # Demo Missions
|
|
||||||
--
|
|
||||||
-- ### [AI_BAI Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/BOMB%20-%20Close%20Air%20Support)
|
|
||||||
--
|
|
||||||
-- ### [AI_BAI Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BOMB%20-%20Close%20Air%20Support)
|
|
||||||
--
|
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # YouTube Channel
|
|
||||||
--
|
|
||||||
-- ### [AI_BAI YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2)
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
|
||||||
--
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI_Bai
|
-- @module AI.AI_Bai
|
||||||
|
-- @image AI_Battlefield_Air_Interdiction.JPG
|
||||||
|
|
||||||
|
|
||||||
--- AI_BAI_ZONE class
|
--- AI_BAI_ZONE class
|
||||||
-- @type AI_BAI_ZONE
|
-- @type AI_BAI_ZONE
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
|
-- @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 @{Zone} where the patrol needs to be executed.
|
||||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||||
|
|
||||||
--- # AI_BAI_ZONE class, extends @{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}.
|
||||||
--
|
--
|
||||||
-- AI_BAI_ZONE derives from the @{AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour.
|
|
||||||
--
|
|
||||||
-- The AI_BAI_ZONE class implements the core functions to provide BattleGround Air Interdiction in an Engage @{Zone} by an AIR @{Controllable} or @{Group}.
|
|
||||||
-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_BAI_ZONE is assigned a @{Group} and this must be done before the AI_BAI_ZONE process can be started through the **Start** event.
|
-- The AI_BAI_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_BAI_ZONE process can be started through the **Start** event.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -120,15 +108,15 @@
|
|||||||
--
|
--
|
||||||
-- ### 2.2. AI_BAI_ZONE Events
|
-- ### 2.2. AI_BAI_ZONE Events
|
||||||
--
|
--
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
||||||
-- * **@{#AI_BAI_ZONE.Engage}**: Engage the AI to provide BOMB in the Engage Zone, destroying any target it finds.
|
-- * **@{#AI_BAI_ZONE.Engage}**: Engage the AI to provide BOMB in the Engage Zone, destroying any target it finds.
|
||||||
-- * **@{#AI_BAI_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
-- * **@{#AI_BAI_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Unit}.
|
-- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Unit}s assigned in the BOMB task.
|
-- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the BOMB task.
|
||||||
-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Modify the Engage Zone behaviour to pinpoint a **map object** or **scenery object**
|
-- ## 3. Modify the Engage Zone behaviour to pinpoint a **map object** or **scenery object**
|
||||||
@@ -155,12 +143,12 @@ AI_BAI_ZONE = {
|
|||||||
--- Creates a new AI_BAI_ZONE object
|
--- Creates a new AI_BAI_ZONE object
|
||||||
-- @param #AI_BAI_ZONE self
|
-- @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 @{Zone} where the patrol needs to be executed.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen.
|
-- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen.
|
||||||
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
||||||
-- @return #AI_BAI_ZONE self
|
-- @return #AI_BAI_ZONE self
|
||||||
function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType )
|
function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType )
|
||||||
|
|
||||||
@@ -197,24 +185,24 @@ function AI_BAI_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @function [parent=#AI_BAI_ZONE] Engage
|
-- @function [parent=#AI_BAI_ZONE] Engage
|
||||||
-- @param #AI_BAI_ZONE self
|
-- @param #AI_BAI_ZONE self
|
||||||
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
||||||
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
||||||
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
|
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
|
||||||
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
|
-- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
|
||||||
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
|
|
||||||
--- Asynchronous Event Trigger for Event Engage.
|
--- Asynchronous Event Trigger for Event Engage.
|
||||||
-- @function [parent=#AI_BAI_ZONE] __Engage
|
-- @function [parent=#AI_BAI_ZONE] __Engage
|
||||||
-- @param #AI_BAI_ZONE self
|
-- @param #AI_BAI_ZONE self
|
||||||
-- @param #number Delay The delay in seconds.
|
-- @param #number Delay The delay in seconds.
|
||||||
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
||||||
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
||||||
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
|
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
|
||||||
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
|
-- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
|
||||||
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
|
|
||||||
--- OnLeave Transition Handler for State Engaging.
|
--- OnLeave Transition Handler for State Engaging.
|
||||||
-- @function [parent=#AI_BAI_ZONE] OnLeaveEngaging
|
-- @function [parent=#AI_BAI_ZONE] OnLeaveEngaging
|
||||||
@@ -501,10 +489,10 @@ end
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
||||||
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
||||||
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||||
EngageSpeed,
|
EngageSpeed,
|
||||||
EngageAltitude,
|
EngageAltitude,
|
||||||
|
|||||||
@@ -1,50 +1,44 @@
|
|||||||
--- **AI** -- **AI Balancing will replace in multi player missions
|
--- **AI** -- Balance player slots with AI to create an engaging simulation environment, independent of the amount of players.
|
||||||
-- non-occupied human slots with AI groups, in order to provide an engaging simulation environment,
|
|
||||||
-- even when there are hardly any players in the mission.**
|
|
||||||
--
|
--
|
||||||
-- 
|
-- **Features:**
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
--
|
||||||
-- # Demo Missions
|
-- * Automatically spawn AI as a replacement of free player slots for a coalition.
|
||||||
|
-- * Make the AI to perform tasks.
|
||||||
|
-- * Define a maximum amount of AI to be active at the same time.
|
||||||
|
-- * Configure the behaviour of AI when a human joins a slot for which an AI is active.
|
||||||
--
|
--
|
||||||
-- ### [AI_BALANCER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/AIB%20-%20AI%20Balancing)
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [AI_BALANCER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AIB%20-%20AI%20Balancing)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/AIB%20-%20AI%20Balancing)
|
||||||
--
|
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # YouTube Channel
|
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl2CJVIrL1TdAumuVS8n64B7)
|
||||||
--
|
--
|
||||||
-- ### [AI_BALANCER YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl2CJVIrL1TdAumuVS8n64B7)
|
-- ===
|
||||||
--
|
--
|
||||||
-- ====
|
-- ### Author: **FlightControl**
|
||||||
--
|
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
|
||||||
-- ### Contributions:
|
-- ### 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](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 :-)
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI_Balancer
|
-- @module AI.AI_Balancer
|
||||||
|
-- @image AI_Balancing.JPG
|
||||||
|
|
||||||
--- @type AI_BALANCER
|
--- @type AI_BALANCER
|
||||||
-- @field Core.Set#SET_CLIENT SetClient
|
-- @field Core.Set#SET_CLIENT SetClient
|
||||||
-- @field Functional.Spawn#SPAWN SpawnAI
|
-- @field Core.Spawn#SPAWN SpawnAI
|
||||||
-- @field Wrapper.Group#GROUP Test
|
-- @field Wrapper.Group#GROUP Test
|
||||||
-- @extends Core.Fsm#FSM_SET
|
-- @extends Core.Fsm#FSM_SET
|
||||||
|
|
||||||
|
|
||||||
--- # AI_BALANCER class, extends @{Fsm#FSM_SET}
|
--- Monitors and manages as many replacement AI groups as there are
|
||||||
--
|
-- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players.
|
||||||
-- The AI_BALANCER class 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.
|
-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions.
|
||||||
--
|
--
|
||||||
-- The parent class @{Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM).
|
-- 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.
|
-- 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 @{FSM} module documentation.
|
||||||
--
|
--
|
||||||
@@ -86,8 +80,8 @@
|
|||||||
-- However, there are 2 additional options that you can use to customize the destroy behaviour.
|
-- However, there are 2 additional options that you can use to customize the destroy behaviour.
|
||||||
-- When a human player joins a slot, you can configure to let the AI return to:
|
-- When a human player joins a slot, you can configure to let the AI return to:
|
||||||
--
|
--
|
||||||
-- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Airbase#AIRBASE}.
|
-- * @{#AI_BALANCER.ReturnToHomeAirbase}: Returns the AI to the **home** @{Wrapper.Airbase#AIRBASE}.
|
||||||
-- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Airbase#AIRBASE}.
|
-- * @{#AI_BALANCER.ReturnToNearestAirbases}: Returns the AI to the **nearest friendly** @{Wrapper.Airbase#AIRBASE}.
|
||||||
--
|
--
|
||||||
-- Note that when AI returns to an airbase, the AI_BALANCER will trigger the **Return** event and the AI will return,
|
-- 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.
|
-- otherwise the AI_BALANCER will trigger a **Destroy** event, and the AI will be destroyed.
|
||||||
@@ -106,7 +100,7 @@ AI_BALANCER = {
|
|||||||
--- Creates a new AI_BALANCER object
|
--- Creates a new AI_BALANCER object
|
||||||
-- @param #AI_BALANCER self
|
-- @param #AI_BALANCER self
|
||||||
-- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player).
|
-- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player).
|
||||||
-- @param Functional.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed.
|
-- @param Core.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed.
|
||||||
-- @return #AI_BALANCER
|
-- @return #AI_BALANCER
|
||||||
function AI_BALANCER:New( SetClient, SpawnAI )
|
function AI_BALANCER:New( SetClient, SpawnAI )
|
||||||
|
|
||||||
@@ -149,10 +143,10 @@ function AI_BALANCER:InitSpawnInterval( Earliest, Latest )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the AI to the nearest friendly @{Airbase#AIRBASE}.
|
--- Returns the AI to the nearest friendly @{Wrapper.Airbase#AIRBASE}.
|
||||||
-- @param #AI_BALANCER self
|
-- @param #AI_BALANCER self
|
||||||
-- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
|
-- @param DCS#Distance ReturnThresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}.
|
||||||
-- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to.
|
-- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Core.Set#SET_AIRBASE}s to evaluate where to return to.
|
||||||
function AI_BALANCER:ReturnToNearestAirbases( ReturnThresholdRange, ReturnAirbaseSet )
|
function AI_BALANCER:ReturnToNearestAirbases( ReturnThresholdRange, ReturnAirbaseSet )
|
||||||
|
|
||||||
self.ToNearestAirbase = true
|
self.ToNearestAirbase = true
|
||||||
@@ -160,9 +154,9 @@ function AI_BALANCER:ReturnToNearestAirbases( ReturnThresholdRange, ReturnAirbas
|
|||||||
self.ReturnAirbaseSet = ReturnAirbaseSet
|
self.ReturnAirbaseSet = ReturnAirbaseSet
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the AI to the home @{Airbase#AIRBASE}.
|
--- Returns the AI to the home @{Wrapper.Airbase#AIRBASE}.
|
||||||
-- @param #AI_BALANCER self
|
-- @param #AI_BALANCER self
|
||||||
-- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
|
-- @param DCS#Distance ReturnThresholdRange If there is an enemy @{Wrapper.Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Wrapper.Airbase#AIRBASE}.
|
||||||
function AI_BALANCER:ReturnToHomeAirbase( ReturnThresholdRange )
|
function AI_BALANCER:ReturnToHomeAirbase( ReturnThresholdRange )
|
||||||
|
|
||||||
self.ToHomeAirbase = true
|
self.ToHomeAirbase = true
|
||||||
@@ -178,9 +172,10 @@ function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName )
|
|||||||
-- OK, Spawn a new group from the default SpawnAI object provided.
|
-- OK, Spawn a new group from the default SpawnAI object provided.
|
||||||
local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP
|
local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP
|
||||||
if AIGroup then
|
if AIGroup then
|
||||||
AIGroup:E( "Spawning new AIGroup" )
|
AIGroup:T( { "Spawning new AIGroup", ClientName = ClientName } )
|
||||||
--TODO: need to rework UnitName thing ...
|
--TODO: need to rework UnitName thing ...
|
||||||
|
|
||||||
|
SetGroup:Remove( ClientName ) -- Ensure that the previously allocated AIGroup to ClientName is removed in the Set.
|
||||||
SetGroup:Add( ClientName, AIGroup )
|
SetGroup:Add( ClientName, AIGroup )
|
||||||
self.SpawnQueue[ClientName] = nil
|
self.SpawnQueue[ClientName] = nil
|
||||||
|
|
||||||
@@ -196,9 +191,9 @@ end
|
|||||||
function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup )
|
function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup )
|
||||||
|
|
||||||
AIGroup:Destroy()
|
AIGroup:Destroy()
|
||||||
SetGroup:Flush()
|
SetGroup:Flush( self )
|
||||||
SetGroup:Remove( ClientName )
|
SetGroup:Remove( ClientName )
|
||||||
SetGroup:Flush()
|
SetGroup:Flush( self )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_BALANCER self
|
--- @param #AI_BALANCER self
|
||||||
@@ -239,7 +234,8 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
|
|||||||
self:T3(Client.ClientName)
|
self:T3(Client.ClientName)
|
||||||
|
|
||||||
local AIGroup = self.Set:Get( Client.UnitName ) -- Wrapper.Group#GROUP
|
local AIGroup = self.Set:Get( Client.UnitName ) -- Wrapper.Group#GROUP
|
||||||
if Client:IsAlive() then
|
if AIGroup then self:T( { AIGroup = AIGroup:GetName(), IsAlive = AIGroup:IsAlive() } ) end
|
||||||
|
if Client:IsAlive() == true then
|
||||||
|
|
||||||
if AIGroup and AIGroup:IsAlive() == true then
|
if AIGroup and AIGroup:IsAlive() == true then
|
||||||
|
|
||||||
@@ -255,7 +251,7 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
|
|||||||
|
|
||||||
self:T2( RangeZone )
|
self:T2( RangeZone )
|
||||||
|
|
||||||
_DATABASE:ForEachPlayer(
|
_DATABASE:ForEachPlayerUnit(
|
||||||
--- @param Wrapper.Unit#UNIT RangeTestUnit
|
--- @param Wrapper.Unit#UNIT RangeTestUnit
|
||||||
function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange )
|
function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange )
|
||||||
self:T2( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } )
|
self:T2( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } )
|
||||||
@@ -284,11 +280,12 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
|
|||||||
else
|
else
|
||||||
if not AIGroup or not AIGroup:IsAlive() == true then
|
if not AIGroup or not AIGroup:IsAlive() == true then
|
||||||
self:T( "Client " .. Client.UnitName .. " not alive." )
|
self:T( "Client " .. Client.UnitName .. " not alive." )
|
||||||
|
self:T( { Queue = self.SpawnQueue[Client.UnitName] } )
|
||||||
if not self.SpawnQueue[Client.UnitName] then
|
if not self.SpawnQueue[Client.UnitName] then
|
||||||
-- Spawn a new AI taking into account the spawn interval Earliest, Latest
|
-- Spawn a new AI taking into account the spawn interval Earliest, Latest
|
||||||
self:__Spawn( math.random( self.Earliest, self.Latest ), Client.UnitName )
|
self:__Spawn( math.random( self.Earliest, self.Latest ), Client.UnitName )
|
||||||
self.SpawnQueue[Client.UnitName] = true
|
self.SpawnQueue[Client.UnitName] = true
|
||||||
self:E( "New AI Spawned for Client " .. Client.UnitName )
|
self:T( "New AI Spawned for Client " .. Client.UnitName )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,35 +1,24 @@
|
|||||||
--- **AI** -- **Execute Combat Air Patrol (CAP).**
|
--- **AI** -- Perform Combat Air Patrolling (CAP) for airplanes.
|
||||||
--
|
--
|
||||||
-- 
|
-- **Features:**
|
||||||
|
--
|
||||||
|
-- * Patrol AI airplanes within a given zone.
|
||||||
|
-- * Trigger detected events when enemy airplanes are detected.
|
||||||
|
-- * Manage a fuel treshold to RTB on time.
|
||||||
|
-- * Engage the enemy when detected.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- AI CAP classes makes AI Controllables execute a Combat Air Patrol.
|
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1YCyPxJgoZn-CfhwyeW65L)
|
||||||
--
|
--
|
||||||
-- There are the following types of CAP classes defined:
|
-- ===
|
||||||
--
|
|
||||||
-- * @{#AI_CAP_ZONE}: Perform a CAP in a zone.
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # Demo Missions
|
|
||||||
--
|
|
||||||
-- ### [AI_CAP Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol)
|
|
||||||
--
|
|
||||||
-- ### [AI_CAP Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAP%20-%20Combat%20Air%20Patrol)
|
|
||||||
--
|
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # YouTube Channel
|
|
||||||
--
|
|
||||||
-- ### [AI_CAP YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1YCyPxJgoZn-CfhwyeW65L)
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
|
||||||
--
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
||||||
@@ -38,25 +27,24 @@
|
|||||||
-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing.
|
-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing.
|
||||||
-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing.
|
-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI_Cap
|
-- @module AI.AI_Cap
|
||||||
|
-- @image AI_Combat_Air_Patrol.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_CAP_ZONE
|
--- @type AI_CAP_ZONE
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
|
-- @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 @{Zone} where the patrol needs to be executed.
|
||||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||||
|
|
||||||
|
|
||||||
--- # AI_CAP_ZONE class, extends @{AI_CAP#AI_PATROL_ZONE}
|
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}
|
||||||
--
|
|
||||||
-- The AI_CAP_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}
|
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_CAP_ZONE is assigned a @{Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event.
|
-- The AI_CAP_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -99,15 +87,15 @@
|
|||||||
--
|
--
|
||||||
-- ### 2.2 AI_CAP_ZONE Events
|
-- ### 2.2 AI_CAP_ZONE Events
|
||||||
--
|
--
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
||||||
-- * **@{#AI_CAP_ZONE.Engage}**: Let the AI engage the bogeys.
|
-- * **@{#AI_CAP_ZONE.Engage}**: Let the AI engage the bogeys.
|
||||||
-- * **@{#AI_CAP_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
-- * **@{#AI_CAP_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Unit}.
|
-- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Unit}s assigned in the CAS task.
|
-- * **@{#AI_CAP_ZONE.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 tresholds have been reached, the AI will RTB.
|
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Set the Range of Engagement
|
-- ## 3. Set the Range of Engagement
|
||||||
@@ -118,7 +106,7 @@
|
|||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- 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 can be beyond or smaller than the range of the Patrol Zone.
|
||||||
-- The range is applied at the position of the AI.
|
-- The range is applied at the position of the AI.
|
||||||
-- Use the method @{AI_CAP#AI_CAP_ZONE.SetEngageRange}() to define that range.
|
-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageRange}() to define that range.
|
||||||
--
|
--
|
||||||
-- ## 4. Set the Zone of Engagement
|
-- ## 4. Set the Zone of Engagement
|
||||||
--
|
--
|
||||||
@@ -126,7 +114,7 @@
|
|||||||
--
|
--
|
||||||
-- An optional @{Zone} can be set,
|
-- An optional @{Zone} can be set,
|
||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- Use the method @{AI_Cap#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
|
-- Use the method @{AI.AI_Cap#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -140,11 +128,11 @@ AI_CAP_ZONE = {
|
|||||||
--- Creates a new AI_CAP_ZONE object
|
--- Creates a new AI_CAP_ZONE object
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @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 @{Zone} where the patrol needs to be executed.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
||||||
-- @return #AI_CAP_ZONE self
|
-- @return #AI_CAP_ZONE self
|
||||||
function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||||
|
|
||||||
|
|||||||
@@ -1,63 +1,48 @@
|
|||||||
--- **AI** -- **Provide Close Air Support to friendly ground troops.**
|
--- **AI** -- Perform Close Air Support (CAS) near friendlies.
|
||||||
--
|
--
|
||||||
-- 
|
-- **Features:**
|
||||||
|
--
|
||||||
|
-- * Hold and standby within a patrol zone.
|
||||||
|
-- * Engage upon command the enemies within an engagement zone.
|
||||||
|
-- * Loop the zone until all enemies are eliminated.
|
||||||
|
-- * Trigger different events upon the results achieved.
|
||||||
|
-- * After combat, return to the patrol zone and hold.
|
||||||
|
-- * RTB when commanded or after fuel.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- AI CAS classes makes AI Controllables execute a Close Air Support.
|
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2)
|
||||||
--
|
--
|
||||||
-- There are the following types of CAS classes defined:
|
-- ===
|
||||||
--
|
|
||||||
-- * @{#AI_CAS_ZONE}: Perform a CAS in a zone.
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # Demo Missions
|
|
||||||
--
|
|
||||||
-- ### [AI_CAS Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support)
|
|
||||||
--
|
|
||||||
-- ### [AI_CAS Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAS%20-%20Close%20Air%20Support)
|
|
||||||
--
|
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # YouTube Channel
|
|
||||||
--
|
|
||||||
-- ### [AI_CAS YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2)
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
|
||||||
--
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
||||||
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: 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.
|
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI_Cas
|
-- @module AI.AI_Cas
|
||||||
|
-- @image AI_Close_Air_Support.JPG
|
||||||
|
|
||||||
--- AI_CAS_ZONE class
|
--- AI_CAS_ZONE class
|
||||||
-- @type AI_CAS_ZONE
|
-- @type AI_CAS_ZONE
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
|
-- @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 @{Zone} where the patrol needs to be executed.
|
||||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||||
|
|
||||||
--- # AI_CAS_ZONE class, extends @{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}.
|
||||||
--
|
|
||||||
-- AI_CAS_ZONE derives from the @{AI_Patrol#AI_PATROL_ZONE}, inheriting its methods and behaviour.
|
|
||||||
--
|
|
||||||
-- The AI_CAS_ZONE class implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Controllable} or @{Group}.
|
|
||||||
-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_CAS_ZONE is assigned a @{Group} and this must be done before the AI_CAS_ZONE process can be started through the **Start** event.
|
-- The AI_CAS_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAS_ZONE process can be started through the **Start** event.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -123,15 +108,15 @@
|
|||||||
--
|
--
|
||||||
-- ### 2.2. AI_CAS_ZONE Events
|
-- ### 2.2. AI_CAS_ZONE Events
|
||||||
--
|
--
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Start}**: Start the process.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Route}**: Route the AI to a new random 3D point within the Patrol Zone.
|
||||||
-- * **@{#AI_CAS_ZONE.Engage}**: Engage the AI to provide CAS in the Engage Zone, destroying any target it finds.
|
-- * **@{#AI_CAS_ZONE.Engage}**: Engage the AI to provide CAS in the Engage Zone, destroying any target it finds.
|
||||||
-- * **@{#AI_CAS_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
-- * **@{#AI_CAS_ZONE.Abort}**: Aborts the engagement and return patrolling in the patrol zone.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.RTB}**: Route the AI to the home base.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detect}**: The AI is detecting targets.
|
||||||
-- * **@{AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Unit}.
|
-- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Unit}s assigned in the CAS task.
|
-- * **@{#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 tresholds have been reached, the AI will RTB.
|
-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -146,12 +131,12 @@ AI_CAS_ZONE = {
|
|||||||
--- Creates a new AI_CAS_ZONE object
|
--- Creates a new AI_CAS_ZONE object
|
||||||
-- @param #AI_CAS_ZONE self
|
-- @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 @{Zone} where the patrol needs to be executed.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen.
|
-- @param Core.Zone#ZONE_BASE EngageZone The zone where the engage will happen.
|
||||||
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
||||||
-- @return #AI_CAS_ZONE self
|
-- @return #AI_CAS_ZONE self
|
||||||
function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType )
|
function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageZone, PatrolAltType )
|
||||||
|
|
||||||
@@ -187,24 +172,24 @@ function AI_CAS_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @function [parent=#AI_CAS_ZONE] Engage
|
-- @function [parent=#AI_CAS_ZONE] Engage
|
||||||
-- @param #AI_CAS_ZONE self
|
-- @param #AI_CAS_ZONE self
|
||||||
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
||||||
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
||||||
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
|
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
|
||||||
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
|
-- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
|
||||||
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
|
|
||||||
--- Asynchronous Event Trigger for Event Engage.
|
--- Asynchronous Event Trigger for Event Engage.
|
||||||
-- @function [parent=#AI_CAS_ZONE] __Engage
|
-- @function [parent=#AI_CAS_ZONE] __Engage
|
||||||
-- @param #AI_CAS_ZONE self
|
-- @param #AI_CAS_ZONE self
|
||||||
-- @param #number Delay The delay in seconds.
|
-- @param #number Delay The delay in seconds.
|
||||||
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
||||||
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
||||||
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
|
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack.
|
||||||
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- Use the structure @{DCSTypes#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
|
-- Use the structure @{DCS#AI.Task.WeaponExpend} to define the amount of weapons to be release at each attack.
|
||||||
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
|
|
||||||
--- OnLeave Transition Handler for State Engaging.
|
--- OnLeave Transition Handler for State Engaging.
|
||||||
-- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging
|
-- @function [parent=#AI_CAS_ZONE] OnLeaveEngaging
|
||||||
@@ -403,7 +388,6 @@ end
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
function AI_CAS_ZONE:onafterTarget( Controllable, From, Event, To )
|
function AI_CAS_ZONE:onafterTarget( Controllable, From, Event, To )
|
||||||
self:E("onafterTarget")
|
|
||||||
|
|
||||||
if Controllable:IsAlive() then
|
if Controllable:IsAlive() then
|
||||||
|
|
||||||
@@ -414,7 +398,7 @@ function AI_CAS_ZONE:onafterTarget( Controllable, From, Event, To )
|
|||||||
if DetectedUnit:IsAlive() then
|
if DetectedUnit:IsAlive() then
|
||||||
if DetectedUnit:IsInZone( self.EngageZone ) then
|
if DetectedUnit:IsInZone( self.EngageZone ) then
|
||||||
if Detected == true then
|
if Detected == true then
|
||||||
self:E( {"Target: ", DetectedUnit } )
|
self:F( {"Target: ", DetectedUnit } )
|
||||||
self.DetectedUnits[DetectedUnit] = false
|
self.DetectedUnits[DetectedUnit] = false
|
||||||
local AttackTask = Controllable:TaskAttackUnit( DetectedUnit, false, self.EngageWeaponExpend, self.EngageAttackQty, self.EngageDirection, self.EngageAltitude, nil )
|
local AttackTask = Controllable:TaskAttackUnit( DetectedUnit, false, self.EngageWeaponExpend, self.EngageAttackQty, self.EngageDirection, self.EngageAltitude, nil )
|
||||||
self.Controllable:PushTask( AttackTask, 1 )
|
self.Controllable:PushTask( AttackTask, 1 )
|
||||||
@@ -447,10 +431,10 @@ end
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
-- @param #number EngageSpeed (optional) The speed the Group will hold when engaging to the target zone.
|
||||||
-- @param Dcs.DCSTypes#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
-- @param DCS#Distance EngageAltitude (optional) Desired altitude to perform the unit engagement.
|
||||||
-- @param Dcs.DCSTypes#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- @param DCS#AI.Task.WeaponExpend EngageWeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number EngageAttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param Dcs.DCSTypes#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth EngageDirection (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||||
EngageSpeed,
|
EngageSpeed,
|
||||||
EngageAltitude,
|
EngageAltitude,
|
||||||
@@ -496,7 +480,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
self:T( DetectedUnit )
|
self:T( DetectedUnit )
|
||||||
if DetectedUnit:IsAlive() then
|
if DetectedUnit:IsAlive() then
|
||||||
if DetectedUnit:IsInZone( self.EngageZone ) then
|
if DetectedUnit:IsInZone( self.EngageZone ) then
|
||||||
self:E( {"Engaging ", DetectedUnit } )
|
self:F( {"Engaging ", DetectedUnit } )
|
||||||
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit,
|
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit,
|
||||||
true,
|
true,
|
||||||
EngageWeaponExpend,
|
EngageWeaponExpend,
|
||||||
|
|||||||
486
Moose Development/Moose/AI/AI_Cargo.lua
Normal file
486
Moose Development/Moose/AI/AI_Cargo.lua
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module AI.AI_Cargo
|
||||||
|
-- @image Cargo.JPG
|
||||||
|
|
||||||
|
--- @type AI_CARGO
|
||||||
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
|
|
||||||
|
--- 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.
|
||||||
|
-- Please consult the @{Cargo.Cargo} module for more information.
|
||||||
|
--
|
||||||
|
-- The derived classes from this module are:
|
||||||
|
--
|
||||||
|
-- * @{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.
|
||||||
|
--
|
||||||
|
-- @field #AI_CARGO
|
||||||
|
AI_CARGO = {
|
||||||
|
ClassName = "AI_CARGO",
|
||||||
|
Coordinate = nil, -- Core.Point#COORDINATE,
|
||||||
|
Carrier_Cargo = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new AI_CARGO object.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param Core.Set#SET_CARGO CargoSet
|
||||||
|
-- @param #number CombatRadius
|
||||||
|
-- @return #AI_CARGO
|
||||||
|
function AI_CARGO:New( Carrier, CargoSet )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( Carrier ) ) -- #AI_CARGO
|
||||||
|
|
||||||
|
self.CargoSet = CargoSet -- Core.Set#SET_CARGO
|
||||||
|
self.CargoCarrier = Carrier -- Wrapper.Group#GROUP
|
||||||
|
|
||||||
|
self:SetStartState( "Unloaded" )
|
||||||
|
|
||||||
|
self:AddTransition( "Unloaded", "Pickup", "*" )
|
||||||
|
self:AddTransition( "Loaded", "Deploy", "*" )
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Load", "Boarding" )
|
||||||
|
self:AddTransition( { "Boarding", "Loaded" }, "Board", "Boarding" )
|
||||||
|
self:AddTransition( "Boarding", "Loaded", "Boarding" )
|
||||||
|
self:AddTransition( "Boarding", "PickedUp", "Loaded" )
|
||||||
|
|
||||||
|
self:AddTransition( "Loaded", "Unload", "Unboarding" )
|
||||||
|
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
|
||||||
|
self:AddTransition( "Unboarding", "Unloaded", "Unboarding" )
|
||||||
|
self:AddTransition( "Unboarding", "Deployed", "Unloaded" )
|
||||||
|
|
||||||
|
--- Pickup Handler OnBefore for AI_CARGO
|
||||||
|
-- @function [parent=#AI_CARGO] OnBeforePickup
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Pickup Handler OnAfter for AI_CARGO
|
||||||
|
-- @function [parent=#AI_CARGO] OnAfterPickup
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
|
||||||
|
|
||||||
|
--- Pickup Trigger for AI_CARGO
|
||||||
|
-- @function [parent=#AI_CARGO] Pickup
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
|
||||||
|
|
||||||
|
--- Pickup Asynchronous Trigger for AI_CARGO
|
||||||
|
-- @function [parent=#AI_CARGO] __Pickup
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param #number Delay
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Pickup place. If not given, loading starts at the current location.
|
||||||
|
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
|
||||||
|
|
||||||
|
--- Deploy Handler OnBefore for AI_CARGO
|
||||||
|
-- @function [parent=#AI_CARGO] OnBeforeDeploy
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Deploy Handler OnAfter for AI_CARGO
|
||||||
|
-- @function [parent=#AI_CARGO] OnAfterDeploy
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
|
||||||
|
|
||||||
|
--- Deploy Trigger for AI_CARGO
|
||||||
|
-- @function [parent=#AI_CARGO] Deploy
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
|
||||||
|
|
||||||
|
--- Deploy Asynchronous Trigger for AI_CARGO
|
||||||
|
-- @function [parent=#AI_CARGO] __Deploy
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param #number Delay
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
|
||||||
|
|
||||||
|
|
||||||
|
--- Loaded Handler OnAfter for AI_CARGO
|
||||||
|
-- @function [parent=#AI_CARGO] OnAfterLoaded
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
--- Unloaded Handler OnAfter for AI_CARGO
|
||||||
|
-- @function [parent=#AI_CARGO] OnAfterUnloaded
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
|
||||||
|
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
|
||||||
|
CarrierUnit:SetCargoBayWeightLimit()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.Transporting = false
|
||||||
|
self.Relocating = false
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function AI_CARGO:IsTransporting()
|
||||||
|
|
||||||
|
return self.Transporting == true
|
||||||
|
end
|
||||||
|
|
||||||
|
function AI_CARGO:IsRelocating()
|
||||||
|
|
||||||
|
return self.Relocating == true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Pickup event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP APC
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate of the pickup point.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height Height in meters to move to the home coordinate.
|
||||||
|
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
|
||||||
|
function AI_CARGO:onafterPickup( APC, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
||||||
|
|
||||||
|
self.Transporting = false
|
||||||
|
self.Relocating = true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Deploy event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP APC
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Deploy place.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the depoly coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height Height in meters to move to the deploy coordinate.
|
||||||
|
-- @param Core.Zone#ZONE DeployZone The zone where the cargo will be deployed.
|
||||||
|
function AI_CARGO:onafterDeploy( APC, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
|
||||||
|
self.Relocating = false
|
||||||
|
self.Transporting = true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On before Load event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
|
||||||
|
function AI_CARGO:onbeforeLoad( Carrier, From, Event, To, PickupZone )
|
||||||
|
self:F( { Carrier, From, Event, To } )
|
||||||
|
|
||||||
|
local Boarding = false
|
||||||
|
|
||||||
|
local LoadInterval = 5
|
||||||
|
local LoadDelay = 0
|
||||||
|
local Carrier_List = {}
|
||||||
|
local Carrier_Weight = {}
|
||||||
|
|
||||||
|
if Carrier and Carrier:IsAlive() then
|
||||||
|
self.Carrier_Cargo = {}
|
||||||
|
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
|
||||||
|
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
local CargoBayFreeWeight = CarrierUnit:GetCargoBayFreeWeight()
|
||||||
|
self:F({CargoBayFreeWeight=CargoBayFreeWeight})
|
||||||
|
|
||||||
|
Carrier_List[#Carrier_List+1] = CarrierUnit
|
||||||
|
Carrier_Weight[CarrierUnit] = CargoBayFreeWeight
|
||||||
|
end
|
||||||
|
|
||||||
|
local Carrier_Count = #Carrier_List
|
||||||
|
local Carrier_Index = 1
|
||||||
|
|
||||||
|
local Loaded = false
|
||||||
|
|
||||||
|
for _, Cargo in UTILS.spairs( self.CargoSet:GetSet(), function( t, a, b ) return t[a]:GetWeight() > t[b]:GetWeight() end ) do
|
||||||
|
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||||
|
|
||||||
|
self:F( { IsUnLoaded = Cargo:IsUnLoaded(), IsDeployed = Cargo:IsDeployed(), Cargo:GetName(), Carrier:GetName() } )
|
||||||
|
|
||||||
|
-- Try all Carriers, but start from the one according the Carrier_Index
|
||||||
|
for Carrier_Loop = 1, #Carrier_List do
|
||||||
|
|
||||||
|
local CarrierUnit = Carrier_List[Carrier_Index] -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
-- This counters loop through the available Carriers.
|
||||||
|
Carrier_Index = Carrier_Index + 1
|
||||||
|
if Carrier_Index > Carrier_Count then
|
||||||
|
Carrier_Index = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then
|
||||||
|
if Cargo:IsInLoadRadius( CarrierUnit:GetCoordinate() ) then
|
||||||
|
self:F( { "In radius", CarrierUnit:GetName() } )
|
||||||
|
|
||||||
|
local CargoWeight = Cargo:GetWeight()
|
||||||
|
|
||||||
|
-- Only when there is space within the bay to load the next cargo item!
|
||||||
|
if Carrier_Weight[CarrierUnit] > CargoWeight then --and CargoBayFreeVolume > CargoVolume then
|
||||||
|
Carrier:RouteStop()
|
||||||
|
--Cargo:Ungroup()
|
||||||
|
Cargo:__Board( -LoadDelay, CarrierUnit )
|
||||||
|
LoadDelay = LoadDelay + Cargo:GetCount() * LoadInterval
|
||||||
|
self:__Board( LoadDelay, Cargo, CarrierUnit, PickupZone )
|
||||||
|
|
||||||
|
-- So now this CarrierUnit has Cargo that is being loaded.
|
||||||
|
-- This will be used further in the logic to follow and to check cargo status.
|
||||||
|
self.Carrier_Cargo[Cargo] = CarrierUnit
|
||||||
|
Boarding = true
|
||||||
|
Carrier_Weight[CarrierUnit] = Carrier_Weight[CarrierUnit] - CargoWeight
|
||||||
|
Loaded = true
|
||||||
|
|
||||||
|
-- Ok, we loaded a cargo, now we can stop the loop.
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if not Loaded == true then
|
||||||
|
-- No loading happened, so we need to pickup something else.
|
||||||
|
self.Relocating = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Boarding
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Board event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Cargo.Cargo#CARGO Cargo Cargo object.
|
||||||
|
-- @param Wrapper.Unit#UNIT CarrierUnit
|
||||||
|
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
|
||||||
|
function AI_CARGO:onafterBoard( Carrier, From, Event, To, Cargo, CarrierUnit, PickupZone )
|
||||||
|
self:F( { Carrier, From, Event, To, Cargo, CarrierUnit:GetName() } )
|
||||||
|
|
||||||
|
if Carrier and Carrier:IsAlive() then
|
||||||
|
self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), Carrier:GetName() } )
|
||||||
|
if not Cargo:IsLoaded() then
|
||||||
|
self:__Board( -10, Cargo, CarrierUnit, PickupZone )
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:__Loaded( 0.1, Cargo, CarrierUnit, PickupZone )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Loaded event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @return #boolean Cargo loaded.
|
||||||
|
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
|
||||||
|
function AI_CARGO:onafterLoaded( Carrier, From, Event, To, Cargo, PickupZone )
|
||||||
|
self:F( { Carrier, From, Event, To } )
|
||||||
|
|
||||||
|
local Loaded = true
|
||||||
|
|
||||||
|
if Carrier and Carrier:IsAlive() then
|
||||||
|
for Cargo, CarrierUnit in pairs( self.Carrier_Cargo ) do
|
||||||
|
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||||
|
self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed(), Cargo:GetName(), Carrier:GetName() } )
|
||||||
|
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
|
||||||
|
Loaded = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if Loaded then
|
||||||
|
self:__PickedUp( 0.1, PickupZone )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after PickedUp event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
|
||||||
|
function AI_CARGO:onafterPickedUp( Carrier, From, Event, To, PickupZone )
|
||||||
|
self:F( { Carrier, From, Event, To } )
|
||||||
|
|
||||||
|
Carrier:RouteResume()
|
||||||
|
|
||||||
|
local HasCargo = false
|
||||||
|
if Carrier and Carrier :IsAlive() then
|
||||||
|
for Cargo, CarrierUnit in pairs( self.Carrier_Cargo ) do
|
||||||
|
HasCargo = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.Relocating = false
|
||||||
|
if HasCargo then
|
||||||
|
self.Transporting = true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Unload event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
|
function AI_CARGO:onafterUnload( Carrier, From, Event, To, DeployZone )
|
||||||
|
self:F( { Carrier, From, Event, To, DeployZone } )
|
||||||
|
|
||||||
|
local UnboardInterval = 10
|
||||||
|
local UnboardDelay = 10
|
||||||
|
|
||||||
|
if Carrier and Carrier:IsAlive() then
|
||||||
|
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
|
||||||
|
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
|
||||||
|
Carrier:RouteStop()
|
||||||
|
for _, Cargo in pairs( CarrierUnit:GetCargo() ) do
|
||||||
|
self:F( { Cargo = Cargo:GetName(), Isloaded = Cargo:IsLoaded() } )
|
||||||
|
if Cargo:IsLoaded() then
|
||||||
|
Cargo:__UnBoard( UnboardDelay )
|
||||||
|
UnboardDelay = UnboardDelay + Cargo:GetCount() * UnboardInterval
|
||||||
|
Cargo:SetDeployed( true )
|
||||||
|
self:__Unboard( UnboardDelay, Cargo, CarrierUnit, DeployZone )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Unboard event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
|
||||||
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
|
function AI_CARGO:onafterUnboard( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone )
|
||||||
|
self:F( { Carrier, From, Event, To, Cargo:GetName() } )
|
||||||
|
|
||||||
|
if Carrier and Carrier:IsAlive() then
|
||||||
|
if not Cargo:IsUnLoaded() then
|
||||||
|
self:__Unboard( 10, Cargo, CarrierUnit, DeployZone )
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:Unloaded( Cargo, CarrierUnit, DeployZone )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Unloaded event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
|
||||||
|
-- @param #boolean Deployed Cargo is deployed.
|
||||||
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
|
function AI_CARGO:onafterUnloaded( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone )
|
||||||
|
self:F( { Carrier, From, Event, To, Cargo:GetName(), DeployZone = DeployZone } )
|
||||||
|
|
||||||
|
local AllUnloaded = true
|
||||||
|
|
||||||
|
--Cargo:Regroup()
|
||||||
|
|
||||||
|
if Carrier and Carrier:IsAlive() then
|
||||||
|
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
|
||||||
|
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
|
||||||
|
local IsEmpty = CarrierUnit:IsCargoEmpty()
|
||||||
|
self:I({ IsEmpty = IsEmpty })
|
||||||
|
if not IsEmpty then
|
||||||
|
AllUnloaded = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if AllUnloaded == true then
|
||||||
|
if DeployZone == true then
|
||||||
|
self.Carrier_Cargo = {}
|
||||||
|
end
|
||||||
|
self.CargoCarrier = Carrier
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if AllUnloaded == true then
|
||||||
|
self:__Deployed( 5, DeployZone )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Deployed event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
|
function AI_CARGO:onafterDeployed( Carrier, From, Event, To, DeployZone )
|
||||||
|
self:F( { Carrier, From, Event, To, DeployZone = DeployZone } )
|
||||||
|
|
||||||
|
self.Transporting = false
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
488
Moose Development/Moose/AI/AI_Cargo_APC.lua
Normal file
488
Moose Development/Moose/AI/AI_Cargo_APC.lua
Normal file
@@ -0,0 +1,488 @@
|
|||||||
|
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module AI.AI_Cargo_APC
|
||||||
|
-- @image AI_Cargo_Dispatching_For_APC.JPG
|
||||||
|
|
||||||
|
--- @type AI_CARGO_APC
|
||||||
|
-- @extends AI.AI_Cargo#AI_CARGO
|
||||||
|
|
||||||
|
|
||||||
|
--- 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.
|
||||||
|
-- @{Cargo.Cargo} must be declared within the mission to make the AI_CARGO_APC object recognize the cargo.
|
||||||
|
-- Please consult the @{Cargo.Cargo} module for more information.
|
||||||
|
--
|
||||||
|
-- ## Cargo loading.
|
||||||
|
--
|
||||||
|
-- The module will load automatically cargo when the APCs are within boarding or loading radius.
|
||||||
|
-- The boarding or loading radius is specified when the cargo is created in the simulation, and therefore, this radius depends on the type of cargo
|
||||||
|
-- and the specified boarding radius.
|
||||||
|
--
|
||||||
|
-- ## **Defending** the APCs when enemies nearby.
|
||||||
|
--
|
||||||
|
-- Cargo will defend the carrier with its available arms, and to avoid cargo being lost within the battlefield.
|
||||||
|
--
|
||||||
|
-- When the APCs are approaching enemy units, something special is happening.
|
||||||
|
-- The APCs will stop moving, and the loaded infantry will unboard and follow the APCs and will help to defend the group.
|
||||||
|
-- The carrier will hold the route once the unboarded infantry is further than 50 meters from the APCs,
|
||||||
|
-- to ensure that the APCs are not too far away from the following running infantry.
|
||||||
|
-- Once all enemies are cleared, the infantry will board again automatically into the APCs. Once boarded, the APCs will follow its pre-defined route.
|
||||||
|
--
|
||||||
|
-- A combat radius needs to be specified in meters at the @{#AI_CARGO_APC.New}() method.
|
||||||
|
-- This combat radius will trigger the unboarding of troops when enemies are within the combat radius around the APCs.
|
||||||
|
-- During my tests, I've noticed that there is a balance between ensuring that the infantry is within sufficient hit radius (effectiveness) versus
|
||||||
|
-- vulnerability of the infantry. It all depends on the kind of enemies that are expected to be encountered.
|
||||||
|
-- A combat radius of 350 meters to 500 meters has been proven to be the most effective and efficient.
|
||||||
|
--
|
||||||
|
-- However, when the defense of the carrier, is not required, it must be switched off.
|
||||||
|
-- This is done by disabling the defense of the carrier using the method @{#AI_CARGO_APC.SetCombatRadius}(), and providing a combat radius of 0 meters.
|
||||||
|
-- It can be switched on later when required by reenabling the defense using the method and providing a combat radius larger than 0.
|
||||||
|
--
|
||||||
|
-- ## Infantry or cargo **health**.
|
||||||
|
--
|
||||||
|
-- When infantry is unboarded from the APCs, the infantry is actually respawned into the battlefield.
|
||||||
|
-- As a result, the unboarding infantry is very _healthy_ every time it unboards.
|
||||||
|
-- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter.
|
||||||
|
-- However, infantry that was destroyed when unboarded and following the APCs, won't be respawned again. Destroyed is destroyed.
|
||||||
|
-- As a result, there is some additional strength that is gained when an unboarding action happens, but in terms of simulation balance this has
|
||||||
|
-- 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 ...
|
||||||
|
--
|
||||||
|
-- ## Control the APCs on the map.
|
||||||
|
--
|
||||||
|
-- It is possible also as a human ground commander to influence the path of the APCs, by pointing a new path using the DCS user interface on the map.
|
||||||
|
-- In this case, the APCs will change the direction towards its new indicated route. However, there is a catch!
|
||||||
|
-- Once the APCs are near the enemy, and infantry is unboarded, the APCs won't be able to hold the route until the infantry could catch up.
|
||||||
|
-- The APCs will simply drive on and won't stop! This is a limitation in ED that prevents user actions being controlled by the scripting engine.
|
||||||
|
-- No workaround is possible on this.
|
||||||
|
--
|
||||||
|
-- ## Cargo deployment.
|
||||||
|
--
|
||||||
|
-- Using the @{#AI_CARGO_APC.Deploy}() method, you are able to direct the APCs towards a point on the battlefield to unboard/unload 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.
|
||||||
|
--
|
||||||
|
-- ## Cargo pickup.
|
||||||
|
--
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #AI_CARGO_APC
|
||||||
|
AI_CARGO_APC = {
|
||||||
|
ClassName = "AI_CARGO_APC",
|
||||||
|
Coordinate = nil, -- Core.Point#COORDINATE,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new AI_CARGO_APC object.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param Wrapper.Group#GROUP APC The carrier APC group.
|
||||||
|
-- @param Core.Set#SET_CARGO CargoSet The set of cargo to be transported.
|
||||||
|
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby. When the combat radius is 0, no defense will happen of the carrier.
|
||||||
|
-- @return #AI_CARGO_APC
|
||||||
|
function AI_CARGO_APC:New( APC, CargoSet, CombatRadius )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, AI_CARGO:New( APC, CargoSet ) ) -- #AI_CARGO_APC
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Monitor", "*" )
|
||||||
|
self:AddTransition( "*", "Follow", "Following" )
|
||||||
|
self:AddTransition( "*", "Guard", "Unloaded" )
|
||||||
|
self:AddTransition( "*", "Home", "*" )
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Destroyed", "Destroyed" )
|
||||||
|
|
||||||
|
self:SetCombatRadius( CombatRadius )
|
||||||
|
|
||||||
|
self:SetCarrier( APC )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set the Carrier.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param Wrapper.Group#GROUP CargoCarrier
|
||||||
|
-- @return #AI_CARGO_APC
|
||||||
|
function AI_CARGO_APC:SetCarrier( CargoCarrier )
|
||||||
|
|
||||||
|
self.CargoCarrier = CargoCarrier -- Wrapper.Group#GROUP
|
||||||
|
self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_APC", self )
|
||||||
|
|
||||||
|
CargoCarrier:HandleEvent( EVENTS.Dead )
|
||||||
|
CargoCarrier:HandleEvent( EVENTS.Hit )
|
||||||
|
|
||||||
|
function CargoCarrier:OnEventDead( EventData )
|
||||||
|
self:F({"dead"})
|
||||||
|
local AICargoTroops = self:GetState( self, "AI_CARGO_APC" )
|
||||||
|
self:F({AICargoTroops=AICargoTroops})
|
||||||
|
if AICargoTroops then
|
||||||
|
self:F({})
|
||||||
|
if not AICargoTroops:Is( "Loaded" ) then
|
||||||
|
-- There are enemies within combat radius. Unload the CargoCarrier.
|
||||||
|
AICargoTroops:Destroyed()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CargoCarrier:OnEventHit( EventData )
|
||||||
|
self:F({"hit"})
|
||||||
|
local AICargoTroops = self:GetState( self, "AI_CARGO_APC" )
|
||||||
|
if AICargoTroops then
|
||||||
|
self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } )
|
||||||
|
if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then
|
||||||
|
-- There are enemies within combat radius. Unload the CargoCarrier.
|
||||||
|
AICargoTroops:Unload( false )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, self.CombatRadius )
|
||||||
|
self.Coalition = self.CargoCarrier:GetCoalition()
|
||||||
|
|
||||||
|
self:SetControllable( CargoCarrier )
|
||||||
|
|
||||||
|
self:Guard()
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Find a free Carrier within a radius.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Radius
|
||||||
|
-- @return Wrapper.Group#GROUP NewCarrier
|
||||||
|
function AI_CARGO_APC:FindCarrier( Coordinate, Radius )
|
||||||
|
|
||||||
|
local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius )
|
||||||
|
CoordinateZone:Scan( { Object.Category.UNIT } )
|
||||||
|
for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do
|
||||||
|
local NearUnit = UNIT:Find( DCSUnit )
|
||||||
|
self:F({NearUnit=NearUnit})
|
||||||
|
if not NearUnit:GetState( NearUnit, "AI_CARGO_APC" ) then
|
||||||
|
local Attributes = NearUnit:GetDesc()
|
||||||
|
self:F({Desc=Attributes})
|
||||||
|
if NearUnit:HasAttribute( "Trucks" ) then
|
||||||
|
return NearUnit:GetGroup()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Enable/Disable unboarding of cargo (infantry) when enemies are nearby (to help defend the carrier).
|
||||||
|
-- This is only valid for APCs and trucks etc, thus ground vehicles.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby.
|
||||||
|
-- When the combat radius is 0, no defense will happen of the carrier.
|
||||||
|
-- When the combat radius is not provided, no defense will happen!
|
||||||
|
-- @return #AI_CARGO_APC
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- Disembark the infantry when the carrier is under attack.
|
||||||
|
-- AICargoAPC:SetCombatRadius( true )
|
||||||
|
--
|
||||||
|
-- -- Keep the cargo in the carrier when the carrier is under attack.
|
||||||
|
-- AICargoAPC:SetCombatRadius( false )
|
||||||
|
function AI_CARGO_APC:SetCombatRadius( CombatRadius )
|
||||||
|
|
||||||
|
self.CombatRadius = CombatRadius or 0
|
||||||
|
|
||||||
|
if self.CombatRadius > 0 then
|
||||||
|
self:__Monitor( -5 )
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Follow Infantry to the Carrier.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param #AI_CARGO_APC Me
|
||||||
|
-- @param Wrapper.Unit#UNIT APCUnit
|
||||||
|
-- @param Cargo.CargoGroup#CARGO_GROUP Cargo
|
||||||
|
-- @return #AI_CARGO_APC
|
||||||
|
function AI_CARGO_APC:FollowToCarrier( Me, APCUnit, CargoGroup )
|
||||||
|
|
||||||
|
local InfantryGroup = CargoGroup:GetGroup()
|
||||||
|
|
||||||
|
self:F( { self = self:GetClassNameAndID(), InfantryGroup = InfantryGroup:GetName() } )
|
||||||
|
|
||||||
|
--if self:Is( "Following" ) then
|
||||||
|
|
||||||
|
if APCUnit:IsAlive() then
|
||||||
|
-- We check if the Cargo is near to the CargoCarrier.
|
||||||
|
if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", APCUnit, 25 ) ) then
|
||||||
|
|
||||||
|
-- The Cargo does not need to follow the Carrier.
|
||||||
|
Me:Guard()
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
self:F( { InfantryGroup = InfantryGroup:GetName() } )
|
||||||
|
|
||||||
|
if InfantryGroup:IsAlive() then
|
||||||
|
|
||||||
|
self:F( { InfantryGroup = InfantryGroup:GetName() } )
|
||||||
|
|
||||||
|
local Waypoints = {}
|
||||||
|
|
||||||
|
-- Calculate the new Route.
|
||||||
|
local FromCoord = InfantryGroup:GetCoordinate()
|
||||||
|
local FromGround = FromCoord:WaypointGround( 10, "Diamond" )
|
||||||
|
self:F({FromGround=FromGround})
|
||||||
|
table.insert( Waypoints, FromGround )
|
||||||
|
|
||||||
|
local ToCoord = APCUnit:GetCoordinate():GetRandomCoordinateInRadius( 10, 5 )
|
||||||
|
local ToGround = ToCoord:WaypointGround( 10, "Diamond" )
|
||||||
|
self:F({ToGround=ToGround})
|
||||||
|
table.insert( Waypoints, ToGround )
|
||||||
|
|
||||||
|
local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_APC.FollowToCarrier", Me, APCUnit, CargoGroup )
|
||||||
|
|
||||||
|
self:F({Waypoints = Waypoints})
|
||||||
|
local Waypoint = Waypoints[#Waypoints]
|
||||||
|
InfantryGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||||
|
|
||||||
|
InfantryGroup:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Monitor event.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param Wrapper.Group#GROUP APC
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
|
||||||
|
self:F( { APC, From, Event, To, IsTransporting = self:IsTransporting() } )
|
||||||
|
|
||||||
|
if self.CombatRadius > 0 then
|
||||||
|
if APC and APC:IsAlive() then
|
||||||
|
if self.CarrierCoordinate then
|
||||||
|
if self:IsTransporting() == true then
|
||||||
|
local Coordinate = APC:GetCoordinate()
|
||||||
|
self.Zone:Scan( { Object.Category.UNIT } )
|
||||||
|
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
|
||||||
|
if self:Is( "Unloaded" ) or self:Is( "Following" ) then
|
||||||
|
-- There are no enemies within combat radius. Load the CargoCarrier.
|
||||||
|
self:Load()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if self:Is( "Loaded" ) then
|
||||||
|
-- There are enemies within combat radius. Unload the CargoCarrier.
|
||||||
|
self:__Unload( 1 )
|
||||||
|
else
|
||||||
|
if self:Is( "Unloaded" ) then
|
||||||
|
self:Follow()
|
||||||
|
end
|
||||||
|
self:F( "I am here" .. self:GetCurrentState() )
|
||||||
|
if self:Is( "Following" ) then
|
||||||
|
for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do
|
||||||
|
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||||
|
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
|
||||||
|
if Cargo:IsAlive() then
|
||||||
|
if not Cargo:IsNear( APCUnit, 40 ) then
|
||||||
|
APCUnit:RouteStop()
|
||||||
|
self.CarrierStopped = true
|
||||||
|
else
|
||||||
|
if self.CarrierStopped then
|
||||||
|
if Cargo:IsNear( APCUnit, 25 ) then
|
||||||
|
APCUnit:RouteResume()
|
||||||
|
self.CarrierStopped = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
self.CarrierCoordinate = APC:GetCoordinate()
|
||||||
|
end
|
||||||
|
|
||||||
|
self:__Monitor( -5 )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Follow event.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param Wrapper.Group#GROUP APC
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
function AI_CARGO_APC:onafterFollow( APC, From, Event, To )
|
||||||
|
self:F( { APC, From, Event, To } )
|
||||||
|
|
||||||
|
self:F( "Follow" )
|
||||||
|
if APC and APC:IsAlive() then
|
||||||
|
for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do
|
||||||
|
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||||
|
if Cargo:IsUnLoaded() then
|
||||||
|
self:FollowToCarrier( self, APCUnit, Cargo )
|
||||||
|
APCUnit:RouteResume()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #AI_CARGO_APC
|
||||||
|
-- @param Wrapper.Group#GROUP APC
|
||||||
|
function AI_CARGO_APC._Pickup( APC, self, Coordinate, Speed, PickupZone )
|
||||||
|
|
||||||
|
APC:F( { "AI_CARGO_APC._Pickup:", APC:GetName() } )
|
||||||
|
|
||||||
|
if APC:IsAlive() then
|
||||||
|
self:Load( PickupZone )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function AI_CARGO_APC._Deploy( APC, self, Coordinate, DeployZone )
|
||||||
|
|
||||||
|
APC:F( { "AI_CARGO_APC._Deploy:", APC } )
|
||||||
|
|
||||||
|
if APC:IsAlive() then
|
||||||
|
self:Unload( DeployZone )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Pickup event.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param Wrapper.Group#GROUP APC
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate of the pickup point.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height Height in meters to move to the pickup coordinate. This parameter is ignored for APCs.
|
||||||
|
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
|
||||||
|
function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
||||||
|
|
||||||
|
if APC and APC:IsAlive() then
|
||||||
|
|
||||||
|
if Coordinate then
|
||||||
|
self.RoutePickup = true
|
||||||
|
|
||||||
|
local _speed=Speed or APC:GetSpeedMax()*0.5
|
||||||
|
|
||||||
|
local Waypoints = APC:TaskGroundOnRoad( Coordinate, _speed, "Line abreast", true )
|
||||||
|
|
||||||
|
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self, Coordinate, Speed, PickupZone )
|
||||||
|
|
||||||
|
self:F({Waypoints = Waypoints})
|
||||||
|
local Waypoint = Waypoints[#Waypoints]
|
||||||
|
APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||||
|
|
||||||
|
APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||||
|
else
|
||||||
|
AI_CARGO_APC._Pickup( APC, self, Coordinate, Speed, PickupZone )
|
||||||
|
end
|
||||||
|
|
||||||
|
self:GetParent( self, AI_CARGO_APC ).onafterPickup( self, APC, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Deploy event.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param Wrapper.Group#GROUP APC
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Deploy place.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the depoly coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height Height in meters to move to the deploy coordinate. This parameter is ignored for APCs.
|
||||||
|
-- @param Core.Zone#ZONE DeployZone The zone where the cargo will be deployed.
|
||||||
|
function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
|
||||||
|
if APC and APC:IsAlive() then
|
||||||
|
|
||||||
|
self.RouteDeploy = true
|
||||||
|
|
||||||
|
local _speed=Speed or APC:GetSpeedMax()*0.5
|
||||||
|
|
||||||
|
local Waypoints = APC:TaskGroundOnRoad( Coordinate, _speed, "Line abreast", true )
|
||||||
|
|
||||||
|
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self, Coordinate, DeployZone )
|
||||||
|
|
||||||
|
self:F({Waypoints = Waypoints})
|
||||||
|
local Waypoint = Waypoints[#Waypoints]
|
||||||
|
APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||||
|
|
||||||
|
APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||||
|
|
||||||
|
self:GetParent( self, AI_CARGO_APC ).onafterDeploy( self, APC, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Deployed event.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
|
function AI_CARGO_APC:onafterDeployed( APC, From, Event, To, DeployZone )
|
||||||
|
self:F( { APC, From, Event, To, DeployZone = DeployZone } )
|
||||||
|
|
||||||
|
self:__Guard( 0.1 )
|
||||||
|
|
||||||
|
self:GetParent( self, AI_CARGO_APC ).onafterDeployed( self, APC, From, Event, To, DeployZone )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Home event.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param Wrapper.Group#GROUP APC
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Home place.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height Height in meters to move to the home coordinate. This parameter is ignored for APCs.
|
||||||
|
function AI_CARGO_APC:onafterHome( APC, From, Event, To, Coordinate, Speed, Height, HomeZone )
|
||||||
|
|
||||||
|
if APC and APC:IsAlive() ~= nil then
|
||||||
|
|
||||||
|
self.RouteHome = true
|
||||||
|
|
||||||
|
Speed = Speed or APC:GetSpeedMax()*0.5
|
||||||
|
|
||||||
|
local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed, "Line abreast", true )
|
||||||
|
|
||||||
|
self:F({Waypoints = Waypoints})
|
||||||
|
local Waypoint = Waypoints[#Waypoints]
|
||||||
|
|
||||||
|
APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
484
Moose Development/Moose/AI/AI_Cargo_Airplane.lua
Normal file
484
Moose Development/Moose/AI/AI_Cargo_Airplane.lua
Normal file
@@ -0,0 +1,484 @@
|
|||||||
|
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry (cargo).
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module AI.AI_Cargo_Airplane
|
||||||
|
-- @image AI_Cargo_Dispatching_For_Airplanes.JPG
|
||||||
|
|
||||||
|
--- @type AI_CARGO_AIRPLANE
|
||||||
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
|
|
||||||
|
--- 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.
|
||||||
|
--
|
||||||
|
-- The AI_CARGO_AIRPLANE module uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
|
-- @{Cargo.Cargo} must be declared within the mission to make AI_CARGO_AIRPLANE recognize the cargo.
|
||||||
|
-- Please consult the @{Cargo.Cargo} module for more information.
|
||||||
|
--
|
||||||
|
-- ## Cargo pickup.
|
||||||
|
--
|
||||||
|
-- Using the @{#AI_CARGO_AIRPLANE.Pickup}() method, you are able to direct the helicopters towards a point on the battlefield to board/load the cargo at the specific coordinate.
|
||||||
|
-- Ensure that the landing zone is horizontally flat, and that trees cannot be found in the landing vicinity, or the helicopters won't land or will even crash!
|
||||||
|
--
|
||||||
|
-- ## Cargo deployment.
|
||||||
|
--
|
||||||
|
-- Using the @{#AI_CARGO_AIRPLANE.Deploy}() method, you are able to direct the helicopters towards a point on the battlefield to unboard/unload the cargo at the specific coordinate.
|
||||||
|
-- Ensure that the landing zone is horizontally flat, and that trees cannot be found in the landing vicinity, or the helicopters won't land or will even crash!
|
||||||
|
--
|
||||||
|
-- ## Infantry health.
|
||||||
|
--
|
||||||
|
-- When infantry is unboarded from the APCs, the infantry is actually respawned into the battlefield.
|
||||||
|
-- As a result, the unboarding infantry is very _healthy_ every time it unboards.
|
||||||
|
-- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter.
|
||||||
|
-- However, infantry that was destroyed when unboarded, won't be respawned again. Destroyed is destroyed.
|
||||||
|
-- As a result, there is some additional strength that is gained when an unboarding action happens, but in terms of simulation balance this has
|
||||||
|
-- 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 ...
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #AI_CARGO_AIRPLANE
|
||||||
|
AI_CARGO_AIRPLANE = {
|
||||||
|
ClassName = "AI_CARGO_AIRPLANE",
|
||||||
|
Coordinate = nil, -- Core.Point#COORDINATE
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new AI_CARGO_AIRPLANE object.
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Plane used for transportation of cargo.
|
||||||
|
-- @param Core.Set#SET_CARGO CargoSet Cargo set to be transported.
|
||||||
|
-- @return #AI_CARGO_AIRPLANE
|
||||||
|
function AI_CARGO_AIRPLANE:New( Airplane, CargoSet )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, AI_CARGO:New( Airplane, CargoSet ) ) -- #AI_CARGO_AIRPLANE
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Landed", "*" )
|
||||||
|
self:AddTransition( "*", "Home" , "*" )
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Destroyed", "Destroyed" )
|
||||||
|
|
||||||
|
--- Pickup Handler OnBefore for AI_CARGO_AIRPLANE
|
||||||
|
-- @function [parent=#AI_CARGO_AIRPLANE] OnBeforePickup
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
|
||||||
|
-- @param #number Speed in km/h for travelling to pickup base.
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Pickup Handler OnAfter for AI_CARGO_AIRPLANE
|
||||||
|
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterPickup
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
|
||||||
|
-- @param #number Speed in km/h for travelling to pickup base.
|
||||||
|
|
||||||
|
--- Pickup Trigger for AI_CARGO_AIRPLANE
|
||||||
|
-- @function [parent=#AI_CARGO_AIRPLANE] Pickup
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
|
||||||
|
-- @param #number Speed in km/h for travelling to pickup base.
|
||||||
|
|
||||||
|
--- Pickup Asynchronous Trigger for AI_CARGO_AIRPLANE
|
||||||
|
-- @function [parent=#AI_CARGO_AIRPLANE] __Pickup
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param #number Delay Delay in seconds.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
|
||||||
|
-- @param #number Speed in km/h for travelling to pickup base.
|
||||||
|
|
||||||
|
--- Deploy Handler OnBefore for AI_CARGO_AIRPLANE
|
||||||
|
-- @function [parent=#AI_CARGO_AIRPLANE] OnBeforeDeploy
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
|
||||||
|
-- @param #number Speed Speed in km/h for travelling to deploy base.
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Deploy Handler OnAfter for AI_CARGO_AIRPLANE
|
||||||
|
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterDeploy
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
|
||||||
|
-- @param #number Speed Speed in km/h for travelling to deploy base.
|
||||||
|
|
||||||
|
--- Deploy Trigger for AI_CARGO_AIRPLANE
|
||||||
|
-- @function [parent=#AI_CARGO_AIRPLANE] Deploy
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
|
||||||
|
-- @param #number Speed Speed in km/h for travelling to deploy base.
|
||||||
|
|
||||||
|
--- Deploy Asynchronous Trigger for AI_CARGO_AIRPLANE
|
||||||
|
-- @function [parent=#AI_CARGO_AIRPLANE] __Deploy
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param #number Delay Delay in seconds.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
|
||||||
|
-- @param #number Speed Speed in km/h for travelling to deploy base.
|
||||||
|
|
||||||
|
--- On after Loaded event, i.e. triggered when the cargo is inside the carrier.
|
||||||
|
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterLoaded
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
|
||||||
|
-- Set carrier.
|
||||||
|
self:SetCarrier( Airplane )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set the Carrier (controllable). Also initializes events for carrier and defines the coalition.
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Transport plane.
|
||||||
|
-- @return #AI_CARGO_AIRPLANE self
|
||||||
|
function AI_CARGO_AIRPLANE:SetCarrier( Airplane )
|
||||||
|
|
||||||
|
local AICargo = self
|
||||||
|
|
||||||
|
self.Airplane = Airplane -- Wrapper.Group#GROUP
|
||||||
|
self.Airplane:SetState( self.Airplane, "AI_CARGO_AIRPLANE", self )
|
||||||
|
|
||||||
|
self.RoutePickup = false
|
||||||
|
self.RouteDeploy = false
|
||||||
|
|
||||||
|
Airplane:HandleEvent( EVENTS.Dead )
|
||||||
|
Airplane:HandleEvent( EVENTS.Hit )
|
||||||
|
Airplane:HandleEvent( EVENTS.EngineShutdown )
|
||||||
|
|
||||||
|
function Airplane:OnEventDead( EventData )
|
||||||
|
local AICargoTroops = self:GetState( self, "AI_CARGO_AIRPLANE" )
|
||||||
|
self:F({AICargoTroops=AICargoTroops})
|
||||||
|
if AICargoTroops then
|
||||||
|
self:F({})
|
||||||
|
if not AICargoTroops:Is( "Loaded" ) then
|
||||||
|
-- There are enemies within combat range. Unload the Airplane.
|
||||||
|
AICargoTroops:Destroyed()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Airplane:OnEventHit( EventData )
|
||||||
|
local AICargoTroops = self:GetState( self, "AI_CARGO_AIRPLANE" )
|
||||||
|
if AICargoTroops then
|
||||||
|
self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } )
|
||||||
|
if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then
|
||||||
|
-- There are enemies within combat range. Unload the Airplane.
|
||||||
|
AICargoTroops:Unload()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Airplane:OnEventEngineShutdown( EventData )
|
||||||
|
AICargo.Relocating = false
|
||||||
|
AICargo:Landed( self.Airplane )
|
||||||
|
end
|
||||||
|
|
||||||
|
self.Coalition = self.Airplane:GetCoalition()
|
||||||
|
|
||||||
|
self:SetControllable( Airplane )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Find a free Carrier within a range.
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase
|
||||||
|
-- @param #number Radius
|
||||||
|
-- @return Wrapper.Group#GROUP NewCarrier
|
||||||
|
function AI_CARGO_AIRPLANE:FindCarrier( Coordinate, Radius )
|
||||||
|
|
||||||
|
local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius )
|
||||||
|
CoordinateZone:Scan( { Object.Category.UNIT } )
|
||||||
|
for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do
|
||||||
|
local NearUnit = UNIT:Find( DCSUnit )
|
||||||
|
self:F({NearUnit=NearUnit})
|
||||||
|
if not NearUnit:GetState( NearUnit, "AI_CARGO_AIRPLANE" ) then
|
||||||
|
local Attributes = NearUnit:GetDesc()
|
||||||
|
self:F({Desc=Attributes})
|
||||||
|
if NearUnit:HasAttribute( "Trucks" ) then
|
||||||
|
self:SetCarrier( NearUnit )
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after "Landed" event. Called on engine shutdown and initiates the pickup mission or unloading event.
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To )
|
||||||
|
|
||||||
|
self:F({Airplane, From, Event, To})
|
||||||
|
|
||||||
|
if Airplane and Airplane:IsAlive()~=nil then
|
||||||
|
|
||||||
|
-- Aircraft was sent to this airbase to pickup troops. Initiate loadling.
|
||||||
|
if self.RoutePickup == true then
|
||||||
|
self:Load( self.PickupZone )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Aircraft was send to this airbase to deploy troops. Initiate unloading.
|
||||||
|
if self.RouteDeploy == true then
|
||||||
|
self:Unload()
|
||||||
|
self.RouteDeploy = false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after "Pickup" event. Routes transport to pickup airbase.
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed in km/h for travelling to pickup base.
|
||||||
|
-- @param #number Height Height in meters to move to the pickup coordinate.
|
||||||
|
-- @param Core.Zone#ZONE_AIRBASE (optional) PickupZone The zone where the cargo will be picked up.
|
||||||
|
function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
||||||
|
|
||||||
|
if Airplane and Airplane:IsAlive() then
|
||||||
|
|
||||||
|
self.PickupZone = PickupZone
|
||||||
|
|
||||||
|
-- Get closest airbase of current position.
|
||||||
|
local ClosestAirbase, DistToAirbase=Airplane:GetCoordinate():GetClosestAirbase()
|
||||||
|
|
||||||
|
-- Two cases. Aircraft spawned in air or at an airbase.
|
||||||
|
if Airplane:InAir() then
|
||||||
|
self.Airbase=nil --> route will start in air
|
||||||
|
else
|
||||||
|
self.Airbase=ClosestAirbase
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set pickup airbase.
|
||||||
|
local Airbase = PickupZone:GetAirbase()
|
||||||
|
|
||||||
|
-- Distance from closest to pickup airbase ==> we need to know if we are already at the pickup airbase.
|
||||||
|
local Dist = Airbase:GetCoordinate():Get2DDistance(ClosestAirbase:GetCoordinate())
|
||||||
|
--env.info("Distance closest to pickup airbase = "..Dist)
|
||||||
|
|
||||||
|
if Airplane:InAir() or Dist>500 then
|
||||||
|
|
||||||
|
-- Route aircraft to pickup airbase.
|
||||||
|
self:Route( Airplane, Airbase, Speed, Height )
|
||||||
|
|
||||||
|
-- Set airbase as starting point in the next Route() call.
|
||||||
|
self.Airbase = Airbase
|
||||||
|
|
||||||
|
-- Aircraft is on a pickup mission.
|
||||||
|
self.RoutePickup = true
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- We are already at the right airbase ==> Landed ==> triggers loading of troops. Is usually called at engine shutdown event.
|
||||||
|
self.RoutePickup=true
|
||||||
|
self:Landed()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self:GetParent( self, AI_CARGO_AIRPLANE ).onafterPickup( self, Airplane, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Depoly event. Routes plane to the airbase where the troops are deployed.
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed in km/h for travelling to pickup base.
|
||||||
|
-- @param #number Height Height in meters to move to the home coordinate.
|
||||||
|
-- @param Core.Zone#ZONE_AIRBASE DeployZone The zone where the cargo will be deployed.
|
||||||
|
function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
|
||||||
|
if Airplane and Airplane:IsAlive()~=nil then
|
||||||
|
|
||||||
|
local Airbase = DeployZone:GetAirbase()
|
||||||
|
|
||||||
|
-- Activate uncontrolled airplane.
|
||||||
|
if Airplane:IsAlive()==false then
|
||||||
|
Airplane:SetCommand({id = 'Start', params = {}})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Route to destination airbase.
|
||||||
|
self:Route( Airplane, Airbase, Speed, Height )
|
||||||
|
|
||||||
|
-- Aircraft is on a depoly mission.
|
||||||
|
self.RouteDeploy = true
|
||||||
|
|
||||||
|
-- Set destination airbase for next :Route() command.
|
||||||
|
self.Airbase = Airbase
|
||||||
|
|
||||||
|
self:GetParent( self, AI_CARGO_AIRPLANE ).onafterDeploy( self, Airplane, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Unload event. Cargo is beeing unloaded, i.e. the unboarding process is started.
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To, DeployZone )
|
||||||
|
|
||||||
|
local UnboardInterval = 10
|
||||||
|
local UnboardDelay = 10
|
||||||
|
|
||||||
|
if Airplane and Airplane:IsAlive() then
|
||||||
|
for _, AirplaneUnit in pairs( Airplane:GetUnits() ) do
|
||||||
|
local Cargos = AirplaneUnit:GetCargo()
|
||||||
|
for CargoID, Cargo in pairs( Cargos ) do
|
||||||
|
|
||||||
|
local Angle = 180
|
||||||
|
local CargoCarrierHeading = Airplane:GetHeading() -- Get Heading of object in degrees.
|
||||||
|
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
||||||
|
self:T( { CargoCarrierHeading, CargoDeployHeading } )
|
||||||
|
local CargoDeployCoordinate = Airplane:GetPointVec2():Translate( 150, CargoDeployHeading )
|
||||||
|
|
||||||
|
Cargo:__UnBoard( UnboardDelay, CargoDeployCoordinate )
|
||||||
|
UnboardDelay = UnboardDelay + UnboardInterval
|
||||||
|
Cargo:SetDeployed( true )
|
||||||
|
self:__Unboard( UnboardDelay, Cargo, AirplaneUnit, DeployZone )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Route the airplane from one airport or it's current position to another airbase.
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane Airplane group to be routed.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase.
|
||||||
|
-- @param #number Speed Speed in km/h. Default is 80% of max possible speed the group can do.
|
||||||
|
-- @param #number Height Height in meters to move to the Airbase.
|
||||||
|
-- @param #boolean Uncontrolled If true, spawn group in uncontrolled state.
|
||||||
|
function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed, Height, Uncontrolled )
|
||||||
|
|
||||||
|
if Airplane and Airplane:IsAlive() then
|
||||||
|
|
||||||
|
-- Set takeoff type.
|
||||||
|
local Takeoff = SPAWN.Takeoff.Cold
|
||||||
|
|
||||||
|
-- Get template of group.
|
||||||
|
local Template = Airplane:GetTemplate()
|
||||||
|
|
||||||
|
-- Nil check
|
||||||
|
if Template==nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Waypoints of the route.
|
||||||
|
local Points={}
|
||||||
|
|
||||||
|
-- To point.
|
||||||
|
local AirbasePointVec2 = Airbase:GetPointVec2()
|
||||||
|
local ToWaypoint = AirbasePointVec2:WaypointAir(
|
||||||
|
POINT_VEC3.RoutePointAltType.BARO,
|
||||||
|
"Land",
|
||||||
|
"Landing",
|
||||||
|
Speed or Airplane:GetSpeedMax()*0.8
|
||||||
|
)
|
||||||
|
ToWaypoint["airdromeId"] = Airbase:GetID()
|
||||||
|
ToWaypoint["speed_locked"] = true
|
||||||
|
|
||||||
|
|
||||||
|
-- If self.Airbase~=nil then group is currently at an airbase, where it should be respawned.
|
||||||
|
if self.Airbase then
|
||||||
|
|
||||||
|
-- Second point of the route. First point is done in RespawnAtCurrentAirbase() routine.
|
||||||
|
Template.route.points[2] = ToWaypoint
|
||||||
|
|
||||||
|
-- Respawn group at the current airbase.
|
||||||
|
Airplane:RespawnAtCurrentAirbase(Template, Takeoff, Uncontrolled)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- From point.
|
||||||
|
local GroupPoint = Airplane:GetVec2()
|
||||||
|
local FromWaypoint = {}
|
||||||
|
FromWaypoint.x = GroupPoint.x
|
||||||
|
FromWaypoint.y = GroupPoint.y
|
||||||
|
FromWaypoint.type = "Turning Point"
|
||||||
|
FromWaypoint.action = "Turning Point"
|
||||||
|
FromWaypoint.speed = Airplane:GetSpeedMax()*0.8
|
||||||
|
|
||||||
|
-- The two route points.
|
||||||
|
Points[1] = FromWaypoint
|
||||||
|
Points[2] = ToWaypoint
|
||||||
|
|
||||||
|
local PointVec3 = Airplane:GetPointVec3()
|
||||||
|
Template.x = PointVec3.x
|
||||||
|
Template.y = PointVec3.z
|
||||||
|
|
||||||
|
Template.route.points = Points
|
||||||
|
|
||||||
|
local GroupSpawned = Airplane:Respawn(Template)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Home event. Aircraft will be routed to their home base.
|
||||||
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
|
-- @param Wrapper.Group#GROUP Airplane The cargo plane.
|
||||||
|
-- @param From From state.
|
||||||
|
-- @param Event Event.
|
||||||
|
-- @param To To State.
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Home place (not used).
|
||||||
|
-- @param #number Speed Speed in km/h to fly to the home airbase (zone). Default is 80% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height Height in meters to move to the home coordinate.
|
||||||
|
-- @param Core.Zone#ZONE_AIRBASE HomeZone The home airbase (zone) where the plane should return to.
|
||||||
|
function AI_CARGO_AIRPLANE:onafterHome(Airplane, From, Event, To, Coordinate, Speed, Height, HomeZone )
|
||||||
|
if Airplane and Airplane:IsAlive() then
|
||||||
|
|
||||||
|
-- We are going home!
|
||||||
|
self.RouteHome = true
|
||||||
|
|
||||||
|
-- Home Base.
|
||||||
|
local HomeBase=HomeZone:GetAirbase()
|
||||||
|
self.Airbase=HomeBase
|
||||||
|
|
||||||
|
-- Now route the airplane home
|
||||||
|
self:Route( Airplane, HomeBase, Speed, Height )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
1222
Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua
Normal file
1222
Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua
Normal file
File diff suppressed because it is too large
Load Diff
209
Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua
Normal file
209
Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
--- **AI** -- (2.4) - Models the intelligent transportation of infantry and other cargo using APCs.
|
||||||
|
--
|
||||||
|
-- ## Features:
|
||||||
|
--
|
||||||
|
-- * Quickly transport cargo to various deploy zones using ground vehicles (APCs, trucks ...).
|
||||||
|
-- * Various @{Cargo.Cargo#CARGO} types can be transported. These are infantry groups and crates.
|
||||||
|
-- * Define a list of deploy zones of various types to transport the cargo to.
|
||||||
|
-- * The vehicles follow the roads to ensure the fastest possible cargo transportation over the ground.
|
||||||
|
-- * Multiple vehicles can transport multiple cargo as one vehicle group.
|
||||||
|
-- * Multiple vehicle groups can be enabled as one collaborating transportation process.
|
||||||
|
-- * Infantry loaded as cargo, will unboard in case enemies are nearby and will help defending the vehicles.
|
||||||
|
-- * Different ranges can be setup for enemy defenses.
|
||||||
|
-- * Different options can be setup to tweak the cargo transporation behaviour.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Test Missions:
|
||||||
|
--
|
||||||
|
-- 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)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module AI.AI_Cargo_Dispatcher_APC
|
||||||
|
-- @image AI_Cargo_Dispatching_For_APC.JPG
|
||||||
|
|
||||||
|
--- @type AI_CARGO_DISPATCHER_APC
|
||||||
|
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
|
||||||
|
|
||||||
|
|
||||||
|
--- 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.
|
||||||
|
--
|
||||||
|
-- ## Note! In order to fully understand the mechanisms of the AI_CARGO_DISPATCHER_APC class, it is recommended that you first consult and READ the documentation of the @{AI.AI_Cargo_Dispatcher} module!!!
|
||||||
|
--
|
||||||
|
-- Especially to learn how to **Tailor the different cargo handling events**, this will be very useful!
|
||||||
|
--
|
||||||
|
-- On top, the AI_CARGO_DISPATCHER_APC 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 be declared within the mission to make the AI_CARGO_DISPATCHER_HELICOPTER object recognize the cargo.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # 1) AI_CARGO_DISPATCHER_APC constructor.
|
||||||
|
--
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_APC.New}(): Creates a new AI_CARGO_DISPATCHER_APC object.
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- # 2) AI_CARGO_DISPATCHER_APC is a Finite State Machine.
|
||||||
|
--
|
||||||
|
-- This section must be read as follows. Each of the rows indicate a state transition, triggered through an event, and with an ending state of the event was executed.
|
||||||
|
-- The first column is the **From** state, the second column the **Event**, and the third column the **To** state.
|
||||||
|
--
|
||||||
|
-- So, each of the rows have the following structure.
|
||||||
|
--
|
||||||
|
-- * **From** => **Event** => **To**
|
||||||
|
--
|
||||||
|
-- Important to know is that an event can only be executed if the **current state** is the **From** state.
|
||||||
|
-- This, when an **Event** that is being triggered has a **From** state that is equal to the **Current** state of the state machine, the event will be executed,
|
||||||
|
-- and the resulting state will be the **To** state.
|
||||||
|
--
|
||||||
|
-- These are the different possible state transitions of this state machine implementation:
|
||||||
|
--
|
||||||
|
-- * Idle => Start => Monitoring
|
||||||
|
-- * Monitoring => Monitor => Monitoring
|
||||||
|
-- * Monitoring => Stop => Idle
|
||||||
|
--
|
||||||
|
-- * Monitoring => Pickup => Monitoring
|
||||||
|
-- * Monitoring => Load => Monitoring
|
||||||
|
-- * Monitoring => Loading => Monitoring
|
||||||
|
-- * Monitoring => Loaded => Monitoring
|
||||||
|
-- * Monitoring => PickedUp => Monitoring
|
||||||
|
-- * Monitoring => Deploy => Monitoring
|
||||||
|
-- * Monitoring => Unload => Monitoring
|
||||||
|
-- * Monitoring => Unloaded => Monitoring
|
||||||
|
-- * Monitoring => Deployed => Monitoring
|
||||||
|
-- * Monitoring => Home => Monitoring
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ## 2.1) AI_CARGO_DISPATCHER States.
|
||||||
|
--
|
||||||
|
-- * **Monitoring**: The process is dispatching.
|
||||||
|
-- * **Idle**: The process is idle.
|
||||||
|
--
|
||||||
|
-- ## 2.2) AI_CARGO_DISPATCHER Events.
|
||||||
|
--
|
||||||
|
-- * **Start**: Start the transport process.
|
||||||
|
-- * **Stop**: Stop the transport process.
|
||||||
|
-- * **Monitor**: Monitor and take action.
|
||||||
|
--
|
||||||
|
-- * **Pickup**: Pickup cargo.
|
||||||
|
-- * **Load**: Load the cargo.
|
||||||
|
-- * **Loading**: The dispatcher is coordinating the loading of a cargo.
|
||||||
|
-- * **Loaded**: Flag that the cargo is loaded.
|
||||||
|
-- * **PickedUp**: The dispatcher has loaded all requested cargo into the CarrierGroup.
|
||||||
|
-- * **Deploy**: Deploy cargo to a location.
|
||||||
|
-- * **Unload**: Unload the cargo.
|
||||||
|
-- * **Unloaded**: Flag that the cargo is unloaded.
|
||||||
|
-- * **Deployed**: All cargo is unloaded from the carriers in the group.
|
||||||
|
-- * **Home**: A Carrier is going home.
|
||||||
|
--
|
||||||
|
-- ## 2.3) Enhance your mission scripts with **Tailored** Event Handling!
|
||||||
|
--
|
||||||
|
-- Within your mission, you can capture these events when triggered, and tailor the events with your own code!
|
||||||
|
-- Check out the @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} class at chapter 3 for details on the different event handlers that are available and how to use them.
|
||||||
|
--
|
||||||
|
-- **There are a lot of templates available that allows you to quickly setup an event handler for a specific event type!**
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- # 3) Set the pickup parameters.
|
||||||
|
--
|
||||||
|
-- Several parameters can be set to pickup cargo:
|
||||||
|
--
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_APC.SetPickupRadius}(): Sets or randomizes the pickup location for the APC around the cargo coordinate in a radius defined an outer and optional inner radius.
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_APC.SetPickupSpeed}(): Set the speed or randomizes the speed in km/h to pickup the cargo.
|
||||||
|
--
|
||||||
|
-- # 4) Set the deploy parameters.
|
||||||
|
--
|
||||||
|
-- Several parameters can be set to deploy cargo:
|
||||||
|
--
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_APC.SetDeployRadius}(): Sets or randomizes the deploy location for the APC around the cargo coordinate in a radius defined an outer and an optional inner radius.
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_APC.SetDeploySpeed}(): Set the speed or randomizes the speed in km/h to deploy the cargo.
|
||||||
|
--
|
||||||
|
-- # 5) Set the home zone when there isn't any more cargo to pickup.
|
||||||
|
--
|
||||||
|
-- A home zone can be specified to where the APCs will move when there isn't any cargo left for pickup.
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @field #AI_CARGO_DISPATCHER_APC
|
||||||
|
AI_CARGO_DISPATCHER_APC = {
|
||||||
|
ClassName = "AI_CARGO_DISPATCHER_APC",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new AI_CARGO_DISPATCHER_APC object.
|
||||||
|
-- @param #AI_CARGO_DISPATCHER_APC self
|
||||||
|
-- @param Core.Set#SET_GROUP APCSet The set of @{Wrapper.Group#GROUP} objects of vehicles, trucks, APCs that will transport the cargo.
|
||||||
|
-- @param Core.Set#SET_CARGO CargoSet The set of @{Cargo.Cargo#CARGO} objects, which can be CARGO_GROUP, CARGO_CRATE, CARGO_SLINGLOAD objects.
|
||||||
|
-- @param Core.Set#SET_ZONE PickupZoneSet (optional) The set of pickup zones, which are used to where the cargo can be picked up by the APCs. If nil, then cargo can be picked up everywhere.
|
||||||
|
-- @param Core.Set#SET_ZONE DeployZoneSet The set of deploy zones, which are used to where the cargo will be deployed by the APCs.
|
||||||
|
-- @param DCS#Distance CombatRadius The cargo will be unloaded from the APC and engage the enemy if the enemy is within CombatRadius range. The radius is in meters, the default value is 500 meters.
|
||||||
|
-- @return #AI_CARGO_DISPATCHER_APC
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- An AI dispatcher object for a vehicle squadron, moving infantry from pickup zones to deploy zones.
|
||||||
|
--
|
||||||
|
-- local SetCargoInfantry = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
|
||||||
|
-- local SetAPC = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
|
||||||
|
-- local SetDeployZones = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
|
||||||
|
--
|
||||||
|
-- AICargoDispatcherAPC = AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargoInfantry, nil, SetDeployZones )
|
||||||
|
-- AICargoDispatcherAPC:Start()
|
||||||
|
--
|
||||||
|
function AI_CARGO_DISPATCHER_APC:New( APCSet, CargoSet, PickupZoneSet, DeployZoneSet, CombatRadius )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( APCSet, CargoSet, PickupZoneSet, DeployZoneSet ) ) -- #AI_CARGO_DISPATCHER_APC
|
||||||
|
|
||||||
|
self:SetDeploySpeed( 120, 70 )
|
||||||
|
self:SetPickupSpeed( 120, 70 )
|
||||||
|
self:SetPickupRadius( 0, 0 )
|
||||||
|
self:SetDeployRadius( 0, 0 )
|
||||||
|
|
||||||
|
self:SetPickupHeight()
|
||||||
|
self:SetDeployHeight()
|
||||||
|
|
||||||
|
self:SetCombatRadius( CombatRadius )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function AI_CARGO_DISPATCHER_APC:AICargo( APC, CargoSet )
|
||||||
|
|
||||||
|
return AI_CARGO_APC:New( APC, CargoSet, self.CombatRadius )
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Enable/Disable unboarding of cargo (infantry) when enemies are nearby (to help defend the carrier).
|
||||||
|
-- This is only valid for APCs and trucks etc, thus ground vehicles.
|
||||||
|
-- @param #AI_CARGO_DISPATCHER_APC self
|
||||||
|
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby.
|
||||||
|
-- When the combat radius is 0, no defense will happen of the carrier.
|
||||||
|
-- When the combat radius is not provided, no defense will happen!
|
||||||
|
-- @return #AI_CARGO_DISPATCHER_APC
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- Disembark the infantry when the carrier is under attack.
|
||||||
|
-- AICargoDispatcher:SetCombatRadius( true )
|
||||||
|
--
|
||||||
|
-- -- Keep the cargo in the carrier when the carrier is under attack.
|
||||||
|
-- AICargoDispatcher:SetCombatRadius( false )
|
||||||
|
function AI_CARGO_DISPATCHER_APC:SetCombatRadius( CombatRadius )
|
||||||
|
|
||||||
|
self.CombatRadius = CombatRadius or 0
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
164
Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua
Normal file
164
Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Planes.
|
||||||
|
--
|
||||||
|
-- ## Features:
|
||||||
|
--
|
||||||
|
-- * The airplanes will fly towards the pickup airbases to pickup the cargo.
|
||||||
|
-- * The airplanes will fly towards the deploy airbases to deploy the cargo.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Test Missions:
|
||||||
|
--
|
||||||
|
-- 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)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module AI.AI_Cargo_Dispatcher_Airplane
|
||||||
|
-- @image AI_Cargo_Dispatching_For_Airplanes.JPG
|
||||||
|
|
||||||
|
|
||||||
|
--- @type AI_CARGO_DISPATCHER_AIRPLANE
|
||||||
|
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
|
||||||
|
|
||||||
|
|
||||||
|
--- 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.
|
||||||
|
--
|
||||||
|
-- ## Note! In order to fully understand the mechanisms of the AI_CARGO_DISPATCHER_AIRPLANE class, it is recommended that you first consult and READ the documentation of the @{AI.AI_Cargo_Dispatcher} module!!!**
|
||||||
|
--
|
||||||
|
-- Especially to learn how to **Tailor the different cargo handling events**, this will be very useful!
|
||||||
|
--
|
||||||
|
-- On top, the AI_CARGO_DISPATCHER_AIRPLANE 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 be declared within the mission to make the AI_CARGO_DISPATCHER_HELICOPTER object recognize the cargo.
|
||||||
|
--
|
||||||
|
-- # 1) AI_CARGO_DISPATCHER_AIRPLANE constructor.
|
||||||
|
--
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_AIRPLANE.New}(): Creates a new AI_CARGO_DISPATCHER_AIRPLANE object.
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- # 2) AI_CARGO_DISPATCHER_AIRPLANE is a Finite State Machine.
|
||||||
|
--
|
||||||
|
-- This section must be read as follows. Each of the rows indicate a state transition, triggered through an event, and with an ending state of the event was executed.
|
||||||
|
-- The first column is the **From** state, the second column the **Event**, and the third column the **To** state.
|
||||||
|
--
|
||||||
|
-- So, each of the rows have the following structure.
|
||||||
|
--
|
||||||
|
-- * **From** => **Event** => **To**
|
||||||
|
--
|
||||||
|
-- Important to know is that an event can only be executed if the **current state** is the **From** state.
|
||||||
|
-- This, when an **Event** that is being triggered has a **From** state that is equal to the **Current** state of the state machine, the event will be executed,
|
||||||
|
-- and the resulting state will be the **To** state.
|
||||||
|
--
|
||||||
|
-- These are the different possible state transitions of this state machine implementation:
|
||||||
|
--
|
||||||
|
-- * Idle => Start => Monitoring
|
||||||
|
-- * Monitoring => Monitor => Monitoring
|
||||||
|
-- * Monitoring => Stop => Idle
|
||||||
|
--
|
||||||
|
-- * Monitoring => Pickup => Monitoring
|
||||||
|
-- * Monitoring => Load => Monitoring
|
||||||
|
-- * Monitoring => Loading => Monitoring
|
||||||
|
-- * Monitoring => Loaded => Monitoring
|
||||||
|
-- * Monitoring => PickedUp => Monitoring
|
||||||
|
-- * Monitoring => Deploy => Monitoring
|
||||||
|
-- * Monitoring => Unload => Monitoring
|
||||||
|
-- * Monitoring => Unloaded => Monitoring
|
||||||
|
-- * Monitoring => Deployed => Monitoring
|
||||||
|
-- * Monitoring => Home => Monitoring
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ## 2.1) AI_CARGO_DISPATCHER States.
|
||||||
|
--
|
||||||
|
-- * **Monitoring**: The process is dispatching.
|
||||||
|
-- * **Idle**: The process is idle.
|
||||||
|
--
|
||||||
|
-- ## 2.2) AI_CARGO_DISPATCHER Events.
|
||||||
|
--
|
||||||
|
-- * **Start**: Start the transport process.
|
||||||
|
-- * **Stop**: Stop the transport process.
|
||||||
|
-- * **Monitor**: Monitor and take action.
|
||||||
|
--
|
||||||
|
-- * **Pickup**: Pickup cargo.
|
||||||
|
-- * **Load**: Load the cargo.
|
||||||
|
-- * **Loading**: The dispatcher is coordinating the loading of a cargo.
|
||||||
|
-- * **Loaded**: Flag that the cargo is loaded.
|
||||||
|
-- * **PickedUp**: The dispatcher has loaded all requested cargo into the CarrierGroup.
|
||||||
|
-- * **Deploy**: Deploy cargo to a location.
|
||||||
|
-- * **Unload**: Unload the cargo.
|
||||||
|
-- * **Unloaded**: Flag that the cargo is unloaded.
|
||||||
|
-- * **Deployed**: All cargo is unloaded from the carriers in the group.
|
||||||
|
-- * **Home**: A Carrier is going home.
|
||||||
|
--
|
||||||
|
-- ## 2.3) Enhance your mission scripts with **Tailored** Event Handling!
|
||||||
|
--
|
||||||
|
-- Within your mission, you can capture these events when triggered, and tailor the events with your own code!
|
||||||
|
-- Check out the @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} class at chapter 3 for details on the different event handlers that are available and how to use them.
|
||||||
|
--
|
||||||
|
-- **There are a lot of templates available that allows you to quickly setup an event handler for a specific event type!**
|
||||||
|
--
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #AI_CARGO_DISPATCHER_AIRPLANE
|
||||||
|
AI_CARGO_DISPATCHER_AIRPLANE = {
|
||||||
|
ClassName = "AI_CARGO_DISPATCHER_AIRPLANE",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new AI_CARGO_DISPATCHER_AIRPLANE object.
|
||||||
|
-- @param #AI_CARGO_DISPATCHER_AIRPLANE self
|
||||||
|
-- @param Core.Set#SET_GROUP AirplaneSet The set of @{Wrapper.Group#GROUP} objects of airplanes that will transport the cargo.
|
||||||
|
-- @param Core.Set#SET_CARGO CargoSet The set of @{Cargo.Cargo#CARGO} objects, which can be CARGO_GROUP, CARGO_CRATE, CARGO_SLINGLOAD objects.
|
||||||
|
-- @param Core.Zone#SET_ZONE PickupZoneSet The set of zone airbases where the cargo has to be picked up.
|
||||||
|
-- @param Core.Zone#SET_ZONE DeployZoneSet The set of zone airbases where the cargo is deployed. Choice for each cargo is random.
|
||||||
|
-- @return #AI_CARGO_DISPATCHER_AIRPLANE self
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- An AI dispatcher object for an airplane squadron, moving infantry and vehicles from pickup airbases to deploy airbases.
|
||||||
|
--
|
||||||
|
-- local CargoInfantrySet = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
|
||||||
|
-- local AirplanesSet = SET_GROUP:New():FilterPrefixes( "Airplane" ):FilterStart()
|
||||||
|
-- local PickupZoneSet = SET_ZONE:New()
|
||||||
|
-- local DeployZoneSet = SET_ZONE:New()
|
||||||
|
--
|
||||||
|
-- PickupZoneSet:AddZone( ZONE_AIRBASE:New( AIRBASE.Caucasus.Gudauta ) )
|
||||||
|
-- DeployZoneSet:AddZone( ZONE_AIRBASE:New( AIRBASE.Caucasus.Sochi_Adler ) )
|
||||||
|
-- DeployZoneSet:AddZone( ZONE_AIRBASE:New( AIRBASE.Caucasus.Maykop_Khanskaya ) )
|
||||||
|
-- DeployZoneSet:AddZone( ZONE_AIRBASE:New( AIRBASE.Caucasus.Mineralnye_Vody ) )
|
||||||
|
-- DeployZoneSet:AddZone( ZONE_AIRBASE:New( AIRBASE.Caucasus.Vaziani ) )
|
||||||
|
--
|
||||||
|
-- AICargoDispatcherAirplanes = AI_CARGO_DISPATCHER_AIRPLANE:New( AirplanesSet, CargoInfantrySet, PickupZoneSet, DeployZoneSet )
|
||||||
|
-- AICargoDispatcherAirplanes:Start()
|
||||||
|
--
|
||||||
|
function AI_CARGO_DISPATCHER_AIRPLANE:New( AirplaneSet, CargoSet, PickupZoneSet, DeployZoneSet )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( AirplaneSet, CargoSet, PickupZoneSet, DeployZoneSet ) ) -- #AI_CARGO_DISPATCHER_AIRPLANE
|
||||||
|
|
||||||
|
self:SetPickupSpeed( 1200, 600 )
|
||||||
|
self:SetDeploySpeed( 1200, 600 )
|
||||||
|
|
||||||
|
self:SetPickupRadius( 0, 0 )
|
||||||
|
self:SetDeployRadius( 0, 0 )
|
||||||
|
|
||||||
|
self:SetPickupHeight( 8000, 6000 )
|
||||||
|
self:SetDeployHeight( 8000, 6000 )
|
||||||
|
|
||||||
|
self:SetMonitorTimeInterval( 600 )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function AI_CARGO_DISPATCHER_AIRPLANE:AICargo( Airplane, CargoSet )
|
||||||
|
|
||||||
|
return AI_CARGO_AIRPLANE:New( Airplane, CargoSet )
|
||||||
|
end
|
||||||
191
Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua
Normal file
191
Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
--- **AI** -- (2.4) - Models the intelligent transportation of infantry and other cargo using Helicopters.
|
||||||
|
--
|
||||||
|
-- ## Features:
|
||||||
|
--
|
||||||
|
-- * The helicopters will fly towards the pickup locations to pickup the cargo.
|
||||||
|
-- * The helicopters will fly towards the deploy zones to deploy the cargo.
|
||||||
|
-- * Precision deployment as well as randomized deployment within the deploy zones are possible.
|
||||||
|
-- * Helicopters will orbit the deploy zones when there is no space for landing until the deploy zone is free.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Test Missions:
|
||||||
|
--
|
||||||
|
-- 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)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module AI.AI_Cargo_Dispatcher_Helicopter
|
||||||
|
-- @image AI_Cargo_Dispatching_For_Helicopters.JPG
|
||||||
|
|
||||||
|
--- @type AI_CARGO_DISPATCHER_HELICOPTER
|
||||||
|
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
|
||||||
|
|
||||||
|
|
||||||
|
--- A dynamic cargo handling capability for AI helicopter groups.
|
||||||
|
--
|
||||||
|
-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- The AI_CARGO_DISPATCHER_HELICOPTER module is derived from the AI_CARGO_DISPATCHER module.
|
||||||
|
--
|
||||||
|
-- ## Note! In order to fully understand the mechanisms of the AI_CARGO_DISPATCHER_HELICOPTER class, it is recommended that you first consult and READ the documentation of the @{AI.AI_Cargo_Dispatcher} module!!!**
|
||||||
|
--
|
||||||
|
-- Especially to learn how to **Tailor the different cargo handling events**, this will be very useful!
|
||||||
|
--
|
||||||
|
-- On top, the AI_CARGO_DISPATCHER_HELICOPTER 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 be declared within the mission to make the AI_CARGO_DISPATCHER_HELICOPTER object recognize the cargo.
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- # 1. AI\_CARGO\_DISPATCHER\_HELICOPTER constructor.
|
||||||
|
--
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER\_HELICOPTER.New}(): Creates a new AI\_CARGO\_DISPATCHER\_HELICOPTER object.
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- # 2. AI\_CARGO\_DISPATCHER\_HELICOPTER is a Finite State Machine.
|
||||||
|
--
|
||||||
|
-- This section must be read as follows. Each of the rows indicate a state transition, triggered through an event, and with an ending state of the event was executed.
|
||||||
|
-- The first column is the **From** state, the second column the **Event**, and the third column the **To** state.
|
||||||
|
--
|
||||||
|
-- So, each of the rows have the following structure.
|
||||||
|
--
|
||||||
|
-- * **From** => **Event** => **To**
|
||||||
|
--
|
||||||
|
-- Important to know is that an event can only be executed if the **current state** is the **From** state.
|
||||||
|
-- This, when an **Event** that is being triggered has a **From** state that is equal to the **Current** state of the state machine, the event will be executed,
|
||||||
|
-- and the resulting state will be the **To** state.
|
||||||
|
--
|
||||||
|
-- These are the different possible state transitions of this state machine implementation:
|
||||||
|
--
|
||||||
|
-- * Idle => Start => Monitoring
|
||||||
|
-- * Monitoring => Monitor => Monitoring
|
||||||
|
-- * Monitoring => Stop => Idle
|
||||||
|
--
|
||||||
|
-- * Monitoring => Pickup => Monitoring
|
||||||
|
-- * Monitoring => Load => Monitoring
|
||||||
|
-- * Monitoring => Loading => Monitoring
|
||||||
|
-- * Monitoring => Loaded => Monitoring
|
||||||
|
-- * Monitoring => PickedUp => Monitoring
|
||||||
|
-- * Monitoring => Deploy => Monitoring
|
||||||
|
-- * Monitoring => Unload => Monitoring
|
||||||
|
-- * Monitoring => Unloaded => Monitoring
|
||||||
|
-- * Monitoring => Deployed => Monitoring
|
||||||
|
-- * Monitoring => Home => Monitoring
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ## 2.1) AI_CARGO_DISPATCHER States.
|
||||||
|
--
|
||||||
|
-- * **Monitoring**: The process is dispatching.
|
||||||
|
-- * **Idle**: The process is idle.
|
||||||
|
--
|
||||||
|
-- ## 2.2) AI_CARGO_DISPATCHER Events.
|
||||||
|
--
|
||||||
|
-- * **Start**: Start the transport process.
|
||||||
|
-- * **Stop**: Stop the transport process.
|
||||||
|
-- * **Monitor**: Monitor and take action.
|
||||||
|
--
|
||||||
|
-- * **Pickup**: Pickup cargo.
|
||||||
|
-- * **Load**: Load the cargo.
|
||||||
|
-- * **Loading**: The dispatcher is coordinating the loading of a cargo.
|
||||||
|
-- * **Loaded**: Flag that the cargo is loaded.
|
||||||
|
-- * **PickedUp**: The dispatcher has loaded all requested cargo into the CarrierGroup.
|
||||||
|
-- * **Deploy**: Deploy cargo to a location.
|
||||||
|
-- * **Unload**: Unload the cargo.
|
||||||
|
-- * **Unloaded**: Flag that the cargo is unloaded.
|
||||||
|
-- * **Deployed**: All cargo is unloaded from the carriers in the group.
|
||||||
|
-- * **Home**: A Carrier is going home.
|
||||||
|
--
|
||||||
|
-- ## 2.3) Enhance your mission scripts with **Tailored** Event Handling!
|
||||||
|
--
|
||||||
|
-- Within your mission, you can capture these events when triggered, and tailor the events with your own code!
|
||||||
|
-- Check out the @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} class at chapter 3 for details on the different event handlers that are available and how to use them.
|
||||||
|
--
|
||||||
|
-- **There are a lot of templates available that allows you to quickly setup an event handler for a specific event type!**
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- ## 3. Set the pickup parameters.
|
||||||
|
--
|
||||||
|
-- Several parameters can be set to pickup cargo:
|
||||||
|
--
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetPickupRadius}(): Sets or randomizes the pickup location for the helicopter around the cargo coordinate in a radius defined an outer and optional inner radius.
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetPickupSpeed}(): Set the speed or randomizes the speed in km/h to pickup the cargo.
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetPickupHeight}(): Set the height or randomizes the height in meters to pickup the cargo.
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- ## 4. Set the deploy parameters.
|
||||||
|
--
|
||||||
|
-- Several parameters can be set to deploy cargo:
|
||||||
|
--
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetDeployRadius}(): Sets or randomizes the deploy location for the helicopter around the cargo coordinate in a radius defined an outer and an optional inner radius.
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetDeploySpeed}(): Set the speed or randomizes the speed in km/h to deploy the cargo.
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_HELICOPTER.SetDeployHeight}(): Set the height or randomizes the height in meters to deploy the cargo.
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- ## 5. Set the home zone when there isn't any more cargo to pickup.
|
||||||
|
--
|
||||||
|
-- A home zone can be specified to where the Helicopters will move when there isn't any cargo left for pickup.
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @field #AI_CARGO_DISPATCHER_HELICOPTER
|
||||||
|
AI_CARGO_DISPATCHER_HELICOPTER = {
|
||||||
|
ClassName = "AI_CARGO_DISPATCHER_HELICOPTER",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new AI_CARGO_DISPATCHER_HELICOPTER object.
|
||||||
|
-- @param #AI_CARGO_DISPATCHER_HELICOPTER self
|
||||||
|
-- @param Core.Set#SET_GROUP HelicopterSet The set of @{Wrapper.Group#GROUP} objects of helicopters that will transport the cargo.
|
||||||
|
-- @param Core.Set#SET_CARGO CargoSet The set of @{Cargo.Cargo#CARGO} objects, which can be CARGO_GROUP, CARGO_CRATE, CARGO_SLINGLOAD objects.
|
||||||
|
-- @param Core.Set#SET_ZONE PickupZoneSet (optional) The set of pickup zones, which are used to where the cargo can be picked up by the APCs. If nil, then cargo can be picked up everywhere.
|
||||||
|
-- @param Core.Set#SET_ZONE DeployZoneSet The set of deploy zones, which are used to where the cargo will be deployed by the Helicopters.
|
||||||
|
-- @return #AI_CARGO_DISPATCHER_HELICOPTER
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- An AI dispatcher object for a helicopter squadron, moving infantry from pickup zones to deploy zones.
|
||||||
|
--
|
||||||
|
-- local SetCargoInfantry = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
|
||||||
|
-- local SetHelicopter = SET_GROUP:New():FilterPrefixes( "Helicopter" ):FilterStart()
|
||||||
|
-- local SetPickupZones = SET_ZONE:New():FilterPrefixes( "Pickup" ):FilterStart()
|
||||||
|
-- local SetDeployZones = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
|
||||||
|
--
|
||||||
|
-- AICargoDispatcherHelicopter = AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargoInfantry, SetPickupZones, SetDeployZones )
|
||||||
|
-- AICargoDispatcherHelicopter:Start()
|
||||||
|
--
|
||||||
|
function AI_CARGO_DISPATCHER_HELICOPTER:New( HelicopterSet, CargoSet, PickupZoneSet, DeployZoneSet )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( HelicopterSet, CargoSet, PickupZoneSet, DeployZoneSet ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER
|
||||||
|
|
||||||
|
self:SetPickupSpeed( 350, 150 )
|
||||||
|
self:SetDeploySpeed( 350, 150 )
|
||||||
|
|
||||||
|
self:SetPickupRadius( 0, 0 )
|
||||||
|
self:SetDeployRadius( 0, 0 )
|
||||||
|
|
||||||
|
self:SetPickupHeight( 500, 200 )
|
||||||
|
self:SetDeployHeight( 500, 200 )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function AI_CARGO_DISPATCHER_HELICOPTER:AICargo( Helicopter, CargoSet )
|
||||||
|
|
||||||
|
return AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
|
||||||
|
end
|
||||||
|
|
||||||
625
Moose Development/Moose/AI/AI_Cargo_Helicopter.lua
Normal file
625
Moose Development/Moose/AI/AI_Cargo_Helicopter.lua
Normal file
@@ -0,0 +1,625 @@
|
|||||||
|
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry (cargo).
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module AI.AI_Cargo_Helicopter
|
||||||
|
-- @image AI_Cargo_Dispatching_For_Helicopters.JPG
|
||||||
|
|
||||||
|
--- @type AI_CARGO_HELICOPTER
|
||||||
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
|
|
||||||
|
--- 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.
|
||||||
|
-- @{Cargo.Cargo} must be declared within the mission to make the AI_CARGO_HELICOPTER object recognize the cargo.
|
||||||
|
-- Please consult the @{Cargo.Cargo} module for more information.
|
||||||
|
--
|
||||||
|
-- ## Cargo pickup.
|
||||||
|
--
|
||||||
|
-- Using the @{#AI_CARGO_HELICOPTER.Pickup}() method, you are able to direct the helicopters towards a point on the battlefield to board/load the cargo at the specific coordinate.
|
||||||
|
-- Ensure that the landing zone is horizontally flat, and that trees cannot be found in the landing vicinity, or the helicopters won't land or will even crash!
|
||||||
|
--
|
||||||
|
-- ## Cargo deployment.
|
||||||
|
--
|
||||||
|
-- Using the @{#AI_CARGO_HELICOPTER.Deploy}() method, you are able to direct the helicopters towards a point on the battlefield to unboard/unload the cargo at the specific coordinate.
|
||||||
|
-- Ensure that the landing zone is horizontally flat, and that trees cannot be found in the landing vicinity, or the helicopters won't land or will even crash!
|
||||||
|
--
|
||||||
|
-- ## Infantry health.
|
||||||
|
--
|
||||||
|
-- When infantry is unboarded from the APCs, the infantry is actually respawned into the battlefield.
|
||||||
|
-- As a result, the unboarding infantry is very _healthy_ every time it unboards.
|
||||||
|
-- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter.
|
||||||
|
-- However, infantry that was destroyed when unboarded, won't be respawned again. Destroyed is destroyed.
|
||||||
|
-- As a result, there is some additional strength that is gained when an unboarding action happens, but in terms of simulation balance this has
|
||||||
|
-- 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 ...
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @field #AI_CARGO_HELICOPTER
|
||||||
|
AI_CARGO_HELICOPTER = {
|
||||||
|
ClassName = "AI_CARGO_HELICOPTER",
|
||||||
|
Coordinate = nil, -- Core.Point#COORDINATE,
|
||||||
|
}
|
||||||
|
|
||||||
|
AI_CARGO_QUEUE = {}
|
||||||
|
|
||||||
|
--- Creates a new AI_CARGO_HELICOPTER object.
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP Helicopter
|
||||||
|
-- @param Core.Set#SET_CARGO CargoSet
|
||||||
|
-- @return #AI_CARGO_HELICOPTER
|
||||||
|
function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, AI_CARGO:New( Helicopter, CargoSet ) ) -- #AI_CARGO_HELICOPTER
|
||||||
|
|
||||||
|
self.Zone = ZONE_GROUP:New( Helicopter:GetName(), Helicopter, 300 )
|
||||||
|
|
||||||
|
self:SetStartState( "Unloaded" )
|
||||||
|
|
||||||
|
self:AddTransition( "Unloaded", "Pickup", "*" )
|
||||||
|
self:AddTransition( "Loaded", "Deploy", "*" )
|
||||||
|
|
||||||
|
self:AddTransition( { "Unloaded", "Loading" }, "Load", "Boarding" )
|
||||||
|
self:AddTransition( "Boarding", "Board", "Boarding" )
|
||||||
|
self:AddTransition( "Boarding", "Loaded", "Boarding" )
|
||||||
|
self:AddTransition( "Boarding", "PickedUp", "Loaded" )
|
||||||
|
self:AddTransition( "Loaded", "Unload", "Unboarding" )
|
||||||
|
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
|
||||||
|
self:AddTransition( "Unboarding", "Unloaded", "Unboarding" )
|
||||||
|
self:AddTransition( "Unboarding", "Deployed", "Unloaded" )
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Landed", "*" )
|
||||||
|
self:AddTransition( "*", "Queue", "*" )
|
||||||
|
self:AddTransition( "*", "Orbit" , "*" )
|
||||||
|
self:AddTransition( "*", "Home" , "*" )
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Destroyed", "Destroyed" )
|
||||||
|
|
||||||
|
--- Pickup Handler OnBefore for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] OnBeforePickup
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Pickup Handler OnAfter for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] OnAfterPickup
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
|
--- Pickup Trigger for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] Pickup
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
|
--- Pickup Asynchronous Trigger for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] __Pickup
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param #number Delay Delay in seconds.
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h to go to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
|
--- Deploy Handler OnBefore for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] OnBeforeDeploy
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Place at which cargo is deployed.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Deploy Handler OnAfter for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] OnAfterDeploy
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
|
--- Deploy Trigger for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] Deploy
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
|
--- Deploy Asynchronous Trigger for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] __Deploy
|
||||||
|
-- @param #number Delay Delay in seconds.
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
|
|
||||||
|
-- We need to capture the Crash events for the helicopters.
|
||||||
|
-- The helicopter reference is used in the semaphore AI_CARGO_QUEUE.
|
||||||
|
-- So, we need to unlock this when the helo is not anymore ...
|
||||||
|
Helicopter:HandleEvent( EVENTS.Crash,
|
||||||
|
function( Helicopter, EventData )
|
||||||
|
AI_CARGO_QUEUE[Helicopter] = nil
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
-- We need to capture the Land events for the helicopters.
|
||||||
|
-- The helicopter reference is used in the semaphore AI_CARGO_QUEUE.
|
||||||
|
-- So, we need to unlock this when the helo has landed, which can be anywhere ...
|
||||||
|
-- But only free the landing coordinate after 1 minute, to ensure that all helos have left.
|
||||||
|
Helicopter:HandleEvent( EVENTS.Land,
|
||||||
|
function( Helicopter, EventData )
|
||||||
|
self:ScheduleOnce( 60,
|
||||||
|
function( Helicopter )
|
||||||
|
AI_CARGO_QUEUE[Helicopter] = nil
|
||||||
|
end, Helicopter
|
||||||
|
)
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
self:SetCarrier( Helicopter )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Set the Carrier.
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP Helicopter
|
||||||
|
-- @return #AI_CARGO_HELICOPTER
|
||||||
|
function AI_CARGO_HELICOPTER:SetCarrier( Helicopter )
|
||||||
|
|
||||||
|
local AICargo = self
|
||||||
|
|
||||||
|
self.Helicopter = Helicopter -- Wrapper.Group#GROUP
|
||||||
|
self.Helicopter:SetState( self.Helicopter, "AI_CARGO_HELICOPTER", self )
|
||||||
|
|
||||||
|
self.RoutePickup = false
|
||||||
|
self.RouteDeploy = false
|
||||||
|
|
||||||
|
Helicopter:HandleEvent( EVENTS.Dead )
|
||||||
|
Helicopter:HandleEvent( EVENTS.Hit )
|
||||||
|
Helicopter:HandleEvent( EVENTS.Land )
|
||||||
|
|
||||||
|
function Helicopter:OnEventDead( EventData )
|
||||||
|
local AICargoTroops = self:GetState( self, "AI_CARGO_HELICOPTER" )
|
||||||
|
self:F({AICargoTroops=AICargoTroops})
|
||||||
|
if AICargoTroops then
|
||||||
|
self:F({})
|
||||||
|
if not AICargoTroops:Is( "Loaded" ) then
|
||||||
|
-- There are enemies within combat range. Unload the Helicopter.
|
||||||
|
AICargoTroops:Destroyed()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Helicopter:OnEventLand( EventData )
|
||||||
|
AICargo:Landed()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.Coalition = self.Helicopter:GetCoalition()
|
||||||
|
|
||||||
|
self:SetControllable( Helicopter )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP Helicopter
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To )
|
||||||
|
|
||||||
|
Helicopter:F( { Name = Helicopter:GetName() } )
|
||||||
|
|
||||||
|
if Helicopter and Helicopter:IsAlive() then
|
||||||
|
|
||||||
|
-- S_EVENT_LAND is directly called in two situations:
|
||||||
|
-- 1 - When the helo lands normally on the ground.
|
||||||
|
-- 2 - when the helo is hit and goes RTB or even when it is destroyed.
|
||||||
|
-- For point 2, this is an issue, the infantry may not unload in this case!
|
||||||
|
-- So we check if the helo is on the ground, and velocity< 5.
|
||||||
|
-- Only then the infantry can unload (and load too, for consistency)!
|
||||||
|
|
||||||
|
self:F( { Helicopter:GetName(), Height = Helicopter:GetHeight( true ), Velocity = Helicopter:GetVelocityKMH() } )
|
||||||
|
|
||||||
|
if self.RoutePickup == true then
|
||||||
|
if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 10 then
|
||||||
|
--self:Load( Helicopter:GetPointVec2() )
|
||||||
|
self:Load( self.PickupZone )
|
||||||
|
self.RoutePickup = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.RouteDeploy == true then
|
||||||
|
if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 10 then
|
||||||
|
self:Unload( self.DeployZone )
|
||||||
|
self.RouteDeploy = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP Helicopter
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed
|
||||||
|
function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordinate, Speed, DeployZone )
|
||||||
|
|
||||||
|
local HelicopterInZone = false
|
||||||
|
|
||||||
|
if Helicopter and Helicopter:IsAlive() == true then
|
||||||
|
|
||||||
|
local Distance = Coordinate:DistanceFromPointVec2( Helicopter:GetCoordinate() )
|
||||||
|
|
||||||
|
if Distance > 2000 then
|
||||||
|
self:__Queue( -10, Coordinate, Speed, DeployZone )
|
||||||
|
else
|
||||||
|
|
||||||
|
local ZoneFree = true
|
||||||
|
|
||||||
|
for Helicopter, ZoneQueue in pairs( AI_CARGO_QUEUE ) do
|
||||||
|
local ZoneQueue = ZoneQueue -- Core.Zone#ZONE_RADIUS
|
||||||
|
if ZoneQueue:IsCoordinateInZone( Coordinate ) then
|
||||||
|
ZoneFree = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:F({ZoneFree=ZoneFree})
|
||||||
|
|
||||||
|
if ZoneFree == true then
|
||||||
|
|
||||||
|
local ZoneQueue = ZONE_RADIUS:New( Helicopter:GetName(), Coordinate:GetVec2(), 100 )
|
||||||
|
|
||||||
|
AI_CARGO_QUEUE[Helicopter] = ZoneQueue
|
||||||
|
|
||||||
|
local Route = {}
|
||||||
|
|
||||||
|
-- local CoordinateFrom = Helicopter:GetCoordinate()
|
||||||
|
-- local WaypointFrom = CoordinateFrom:WaypointAir(
|
||||||
|
-- "RADIO",
|
||||||
|
-- POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
|
-- POINT_VEC3.RoutePointAction.TurningPoint,
|
||||||
|
-- Speed,
|
||||||
|
-- true
|
||||||
|
-- )
|
||||||
|
-- Route[#Route+1] = WaypointFrom
|
||||||
|
local CoordinateTo = Coordinate
|
||||||
|
local WaypointTo = CoordinateTo:WaypointAir(
|
||||||
|
"RADIO",
|
||||||
|
POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
|
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||||
|
50,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
local Tasks = {}
|
||||||
|
Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() )
|
||||||
|
Route[#Route].task = Helicopter:TaskCombo( Tasks )
|
||||||
|
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
-- Now route the helicopter
|
||||||
|
Helicopter:Route( Route, 0 )
|
||||||
|
|
||||||
|
-- Keep the DeployZone, because when the helo has landed, we want to provide the DeployZone to the mission designer as part of the Unloaded event.
|
||||||
|
self.DeployZone = DeployZone
|
||||||
|
|
||||||
|
else
|
||||||
|
self:__Queue( -10, Coordinate, Speed, DeployZone )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
AI_CARGO_QUEUE[Helicopter] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP Helicopter
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Speed
|
||||||
|
function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordinate )
|
||||||
|
|
||||||
|
if Helicopter and Helicopter:IsAlive() then
|
||||||
|
|
||||||
|
local Route = {}
|
||||||
|
|
||||||
|
-- local CoordinateFrom = Helicopter:GetCoordinate()
|
||||||
|
-- local WaypointFrom = CoordinateFrom:WaypointAir(
|
||||||
|
-- "RADIO",
|
||||||
|
-- POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
|
-- POINT_VEC3.RoutePointAction.TurningPoint,
|
||||||
|
-- Speed,
|
||||||
|
-- true
|
||||||
|
-- )
|
||||||
|
-- Route[#Route+1] = WaypointFrom
|
||||||
|
local CoordinateTo = Coordinate
|
||||||
|
local WaypointTo = CoordinateTo:WaypointAir(
|
||||||
|
"RADIO",
|
||||||
|
POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
|
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||||
|
50,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
local Tasks = {}
|
||||||
|
Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 80 ), 150, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) )
|
||||||
|
Route[#Route].task = Helicopter:TaskCombo( Tasks )
|
||||||
|
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
-- Now route the helicopter
|
||||||
|
Helicopter:Route( Route, 0 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Deployed event.
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP Helicopter
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Cargo.Cargo#CARGO Cargo Cargo object.
|
||||||
|
-- @param #boolean Deployed Cargo is deployed.
|
||||||
|
-- @return #boolean True if all cargo has been unloaded.
|
||||||
|
function AI_CARGO_HELICOPTER:onafterDeployed( Helicopter, From, Event, To, DeployZone )
|
||||||
|
self:F( { Helicopter, From, Event, To, DeployZone = DeployZone } )
|
||||||
|
|
||||||
|
self:Orbit( Helicopter:GetCoordinate(), 50 )
|
||||||
|
|
||||||
|
-- Free the coordinate zone after 30 seconds, so that the original helicopter can fly away first.
|
||||||
|
self:ScheduleOnce( 30,
|
||||||
|
function( Helicopter )
|
||||||
|
AI_CARGO_QUEUE[Helicopter] = nil
|
||||||
|
end, Helicopter
|
||||||
|
)
|
||||||
|
|
||||||
|
self:GetParent( self, AI_CARGO_HELICOPTER ).onafterDeployed( self, Helicopter, From, Event, To, DeployZone )
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Pickup event.
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP Helicopter
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Pickup place.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height Height in meters to move to the pickup coordinate. This parameter is ignored for APCs.
|
||||||
|
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
|
||||||
|
function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
||||||
|
|
||||||
|
if Helicopter and Helicopter:IsAlive() ~= nil then
|
||||||
|
|
||||||
|
Helicopter:Activate()
|
||||||
|
|
||||||
|
self.RoutePickup = true
|
||||||
|
Coordinate.y = Height
|
||||||
|
|
||||||
|
local _speed=Speed or Helicopter:GetSpeedMax()*0.5
|
||||||
|
|
||||||
|
local Route = {}
|
||||||
|
|
||||||
|
--- Calculate the target route point.
|
||||||
|
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||||
|
local CoordinateTo = Coordinate
|
||||||
|
|
||||||
|
--- Create a route point of type air.
|
||||||
|
local WaypointFrom = CoordinateFrom:WaypointAir(
|
||||||
|
"RADIO",
|
||||||
|
POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
|
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||||
|
_speed,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
--- Create a route point of type air.
|
||||||
|
local WaypointTo = CoordinateTo:WaypointAir(
|
||||||
|
"RADIO",
|
||||||
|
POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
|
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||||
|
_speed,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
Route[#Route+1] = WaypointFrom
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
|
||||||
|
Helicopter:WayPointInitialize( Route )
|
||||||
|
|
||||||
|
local Tasks = {}
|
||||||
|
|
||||||
|
Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() )
|
||||||
|
Route[#Route].task = Helicopter:TaskCombo( Tasks )
|
||||||
|
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
-- Now route the helicopter
|
||||||
|
Helicopter:Route( Route, 1 )
|
||||||
|
|
||||||
|
self.PickupZone = PickupZone
|
||||||
|
|
||||||
|
self:GetParent( self, AI_CARGO_HELICOPTER ).onafterPickup( self, Helicopter, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Depoloy function and queue.
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP AICargoHelicopter
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Coordinate
|
||||||
|
function AI_CARGO_HELICOPTER:_Deploy( AICargoHelicopter, Coordinate, DeployZone )
|
||||||
|
AICargoHelicopter:__Queue( -10, Coordinate, 100, DeployZone )
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Deploy event.
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP Helicopter Transport helicopter.
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height Height in meters to move to the deploy coordinate.
|
||||||
|
function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
|
||||||
|
if Helicopter and Helicopter:IsAlive() ~= nil then
|
||||||
|
|
||||||
|
self.RouteDeploy = true
|
||||||
|
|
||||||
|
|
||||||
|
local Route = {}
|
||||||
|
|
||||||
|
--- Calculate the target route point.
|
||||||
|
|
||||||
|
Coordinate.y = Height
|
||||||
|
|
||||||
|
local _speed=Speed or Helicopter:GetSpeedMax()*0.5
|
||||||
|
|
||||||
|
--- 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
|
||||||
|
)
|
||||||
|
Route[#Route+1] = WaypointFrom
|
||||||
|
Route[#Route+1] = WaypointFrom
|
||||||
|
|
||||||
|
--- Create a route point of type air.
|
||||||
|
local CoordinateTo = Coordinate
|
||||||
|
local WaypointTo = CoordinateTo:WaypointAir(
|
||||||
|
"RADIO",
|
||||||
|
POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
|
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||||
|
_speed,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
|
||||||
|
Helicopter:WayPointInitialize( Route )
|
||||||
|
|
||||||
|
local Tasks = {}
|
||||||
|
|
||||||
|
Tasks[#Tasks+1] = Helicopter:TaskFunction( "AI_CARGO_HELICOPTER._Deploy", self, Coordinate, DeployZone )
|
||||||
|
Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 100 ), _speed, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) )
|
||||||
|
|
||||||
|
--Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() )
|
||||||
|
Route[#Route].task = Helicopter:TaskCombo( Tasks )
|
||||||
|
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
-- Now route the helicopter
|
||||||
|
Helicopter:Route( Route, 0 )
|
||||||
|
|
||||||
|
self:GetParent( self, AI_CARGO_HELICOPTER ).onafterDeploy( self, Helicopter, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after Home event.
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP Helicopter
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Home place.
|
||||||
|
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height Height in meters to move to the home coordinate.
|
||||||
|
-- @param Core.Zone#ZONE HomeZone The zone wherein the carrier will return when all cargo has been transported. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
|
function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinate, Speed, Height, HomeZone )
|
||||||
|
|
||||||
|
if Helicopter and Helicopter:IsAlive() ~= nil then
|
||||||
|
|
||||||
|
self.RouteHome = true
|
||||||
|
|
||||||
|
local Route = {}
|
||||||
|
|
||||||
|
--- Calculate the target route point.
|
||||||
|
|
||||||
|
Coordinate.y = Height
|
||||||
|
|
||||||
|
Speed = Speed or Helicopter:GetSpeedMax()*0.5
|
||||||
|
|
||||||
|
--- 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
|
||||||
|
)
|
||||||
|
Route[#Route+1] = WaypointFrom
|
||||||
|
|
||||||
|
--- Create a route point of type air.
|
||||||
|
local CoordinateTo = Coordinate
|
||||||
|
local WaypointTo = CoordinateTo:WaypointAir(
|
||||||
|
"RADIO",
|
||||||
|
POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
|
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||||
|
Speed ,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
|
||||||
|
Helicopter:WayPointInitialize( Route )
|
||||||
|
|
||||||
|
local Tasks = {}
|
||||||
|
|
||||||
|
Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() )
|
||||||
|
Route[#Route].task = Helicopter:TaskCombo( Tasks )
|
||||||
|
|
||||||
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
|
-- Now route the helicopter
|
||||||
|
Helicopter:Route( Route, 0 )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -1,64 +1,34 @@
|
|||||||
--- **AI** -- Build large **formations** of AI @{Group}s flying together.
|
--- **AI** -- Build large airborne formations of aircraft.
|
||||||
--
|
--
|
||||||
-- 
|
-- **Features:**
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- AI_FORMATION makes AI @{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:
|
|
||||||
--
|
|
||||||
-- * Make formation building a process that can be managed while in flight, rather than a task.
|
|
||||||
-- * Human players can guide formations, consisting of larget planes.
|
|
||||||
-- * Build large formations (like a large bomber field).
|
|
||||||
-- * Form formations that DCS does not support off the shelve.
|
|
||||||
--
|
|
||||||
-- A few remarks:
|
|
||||||
--
|
|
||||||
-- * Depending on the type of plane, the change in direction by the leader may result in the formation getting disentangled while in flight and needs to be rebuild.
|
|
||||||
-- * Formations are vulnerable to collissions, but is depending on the type of plane, the distance between the planes and the speed and angle executed by the leader.
|
|
||||||
-- * Formations may take a while to build up.
|
|
||||||
--
|
|
||||||
-- As a result, the AI_FORMATION is not perfect, but is very useful to:
|
|
||||||
--
|
|
||||||
-- * Model large formations when flying straight line.
|
|
||||||
-- * Make humans guide a large formation, when the planes are wide from each other.
|
|
||||||
--
|
|
||||||
-- There are the following types of classes defined:
|
|
||||||
--
|
|
||||||
-- * @{#AI_FORMATION}: Create a formation from several @{GROUP}s.
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # Demo Missions
|
|
||||||
--
|
|
||||||
-- ### [AI_FORMATION Demo Missions source code]()
|
|
||||||
--
|
|
||||||
-- ### [AI_FORMATION Demo Missions, only for beta testers]()
|
|
||||||
--
|
--
|
||||||
-- ### [ALL Demo Missions pack of the last release]()
|
-- * Build in-air formations consisting of more than 40 aircraft as one group.
|
||||||
--
|
-- * Build different formation types.
|
||||||
-- ====
|
-- * Assign a group leader that will guide the large formation path.
|
||||||
--
|
|
||||||
-- # YouTube Channel
|
|
||||||
--
|
|
||||||
--- ### [AI_FORMATION YouTube Channel]()
|
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/FOR%20-%20Formation)
|
||||||
--
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0bFIJ9jIdYM22uaWmIN4oz)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI_Formation
|
-- @module AI.AI_Formation
|
||||||
|
-- @image AI_Large_Formations.JPG
|
||||||
|
|
||||||
--- AI_FORMATION class
|
--- AI_FORMATION class
|
||||||
-- @type AI_FORMATION
|
-- @type AI_FORMATION
|
||||||
-- @extends Fsm#FSM_SET
|
-- @extends Core.Fsm#FSM_SET
|
||||||
-- @field Unit#UNIT FollowUnit
|
-- @field Wrapper.Unit#UNIT FollowUnit
|
||||||
-- @field Set#SET_GROUP FollowGroupSet
|
-- @field Core.Set#SET_GROUP FollowGroupSet
|
||||||
-- @field #string FollowName
|
-- @field #string FollowName
|
||||||
-- @field #AI_FORMATION.MODE FollowMode The mode the escort is in.
|
-- @field #AI_FORMATION.MODE FollowMode The mode the escort is in.
|
||||||
-- @field Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
|
-- @field Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
|
||||||
@@ -66,12 +36,9 @@
|
|||||||
-- @field #boolean ReportTargets If true, nearby targets are reported.
|
-- @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.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 DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup.
|
||||||
-- @field Menu#MENU_CLIENT FollowMenuResumeMission
|
|
||||||
|
|
||||||
|
|
||||||
--- # AI_FORMATION class, extends @{Fsm#FSM_SET}
|
--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader.
|
||||||
--
|
|
||||||
-- The #AI_FORMATION class allows you to build large formations, make AI follow a @{Client#CLIENT} (player) leader or a @{Unit#UNIT} (AI) leader.
|
|
||||||
--
|
--
|
||||||
-- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions.
|
-- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions.
|
||||||
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
|
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
|
||||||
@@ -97,25 +64,25 @@
|
|||||||
--
|
--
|
||||||
-- Create a new SPAWN object with the @{#AI_FORMATION.New} method:
|
-- Create a new SPAWN object with the @{#AI_FORMATION.New} method:
|
||||||
--
|
--
|
||||||
-- * @{Follow#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Group#GROUP} for a @{Client#CLIENT} or a @{Unit#UNIT}, with an optional briefing text.
|
-- * @{#AI_FORMATION.New}(): Creates a new AI_FORMATION object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT} or a @{Wrapper.Unit#UNIT}, with an optional briefing text.
|
||||||
--
|
--
|
||||||
-- ## Formation methods
|
-- ## Formation methods
|
||||||
--
|
--
|
||||||
-- The following methods can be used to set or change the formation:
|
-- The following methods can be used to set or change the formation:
|
||||||
--
|
--
|
||||||
-- * @{AI_Formation#AI_FORMATION.FormationLine}(): Form a line formation (core formation function).
|
-- * @{#AI_FORMATION.FormationLine}(): Form a line formation (core formation function).
|
||||||
-- * @{AI_Formation#AI_FORMATION.FormationTrail}(): Form a trail formation.
|
-- * @{#AI_FORMATION.FormationTrail}(): Form a trail formation.
|
||||||
-- * @{AI_Formation#AI_FORMATION.FormationLeftLine}(): Form a left line formation.
|
-- * @{#AI_FORMATION.FormationLeftLine}(): Form a left line formation.
|
||||||
-- * @{AI_Formation#AI_FORMATION.FormationRightLine}(): Form a right line formation.
|
-- * @{#AI_FORMATION.FormationRightLine}(): Form a right line formation.
|
||||||
-- * @{AI_Formation#AI_FORMATION.FormationRightWing}(): Form a right wing formation.
|
-- * @{#AI_FORMATION.FormationRightWing}(): Form a right wing formation.
|
||||||
-- * @{AI_Formation#AI_FORMATION.FormationLeftWing}(): Form a left wing formation.
|
-- * @{#AI_FORMATION.FormationLeftWing}(): Form a left wing formation.
|
||||||
-- * @{AI_Formation#AI_FORMATION.FormationCenterWing}(): Form a center wing formation.
|
-- * @{#AI_FORMATION.FormationCenterWing}(): Form a center wing formation.
|
||||||
-- * @{AI_Formation#AI_FORMATION.FormationCenterVic}(): Form a Vic formation (same as CenterWing.
|
-- * @{#AI_FORMATION.FormationCenterVic}(): Form a Vic formation (same as CenterWing.
|
||||||
-- * @{AI_Formation#AI_FORMATION.FormationCenterBoxed}(): Form a center boxed formation.
|
-- * @{#AI_FORMATION.FormationCenterBoxed}(): Form a center boxed formation.
|
||||||
--
|
--
|
||||||
-- ## Randomization
|
-- ## Randomization
|
||||||
--
|
--
|
||||||
-- Use the method @{AI_Formation#AI_FORMATION.SetFlightRandomization}() to simulate the formation flying errors that pilots make while in formation. Is a range set in meters.
|
-- Use the method @{AI.AI_Formation#AI_FORMATION.SetFlightRandomization}() to simulate the formation flying errors that pilots make while in formation. Is a range set in meters.
|
||||||
--
|
--
|
||||||
-- @usage
|
-- @usage
|
||||||
-- local FollowGroupSet = SET_GROUP:New():FilterCategories("plane"):FilterCoalitions("blue"):FilterPrefixes("Follow"):FilterStart()
|
-- local FollowGroupSet = SET_GROUP:New():FilterCategories("plane"):FilterCoalitions("blue"):FilterPrefixes("Follow"):FilterStart()
|
||||||
@@ -155,7 +122,7 @@ AI_FORMATION = {
|
|||||||
|
|
||||||
--- AI_FORMATION class constructor for an AI group
|
--- AI_FORMATION class constructor for an AI group
|
||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet.
|
-- @param Wrapper.Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet.
|
||||||
-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit.
|
-- @param Core.Set#SET_GROUP FollowGroupSet The group AI escorting the FollowUnit.
|
||||||
-- @param #string FollowName Name of the escort.
|
-- @param #string FollowName Name of the escort.
|
||||||
-- @return #AI_FORMATION self
|
-- @return #AI_FORMATION self
|
||||||
@@ -163,8 +130,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
local self = BASE:Inherit( self, FSM_SET:New( FollowGroupSet ) )
|
local self = BASE:Inherit( self, FSM_SET:New( FollowGroupSet ) )
|
||||||
self:F( { FollowUnit, FollowGroupSet, FollowName } )
|
self:F( { FollowUnit, FollowGroupSet, FollowName } )
|
||||||
|
|
||||||
self.FollowUnit = FollowUnit -- Unit#UNIT
|
self.FollowUnit = FollowUnit -- Wrapper.Unit#UNIT
|
||||||
self.FollowGroupSet = FollowGroupSet -- Set#SET_GROUP
|
self.FollowGroupSet = FollowGroupSet -- Core.Set#SET_GROUP
|
||||||
|
|
||||||
self:SetFlightRandomization( 2 )
|
self:SetFlightRandomization( 2 )
|
||||||
|
|
||||||
@@ -679,11 +646,11 @@ end
|
|||||||
function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) --R2.1
|
function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) --R2.1
|
||||||
self:F( { FollowGroupSet, From , Event ,To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace } )
|
self:F( { FollowGroupSet, From , Event ,To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace } )
|
||||||
|
|
||||||
FollowGroupSet:Flush()
|
FollowGroupSet:Flush( self )
|
||||||
|
|
||||||
local FollowSet = FollowGroupSet:GetSet()
|
local FollowSet = FollowGroupSet:GetSet()
|
||||||
|
|
||||||
local i = 0
|
local i = 1 --FF i=0 caused first unit to have no XSpace! Probably needs further adjustments. This is just a quick work around.
|
||||||
|
|
||||||
for FollowID, FollowGroup in pairs( FollowSet ) do
|
for FollowID, FollowGroup in pairs( FollowSet ) do
|
||||||
|
|
||||||
@@ -914,7 +881,7 @@ function AI_FORMATION:onafterFormationBox( FollowGroupSet, From , Event , To, XS
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Use the method @{AI_Formation#AI_FORMATION.SetFlightRandomization}() to make the air units in your formation randomize their flight a bit while in formation.
|
--- Use the method @{AI.AI_Formation#AI_FORMATION.SetFlightRandomization}() to make the air units in your formation randomize their flight a bit while in formation.
|
||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number FlightRandomization The formation flying errors that pilots can make while in formation. Is a range set in meters.
|
-- @param #number FlightRandomization The formation flying errors that pilots can make while in formation. Is a range set in meters.
|
||||||
-- @return #AI_FORMATION
|
-- @return #AI_FORMATION
|
||||||
@@ -1001,7 +968,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
|||||||
local Alpha_R = ( Alpha_T < 0 ) and Alpha_T + 2 * math.pi or Alpha_T
|
local Alpha_R = ( Alpha_T < 0 ) and Alpha_T + 2 * math.pi or Alpha_T
|
||||||
local Position = math.cos( Alpha_R )
|
local Position = math.cos( Alpha_R )
|
||||||
local GD = ( ( GDv.x )^2 + ( GDv.z )^2 ) ^ 0.5
|
local GD = ( ( GDv.x )^2 + ( GDv.z )^2 ) ^ 0.5
|
||||||
local Distance = GD * Position + - CS * 0,5
|
local Distance = GD * Position + - CS * 0.5
|
||||||
|
|
||||||
-- Calculate the group direction vector
|
-- Calculate the group direction vector
|
||||||
local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z }
|
local GV = { x = GV2.x - CV2.x, y = GV2.y - CV2.y, z = GV2.z - CV2.z }
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
--- **AI** -- **Air Patrolling or Staging.**
|
--- **AI** -- Perform Air Patrolling for airplanes.
|
||||||
--
|
--
|
||||||
-- 
|
-- **Features:**
|
||||||
|
--
|
||||||
|
-- * Patrol AI airplanes within a given zone.
|
||||||
|
-- * Trigger detected events when enemy airplanes are detected.
|
||||||
|
-- * Manage a fuel treshold to RTB on time.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -10,53 +14,43 @@
|
|||||||
--
|
--
|
||||||
-- * @{#AI_PATROL_ZONE}: Perform a PATROL in a zone.
|
-- * @{#AI_PATROL_ZONE}: Perform a PATROL in a zone.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # Demo Missions
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
|
||||||
--
|
--
|
||||||
-- ### [AI_PATROL Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [AI_PATROL Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/PAT%20-%20Patrolling)
|
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl35HvYZKA6G22WMt7iI3zky)
|
||||||
--
|
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # YouTube Channel
|
-- ### Author: **FlightControl**
|
||||||
--
|
|
||||||
-- ### [AI_PATROL YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl35HvYZKA6G22WMt7iI3zky)
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
|
||||||
-- ### Contributions:
|
-- ### 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](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.
|
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Testing and API concept review.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI_Patrol
|
-- @module AI.AI_Patrol
|
||||||
|
-- @image AI_Air_Patrolling.JPG
|
||||||
|
|
||||||
--- AI_PATROL_ZONE class
|
--- AI_PATROL_ZONE class
|
||||||
-- @type AI_PATROL_ZONE
|
-- @type AI_PATROL_ZONE
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
|
-- @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 @{Zone} where the patrol needs to be executed.
|
||||||
-- @field Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @field DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @field DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
-- @field DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
-- @field DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @field Functional.Spawn#SPAWN CoordTest
|
-- @field Core.Spawn#SPAWN CoordTest
|
||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
--- # AI_PATROL_ZONE class, extends @{Fsm#FSM_CONTROLLABLE}
|
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||||
--
|
|
||||||
-- The AI_PATROL_ZONE class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}.
|
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_PATROL_ZONE is assigned a @{Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event.
|
-- The AI_PATROL_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -129,7 +123,7 @@
|
|||||||
-- * @{#AI_PATROL_ZONE.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased.
|
-- * @{#AI_PATROL_ZONE.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased.
|
||||||
--
|
--
|
||||||
-- The detection frequency can be set with @{#AI_PATROL_ZONE.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
|
-- The detection frequency can be set with @{#AI_PATROL_ZONE.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
|
||||||
-- Use the method @{#AI_PATROL_ZONE.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI.
|
-- Use the method @{#AI_PATROL_ZONE.GetDetectedUnits}() to obtain a list of the @{Wrapper.Unit}s detected by the AI.
|
||||||
--
|
--
|
||||||
-- The detection can be filtered to potential targets in a specific zone.
|
-- The detection can be filtered to potential targets in a specific zone.
|
||||||
-- Use the method @{#AI_PATROL_ZONE.SetDetectionZone}() to set the zone where targets need to be detected.
|
-- Use the method @{#AI_PATROL_ZONE.SetDetectionZone}() to set the zone where targets need to be detected.
|
||||||
@@ -161,11 +155,11 @@ AI_PATROL_ZONE = {
|
|||||||
--- Creates a new AI_PATROL_ZONE object
|
--- Creates a new AI_PATROL_ZONE object
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @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 @{Zone} where the patrol needs to be executed.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
-- @param DCS#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
||||||
-- @return #AI_PATROL_ZONE self
|
-- @return #AI_PATROL_ZONE self
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Define a new AI_PATROL_ZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
|
-- -- Define a new AI_PATROL_ZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
|
||||||
@@ -460,8 +454,8 @@ end
|
|||||||
|
|
||||||
--- Sets (modifies) the minimum and maximum speed of the patrol.
|
--- Sets (modifies) the minimum and maximum speed of the patrol.
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
-- @return #AI_PATROL_ZONE self
|
-- @return #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
|
function AI_PATROL_ZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
|
||||||
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
|
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
|
||||||
@@ -474,8 +468,8 @@ end
|
|||||||
|
|
||||||
--- Sets the floor and ceiling altitude of the patrol.
|
--- Sets the floor and ceiling altitude of the patrol.
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @return #AI_PATROL_ZONE self
|
-- @return #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
function AI_PATROL_ZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
||||||
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
|
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
|
||||||
@@ -568,18 +562,18 @@ function AI_PATROL_ZONE:SetDetectionZone( DetectionZone )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Gets a list of @{Unit#UNIT}s that were detected by the AI.
|
--- Gets a list of @{Wrapper.Unit#UNIT}s that were detected by the AI.
|
||||||
-- No filtering is applied, so, ANY detected UNIT can be in this list.
|
-- No filtering is applied, so, ANY detected UNIT can be in this list.
|
||||||
-- It is up to the mission designer to use the @{Unit} class and methods to filter the targets.
|
-- It is up to the mission designer to use the @{Wrapper.Unit} class and methods to filter the targets.
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @return #table The list of @{Unit#UNIT}s
|
-- @return #table The list of @{Wrapper.Unit#UNIT}s
|
||||||
function AI_PATROL_ZONE:GetDetectedUnits()
|
function AI_PATROL_ZONE:GetDetectedUnits()
|
||||||
self:F2()
|
self:F2()
|
||||||
|
|
||||||
return self.DetectedUnits
|
return self.DetectedUnits
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Clears the list of @{Unit#UNIT}s that were detected by the AI.
|
--- Clears the list of @{Wrapper.Unit#UNIT}s that were detected by the AI.
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:ClearDetectedUnits()
|
function AI_PATROL_ZONE:ClearDetectedUnits()
|
||||||
self:F2()
|
self:F2()
|
||||||
@@ -596,7 +590,6 @@ end
|
|||||||
-- @return #AI_PATROL_ZONE self
|
-- @return #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
|
function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
|
||||||
|
|
||||||
self.PatrolManageFuel = true
|
|
||||||
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
|
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
|
||||||
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
|
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
|
||||||
|
|
||||||
@@ -830,7 +823,7 @@ function AI_PATROL_ZONE:onafterStatus()
|
|||||||
|
|
||||||
local RTB = false
|
local RTB = false
|
||||||
|
|
||||||
local Fuel = self.Controllable:GetUnit(1):GetFuel()
|
local Fuel = self.Controllable:GetFuelMin()
|
||||||
if Fuel < self.PatrolFuelThresholdPercentage then
|
if Fuel < self.PatrolFuelThresholdPercentage then
|
||||||
self:E( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
|
self:E( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
|
||||||
local OldAIControllable = self.Controllable
|
local OldAIControllable = self.Controllable
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occuring on @{Unit}s.
|
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occuring on @{Wrapper.Unit}s.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Account
|
-- @module Actions.Account
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
do -- ACT_ACCOUNT
|
do -- ACT_ACCOUNT
|
||||||
|
|
||||||
--- # @{#ACT_ACCOUNT} FSM class, extends @{Fsm#FSM_PROCESS}
|
--- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||||
--
|
--
|
||||||
-- ## ACT_ACCOUNT state machine:
|
-- ## ACT_ACCOUNT state machine:
|
||||||
--
|
--
|
||||||
@@ -55,7 +55,7 @@ do -- ACT_ACCOUNT
|
|||||||
-- These state transition methods need to provide a return value, which is specified at the function description.
|
-- These state transition methods need to provide a return value, which is specified at the function description.
|
||||||
--
|
--
|
||||||
-- @type ACT_ACCOUNT
|
-- @type ACT_ACCOUNT
|
||||||
-- @field Set#SET_UNIT TargetSetUnit
|
-- @field Core.Set#SET_UNIT TargetSetUnit
|
||||||
-- @extends Core.Fsm#FSM_PROCESS
|
-- @extends Core.Fsm#FSM_PROCESS
|
||||||
ACT_ACCOUNT = {
|
ACT_ACCOUNT = {
|
||||||
ClassName = "ACT_ACCOUNT",
|
ClassName = "ACT_ACCOUNT",
|
||||||
@@ -138,7 +138,7 @@ end -- ACT_ACCOUNT
|
|||||||
|
|
||||||
do -- ACT_ACCOUNT_DEADS
|
do -- ACT_ACCOUNT_DEADS
|
||||||
|
|
||||||
--- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Fsm.Account#ACT_ACCOUNT}
|
--- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Core.Fsm.Account#ACT_ACCOUNT}
|
||||||
--
|
--
|
||||||
-- The ACT_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units.
|
-- 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 @{Set} of units that will be tracked upon successful destruction.
|
||||||
@@ -151,7 +151,7 @@ do -- ACT_ACCOUNT_DEADS
|
|||||||
-- * @{#ACT_ACCOUNT_DEADS.New}(): Creates a new ACT_ACCOUNT_DEADS object.
|
-- * @{#ACT_ACCOUNT_DEADS.New}(): Creates a new ACT_ACCOUNT_DEADS object.
|
||||||
--
|
--
|
||||||
-- @type ACT_ACCOUNT_DEADS
|
-- @type ACT_ACCOUNT_DEADS
|
||||||
-- @field Set#SET_UNIT TargetSetUnit
|
-- @field Core.Set#SET_UNIT TargetSetUnit
|
||||||
-- @extends #ACT_ACCOUNT
|
-- @extends #ACT_ACCOUNT
|
||||||
ACT_ACCOUNT_DEADS = {
|
ACT_ACCOUNT_DEADS = {
|
||||||
ClassName = "ACT_ACCOUNT_DEADS",
|
ClassName = "ACT_ACCOUNT_DEADS",
|
||||||
@@ -160,7 +160,7 @@ do -- ACT_ACCOUNT_DEADS
|
|||||||
|
|
||||||
--- Creates a new DESTROY process.
|
--- Creates a new DESTROY process.
|
||||||
-- @param #ACT_ACCOUNT_DEADS self
|
-- @param #ACT_ACCOUNT_DEADS self
|
||||||
-- @param Set#SET_UNIT TargetSetUnit
|
-- @param Core.Set#SET_UNIT TargetSetUnit
|
||||||
-- @param #string TaskName
|
-- @param #string TaskName
|
||||||
function ACT_ACCOUNT_DEADS:New()
|
function ACT_ACCOUNT_DEADS:New()
|
||||||
-- Inherits from BASE
|
-- Inherits from BASE
|
||||||
@@ -190,7 +190,6 @@ do -- ACT_ACCOUNT_DEADS
|
|||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ACCOUNT_DEADS:onenterReport( ProcessUnit, Task, From, Event, To )
|
function ACT_ACCOUNT_DEADS:onenterReport( ProcessUnit, Task, From, Event, To )
|
||||||
self:E( { ProcessUnit, From, Event, To } )
|
|
||||||
|
|
||||||
local MessageText = "Your group with assigned " .. self.TaskName .. " task has " .. Task.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed."
|
local MessageText = "Your group with assigned " .. self.TaskName .. " task has " .. Task.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed."
|
||||||
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||||
@@ -286,7 +285,7 @@ do -- ACT_ACCOUNT_DEADS
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- @param #ACT_ACCOUNT_DEADS self
|
--- @param #ACT_ACCOUNT_DEADS self
|
||||||
-- @param Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function ACT_ACCOUNT_DEADS:onfuncEventDead( EventData )
|
function ACT_ACCOUNT_DEADS:onfuncEventDead( EventData )
|
||||||
self:T( { "EventDead", EventData } )
|
self:T( { "EventDead", EventData } )
|
||||||
|
|
||||||
@@ -298,7 +297,7 @@ do -- ACT_ACCOUNT_DEADS
|
|||||||
--- DCS Events
|
--- DCS Events
|
||||||
|
|
||||||
--- @param #ACT_ACCOUNT_DEADS self
|
--- @param #ACT_ACCOUNT_DEADS self
|
||||||
-- @param Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function ACT_ACCOUNT_DEADS:onfuncEventCrash( EventData )
|
function ACT_ACCOUNT_DEADS:onfuncEventCrash( EventData )
|
||||||
self:T( { "EventDead", EventData } )
|
self:T( { "EventDead", EventData } )
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # @{#ACT_ASSIGN} FSM template class, extends @{Fsm#FSM_PROCESS}
|
-- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS}
|
||||||
--
|
--
|
||||||
-- ## ACT_ASSIGN state machine:
|
-- ## ACT_ASSIGN state machine:
|
||||||
--
|
--
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN}
|
-- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Core.Fsm.Assign#ACT_ASSIGN}
|
||||||
--
|
--
|
||||||
-- The ACT_ASSIGN_ACCEPT class accepts by default a task for a player. No player intervention is allowed to reject the task.
|
-- The ACT_ASSIGN_ACCEPT class accepts by default a task for a player. No player intervention is allowed to reject the task.
|
||||||
--
|
--
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Fsm.Assign#ACT_ASSIGN}
|
-- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Core.Fsm.Assign#ACT_ASSIGN}
|
||||||
--
|
--
|
||||||
-- The ACT_ASSIGN_MENU_ACCEPT class accepts a task when the player accepts the task through an added menu option.
|
-- 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.
|
-- This assignment type is useful to conditionally allow the player to choose whether or not he would accept the task.
|
||||||
@@ -77,7 +77,8 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Assign
|
-- @module Actions.Assign
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
|
||||||
do -- ACT_ASSIGN
|
do -- ACT_ASSIGN
|
||||||
@@ -155,8 +156,7 @@ do -- ACT_ASSIGN_ACCEPT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ASSIGN_ACCEPT:onafterStart( ProcessUnit, From, Event, To )
|
function ACT_ASSIGN_ACCEPT:onafterStart( ProcessUnit, Task, From, Event, To )
|
||||||
self:E( { ProcessUnit, From, Event, To } )
|
|
||||||
|
|
||||||
self:__Assign( 1 )
|
self:__Assign( 1 )
|
||||||
end
|
end
|
||||||
@@ -167,12 +167,8 @@ do -- ACT_ASSIGN_ACCEPT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, From, Event, To )
|
function ACT_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, Task, From, Event, To )
|
||||||
env.info( "in here" )
|
|
||||||
self:E( { ProcessUnit, From, Event, To } )
|
|
||||||
|
|
||||||
local ProcessGroup = ProcessUnit:GetGroup()
|
|
||||||
|
|
||||||
self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() )
|
self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -193,36 +189,26 @@ do -- ACT_ASSIGN_MENU_ACCEPT
|
|||||||
|
|
||||||
--- Init.
|
--- Init.
|
||||||
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
||||||
-- @param #string TaskName
|
|
||||||
-- @param #string TaskBriefing
|
-- @param #string TaskBriefing
|
||||||
-- @return #ACT_ASSIGN_MENU_ACCEPT self
|
-- @return #ACT_ASSIGN_MENU_ACCEPT self
|
||||||
function ACT_ASSIGN_MENU_ACCEPT:New( TaskName, TaskBriefing )
|
function ACT_ASSIGN_MENU_ACCEPT:New( TaskBriefing )
|
||||||
|
|
||||||
-- Inherits from BASE
|
-- Inherits from BASE
|
||||||
local self = BASE:Inherit( self, ACT_ASSIGN:New() ) -- #ACT_ASSIGN_MENU_ACCEPT
|
local self = BASE:Inherit( self, ACT_ASSIGN:New() ) -- #ACT_ASSIGN_MENU_ACCEPT
|
||||||
|
|
||||||
self.TaskName = TaskName
|
|
||||||
self.TaskBriefing = TaskBriefing
|
self.TaskBriefing = TaskBriefing
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function ACT_ASSIGN_MENU_ACCEPT:Init( FsmAssign )
|
|
||||||
|
|
||||||
self.TaskName = FsmAssign.TaskName
|
|
||||||
self.TaskBriefing = FsmAssign.TaskBriefing
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
|
--- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
|
||||||
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
||||||
-- @param #string TaskName
|
|
||||||
-- @param #string TaskBriefing
|
-- @param #string TaskBriefing
|
||||||
-- @return #ACT_ASSIGN_MENU_ACCEPT self
|
-- @return #ACT_ASSIGN_MENU_ACCEPT self
|
||||||
function ACT_ASSIGN_MENU_ACCEPT:Init( TaskName, TaskBriefing )
|
function ACT_ASSIGN_MENU_ACCEPT:Init( TaskBriefing )
|
||||||
|
|
||||||
self.TaskBriefing = TaskBriefing
|
self.TaskBriefing = TaskBriefing
|
||||||
self.TaskName = TaskName
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -233,32 +219,31 @@ do -- ACT_ASSIGN_MENU_ACCEPT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, From, Event, To )
|
function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, Task, From, Event, To )
|
||||||
self:E( { ProcessUnit, From, Event, To } )
|
|
||||||
|
|
||||||
self:GetCommandCenter():MessageTypeToGroup( "Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled.", ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
self:GetCommandCenter():MessageToGroup( "Task " .. self.Task:GetName() .. " has been assigned to you and your group!\nRead the briefing and use the Radio Menu (F10) / Task ... CONFIRMATION menu to accept or reject the task.\nYou have 2 minutes to accept, or the task assignment will be cancelled!", ProcessUnit:GetGroup(), 120 )
|
||||||
|
|
||||||
local ProcessGroup = ProcessUnit:GetGroup()
|
local TaskGroup = ProcessUnit:GetGroup()
|
||||||
|
|
||||||
|
self.Menu = MENU_GROUP:New( TaskGroup, "Task " .. self.Task:GetName() .. " CONFIRMATION" )
|
||||||
|
self.MenuAcceptTask = MENU_GROUP_COMMAND:New( TaskGroup, "Accept task " .. self.Task:GetName(), self.Menu, self.MenuAssign, self, TaskGroup )
|
||||||
|
self.MenuRejectTask = MENU_GROUP_COMMAND:New( TaskGroup, "Reject task " .. self.Task:GetName(), self.Menu, self.MenuReject, self, TaskGroup )
|
||||||
|
|
||||||
self.Menu = MENU_GROUP:New( ProcessGroup, "Task " .. self.TaskName .. " acceptance" )
|
self:__Reject( 120, TaskGroup )
|
||||||
self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.TaskName, self.Menu, self.MenuAssign, self )
|
|
||||||
self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.TaskName, self.Menu, self.MenuReject, self )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Menu function.
|
--- Menu function.
|
||||||
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
||||||
function ACT_ASSIGN_MENU_ACCEPT:MenuAssign()
|
function ACT_ASSIGN_MENU_ACCEPT:MenuAssign( TaskGroup )
|
||||||
self:E( )
|
|
||||||
|
|
||||||
self:__Assign( 1 )
|
self:__Assign( -1, TaskGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Menu function.
|
--- Menu function.
|
||||||
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
||||||
function ACT_ASSIGN_MENU_ACCEPT:MenuReject()
|
function ACT_ASSIGN_MENU_ACCEPT:MenuReject( TaskGroup )
|
||||||
self:E( )
|
|
||||||
|
|
||||||
self:__Reject( 1 )
|
self:__Reject( -1, TaskGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- StateMachine callback function
|
--- StateMachine callback function
|
||||||
@@ -267,8 +252,7 @@ do -- ACT_ASSIGN_MENU_ACCEPT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, From, Event, To )
|
function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, Task, From, Event, To, TaskGroup )
|
||||||
self:E( { ProcessUnit.UnitNameFrom, Event, To } )
|
|
||||||
|
|
||||||
self.Menu:Remove()
|
self.Menu:Remove()
|
||||||
end
|
end
|
||||||
@@ -279,13 +263,25 @@ do -- ACT_ASSIGN_MENU_ACCEPT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, From, Event, To )
|
function ACT_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, Task, From, Event, To, TaskGroup )
|
||||||
self:E( { ProcessUnit.UnitName, From, Event, To } )
|
self:F( { TaskGroup = TaskGroup } )
|
||||||
|
|
||||||
self.Menu:Remove()
|
self.Menu:Remove()
|
||||||
--TODO: need to resolve this problem ... it has to do with the events ...
|
--TODO: need to resolve this problem ... it has to do with the events ...
|
||||||
--self.Task:UnAssignFromUnit( ProcessUnit )needs to become a callback funtion call upon the event
|
--self.Task:UnAssignFromUnit( ProcessUnit )needs to become a callback funtion call upon the event
|
||||||
ProcessUnit:Destroy()
|
self.Task:RejectGroup( TaskGroup )
|
||||||
|
end
|
||||||
|
|
||||||
|
--- StateMachine callback function
|
||||||
|
-- @param #ACT_ASSIGN_ACCEPT self
|
||||||
|
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
function ACT_ASSIGN_MENU_ACCEPT:onenterAssigned( ProcessUnit, Task, From, Event, To, TaskGroup )
|
||||||
|
|
||||||
|
--self.Task:AssignToGroup( TaskGroup )
|
||||||
|
self.Task:Assign( ProcessUnit, ProcessUnit:GetPlayerName() )
|
||||||
end
|
end
|
||||||
|
|
||||||
end -- ACT_ASSIGN_MENU_ACCEPT
|
end -- ACT_ASSIGN_MENU_ACCEPT
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
|
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
|
||||||
--
|
--
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- # @{#ACT_ASSIST} FSM class, extends @{Fsm#FSM_PROCESS}
|
|
||||||
--
|
|
||||||
-- ## ACT_ASSIST state machine:
|
-- ## ACT_ASSIST state machine:
|
||||||
--
|
--
|
||||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||||
@@ -52,7 +48,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Fsm.Route#ACT_ASSIST}
|
-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Core.Fsm.Route#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 @{Zone}.
|
||||||
-- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour.
|
-- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour.
|
||||||
@@ -64,7 +60,9 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Smoke
|
-- @module Actions.Assist
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
|
||||||
do -- ACT_ASSIST
|
do -- ACT_ASSIST
|
||||||
|
|
||||||
@@ -111,7 +109,6 @@ do -- ACT_ASSIST
|
|||||||
local MissionMenu = self:GetMission():GetMenu( ProcessGroup )
|
local MissionMenu = self:GetMission():GetMenu( ProcessGroup )
|
||||||
|
|
||||||
local function MenuSmoke( MenuParam )
|
local function MenuSmoke( MenuParam )
|
||||||
self:E( MenuParam )
|
|
||||||
local self = MenuParam.self
|
local self = MenuParam.self
|
||||||
local SmokeColor = MenuParam.SmokeColor
|
local SmokeColor = MenuParam.SmokeColor
|
||||||
self.SmokeColor = SmokeColor
|
self.SmokeColor = SmokeColor
|
||||||
@@ -143,7 +140,7 @@ do -- ACT_ASSIST_SMOKE_TARGETS_ZONE
|
|||||||
|
|
||||||
--- ACT_ASSIST_SMOKE_TARGETS_ZONE class
|
--- ACT_ASSIST_SMOKE_TARGETS_ZONE class
|
||||||
-- @type ACT_ASSIST_SMOKE_TARGETS_ZONE
|
-- @type ACT_ASSIST_SMOKE_TARGETS_ZONE
|
||||||
-- @field Set#SET_UNIT TargetSetUnit
|
-- @field Core.Set#SET_UNIT TargetSetUnit
|
||||||
-- @field Core.Zone#ZONE_BASE TargetZone
|
-- @field Core.Zone#ZONE_BASE TargetZone
|
||||||
-- @extends #ACT_ASSIST
|
-- @extends #ACT_ASSIST
|
||||||
ACT_ASSIST_SMOKE_TARGETS_ZONE = {
|
ACT_ASSIST_SMOKE_TARGETS_ZONE = {
|
||||||
@@ -159,7 +156,7 @@ do -- ACT_ASSIST_SMOKE_TARGETS_ZONE
|
|||||||
|
|
||||||
--- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
|
--- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
|
||||||
-- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self
|
-- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self
|
||||||
-- @param Set#SET_UNIT TargetSetUnit
|
-- @param Core.Set#SET_UNIT TargetSetUnit
|
||||||
-- @param Core.Zone#ZONE_BASE TargetZone
|
-- @param Core.Zone#ZONE_BASE TargetZone
|
||||||
function ACT_ASSIST_SMOKE_TARGETS_ZONE:New( TargetSetUnit, TargetZone )
|
function ACT_ASSIST_SMOKE_TARGETS_ZONE:New( TargetSetUnit, TargetZone )
|
||||||
local self = BASE:Inherit( self, ACT_ASSIST:New() ) -- #ACT_ASSIST
|
local self = BASE:Inherit( self, ACT_ASSIST:New() ) -- #ACT_ASSIST
|
||||||
@@ -178,7 +175,7 @@ do -- ACT_ASSIST_SMOKE_TARGETS_ZONE
|
|||||||
|
|
||||||
--- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
|
--- Creates a new target smoking state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
|
||||||
-- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self
|
-- @param #ACT_ASSIST_SMOKE_TARGETS_ZONE self
|
||||||
-- @param Set#SET_UNIT TargetSetUnit
|
-- @param Core.Set#SET_UNIT TargetSetUnit
|
||||||
-- @param Core.Zone#ZONE_BASE TargetZone
|
-- @param Core.Zone#ZONE_BASE TargetZone
|
||||||
-- @return #ACT_ASSIST_SMOKE_TARGETS_ZONE self
|
-- @return #ACT_ASSIST_SMOKE_TARGETS_ZONE self
|
||||||
function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init( TargetSetUnit, TargetZone )
|
function ACT_ASSIST_SMOKE_TARGETS_ZONE:Init( TargetSetUnit, TargetZone )
|
||||||
|
|||||||
@@ -1,198 +0,0 @@
|
|||||||
--- @module Process_JTAC
|
|
||||||
|
|
||||||
--- PROCESS_JTAC class
|
|
||||||
-- @type PROCESS_JTAC
|
|
||||||
-- @field Wrapper.Unit#UNIT ProcessUnit
|
|
||||||
-- @field Core.Set#SET_UNIT TargetSetUnit
|
|
||||||
-- @extends Core.Fsm#FSM_PROCESS
|
|
||||||
PROCESS_JTAC = {
|
|
||||||
ClassName = "PROCESS_JTAC",
|
|
||||||
Fsm = {},
|
|
||||||
TargetSetUnit = nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new DESTROY process.
|
|
||||||
-- @param #PROCESS_JTAC self
|
|
||||||
-- @param Tasking.Task#TASK Task
|
|
||||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
|
||||||
-- @param Core.Set#SET_UNIT TargetSetUnit
|
|
||||||
-- @param Wrapper.Unit#UNIT FACUnit
|
|
||||||
-- @return #PROCESS_JTAC self
|
|
||||||
function PROCESS_JTAC:New( Task, ProcessUnit, TargetSetUnit, FACUnit )
|
|
||||||
|
|
||||||
-- Inherits from BASE
|
|
||||||
local self = BASE:Inherit( self, PROCESS:New( "JTAC", Task, ProcessUnit ) ) -- #PROCESS_JTAC
|
|
||||||
|
|
||||||
self.TargetSetUnit = TargetSetUnit
|
|
||||||
self.FACUnit = FACUnit
|
|
||||||
|
|
||||||
self.DisplayInterval = 60
|
|
||||||
self.DisplayCount = 30
|
|
||||||
self.DisplayMessage = true
|
|
||||||
self.DisplayTime = 10 -- 10 seconds is the default
|
|
||||||
self.DisplayCategory = "HQ" -- Targets is the default display category
|
|
||||||
|
|
||||||
|
|
||||||
self.Fsm = FSM_PROCESS:New( self, {
|
|
||||||
initial = 'Assigned',
|
|
||||||
events = {
|
|
||||||
{ name = 'Start', from = 'Assigned', to = 'CreatedMenu' },
|
|
||||||
{ name = 'JTACMenuUpdate', from = 'CreatedMenu', to = 'AwaitingMenu' },
|
|
||||||
{ name = 'JTACMenuAwait', from = 'AwaitingMenu', to = 'AwaitingMenu' },
|
|
||||||
{ name = 'JTACMenuSpot', from = 'AwaitingMenu', to = 'AwaitingMenu' },
|
|
||||||
{ name = 'JTACMenuCancel', from = 'AwaitingMenu', to = 'AwaitingMenu' },
|
|
||||||
{ name = 'JTACStatus', from = 'AwaitingMenu', to = 'AwaitingMenu' },
|
|
||||||
{ name = 'Fail', from = 'AwaitingMenu', to = 'Failed' },
|
|
||||||
{ name = 'Fail', from = 'CreatedMenu', to = 'Failed' },
|
|
||||||
},
|
|
||||||
callbacks = {
|
|
||||||
onStart = self.OnStart,
|
|
||||||
onJTACMenuUpdate = self.OnJTACMenuUpdate,
|
|
||||||
onJTACMenuAwait = self.OnJTACMenuAwait,
|
|
||||||
onJTACMenuSpot = self.OnJTACMenuSpot,
|
|
||||||
onJTACMenuCancel = self.OnJTACMenuCancel,
|
|
||||||
},
|
|
||||||
endstates = { 'Failed' }
|
|
||||||
} )
|
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Dead, self.EventDead )
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Process Events
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_JTAC self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
function PROCESS_JTAC:OnStart( Fsm, From, Event, To )
|
|
||||||
|
|
||||||
self:NextEvent( Fsm.JTACMenuUpdate )
|
|
||||||
end
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_JTAC self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
function PROCESS_JTAC:OnJTACMenuUpdate( Fsm, From, Event, To )
|
|
||||||
|
|
||||||
local function JTACMenuSpot( MenuParam )
|
|
||||||
self:E( MenuParam.TargetUnit.UnitName )
|
|
||||||
local self = MenuParam.self
|
|
||||||
local TargetUnit = MenuParam.TargetUnit
|
|
||||||
|
|
||||||
self:NextEvent( self.Fsm.JTACMenuSpot, TargetUnit )
|
|
||||||
end
|
|
||||||
|
|
||||||
local function JTACMenuCancel( MenuParam )
|
|
||||||
self:E( MenuParam )
|
|
||||||
local self = MenuParam.self
|
|
||||||
local TargetUnit = MenuParam.TargetUnit
|
|
||||||
|
|
||||||
self:NextEvent( self.Fsm.JTACMenuCancel, TargetUnit )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Loop each unit in the target set, and determine the threat levels map table.
|
|
||||||
local UnitThreatLevels = self.TargetSetUnit:GetUnitThreatLevels()
|
|
||||||
|
|
||||||
self:E( {"UnitThreadLevels", UnitThreatLevels } )
|
|
||||||
|
|
||||||
local JTACMenu = self.ProcessGroup:GetState( self.ProcessGroup, "JTACMenu" )
|
|
||||||
|
|
||||||
if not JTACMenu then
|
|
||||||
JTACMenu = MENU_GROUP:New( self.ProcessGroup, "JTAC", self.MissionMenu )
|
|
||||||
for ThreatLevel, ThreatLevelTable in pairs( UnitThreatLevels ) do
|
|
||||||
local JTACMenuThreatLevel = MENU_GROUP:New( self.ProcessGroup, ThreatLevelTable.UnitThreatLevelText, JTACMenu )
|
|
||||||
for ThreatUnitName, ThreatUnit in pairs( ThreatLevelTable.Units ) do
|
|
||||||
local JTACMenuUnit = MENU_GROUP:New( self.ProcessGroup, ThreatUnit:GetTypeName(), JTACMenuThreatLevel )
|
|
||||||
MENU_GROUP_COMMAND:New( self.ProcessGroup, "Lase Target", JTACMenuUnit, JTACMenuSpot, { self = self, TargetUnit = ThreatUnit } )
|
|
||||||
MENU_GROUP_COMMAND:New( self.ProcessGroup, "Cancel Target", JTACMenuUnit, JTACMenuCancel, { self = self, TargetUnit = ThreatUnit } )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_JTAC self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
function PROCESS_JTAC:OnJTACMenuAwait( Fsm, From, Event, To )
|
|
||||||
|
|
||||||
if self.DisplayCount >= self.DisplayInterval then
|
|
||||||
|
|
||||||
local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC
|
|
||||||
TaskJTAC.Spots = TaskJTAC.Spots or {}
|
|
||||||
for TargetUnitName, SpotData in pairs( TaskJTAC.Spots) do
|
|
||||||
local TargetUnit = UNIT:FindByName( TargetUnitName )
|
|
||||||
self.FACUnit:MessageToGroup( "Lasing " .. TargetUnit:GetTypeName() .. " with laser code " .. SpotData:getCode(), 15, self.ProcessGroup )
|
|
||||||
end
|
|
||||||
self.DisplayCount = 1
|
|
||||||
else
|
|
||||||
self.DisplayCount = self.DisplayCount + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
self:NextEvent( Fsm.JTACMenuAwait )
|
|
||||||
end
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_JTAC self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
-- @param Wrapper.Unit#UNIT TargetUnit
|
|
||||||
function PROCESS_JTAC:OnJTACMenuSpot( Fsm, From, Event, To, TargetUnit )
|
|
||||||
|
|
||||||
local TargetUnitName = TargetUnit:GetName()
|
|
||||||
|
|
||||||
local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC
|
|
||||||
|
|
||||||
TaskJTAC.Spots = TaskJTAC.Spots or {}
|
|
||||||
TaskJTAC.Spots[TargetUnitName] = TaskJTAC.Spots[TargetUnitName] or {}
|
|
||||||
|
|
||||||
local DCSFACObject = self.FACUnit:GetDCSObject()
|
|
||||||
local TargetVec3 = TargetUnit:GetVec3()
|
|
||||||
|
|
||||||
TaskJTAC.Spots[TargetUnitName] = Spot.createInfraRed( self.FACUnit:GetDCSObject(), { x = 0, y = 1, z = 0 }, TargetUnit:GetVec3(), math.random( 1000, 9999 ) )
|
|
||||||
|
|
||||||
local SpotData = TaskJTAC.Spots[TargetUnitName]
|
|
||||||
self.FACUnit:MessageToGroup( "Lasing " .. TargetUnit:GetTypeName() .. " with laser code " .. SpotData:getCode(), 15, self.ProcessGroup )
|
|
||||||
|
|
||||||
self:NextEvent( Fsm.JTACMenuAwait )
|
|
||||||
end
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_JTAC self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
-- @param Wrapper.Unit#UNIT TargetUnit
|
|
||||||
function PROCESS_JTAC:OnJTACMenuCancel( Fsm, From, Event, To, TargetUnit )
|
|
||||||
|
|
||||||
local TargetUnitName = TargetUnit:GetName()
|
|
||||||
|
|
||||||
local TaskJTAC = self.Task -- Tasking.Task#TASK_JTAC
|
|
||||||
|
|
||||||
TaskJTAC.Spots = TaskJTAC.Spots or {}
|
|
||||||
if TaskJTAC.Spots[TargetUnitName] then
|
|
||||||
TaskJTAC.Spots[TargetUnitName]:destroy() -- destroys the spot
|
|
||||||
TaskJTAC.Spots[TargetUnitName] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
self.FACUnit:MessageToGroup( "Stopped lasing " .. TargetUnit:GetTypeName(), 15, self.ProcessGroup )
|
|
||||||
|
|
||||||
self:NextEvent( Fsm.JTACMenuAwait )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
--- @module Process_Pickup
|
|
||||||
|
|
||||||
--- PROCESS_PICKUP class
|
|
||||||
-- @type PROCESS_PICKUP
|
|
||||||
-- @field Wrapper.Unit#UNIT ProcessUnit
|
|
||||||
-- @field Core.Set#SET_UNIT TargetSetUnit
|
|
||||||
-- @extends Core.Fsm#FSM_PROCESS
|
|
||||||
PROCESS_PICKUP = {
|
|
||||||
ClassName = "PROCESS_PICKUP",
|
|
||||||
Fsm = {},
|
|
||||||
TargetSetUnit = nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new DESTROY process.
|
|
||||||
-- @param #PROCESS_PICKUP self
|
|
||||||
-- @param Tasking.Task#TASK Task
|
|
||||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
|
||||||
-- @param Core.Set#SET_UNIT TargetSetUnit
|
|
||||||
-- @return #PROCESS_PICKUP self
|
|
||||||
function PROCESS_PICKUP:New( Task, ProcessName, ProcessUnit )
|
|
||||||
|
|
||||||
-- Inherits from BASE
|
|
||||||
local self = BASE:Inherit( self, PROCESS:New( ProcessName, Task, ProcessUnit ) ) -- #PROCESS_PICKUP
|
|
||||||
|
|
||||||
self.DisplayInterval = 30
|
|
||||||
self.DisplayCount = 30
|
|
||||||
self.DisplayMessage = true
|
|
||||||
self.DisplayTime = 10 -- 10 seconds is the default
|
|
||||||
self.DisplayCategory = "HQ" -- Targets is the default display category
|
|
||||||
|
|
||||||
self.Fsm = FSM_PROCESS:New( self, {
|
|
||||||
initial = 'Assigned',
|
|
||||||
events = {
|
|
||||||
{ name = 'Start', from = 'Assigned', to = 'Navigating' },
|
|
||||||
{ name = 'Start', from = 'Navigating', to = 'Navigating' },
|
|
||||||
{ name = 'Nearby', from = 'Navigating', to = 'Preparing' },
|
|
||||||
{ name = 'Pickup', from = 'Preparing', to = 'Loading' },
|
|
||||||
{ name = 'Load', from = 'Loading', to = 'Success' },
|
|
||||||
{ name = 'Fail', from = 'Assigned', to = 'Failed' },
|
|
||||||
{ name = 'Fail', from = 'Navigating', to = 'Failed' },
|
|
||||||
{ name = 'Fail', from = 'Preparing', to = 'Failed' },
|
|
||||||
},
|
|
||||||
callbacks = {
|
|
||||||
onStart = self.OnStart,
|
|
||||||
onNearby = self.OnNearby,
|
|
||||||
onPickup = self.OnPickup,
|
|
||||||
onLoad = self.OnLoad,
|
|
||||||
},
|
|
||||||
endstates = { 'Success', 'Failed' }
|
|
||||||
} )
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Process Events
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_PICKUP self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
function PROCESS_PICKUP:OnStart( Fsm, From, Event, To )
|
|
||||||
|
|
||||||
self:NextEvent( Fsm.Start )
|
|
||||||
end
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_PICKUP self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
function PROCESS_PICKUP:OnNavigating( Fsm, From, Event, To )
|
|
||||||
|
|
||||||
local TaskGroup = self.ProcessUnit:GetGroup()
|
|
||||||
if self.DisplayCount >= self.DisplayInterval then
|
|
||||||
MESSAGE:New( "Your group with assigned " .. self.Task:GetName() .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed.", 5, "HQ" ):ToGroup( TaskGroup )
|
|
||||||
self.DisplayCount = 1
|
|
||||||
else
|
|
||||||
self.DisplayCount = self.DisplayCount + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
return true -- Process always the event.
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_PICKUP self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
-- @param Core.Event#EVENTDATA Event
|
|
||||||
function PROCESS_PICKUP:OnHitTarget( Fsm, From, Event, To, Event )
|
|
||||||
|
|
||||||
|
|
||||||
self.TargetSetUnit:Flush()
|
|
||||||
|
|
||||||
if self.TargetSetUnit:FindUnit( Event.IniUnitName ) then
|
|
||||||
self.TargetSetUnit:RemoveUnitsByName( Event.IniUnitName )
|
|
||||||
local TaskGroup = self.ProcessUnit:GetGroup()
|
|
||||||
MESSAGE:New( "You hit a target. Your group with assigned " .. self.Task:GetName() .. " task has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed.", 15, "HQ" ):ToGroup( TaskGroup )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
if self.TargetSetUnit:Count() > 0 then
|
|
||||||
self:NextEvent( Fsm.MoreTargets )
|
|
||||||
else
|
|
||||||
self:NextEvent( Fsm.Destroyed )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_PICKUP self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
function PROCESS_PICKUP:OnMoreTargets( Fsm, From, Event, To )
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_PICKUP self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
-- @param Core.Event#EVENTDATA DCSEvent
|
|
||||||
function PROCESS_PICKUP:OnKilled( Fsm, From, Event, To )
|
|
||||||
|
|
||||||
self:NextEvent( Fsm.Restart )
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_PICKUP self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
function PROCESS_PICKUP:OnRestart( Fsm, From, Event, To )
|
|
||||||
|
|
||||||
self:NextEvent( Fsm.Menu )
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- StateMachine callback function for a PROCESS
|
|
||||||
-- @param #PROCESS_PICKUP self
|
|
||||||
-- @param Core.Fsm#FSM_PROCESS Fsm
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
function PROCESS_PICKUP:OnDestroyed( Fsm, From, Event, To )
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- DCS Events
|
|
||||||
|
|
||||||
--- @param #PROCESS_PICKUP self
|
|
||||||
-- @param Core.Event#EVENTDATA Event
|
|
||||||
function PROCESS_PICKUP:EventDead( Event )
|
|
||||||
|
|
||||||
if Event.IniDCSUnit then
|
|
||||||
self:NextEvent( self.Fsm.HitTarget, Event )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # @{#ACT_ROUTE} FSM class, extends @{Fsm#FSM_PROCESS}
|
-- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||||
--
|
--
|
||||||
-- ## ACT_ROUTE state machine:
|
-- ## ACT_ROUTE state machine:
|
||||||
--
|
--
|
||||||
@@ -60,9 +60,9 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Fsm.Route#ACT_ROUTE}
|
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Core.Fsm.Route#ACT_ROUTE}
|
||||||
--
|
--
|
||||||
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Controllable} player @{Unit} to a @{Zone}.
|
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Zone}.
|
||||||
-- The player receives on perioding times messages with the coordinates of the route to follow.
|
-- 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.
|
-- Upon arrival at the zone, a confirmation of arrival is sent, and the process will be ended.
|
||||||
--
|
--
|
||||||
@@ -72,7 +72,8 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Route
|
-- @module Actions.Route
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
|
||||||
do -- ACT_ROUTE
|
do -- ACT_ROUTE
|
||||||
@@ -123,16 +124,20 @@ do -- ACT_ROUTE
|
|||||||
--- Set a Cancel Menu item.
|
--- Set a Cancel Menu item.
|
||||||
-- @param #ACT_ROUTE self
|
-- @param #ACT_ROUTE self
|
||||||
-- @return #ACT_ROUTE
|
-- @return #ACT_ROUTE
|
||||||
function ACT_ROUTE:SetMenuCancel( MenuGroup, MenuText, ParentMenu, MenuTime )
|
function ACT_ROUTE:SetMenuCancel( MenuGroup, MenuText, ParentMenu, MenuTime, MenuTag )
|
||||||
|
|
||||||
MENU_GROUP_COMMAND:New(
|
self.CancelMenuGroupCommand = MENU_GROUP_COMMAND:New(
|
||||||
MenuGroup,
|
MenuGroup,
|
||||||
MenuText,
|
MenuText,
|
||||||
ParentMenu,
|
ParentMenu,
|
||||||
self.MenuCancel,
|
self.MenuCancel,
|
||||||
self
|
self
|
||||||
):SetTime(MenuTime)
|
):SetTime( MenuTime ):SetTag( MenuTag )
|
||||||
|
|
||||||
|
ParentMenu:SetTime( MenuTime )
|
||||||
|
|
||||||
|
ParentMenu:Remove( MenuTime, MenuTag )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -158,8 +163,6 @@ do -- ACT_ROUTE
|
|||||||
-- @return #string
|
-- @return #string
|
||||||
function ACT_ROUTE:GetRouteText( Controllable )
|
function ACT_ROUTE:GetRouteText( Controllable )
|
||||||
|
|
||||||
self:E()
|
|
||||||
|
|
||||||
local RouteText = ""
|
local RouteText = ""
|
||||||
|
|
||||||
local Coordinate = nil -- Core.Point#COORDINATE
|
local Coordinate = nil -- Core.Point#COORDINATE
|
||||||
@@ -182,13 +185,13 @@ do -- ACT_ROUTE
|
|||||||
local ShortestDistance = 0
|
local ShortestDistance = 0
|
||||||
local ShortestReferencePoint = nil
|
local ShortestReferencePoint = nil
|
||||||
local ShortestReferenceName = ""
|
local ShortestReferenceName = ""
|
||||||
self:E( { CC.ReferencePoints } )
|
self:F( { CC.ReferencePoints } )
|
||||||
for ZoneName, Zone in pairs( CC.ReferencePoints ) do
|
for ZoneName, Zone in pairs( CC.ReferencePoints ) do
|
||||||
self:E( { ZoneName = ZoneName } )
|
self:F( { ZoneName = ZoneName } )
|
||||||
local Zone = Zone -- Core.Zone#ZONE
|
local Zone = Zone -- Core.Zone#ZONE
|
||||||
local ZoneCoord = Zone:GetCoordinate()
|
local ZoneCoord = Zone:GetCoordinate()
|
||||||
local ZoneDistance = ZoneCoord:Get2DDistance( self.Coordinate )
|
local ZoneDistance = ZoneCoord:Get2DDistance( self.Coordinate )
|
||||||
self:E( { ShortestDistance, ShortestReferenceName } )
|
self:F( { ShortestDistance, ShortestReferenceName } )
|
||||||
if ShortestDistance == 0 or ZoneDistance < ShortestDistance then
|
if ShortestDistance == 0 or ZoneDistance < ShortestDistance then
|
||||||
ShortestDistance = ZoneDistance
|
ShortestDistance = ZoneDistance
|
||||||
ShortestReferencePoint = ZoneCoord
|
ShortestReferencePoint = ZoneCoord
|
||||||
@@ -208,7 +211,9 @@ do -- ACT_ROUTE
|
|||||||
|
|
||||||
|
|
||||||
function ACT_ROUTE:MenuCancel()
|
function ACT_ROUTE:MenuCancel()
|
||||||
self:Cancel()
|
self:F("Cancelled")
|
||||||
|
self.CancelMenuGroupCommand:Remove()
|
||||||
|
self:__Cancel( 1 )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Task Events
|
--- Task Events
|
||||||
@@ -240,10 +245,8 @@ do -- ACT_ROUTE
|
|||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ROUTE:onbeforeRoute( ProcessUnit, From, Event, To )
|
function ACT_ROUTE:onbeforeRoute( ProcessUnit, From, Event, To )
|
||||||
self:F( { "BeforeRoute 1", self.DisplayCount, self.DisplayInterval } )
|
|
||||||
|
|
||||||
if ProcessUnit:IsAlive() then
|
if ProcessUnit:IsAlive() then
|
||||||
self:F( "BeforeRoute 2" )
|
|
||||||
local HasArrived = self:onfuncHasArrived( ProcessUnit ) -- Polymorphic
|
local HasArrived = self:onfuncHasArrived( ProcessUnit ) -- Polymorphic
|
||||||
if self.DisplayCount >= self.DisplayInterval then
|
if self.DisplayCount >= self.DisplayInterval then
|
||||||
self:T( { HasArrived = HasArrived } )
|
self:T( { HasArrived = HasArrived } )
|
||||||
@@ -255,8 +258,6 @@ do -- ACT_ROUTE
|
|||||||
self.DisplayCount = self.DisplayCount + 1
|
self.DisplayCount = self.DisplayCount + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T( { DisplayCount = self.DisplayCount } )
|
|
||||||
|
|
||||||
if HasArrived then
|
if HasArrived then
|
||||||
self:__Arrive( 1 )
|
self:__Arrive( 1 )
|
||||||
else
|
else
|
||||||
@@ -339,7 +340,7 @@ do -- ACT_ROUTE_POINT
|
|||||||
-- @param #ACT_ROUTE_POINT self
|
-- @param #ACT_ROUTE_POINT self
|
||||||
-- @param #number Range The Range to consider the arrival. Default is 10000 meters.
|
-- @param #number Range The Range to consider the arrival. Default is 10000 meters.
|
||||||
function ACT_ROUTE_POINT:SetRange( Range )
|
function ACT_ROUTE_POINT:SetRange( Range )
|
||||||
self:F2( { self.Range } )
|
self:F2( { Range } )
|
||||||
self.Range = Range or 10000
|
self.Range = Range or 10000
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -347,6 +348,7 @@ do -- ACT_ROUTE_POINT
|
|||||||
-- @param #ACT_ROUTE_POINT self
|
-- @param #ACT_ROUTE_POINT self
|
||||||
-- @return #number The Range to consider the arrival. Default is 10000 meters.
|
-- @return #number The Range to consider the arrival. Default is 10000 meters.
|
||||||
function ACT_ROUTE_POINT:GetRange()
|
function ACT_ROUTE_POINT:GetRange()
|
||||||
|
self:F2( { self.Range } )
|
||||||
return self.Range
|
return self.Range
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -360,7 +362,7 @@ do -- ACT_ROUTE_POINT
|
|||||||
local Distance = self.Coordinate:Get2DDistance( ProcessUnit:GetCoordinate() )
|
local Distance = self.Coordinate:Get2DDistance( ProcessUnit:GetCoordinate() )
|
||||||
|
|
||||||
if Distance <= self.Range then
|
if Distance <= self.Range then
|
||||||
local RouteText = "You have arrived."
|
local RouteText = "Task \"" .. self:GetTask():GetName() .. "\", you have arrived."
|
||||||
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -379,7 +381,7 @@ do -- ACT_ROUTE_POINT
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ROUTE_POINT:onafterReport( ProcessUnit, From, Event, To )
|
function ACT_ROUTE_POINT:onafterReport( ProcessUnit, From, Event, To )
|
||||||
|
|
||||||
local RouteText = self:GetRouteText( ProcessUnit )
|
local RouteText = "Task \"" .. self:GetTask():GetName() .. "\", " .. self:GetRouteText( ProcessUnit )
|
||||||
|
|
||||||
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
|
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
|
||||||
end
|
end
|
||||||
@@ -451,7 +453,7 @@ do -- ACT_ROUTE_ZONE
|
|||||||
function ACT_ROUTE_ZONE:onfuncHasArrived( ProcessUnit )
|
function ACT_ROUTE_ZONE:onfuncHasArrived( ProcessUnit )
|
||||||
|
|
||||||
if ProcessUnit:IsInZone( self.Zone ) then
|
if ProcessUnit:IsInZone( self.Zone ) then
|
||||||
local RouteText = "You have arrived within the zone."
|
local RouteText = "Task \"" .. self:GetTask():GetName() .. "\", you have arrived within the zone."
|
||||||
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -467,9 +469,9 @@ do -- ACT_ROUTE_ZONE
|
|||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ROUTE_ZONE:onafterReport( ProcessUnit, From, Event, To )
|
function ACT_ROUTE_ZONE:onafterReport( ProcessUnit, From, Event, To )
|
||||||
self:E( { ProcessUnit = ProcessUnit } )
|
self:F( { ProcessUnit = ProcessUnit } )
|
||||||
|
|
||||||
local RouteText = self:GetRouteText( ProcessUnit )
|
local RouteText = "Task \"" .. self:GetTask():GetName() .. "\", " .. self:GetRouteText( ProcessUnit )
|
||||||
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
|
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
1426
Moose Development/Moose/Cargo/Cargo.lua
Normal file
1426
Moose Development/Moose/Cargo/Cargo.lua
Normal file
File diff suppressed because it is too large
Load Diff
332
Moose Development/Moose/Cargo/CargoCrate.lua
Normal file
332
Moose Development/Moose/Cargo/CargoCrate.lua
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### [Demo Missions]()
|
||||||
|
--
|
||||||
|
-- ### [YouTube Playlist]()
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
-- ### Contributions:
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Cargo.CargoCrate
|
||||||
|
-- @image Cargo_Crates.JPG
|
||||||
|
|
||||||
|
do -- CARGO_CRATE
|
||||||
|
|
||||||
|
--- Models the behaviour of cargo crates, which can be slingloaded and boarded on helicopters.
|
||||||
|
-- @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.
|
||||||
|
--
|
||||||
|
-- The above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo:
|
||||||
|
--
|
||||||
|
-- * AI Armoured Personnel Carriers to transport cargo and engage in battles, using the @{AI.AI_Cargo_APC} module.
|
||||||
|
-- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter} module.
|
||||||
|
-- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Airplane} module.
|
||||||
|
-- * AI Ships is planned.
|
||||||
|
--
|
||||||
|
-- The above cargo classes are also used by the TASK_CARGO_ classes to allow human players to transport cargo as part of a tasking:
|
||||||
|
--
|
||||||
|
-- * @{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.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @field #CARGO_CRATE
|
||||||
|
CARGO_CRATE = {
|
||||||
|
ClassName = "CARGO_CRATE"
|
||||||
|
}
|
||||||
|
|
||||||
|
--- CARGO_CRATE Constructor.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
-- @param Wrapper.Static#STATIC CargoStatic
|
||||||
|
-- @param #string Type
|
||||||
|
-- @param #string Name
|
||||||
|
-- @param #number LoadRadius (optional)
|
||||||
|
-- @param #number NearRadius (optional)
|
||||||
|
-- @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.CargoObject = CargoStatic -- Wrapper.Static#STATIC
|
||||||
|
|
||||||
|
-- Cargo objects are added to the _DATABASE and SET_CARGO objects.
|
||||||
|
_EVENTDISPATCHER:CreateEventNewCargo( self )
|
||||||
|
|
||||||
|
self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead )
|
||||||
|
self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead )
|
||||||
|
--self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCargoDead )
|
||||||
|
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead )
|
||||||
|
|
||||||
|
self:SetEventPriority( 4 )
|
||||||
|
|
||||||
|
self.NearRadius = NearRadius or 25
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param #CARGO_CRATE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function CARGO_CRATE:OnEventCargoDead( EventData )
|
||||||
|
|
||||||
|
local Destroyed = false
|
||||||
|
|
||||||
|
if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then
|
||||||
|
if self.CargoObject:GetName() == EventData.IniUnitName then
|
||||||
|
if not self.NoDestroy then
|
||||||
|
Destroyed = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if self:IsLoaded() then
|
||||||
|
local CarrierName = self.CargoCarrier:GetName()
|
||||||
|
if CarrierName == EventData.IniDCSUnitName then
|
||||||
|
MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll()
|
||||||
|
Destroyed = true
|
||||||
|
self.CargoCarrier:ClearCargo()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if Destroyed then
|
||||||
|
self:I( { "Cargo crate destroyed: " .. self.CargoObject:GetName() } )
|
||||||
|
self:Destroyed()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Enter UnLoaded State.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#POINT_VEC2
|
||||||
|
function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 )
|
||||||
|
--self:F( { ToPointVec2, From, Event, To } )
|
||||||
|
|
||||||
|
local Angle = 180
|
||||||
|
local Speed = 10
|
||||||
|
local Distance = 10
|
||||||
|
|
||||||
|
if From == "Loaded" then
|
||||||
|
local StartCoordinate = self.CargoCarrier:GetCoordinate()
|
||||||
|
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
||||||
|
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
||||||
|
local CargoDeployCoord = StartCoordinate:Translate( Distance, CargoDeployHeading )
|
||||||
|
|
||||||
|
ToPointVec2 = ToPointVec2 or COORDINATE:NewFromVec2( { x= CargoDeployCoord.x, y = CargoDeployCoord.z } )
|
||||||
|
|
||||||
|
-- Respawn the group...
|
||||||
|
if self.CargoObject then
|
||||||
|
self.CargoObject:ReSpawnAt( ToPointVec2, 0 )
|
||||||
|
self.CargoCarrier = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.OnUnLoadedCallBack then
|
||||||
|
self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) )
|
||||||
|
self.OnUnLoadedCallBack = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Loaded State.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||||
|
function CARGO_CRATE:onenterLoaded( From, Event, To, CargoCarrier )
|
||||||
|
--self:F( { From, Event, To, CargoCarrier } )
|
||||||
|
|
||||||
|
self.CargoCarrier = CargoCarrier
|
||||||
|
|
||||||
|
-- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects).
|
||||||
|
if self.CargoObject then
|
||||||
|
self:T("Destroying")
|
||||||
|
self.NoDestroy = true
|
||||||
|
self.CargoObject:Destroy( false ) -- Do not generate a remove unit event, because we want to keep the template for later respawn in the database.
|
||||||
|
--local Coordinate = self.CargoObject:GetCoordinate():GetRandomCoordinateInRadius( 50, 20 )
|
||||||
|
--self.CargoObject:ReSpawnAt( Coordinate, 0 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the cargo can be Boarded.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
function CARGO_CRATE:CanBoard()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the cargo can be Unboarded.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
function CARGO_CRATE:CanUnboard()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the cargo can be sling loaded.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
function CARGO_CRATE:CanSlingload()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if Cargo Crate is in the radius for the Cargo to be reported.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
local Distance = 0
|
||||||
|
if self:IsUnLoaded() then
|
||||||
|
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||||
|
--self:T( Distance )
|
||||||
|
if Distance <= self.LoadRadius then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if Cargo Crate is in the radius for the Cargo to be Boarded or Loaded.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
local Distance = 0
|
||||||
|
if self:IsUnLoaded() then
|
||||||
|
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||||
|
--self:T( Distance )
|
||||||
|
if Distance <= self.NearRadius then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the current Coordinate of the CargoGroup.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
-- @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()
|
||||||
|
|
||||||
|
return self.CargoObject:GetCoordinate()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the CargoGroup is alive.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
-- @return #boolean true if the CargoGroup is alive.
|
||||||
|
-- @return #boolean false if the CargoGroup is dead.
|
||||||
|
function CARGO_CRATE:IsAlive()
|
||||||
|
|
||||||
|
local Alive = true
|
||||||
|
|
||||||
|
-- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive.
|
||||||
|
-- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive.
|
||||||
|
if self:IsLoaded() then
|
||||||
|
Alive = Alive == true and self.CargoCarrier:IsAlive()
|
||||||
|
else
|
||||||
|
Alive = Alive == true and self.CargoObject:IsAlive()
|
||||||
|
end
|
||||||
|
|
||||||
|
return Alive
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Route Cargo to Coordinate and randomize locations.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
function CARGO_CRATE:RouteTo( Coordinate )
|
||||||
|
self:F( {Coordinate = Coordinate } )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if Cargo is near to the Carrier.
|
||||||
|
-- The Cargo is near to the Carrier within NearRadius.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
-- @param Wrapper.Group#GROUP CargoCarrier
|
||||||
|
-- @param #number NearRadius
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius )
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Respawn the CargoGroup.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
function CARGO_CRATE:Respawn()
|
||||||
|
|
||||||
|
self:F( { "Respawning crate " .. self:GetName() } )
|
||||||
|
|
||||||
|
|
||||||
|
-- Respawn the group...
|
||||||
|
if self.CargoObject then
|
||||||
|
self.CargoObject:ReSpawn() -- A cargo destroy crates a DEAD event.
|
||||||
|
self:__Reset( -0.1 )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Respawn the CargoGroup.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
function CARGO_CRATE:onafterReset()
|
||||||
|
|
||||||
|
self:F( { "Reset crate " .. self:GetName() } )
|
||||||
|
|
||||||
|
|
||||||
|
-- Respawn the group...
|
||||||
|
if self.CargoObject then
|
||||||
|
self:SetDeployed( false )
|
||||||
|
self:SetStartState( "UnLoaded" )
|
||||||
|
self.CargoCarrier = nil
|
||||||
|
-- Cargo objects are added to the _DATABASE and SET_CARGO objects.
|
||||||
|
_EVENTDISPATCHER:CreateEventNewCargo( self )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the transportation method of the Cargo.
|
||||||
|
-- @param #CARGO_CRATE self
|
||||||
|
-- @return #string The transportation method of the Cargo.
|
||||||
|
function CARGO_CRATE:GetTransportationMethod()
|
||||||
|
if self:IsLoaded() then
|
||||||
|
return "for unloading"
|
||||||
|
else
|
||||||
|
if self:IsUnLoaded() then
|
||||||
|
return "for loading"
|
||||||
|
else
|
||||||
|
if self:IsDeployed() then
|
||||||
|
return "delivered"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
775
Moose Development/Moose/Cargo/CargoGroup.lua
Normal file
775
Moose Development/Moose/Cargo/CargoGroup.lua
Normal file
@@ -0,0 +1,775 @@
|
|||||||
|
--- **Cargo** -- Management of grouped cargo logistics, which are based on a @{Wrapper.Group} object.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### [Demo Missions]()
|
||||||
|
--
|
||||||
|
-- ### [YouTube Playlist]()
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
-- ### Contributions:
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Cargo.CargoGroup
|
||||||
|
-- @image Cargo_Groups.JPG
|
||||||
|
|
||||||
|
|
||||||
|
do -- CARGO_GROUP
|
||||||
|
|
||||||
|
--- @type CARGO_GROUP
|
||||||
|
-- @extends Cargo.Cargo#CARGO_REPORTABLE
|
||||||
|
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
|
||||||
|
-- @field #string GroupName The name of the CargoGroup.
|
||||||
|
|
||||||
|
--- 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:
|
||||||
|
--
|
||||||
|
-- * AI Armoured Personnel Carriers to transport cargo and engage in battles, using the @{AI.AI_Cargo_APC} module.
|
||||||
|
-- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter} module.
|
||||||
|
-- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Airplane} module.
|
||||||
|
-- * AI Ships is planned.
|
||||||
|
--
|
||||||
|
-- The above cargo classes are also used by the TASK_CARGO_ classes to allow human players to transport cargo as part of a tasking:
|
||||||
|
--
|
||||||
|
-- * @{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.
|
||||||
|
--
|
||||||
|
-- @field #CARGO_GROUP CARGO_GROUP
|
||||||
|
--
|
||||||
|
CARGO_GROUP = {
|
||||||
|
ClassName = "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.
|
||||||
|
-- @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.
|
||||||
|
-- @param #string Name Some user defined name of the cargo group.
|
||||||
|
-- @param #number LoadRadius (optional) Distance in meters until which a cargo is loaded into the carrier. Cargo outside this radius has to be routed by other means to within the radius to be loaded.
|
||||||
|
-- @param #number NearRadius (optional) Once the units are within this radius of the carrier, they are actually loaded, i.e. disappear from the scene.
|
||||||
|
-- @return #CARGO_GROUP Cargo group object.
|
||||||
|
function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius )
|
||||||
|
local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_GROUP
|
||||||
|
self:F( { Type, Name, LoadRadius } )
|
||||||
|
|
||||||
|
self.CargoSet = SET_CARGO:New()
|
||||||
|
self.CargoGroup = CargoGroup
|
||||||
|
self.Grouped = true
|
||||||
|
self.CargoUnitTemplate = {}
|
||||||
|
|
||||||
|
self.NearRadius = NearRadius
|
||||||
|
|
||||||
|
self:SetDeployed( false )
|
||||||
|
|
||||||
|
local WeightGroup = 0
|
||||||
|
local VolumeGroup = 0
|
||||||
|
|
||||||
|
self.CargoGroup:Destroy() -- destroy and generate a unit removal event, so that the database gets cleaned, and the linked sets get properly cleaned.
|
||||||
|
|
||||||
|
local GroupName = CargoGroup:GetName()
|
||||||
|
self.CargoName = Name
|
||||||
|
self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) )
|
||||||
|
|
||||||
|
self.GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||||
|
self.GroupTemplate.name = self.CargoName .. "#CARGO"
|
||||||
|
self.GroupTemplate.groupId = nil
|
||||||
|
|
||||||
|
self.GroupTemplate.units = {}
|
||||||
|
|
||||||
|
for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do
|
||||||
|
UnitTemplate.name = UnitTemplate.name .. "#CARGO"
|
||||||
|
local CargoUnitName = UnitTemplate.name
|
||||||
|
self.CargoUnitTemplate[CargoUnitName] = UnitTemplate
|
||||||
|
|
||||||
|
self.GroupTemplate.units[#self.GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName]
|
||||||
|
self.GroupTemplate.units[#self.GroupTemplate.units].unitId = nil
|
||||||
|
|
||||||
|
-- And we register the spawned unit as part of the CargoSet.
|
||||||
|
local Unit = UNIT:Register( CargoUnitName )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Then we register the new group in the database
|
||||||
|
self.CargoGroup = GROUP:NewTemplate( self.GroupTemplate, self.GroupTemplate.CoalitionID, self.GroupTemplate.CategoryID, self.GroupTemplate.CountryID )
|
||||||
|
|
||||||
|
-- Now we spawn the new group based on the template created.
|
||||||
|
self.CargoObject = _DATABASE:Spawn( self.GroupTemplate )
|
||||||
|
|
||||||
|
for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do
|
||||||
|
|
||||||
|
|
||||||
|
local CargoUnitName = CargoUnit:GetName()
|
||||||
|
|
||||||
|
local Cargo = CARGO_UNIT:New( CargoUnit, Type, CargoUnitName, LoadRadius, NearRadius )
|
||||||
|
self.CargoSet:Add( CargoUnitName, Cargo )
|
||||||
|
|
||||||
|
WeightGroup = WeightGroup + Cargo:GetWeight()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetWeight( WeightGroup )
|
||||||
|
|
||||||
|
self:T( { "Weight Cargo", WeightGroup } )
|
||||||
|
|
||||||
|
-- Cargo objects are added to the _DATABASE and SET_CARGO objects.
|
||||||
|
_EVENTDISPATCHER:CreateEventNewCargo( self )
|
||||||
|
|
||||||
|
self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead )
|
||||||
|
self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead )
|
||||||
|
--self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCargoDead )
|
||||||
|
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead )
|
||||||
|
|
||||||
|
self:SetEventPriority( 4 )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Respawn the CargoGroup.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
function CARGO_GROUP:Respawn()
|
||||||
|
|
||||||
|
self:F( { "Respawning" } )
|
||||||
|
|
||||||
|
for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do
|
||||||
|
local Cargo = CargoData -- Cargo.Cargo#CARGO
|
||||||
|
Cargo:Destroy() -- Destroy the cargo and generate a remove unit event to update the sets.
|
||||||
|
Cargo:SetStartState( "UnLoaded" )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Now we spawn the new group based on the template created.
|
||||||
|
_DATABASE:Spawn( self.GroupTemplate )
|
||||||
|
|
||||||
|
for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do
|
||||||
|
|
||||||
|
local CargoUnitName = CargoUnit:GetName()
|
||||||
|
|
||||||
|
local Cargo = CARGO_UNIT:New( CargoUnit, self.Type, CargoUnitName, self.LoadRadius )
|
||||||
|
self.CargoSet:Add( CargoUnitName, Cargo )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetDeployed( false )
|
||||||
|
self:SetStartState( "UnLoaded" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Ungroup the cargo group into individual groups with one unit.
|
||||||
|
-- This is required because by default a group will move in formation and this is really an issue for group control.
|
||||||
|
-- Therefore this method is made to be able to ungroup a group.
|
||||||
|
-- This works for ground only groups.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
function CARGO_GROUP:Ungroup()
|
||||||
|
|
||||||
|
if self.Grouped == true then
|
||||||
|
|
||||||
|
self.Grouped = false
|
||||||
|
|
||||||
|
self.CargoGroup:Destroy()
|
||||||
|
|
||||||
|
for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do
|
||||||
|
local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT
|
||||||
|
|
||||||
|
if CargoUnit:IsUnLoaded() then
|
||||||
|
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||||
|
--local GroupName = env.getValueDictByKey( GroupTemplate.name )
|
||||||
|
|
||||||
|
-- We create a new group object with one unit...
|
||||||
|
-- First we prepare the template...
|
||||||
|
GroupTemplate.name = self.CargoName .. "#CARGO#" .. CargoUnitName
|
||||||
|
GroupTemplate.groupId = nil
|
||||||
|
|
||||||
|
if CargoUnit:IsUnLoaded() then
|
||||||
|
GroupTemplate.units = {}
|
||||||
|
GroupTemplate.units[1] = self.CargoUnitTemplate[CargoUnitName]
|
||||||
|
GroupTemplate.units[#GroupTemplate.units].unitId = nil
|
||||||
|
GroupTemplate.units[#GroupTemplate.units].x = CargoUnit:GetX()
|
||||||
|
GroupTemplate.units[#GroupTemplate.units].y = CargoUnit:GetY()
|
||||||
|
GroupTemplate.units[#GroupTemplate.units].heading = CargoUnit:GetHeading()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Then we register the new group in the database
|
||||||
|
local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID)
|
||||||
|
|
||||||
|
-- Now we spawn the new group based on the template created.
|
||||||
|
_DATABASE:Spawn( GroupTemplate )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.CargoObject = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Regroup the cargo group into one group with multiple unit.
|
||||||
|
-- This is required because by default a group will move in formation and this is really an issue for group control.
|
||||||
|
-- Therefore this method is made to be able to regroup a group.
|
||||||
|
-- This works for ground only groups.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
function CARGO_GROUP:Regroup()
|
||||||
|
|
||||||
|
self:F("Regroup")
|
||||||
|
|
||||||
|
if self.Grouped == false then
|
||||||
|
|
||||||
|
self.Grouped = true
|
||||||
|
|
||||||
|
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||||
|
GroupTemplate.name = self.CargoName .. "#CARGO"
|
||||||
|
GroupTemplate.groupId = nil
|
||||||
|
GroupTemplate.units = {}
|
||||||
|
|
||||||
|
for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do
|
||||||
|
local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT
|
||||||
|
|
||||||
|
self:F( { CargoUnit:GetName(), UnLoaded = CargoUnit:IsUnLoaded() } )
|
||||||
|
|
||||||
|
if CargoUnit:IsUnLoaded() then
|
||||||
|
|
||||||
|
CargoUnit.CargoObject:Destroy()
|
||||||
|
|
||||||
|
GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName]
|
||||||
|
GroupTemplate.units[#GroupTemplate.units].unitId = nil
|
||||||
|
GroupTemplate.units[#GroupTemplate.units].x = CargoUnit:GetX()
|
||||||
|
GroupTemplate.units[#GroupTemplate.units].y = CargoUnit:GetY()
|
||||||
|
GroupTemplate.units[#GroupTemplate.units].heading = CargoUnit:GetHeading()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Then we register the new group in the database
|
||||||
|
self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID )
|
||||||
|
|
||||||
|
self:F( { "Regroup", GroupTemplate } )
|
||||||
|
|
||||||
|
-- Now we spawn the new group based on the template created.
|
||||||
|
self.CargoObject = _DATABASE:Spawn( GroupTemplate )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #CARGO_GROUP self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function CARGO_GROUP:OnEventCargoDead( EventData )
|
||||||
|
|
||||||
|
self:E(EventData)
|
||||||
|
|
||||||
|
local Destroyed = false
|
||||||
|
|
||||||
|
if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() or self:IsUnboarding() then
|
||||||
|
Destroyed = true
|
||||||
|
for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do
|
||||||
|
local Cargo = CargoData -- Cargo.Cargo#CARGO
|
||||||
|
if Cargo:IsAlive() then
|
||||||
|
Destroyed = false
|
||||||
|
else
|
||||||
|
Cargo:Destroyed()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local CarrierName = self.CargoCarrier:GetName()
|
||||||
|
if CarrierName == EventData.IniDCSUnitName then
|
||||||
|
MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll()
|
||||||
|
Destroyed = true
|
||||||
|
self.CargoCarrier:ClearCargo()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if Destroyed then
|
||||||
|
self:Destroyed()
|
||||||
|
self:E( { "Cargo group destroyed" } )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Enter Boarding State.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||||
|
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||||
|
function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
|
||||||
|
self:F( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } )
|
||||||
|
|
||||||
|
NearRadius = NearRadius or self.NearRadius
|
||||||
|
|
||||||
|
if From == "UnLoaded" then
|
||||||
|
|
||||||
|
-- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2
|
||||||
|
self.CargoSet:ForEach(
|
||||||
|
function( Cargo, ... )
|
||||||
|
Cargo:__Board( 1, CargoCarrier, NearRadius, ... )
|
||||||
|
end, ...
|
||||||
|
)
|
||||||
|
|
||||||
|
self:__Boarding( 1, CargoCarrier, NearRadius, ... )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Enter Loaded State.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||||
|
function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... )
|
||||||
|
--self:F( { From, Event, To, CargoCarrier, ...} )
|
||||||
|
|
||||||
|
if From == "UnLoaded" then
|
||||||
|
-- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier.
|
||||||
|
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||||
|
Cargo:Load( CargoCarrier )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--self.CargoObject:Destroy()
|
||||||
|
self.CargoCarrier = CargoCarrier
|
||||||
|
self.CargoCarrier:AddCargo( self )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Leave Boarding State.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
local Boarded = true
|
||||||
|
local Cancelled = false
|
||||||
|
local Dead = true
|
||||||
|
|
||||||
|
self.CargoSet:Flush()
|
||||||
|
|
||||||
|
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
|
||||||
|
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||||
|
--self:T( { Cargo:GetName(), Cargo.current } )
|
||||||
|
|
||||||
|
|
||||||
|
if not Cargo:is( "Loaded" )
|
||||||
|
and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function.
|
||||||
|
Boarded = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if Cargo:is( "UnLoaded" ) then
|
||||||
|
Cancelled = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if not Cargo:is( "Destroyed" ) then
|
||||||
|
Dead = false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if not Dead then
|
||||||
|
|
||||||
|
if not Cancelled then
|
||||||
|
if not Boarded then
|
||||||
|
self:__Boarding( -5, CargoCarrier, NearRadius, ... )
|
||||||
|
else
|
||||||
|
self:F("Group Cargo is loaded")
|
||||||
|
self:__Load( 1, CargoCarrier, ... )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:__CancelBoarding( 1, CargoCarrier, NearRadius, ... )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:__Destroyed( 1, CargoCarrier, NearRadius, ... )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Enter UnBoarding State.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||||
|
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||||
|
function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
|
||||||
|
self:F( {From, Event, To, ToPointVec2, NearRadius } )
|
||||||
|
|
||||||
|
NearRadius = NearRadius or 25
|
||||||
|
|
||||||
|
local Timer = 1
|
||||||
|
|
||||||
|
if From == "Loaded" then
|
||||||
|
|
||||||
|
if self.CargoObject then
|
||||||
|
self.CargoObject:Destroy()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
|
||||||
|
self.CargoSet:ForEach(
|
||||||
|
--- @param Cargo.Cargo#CARGO Cargo
|
||||||
|
function( Cargo, NearRadius )
|
||||||
|
if not Cargo:IsDestroyed() then
|
||||||
|
local ToVec=nil
|
||||||
|
if ToPointVec2==nil then
|
||||||
|
ToVec=self.CargoCarrier:GetPointVec2():GetRandomPointVec2InRadius(2*NearRadius, NearRadius)
|
||||||
|
else
|
||||||
|
ToVec=ToPointVec2
|
||||||
|
end
|
||||||
|
Cargo:__UnBoard( Timer, ToVec, NearRadius )
|
||||||
|
Timer = Timer + 1
|
||||||
|
end
|
||||||
|
end, { NearRadius }
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Leave UnBoarding State.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||||
|
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||||
|
function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
|
||||||
|
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
|
||||||
|
|
||||||
|
--local NearRadius = NearRadius or 25
|
||||||
|
|
||||||
|
local Angle = 180
|
||||||
|
local Speed = 10
|
||||||
|
local Distance = 5
|
||||||
|
|
||||||
|
if From == "UnBoarding" then
|
||||||
|
local UnBoarded = true
|
||||||
|
|
||||||
|
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
|
||||||
|
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||||
|
self:T( { Cargo:GetName(), Cargo.current } )
|
||||||
|
if not Cargo:is( "UnLoaded" ) and not Cargo:IsDestroyed() then
|
||||||
|
UnBoarded = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if UnBoarded then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- UnBoard Event.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#POINT_VEC2 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 } )
|
||||||
|
|
||||||
|
--local NearRadius = NearRadius or 25
|
||||||
|
|
||||||
|
self:__UnLoad( 1, ToPointVec2, ... )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Enter UnLoaded State.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#POINT_VEC2
|
||||||
|
function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... )
|
||||||
|
--self:F( { From, Event, To, ToPointVec2 } )
|
||||||
|
|
||||||
|
if From == "Loaded" then
|
||||||
|
|
||||||
|
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
|
||||||
|
self.CargoSet:ForEach(
|
||||||
|
function( Cargo )
|
||||||
|
--Cargo:UnLoad( ToPointVec2 )
|
||||||
|
local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10)
|
||||||
|
Cargo:UnLoad( RandomVec2 )
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self.CargoCarrier:RemoveCargo( self )
|
||||||
|
self.CargoCarrier = nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the current Coordinate of the CargoGroup.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @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_GROUP:GetCoordinate()
|
||||||
|
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||||
|
|
||||||
|
if Cargo then
|
||||||
|
return Cargo.CargoObject:GetCoordinate()
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the x position of the cargo.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @return #number
|
||||||
|
function CARGO:GetX()
|
||||||
|
|
||||||
|
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||||
|
|
||||||
|
if Cargo then
|
||||||
|
return Cargo:GetCoordinate().x
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the y position of the cargo.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @return #number
|
||||||
|
function CARGO:GetY()
|
||||||
|
|
||||||
|
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||||
|
|
||||||
|
if Cargo then
|
||||||
|
return Cargo:GetCoordinate().z
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if the CargoGroup is alive.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @return #boolean true if the CargoGroup is alive.
|
||||||
|
-- @return #boolean false if the CargoGroup is dead.
|
||||||
|
function CARGO_GROUP:IsAlive()
|
||||||
|
|
||||||
|
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||||
|
return Cargo ~= nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the first alive Cargo Unit of the Cargo Group.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @return #CARGO_GROUP
|
||||||
|
function CARGO_GROUP:GetFirstAlive()
|
||||||
|
|
||||||
|
local CargoFirstAlive = nil
|
||||||
|
|
||||||
|
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||||
|
if not Cargo:IsDestroyed() then
|
||||||
|
CargoFirstAlive = Cargo
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return CargoFirstAlive
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the amount of cargo units in the group.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @return #CARGO_GROUP
|
||||||
|
function CARGO_GROUP:GetCount()
|
||||||
|
return self.CargoSet:Count()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the amount of cargo units in the group.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @return #CARGO_GROUP
|
||||||
|
function CARGO_GROUP:GetGroup( Cargo )
|
||||||
|
local Cargo = Cargo or self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||||
|
return Cargo.CargoObject:GetGroup()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Route Cargo to Coordinate and randomize locations.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
function CARGO_GROUP:RouteTo( Coordinate )
|
||||||
|
--self:F( {Coordinate = Coordinate } )
|
||||||
|
|
||||||
|
-- For each Cargo within the CargoSet, route each object to the Coordinate
|
||||||
|
self.CargoSet:ForEach(
|
||||||
|
function( Cargo )
|
||||||
|
Cargo.CargoObject:RouteGroundTo( Coordinate, 10, "vee", 0 )
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if Cargo is near to the Carrier.
|
||||||
|
-- The Cargo is near to the Carrier if the first unit of the Cargo Group is within NearRadius.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param Wrapper.Group#GROUP CargoCarrier
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
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" )
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if Cargo Group is in the radius for the Cargo to be Boarded.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||||
|
|
||||||
|
if Cargo then
|
||||||
|
local Distance = 0
|
||||||
|
local CargoCoordinate
|
||||||
|
if Cargo:IsLoaded() then
|
||||||
|
CargoCoordinate = Cargo.CargoCarrier:GetCoordinate()
|
||||||
|
else
|
||||||
|
CargoCoordinate = Cargo.CargoObject:GetCoordinate()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- FF check if coordinate could be obtained. This was commented out for some (unknown) reason. But the check seems valid!
|
||||||
|
if CargoCoordinate then
|
||||||
|
Distance = Coordinate:Get2DDistance( CargoCoordinate )
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
self:F( { Distance = Distance, LoadRadius = self.LoadRadius } )
|
||||||
|
if Distance <= self.LoadRadius then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if Cargo Group is in the report radius.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||||
|
|
||||||
|
if Cargo then
|
||||||
|
self:F( { Cargo } )
|
||||||
|
local Distance = 0
|
||||||
|
if Cargo:IsUnLoaded() then
|
||||||
|
Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() )
|
||||||
|
--self:T( Distance )
|
||||||
|
if Distance <= self.LoadRadius then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Signal a flare at the position of the CargoGroup.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param Utilities.Utils#FLARECOLOR FlareColor
|
||||||
|
function CARGO_GROUP:Flare( FlareColor )
|
||||||
|
|
||||||
|
local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO
|
||||||
|
if Cargo then
|
||||||
|
Cargo:Flare( FlareColor )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Smoke the CargoGroup.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke.
|
||||||
|
-- @param #number Radius The radius of randomization around the center of the first element of the CargoGroup.
|
||||||
|
function CARGO_GROUP:Smoke( SmokeColor, Radius )
|
||||||
|
|
||||||
|
local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO
|
||||||
|
|
||||||
|
if Cargo then
|
||||||
|
Cargo:Smoke( SmokeColor, Radius )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the first element of the CargoGroup is the given @{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 } )
|
||||||
|
|
||||||
|
local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO
|
||||||
|
|
||||||
|
if Cargo then
|
||||||
|
return Cargo:IsInZone( Zone )
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the transportation method of the Cargo.
|
||||||
|
-- @param #CARGO_GROUP self
|
||||||
|
-- @return #string The transportation method of the Cargo.
|
||||||
|
function CARGO_GROUP:GetTransportationMethod()
|
||||||
|
if self:IsLoaded() then
|
||||||
|
return "for unboarding"
|
||||||
|
else
|
||||||
|
if self:IsUnLoaded() then
|
||||||
|
return "for boarding"
|
||||||
|
else
|
||||||
|
if self:IsDeployed() then
|
||||||
|
return "delivered"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end -- CARGO_GROUP
|
||||||
270
Moose Development/Moose/Cargo/CargoSlingload.lua
Normal file
270
Moose Development/Moose/Cargo/CargoSlingload.lua
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. The cargo can only be slingloaded.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### [Demo Missions]()
|
||||||
|
--
|
||||||
|
-- ### [YouTube Playlist]()
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
-- ### Contributions:
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Cargo.CargoSlingload
|
||||||
|
-- @image Cargo_Slingload.JPG
|
||||||
|
|
||||||
|
|
||||||
|
do -- CARGO_SLINGLOAD
|
||||||
|
|
||||||
|
--- Models the behaviour of cargo crates, which can only be slingloaded.
|
||||||
|
-- @type CARGO_SLINGLOAD
|
||||||
|
-- @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.
|
||||||
|
--
|
||||||
|
-- The above cargo classes are also used by the TASK_CARGO_ classes to allow human players to transport cargo as part of a tasking:
|
||||||
|
--
|
||||||
|
-- * @{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.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @field #CARGO_SLINGLOAD
|
||||||
|
CARGO_SLINGLOAD = {
|
||||||
|
ClassName = "CARGO_SLINGLOAD"
|
||||||
|
}
|
||||||
|
|
||||||
|
--- CARGO_SLINGLOAD Constructor.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
-- @param Wrapper.Static#STATIC CargoStatic
|
||||||
|
-- @param #string Type
|
||||||
|
-- @param #string Name
|
||||||
|
-- @param #number LoadRadius (optional)
|
||||||
|
-- @param #number NearRadius (optional)
|
||||||
|
-- @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.CargoObject = CargoStatic
|
||||||
|
|
||||||
|
-- Cargo objects are added to the _DATABASE and SET_CARGO objects.
|
||||||
|
_EVENTDISPATCHER:CreateEventNewCargo( self )
|
||||||
|
|
||||||
|
self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead )
|
||||||
|
self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead )
|
||||||
|
--self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCargoDead )
|
||||||
|
self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead )
|
||||||
|
|
||||||
|
self:SetEventPriority( 4 )
|
||||||
|
|
||||||
|
self.NearRadius = NearRadius or 25
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #CARGO_SLINGLOAD self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function CARGO_SLINGLOAD:OnEventCargoDead( EventData )
|
||||||
|
|
||||||
|
local Destroyed = false
|
||||||
|
|
||||||
|
if self:IsDestroyed() or self:IsUnLoaded() then
|
||||||
|
if self.CargoObject:GetName() == EventData.IniUnitName then
|
||||||
|
if not self.NoDestroy then
|
||||||
|
Destroyed = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if Destroyed then
|
||||||
|
self:I( { "Cargo crate destroyed: " .. self.CargoObject:GetName() } )
|
||||||
|
self:Destroyed()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if the cargo can be Slingloaded.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
function CARGO_SLINGLOAD:CanSlingload()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the cargo can be Boarded.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
function CARGO_SLINGLOAD:CanBoard()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the cargo can be Unboarded.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
function CARGO_SLINGLOAD:CanUnboard()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the cargo can be Loaded.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
function CARGO_SLINGLOAD:CanLoad()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the cargo can be Unloaded.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
function CARGO_SLINGLOAD:CanUnload()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if Cargo Crate is in the radius for the Cargo to be reported.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
local Distance = 0
|
||||||
|
if self:IsUnLoaded() then
|
||||||
|
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||||
|
if Distance <= self.LoadRadius then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if Cargo Slingload is in the radius for the Cargo to be Boarded or Loaded.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
local Distance = 0
|
||||||
|
if self:IsUnLoaded() then
|
||||||
|
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||||
|
if Distance <= self.NearRadius then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the current Coordinate of the CargoGroup.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
-- @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()
|
||||||
|
|
||||||
|
return self.CargoObject:GetCoordinate()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the CargoGroup is alive.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
-- @return #boolean true if the CargoGroup is alive.
|
||||||
|
-- @return #boolean false if the CargoGroup is dead.
|
||||||
|
function CARGO_SLINGLOAD:IsAlive()
|
||||||
|
|
||||||
|
local Alive = true
|
||||||
|
|
||||||
|
-- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive.
|
||||||
|
-- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive.
|
||||||
|
if self:IsLoaded() then
|
||||||
|
Alive = Alive == true and self.CargoCarrier:IsAlive()
|
||||||
|
else
|
||||||
|
Alive = Alive == true and self.CargoObject:IsAlive()
|
||||||
|
end
|
||||||
|
|
||||||
|
return Alive
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Route Cargo to Coordinate and randomize locations.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
function CARGO_SLINGLOAD:RouteTo( Coordinate )
|
||||||
|
--self:F( {Coordinate = Coordinate } )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if Cargo is near to the Carrier.
|
||||||
|
-- The Cargo is near to the Carrier within NearRadius.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
-- @param Wrapper.Group#GROUP CargoCarrier
|
||||||
|
-- @param #number NearRadius
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Respawn the CargoGroup.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
function CARGO_SLINGLOAD:Respawn()
|
||||||
|
|
||||||
|
--self:F( { "Respawning slingload " .. self:GetName() } )
|
||||||
|
|
||||||
|
|
||||||
|
-- Respawn the group...
|
||||||
|
if self.CargoObject then
|
||||||
|
self.CargoObject:ReSpawn() -- A cargo destroy crates a DEAD event.
|
||||||
|
self:__Reset( -0.1 )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Respawn the CargoGroup.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
function CARGO_SLINGLOAD:onafterReset()
|
||||||
|
|
||||||
|
--self:F( { "Reset slingload " .. self:GetName() } )
|
||||||
|
|
||||||
|
|
||||||
|
-- Respawn the group...
|
||||||
|
if self.CargoObject then
|
||||||
|
self:SetDeployed( false )
|
||||||
|
self:SetStartState( "UnLoaded" )
|
||||||
|
self.CargoCarrier = nil
|
||||||
|
-- Cargo objects are added to the _DATABASE and SET_CARGO objects.
|
||||||
|
_EVENTDISPATCHER:CreateEventNewCargo( self )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the transportation method of the Cargo.
|
||||||
|
-- @param #CARGO_SLINGLOAD self
|
||||||
|
-- @return #string The transportation method of the Cargo.
|
||||||
|
function CARGO_SLINGLOAD:GetTransportationMethod()
|
||||||
|
if self:IsLoaded() then
|
||||||
|
return "for sling loading"
|
||||||
|
else
|
||||||
|
if self:IsUnLoaded() then
|
||||||
|
return "for sling loading"
|
||||||
|
else
|
||||||
|
if self:IsDeployed() then
|
||||||
|
return "delivered"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
397
Moose Development/Moose/Cargo/CargoUnit.lua
Normal file
397
Moose Development/Moose/Cargo/CargoUnit.lua
Normal file
@@ -0,0 +1,397 @@
|
|||||||
|
--- **Cargo** -- Management of single cargo logistics, which are based on a @{Wrapper.Unit} object.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### [Demo Missions]()
|
||||||
|
--
|
||||||
|
-- ### [YouTube Playlist]()
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
-- ### Contributions:
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Cargo.CargoUnit
|
||||||
|
-- @image Cargo_Units.JPG
|
||||||
|
|
||||||
|
do -- CARGO_UNIT
|
||||||
|
|
||||||
|
--- Models CARGO in the form of units, which can be boarded, unboarded, loaded, unloaded.
|
||||||
|
-- @type CARGO_UNIT
|
||||||
|
-- @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_UNIT objects to and from carriers.
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @field #CARGO_UNIT CARGO_UNIT
|
||||||
|
--
|
||||||
|
CARGO_UNIT = {
|
||||||
|
ClassName = "CARGO_UNIT"
|
||||||
|
}
|
||||||
|
|
||||||
|
--- CARGO_UNIT Constructor.
|
||||||
|
-- @param #CARGO_UNIT self
|
||||||
|
-- @param Wrapper.Unit#UNIT CargoUnit
|
||||||
|
-- @param #string Type
|
||||||
|
-- @param #string Name
|
||||||
|
-- @param #number Weight
|
||||||
|
-- @param #number LoadRadius (optional)
|
||||||
|
-- @param #number NearRadius (optional)
|
||||||
|
-- @return #CARGO_UNIT
|
||||||
|
function CARGO_UNIT:New( CargoUnit, Type, Name, LoadRadius, NearRadius )
|
||||||
|
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, LoadRadius, NearRadius ) ) -- #CARGO_UNIT
|
||||||
|
self:I( { Type, Name, LoadRadius, NearRadius } )
|
||||||
|
|
||||||
|
self:T( CargoUnit )
|
||||||
|
self.CargoObject = CargoUnit
|
||||||
|
|
||||||
|
self:T( self.ClassName )
|
||||||
|
|
||||||
|
self:SetEventPriority( 5 )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Enter UnBoarding State.
|
||||||
|
-- @param #CARGO_UNIT self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||||
|
-- @param #number NearRadius (optional) Defaut 25 m.
|
||||||
|
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||||
|
self:F( { From, Event, To, ToPointVec2, NearRadius } )
|
||||||
|
|
||||||
|
local Angle = 180
|
||||||
|
local Speed = 60
|
||||||
|
local DeployDistance = 9
|
||||||
|
local RouteDistance = 60
|
||||||
|
|
||||||
|
if From == "Loaded" then
|
||||||
|
|
||||||
|
if not self:IsDestroyed() then
|
||||||
|
|
||||||
|
local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE
|
||||||
|
|
||||||
|
if CargoCarrier:IsAlive() then
|
||||||
|
|
||||||
|
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
|
||||||
|
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
||||||
|
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
||||||
|
|
||||||
|
|
||||||
|
local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading )
|
||||||
|
|
||||||
|
|
||||||
|
-- if there is no ToPointVec2 given, then use the CargoRoutePointVec2
|
||||||
|
local FromDirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3( ToPointVec2 or CargoRoutePointVec2 )
|
||||||
|
local FromAngle = CargoCarrierPointVec2:GetAngleDegrees(FromDirectionVec3)
|
||||||
|
local FromPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, FromAngle )
|
||||||
|
--local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( 10, 5 )
|
||||||
|
|
||||||
|
ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, DeployDistance )
|
||||||
|
|
||||||
|
-- Respawn the group...
|
||||||
|
if self.CargoObject then
|
||||||
|
self.CargoObject:ReSpawnAt( FromPointVec2, CargoDeployHeading )
|
||||||
|
self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } )
|
||||||
|
self.CargoCarrier = nil
|
||||||
|
|
||||||
|
local Points = {}
|
||||||
|
|
||||||
|
-- From
|
||||||
|
Points[#Points+1] = FromPointVec2:WaypointGround( Speed, "Vee" )
|
||||||
|
|
||||||
|
-- To
|
||||||
|
Points[#Points+1] = ToPointVec2:WaypointGround( Speed, "Vee" )
|
||||||
|
|
||||||
|
local TaskRoute = self.CargoObject:TaskRoute( Points )
|
||||||
|
self.CargoObject:SetTask( TaskRoute, 1 )
|
||||||
|
|
||||||
|
|
||||||
|
self:__UnBoarding( 1, ToPointVec2, NearRadius )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- the Carrier is dead. This cargo is dead too!
|
||||||
|
self:Destroyed()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Leave UnBoarding State.
|
||||||
|
-- @param #CARGO_UNIT self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||||
|
-- @param #number NearRadius (optional) Defaut 100 m.
|
||||||
|
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
|
||||||
|
self:F( { From, Event, To, ToPointVec2, NearRadius } )
|
||||||
|
|
||||||
|
local Angle = 180
|
||||||
|
local Speed = 10
|
||||||
|
local Distance = 5
|
||||||
|
|
||||||
|
if From == "UnBoarding" then
|
||||||
|
--if self:IsNear( ToPointVec2, NearRadius ) then
|
||||||
|
return true
|
||||||
|
--else
|
||||||
|
|
||||||
|
--self:__UnBoarding( 1, ToPointVec2, NearRadius )
|
||||||
|
--end
|
||||||
|
--return false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- UnBoard Event.
|
||||||
|
-- @param #CARGO_UNIT self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#POINT_VEC2 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.CargoInAir = self.CargoObject:InAir()
|
||||||
|
|
||||||
|
self:T( self.CargoInAir )
|
||||||
|
|
||||||
|
-- Only unboard the cargo when the carrier is not in the air.
|
||||||
|
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
|
||||||
|
if not self.CargoInAir then
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self:__UnLoad( 1, ToPointVec2, NearRadius )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Enter UnLoaded State.
|
||||||
|
-- @param #CARGO_UNIT self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Core.Point#POINT_VEC2
|
||||||
|
function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
|
||||||
|
self:F( { ToPointVec2, From, Event, To } )
|
||||||
|
|
||||||
|
local Angle = 180
|
||||||
|
local Speed = 10
|
||||||
|
local Distance = 5
|
||||||
|
|
||||||
|
if From == "Loaded" then
|
||||||
|
local StartPointVec2 = self.CargoCarrier:GetPointVec2()
|
||||||
|
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
||||||
|
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
||||||
|
local CargoDeployCoord = StartPointVec2:Translate( Distance, CargoDeployHeading )
|
||||||
|
|
||||||
|
ToPointVec2 = ToPointVec2 or COORDINATE:New( CargoDeployCoord.x, CargoDeployCoord.z )
|
||||||
|
|
||||||
|
-- Respawn the group...
|
||||||
|
if self.CargoObject then
|
||||||
|
self.CargoObject:ReSpawnAt( ToPointVec2, 0 )
|
||||||
|
self.CargoCarrier = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.OnUnLoadedCallBack then
|
||||||
|
self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) )
|
||||||
|
self.OnUnLoadedCallBack = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Board Event.
|
||||||
|
-- @param #CARGO_UNIT self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @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.CargoInAir = self.CargoObject:InAir()
|
||||||
|
|
||||||
|
local Desc = self.CargoObject:GetDesc()
|
||||||
|
local MaxSpeed = Desc.speedMaxOffRoad
|
||||||
|
local TypeName = Desc.typeName
|
||||||
|
|
||||||
|
self:T( self.CargoInAir )
|
||||||
|
|
||||||
|
-- Only move the group to the carrier when the cargo is not in the air
|
||||||
|
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
|
||||||
|
if not self.CargoInAir then
|
||||||
|
-- If NearRadius is given, then use the given NearRadius, otherwise calculate the NearRadius
|
||||||
|
-- based upon the Carrier bounding radius, which is calculated from the bounding rectangle on the Y axis.
|
||||||
|
local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius() + 5
|
||||||
|
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
|
||||||
|
self:Load( CargoCarrier, NearRadius, ... )
|
||||||
|
else
|
||||||
|
if MaxSpeed and MaxSpeed == 0 or TypeName and TypeName == "Stinger comm" then
|
||||||
|
self:Load( CargoCarrier, NearRadius, ... )
|
||||||
|
else
|
||||||
|
|
||||||
|
local Speed = 90
|
||||||
|
local Angle = 180
|
||||||
|
local Distance = 5
|
||||||
|
|
||||||
|
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
|
||||||
|
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
||||||
|
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
||||||
|
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
|
||||||
|
|
||||||
|
-- Set the CargoObject to state Green to ensure it is boarding!
|
||||||
|
self.CargoObject:OptionAlarmStateGreen()
|
||||||
|
|
||||||
|
local Points = {}
|
||||||
|
|
||||||
|
local PointStartVec2 = self.CargoObject:GetPointVec2()
|
||||||
|
|
||||||
|
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
|
||||||
|
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
|
||||||
|
|
||||||
|
local TaskRoute = self.CargoObject:TaskRoute( Points )
|
||||||
|
self.CargoObject:SetTask( TaskRoute, 2 )
|
||||||
|
self:__Boarding( -5, CargoCarrier, NearRadius, ... )
|
||||||
|
self.RunCount = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Boarding Event.
|
||||||
|
-- @param #CARGO_UNIT self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @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 } )
|
||||||
|
|
||||||
|
|
||||||
|
if CargoCarrier and CargoCarrier:IsAlive() and self.CargoObject and self.CargoObject:IsAlive() then
|
||||||
|
if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then
|
||||||
|
local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius( NearRadius ) + 5
|
||||||
|
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
|
||||||
|
self:__Load( 1, CargoCarrier, ... )
|
||||||
|
else
|
||||||
|
if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then
|
||||||
|
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
|
||||||
|
self.RunCount = self.RunCount + 1
|
||||||
|
else
|
||||||
|
self:__Boarding( -5, CargoCarrier, NearRadius, ... )
|
||||||
|
self.RunCount = self.RunCount + 5
|
||||||
|
end
|
||||||
|
if self.RunCount >= 40 then
|
||||||
|
self.RunCount = 0
|
||||||
|
local Speed = 90
|
||||||
|
local Angle = 180
|
||||||
|
local Distance = 5
|
||||||
|
|
||||||
|
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
|
||||||
|
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
||||||
|
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
||||||
|
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
|
||||||
|
|
||||||
|
-- Set the CargoObject to state Green to ensure it is boarding!
|
||||||
|
self.CargoObject:OptionAlarmStateGreen()
|
||||||
|
|
||||||
|
local Points = {}
|
||||||
|
|
||||||
|
local PointStartVec2 = self.CargoObject:GetPointVec2()
|
||||||
|
|
||||||
|
Points[#Points+1] = PointStartVec2:WaypointGround( Speed, "Off road" )
|
||||||
|
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed, "Off road" )
|
||||||
|
|
||||||
|
local TaskRoute = self.CargoObject:TaskRoute( Points )
|
||||||
|
self.CargoObject:SetTask( TaskRoute, 0.2 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() )
|
||||||
|
self:CancelBoarding( CargoCarrier, NearRadius, ... )
|
||||||
|
self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:E("Something is wrong")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Enter Boarding State.
|
||||||
|
-- @param #CARGO_UNIT self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||||
|
-- @param #number NearRadius Default 25 m.
|
||||||
|
function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
|
||||||
|
--self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
|
||||||
|
|
||||||
|
local Speed = 90
|
||||||
|
local Angle = 180
|
||||||
|
local Distance = 5
|
||||||
|
|
||||||
|
if From == "UnLoaded" or From == "Boarding" then
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Loaded State.
|
||||||
|
-- @param #CARGO_UNIT self
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||||
|
function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier )
|
||||||
|
self:F( { From, Event, To, CargoCarrier } )
|
||||||
|
|
||||||
|
self.CargoCarrier = CargoCarrier
|
||||||
|
|
||||||
|
-- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects).
|
||||||
|
if self.CargoObject then
|
||||||
|
self:T("Destroying")
|
||||||
|
self.CargoObject:Destroy()
|
||||||
|
--self.CargoObject:ReSpawnAt( COORDINATE:NewFromVec2( {x=0,y=0} ), 0 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the transportation method of the Cargo.
|
||||||
|
-- @param #CARGO_UNIT self
|
||||||
|
-- @return #string The transportation method of the Cargo.
|
||||||
|
function CARGO_UNIT:GetTransportationMethod()
|
||||||
|
if self:IsLoaded() then
|
||||||
|
return "for unboarding"
|
||||||
|
else
|
||||||
|
if self:IsUnLoaded() then
|
||||||
|
return "for boarding"
|
||||||
|
else
|
||||||
|
if self:IsDeployed() then
|
||||||
|
return "delivered"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
end -- CARGO_UNIT
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
--- **Core** -- BASE forms **the basis of the MOOSE framework**. Each class within the MOOSE framework derives from BASE.
|
--- **Core** -- BASE forms **the basis of the MOOSE framework**. Each class within the MOOSE framework derives from BASE.
|
||||||
--
|
--
|
||||||
-- 
|
-- ### Author: **FlightControl**
|
||||||
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- @module Core.Base
|
||||||
-- ### Contributions:
|
-- @image Core_Base.JPG
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- @module Base
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -26,9 +23,7 @@ local _ClassID = 0
|
|||||||
-- @field ClassID The ID number 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.
|
-- @field ClassNameAndID The name of the class concatenated with the ID number of the class.
|
||||||
|
|
||||||
--- # 1) #BASE class
|
--- All classes within the MOOSE framework are derived from the BASE class.
|
||||||
--
|
|
||||||
-- All classes within the MOOSE framework are derived from the BASE class.
|
|
||||||
--
|
--
|
||||||
-- BASE provides facilities for :
|
-- BASE provides facilities for :
|
||||||
--
|
--
|
||||||
@@ -42,8 +37,8 @@ local _ClassID = 0
|
|||||||
--
|
--
|
||||||
-- ## 1.1) BASE constructor
|
-- ## 1.1) BASE constructor
|
||||||
--
|
--
|
||||||
-- Any class derived from BASE, will use the @{Base#BASE.New} constructor embedded in the @{Base#BASE.Inherit} method.
|
-- Any class derived from BASE, will use the @{Core.Base#BASE.New} constructor embedded in the @{Core.Base#BASE.Inherit} method.
|
||||||
-- See an example at the @{Base#BASE.New} method how this is done.
|
-- See an example at the @{Core.Base#BASE.New} method how this is done.
|
||||||
--
|
--
|
||||||
-- ## 1.2) Trace information for debugging
|
-- ## 1.2) Trace information for debugging
|
||||||
--
|
--
|
||||||
@@ -127,7 +122,7 @@ local _ClassID = 0
|
|||||||
-- ### 1.3.2 Event Handling of DCS Events
|
-- ### 1.3.2 Event Handling of DCS Events
|
||||||
--
|
--
|
||||||
-- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called
|
-- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called
|
||||||
-- when the DCS event occurs. The Event Handling method receives an @{Event#EVENTDATA} structure, which contains a lot of information
|
-- when the DCS event occurs. The Event Handling method receives an @{Core.Event#EVENTDATA} structure, which contains a lot of information
|
||||||
-- about the event that occurred.
|
-- about the event that occurred.
|
||||||
--
|
--
|
||||||
-- Find below an example of the prototype how to write an event handling function for two units:
|
-- Find below an example of the prototype how to write an event handling function for two units:
|
||||||
@@ -198,6 +193,8 @@ BASE = {
|
|||||||
ClassID = 0,
|
ClassID = 0,
|
||||||
Events = {},
|
Events = {},
|
||||||
States = {},
|
States = {},
|
||||||
|
Debug = debug,
|
||||||
|
Scheduler = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -269,6 +266,23 @@ function BASE:Inherit( Child, Parent )
|
|||||||
return Child
|
return Child
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function getParent( Child )
|
||||||
|
local Parent = nil
|
||||||
|
|
||||||
|
if Child.ClassName == 'BASE' then
|
||||||
|
Parent = nil
|
||||||
|
else
|
||||||
|
if rawget( Child, "__" ) then
|
||||||
|
Parent = getmetatable( Child.__ ).__index
|
||||||
|
else
|
||||||
|
Parent = getmetatable( Child ).__index
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return Parent
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- This is the worker method to retrieve the Parent class.
|
--- This is the worker method to retrieve the Parent class.
|
||||||
-- Note that the Parent class must be passed to call the parent class method.
|
-- Note that the Parent class must be passed to call the parent class method.
|
||||||
--
|
--
|
||||||
@@ -278,17 +292,31 @@ end
|
|||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #BASE Child is the Child class from which the Parent class needs to be retrieved.
|
-- @param #BASE Child is the Child class from which the Parent class needs to be retrieved.
|
||||||
-- @return #BASE
|
-- @return #BASE
|
||||||
function BASE:GetParent( Child )
|
function BASE:GetParent( Child, FromClass )
|
||||||
|
|
||||||
|
|
||||||
local Parent
|
local Parent
|
||||||
-- BASE class has no parent
|
-- BASE class has no parent
|
||||||
if Child.ClassName == 'BASE' then
|
if Child.ClassName == 'BASE' then
|
||||||
Parent = nil
|
Parent = nil
|
||||||
elseif rawget( Child, "__" ) then
|
else
|
||||||
Parent = getmetatable( Child.__ ).__index
|
|
||||||
else
|
--self:E({FromClass = FromClass})
|
||||||
Parent = getmetatable( Child ).__index
|
--self:E({Child = Child.ClassName})
|
||||||
end
|
if FromClass then
|
||||||
return Parent
|
while( Child.ClassName ~= "BASE" and Child.ClassName ~= FromClass.ClassName ) do
|
||||||
|
Child = getParent( Child )
|
||||||
|
--self:E({Child.ClassName})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if Child.ClassName == 'BASE' then
|
||||||
|
Parent = nil
|
||||||
|
else
|
||||||
|
Parent = getParent( Child )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--self:E({Parent.ClassName})
|
||||||
|
return Parent
|
||||||
end
|
end
|
||||||
|
|
||||||
--- This is the worker method to check if an object is an (sub)instance of a class.
|
--- This is the worker method to check if an object is an (sub)instance of a class.
|
||||||
@@ -334,7 +362,7 @@ function BASE:IsInstanceOf( ClassName )
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local Parent = self:GetParent(self)
|
local Parent = getParent(self)
|
||||||
|
|
||||||
while Parent do
|
while Parent do
|
||||||
|
|
||||||
@@ -342,7 +370,7 @@ function BASE:IsInstanceOf( ClassName )
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
Parent = Parent:GetParent(Parent)
|
Parent = getParent( Parent )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -576,8 +604,8 @@ end
|
|||||||
|
|
||||||
--- Creation of a Birth Event.
|
--- Creation of a Birth Event.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event.
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event.
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
-- @param #string IniUnitName The initiating unit name.
|
-- @param #string IniUnitName The initiating unit name.
|
||||||
-- @param place
|
-- @param place
|
||||||
-- @param subplace
|
-- @param subplace
|
||||||
@@ -598,8 +626,8 @@ end
|
|||||||
|
|
||||||
--- Creation of a Crash Event.
|
--- Creation of a Crash Event.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event.
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event.
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
function BASE:CreateEventCrash( EventTime, Initiator )
|
function BASE:CreateEventCrash( EventTime, Initiator )
|
||||||
self:F( { EventTime, Initiator } )
|
self:F( { EventTime, Initiator } )
|
||||||
|
|
||||||
@@ -612,10 +640,42 @@ function BASE:CreateEventCrash( EventTime, Initiator )
|
|||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Creation of a Dead Event.
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
|
function BASE:CreateEventDead( EventTime, Initiator )
|
||||||
|
self:F( { EventTime, Initiator } )
|
||||||
|
|
||||||
|
local Event = {
|
||||||
|
id = world.event.S_EVENT_DEAD,
|
||||||
|
time = EventTime,
|
||||||
|
initiator = Initiator,
|
||||||
|
}
|
||||||
|
|
||||||
|
world.onEvent( Event )
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Creation of a Remove Unit Event.
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
|
function BASE:CreateEventRemoveUnit( EventTime, Initiator )
|
||||||
|
self:F( { EventTime, Initiator } )
|
||||||
|
|
||||||
|
local Event = {
|
||||||
|
id = EVENTS.RemoveUnit,
|
||||||
|
time = EventTime,
|
||||||
|
initiator = Initiator,
|
||||||
|
}
|
||||||
|
|
||||||
|
world.onEvent( Event )
|
||||||
|
end
|
||||||
|
|
||||||
--- Creation of a Takeoff Event.
|
--- Creation of a Takeoff Event.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event.
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event.
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
function BASE:CreateEventTakeoff( EventTime, Initiator )
|
function BASE:CreateEventTakeoff( EventTime, Initiator )
|
||||||
self:F( { EventTime, Initiator } )
|
self:F( { EventTime, Initiator } )
|
||||||
|
|
||||||
@@ -628,10 +688,10 @@ function BASE:CreateEventTakeoff( EventTime, Initiator )
|
|||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO: Complete Dcs.DCSTypes#Event structure.
|
-- TODO: Complete DCS#Event structure.
|
||||||
--- The main event handling function... This function captures all events generated for the class.
|
--- The main event handling function... This function captures all events generated for the class.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Dcs.DCSTypes#Event event
|
-- @param DCS#Event event
|
||||||
function BASE:onEvent(event)
|
function BASE:onEvent(event)
|
||||||
--self:F( { BaseEventCodes[event.id], event } )
|
--self:F( { BaseEventCodes[event.id], event } )
|
||||||
|
|
||||||
@@ -674,7 +734,12 @@ do -- Scheduling
|
|||||||
ObjectName = self.ClassName .. self.ClassID
|
ObjectName = self.ClassName .. self.ClassID
|
||||||
|
|
||||||
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
|
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
|
||||||
self.SchedulerObject = self
|
|
||||||
|
if not self.Scheduler then
|
||||||
|
self.Scheduler = SCHEDULER:New( self )
|
||||||
|
end
|
||||||
|
|
||||||
|
self.Scheduler.SchedulerObject = self.Scheduler
|
||||||
|
|
||||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
||||||
self,
|
self,
|
||||||
@@ -686,9 +751,9 @@ do -- Scheduling
|
|||||||
nil
|
nil
|
||||||
)
|
)
|
||||||
|
|
||||||
self._.Schedules[#self.Schedules+1] = ScheduleID
|
self._.Schedules[#self._.Schedules+1] = ScheduleID
|
||||||
|
|
||||||
return self._.Schedules
|
return self._.Schedules[#self._.Schedules]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also.
|
--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also.
|
||||||
@@ -708,7 +773,12 @@ do -- Scheduling
|
|||||||
ObjectName = self.ClassName .. self.ClassID
|
ObjectName = self.ClassName .. self.ClassID
|
||||||
|
|
||||||
self:F3( { "ScheduleRepeat: ", ObjectName, Start, Repeat, RandomizeFactor, Stop } )
|
self:F3( { "ScheduleRepeat: ", ObjectName, Start, Repeat, RandomizeFactor, Stop } )
|
||||||
self.SchedulerObject = self
|
|
||||||
|
if not self.Scheduler then
|
||||||
|
self.Scheduler = SCHEDULER:New( self )
|
||||||
|
end
|
||||||
|
|
||||||
|
self.Scheduler.SchedulerObject = self.Scheduler
|
||||||
|
|
||||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
||||||
self,
|
self,
|
||||||
@@ -720,9 +790,9 @@ do -- Scheduling
|
|||||||
Stop
|
Stop
|
||||||
)
|
)
|
||||||
|
|
||||||
self._.Schedules[SchedulerFunction] = ScheduleID
|
self._.Schedules[#self._.Schedules+1] = ScheduleID
|
||||||
|
|
||||||
return self._.Schedules
|
return self._.Schedules[#self._.Schedules]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stops the Schedule.
|
--- Stops the Schedule.
|
||||||
@@ -732,7 +802,7 @@ do -- Scheduling
|
|||||||
|
|
||||||
self:F3( { "ScheduleStop:" } )
|
self:F3( { "ScheduleStop:" } )
|
||||||
|
|
||||||
_SCHEDULEDISPATCHER:Stop( self, self._.Schedules[SchedulerFunction] )
|
_SCHEDULEDISPATCHER:Stop( self.Scheduler, self._.Schedules[SchedulerFunction] )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -744,8 +814,7 @@ end
|
|||||||
-- @param Object The object that will hold the Value set by the Key.
|
-- @param Object The object that will hold the Value set by the Key.
|
||||||
-- @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 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 to is stored in the object.
|
-- @param Value The value to is stored in the object.
|
||||||
-- @return The Value set.
|
-- @return The Value set.
|
||||||
-- @return #nil The Key was not found and thus the Value could not be retrieved.
|
|
||||||
function BASE:SetState( Object, Key, Value )
|
function BASE:SetState( Object, Key, Value )
|
||||||
|
|
||||||
local ClassNameAndID = Object:GetClassNameAndID()
|
local ClassNameAndID = Object:GetClassNameAndID()
|
||||||
@@ -762,7 +831,7 @@ end
|
|||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Object The object that holds the Value set by the Key.
|
-- @param Object The object that holds the Value set by the Key.
|
||||||
-- @param Key The key that is used to retrieve the value. Note that the key can be a #string, but it can also be any other type!
|
-- @param Key The key that is used to retrieve the value. Note that the key can be a #string, but it can also be any other type!
|
||||||
-- @return The Value retrieved.
|
-- @return The Value retrieved or nil if the Key was not found and thus the Value could not be retrieved.
|
||||||
function BASE:GetState( Object, Key )
|
function BASE:GetState( Object, Key )
|
||||||
|
|
||||||
local ClassNameAndID = Object:GetClassNameAndID()
|
local ClassNameAndID = Object:GetClassNameAndID()
|
||||||
@@ -775,6 +844,10 @@ function BASE:GetState( Object, Key )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Clear the state of an object.
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Object The object that holds the Value set by the Key.
|
||||||
|
-- @param StateName The key that is should be cleared.
|
||||||
function BASE:ClearState( Object, StateName )
|
function BASE:ClearState( Object, StateName )
|
||||||
|
|
||||||
local ClassNameAndID = Object:GetClassNameAndID()
|
local ClassNameAndID = Object:GetClassNameAndID()
|
||||||
@@ -789,7 +862,7 @@ end
|
|||||||
-- TODO: Make trace function using variable parameters.
|
-- TODO: Make trace function using variable parameters.
|
||||||
|
|
||||||
--- Set trace on or off
|
--- Set trace on or off
|
||||||
-- Note that when trace is off, no debug statement is performed, increasing performance!
|
-- Note that when trace is off, no BASE.Debug statement is performed, increasing performance!
|
||||||
-- When Moose is loaded statically, (as one file), tracing is switched off by default.
|
-- When Moose is loaded statically, (as one file), tracing is switched off by default.
|
||||||
-- So tracing must be switched on manually in your mission if you are using Moose statically.
|
-- So tracing must be switched on manually in your mission if you are using Moose statically.
|
||||||
-- When moose is loading dynamically (for moose class development), tracing is switched on by default.
|
-- When moose is loading dynamically (for moose class development), tracing is switched on by default.
|
||||||
@@ -811,7 +884,7 @@ end
|
|||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
function BASE:IsTrace()
|
function BASE:IsTrace()
|
||||||
|
|
||||||
if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
|
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
@@ -867,10 +940,10 @@ end
|
|||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
||||||
|
|
||||||
if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
|
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
|
||||||
|
|
||||||
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo( 2, "nl" )
|
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" )
|
||||||
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" )
|
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" )
|
||||||
|
|
||||||
local Function = "function"
|
local Function = "function"
|
||||||
if DebugInfoCurrent.name then
|
if DebugInfoCurrent.name then
|
||||||
@@ -896,9 +969,9 @@ end
|
|||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
function BASE:F( Arguments )
|
function BASE:F( Arguments )
|
||||||
|
|
||||||
if debug and _TraceOnOff then
|
if BASE.Debug and _TraceOnOff then
|
||||||
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
|
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||||
local DebugInfoFrom = debug.getinfo( 3, "l" )
|
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||||
|
|
||||||
if _TraceLevel >= 1 then
|
if _TraceLevel >= 1 then
|
||||||
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
||||||
@@ -912,9 +985,9 @@ end
|
|||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
function BASE:F2( Arguments )
|
function BASE:F2( Arguments )
|
||||||
|
|
||||||
if debug and _TraceOnOff then
|
if BASE.Debug and _TraceOnOff then
|
||||||
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
|
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||||
local DebugInfoFrom = debug.getinfo( 3, "l" )
|
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||||
|
|
||||||
if _TraceLevel >= 2 then
|
if _TraceLevel >= 2 then
|
||||||
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
||||||
@@ -927,9 +1000,9 @@ end
|
|||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
function BASE:F3( Arguments )
|
function BASE:F3( Arguments )
|
||||||
|
|
||||||
if debug and _TraceOnOff then
|
if BASE.Debug and _TraceOnOff then
|
||||||
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
|
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||||
local DebugInfoFrom = debug.getinfo( 3, "l" )
|
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||||
|
|
||||||
if _TraceLevel >= 3 then
|
if _TraceLevel >= 3 then
|
||||||
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
||||||
@@ -942,10 +1015,10 @@ end
|
|||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
||||||
|
|
||||||
if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
|
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
|
||||||
|
|
||||||
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo( 2, "nl" )
|
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" )
|
||||||
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" )
|
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" )
|
||||||
|
|
||||||
local Function = "function"
|
local Function = "function"
|
||||||
if DebugInfoCurrent.name then
|
if DebugInfoCurrent.name then
|
||||||
@@ -971,9 +1044,9 @@ end
|
|||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
function BASE:T( Arguments )
|
function BASE:T( Arguments )
|
||||||
|
|
||||||
if debug and _TraceOnOff then
|
if BASE.Debug and _TraceOnOff then
|
||||||
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
|
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||||
local DebugInfoFrom = debug.getinfo( 3, "l" )
|
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||||
|
|
||||||
if _TraceLevel >= 1 then
|
if _TraceLevel >= 1 then
|
||||||
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
||||||
@@ -987,9 +1060,9 @@ end
|
|||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
function BASE:T2( Arguments )
|
function BASE:T2( Arguments )
|
||||||
|
|
||||||
if debug and _TraceOnOff then
|
if BASE.Debug and _TraceOnOff then
|
||||||
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
|
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||||
local DebugInfoFrom = debug.getinfo( 3, "l" )
|
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||||
|
|
||||||
if _TraceLevel >= 2 then
|
if _TraceLevel >= 2 then
|
||||||
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
||||||
@@ -1002,9 +1075,9 @@ end
|
|||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
function BASE:T3( Arguments )
|
function BASE:T3( Arguments )
|
||||||
|
|
||||||
if debug and _TraceOnOff then
|
if BASE.Debug and _TraceOnOff then
|
||||||
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
|
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||||
local DebugInfoFrom = debug.getinfo( 3, "l" )
|
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||||
|
|
||||||
if _TraceLevel >= 3 then
|
if _TraceLevel >= 3 then
|
||||||
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
|
||||||
@@ -1017,9 +1090,9 @@ end
|
|||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
function BASE:E( Arguments )
|
function BASE:E( Arguments )
|
||||||
|
|
||||||
if debug then
|
if BASE.Debug then
|
||||||
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
|
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||||
local DebugInfoFrom = debug.getinfo( 3, "l" )
|
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||||
|
|
||||||
local Function = "function"
|
local Function = "function"
|
||||||
if DebugInfoCurrent.name then
|
if DebugInfoCurrent.name then
|
||||||
@@ -1033,6 +1106,36 @@ function BASE:E( Arguments )
|
|||||||
end
|
end
|
||||||
|
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||||
|
else
|
||||||
|
env.info( string.format( "%1s:%20s%05d(%s)" , "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Log an information which will be traced always. Can be anywhere within the function logic.
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Arguments A #table or any field.
|
||||||
|
function BASE:I( Arguments )
|
||||||
|
|
||||||
|
if BASE.Debug then
|
||||||
|
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||||
|
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||||
|
|
||||||
|
local Function = "function"
|
||||||
|
if DebugInfoCurrent.name then
|
||||||
|
Function = DebugInfoCurrent.name
|
||||||
|
end
|
||||||
|
|
||||||
|
local LineCurrent = DebugInfoCurrent.currentline
|
||||||
|
local LineFrom = -1
|
||||||
|
if DebugInfoFrom then
|
||||||
|
LineFrom = DebugInfoFrom.currentline
|
||||||
|
end
|
||||||
|
|
||||||
|
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||||
|
else
|
||||||
|
env.info( string.format( "%1s:%20s%05d(%s)" , "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,21 @@
|
|||||||
--- **Core** -- DATABASE manages the database of mission objects.
|
--- **Core** -- DATABASE manages the database of mission objects.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
-- ### Contributions:
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Core.Database
|
||||||
|
-- @image Core_Database.JPG
|
||||||
|
|
||||||
|
|
||||||
|
--- @type DATABASE
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
|
||||||
--
|
--
|
||||||
-- 1) @{#DATABASE} class, extends @{Base#BASE}
|
|
||||||
-- ===================================================
|
|
||||||
-- Mission designers can use the DATABASE class to refer to:
|
-- Mission designers can use the DATABASE class to refer to:
|
||||||
--
|
--
|
||||||
-- * STATICS
|
-- * STATICS
|
||||||
@@ -17,35 +29,10 @@
|
|||||||
--
|
--
|
||||||
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
|
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
|
||||||
--
|
--
|
||||||
-- Moose will automatically create one instance of the DATABASE class into the **global** object _DATABASE.
|
-- The singleton object **_DATABASE** is automatically created by MOOSE, that administers all objects within the mission.
|
||||||
-- Moose refers to _DATABASE within the framework extensively, but you can also refer to the _DATABASE object within your missions if required.
|
-- Moose refers to **_DATABASE** within the framework extensively, but you can also refer to the _DATABASE object within your missions if required.
|
||||||
--
|
--
|
||||||
-- 1.1) DATABASE iterators
|
-- @field #DATABASE
|
||||||
-- -----------------------
|
|
||||||
-- You can iterate the database with the available iterator methods.
|
|
||||||
-- The iterator methods will walk the DATABASE set, and call for each element within the set a function that you provide.
|
|
||||||
-- The following iterator methods are currently available within the DATABASE:
|
|
||||||
--
|
|
||||||
-- * @{#DATABASE.ForEachUnit}: Calls a function for each @{UNIT} it finds within the DATABASE.
|
|
||||||
-- * @{#DATABASE.ForEachGroup}: Calls a function for each @{GROUP} it finds within the DATABASE.
|
|
||||||
-- * @{#DATABASE.ForEachPlayer}: Calls a function for each alive player it finds within the DATABASE.
|
|
||||||
-- * @{#DATABASE.ForEachPlayerJoined}: Calls a function for each joined player it finds within the DATABASE.
|
|
||||||
-- * @{#DATABASE.ForEachClient}: Calls a function for each @{CLIENT} it finds within the DATABASE.
|
|
||||||
-- * @{#DATABASE.ForEachClientAlive}: Calls a function for each alive @{CLIENT} it finds within the DATABASE.
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
|
||||||
-- ### Contributions:
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
-- @module Database
|
|
||||||
|
|
||||||
|
|
||||||
--- DATABASE class
|
|
||||||
-- @type DATABASE
|
|
||||||
-- @extends Core.Base#BASE
|
|
||||||
DATABASE = {
|
DATABASE = {
|
||||||
ClassName = "DATABASE",
|
ClassName = "DATABASE",
|
||||||
Templates = {
|
Templates = {
|
||||||
@@ -70,12 +57,16 @@ DATABASE = {
|
|||||||
NavPoints = {},
|
NavPoints = {},
|
||||||
PLAYERSETTINGS = {},
|
PLAYERSETTINGS = {},
|
||||||
ZONENAMES = {},
|
ZONENAMES = {},
|
||||||
|
HITS = {},
|
||||||
|
DESTROYS = {},
|
||||||
|
ZONES = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
local _DATABASECoalition =
|
local _DATABASECoalition =
|
||||||
{
|
{
|
||||||
[1] = "Red",
|
[1] = "Red",
|
||||||
[2] = "Blue",
|
[2] = "Blue",
|
||||||
|
[3] = "Neutral",
|
||||||
}
|
}
|
||||||
|
|
||||||
local _DATABASECategory =
|
local _DATABASECategory =
|
||||||
@@ -104,11 +95,15 @@ function DATABASE:New()
|
|||||||
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
|
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
|
||||||
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
|
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
|
||||||
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
||||||
|
self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash )
|
||||||
|
self:HandleEvent( EVENTS.Hit, self.AccountHits )
|
||||||
self:HandleEvent( EVENTS.NewCargo )
|
self:HandleEvent( EVENTS.NewCargo )
|
||||||
self:HandleEvent( EVENTS.DeleteCargo )
|
self:HandleEvent( EVENTS.DeleteCargo )
|
||||||
|
self:HandleEvent( EVENTS.NewZone )
|
||||||
|
self:HandleEvent( EVENTS.DeleteZone )
|
||||||
|
|
||||||
-- Follow alive players and clients
|
-- Follow alive players and clients
|
||||||
self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit )
|
--self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event.
|
||||||
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit )
|
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit )
|
||||||
|
|
||||||
self:_RegisterTemplates()
|
self:_RegisterTemplates()
|
||||||
@@ -123,7 +118,7 @@ function DATABASE:New()
|
|||||||
--- @param #DATABASE self
|
--- @param #DATABASE self
|
||||||
local function CheckPlayers( self )
|
local function CheckPlayers( self )
|
||||||
|
|
||||||
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) }
|
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ), AlivePlayersNeutral = coalition.getPlayers( coalition.side.NEUTRAL )}
|
||||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
||||||
--self:E( { "CoalitionData:", CoalitionData } )
|
--self:E( { "CoalitionData:", CoalitionData } )
|
||||||
for UnitId, UnitData in pairs( CoalitionData ) do
|
for UnitId, UnitData in pairs( CoalitionData ) do
|
||||||
@@ -148,8 +143,8 @@ function DATABASE:New()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:E( "Scheduling" )
|
--self:E( "Scheduling" )
|
||||||
PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 1, 1 )
|
--PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 1, 1 )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -193,7 +188,10 @@ function DATABASE:AddStatic( DCSStaticName )
|
|||||||
|
|
||||||
if not self.STATICS[DCSStaticName] then
|
if not self.STATICS[DCSStaticName] then
|
||||||
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
|
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
|
||||||
|
return self.STATICS[DCSStaticName]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -253,35 +251,179 @@ function DATABASE:FindAirbase( AirbaseName )
|
|||||||
return AirbaseFound
|
return AirbaseFound
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Adds a Cargo based on the Cargo Name in the DATABASE.
|
|
||||||
-- @param #DATABASE self
|
|
||||||
-- @param #string CargoName The name of the airbase
|
|
||||||
function DATABASE:AddCargo( Cargo )
|
|
||||||
|
|
||||||
if not self.CARGOS[Cargo.Name] then
|
do -- Zones
|
||||||
self.CARGOS[Cargo.Name] = Cargo
|
|
||||||
|
--- Finds a @{Zone} based on the zone name.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string ZoneName The name of the zone.
|
||||||
|
-- @return Core.Zone#ZONE_BASE The found ZONE.
|
||||||
|
function DATABASE:FindZone( ZoneName )
|
||||||
|
|
||||||
|
local ZoneFound = self.ZONES[ZoneName]
|
||||||
|
return ZoneFound
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Adds a @{Zone} based on the zone name in the DATABASE.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string ZoneName The name of the zone.
|
||||||
|
-- @param Core.Zone#ZONE_BASE Zone The zone.
|
||||||
|
function DATABASE:AddZone( ZoneName, Zone )
|
||||||
|
|
||||||
|
if not self.ZONES[ZoneName] then
|
||||||
|
self.ZONES[ZoneName] = Zone
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Deletes a @{Zone} from the DATABASE based on the zone name.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string ZoneName The name of the zone.
|
||||||
|
function DATABASE:DeleteZone( ZoneName )
|
||||||
|
|
||||||
|
self.ZONES[ZoneName] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds an @{Zone} based on the zone name in the DATABASE.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string ZoneName
|
||||||
|
-- @return Core.Zone#ZONE_BASE The found @{Zone}.
|
||||||
|
function DATABASE:FindZone( ZoneName )
|
||||||
|
|
||||||
|
local ZoneFound = self.ZONES[ZoneName]
|
||||||
|
return ZoneFound
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Deletes a Cargo from the DATABASE based on the Cargo Name.
|
--- Private method that registers new ZONE_BASE derived objects within the DATABASE Object.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param #string CargoName The name of the airbase
|
-- @return #DATABASE self
|
||||||
function DATABASE:DeleteCargo( CargoName )
|
function DATABASE:_RegisterZones()
|
||||||
|
|
||||||
self.CARGOS[CargoName] = nil
|
for ZoneID, ZoneData in pairs( env.mission.triggers.zones ) do
|
||||||
end
|
local ZoneName = ZoneData.name
|
||||||
|
|
||||||
--- Finds an CARGO based on the CargoName.
|
self:I( { "Register ZONE:", Name = ZoneName } )
|
||||||
-- @param #DATABASE self
|
local Zone = ZONE:New( ZoneName )
|
||||||
-- @param #string CargoName
|
self.ZONENAMES[ZoneName] = ZoneName
|
||||||
-- @return Wrapper.Cargo#CARGO The found CARGO.
|
self:AddZone( ZoneName, Zone )
|
||||||
function DATABASE:FindCargo( CargoName )
|
end
|
||||||
|
|
||||||
|
for ZoneGroupName, ZoneGroup in pairs( self.GROUPS ) do
|
||||||
|
if ZoneGroupName:match("#ZONE_POLYGON") then
|
||||||
|
local ZoneName1 = ZoneGroupName:match("(.*)#ZONE_POLYGON")
|
||||||
|
local ZoneName2 = ZoneGroupName:match(".*#ZONE_POLYGON(.*)")
|
||||||
|
local ZoneName = ZoneName1 .. ( ZoneName2 or "" )
|
||||||
|
|
||||||
|
self:I( { "Register ZONE_POLYGON:", Name = ZoneName } )
|
||||||
|
local Zone_Polygon = ZONE_POLYGON:New( ZoneName, ZoneGroup )
|
||||||
|
self.ZONENAMES[ZoneName] = ZoneName
|
||||||
|
self:AddZone( ZoneName, Zone_Polygon )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
local CargoFound = self.CARGOS[CargoName]
|
|
||||||
return CargoFound
|
|
||||||
end
|
|
||||||
|
|
||||||
|
end -- zone
|
||||||
|
|
||||||
|
|
||||||
|
do -- cargo
|
||||||
|
|
||||||
|
--- Adds a Cargo based on the Cargo Name in the DATABASE.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string CargoName The name of the airbase
|
||||||
|
function DATABASE:AddCargo( Cargo )
|
||||||
|
|
||||||
|
if not self.CARGOS[Cargo.Name] then
|
||||||
|
self.CARGOS[Cargo.Name] = Cargo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Deletes a Cargo from the DATABASE based on the Cargo Name.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string CargoName The name of the airbase
|
||||||
|
function DATABASE:DeleteCargo( CargoName )
|
||||||
|
|
||||||
|
self.CARGOS[CargoName] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds an CARGO based on the CargoName.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string CargoName
|
||||||
|
-- @return Wrapper.Cargo#CARGO The found CARGO.
|
||||||
|
function DATABASE:FindCargo( CargoName )
|
||||||
|
|
||||||
|
local CargoFound = self.CARGOS[CargoName]
|
||||||
|
return CargoFound
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if the Template name has a #CARGO tag.
|
||||||
|
-- If yes, the group is a cargo.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string TemplateName
|
||||||
|
-- @return #boolean
|
||||||
|
function DATABASE:IsCargo( TemplateName )
|
||||||
|
|
||||||
|
TemplateName = env.getValueDictByKey( TemplateName )
|
||||||
|
|
||||||
|
local Cargo = TemplateName:match( "#(CARGO)" )
|
||||||
|
|
||||||
|
return Cargo and Cargo == "CARGO"
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Private method that registers new Static Templates within the DATABASE Object.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @return #DATABASE self
|
||||||
|
function DATABASE:_RegisterCargos()
|
||||||
|
|
||||||
|
local Groups = UTILS.DeepCopy( self.GROUPS ) -- This is a very important statement. CARGO_GROUP:New creates a new _DATABASE.GROUP entry, which will confuse the loop. I searched 4 hours on this to find the bug!
|
||||||
|
|
||||||
|
for CargoGroupName, CargoGroup in pairs( Groups ) do
|
||||||
|
self:I( { Cargo = CargoGroupName } )
|
||||||
|
if self:IsCargo( CargoGroupName ) then
|
||||||
|
local CargoInfo = CargoGroupName:match("#CARGO(.*)")
|
||||||
|
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)")
|
||||||
|
local CargoName1 = CargoGroupName:match("(.*)#CARGO%(.*%)")
|
||||||
|
local CargoName2 = CargoGroupName:match(".*#CARGO%(.*%)(.*)")
|
||||||
|
local CargoName = CargoName1 .. ( CargoName2 or "" )
|
||||||
|
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?")
|
||||||
|
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
|
||||||
|
local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") )
|
||||||
|
local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") )
|
||||||
|
|
||||||
|
self:I({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
|
||||||
|
CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for CargoStaticName, CargoStatic in pairs( self.STATICS ) do
|
||||||
|
if self:IsCargo( CargoStaticName ) then
|
||||||
|
local CargoInfo = CargoStaticName:match("#CARGO(.*)")
|
||||||
|
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)")
|
||||||
|
local CargoName = CargoStaticName:match("(.*)#CARGO")
|
||||||
|
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?")
|
||||||
|
local Category = CargoParam and CargoParam:match( "C=([%a%d ]+),?")
|
||||||
|
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
|
||||||
|
local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") )
|
||||||
|
local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") )
|
||||||
|
|
||||||
|
if Category == "SLING" then
|
||||||
|
self:I({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
|
||||||
|
CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
|
||||||
|
else
|
||||||
|
if Category == "CRATE" then
|
||||||
|
self:I({"Register CargoCrate:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
|
||||||
|
CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end -- cargo
|
||||||
|
|
||||||
--- Finds a CLIENT based on the ClientName.
|
--- Finds a CLIENT based on the ClientName.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
@@ -322,7 +464,7 @@ end
|
|||||||
function DATABASE:AddGroup( GroupName )
|
function DATABASE:AddGroup( GroupName )
|
||||||
|
|
||||||
if not self.GROUPS[GroupName] then
|
if not self.GROUPS[GroupName] then
|
||||||
self:E( { "Add GROUP:", GroupName } )
|
self:I( { "Add GROUP:", GroupName } )
|
||||||
self.GROUPS[GroupName] = GROUP:Register( GroupName )
|
self.GROUPS[GroupName] = GROUP:Register( GroupName )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -334,9 +476,9 @@ end
|
|||||||
function DATABASE:AddPlayer( UnitName, PlayerName )
|
function DATABASE:AddPlayer( UnitName, PlayerName )
|
||||||
|
|
||||||
if PlayerName then
|
if PlayerName then
|
||||||
self:E( { "Add player for unit:", UnitName, PlayerName } )
|
self:I( { "Add player for unit:", UnitName, PlayerName } )
|
||||||
self.PLAYERS[PlayerName] = UnitName
|
self.PLAYERS[PlayerName] = UnitName
|
||||||
self.PLAYERUNITS[UnitName] = PlayerName
|
self.PLAYERUNITS[PlayerName] = self:FindUnit( UnitName )
|
||||||
self.PLAYERSJOINED[PlayerName] = PlayerName
|
self.PLAYERSJOINED[PlayerName] = PlayerName
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -346,20 +488,58 @@ end
|
|||||||
function DATABASE:DeletePlayer( UnitName, PlayerName )
|
function DATABASE:DeletePlayer( UnitName, PlayerName )
|
||||||
|
|
||||||
if PlayerName then
|
if PlayerName then
|
||||||
self:E( { "Clean player:", PlayerName } )
|
self:I( { "Clean player:", PlayerName } )
|
||||||
self.PLAYERS[PlayerName] = nil
|
self.PLAYERS[PlayerName] = nil
|
||||||
self.PLAYERUNITS[UnitName] = PlayerName
|
self.PLAYERUNITS[PlayerName] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the player table from the DATABASE.
|
||||||
|
-- The player table contains all unit names with the key the name of the player (PlayerName).
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @usage
|
||||||
|
-- local Players = _DATABASE:GetPlayers()
|
||||||
|
-- for PlayerName, UnitName in pairs( Players ) do
|
||||||
|
-- ..
|
||||||
|
-- end
|
||||||
|
function DATABASE:GetPlayers()
|
||||||
|
return self.PLAYERS
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the player table from the DATABASE, which contains all UNIT objects.
|
||||||
|
-- The player table contains all UNIT objects of the player with the key the name of the player (PlayerName).
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @usage
|
||||||
|
-- local PlayerUnits = _DATABASE:GetPlayerUnits()
|
||||||
|
-- for PlayerName, PlayerUnit in pairs( PlayerUnits ) do
|
||||||
|
-- ..
|
||||||
|
-- end
|
||||||
|
function DATABASE:GetPlayerUnits()
|
||||||
|
return self.PLAYERUNITS
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the player table from the DATABASE which have joined in the mission historically.
|
||||||
|
-- The player table contains all UNIT objects with the key the name of the player (PlayerName).
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @usage
|
||||||
|
-- local PlayersJoined = _DATABASE:GetPlayersJoined()
|
||||||
|
-- for PlayerName, PlayerUnit in pairs( PlayersJoined ) do
|
||||||
|
-- ..
|
||||||
|
-- end
|
||||||
|
function DATABASE:GetPlayersJoined()
|
||||||
|
return self.PLAYERSJOINED
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Instantiate new Groups within the DCSRTE.
|
--- Instantiate new Groups within the DCSRTE.
|
||||||
-- This method expects EXACTLY the same structure as a structure within the ME, and needs 2 additional fields defined:
|
-- This method expects EXACTLY the same structure as a structure within the ME, and needs 2 additional fields defined:
|
||||||
-- SpawnCountryID, SpawnCategoryID
|
-- SpawnCountryID, SpawnCategoryID
|
||||||
-- This method is used by the SPAWN class.
|
-- This method is used by the SPAWN class.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param #table SpawnTemplate
|
-- @param #table SpawnTemplate Template of the group to spawn.
|
||||||
-- @return #DATABASE self
|
-- @return Wrapper.Group#GROUP Spawned group.
|
||||||
function DATABASE:Spawn( SpawnTemplate )
|
function DATABASE:Spawn( SpawnTemplate )
|
||||||
self:F( SpawnTemplate.name )
|
self:F( SpawnTemplate.name )
|
||||||
|
|
||||||
@@ -415,13 +595,14 @@ end
|
|||||||
--- Private method that registers new Group Templates within the DATABASE Object.
|
--- Private method that registers new Group Templates within the DATABASE Object.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param #table GroupTemplate
|
-- @param #table GroupTemplate
|
||||||
|
-- @param DCS#coalition.side CoalitionSide The coalition.side of the object.
|
||||||
|
-- @param DCS#Object.Category CategoryID The Object.category of the object.
|
||||||
|
-- @param DCS#country.id CountryID the country.id of the object
|
||||||
-- @return #DATABASE self
|
-- @return #DATABASE self
|
||||||
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID )
|
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName )
|
||||||
|
|
||||||
local GroupTemplateName = env.getValueDictByKey(GroupTemplate.name)
|
local GroupTemplateName = GroupName or env.getValueDictByKey( GroupTemplate.name )
|
||||||
|
|
||||||
local TraceTable = {}
|
|
||||||
|
|
||||||
if not self.Templates.Groups[GroupTemplateName] then
|
if not self.Templates.Groups[GroupTemplateName] then
|
||||||
self.Templates.Groups[GroupTemplateName] = {}
|
self.Templates.Groups[GroupTemplateName] = {}
|
||||||
self.Templates.Groups[GroupTemplateName].Status = nil
|
self.Templates.Groups[GroupTemplateName].Status = nil
|
||||||
@@ -433,7 +614,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID
|
|||||||
end
|
end
|
||||||
|
|
||||||
GroupTemplate.CategoryID = CategoryID
|
GroupTemplate.CategoryID = CategoryID
|
||||||
GroupTemplate.CoalitionID = CoalitionID
|
GroupTemplate.CoalitionID = CoalitionSide
|
||||||
GroupTemplate.CountryID = CountryID
|
GroupTemplate.CountryID = CountryID
|
||||||
|
|
||||||
self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName
|
self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName
|
||||||
@@ -442,21 +623,10 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID
|
|||||||
self.Templates.Groups[GroupTemplateName].UnitCount = #GroupTemplate.units
|
self.Templates.Groups[GroupTemplateName].UnitCount = #GroupTemplate.units
|
||||||
self.Templates.Groups[GroupTemplateName].Units = GroupTemplate.units
|
self.Templates.Groups[GroupTemplateName].Units = GroupTemplate.units
|
||||||
self.Templates.Groups[GroupTemplateName].CategoryID = CategoryID
|
self.Templates.Groups[GroupTemplateName].CategoryID = CategoryID
|
||||||
self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionID
|
self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionSide
|
||||||
self.Templates.Groups[GroupTemplateName].CountryID = CountryID
|
self.Templates.Groups[GroupTemplateName].CountryID = CountryID
|
||||||
|
|
||||||
|
local UnitNames = {}
|
||||||
TraceTable[#TraceTable+1] = "Group"
|
|
||||||
TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].GroupName
|
|
||||||
|
|
||||||
TraceTable[#TraceTable+1] = "Coalition"
|
|
||||||
TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CoalitionID
|
|
||||||
TraceTable[#TraceTable+1] = "Category"
|
|
||||||
TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CategoryID
|
|
||||||
TraceTable[#TraceTable+1] = "Country"
|
|
||||||
TraceTable[#TraceTable+1] = self.Templates.Groups[GroupTemplateName].CountryID
|
|
||||||
|
|
||||||
TraceTable[#TraceTable+1] = "Units"
|
|
||||||
|
|
||||||
for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do
|
for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do
|
||||||
|
|
||||||
@@ -469,21 +639,27 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID
|
|||||||
self.Templates.Units[UnitTemplate.name].GroupTemplate = GroupTemplate
|
self.Templates.Units[UnitTemplate.name].GroupTemplate = GroupTemplate
|
||||||
self.Templates.Units[UnitTemplate.name].GroupId = GroupTemplate.groupId
|
self.Templates.Units[UnitTemplate.name].GroupId = GroupTemplate.groupId
|
||||||
self.Templates.Units[UnitTemplate.name].CategoryID = CategoryID
|
self.Templates.Units[UnitTemplate.name].CategoryID = CategoryID
|
||||||
self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionID
|
self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionSide
|
||||||
self.Templates.Units[UnitTemplate.name].CountryID = CountryID
|
self.Templates.Units[UnitTemplate.name].CountryID = CountryID
|
||||||
|
|
||||||
if UnitTemplate.skill and (UnitTemplate.skill == "Client" or UnitTemplate.skill == "Player") then
|
if UnitTemplate.skill and (UnitTemplate.skill == "Client" or UnitTemplate.skill == "Player") then
|
||||||
self.Templates.ClientsByName[UnitTemplate.name] = UnitTemplate
|
self.Templates.ClientsByName[UnitTemplate.name] = UnitTemplate
|
||||||
self.Templates.ClientsByName[UnitTemplate.name].CategoryID = CategoryID
|
self.Templates.ClientsByName[UnitTemplate.name].CategoryID = CategoryID
|
||||||
self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionID
|
self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionSide
|
||||||
self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID
|
self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID
|
||||||
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
|
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
|
||||||
end
|
end
|
||||||
|
|
||||||
TraceTable[#TraceTable+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
||||||
end
|
end
|
||||||
|
|
||||||
self:E( TraceTable )
|
self:I( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
|
||||||
|
Coalition = self.Templates.Groups[GroupTemplateName].CoalitionID,
|
||||||
|
Category = self.Templates.Groups[GroupTemplateName].CategoryID,
|
||||||
|
Country = self.Templates.Groups[GroupTemplateName].CountryID,
|
||||||
|
Units = UnitNames
|
||||||
|
}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function DATABASE:GetGroupTemplate( GroupName )
|
function DATABASE:GetGroupTemplate( GroupName )
|
||||||
@@ -496,11 +672,11 @@ end
|
|||||||
|
|
||||||
--- Private method that registers new Static Templates within the DATABASE Object.
|
--- Private method that registers new Static Templates within the DATABASE Object.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param #table GroupTemplate
|
-- @param #table StaticTemplate
|
||||||
-- @return #DATABASE self
|
-- @return #DATABASE self
|
||||||
function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID )
|
function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID )
|
||||||
|
|
||||||
local TraceTable = {}
|
local StaticTemplate = UTILS.DeepCopy( StaticTemplate )
|
||||||
|
|
||||||
local StaticTemplateName = env.getValueDictByKey(StaticTemplate.name)
|
local StaticTemplateName = env.getValueDictByKey(StaticTemplate.name)
|
||||||
|
|
||||||
@@ -517,28 +693,28 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
|
|||||||
self.Templates.Statics[StaticTemplateName].CoalitionID = CoalitionID
|
self.Templates.Statics[StaticTemplateName].CoalitionID = CoalitionID
|
||||||
self.Templates.Statics[StaticTemplateName].CountryID = CountryID
|
self.Templates.Statics[StaticTemplateName].CountryID = CountryID
|
||||||
|
|
||||||
|
self:I( { Static = self.Templates.Statics[StaticTemplateName].StaticName,
|
||||||
|
Coalition = self.Templates.Statics[StaticTemplateName].CoalitionID,
|
||||||
|
Category = self.Templates.Statics[StaticTemplateName].CategoryID,
|
||||||
|
Country = self.Templates.Statics[StaticTemplateName].CountryID
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self:AddStatic( StaticTemplateName )
|
||||||
|
|
||||||
TraceTable[#TraceTable+1] = "Static"
|
|
||||||
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].GroupName
|
|
||||||
|
|
||||||
TraceTable[#TraceTable+1] = "Coalition"
|
|
||||||
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CoalitionID
|
|
||||||
TraceTable[#TraceTable+1] = "Category"
|
|
||||||
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CategoryID
|
|
||||||
TraceTable[#TraceTable+1] = "Country"
|
|
||||||
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CountryID
|
|
||||||
|
|
||||||
self:E( TraceTable )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #DATABASE self
|
||||||
|
function DATABASE:GetStaticGroupTemplate( StaticName )
|
||||||
|
local StaticTemplate = self.Templates.Statics[StaticName].GroupTemplate
|
||||||
|
return StaticTemplate, self.Templates.Statics[StaticName].CoalitionID, self.Templates.Statics[StaticName].CategoryID, self.Templates.Statics[StaticName].CountryID
|
||||||
|
end
|
||||||
|
|
||||||
--- @param #DATABASE self
|
--- @param #DATABASE self
|
||||||
function DATABASE:GetStaticUnitTemplate( StaticName )
|
function DATABASE:GetStaticUnitTemplate( StaticName )
|
||||||
local StaticTemplate = self.Templates.Statics[StaticName].UnitTemplate
|
local UnitTemplate = self.Templates.Statics[StaticName].UnitTemplate
|
||||||
StaticTemplate.SpawnCoalitionID = self.Templates.Statics[StaticName].CoalitionID
|
return UnitTemplate, self.Templates.Statics[StaticName].CoalitionID, self.Templates.Statics[StaticName].CategoryID, self.Templates.Statics[StaticName].CountryID
|
||||||
StaticTemplate.SpawnCategoryID = self.Templates.Statics[StaticName].CategoryID
|
|
||||||
StaticTemplate.SpawnCountryID = self.Templates.Statics[StaticName].CountryID
|
|
||||||
return StaticTemplate
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -579,7 +755,7 @@ end
|
|||||||
-- @return #DATABASE self
|
-- @return #DATABASE self
|
||||||
function DATABASE:_RegisterPlayers()
|
function DATABASE:_RegisterPlayers()
|
||||||
|
|
||||||
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) }
|
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ), AlivePlayersNeutral = coalition.getPlayers( coalition.side.NEUTRAL ) }
|
||||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
||||||
for UnitId, UnitData in pairs( CoalitionData ) do
|
for UnitId, UnitData in pairs( CoalitionData ) do
|
||||||
self:T3( { "UnitData:", UnitData } )
|
self:T3( { "UnitData:", UnitData } )
|
||||||
@@ -587,7 +763,7 @@ function DATABASE:_RegisterPlayers()
|
|||||||
local UnitName = UnitData:getName()
|
local UnitName = UnitData:getName()
|
||||||
local PlayerName = UnitData:getPlayerName()
|
local PlayerName = UnitData:getPlayerName()
|
||||||
if not self.PLAYERS[PlayerName] then
|
if not self.PLAYERS[PlayerName] then
|
||||||
self:E( { "Add player for unit:", UnitName, PlayerName } )
|
self:I( { "Add player for unit:", UnitName, PlayerName } )
|
||||||
self:AddPlayer( UnitName, PlayerName )
|
self:AddPlayer( UnitName, PlayerName )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -603,20 +779,20 @@ end
|
|||||||
-- @return #DATABASE self
|
-- @return #DATABASE self
|
||||||
function DATABASE:_RegisterGroupsAndUnits()
|
function DATABASE:_RegisterGroupsAndUnits()
|
||||||
|
|
||||||
local CoalitionsData = { GroupsRed = coalition.getGroups( coalition.side.RED ), GroupsBlue = coalition.getGroups( coalition.side.BLUE ) }
|
local CoalitionsData = { GroupsRed = coalition.getGroups( coalition.side.RED ), GroupsBlue = coalition.getGroups( coalition.side.BLUE ), GroupsNeutral = coalition.getGroups( coalition.side.NEUTRAL ) }
|
||||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
||||||
for DCSGroupId, DCSGroup in pairs( CoalitionData ) do
|
for DCSGroupId, DCSGroup in pairs( CoalitionData ) do
|
||||||
|
|
||||||
if DCSGroup:isExist() then
|
if DCSGroup:isExist() then
|
||||||
local DCSGroupName = DCSGroup:getName()
|
local DCSGroupName = DCSGroup:getName()
|
||||||
|
|
||||||
self:E( { "Register Group:", DCSGroupName } )
|
self:I( { "Register Group:", DCSGroupName } )
|
||||||
self:AddGroup( DCSGroupName )
|
self:AddGroup( DCSGroupName )
|
||||||
|
|
||||||
for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do
|
for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do
|
||||||
|
|
||||||
local DCSUnitName = DCSUnit:getName()
|
local DCSUnitName = DCSUnit:getName()
|
||||||
self:E( { "Register Unit:", DCSUnitName } )
|
self:I( { "Register Unit:", DCSUnitName } )
|
||||||
self:AddUnit( DCSUnitName )
|
self:AddUnit( DCSUnitName )
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -625,6 +801,11 @@ function DATABASE:_RegisterGroupsAndUnits()
|
|||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:I("Groups:")
|
||||||
|
for GroupName, Group in pairs( self.GROUPS ) do
|
||||||
|
self:I( { "Group:", GroupName } )
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -635,7 +816,7 @@ end
|
|||||||
function DATABASE:_RegisterClients()
|
function DATABASE:_RegisterClients()
|
||||||
|
|
||||||
for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do
|
for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do
|
||||||
self:E( { "Register Client:", ClientName } )
|
self:I( { "Register Client:", ClientName } )
|
||||||
self:AddClient( ClientName )
|
self:AddClient( ClientName )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -646,13 +827,14 @@ end
|
|||||||
function DATABASE:_RegisterStatics()
|
function DATABASE:_RegisterStatics()
|
||||||
|
|
||||||
local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) }
|
local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) }
|
||||||
|
self:I( { Statics = CoalitionsData } )
|
||||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
||||||
for DCSStaticId, DCSStatic in pairs( CoalitionData ) do
|
for DCSStaticId, DCSStatic in pairs( CoalitionData ) do
|
||||||
|
|
||||||
if DCSStatic:isExist() then
|
if DCSStatic:isExist() then
|
||||||
local DCSStaticName = DCSStatic:getName()
|
local DCSStaticName = DCSStatic:getName()
|
||||||
|
|
||||||
self:E( { "Register Static:", DCSStaticName } )
|
self:I( { "Register Static:", DCSStaticName } )
|
||||||
self:AddStatic( DCSStaticName )
|
self:AddStatic( DCSStaticName )
|
||||||
else
|
else
|
||||||
self:E( { "Static does not exist: ", DCSStatic } )
|
self:E( { "Static does not exist: ", DCSStatic } )
|
||||||
@@ -672,7 +854,7 @@ function DATABASE:_RegisterAirbases()
|
|||||||
|
|
||||||
local DCSAirbaseName = DCSAirbase:getName()
|
local DCSAirbaseName = DCSAirbase:getName()
|
||||||
|
|
||||||
self:E( { "Register Airbase:", DCSAirbaseName } )
|
self:I( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } )
|
||||||
self:AddAirbase( DCSAirbaseName )
|
self:AddAirbase( DCSAirbaseName )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -698,7 +880,20 @@ function DATABASE:_EventOnBirth( Event )
|
|||||||
self:AddGroup( Event.IniDCSGroupName )
|
self:AddGroup( Event.IniDCSGroupName )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
--self:_EventOnPlayerEnterUnit( Event )
|
if Event.IniObjectCategory == 1 then
|
||||||
|
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
|
||||||
|
Event.IniGroup = self:FindGroup( Event.IniDCSGroupName )
|
||||||
|
local PlayerName = Event.IniUnit:GetPlayerName()
|
||||||
|
if PlayerName then
|
||||||
|
self:I( { "Player Joined:", PlayerName } )
|
||||||
|
if not self.PLAYERS[PlayerName] then
|
||||||
|
self:AddPlayer( Event.IniUnitName, PlayerName )
|
||||||
|
end
|
||||||
|
local Settings = SETTINGS:Set( PlayerName )
|
||||||
|
Settings:SetPlayerMenu( Event.IniUnit )
|
||||||
|
--MENU_INDEX:Refresh( Event.IniGroup )
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -722,6 +917,8 @@ function DATABASE:_EventOnDeadOrCrash( Event )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:AccountDestroys( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -731,13 +928,14 @@ end
|
|||||||
function DATABASE:_EventOnPlayerEnterUnit( Event )
|
function DATABASE:_EventOnPlayerEnterUnit( Event )
|
||||||
self:F2( { Event } )
|
self:F2( { Event } )
|
||||||
|
|
||||||
if Event.IniUnit then
|
if Event.IniDCSUnit then
|
||||||
if Event.IniObjectCategory == 1 then
|
if Event.IniObjectCategory == 1 then
|
||||||
self:AddUnit( Event.IniDCSUnitName )
|
self:AddUnit( Event.IniDCSUnitName )
|
||||||
|
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
|
||||||
self:AddGroup( Event.IniDCSGroupName )
|
self:AddGroup( Event.IniDCSGroupName )
|
||||||
local PlayerName = Event.IniUnit:GetPlayerName()
|
local PlayerName = Event.IniDCSUnit:getPlayerName()
|
||||||
if not self.PLAYERS[PlayerName] then
|
if not self.PLAYERS[PlayerName] then
|
||||||
self:AddPlayer( Event.IniUnitName, PlayerName )
|
self:AddPlayer( Event.IniDCSUnitName, PlayerName )
|
||||||
end
|
end
|
||||||
local Settings = SETTINGS:Set( PlayerName )
|
local Settings = SETTINGS:Set( PlayerName )
|
||||||
Settings:SetPlayerMenu( Event.IniUnit )
|
Settings:SetPlayerMenu( Event.IniUnit )
|
||||||
@@ -755,7 +953,8 @@ function DATABASE:_EventOnPlayerLeaveUnit( Event )
|
|||||||
if Event.IniUnit then
|
if Event.IniUnit then
|
||||||
if Event.IniObjectCategory == 1 then
|
if Event.IniObjectCategory == 1 then
|
||||||
local PlayerName = Event.IniUnit:GetPlayerName()
|
local PlayerName = Event.IniUnit:GetPlayerName()
|
||||||
if self.PLAYERS[PlayerName] then
|
if PlayerName and self.PLAYERS[PlayerName] then
|
||||||
|
self:I( { "Player Left:", PlayerName } )
|
||||||
local Settings = SETTINGS:Set( PlayerName )
|
local Settings = SETTINGS:Set( PlayerName )
|
||||||
Settings:RemovePlayerMenu( Event.IniUnit )
|
Settings:RemovePlayerMenu( Event.IniUnit )
|
||||||
self:DeletePlayer( Event.IniUnit, PlayerName )
|
self:DeletePlayer( Event.IniUnit, PlayerName )
|
||||||
@@ -939,6 +1138,31 @@ function DATABASE:OnEventDeleteCargo( EventData )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Handles the OnEventNewZone event.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function DATABASE:OnEventNewZone( EventData )
|
||||||
|
self:F2( { EventData } )
|
||||||
|
|
||||||
|
if EventData.Zone then
|
||||||
|
self:AddZone( EventData.Zone )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Handles the OnEventDeleteZone.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function DATABASE:OnEventDeleteZone( EventData )
|
||||||
|
self:F2( { EventData } )
|
||||||
|
|
||||||
|
if EventData.Zone then
|
||||||
|
self:DeleteZone( EventData.Zone.ZoneName )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Gets the player settings
|
--- Gets the player settings
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param #string PlayerName
|
-- @param #string PlayerName
|
||||||
@@ -970,13 +1194,20 @@ function DATABASE:_RegisterTemplates()
|
|||||||
self.UNITS = {}
|
self.UNITS = {}
|
||||||
--Build routines.db.units and self.Navpoints
|
--Build routines.db.units and self.Navpoints
|
||||||
for CoalitionName, coa_data in pairs(env.mission.coalition) do
|
for CoalitionName, coa_data in pairs(env.mission.coalition) do
|
||||||
|
self:T({CoalitionName=CoalitionName})
|
||||||
|
|
||||||
if (CoalitionName == 'red' or CoalitionName == 'blue') and type(coa_data) == 'table' then
|
if (CoalitionName == 'red' or CoalitionName == 'blue' or CoalitionName == 'neutrals') and type(coa_data) == 'table' then
|
||||||
--self.Units[coa_name] = {}
|
--self.Units[coa_name] = {}
|
||||||
|
|
||||||
local CoalitionSide = coalition.side[string.upper(CoalitionName)]
|
local CoalitionSide = coalition.side[string.upper(CoalitionName)]
|
||||||
|
if CoalitionName=="red" then
|
||||||
|
CoalitionSide=coalition.side.NEUTRAL
|
||||||
|
elseif CoalitionName=="blue" then
|
||||||
|
CoalitionSide=coalition.side.BLUE
|
||||||
|
else
|
||||||
|
CoalitionSide=coalition.side.NEUTRAL
|
||||||
|
end
|
||||||
|
|
||||||
----------------------------------------------
|
|
||||||
-- build nav points DB
|
-- build nav points DB
|
||||||
self.Navpoints[CoalitionName] = {}
|
self.Navpoints[CoalitionName] = {}
|
||||||
if coa_data.nav_points then --navpoints
|
if coa_data.nav_points then --navpoints
|
||||||
@@ -991,8 +1222,9 @@ function DATABASE:_RegisterTemplates()
|
|||||||
self.Navpoints[CoalitionName][nav_ind]['point']['y'] = 0
|
self.Navpoints[CoalitionName][nav_ind]['point']['y'] = 0
|
||||||
self.Navpoints[CoalitionName][nav_ind]['point']['z'] = nav_data.y
|
self.Navpoints[CoalitionName][nav_ind]['point']['z'] = nav_data.y
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
if coa_data.country then --there is a country table
|
if coa_data.country then --there is a country table
|
||||||
for cntry_id, cntry_data in pairs(coa_data.country) do
|
for cntry_id, cntry_data in pairs(coa_data.country) do
|
||||||
@@ -1045,14 +1277,98 @@ function DATABASE:_RegisterTemplates()
|
|||||||
end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then
|
end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then
|
||||||
end --for coa_name, coa_data in pairs(mission.coalition) do
|
end --for coa_name, coa_data in pairs(mission.coalition) do
|
||||||
|
|
||||||
for ZoneID, ZoneData in pairs( env.mission.triggers.zones ) do
|
|
||||||
local ZoneName = ZoneData.name
|
|
||||||
self.ZONENAMES[ZoneName] = ZoneName
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Account the Hits of the Players.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param Core.Event#EVENTDATA Event
|
||||||
|
function DATABASE:AccountHits( Event )
|
||||||
|
self:F( { Event } )
|
||||||
|
|
||||||
|
if Event.IniPlayerName ~= nil then -- It is a player that is hitting something
|
||||||
|
self:T( "Hitting Something" )
|
||||||
|
|
||||||
|
-- What is he hitting?
|
||||||
|
if Event.TgtCategory then
|
||||||
|
|
||||||
|
-- A target got hit
|
||||||
|
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
|
||||||
|
local Hit = self.HITS[Event.TgtUnitName]
|
||||||
|
|
||||||
|
Hit.Players = Hit.Players or {}
|
||||||
|
Hit.Players[Event.IniPlayerName] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- It is a weapon initiated by a player, that is hitting something
|
||||||
|
-- This seems to occur only with scenery and static objects.
|
||||||
|
if Event.WeaponPlayerName ~= nil then
|
||||||
|
self:T( "Hitting Scenery" )
|
||||||
|
|
||||||
|
-- What is he hitting?
|
||||||
|
if Event.TgtCategory then
|
||||||
|
|
||||||
|
if Event.IniCoalition then -- A coalition object was hit, probably a static.
|
||||||
|
-- A target got hit
|
||||||
|
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
|
||||||
|
local Hit = self.HITS[Event.TgtUnitName]
|
||||||
|
|
||||||
|
Hit.Players = Hit.Players or {}
|
||||||
|
Hit.Players[Event.WeaponPlayerName] = true
|
||||||
|
else -- A scenery object was hit.
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Account the destroys.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param Core.Event#EVENTDATA Event
|
||||||
|
function DATABASE:AccountDestroys( Event )
|
||||||
|
self:F( { Event } )
|
||||||
|
|
||||||
|
local TargetUnit = nil
|
||||||
|
local TargetGroup = nil
|
||||||
|
local TargetUnitName = ""
|
||||||
|
local TargetGroupName = ""
|
||||||
|
local TargetPlayerName = ""
|
||||||
|
local TargetCoalition = nil
|
||||||
|
local TargetCategory = nil
|
||||||
|
local TargetType = nil
|
||||||
|
local TargetUnitCoalition = nil
|
||||||
|
local TargetUnitCategory = nil
|
||||||
|
local TargetUnitType = nil
|
||||||
|
|
||||||
|
if Event.IniDCSUnit then
|
||||||
|
|
||||||
|
TargetUnit = Event.IniUnit
|
||||||
|
TargetUnitName = Event.IniDCSUnitName
|
||||||
|
TargetGroup = Event.IniDCSGroup
|
||||||
|
TargetGroupName = Event.IniDCSGroupName
|
||||||
|
TargetPlayerName = Event.IniPlayerName
|
||||||
|
|
||||||
|
TargetCoalition = Event.IniCoalition
|
||||||
|
--TargetCategory = TargetUnit:getCategory()
|
||||||
|
--TargetCategory = TargetUnit:getDesc().category -- Workaround
|
||||||
|
TargetCategory = Event.IniCategory
|
||||||
|
TargetType = Event.IniTypeName
|
||||||
|
|
||||||
|
TargetUnitType = TargetType
|
||||||
|
|
||||||
|
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
|
||||||
|
end
|
||||||
|
|
||||||
|
local Destroyed = false
|
||||||
|
|
||||||
|
-- What is the player destroying?
|
||||||
|
if self.HITS[Event.IniUnitName] then -- Was there a hit for this unit for this player before registered???
|
||||||
|
self.DESTROYS[Event.IniUnitName] = self.DESTROYS[Event.IniUnitName] or {}
|
||||||
|
self.DESTROYS[Event.IniUnitName] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
--- **Core** -- EVENT models DCS **event dispatching** using a **publish-subscribe** model.
|
--- **Core** -- EVENT models DCS **event dispatching** using a **publish-subscribe** model.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # 1) Event Handling Overview
|
-- # 1) Event Handling Overview
|
||||||
@@ -61,8 +59,8 @@
|
|||||||
-- So, when the DCS event occurs, the class will be notified of that event.
|
-- So, when the DCS event occurs, the class will be notified of that event.
|
||||||
-- There are two functions which you use to subscribe to or unsubscribe from an event.
|
-- There are two functions which you use to subscribe to or unsubscribe from an event.
|
||||||
--
|
--
|
||||||
-- * @{Base#BASE.HandleEvent}(): Subscribe to a DCS Event.
|
-- * @{Core.Base#BASE.HandleEvent}(): Subscribe to a DCS Event.
|
||||||
-- * @{Base#BASE.UnHandleEvent}(): Unsubscribe from a DCS Event.
|
-- * @{Core.Base#BASE.UnHandleEvent}(): Unsubscribe from a DCS Event.
|
||||||
--
|
--
|
||||||
-- Note that for a UNIT, the event will be handled **for that UNIT only**!
|
-- Note that for a UNIT, the event will be handled **for that UNIT only**!
|
||||||
-- Note that for a GROUP, the event will be handled **for all the UNITs in that GROUP only**!
|
-- Note that for a GROUP, the event will be handled **for all the UNITs in that GROUP only**!
|
||||||
@@ -74,7 +72,7 @@
|
|||||||
-- ### 1.3.2 Event Handling of DCS Events
|
-- ### 1.3.2 Event Handling of DCS Events
|
||||||
--
|
--
|
||||||
-- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called
|
-- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called
|
||||||
-- when the DCS event occurs. The Event Handling method receives an @{Event#EVENTDATA} structure, which contains a lot of information
|
-- when the DCS event occurs. The Event Handling method receives an @{Core.Event#EVENTDATA} structure, which contains a lot of information
|
||||||
-- about the event that occurred.
|
-- about the event that occurred.
|
||||||
--
|
--
|
||||||
-- Find below an example of the prototype how to write an event handling function for two units:
|
-- Find below an example of the prototype how to write an event handling function for two units:
|
||||||
@@ -112,11 +110,11 @@
|
|||||||
-- # 2) EVENTS type
|
-- # 2) EVENTS type
|
||||||
--
|
--
|
||||||
-- The EVENTS structure contains names for all the different DCS events that objects can subscribe to using the
|
-- The EVENTS structure contains names for all the different DCS events that objects can subscribe to using the
|
||||||
-- @{Base#BASE.HandleEvent}() method.
|
-- @{Core.Base#BASE.HandleEvent}() method.
|
||||||
--
|
--
|
||||||
-- # 3) EVENTDATA type
|
-- # 3) EVENTDATA type
|
||||||
--
|
--
|
||||||
-- The @{Event#EVENTDATA} structure contains all the fields that are populated with event information before
|
-- The @{Core.Event#EVENTDATA} structure contains all the fields that are populated with event information before
|
||||||
-- an Event Handler method is being called by the event dispatcher.
|
-- an Event Handler method is being called by the event dispatcher.
|
||||||
-- The Event Handler received the EVENTDATA object as a parameter, and can be used to investigate further the different events.
|
-- The Event Handler received the EVENTDATA object as a parameter, and can be used to investigate further the different events.
|
||||||
-- There are basically 4 main categories of information stored in the EVENTDATA structure:
|
-- There are basically 4 main categories of information stored in the EVENTDATA structure:
|
||||||
@@ -159,28 +157,35 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Event
|
-- @module Core.Event
|
||||||
|
-- @image Core_Event.JPG
|
||||||
|
|
||||||
|
|
||||||
--- The EVENT structure
|
--- The EVENT structure
|
||||||
|
--
|
||||||
-- @type EVENT
|
-- @type EVENT
|
||||||
-- @field #EVENT.Events Events
|
-- @field #EVENT.Events Events
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
EVENT = {
|
EVENT = {
|
||||||
ClassName = "EVENT",
|
ClassName = "EVENT",
|
||||||
ClassID = 0,
|
ClassID = 0,
|
||||||
|
MissionEnd = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000
|
world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000
|
||||||
world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001
|
world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001
|
||||||
|
world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1002
|
||||||
|
world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003
|
||||||
|
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1004
|
||||||
|
|
||||||
|
|
||||||
--- The different types of events supported by MOOSE.
|
--- The different types of events supported by MOOSE.
|
||||||
-- Use this structure to subscribe to events using the @{Base#BASE.HandleEvent}() method.
|
-- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method.
|
||||||
-- @type EVENTS
|
-- @type EVENTS
|
||||||
EVENTS = {
|
EVENTS = {
|
||||||
Shot = world.event.S_EVENT_SHOT,
|
Shot = world.event.S_EVENT_SHOT,
|
||||||
@@ -206,8 +211,14 @@ EVENTS = {
|
|||||||
PlayerComment = world.event.S_EVENT_PLAYER_COMMENT,
|
PlayerComment = world.event.S_EVENT_PLAYER_COMMENT,
|
||||||
ShootingStart = world.event.S_EVENT_SHOOTING_START,
|
ShootingStart = world.event.S_EVENT_SHOOTING_START,
|
||||||
ShootingEnd = world.event.S_EVENT_SHOOTING_END,
|
ShootingEnd = world.event.S_EVENT_SHOOTING_END,
|
||||||
|
MarkAdded = world.event.S_EVENT_MARK_ADDED,
|
||||||
|
MarkChange = world.event.S_EVENT_MARK_CHANGE,
|
||||||
|
MarkRemoved = world.event.S_EVENT_MARK_REMOVED,
|
||||||
NewCargo = world.event.S_EVENT_NEW_CARGO,
|
NewCargo = world.event.S_EVENT_NEW_CARGO,
|
||||||
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
|
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
|
||||||
|
NewZone = world.event.S_EVENT_NEW_ZONE,
|
||||||
|
DeleteZone = world.event.S_EVENT_DELETE_ZONE,
|
||||||
|
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- The Event structure
|
--- The Event structure
|
||||||
@@ -219,36 +230,40 @@ EVENTS = {
|
|||||||
-- @type EVENTDATA
|
-- @type EVENTDATA
|
||||||
-- @field #number id The identifier of the event.
|
-- @field #number id The identifier of the event.
|
||||||
--
|
--
|
||||||
-- @field Dcs.DCSUnit#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{Dcs.DCSUnit#Unit} or @{Dcs.DCSStaticObject#StaticObject}.
|
-- @field DCS#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{DCS#Unit} or @{DCS#StaticObject}.
|
||||||
-- @field Dcs.DCSObject#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ).
|
-- @field DCS#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ).
|
||||||
-- @field Dcs.DCSUnit#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCSUnit#Unit} or @{DCSStaticObject#StaticObject}.
|
-- @field DCS#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCS#Unit} or @{DCS#StaticObject}.
|
||||||
-- @field #string IniDCSUnitName (UNIT/STATIC) The initiating Unit name.
|
-- @field #string IniDCSUnitName (UNIT/STATIC) The initiating Unit name.
|
||||||
-- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Unit#UNIT} of the initiator Unit object.
|
-- @field Wrapper.Unit#UNIT IniUnit (UNIT/STATIC) The initiating MOOSE wrapper @{Wrapper.Unit#UNIT} of the initiator Unit object.
|
||||||
-- @field #string IniUnitName (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName).
|
-- @field #string IniUnitName (UNIT/STATIC) The initiating UNIT name (same as IniDCSUnitName).
|
||||||
-- @field Dcs.DCSGroup#Group IniDCSGroup (UNIT) The initiating {DCSGroup#Group}.
|
-- @field DCS#Group IniDCSGroup (UNIT) The initiating {DCSGroup#Group}.
|
||||||
-- @field #string IniDCSGroupName (UNIT) The initiating Group name.
|
-- @field #string IniDCSGroupName (UNIT) The initiating Group name.
|
||||||
-- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Group#GROUP} of the initiator Group object.
|
-- @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 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 IniPlayerName (UNIT) The name of the initiating player in case the Unit is a client or player slot.
|
||||||
-- @field Dcs.DCScoalition#coalition.side IniCoalition (UNIT) The coalition of the initiator.
|
-- @field DCS#coalition.side IniCoalition (UNIT) The coalition of the initiator.
|
||||||
-- @field Dcs.DCSUnit#Unit.Category IniCategory (UNIT) The category of the initiator.
|
-- @field DCS#Unit.Category IniCategory (UNIT) The category of the initiator.
|
||||||
-- @field #string IniTypeName (UNIT) The type name of the initiator.
|
-- @field #string IniTypeName (UNIT) The type name of the initiator.
|
||||||
--
|
--
|
||||||
-- @field Dcs.DCSUnit#Unit target (UNIT/STATIC) The target @{Dcs.DCSUnit#Unit} or @{DCSStaticObject#StaticObject}.
|
-- @field DCS#Unit target (UNIT/STATIC) The target @{DCS#Unit} or @{DCS#StaticObject}.
|
||||||
-- @field Dcs.DCSObject#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ).
|
-- @field DCS#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ).
|
||||||
-- @field Dcs.DCSUnit#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCSUnit#Unit} or @{DCSStaticObject#StaticObject}.
|
-- @field DCS#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCS#Unit} or @{DCS#StaticObject}.
|
||||||
-- @field #string TgtDCSUnitName (UNIT/STATIC) The target Unit name.
|
-- @field #string TgtDCSUnitName (UNIT/STATIC) The target Unit name.
|
||||||
-- @field Wrapper.Unit#UNIT TgtUnit (UNIT/STATIC) The target MOOSE wrapper @{Unit#UNIT} of the target Unit object.
|
-- @field Wrapper.Unit#UNIT TgtUnit (UNIT/STATIC) The target MOOSE wrapper @{Wrapper.Unit#UNIT} of the target Unit object.
|
||||||
-- @field #string TgtUnitName (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName).
|
-- @field #string TgtUnitName (UNIT/STATIC) The target UNIT name (same as TgtDCSUnitName).
|
||||||
-- @field Dcs.DCSGroup#Group TgtDCSGroup (UNIT) The target {DCSGroup#Group}.
|
-- @field DCS#Group TgtDCSGroup (UNIT) The target {DCSGroup#Group}.
|
||||||
-- @field #string TgtDCSGroupName (UNIT) The target Group name.
|
-- @field #string TgtDCSGroupName (UNIT) The target Group name.
|
||||||
-- @field Wrapper.Group#GROUP TgtGroup (UNIT) The target MOOSE wrapper @{Group#GROUP} of the target Group object.
|
-- @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 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 TgtPlayerName (UNIT) The name of the target player in case the Unit is a client or player slot.
|
||||||
-- @field Dcs.DCScoalition#coalition.side TgtCoalition (UNIT) The coalition of the target.
|
-- @field DCS#coalition.side TgtCoalition (UNIT) The coalition of the target.
|
||||||
-- @field Dcs.DCSUnit#Unit.Category TgtCategory (UNIT) The category of the target.
|
-- @field DCS#Unit.Category TgtCategory (UNIT) The category of the target.
|
||||||
-- @field #string TgtTypeName (UNIT) The type name of the target.
|
-- @field #string TgtTypeName (UNIT) The type name of the target.
|
||||||
--
|
--
|
||||||
|
-- @field DCS#Airbase place The @{DCS#Airbase}
|
||||||
|
-- @field Wrapper.Airbase#AIRBASE Place The MOOSE airbase object.
|
||||||
|
-- @field #string PlaceName The name of the airbase.
|
||||||
|
--
|
||||||
-- @field weapon The weapon used during the event.
|
-- @field weapon The weapon used during the event.
|
||||||
-- @field Weapon
|
-- @field Weapon
|
||||||
-- @field WeaponName
|
-- @field WeaponName
|
||||||
@@ -395,6 +410,24 @@ local _EVENTMETA = {
|
|||||||
Event = "OnEventShootingEnd",
|
Event = "OnEventShootingEnd",
|
||||||
Text = "S_EVENT_SHOOTING_END"
|
Text = "S_EVENT_SHOOTING_END"
|
||||||
},
|
},
|
||||||
|
[world.event.S_EVENT_MARK_ADDED] = {
|
||||||
|
Order = 1,
|
||||||
|
Side = "I",
|
||||||
|
Event = "OnEventMarkAdded",
|
||||||
|
Text = "S_EVENT_MARK_ADDED"
|
||||||
|
},
|
||||||
|
[world.event.S_EVENT_MARK_CHANGE] = {
|
||||||
|
Order = 1,
|
||||||
|
Side = "I",
|
||||||
|
Event = "OnEventMarkChange",
|
||||||
|
Text = "S_EVENT_MARK_CHANGE"
|
||||||
|
},
|
||||||
|
[world.event.S_EVENT_MARK_REMOVED] = {
|
||||||
|
Order = 1,
|
||||||
|
Side = "I",
|
||||||
|
Event = "OnEventMarkRemoved",
|
||||||
|
Text = "S_EVENT_MARK_REMOVED"
|
||||||
|
},
|
||||||
[EVENTS.NewCargo] = {
|
[EVENTS.NewCargo] = {
|
||||||
Order = 1,
|
Order = 1,
|
||||||
Event = "OnEventNewCargo",
|
Event = "OnEventNewCargo",
|
||||||
@@ -405,6 +438,21 @@ local _EVENTMETA = {
|
|||||||
Event = "OnEventDeleteCargo",
|
Event = "OnEventDeleteCargo",
|
||||||
Text = "S_EVENT_DELETE_CARGO"
|
Text = "S_EVENT_DELETE_CARGO"
|
||||||
},
|
},
|
||||||
|
[EVENTS.NewZone] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventNewZone",
|
||||||
|
Text = "S_EVENT_NEW_ZONE"
|
||||||
|
},
|
||||||
|
[EVENTS.DeleteZone] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventDeleteZone",
|
||||||
|
Text = "S_EVENT_DELETE_ZONE"
|
||||||
|
},
|
||||||
|
[EVENTS.RemoveUnit] = {
|
||||||
|
Order = -1,
|
||||||
|
Event = "OnEventRemoveUnit",
|
||||||
|
Text = "S_EVENT_REMOVE_UNIT"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -422,7 +470,7 @@ end
|
|||||||
|
|
||||||
--- Initializes the Events structure for the event
|
--- Initializes the Events structure for the event
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Dcs.DCSWorld#world.event EventID
|
-- @param DCS#world.event EventID
|
||||||
-- @param Core.Base#BASE EventClass
|
-- @param Core.Base#BASE EventClass
|
||||||
-- @return #EVENT.Events
|
-- @return #EVENT.Events
|
||||||
function EVENT:Init( EventID, EventClass )
|
function EVENT:Init( EventID, EventClass )
|
||||||
@@ -448,7 +496,7 @@ end
|
|||||||
--- Removes a subscription
|
--- Removes a subscription
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||||
-- @param Dcs.DCSWorld#world.event EventID
|
-- @param DCS#world.event EventID
|
||||||
-- @return #EVENT.Events
|
-- @return #EVENT.Events
|
||||||
function EVENT:RemoveEvent( EventClass, EventID )
|
function EVENT:RemoveEvent( EventClass, EventID )
|
||||||
|
|
||||||
@@ -459,7 +507,6 @@ function EVENT:RemoveEvent( EventClass, EventID )
|
|||||||
self.Events = self.Events or {}
|
self.Events = self.Events or {}
|
||||||
self.Events[EventID] = self.Events[EventID] or {}
|
self.Events[EventID] = self.Events[EventID] or {}
|
||||||
self.Events[EventID][EventPriority] = self.Events[EventID][EventPriority] or {}
|
self.Events[EventID][EventPriority] = self.Events[EventID][EventPriority] or {}
|
||||||
self.Events[EventID][EventPriority][EventClass] = self.Events[EventID][EventPriority][EventClass]
|
|
||||||
|
|
||||||
self.Events[EventID][EventPriority][EventClass] = nil
|
self.Events[EventID][EventPriority][EventClass] = nil
|
||||||
|
|
||||||
@@ -468,11 +515,11 @@ end
|
|||||||
--- Resets subscriptions
|
--- Resets subscriptions
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||||
-- @param Dcs.DCSWorld#world.event EventID
|
-- @param DCS#world.event EventID
|
||||||
-- @return #EVENT.Events
|
-- @return #EVENT.Events
|
||||||
function EVENT:Reset( EventObject ) --R2.1
|
function EVENT:Reset( EventObject ) --R2.1
|
||||||
|
|
||||||
self:E( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
|
self:F( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
|
||||||
|
|
||||||
local EventPriority = EventObject:GetEventPriority()
|
local EventPriority = EventObject:GetEventPriority()
|
||||||
for EventID, EventData in pairs( self.Events ) do
|
for EventID, EventData in pairs( self.Events ) do
|
||||||
@@ -491,7 +538,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Clears all event subscriptions for a @{Base#BASE} derived object.
|
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Core.Base#BASE EventObject
|
-- @param Core.Base#BASE EventObject
|
||||||
function EVENT:RemoveAll( EventObject )
|
function EVENT:RemoveAll( EventObject )
|
||||||
@@ -562,7 +609,6 @@ end
|
|||||||
-- @param EventID
|
-- @param EventID
|
||||||
-- @return #EVENT
|
-- @return #EVENT
|
||||||
function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID, ... )
|
function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID, ... )
|
||||||
self:E( GroupName )
|
|
||||||
|
|
||||||
local Event = self:Init( EventID, EventClass )
|
local Event = self:Init( EventID, EventClass )
|
||||||
Event.EventGroup = true
|
Event.EventGroup = true
|
||||||
@@ -684,7 +730,7 @@ do -- Event Creation
|
|||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
|
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
|
||||||
function EVENT:CreateEventNewCargo( Cargo )
|
function EVENT:CreateEventNewCargo( Cargo )
|
||||||
self:F( { Cargo } )
|
self:I( { Cargo } )
|
||||||
|
|
||||||
local Event = {
|
local Event = {
|
||||||
id = EVENTS.NewCargo,
|
id = EVENTS.NewCargo,
|
||||||
@@ -710,6 +756,36 @@ do -- Event Creation
|
|||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Creation of a New Zone Event.
|
||||||
|
-- @param #EVENT self
|
||||||
|
-- @param Core.Zone#ZONE_BASE Zone The Zone created.
|
||||||
|
function EVENT:CreateEventNewZone( Zone )
|
||||||
|
self:F( { Zone } )
|
||||||
|
|
||||||
|
local Event = {
|
||||||
|
id = EVENTS.NewZone,
|
||||||
|
time = timer.getTime(),
|
||||||
|
zone = Zone,
|
||||||
|
}
|
||||||
|
|
||||||
|
world.onEvent( Event )
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Creation of a Zone Deletion Event.
|
||||||
|
-- @param #EVENT self
|
||||||
|
-- @param Core.Zone#ZONE_BASE Zone The Zone created.
|
||||||
|
function EVENT:CreateEventDeleteZone( Zone )
|
||||||
|
self:F( { Zone } )
|
||||||
|
|
||||||
|
local Event = {
|
||||||
|
id = EVENTS.DeleteZone,
|
||||||
|
time = timer.getTime(),
|
||||||
|
zone = Zone,
|
||||||
|
}
|
||||||
|
|
||||||
|
world.onEvent( Event )
|
||||||
|
end
|
||||||
|
|
||||||
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
|
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Wrapper.Unit#UNIT PlayerUnit.
|
-- @param Wrapper.Unit#UNIT PlayerUnit.
|
||||||
@@ -734,7 +810,7 @@ function EVENT:onEvent( Event )
|
|||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
|
|
||||||
env.info( "Error in SCHEDULER function:" .. errmsg )
|
env.info( "Error in SCHEDULER function:" .. errmsg )
|
||||||
if debug ~= nil then
|
if BASE.Debug ~= nil then
|
||||||
env.info( debug.traceback() )
|
env.info( debug.traceback() )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -744,13 +820,20 @@ function EVENT:onEvent( Event )
|
|||||||
|
|
||||||
local EventMeta = _EVENTMETA[Event.id]
|
local EventMeta = _EVENTMETA[Event.id]
|
||||||
|
|
||||||
|
--self:E( { EventMeta.Text, Event } ) -- Activate the see all incoming events ...
|
||||||
|
|
||||||
if self and
|
if self and
|
||||||
self.Events and
|
self.Events and
|
||||||
self.Events[Event.id] and
|
self.Events[Event.id] and
|
||||||
|
self.MissionEnd == false and
|
||||||
( Event.initiator ~= nil or ( Event.initiator == nil and Event.id ~= EVENTS.PlayerLeaveUnit ) ) then
|
( Event.initiator ~= nil or ( Event.initiator == nil and Event.id ~= EVENTS.PlayerLeaveUnit ) ) then
|
||||||
|
|
||||||
|
if Event.id and Event.id == EVENTS.MissionEnd then
|
||||||
|
self.MissionEnd = true
|
||||||
|
end
|
||||||
|
|
||||||
if Event.initiator then
|
if Event.initiator then
|
||||||
|
|
||||||
Event.IniObjectCategory = Event.initiator:getCategory()
|
Event.IniObjectCategory = Event.initiator:getCategory()
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.UNIT then
|
if Event.IniObjectCategory == Object.Category.UNIT then
|
||||||
@@ -787,6 +870,16 @@ function EVENT:onEvent( Event )
|
|||||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Event.IniObjectCategory == Object.Category.CARGO then
|
||||||
|
Event.IniDCSUnit = Event.initiator
|
||||||
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
|
Event.IniUnit = CARGO:FindByName( Event.IniDCSUnitName )
|
||||||
|
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||||
|
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||||
|
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||||
|
end
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.SCENERY then
|
if Event.IniObjectCategory == Object.Category.SCENERY then
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
@@ -825,7 +918,7 @@ function EVENT:onEvent( Event )
|
|||||||
Event.TgtDCSUnit = Event.target
|
Event.TgtDCSUnit = Event.target
|
||||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
||||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||||
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName )
|
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
|
||||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||||
@@ -852,17 +945,40 @@ function EVENT:onEvent( Event )
|
|||||||
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
|
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Place should be given for takeoff and landing events as well as base captured. It should be a DCS airbase.
|
||||||
|
if Event.place then
|
||||||
|
Event.Place=AIRBASE:Find(Event.place)
|
||||||
|
Event.PlaceName=Event.Place:GetName()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- @FC: something like this should be added.
|
||||||
|
--[[
|
||||||
|
if Event.idx then
|
||||||
|
Event.MarkID=Event.idx
|
||||||
|
Event.MarkVec3=Event.pos
|
||||||
|
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
|
||||||
|
Event.MarkText=Event.text
|
||||||
|
Event.MarkCoalition=Event.coalition
|
||||||
|
Event.MarkGroupID = Event.groupID
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
if Event.cargo then
|
if Event.cargo then
|
||||||
Event.Cargo = Event.cargo
|
Event.Cargo = Event.cargo
|
||||||
Event.CargoName = Event.cargo.Name
|
Event.CargoName = Event.cargo.Name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Event.zone then
|
||||||
|
Event.Zone = Event.zone
|
||||||
|
Event.ZoneName = Event.zone.ZoneName
|
||||||
|
end
|
||||||
|
|
||||||
local PriorityOrder = EventMeta.Order
|
local PriorityOrder = EventMeta.Order
|
||||||
local PriorityBegin = PriorityOrder == -1 and 5 or 1
|
local PriorityBegin = PriorityOrder == -1 and 5 or 1
|
||||||
local PriorityEnd = PriorityOrder == -1 and 1 or 5
|
local PriorityEnd = PriorityOrder == -1 and 1 or 5
|
||||||
|
|
||||||
if Event.IniObjectCategory ~= Object.Category.STATIC then
|
if Event.IniObjectCategory ~= Object.Category.STATIC then
|
||||||
self:E( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } )
|
self:T( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } )
|
||||||
end
|
end
|
||||||
|
|
||||||
for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do
|
for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do
|
||||||
@@ -871,7 +987,7 @@ function EVENT:onEvent( Event )
|
|||||||
|
|
||||||
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
|
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
|
||||||
for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do
|
for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do
|
||||||
|
|
||||||
--if Event.IniObjectCategory ~= Object.Category.STATIC then
|
--if Event.IniObjectCategory ~= Object.Category.STATIC then
|
||||||
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
|
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
|
||||||
--end
|
--end
|
||||||
@@ -884,8 +1000,10 @@ function EVENT:onEvent( Event )
|
|||||||
|
|
||||||
-- So now the EventClass must be a UNIT class!!! We check if it is still "Alive".
|
-- So now the EventClass must be a UNIT class!!! We check if it is still "Alive".
|
||||||
if EventClass:IsAlive() or
|
if EventClass:IsAlive() or
|
||||||
|
Event.id == EVENTS.PlayerEnterUnit or
|
||||||
Event.id == EVENTS.Crash or
|
Event.id == EVENTS.Crash or
|
||||||
Event.id == EVENTS.Dead then
|
Event.id == EVENTS.Dead or
|
||||||
|
Event.id == EVENTS.RemoveUnit then
|
||||||
|
|
||||||
local UnitName = EventClass:GetName()
|
local UnitName = EventClass:GetName()
|
||||||
|
|
||||||
@@ -896,7 +1014,7 @@ function EVENT:onEvent( Event )
|
|||||||
if EventData.EventFunction then
|
if EventData.EventFunction then
|
||||||
|
|
||||||
if Event.IniObjectCategory ~= 3 then
|
if Event.IniObjectCategory ~= 3 then
|
||||||
self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
|
self:F( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
|
||||||
end
|
end
|
||||||
|
|
||||||
local Result, Value = xpcall(
|
local Result, Value = xpcall(
|
||||||
@@ -912,7 +1030,7 @@ function EVENT:onEvent( Event )
|
|||||||
|
|
||||||
-- Now call the default event function.
|
-- Now call the default event function.
|
||||||
if Event.IniObjectCategory ~= 3 then
|
if Event.IniObjectCategory ~= 3 then
|
||||||
self:E( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
self:F( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
||||||
end
|
end
|
||||||
|
|
||||||
local Result, Value = xpcall(
|
local Result, Value = xpcall(
|
||||||
@@ -933,8 +1051,10 @@ function EVENT:onEvent( Event )
|
|||||||
|
|
||||||
-- So now the EventClass must be a GROUP class!!! We check if it is still "Alive".
|
-- So now the EventClass must be a GROUP class!!! We check if it is still "Alive".
|
||||||
if EventClass:IsAlive() or
|
if EventClass:IsAlive() or
|
||||||
|
Event.id == EVENTS.PlayerEnterUnit or
|
||||||
Event.id == EVENTS.Crash or
|
Event.id == EVENTS.Crash or
|
||||||
Event.id == EVENTS.Dead then
|
Event.id == EVENTS.Dead or
|
||||||
|
Event.id == EVENTS.RemoveUnit then
|
||||||
|
|
||||||
-- We can get the name of the EventClass, which is now always a GROUP object.
|
-- We can get the name of the EventClass, which is now always a GROUP object.
|
||||||
local GroupName = EventClass:GetName()
|
local GroupName = EventClass:GetName()
|
||||||
@@ -946,7 +1066,7 @@ function EVENT:onEvent( Event )
|
|||||||
if EventData.EventFunction then
|
if EventData.EventFunction then
|
||||||
|
|
||||||
if Event.IniObjectCategory ~= 3 then
|
if Event.IniObjectCategory ~= 3 then
|
||||||
self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
|
self:F( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
|
||||||
end
|
end
|
||||||
|
|
||||||
local Result, Value = xpcall(
|
local Result, Value = xpcall(
|
||||||
@@ -962,7 +1082,7 @@ function EVENT:onEvent( Event )
|
|||||||
|
|
||||||
-- Now call the default event function.
|
-- Now call the default event function.
|
||||||
if Event.IniObjectCategory ~= 3 then
|
if Event.IniObjectCategory ~= 3 then
|
||||||
self:E( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
|
self:F( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
|
||||||
end
|
end
|
||||||
|
|
||||||
local Result, Value = xpcall(
|
local Result, Value = xpcall(
|
||||||
@@ -1018,8 +1138,18 @@ function EVENT:onEvent( Event )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- When cargo was deleted, it may probably be because of an S_EVENT_DEAD.
|
||||||
|
-- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call.
|
||||||
|
-- And this is a problem because it will remove all entries from the SET_CARGOs.
|
||||||
|
-- To prevent this from happening, the Cargo object has a flag NoDestroy.
|
||||||
|
-- When true, the SET_CARGO won't Remove the Cargo object from the set.
|
||||||
|
-- But we need to switch that flag off after the event handlers have been called.
|
||||||
|
if Event.id == EVENTS.DeleteCargo then
|
||||||
|
Event.Cargo.NoDestroy = nil
|
||||||
|
end
|
||||||
else
|
else
|
||||||
self:E( { EventMeta.Text, Event } )
|
self:T( { EventMeta.Text, Event } )
|
||||||
end
|
end
|
||||||
|
|
||||||
Event = nil
|
Event = nil
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
--- **Core** -- The **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes
|
--- **Core** -- The **FSM** (**F**inite **S**tate **M**achine) class and derived **FSM\_** classes
|
||||||
-- are design patterns allowing efficient (long-lasting) processes and workflows.
|
-- are design patterns allowing efficient (long-lasting) processes and workflows.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**.
|
-- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**.
|
||||||
@@ -52,19 +50,20 @@
|
|||||||
--
|
--
|
||||||
-- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s.
|
-- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s.
|
||||||
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s.
|
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s.
|
||||||
-- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Controllable}s, which are @{Group}s, @{Unit}s, @{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_SET}: Models Finite State Machines for @{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.
|
-- for multiple objects or the position of the state machine in the process.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Fsm
|
-- @module Core.Fsm
|
||||||
|
-- @image Core_Finite_State_Machine.JPG
|
||||||
|
|
||||||
do -- FSM
|
do -- FSM
|
||||||
|
|
||||||
@@ -72,9 +71,7 @@ do -- FSM
|
|||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
--- # FSM class, extends @{Base#BASE}
|
--- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**.
|
||||||
--
|
|
||||||
-- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**.
|
|
||||||
--
|
--
|
||||||
-- A FSM can only be in one of a finite number of states.
|
-- A FSM can only be in one of a finite number of states.
|
||||||
-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**.
|
-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**.
|
||||||
@@ -328,7 +325,7 @@ do -- FSM
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @field #FSM FSM
|
-- @field #FSM
|
||||||
--
|
--
|
||||||
FSM = {
|
FSM = {
|
||||||
ClassName = "FSM",
|
ClassName = "FSM",
|
||||||
@@ -337,7 +334,7 @@ do -- FSM
|
|||||||
--- Creates a new FSM object.
|
--- Creates a new FSM object.
|
||||||
-- @param #FSM self
|
-- @param #FSM self
|
||||||
-- @return #FSM
|
-- @return #FSM
|
||||||
function FSM:New( FsmT )
|
function FSM:New()
|
||||||
|
|
||||||
-- Inherits from BASE
|
-- Inherits from BASE
|
||||||
self = BASE:Inherit( self, BASE:New() )
|
self = BASE:Inherit( self, BASE:New() )
|
||||||
@@ -410,7 +407,7 @@ do -- FSM
|
|||||||
return self._Transitions or {}
|
return self._Transitions or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Controllable} by the task.
|
--- 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.
|
||||||
-- @param #FSM self
|
-- @param #FSM self
|
||||||
-- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states.
|
-- @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.
|
-- @param #string Event The Event name.
|
||||||
@@ -441,6 +438,8 @@ do -- FSM
|
|||||||
-- @return #table
|
-- @return #table
|
||||||
function FSM:GetProcesses()
|
function FSM:GetProcesses()
|
||||||
|
|
||||||
|
self:F( { Processes = self._Processes } )
|
||||||
|
|
||||||
return self._Processes or {}
|
return self._Processes or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -455,6 +454,18 @@ do -- FSM
|
|||||||
error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" )
|
error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function FSM:SetProcess( From, Event, Fsm )
|
||||||
|
|
||||||
|
for ProcessID, Process in pairs( self:GetProcesses() ) do
|
||||||
|
if Process.From == From and Process.Event == Event then
|
||||||
|
Process.fsm = Fsm
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
error( "Sub-Process from state " .. From .. " with event " .. Event .. " not found!" )
|
||||||
|
end
|
||||||
|
|
||||||
--- Adds an End state.
|
--- Adds an End state.
|
||||||
function FSM:AddEndState( State )
|
function FSM:AddEndState( State )
|
||||||
|
|
||||||
@@ -557,95 +568,130 @@ do -- FSM
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function FSM:_call_handler( handler, params, EventName )
|
function FSM:_call_handler( step, trigger, params, EventName )
|
||||||
|
|
||||||
|
local handler = step .. trigger
|
||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
|
|
||||||
env.info( "Error in SCHEDULER function:" .. errmsg )
|
env.info( "Error in SCHEDULER function:" .. errmsg )
|
||||||
if debug ~= nil then
|
if BASE.Debug ~= nil then
|
||||||
env.info( debug.traceback() )
|
env.info( BASE.Debug.traceback() )
|
||||||
end
|
end
|
||||||
|
|
||||||
return errmsg
|
return errmsg
|
||||||
end
|
end
|
||||||
if self[handler] then
|
if self[handler] then
|
||||||
self:T2( "Calling " .. handler )
|
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] )
|
||||||
self._EventSchedules[EventName] = nil
|
self._EventSchedules[EventName] = nil
|
||||||
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
|
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
|
||||||
return Value
|
return Value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- @param #FSM self
|
||||||
function FSM._handler( self, EventName, ... )
|
function FSM._handler( self, EventName, ... )
|
||||||
|
|
||||||
local Can, to = self:can( EventName )
|
local Can, To = self:can( EventName )
|
||||||
|
|
||||||
if to == "*" then
|
if To == "*" then
|
||||||
to = self.current
|
To = self.current
|
||||||
end
|
end
|
||||||
|
|
||||||
if Can then
|
if Can then
|
||||||
local from = self.current
|
local From = self.current
|
||||||
local params = { from, EventName, to, ... }
|
local Params = { From, EventName, To, ... }
|
||||||
|
|
||||||
if self.Controllable then
|
|
||||||
self:T( "FSM Transition for " .. self.Controllable.ControllableName .. " :" .. self.current .. " --> " .. EventName .. " --> " .. to )
|
if self["onleave".. From] or
|
||||||
|
self["OnLeave".. From] or
|
||||||
|
self["onbefore".. EventName] or
|
||||||
|
self["OnBefore".. EventName] or
|
||||||
|
self["onafter".. EventName] or
|
||||||
|
self["OnAfter".. EventName] or
|
||||||
|
self["onenter".. To] or
|
||||||
|
self["OnEnter".. To]
|
||||||
|
then
|
||||||
|
if self:_call_handler( "onbefore", EventName, Params, EventName ) == false then
|
||||||
|
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onbefore" .. EventName )
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
if self:_call_handler( "OnBefore", EventName, Params, EventName ) == false then
|
||||||
|
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** OnBefore" .. EventName )
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
if self:_call_handler( "onleave", From, Params, EventName ) == false then
|
||||||
|
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onleave" .. From )
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
if self:_call_handler( "OnLeave", From, Params, EventName ) == false then
|
||||||
|
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** OnLeave" .. From )
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
else
|
else
|
||||||
self:T( "FSM Transition:" .. self.current .. " --> " .. EventName .. " --> " .. to )
|
local ClassName = self:GetClassName()
|
||||||
end
|
if ClassName == "FSM" then
|
||||||
|
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To )
|
||||||
|
end
|
||||||
|
|
||||||
if ( self:_call_handler("onbefore" .. EventName, params, EventName ) == false )
|
if ClassName == "FSM_TASK" then
|
||||||
or ( self:_call_handler("OnBefore" .. EventName, params, EventName ) == false )
|
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** Task: " .. self.TaskName )
|
||||||
or ( self:_call_handler("onleave" .. from, params, EventName ) == false )
|
end
|
||||||
or ( self:_call_handler("OnLeave" .. from, params, EventName ) == false ) then
|
|
||||||
self:T( "Cancel Transition" )
|
if ClassName == "FSM_CONTROLLABLE" then
|
||||||
return false
|
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** TaskUnit: " .. self.Controllable.ControllableName .. " *** " )
|
||||||
|
end
|
||||||
|
|
||||||
|
if ClassName == "FSM_PROCESS" then
|
||||||
|
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** Task: " .. self.Task:GetName() .. ", TaskUnit: " .. self.Controllable.ControllableName .. " *** " )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.current = to
|
self.current = To
|
||||||
|
|
||||||
local execute = true
|
local execute = true
|
||||||
|
|
||||||
local subtable = self:_gosub( from, EventName )
|
local subtable = self:_gosub( From, EventName )
|
||||||
for _, sub in pairs( subtable ) do
|
for _, sub in pairs( subtable ) do
|
||||||
--if sub.nextevent then
|
--if sub.nextevent then
|
||||||
-- self:F2( "nextevent = " .. sub.nextevent )
|
-- self:F2( "nextevent = " .. sub.nextevent )
|
||||||
-- self[sub.nextevent]( self )
|
-- self[sub.nextevent]( self )
|
||||||
--end
|
--end
|
||||||
self:T( "calling sub start event: " .. sub.StartEvent )
|
self:T( "*** FSM *** Sub *** " .. sub.StartEvent )
|
||||||
sub.fsm.fsmparent = self
|
sub.fsm.fsmparent = self
|
||||||
sub.fsm.ReturnEvents = sub.ReturnEvents
|
sub.fsm.ReturnEvents = sub.ReturnEvents
|
||||||
sub.fsm[sub.StartEvent]( sub.fsm )
|
sub.fsm[sub.StartEvent]( sub.fsm )
|
||||||
execute = false
|
execute = false
|
||||||
end
|
end
|
||||||
|
|
||||||
local fsmparent, Event = self:_isendstate( to )
|
local fsmparent, Event = self:_isendstate( To )
|
||||||
if fsmparent and Event then
|
if fsmparent and Event then
|
||||||
self:F2( { "end state: ", fsmparent, Event } )
|
self:T( "*** FSM *** End *** " .. Event )
|
||||||
self:_call_handler("onenter" .. to, params, EventName )
|
self:_call_handler("onenter", To, Params, EventName )
|
||||||
self:_call_handler("OnEnter" .. to, params, EventName )
|
self:_call_handler("OnEnter", To, Params, EventName )
|
||||||
self:_call_handler("onafter" .. EventName, params, EventName )
|
self:_call_handler("onafter", EventName, Params, EventName )
|
||||||
self:_call_handler("OnAfter" .. EventName, params, EventName )
|
self:_call_handler("OnAfter", EventName, Params, EventName )
|
||||||
self:_call_handler("onstatechange", params, EventName )
|
self:_call_handler("onstate", "change", Params, EventName )
|
||||||
fsmparent[Event]( fsmparent )
|
fsmparent[Event]( fsmparent )
|
||||||
execute = false
|
execute = false
|
||||||
end
|
end
|
||||||
|
|
||||||
if execute then
|
if execute then
|
||||||
|
self:_call_handler("onafter", EventName, Params, EventName )
|
||||||
|
self:_call_handler("OnAfter", EventName, Params, EventName )
|
||||||
|
|
||||||
-- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute!
|
-- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute!
|
||||||
--if from ~= to then
|
--if from ~= to then
|
||||||
self:_call_handler("onenter" .. to, params, EventName )
|
self:_call_handler("onenter", To, Params, EventName )
|
||||||
self:_call_handler("OnEnter" .. to, params, EventName )
|
self:_call_handler("OnEnter", To, Params, EventName )
|
||||||
--end
|
--end
|
||||||
|
|
||||||
self:_call_handler("onafter" .. EventName, params, EventName )
|
self:_call_handler("onstate", "change", Params, EventName )
|
||||||
self:_call_handler("OnAfter" .. EventName, params, EventName )
|
|
||||||
|
|
||||||
self:_call_handler("onstatechange", params, EventName )
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:T( "Cannot execute transition." )
|
self:T( "*** FSM *** NO Transition *** " .. self.current .. " --> " .. EventName .. " --> ? " )
|
||||||
self:T( { From = self.current, Event = EventName, To = to, Can = Can } )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -691,17 +737,16 @@ do -- FSM
|
|||||||
function FSM:_isendstate( Current )
|
function FSM:_isendstate( Current )
|
||||||
local FSMParent = self.fsmparent
|
local FSMParent = self.fsmparent
|
||||||
if FSMParent and self.endstates[Current] then
|
if FSMParent and self.endstates[Current] then
|
||||||
self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } )
|
--self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } )
|
||||||
FSMParent.current = Current
|
FSMParent.current = Current
|
||||||
local ParentFrom = FSMParent.current
|
local ParentFrom = FSMParent.current
|
||||||
self:T( ParentFrom )
|
--self:T( { ParentFrom, self.ReturnEvents } )
|
||||||
self:T( self.ReturnEvents )
|
|
||||||
local Event = self.ReturnEvents[Current]
|
local Event = self.ReturnEvents[Current]
|
||||||
self:T( { ParentFrom, Event, self.ReturnEvents } )
|
--self:T( { Event } )
|
||||||
if Event then
|
if Event then
|
||||||
return FSMParent, Event
|
return FSMParent, Event
|
||||||
else
|
else
|
||||||
self:T( { "Could not find parent event name for state ", ParentFrom } )
|
--self:T( { "Could not find parent event name for state ", ParentFrom } )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -724,6 +769,10 @@ do -- FSM
|
|||||||
return self.current
|
return self.current
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function FSM:GetCurrentState()
|
||||||
|
return self.current
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function FSM:Is( State )
|
function FSM:Is( State )
|
||||||
return self.current == State
|
return self.current == State
|
||||||
@@ -752,14 +801,11 @@ do -- FSM_CONTROLLABLE
|
|||||||
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- # FSM_CONTROLLABLE, extends @{#FSM}
|
--- Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s.
|
||||||
--
|
|
||||||
-- FSM_CONTROLLABLE class models Finite State Machines for @{Controllable}s, which are @{Group}s, @{Unit}s, @{Client}s.
|
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @field #FSM_CONTROLLABLE FSM_CONTROLLABLE
|
-- @field #FSM_CONTROLLABLE
|
||||||
--
|
|
||||||
FSM_CONTROLLABLE = {
|
FSM_CONTROLLABLE = {
|
||||||
ClassName = "FSM_CONTROLLABLE",
|
ClassName = "FSM_CONTROLLABLE",
|
||||||
}
|
}
|
||||||
@@ -769,10 +815,10 @@ do -- FSM_CONTROLLABLE
|
|||||||
-- @param #table FSMT Finite State Machine Table
|
-- @param #table FSMT Finite State Machine Table
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable (optional) The CONTROLLABLE object that the FSM_CONTROLLABLE governs.
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable (optional) The CONTROLLABLE object that the FSM_CONTROLLABLE governs.
|
||||||
-- @return #FSM_CONTROLLABLE
|
-- @return #FSM_CONTROLLABLE
|
||||||
function FSM_CONTROLLABLE:New( FSMT, Controllable )
|
function FSM_CONTROLLABLE:New( Controllable )
|
||||||
|
|
||||||
-- Inherits from BASE
|
-- Inherits from BASE
|
||||||
local self = BASE:Inherit( self, FSM:New( FSMT ) ) -- Core.Fsm#FSM_CONTROLLABLE
|
local self = BASE:Inherit( self, FSM:New() ) -- Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
if Controllable then
|
if Controllable then
|
||||||
self:SetControllable( Controllable )
|
self:SetControllable( Controllable )
|
||||||
@@ -855,20 +901,22 @@ do -- FSM_CONTROLLABLE
|
|||||||
return self.Controllable
|
return self.Controllable
|
||||||
end
|
end
|
||||||
|
|
||||||
function FSM_CONTROLLABLE:_call_handler( handler, params, EventName )
|
function FSM_CONTROLLABLE:_call_handler( step, trigger, params, EventName )
|
||||||
|
|
||||||
|
local handler = step .. trigger
|
||||||
|
|
||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
|
|
||||||
env.info( "Error in SCHEDULER function:" .. errmsg )
|
env.info( "Error in SCHEDULER function:" .. errmsg )
|
||||||
if debug ~= nil then
|
if BASE.Debug ~= nil then
|
||||||
env.info( debug.traceback() )
|
env.info( BASE.Debug.traceback() )
|
||||||
end
|
end
|
||||||
|
|
||||||
return errmsg
|
return errmsg
|
||||||
end
|
end
|
||||||
|
|
||||||
if self[handler] then
|
if self[handler] then
|
||||||
self:F3( "Calling " .. handler )
|
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** TaskUnit: " .. self.Controllable:GetName() )
|
||||||
self._EventSchedules[EventName] = nil
|
self._EventSchedules[EventName] = nil
|
||||||
local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler )
|
local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler )
|
||||||
return Value
|
return Value
|
||||||
@@ -885,9 +933,7 @@ do -- FSM_PROCESS
|
|||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
|
|
||||||
--- # FSM_PROCESS, extends @{#FSM}
|
--- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s.
|
||||||
--
|
|
||||||
-- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s.
|
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -905,9 +951,9 @@ do -- FSM_PROCESS
|
|||||||
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS
|
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS
|
||||||
|
|
||||||
--self:F( Controllable )
|
--self:F( Controllable )
|
||||||
|
|
||||||
self:Assign( Controllable, Task )
|
self:Assign( Controllable, Task )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -915,22 +961,29 @@ do -- FSM_PROCESS
|
|||||||
self:T( "No Initialisation" )
|
self:T( "No Initialisation" )
|
||||||
end
|
end
|
||||||
|
|
||||||
function FSM_PROCESS:_call_handler( handler, params, EventName )
|
function FSM_PROCESS:_call_handler( step, trigger, params, EventName )
|
||||||
|
|
||||||
|
local handler = step .. trigger
|
||||||
|
|
||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
|
|
||||||
env.info( "Error in FSM_PROCESS call handler:" .. errmsg )
|
env.info( "Error in FSM_PROCESS call handler:" .. errmsg )
|
||||||
if debug ~= nil then
|
if BASE.Debug ~= nil then
|
||||||
env.info( debug.traceback() )
|
env.info( BASE.Debug.traceback() )
|
||||||
end
|
end
|
||||||
|
|
||||||
return errmsg
|
return errmsg
|
||||||
end
|
end
|
||||||
|
|
||||||
if self[handler] then
|
if self[handler] then
|
||||||
self:F3( "Calling " .. handler )
|
if handler ~= "onstatechange" then
|
||||||
|
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** Task: " .. self.Task:GetName() .. ", TaskUnit: " .. self.Controllable:GetName() )
|
||||||
|
end
|
||||||
self._EventSchedules[EventName] = nil
|
self._EventSchedules[EventName] = nil
|
||||||
local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler )
|
local Result, Value
|
||||||
|
if self.Controllable and self.Controllable:IsAlive() == true then
|
||||||
|
Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler )
|
||||||
|
end
|
||||||
return Value
|
return Value
|
||||||
--return self[handler]( self, self.Controllable, unpack( params ) )
|
--return self[handler]( self, self.Controllable, unpack( params ) )
|
||||||
end
|
end
|
||||||
@@ -946,7 +999,7 @@ do -- FSM_PROCESS
|
|||||||
local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS
|
local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS
|
||||||
|
|
||||||
NewFsm:Assign( Controllable, Task )
|
NewFsm:Assign( Controllable, Task )
|
||||||
|
|
||||||
-- Polymorphic call to initialize the new FSM_PROCESS based on self FSM_PROCESS
|
-- Polymorphic call to initialize the new FSM_PROCESS based on self FSM_PROCESS
|
||||||
NewFsm:Init( self )
|
NewFsm:Init( self )
|
||||||
|
|
||||||
@@ -1037,26 +1090,26 @@ do -- FSM_PROCESS
|
|||||||
-- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP.
|
-- 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 @{Task} to the Group of the Unit.
|
||||||
-- @param #FSM_PROCESS self
|
-- @param #FSM_PROCESS self
|
||||||
function FSM_PROCESS:Message( Message )
|
function FSM_PROCESS:Message( Message )
|
||||||
self:F( { Message = Message } )
|
self:F( { Message = Message } )
|
||||||
|
|
||||||
local CC = self:GetCommandCenter()
|
|
||||||
local TaskGroup = self.Controllable:GetGroup()
|
|
||||||
|
|
||||||
local PlayerName = self.Controllable:GetPlayerName() -- Only for a unit
|
local CC = self:GetCommandCenter()
|
||||||
PlayerName = PlayerName and " (" .. PlayerName .. ")" or "" -- If PlayerName is nil, then keep it nil, otherwise add brackets.
|
local TaskGroup = self.Controllable:GetGroup()
|
||||||
local Callsign = self.Controllable:GetCallsign()
|
|
||||||
local Prefix = Callsign and " @ " .. Callsign .. PlayerName or ""
|
local PlayerName = self.Controllable:GetPlayerName() -- Only for a unit
|
||||||
|
PlayerName = PlayerName and " (" .. PlayerName .. ")" or "" -- If PlayerName is nil, then keep it nil, otherwise add brackets.
|
||||||
Message = Prefix .. ": " .. Message
|
local Callsign = self.Controllable:GetCallsign()
|
||||||
CC:MessageToGroup( Message, TaskGroup )
|
local Prefix = Callsign and " @ " .. Callsign .. PlayerName or ""
|
||||||
end
|
|
||||||
|
Message = Prefix .. ": " .. Message
|
||||||
|
CC:MessageToGroup( Message, TaskGroup )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Assign the process to a @{Unit} and activate the process.
|
--- Assign the process to a @{Wrapper.Unit} and activate the process.
|
||||||
-- @param #FSM_PROCESS self
|
-- @param #FSM_PROCESS self
|
||||||
-- @param Task.Tasking#TASK Task
|
-- @param Task.Tasking#TASK Task
|
||||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||||
@@ -1072,14 +1125,16 @@ end
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function FSM_PROCESS:onenterAssigned( ProcessUnit )
|
-- function FSM_PROCESS:onenterAssigned( ProcessUnit, Task, From, Event, To )
|
||||||
self:T( "Assign" )
|
--
|
||||||
|
-- if From( "Planned" ) then
|
||||||
|
-- self:T( "*** FSM *** Assign *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
|
||||||
|
-- self.Task:Assign()
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
self.Task:Assign()
|
function FSM_PROCESS:onenterFailed( ProcessUnit, Task, From, Event, To )
|
||||||
end
|
self:T( "*** FSM *** Failed *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
|
||||||
|
|
||||||
function FSM_PROCESS:onenterFailed( ProcessUnit )
|
|
||||||
self:T( "Failed" )
|
|
||||||
|
|
||||||
self.Task:Fail()
|
self.Task:Fail()
|
||||||
end
|
end
|
||||||
@@ -1091,14 +1146,17 @@ end
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function FSM_PROCESS:onstatechange( ProcessUnit, Task, From, Event, To, Dummy )
|
function FSM_PROCESS:onstatechange( ProcessUnit, Task, From, Event, To )
|
||||||
self:T( { ProcessUnit:GetName(), From, Event, To, Dummy, self:IsTrace() } )
|
|
||||||
|
|
||||||
if self:IsTrace() then
|
if From ~= To then
|
||||||
--MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll()
|
self:T( "*** FSM *** Change *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T( { Scores = self._Scores, To = To } )
|
-- if self:IsTrace() then
|
||||||
|
-- MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll()
|
||||||
|
-- self:F2( { Scores = self._Scores, To = To } )
|
||||||
|
-- end
|
||||||
|
|
||||||
-- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects...
|
-- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects...
|
||||||
if self._Scores[To] then
|
if self._Scores[To] then
|
||||||
|
|
||||||
@@ -1119,9 +1177,7 @@ do -- FSM_TASK
|
|||||||
-- @field Tasking.Task#TASK Task
|
-- @field Tasking.Task#TASK Task
|
||||||
-- @extends #FSM
|
-- @extends #FSM
|
||||||
|
|
||||||
--- # FSM_TASK, extends @{#FSM}
|
--- Models Finite State Machines for @{Tasking.Task}s.
|
||||||
--
|
|
||||||
-- FSM_TASK class models Finite State Machines for @{Task}s.
|
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -1133,24 +1189,37 @@ do -- FSM_TASK
|
|||||||
|
|
||||||
--- Creates a new FSM_TASK object.
|
--- Creates a new FSM_TASK object.
|
||||||
-- @param #FSM_TASK self
|
-- @param #FSM_TASK self
|
||||||
-- @param #table FSMT
|
-- @param #string TaskName The name of the task.
|
||||||
-- @param Tasking.Task#TASK Task
|
|
||||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
|
||||||
-- @return #FSM_TASK
|
-- @return #FSM_TASK
|
||||||
function FSM_TASK:New( FSMT )
|
function FSM_TASK:New( TaskName )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( FSMT ) ) -- Core.Fsm#FSM_TASK
|
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_TASK
|
||||||
|
|
||||||
self["onstatechange"] = self.OnStateChange
|
self["onstatechange"] = self.OnStateChange
|
||||||
|
self.TaskName = TaskName
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function FSM_TASK:_call_handler( handler, params, EventName )
|
function FSM_TASK:_call_handler( step, trigger, params, EventName )
|
||||||
|
local handler = step .. trigger
|
||||||
|
|
||||||
|
local ErrorHandler = function( errmsg )
|
||||||
|
|
||||||
|
env.info( "Error in SCHEDULER function:" .. errmsg )
|
||||||
|
if BASE.Debug ~= nil then
|
||||||
|
env.info( BASE.Debug.traceback() )
|
||||||
|
end
|
||||||
|
|
||||||
|
return errmsg
|
||||||
|
end
|
||||||
|
|
||||||
if self[handler] then
|
if self[handler] then
|
||||||
self:T( "Calling " .. handler )
|
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** Task: " .. self.TaskName )
|
||||||
self._EventSchedules[EventName] = nil
|
self._EventSchedules[EventName] = nil
|
||||||
return self[handler]( self, unpack( params ) )
|
--return self[handler]( self, unpack( params ) )
|
||||||
|
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
|
||||||
|
return Value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1164,9 +1233,7 @@ do -- FSM_SET
|
|||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
--- # FSM_SET, extends @{#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 @{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.
|
-- for multiple objects or the position of the state machine in the process.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -1210,9 +1277,10 @@ do -- FSM_SET
|
|||||||
return self.Controllable
|
return self.Controllable
|
||||||
end
|
end
|
||||||
|
|
||||||
function FSM_SET:_call_handler( handler, params, EventName )
|
function FSM_SET:_call_handler( step, trigger, params, EventName )
|
||||||
|
local handler = step .. trigger
|
||||||
if self[handler] then
|
if self[handler] then
|
||||||
self:T( "Calling " .. handler )
|
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] )
|
||||||
self._EventSchedules[EventName] = nil
|
self._EventSchedules[EventName] = nil
|
||||||
return self[handler]( self, self.Set, unpack( params ) )
|
return self[handler]( self, self.Set, unpack( params ) )
|
||||||
end
|
end
|
||||||
|
|||||||
153
Moose Development/Moose/Core/Goal.lua
Normal file
153
Moose Development/Moose/Core/Goal.lua
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
--- **Core (WIP)** -- Base class to allow the modeling of processes to achieve Goals.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Core.Goal
|
||||||
|
-- @image Core_Goal.JPG
|
||||||
|
|
||||||
|
do -- Goal
|
||||||
|
|
||||||
|
--- @type GOAL
|
||||||
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
|
--- Models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
|
||||||
|
--
|
||||||
|
-- ## 1. GOAL constructor
|
||||||
|
--
|
||||||
|
-- * @{#GOAL.New}(): Creates a new GOAL object.
|
||||||
|
--
|
||||||
|
-- ## 2. GOAL is a finite state machine (FSM).
|
||||||
|
--
|
||||||
|
-- ### 2.1 GOAL States
|
||||||
|
--
|
||||||
|
-- * **Pending**: The goal object is in progress.
|
||||||
|
-- * **Achieved**: The goal objective is Achieved.
|
||||||
|
--
|
||||||
|
-- ### 2.2 GOAL Events
|
||||||
|
--
|
||||||
|
-- * **Achieved**: Set the goal objective to Achieved.
|
||||||
|
--
|
||||||
|
-- @field #GOAL
|
||||||
|
GOAL = {
|
||||||
|
ClassName = "GOAL",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- @field #table GOAL.Players
|
||||||
|
GOAL.Players = {}
|
||||||
|
|
||||||
|
--- @field #number GOAL.TotalContributions
|
||||||
|
GOAL.TotalContributions = 0
|
||||||
|
|
||||||
|
--- GOAL Constructor.
|
||||||
|
-- @param #GOAL self
|
||||||
|
-- @return #GOAL
|
||||||
|
function GOAL:New()
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, FSM:New() ) -- #GOAL
|
||||||
|
self:F( {} )
|
||||||
|
|
||||||
|
--- Achieved State for GOAL
|
||||||
|
-- @field GOAL.Achieved
|
||||||
|
|
||||||
|
--- Achieved State Handler OnLeave for GOAL
|
||||||
|
-- @function [parent=#GOAL] OnLeaveAchieved
|
||||||
|
-- @param #GOAL self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Achieved State Handler OnEnter for GOAL
|
||||||
|
-- @function [parent=#GOAL] OnEnterAchieved
|
||||||
|
-- @param #GOAL self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
|
||||||
|
self:SetStartState( "Pending" )
|
||||||
|
self:AddTransition( "*", "Achieved", "Achieved" )
|
||||||
|
|
||||||
|
--- Achieved Handler OnBefore for GOAL
|
||||||
|
-- @function [parent=#GOAL] OnBeforeAchieved
|
||||||
|
-- @param #GOAL self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Achieved Handler OnAfter for GOAL
|
||||||
|
-- @function [parent=#GOAL] OnAfterAchieved
|
||||||
|
-- @param #GOAL self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
--- Achieved Trigger for GOAL
|
||||||
|
-- @function [parent=#GOAL] Achieved
|
||||||
|
-- @param #GOAL self
|
||||||
|
|
||||||
|
--- Achieved Asynchronous Trigger for GOAL
|
||||||
|
-- @function [parent=#GOAL] __Achieved
|
||||||
|
-- @param #GOAL self
|
||||||
|
-- @param #number Delay
|
||||||
|
|
||||||
|
self:SetEventPriority( 5 )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add a new contribution by a player.
|
||||||
|
-- @param #GOAL self
|
||||||
|
-- @param #string PlayerName The name of the player.
|
||||||
|
function GOAL:AddPlayerContribution( PlayerName )
|
||||||
|
self.Players[PlayerName] = self.Players[PlayerName] or 0
|
||||||
|
self.Players[PlayerName] = self.Players[PlayerName] + 1
|
||||||
|
self.TotalContributions = self.TotalContributions + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #GOAL self
|
||||||
|
-- @param #number Player contribution.
|
||||||
|
function GOAL:GetPlayerContribution( PlayerName )
|
||||||
|
return self.Players[PlayerName] or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the players who contributed to achieve the goal.
|
||||||
|
-- The result is a list of players, sorted by the name of the players.
|
||||||
|
-- @param #GOAL self
|
||||||
|
-- @return #list The list of players, indexed by the player name.
|
||||||
|
function GOAL:GetPlayerContributions()
|
||||||
|
return self.Players or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Gets the total contributions that happened to achieve the goal.
|
||||||
|
-- The result is a number.
|
||||||
|
-- @param #GOAL self
|
||||||
|
-- @return #number The total number of contributions. 0 is returned if there were no contributions (yet).
|
||||||
|
function GOAL:GetTotalContributions()
|
||||||
|
return self.TotalContributions or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Validates if the goal is achieved.
|
||||||
|
-- @param #GOAL self
|
||||||
|
-- @return #boolean true if the goal is achieved.
|
||||||
|
function GOAL:IsAchieved()
|
||||||
|
return self:Is( "Achieved" )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +1,47 @@
|
|||||||
--- **Core** -- MESSAGE class takes are of the **real-time notifications** and **messages to players** during a simulation.
|
--- **Core** -- MESSAGE class takes are of the **real-time notifications** and **messages to players** during a simulation.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Message
|
-- @module Core.Message
|
||||||
|
-- @image Core_Message.JPG
|
||||||
|
|
||||||
--- The MESSAGE class
|
--- The MESSAGE class
|
||||||
-- @type MESSAGE
|
-- @type MESSAGE
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- # MESSAGE class, extends @{Base#BASE}
|
--- Message System to display Messages to Clients, Coalitions or All.
|
||||||
--
|
|
||||||
-- Message System to display Messages to Clients, Coalitions or All.
|
|
||||||
-- Messages are shown on the display panel for an amount of seconds, and will then disappear.
|
-- Messages are shown on the display panel for an amount of seconds, and will then disappear.
|
||||||
-- Messages can contain a category which is indicating the category of the message.
|
-- Messages can contain a category which is indicating the category of the message.
|
||||||
--
|
--
|
||||||
-- ## MESSAGE construction
|
-- ## MESSAGE construction
|
||||||
--
|
--
|
||||||
-- Messages are created with @{Message#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet.
|
-- Messages are created with @{#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet.
|
||||||
-- To send messages, you need to use the To functions.
|
-- To send messages, you need to use the To functions.
|
||||||
--
|
--
|
||||||
-- ## Send messages to an audience
|
-- ## Send messages to an audience
|
||||||
--
|
--
|
||||||
-- Messages are sent:
|
-- Messages are sent:
|
||||||
--
|
--
|
||||||
-- * To a @{Client} using @{Message#MESSAGE.ToClient}().
|
-- * To a @{Client} using @{#MESSAGE.ToClient}().
|
||||||
-- * To a @{Group} using @{Message#MESSAGE.ToGroup}()
|
-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}()
|
||||||
-- * To a coalition using @{Message#MESSAGE.ToCoalition}().
|
-- * To a coalition using @{#MESSAGE.ToCoalition}().
|
||||||
-- * To the red coalition using @{Message#MESSAGE.ToRed}().
|
-- * To the red coalition using @{#MESSAGE.ToRed}().
|
||||||
-- * To the blue coalition using @{Message#MESSAGE.ToBlue}().
|
-- * To the blue coalition using @{#MESSAGE.ToBlue}().
|
||||||
-- * To all Players using @{Message#MESSAGE.ToAll}().
|
-- * To all Players using @{#MESSAGE.ToAll}().
|
||||||
--
|
--
|
||||||
-- ## Send conditionally to an audience
|
-- ## Send conditionally to an audience
|
||||||
--
|
--
|
||||||
-- Messages can be sent conditionally to an audience (when a condition is true):
|
-- Messages can be sent conditionally to an audience (when a condition is true):
|
||||||
--
|
--
|
||||||
-- * To all players using @{Message#MESSAGE.ToAllIf}().
|
-- * To all players using @{#MESSAGE.ToAllIf}().
|
||||||
-- * To a coalition using @{Message#MESSAGE.ToCoalitionIf}().
|
-- * To a coalition using @{#MESSAGE.ToCoalitionIf}().
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @field #MESSAGE
|
-- @field #MESSAGE
|
||||||
MESSAGE = {
|
MESSAGE = {
|
||||||
@@ -69,6 +66,7 @@ MESSAGE.Type = {
|
|||||||
-- @param #string MessageText is the text of the Message.
|
-- @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 #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 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 #boolean ClearScreen (optional) Clear all previous messages if true.
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Create a series of new Messages.
|
-- -- Create a series of new Messages.
|
||||||
@@ -80,7 +78,7 @@ MESSAGE.Type = {
|
|||||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
|
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
|
||||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
|
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
|
||||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
|
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
|
||||||
function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
|
function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen )
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, BASE:New() )
|
||||||
self:F( { MessageText, MessageDuration, MessageCategory } )
|
self:F( { MessageText, MessageDuration, MessageCategory } )
|
||||||
|
|
||||||
@@ -97,6 +95,11 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
|
|||||||
else
|
else
|
||||||
self.MessageCategory = ""
|
self.MessageCategory = ""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.ClearScreen=false
|
||||||
|
if ClearScreen~=nil then
|
||||||
|
self.ClearScreen=ClearScreen
|
||||||
|
end
|
||||||
|
|
||||||
self.MessageDuration = MessageDuration or 5
|
self.MessageDuration = MessageDuration or 5
|
||||||
self.MessageTime = timer.getTime()
|
self.MessageTime = timer.getTime()
|
||||||
@@ -117,18 +120,24 @@ end
|
|||||||
-- @param self
|
-- @param self
|
||||||
-- @param #string MessageText is the text of the Message.
|
-- @param #string MessageText is the text of the Message.
|
||||||
-- @param #MESSAGE.Type MessageType The type of the message.
|
-- @param #MESSAGE.Type MessageType The type of the message.
|
||||||
|
-- @param #boolean ClearScreen (optional) Clear all previous messages.
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE
|
||||||
-- @usage
|
-- @usage
|
||||||
-- MessageAll = MESSAGE:NewType( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", MESSAGE.Type.Information )
|
-- MessageAll = MESSAGE:NewType( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", MESSAGE.Type.Information )
|
||||||
-- MessageRED = MESSAGE:NewType( "To the RED Players: You receive a penalty because you've killed one of your own units", MESSAGE.Type.Information )
|
-- MessageRED = MESSAGE:NewType( "To the RED Players: You receive a penalty because you've killed one of your own units", MESSAGE.Type.Information )
|
||||||
-- MessageClient1 = MESSAGE:NewType( "Congratulations, you've just hit a target", MESSAGE.Type.Update )
|
-- MessageClient1 = MESSAGE:NewType( "Congratulations, you've just hit a target", MESSAGE.Type.Update )
|
||||||
-- MessageClient2 = MESSAGE:NewType( "Congratulations, you've just killed a target", MESSAGE.Type.Update )
|
-- MessageClient2 = MESSAGE:NewType( "Congratulations, you've just killed a target", MESSAGE.Type.Update )
|
||||||
function MESSAGE:NewType( MessageText, MessageType )
|
function MESSAGE:NewType( MessageText, MessageType, ClearScreen )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, BASE:New() )
|
||||||
self:F( { MessageText } )
|
self:F( { MessageText } )
|
||||||
|
|
||||||
self.MessageType = MessageType
|
self.MessageType = MessageType
|
||||||
|
|
||||||
|
self.ClearScreen=false
|
||||||
|
if ClearScreen~=nil then
|
||||||
|
self.ClearScreen=ClearScreen
|
||||||
|
end
|
||||||
|
|
||||||
self.MessageTime = timer.getTime()
|
self.MessageTime = timer.getTime()
|
||||||
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
|
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
|
||||||
@@ -138,11 +147,21 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Clears all previous messages from the screen before the new message is displayed. Not that this must come before all functions starting with ToX(), e.g. ToAll(), ToGroup() etc.
|
||||||
|
-- @param #MESSAGE self
|
||||||
|
-- @return #MESSAGE
|
||||||
|
function MESSAGE:Clear()
|
||||||
|
self:F()
|
||||||
|
self.ClearScreen=true
|
||||||
|
return self
|
||||||
|
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".
|
--- 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 #MESSAGE self
|
||||||
-- @param Wrapper.Client#CLIENT Client is the Group of the Client.
|
-- @param Wrapper.Client#CLIENT Client is the Group of the Client.
|
||||||
|
-- @param Core.Settings#SETTINGS Settings Settings used to display the message.
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Send the 2 messages created with the @{New} method to the Client Group.
|
-- -- Send the 2 messages created with the @{New} method to the Client Group.
|
||||||
@@ -167,13 +186,13 @@ function MESSAGE:ToClient( Client, Settings )
|
|||||||
if self.MessageType then
|
if self.MessageType then
|
||||||
local Settings = Settings or ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
self.MessageCategory = self.MessageType .. ": "
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.MessageDuration ~= 0 then
|
if self.MessageDuration ~= 0 then
|
||||||
local ClientGroupID = Client:GetClientGroupID()
|
local ClientGroupID = Client:GetClientGroupID()
|
||||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
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 )
|
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -182,8 +201,8 @@ end
|
|||||||
|
|
||||||
--- Sends a MESSAGE to a Group.
|
--- Sends a MESSAGE to a Group.
|
||||||
-- @param #MESSAGE self
|
-- @param #MESSAGE self
|
||||||
-- @param Wrapper.Group#GROUP Group is the Group.
|
-- @param Wrapper.Group#GROUP Group to which the message is displayed.
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE Message object.
|
||||||
function MESSAGE:ToGroup( Group, Settings )
|
function MESSAGE:ToGroup( Group, Settings )
|
||||||
self:F( Group.GroupName )
|
self:F( Group.GroupName )
|
||||||
|
|
||||||
@@ -192,12 +211,12 @@ function MESSAGE:ToGroup( Group, Settings )
|
|||||||
if self.MessageType then
|
if self.MessageType then
|
||||||
local Settings = Settings or ( Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or ( Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
self.MessageCategory = self.MessageType .. ": "
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.MessageDuration ~= 0 then
|
if self.MessageDuration ~= 0 then
|
||||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||||
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
|
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -243,8 +262,9 @@ end
|
|||||||
|
|
||||||
--- Sends a MESSAGE to a Coalition.
|
--- Sends a MESSAGE to a Coalition.
|
||||||
-- @param #MESSAGE self
|
-- @param #MESSAGE self
|
||||||
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}.
|
-- @param #DCS.coalition.side CoalitionSide @{#DCS.coalition.side} to which the message is displayed.
|
||||||
-- @return #MESSAGE
|
-- @param Core.Settings#SETTINGS Settings (Optional) Settings for message display.
|
||||||
|
-- @return #MESSAGE Message object.
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Send a message created with the @{New} method to the RED coalition.
|
-- -- 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", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
|
||||||
@@ -259,13 +279,13 @@ function MESSAGE:ToCoalition( CoalitionSide, Settings )
|
|||||||
if self.MessageType then
|
if self.MessageType then
|
||||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
self.MessageCategory = self.MessageType .. ": "
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
end
|
end
|
||||||
|
|
||||||
if CoalitionSide then
|
if CoalitionSide then
|
||||||
if self.MessageDuration ~= 0 then
|
if self.MessageDuration ~= 0 then
|
||||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||||
trigger.action.outTextForCoalition( CoalitionSide, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
|
trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -274,8 +294,9 @@ end
|
|||||||
|
|
||||||
--- Sends a MESSAGE to a Coalition if the given Condition is true.
|
--- Sends a MESSAGE to a Coalition if the given Condition is true.
|
||||||
-- @param #MESSAGE self
|
-- @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 @{coalition.side}.
|
||||||
-- @return #MESSAGE
|
-- @param #boolean Condition Sends the message only if the condition is true.
|
||||||
|
-- @return #MESSAGE self
|
||||||
function MESSAGE:ToCoalitionIf( CoalitionSide, Condition )
|
function MESSAGE:ToCoalitionIf( CoalitionSide, Condition )
|
||||||
self:F( CoalitionSide )
|
self:F( CoalitionSide )
|
||||||
|
|
||||||
@@ -288,6 +309,7 @@ end
|
|||||||
|
|
||||||
--- Sends a MESSAGE to all players.
|
--- Sends a MESSAGE to all players.
|
||||||
-- @param #MESSAGE self
|
-- @param #MESSAGE self
|
||||||
|
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Send a message created to all players.
|
-- -- Send a message created to all players.
|
||||||
@@ -297,18 +319,18 @@ end
|
|||||||
-- or
|
-- 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!", "End of Mission", 25, "Win" )
|
||||||
-- MessageAll:ToAll()
|
-- MessageAll:ToAll()
|
||||||
function MESSAGE:ToAll()
|
function MESSAGE:ToAll(Settings)
|
||||||
self:F()
|
self:F()
|
||||||
|
|
||||||
if self.MessageType then
|
if self.MessageType then
|
||||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
self.MessageCategory = self.MessageType .. ": "
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.MessageDuration ~= 0 then
|
if self.MessageDuration ~= 0 then
|
||||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
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 )
|
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,5 @@
|
|||||||
--- **Core** -- The RADIO Module is responsible for everything that is related to radio transmission and you can hear in DCS, be it TACAN beacons, Radio transmissions...
|
--- **Core** -- The RADIO Module is responsible for everything that is related to radio transmission and you can hear in DCS, be it TACAN beacons, Radio transmissions...
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- The Radio contains 2 classes : RADIO and BEACON
|
-- The Radio contains 2 classes : RADIO and BEACON
|
||||||
@@ -18,10 +16,10 @@
|
|||||||
-- * They need to be added in .\l10n\DEFAULT\ in you .miz file (wich can be decompressed like a .zip file),
|
-- * They need to be added in .\l10n\DEFAULT\ in you .miz file (wich can be decompressed like a .zip file),
|
||||||
-- * For simplicty sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission.
|
-- * For simplicty sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission.
|
||||||
--
|
--
|
||||||
-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Unit#UNIT} or a @{Group#GROUP} or by any other @{Positionable#POSITIONABLE}
|
-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Wrapper.Positionable#POSITIONABLE}
|
||||||
--
|
--
|
||||||
-- * If the transmitter is a @{Unit#UNIT} or a @{Group#GROUP}, DCS will set the power of the transmission automatically,
|
-- * If the transmitter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, DCS will set the power of the transmission automatically,
|
||||||
-- * If the transmitter is any other @{Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped.
|
-- * If the transmitter is any other @{Wrapper.Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped.
|
||||||
--
|
--
|
||||||
-- Note that obviously, the **frequency** and the **modulation** of the transmission are important only if the players are piloting an **Advanced System Modelling** enabled aircraft,
|
-- Note that obviously, the **frequency** and the **modulation** of the transmission are important only if the players are piloting an **Advanced System Modelling** enabled aircraft,
|
||||||
-- like the A10C or the Mirage 2000C. They will **hear the transmission** if they are tuned on the **right frequency and modulation** (and if they are close enough - more on that below).
|
-- like the A10C or the Mirage 2000C. They will **hear the transmission** if they are tuned on the **right frequency and modulation** (and if they are close enough - more on that below).
|
||||||
@@ -32,39 +30,40 @@
|
|||||||
--
|
--
|
||||||
-- ### Author: Hugues "Grey_Echo" Bousquet
|
-- ### Author: Hugues "Grey_Echo" Bousquet
|
||||||
--
|
--
|
||||||
-- @module Radio
|
-- @module Core.Radio
|
||||||
|
-- @image Core_Radio.JPG
|
||||||
|
|
||||||
|
|
||||||
--- # RADIO class, extends @{Base#BASE}
|
--- Models the radio capabilty.
|
||||||
--
|
--
|
||||||
-- ## RADIO usage
|
-- ## RADIO usage
|
||||||
--
|
--
|
||||||
-- There are 3 steps to a successful radio transmission.
|
-- There are 3 steps to a successful radio transmission.
|
||||||
--
|
--
|
||||||
-- * First, you need to **"add a @{#RADIO} object** to your @{Positionable#POSITIONABLE}. This is done using the @{Positionable#POSITIONABLE.GetRadio}() function,
|
-- * First, you need to **"add a @{#RADIO} object** to your @{Wrapper.Positionable#POSITIONABLE}. This is done using the @{Wrapper.Positionable#POSITIONABLE.GetRadio}() function,
|
||||||
-- * Then, you will **set the relevant parameters** to the transmission (see below),
|
-- * Then, you will **set the relevant parameters** to the transmission (see below),
|
||||||
-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function.
|
-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function.
|
||||||
--
|
--
|
||||||
-- Methods to set relevant parameters for both a @{Unit#UNIT} or a @{Group#GROUP} or any other @{Positionable#POSITIONABLE}
|
-- Methods to set relevant parameters for both a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or any other @{Wrapper.Positionable#POSITIONABLE}
|
||||||
--
|
--
|
||||||
-- * @{#RADIO.SetFileName}() : Sets the file name of your sound file (e.g. "Noise.ogg"),
|
-- * @{#RADIO.SetFileName}() : Sets the file name of your sound file (e.g. "Noise.ogg"),
|
||||||
-- * @{#RADIO.SetFrequency}() : Sets the frequency of your transmission.
|
-- * @{#RADIO.SetFrequency}() : Sets the frequency of your transmission.
|
||||||
-- * @{#RADIO.SetModulation}() : Sets the modulation of your transmission.
|
-- * @{#RADIO.SetModulation}() : Sets the modulation of your transmission.
|
||||||
-- * @{#RADIO.SetLoop}() : Choose if you want the transmission to be looped. If you need your transmission to be looped, you might need a @{#BEACON} instead...
|
-- * @{#RADIO.SetLoop}() : Choose if you want the transmission to be looped. If you need your transmission to be looped, you might need a @{#BEACON} instead...
|
||||||
--
|
--
|
||||||
-- Additional Methods to set relevant parameters if the transmiter is a @{Unit#UNIT} or a @{Group#GROUP}
|
-- Additional Methods to set relevant parameters if the transmiter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}
|
||||||
--
|
--
|
||||||
-- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration,
|
-- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration,
|
||||||
-- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call
|
-- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call
|
||||||
--
|
--
|
||||||
-- Additional Methods to set relevant parameters if the transmiter is any other @{Positionable#POSITIONABLE}
|
-- Additional Methods to set relevant parameters if the transmiter is any other @{Wrapper.Positionable#POSITIONABLE}
|
||||||
--
|
--
|
||||||
-- * @{#RADIO.SetPower}() : Sets the power of the antenna in Watts
|
-- * @{#RADIO.SetPower}() : Sets the power of the antenna in Watts
|
||||||
-- * @{#RADIO.NewGenericTransmission}() : Shortcut to set all the relevant parameters in one method call
|
-- * @{#RADIO.NewGenericTransmission}() : Shortcut to set all the relevant parameters in one method call
|
||||||
--
|
--
|
||||||
-- What is this power thing ?
|
-- What is this power thing ?
|
||||||
--
|
--
|
||||||
-- * If your transmission is sent by a @{Positionable#POSITIONABLE} other than a @{Unit#UNIT} or a @{Group#GROUP}, you can set the power of the antenna,
|
-- * If your transmission is sent by a @{Wrapper.Positionable#POSITIONABLE} other than a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, you can set the power of the antenna,
|
||||||
-- * Otherwise, DCS sets it automatically, depending on what's available on your Unit,
|
-- * Otherwise, DCS sets it automatically, depending on what's available on your Unit,
|
||||||
-- * If the player gets **too far** from the transmiter, or if the antenna is **too weak**, the transmission will **fade** and **become noisyer**,
|
-- * If the player gets **too far** from the transmiter, or if the antenna is **too weak**, the transmission will **fade** and **become noisyer**,
|
||||||
-- * This an automated DCS calculation you have no say on,
|
-- * This an automated DCS calculation you have no say on,
|
||||||
@@ -93,7 +92,7 @@ RADIO = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
--- Create a new RADIO Object. This doesn't broadcast a transmission, though, use @{#RADIO.Broadcast} to actually broadcast
|
--- Create a new RADIO Object. This doesn't broadcast a transmission, though, use @{#RADIO.Broadcast} to actually broadcast
|
||||||
-- If you want to create a RADIO, you probably should use @{Positionable#POSITIONABLE.GetRadio}() instead
|
-- If you want to create a RADIO, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetRadio}() instead
|
||||||
-- @param #RADIO self
|
-- @param #RADIO self
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
||||||
-- @return #RADIO Radio
|
-- @return #RADIO Radio
|
||||||
@@ -262,7 +261,7 @@ end
|
|||||||
|
|
||||||
--- Create a new transmission, that is to say, populate the RADIO with relevant data
|
--- Create a new transmission, that is to say, populate the RADIO with relevant data
|
||||||
-- In this function the data is especially relevant if the broadcaster is a UNIT or a GROUP,
|
-- In this function the data is especially relevant if the broadcaster is a UNIT or a GROUP,
|
||||||
-- but it will work for any @{Positionable#POSITIONABLE}.
|
-- but it will work for any @{Wrapper.Positionable#POSITIONABLE}.
|
||||||
-- Only the RADIO and the Filename are mandatory.
|
-- Only the RADIO and the Filename are mandatory.
|
||||||
-- @param #RADIO self
|
-- @param #RADIO self
|
||||||
-- @param #string FileName
|
-- @param #string FileName
|
||||||
@@ -276,8 +275,12 @@ function RADIO:NewUnitTransmission(FileName, Subtitle, SubtitleDuration, Frequen
|
|||||||
self:F({FileName, Subtitle, SubtitleDuration, Frequency, Modulation, Loop})
|
self:F({FileName, Subtitle, SubtitleDuration, Frequency, Modulation, Loop})
|
||||||
|
|
||||||
self:SetFileName(FileName)
|
self:SetFileName(FileName)
|
||||||
if Subtitle then self:SetSubtitle(Subtitle) end
|
local Duration = 5
|
||||||
if SubtitleDuration then self:SetSubtitleDuration(SubtitleDuration) end
|
if SubtitleDuration then Duration = SubtitleDuration end
|
||||||
|
-- SubtitleDuration argument was missing, adding it
|
||||||
|
if Subtitle then self:SetSubtitle(Subtitle, Duration) end
|
||||||
|
-- self:SetSubtitleDuration is non existent, removing faulty line
|
||||||
|
-- if SubtitleDuration then self:SetSubtitleDuration(SubtitleDuration) end
|
||||||
if Frequency then self:SetFrequency(Frequency) end
|
if Frequency then self:SetFrequency(Frequency) end
|
||||||
if Modulation then self:SetModulation(Modulation) end
|
if Modulation then self:SetModulation(Modulation) end
|
||||||
if Loop then self:SetLoop(Loop) end
|
if Loop then self:SetLoop(Loop) end
|
||||||
@@ -287,7 +290,7 @@ end
|
|||||||
|
|
||||||
--- Actually Broadcast the transmission
|
--- Actually Broadcast the transmission
|
||||||
-- * The Radio has to be populated with the new transmission before broadcasting.
|
-- * The Radio has to be populated with the new transmission before broadcasting.
|
||||||
-- * Please use RADIO setters or either @{Radio#RADIO.NewGenericTransmission} or @{Radio#RADIO.NewUnitTransmission}
|
-- * Please use RADIO setters or either @{#RADIO.NewGenericTransmission} or @{#RADIO.NewUnitTransmission}
|
||||||
-- * This class is in fact pretty smart, it determines the right DCS function to use depending on the type of POSITIONABLE
|
-- * This class is in fact pretty smart, it determines the right DCS function to use depending on the type of POSITIONABLE
|
||||||
-- * If the POSITIONABLE is not a UNIT or a GROUP, we use the generic (but limited) trigger.action.radioTransmission()
|
-- * If the POSITIONABLE is not a UNIT or a GROUP, we use the generic (but limited) trigger.action.radioTransmission()
|
||||||
-- * If the POSITIONABLE is a UNIT or a GROUP, we use the "TransmitMessage" Command
|
-- * If the POSITIONABLE is a UNIT or a GROUP, we use the "TransmitMessage" Command
|
||||||
@@ -339,22 +342,20 @@ function RADIO:StopBroadcast()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- # BEACON class, extends @{Base#BASE}
|
--- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
|
||||||
--
|
|
||||||
-- After attaching a @{#BEACON} to your @{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 AA TACAN Beacon and the general purpose Radio Beacon.
|
-- There are two types of BEACONs available : the AA 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
|
-- 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.
|
-- attach to a cargo crate, for exemple.
|
||||||
--
|
--
|
||||||
-- ## AA TACAN Beacon usage
|
-- ## AA TACAN Beacon usage
|
||||||
--
|
--
|
||||||
-- This beacon only works with airborne @{Unit#UNIT} or a @{Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon.
|
-- This beacon only works with airborne @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon.
|
||||||
-- Use @#BEACON:StopAATACAN}() to stop it.
|
-- Use @#BEACON:StopAATACAN}() to stop it.
|
||||||
--
|
--
|
||||||
-- ## General Purpose Radio Beacon usage
|
-- ## General Purpose Radio Beacon usage
|
||||||
--
|
--
|
||||||
-- This beacon will work with any @{Positionable#POSITIONABLE}, but **it won't follow the @{Positionable#POSITIONABLE}** ! This means that you should only use it with
|
-- This beacon will work with any @{Wrapper.Positionable#POSITIONABLE}, but **it won't follow the @{Wrapper.Positionable#POSITIONABLE}** ! This means that you should only use it with
|
||||||
-- @{Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON:RadioBeacon}() to set the beacon parameters and start the beacon.
|
-- @{Wrapper.Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON:RadioBeacon}() to set the beacon parameters and start the beacon.
|
||||||
-- Use @{#BEACON:StopRadioBeacon}() to stop it.
|
-- Use @{#BEACON:StopRadioBeacon}() to stop it.
|
||||||
--
|
--
|
||||||
-- @type BEACON
|
-- @type BEACON
|
||||||
@@ -364,7 +365,7 @@ BEACON = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
--- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.AATACAN} or @{#BEACON.Generic}
|
--- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.AATACAN} or @{#BEACON.Generic}
|
||||||
-- If you want to create a BEACON, you probably should use @{Positionable#POSITIONABLE.GetBeacon}() instead.
|
-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead.
|
||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
||||||
-- @return #BEACON Beacon
|
-- @return #BEACON Beacon
|
||||||
|
|||||||
@@ -1,3 +1,17 @@
|
|||||||
|
--- **Core** -- **REPORT** class provides a handy means to create messages and reports.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Authors:
|
||||||
|
--
|
||||||
|
-- * FlightControl : Design & Programming
|
||||||
|
--
|
||||||
|
-- ### Contributions:
|
||||||
|
--
|
||||||
|
-- @module Core.Report
|
||||||
|
-- @image Core_Report.JPG
|
||||||
|
|
||||||
|
|
||||||
--- The REPORT class
|
--- The REPORT class
|
||||||
-- @type REPORT
|
-- @type REPORT
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
@@ -54,8 +68,8 @@ end
|
|||||||
-- @param #REPORT self
|
-- @param #REPORT self
|
||||||
-- @param #string Text
|
-- @param #string Text
|
||||||
-- @return #REPORT
|
-- @return #REPORT
|
||||||
function REPORT:AddIndent( Text ) --R2.1
|
function REPORT:AddIndent( Text, Separator ) --R2.1
|
||||||
self.Report[#self.Report+1] = string.rep(" ", self.Indent ) .. Text:gsub("\n","\n"..string.rep( " ", self.Indent ) )
|
self.Report[#self.Report+1] = ( ( Separator and Separator .. string.rep( " ", self.Indent - 1 ) ) or string.rep(" ", self.Indent ) ) .. Text:gsub("\n","\n"..string.rep( " ", self.Indent ) )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
--
|
--
|
||||||
-- The SCHEDULEDISPATCHER allows multiple scheduled functions to be planned and executed for one SCHEDULER object.
|
-- The SCHEDULEDISPATCHER allows multiple scheduled functions to be planned and executed for one SCHEDULER object.
|
||||||
-- The SCHEDULER object therefore keeps a table of "CallID's", which are returned after each planning of a new scheduled function by the SCHEDULEDISPATCHER.
|
-- The SCHEDULER object therefore keeps a table of "CallID's", which are returned after each planning of a new scheduled function by the SCHEDULEDISPATCHER.
|
||||||
-- The SCHEDULER object plans new scheduled functions through the @{Scheduler#SCHEDULER.Schedule}() method.
|
-- The SCHEDULER object plans new scheduled functions through the @{Core.Scheduler#SCHEDULER.Schedule}() method.
|
||||||
-- The Schedule() method returns the CallID that is the reference ID for each planned schedule.
|
-- The Schedule() method returns the CallID that is the reference ID for each planned schedule.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -30,7 +30,8 @@
|
|||||||
-- ### Contributions: -
|
-- ### Contributions: -
|
||||||
-- ### Authors: FlightControl : Design & Programming
|
-- ### Authors: FlightControl : Design & Programming
|
||||||
--
|
--
|
||||||
-- @module ScheduleDispatcher
|
-- @module Core.ScheduleDispatcher
|
||||||
|
-- @image Core_Schedule_Dispatcher.JPG
|
||||||
|
|
||||||
--- The SCHEDULEDISPATCHER structure
|
--- The SCHEDULEDISPATCHER structure
|
||||||
-- @type SCHEDULEDISPATCHER
|
-- @type SCHEDULEDISPATCHER
|
||||||
@@ -87,12 +88,12 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
|||||||
self:T3( self.Schedule[Scheduler][CallID] )
|
self:T3( self.Schedule[Scheduler][CallID] )
|
||||||
|
|
||||||
self.Schedule[Scheduler][CallID].CallHandler = function( CallID )
|
self.Schedule[Scheduler][CallID].CallHandler = function( CallID )
|
||||||
self:F2( CallID )
|
--self:E( CallID )
|
||||||
|
|
||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
env.info( "Error in timer function: " .. errmsg )
|
env.info( "Error in timer function: " .. errmsg )
|
||||||
if debug ~= nil then
|
if BASE.Debug ~= nil then
|
||||||
env.info( debug.traceback() )
|
env.info( BASE.Debug.traceback() )
|
||||||
end
|
end
|
||||||
return errmsg
|
return errmsg
|
||||||
end
|
end
|
||||||
@@ -111,7 +112,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
|||||||
|
|
||||||
--self:T3( { Schedule = Schedule } )
|
--self:T3( { Schedule = Schedule } )
|
||||||
|
|
||||||
local ScheduleObject = Scheduler.SchedulerObject
|
local SchedulerObject = Scheduler.SchedulerObject
|
||||||
--local ScheduleObjectName = Scheduler.SchedulerObject:GetNameAndClassID()
|
--local ScheduleObjectName = Scheduler.SchedulerObject:GetNameAndClassID()
|
||||||
local ScheduleFunction = Schedule.Function
|
local ScheduleFunction = Schedule.Function
|
||||||
local ScheduleArguments = Schedule.Arguments
|
local ScheduleArguments = Schedule.Arguments
|
||||||
@@ -122,9 +123,10 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
|||||||
local ScheduleID = Schedule.ScheduleID
|
local ScheduleID = Schedule.ScheduleID
|
||||||
|
|
||||||
local Status, Result
|
local Status, Result
|
||||||
if ScheduleObject then
|
--self:E( { SchedulerObject = SchedulerObject } )
|
||||||
|
if SchedulerObject then
|
||||||
local function Timer()
|
local function Timer()
|
||||||
return ScheduleFunction( ScheduleObject, unpack( ScheduleArguments ) )
|
return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) )
|
||||||
end
|
end
|
||||||
Status, Result = xpcall( Timer, ErrorHandler )
|
Status, Result = xpcall( Timer, ErrorHandler )
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
--- **Core** -- SCHEDULER prepares and handles the **execution of functions over scheduled time (intervals)**.
|
--- **Core** -- SCHEDULER prepares and handles the **execution of functions over scheduled time (intervals)**.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- SCHEDULER manages the **scheduling of functions**:
|
-- SCHEDULER manages the **scheduling of functions**:
|
||||||
@@ -21,13 +19,13 @@
|
|||||||
--
|
--
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # YouTube Channel
|
-- # YouTube Channel
|
||||||
--
|
--
|
||||||
-- ### [SCHEDULER YouTube Channel (none)]()
|
-- ### [SCHEDULER YouTube Channel (none)]()
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
@@ -39,8 +37,8 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Scheduler
|
-- @module Core.Scheduler
|
||||||
|
-- @image Core_Scheduler.JPG
|
||||||
|
|
||||||
--- The SCHEDULER class
|
--- The SCHEDULER class
|
||||||
-- @type SCHEDULER
|
-- @type SCHEDULER
|
||||||
@@ -48,9 +46,7 @@
|
|||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
--- # SCHEDULER class, extends @{Base#BASE}
|
--- Creates and handles schedules over time, which allow to execute code at specific time intervals with randomization.
|
||||||
--
|
|
||||||
-- The SCHEDULER class creates schedule.
|
|
||||||
--
|
--
|
||||||
-- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**.
|
-- 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.
|
-- The ScheduleID is returned when the method @{#SCHEDULER.Schedule}() is called.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,46 +1,193 @@
|
|||||||
--- **Core** -- **SETTINGS** classe defines the format settings management for measurement.
|
--- **Core** -- Manages various settings for MOOSE classes.
|
||||||
--
|
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # Demo Missions
|
|
||||||
--
|
|
||||||
-- ### [SETTINGS Demo Missions source code]()
|
|
||||||
--
|
|
||||||
-- ### [SETTINGS Demo Missions, only for beta testers]()
|
|
||||||
--
|
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
|
||||||
-- # YouTube Channel
|
|
||||||
--
|
|
||||||
-- ### [SETTINGS YouTube Channel]()
|
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- The documentation of the SETTINGS class can be found further in this document.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # **AUTHORS and CONTRIBUTIONS**
|
||||||
|
--
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- ====
|
-- ### Authors:
|
||||||
|
--
|
||||||
|
-- * **FlightControl**: Design & Programming
|
||||||
--
|
--
|
||||||
-- @module Settings
|
-- @module Core.Settings
|
||||||
|
-- @image Core_Settings.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type SETTINGS
|
--- @type SETTINGS
|
||||||
-- @field #number LL_Accuracy
|
|
||||||
-- @field #boolean LL_DMS
|
|
||||||
-- @field #number MGRS_Accuracy
|
|
||||||
-- @field #string A2GSystem
|
|
||||||
-- @field #string A2ASystem
|
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- # SETTINGS class, extends @{Base#BASE}
|
--- Takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
|
||||||
--
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
|
||||||
|
-- SETTINGS can work on 2 levels:
|
||||||
|
--
|
||||||
|
-- - **Default settings**: A running mission has **Default settings**.
|
||||||
|
-- - **Player settings**: For each player its own **Player settings** can be defined, overriding the **Default settings**.
|
||||||
|
--
|
||||||
|
-- So, when there isn't any **Player setting** defined for a player for a specific setting, or, the player cannot be identified, the **Default setting** will be used instead.
|
||||||
|
--
|
||||||
|
-- # 1) \_SETTINGS object
|
||||||
|
--
|
||||||
|
-- MOOSE defines by default a singleton object called **\_SETTINGS**. Use this object to modify all the **Default settings** for a running mission.
|
||||||
|
-- For each player, MOOSE will automatically allocate also a **player settings** object, and will expose a radio menu to allow the player to adapt the settings to his own preferences.
|
||||||
|
--
|
||||||
|
-- # 2) SETTINGS Menu
|
||||||
|
--
|
||||||
|
-- Settings can be adapted by the Players and by the Mission Administrator through **radio menus, which are automatically available in the mission**.
|
||||||
|
-- These menus can be found **on level F10 under "Settings"**. There are two kinds of menus generated by the system.
|
||||||
|
--
|
||||||
|
-- ## 2.1) Default settings menu
|
||||||
|
--
|
||||||
|
-- A menu is created automatically per Command Center that allows to modify the **Default** settings.
|
||||||
|
-- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**!
|
||||||
|
-- Note that the **Default settings** will only be used when a player has not choosen its own settings.
|
||||||
|
--
|
||||||
|
-- ## 2.2) Player settings menu
|
||||||
|
--
|
||||||
|
-- A menu is created automatically per Player Slot (group) that allows to modify the **Player** settings.
|
||||||
|
-- So, when joining a slot, a menu wil be available that allows to change the settings parameters **FOR THE PLAYER ONLY**!
|
||||||
|
-- Note that when a player has not chosen a specific setting, the **Default settings** will be used.
|
||||||
|
--
|
||||||
|
-- ## 2.3) Show or Hide the Player Setting menus
|
||||||
|
--
|
||||||
|
-- Of course, it may be requried not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**.
|
||||||
|
-- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus.
|
||||||
|
-- Note that when this method is used, any player already in a slot will not have its menus visibility changed.
|
||||||
|
-- The option will only have effect when a player enters a new slot or changes a slot.
|
||||||
|
--
|
||||||
|
-- Example:
|
||||||
|
--
|
||||||
|
-- _SETTINGS:SetPlayerMenuOff() -- will disable the player menus.
|
||||||
|
-- _SETTINGS:SetPlayerMenuOn() -- will enable the player menus.
|
||||||
|
-- -- But only when a player exits and reenters the slot these settings will have effect!
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # 3) Settings
|
||||||
|
--
|
||||||
|
-- There are different settings that are managed and applied within the MOOSE framework.
|
||||||
|
-- See below a comprehensive description of each.
|
||||||
|
--
|
||||||
|
-- ## 3.1) **A2G coordinates** display formatting
|
||||||
|
--
|
||||||
|
-- ### 3.1.1) A2G coordinates setting **types**
|
||||||
|
--
|
||||||
|
-- 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 MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
|
||||||
|
-- - A2G LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
|
||||||
|
-- - A2G LL DDM: Lattitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
|
||||||
|
--
|
||||||
|
-- ### 3.1.2) A2G coordinates setting **menu**
|
||||||
|
--
|
||||||
|
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
|
||||||
|
--
|
||||||
|
-- ### 3.1.3) A2G coordinates setting **methods**
|
||||||
|
--
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
-- ### 3.1.4) A2G coordinates setting - additional notes
|
||||||
|
--
|
||||||
|
-- One additional note on BR. In a situation when a BR coordinate should be given,
|
||||||
|
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
|
||||||
|
--
|
||||||
|
-- ## 3.2) **A2A coordinates** formatting
|
||||||
|
--
|
||||||
|
-- ### 3.2.1) A2A coordinates setting **types**
|
||||||
|
--
|
||||||
|
-- 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 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.
|
||||||
|
-- - A2A BULLS: [Bullseye](http://falcon4.wikidot.com/concepts:bullseye).
|
||||||
|
--
|
||||||
|
-- ### 3.2.2) A2A coordinates setting **menu**
|
||||||
|
--
|
||||||
|
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
|
||||||
|
--
|
||||||
|
-- ### 3.2.3) A2A coordinates setting **methods**
|
||||||
|
--
|
||||||
|
-- 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_BULLS}(): Enable the BULLSeye display formatting by default.
|
||||||
|
--
|
||||||
|
-- ### 3.2.4) A2A coordinates settings - additional notes
|
||||||
|
--
|
||||||
|
-- One additional note on BRAA. In a situation when a BRAA coordinate should be given,
|
||||||
|
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
|
||||||
|
--
|
||||||
|
-- ## 3.3) **Measurements** formatting
|
||||||
|
--
|
||||||
|
-- ### 3.3.1) Measurements setting **types**
|
||||||
|
--
|
||||||
|
-- Will customize the measurements system being used as part as part of the Command Center communications.
|
||||||
|
--
|
||||||
|
-- - **Metrics** system: Applies the [Metrics system](https://en.wikipedia.org/wiki/Metric_system) ...
|
||||||
|
-- - **Imperial** system: Applies the [Imperial system](https://en.wikipedia.org/wiki/Imperial_units) ...
|
||||||
|
--
|
||||||
|
-- ### 3.3.2) Measurements setting **menu**
|
||||||
|
--
|
||||||
|
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
|
||||||
|
--
|
||||||
|
-- ### 3.3.3) Measurements setting **methods**
|
||||||
|
--
|
||||||
|
-- There are different methods that can be used to change the **Default settings** using the \_SETTINGS object.
|
||||||
|
--
|
||||||
|
-- - @{#SETTINGS.SetMetric}(): Enable the Metric system.
|
||||||
|
-- - @{#SETTINGS.SetImperial}(): Enable the Imperial system.
|
||||||
|
--
|
||||||
|
-- ## 3.4) **Message** display times
|
||||||
|
--
|
||||||
|
-- ### 3.4.1) Message setting **types**
|
||||||
|
--
|
||||||
|
-- There are various **Message Types** that will influence the duration how long a message will appear as part of the Command Center communications.
|
||||||
|
--
|
||||||
|
-- - **Update** message: A short update message.
|
||||||
|
-- - **Information** message: Provides new information **while** executing a mission.
|
||||||
|
-- - **Briefing** message: Provides a complete briefing **before** executing a mission.
|
||||||
|
-- - **Overview report**: Provides a short report overview, the summary of the report.
|
||||||
|
-- - **Detailed report**: Provides a complete report.
|
||||||
|
--
|
||||||
|
-- ### 3.4.2) Message setting **menu**
|
||||||
|
--
|
||||||
|
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
|
||||||
|
--
|
||||||
|
-- Each Message Type has specific timings that will be applied when the message is displayed.
|
||||||
|
-- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be choosen.
|
||||||
|
-- So the player can choose its own amount of seconds how long a message should be displayed of a certain type.
|
||||||
|
-- Note that **Update** messages can be chosen not to be displayed at all!
|
||||||
|
--
|
||||||
|
-- ### 3.4.3) Message setting **methods**
|
||||||
|
--
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- @field #SETTINGS
|
-- @field #SETTINGS
|
||||||
SETTINGS = {
|
SETTINGS = {
|
||||||
ClassName = "SETTINGS",
|
ClassName = "SETTINGS",
|
||||||
|
ShowPlayerMenu = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -217,7 +364,6 @@ do -- SETTINGS
|
|||||||
-- @param #SETTINGS self
|
-- @param #SETTINGS self
|
||||||
-- @return #boolean true if BRA
|
-- @return #boolean true if BRA
|
||||||
function SETTINGS:IsA2A_BRAA()
|
function SETTINGS:IsA2A_BRAA()
|
||||||
self:E( { BRA = ( self.A2ASystem and self.A2ASystem == "BRAA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRAA() ) } )
|
|
||||||
return ( self.A2ASystem and self.A2ASystem == "BRAA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRAA() )
|
return ( self.A2ASystem and self.A2ASystem == "BRAA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRAA() )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -411,152 +557,179 @@ do -- SETTINGS
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #SETTINGS self
|
--- Sets the player menus on, so that the **Player setting menus** show up for the players.
|
||||||
-- @param RootMenu
|
-- But only when a player exits and reenters the slot these settings will have effect!
|
||||||
-- @param Wrapper.Client#CLIENT PlayerUnit
|
-- It is advised to use this method at the start of the mission.
|
||||||
-- @param #string MenuText
|
-- @param #SETTINGS self
|
||||||
-- @return #SETTINGS
|
-- @return #SETTINGS
|
||||||
|
-- @usage
|
||||||
|
-- _SETTINGS:SetPlayerMenuOn() -- will enable the player menus.
|
||||||
|
function SETTINGS:SetPlayerMenuOn()
|
||||||
|
self.ShowPlayerMenu = true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Sets the player menus off, so that the **Player setting menus** won't show up for the players.
|
||||||
|
-- But only when a player exits and reenters the slot these settings will have effect!
|
||||||
|
-- It is advised to use this method at the start of the mission.
|
||||||
|
-- @param #SETTINGS self
|
||||||
|
-- @return #SETTINGS self
|
||||||
|
-- @usage
|
||||||
|
-- _SETTINGS:SetPlayerMenuOff() -- will disable the player menus.
|
||||||
|
function SETTINGS:SetPlayerMenuOff()
|
||||||
|
self.ShowPlayerMenu = false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Updates the menu of the player seated in the PlayerUnit.
|
||||||
|
-- @param #SETTINGS self
|
||||||
|
-- @param Wrapper.Client#CLIENT PlayerUnit
|
||||||
|
-- @return #SETTINGS self
|
||||||
function SETTINGS:SetPlayerMenu( PlayerUnit )
|
function SETTINGS:SetPlayerMenu( PlayerUnit )
|
||||||
|
|
||||||
local PlayerGroup = PlayerUnit:GetGroup()
|
if _SETTINGS.ShowPlayerMenu == true then
|
||||||
local PlayerName = PlayerUnit:GetPlayerName()
|
|
||||||
local PlayerNames = PlayerGroup:GetPlayerNames()
|
|
||||||
|
|
||||||
local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' )
|
|
||||||
|
|
||||||
self.PlayerMenu = PlayerMenu
|
local PlayerGroup = PlayerUnit:GetGroup()
|
||||||
|
local PlayerName = PlayerUnit:GetPlayerName()
|
||||||
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2G Coordinate System", PlayerMenu )
|
local PlayerNames = PlayerGroup:GetPlayerNames()
|
||||||
|
|
||||||
if not self:IsA2G_LL_DMS() then
|
local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' )
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
|
||||||
end
|
self.PlayerMenu = PlayerMenu
|
||||||
|
|
||||||
if not self:IsA2G_LL_DDM() then
|
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2G Coordinate System", PlayerMenu )
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
|
|
||||||
end
|
if not self:IsA2G_LL_DMS() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self:IsA2G_LL_DDM() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
|
||||||
|
end
|
||||||
|
|
||||||
|
if self:IsA2G_LL_DDM() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self:IsA2G_BR() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self:IsA2G_MGRS() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
||||||
|
end
|
||||||
|
|
||||||
if self:IsA2G_LL_DDM() then
|
if self:IsA2G_MGRS() then
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 2", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||||
end
|
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
|
||||||
if not self:IsA2G_BR() then
|
end
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self:IsA2G_MGRS() then
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
|
||||||
end
|
|
||||||
|
|
||||||
if self:IsA2G_MGRS() then
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 2", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
|
|
||||||
end
|
|
||||||
|
|
||||||
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2A Coordinate System", PlayerMenu )
|
|
||||||
|
|
||||||
|
|
||||||
if not self:IsA2A_LL_DMS() then
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self:IsA2A_LL_DDM() then
|
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2A Coordinate System", PlayerMenu )
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
|
|
||||||
end
|
|
||||||
|
|
||||||
if self:IsA2A_LL_DDM() then
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
if not self:IsA2A_LL_DMS() then
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if not self:IsA2A_BULLS() then
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self:IsA2A_BRAA() then
|
if not self:IsA2A_LL_DDM() then
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self:IsA2A_MGRS() then
|
if self:IsA2A_LL_DDM() then
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||||
end
|
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self:IsA2A_BULLS() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self:IsA2A_BRAA() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self:IsA2A_MGRS() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
||||||
|
end
|
||||||
|
|
||||||
|
if self:IsA2A_MGRS() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 1", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 2", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 3", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 4", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 5", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
|
||||||
|
end
|
||||||
|
|
||||||
|
local MetricsMenu = MENU_GROUP:New( PlayerGroup, "Measures and Weights System", PlayerMenu )
|
||||||
|
|
||||||
|
if self:IsMetric() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Imperial (Miles,Feet)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
|
||||||
|
end
|
||||||
|
|
||||||
|
if self:IsImperial() then
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local MessagesMenu = MENU_GROUP:New( PlayerGroup, "Messages and Reports", PlayerMenu )
|
||||||
|
|
||||||
|
local UpdateMessagesMenu = MENU_GROUP:New( PlayerGroup, "Update Messages", MessagesMenu )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "Off", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 0 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 5 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 10 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 15 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 30 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 60 )
|
||||||
|
|
||||||
|
local InformationMessagesMenu = MENU_GROUP:New( PlayerGroup, "Information Messages", MessagesMenu )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 5 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 10 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 15 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 30 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 60 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 120 )
|
||||||
|
|
||||||
|
local BriefingReportsMenu = MENU_GROUP:New( PlayerGroup, "Briefing Reports", MessagesMenu )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 15 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 30 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 60 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 120 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 180 )
|
||||||
|
|
||||||
|
local OverviewReportsMenu = MENU_GROUP:New( PlayerGroup, "Overview Reports", MessagesMenu )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 15 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 30 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 60 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 120 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 180 )
|
||||||
|
|
||||||
|
local DetailedReportsMenu = MENU_GROUP:New( PlayerGroup, "Detailed Reports", MessagesMenu )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 15 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 30 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 60 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 120 )
|
||||||
|
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 180 )
|
||||||
|
|
||||||
if self:IsA2A_MGRS() then
|
end
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 1", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 2", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 3", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 4", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 5", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
|
|
||||||
end
|
|
||||||
|
|
||||||
local MetricsMenu = MENU_GROUP:New( PlayerGroup, "Measures and Weights System", PlayerMenu )
|
|
||||||
|
|
||||||
if self:IsMetric() then
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Imperial (Miles,Feet)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
|
|
||||||
end
|
|
||||||
|
|
||||||
if self:IsImperial() then
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local MessagesMenu = MENU_GROUP:New( PlayerGroup, "Messages and Reports", PlayerMenu )
|
|
||||||
|
|
||||||
local UpdateMessagesMenu = MENU_GROUP:New( PlayerGroup, "Update Messages", MessagesMenu )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Off", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 0 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 5 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 10 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 15 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 30 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 60 )
|
|
||||||
|
|
||||||
local InformationMessagesMenu = MENU_GROUP:New( PlayerGroup, "Information Messages", MessagesMenu )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 5 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 10 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 15 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 30 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 60 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 120 )
|
|
||||||
|
|
||||||
local BriefingReportsMenu = MENU_GROUP:New( PlayerGroup, "Briefing Reports", MessagesMenu )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 15 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 30 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 60 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 120 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 180 )
|
|
||||||
|
|
||||||
local OverviewReportsMenu = MENU_GROUP:New( PlayerGroup, "Overview Reports", MessagesMenu )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 15 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 30 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 60 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 120 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 180 )
|
|
||||||
|
|
||||||
local DetailedReportsMenu = MENU_GROUP:New( PlayerGroup, "Detailed Reports", MessagesMenu )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 15 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 30 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 60 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 120 )
|
|
||||||
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 180 )
|
|
||||||
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #SETTINGS self
|
--- Removes the player menu from the PlayerUnit.
|
||||||
-- @param RootMenu
|
-- @param #SETTINGS self
|
||||||
-- @param Wrapper.Client#CLIENT PlayerUnit
|
-- @param Wrapper.Client#CLIENT PlayerUnit
|
||||||
-- @return #SETTINGS
|
-- @return #SETTINGS self
|
||||||
function SETTINGS:RemovePlayerMenu( PlayerUnit )
|
function SETTINGS:RemovePlayerMenu( PlayerUnit )
|
||||||
|
|
||||||
if self.PlayerMenu then
|
if self.PlayerMenu then
|
||||||
self.PlayerMenu:Remove()
|
self.PlayerMenu:Remove()
|
||||||
|
self.PlayerMenu = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,10 @@
|
|||||||
--- **Core** -- Spawn dynamically new STATICs in your missions.
|
--- **Core** -- Spawn dynamically new STATICs in your missions.
|
||||||
--
|
--
|
||||||
-- 
|
-- ===
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
--
|
||||||
-- SPAWNSTATIC spawns static structures in your missions dynamically. See below the SPAWNSTATIC class documentation.
|
-- SPAWNSTATIC spawns static structures in your missions dynamically. See below the SPAWNSTATIC class documentation.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # Demo Missions
|
-- # Demo Missions
|
||||||
--
|
--
|
||||||
@@ -16,20 +14,21 @@
|
|||||||
--
|
--
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # YouTube Channel
|
-- # YouTube Channel
|
||||||
--
|
--
|
||||||
-- ### [SPAWNSTATIC YouTube Channel]()
|
-- ### [SPAWNSTATIC YouTube Channel]()
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module SpawnStatic
|
-- @module Core.SpawnStatic
|
||||||
|
-- @image Core_Spawnstatic.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -37,9 +36,7 @@
|
|||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
--- # SPAWNSTATIC class, extends @{Base#BASE}
|
--- Allows to spawn dynamically new @{Static}s.
|
||||||
--
|
|
||||||
-- The SPAWNSTATIC class allows to spawn dynamically new @{Static}s.
|
|
||||||
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME),
|
-- 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"
|
-- 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.
|
-- these properties to create a new static object and place it at the desired coordinate.
|
||||||
@@ -80,18 +77,22 @@ SPAWNSTATIC = {
|
|||||||
--- Creates the main object to spawn a @{Static} defined in the ME.
|
--- Creates the main object to spawn a @{Static} defined in the ME.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix.
|
-- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix.
|
||||||
|
-- @param DCS#country.id SpawnCountryID The ID of the country.
|
||||||
|
-- @param DCS#coalition.side SpawnCoalitionID The ID of the coalition.
|
||||||
-- @return #SPAWNSTATIC
|
-- @return #SPAWNSTATIC
|
||||||
function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, CountryID ) --R2.1
|
function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, SpawnCountryID, SpawnCoalitionID )
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
||||||
self:F( { SpawnTemplatePrefix } )
|
self:F( { SpawnTemplatePrefix } )
|
||||||
|
|
||||||
local TemplateStatic = StaticObject.getByName( SpawnTemplatePrefix )
|
local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( SpawnTemplatePrefix )
|
||||||
if TemplateStatic then
|
if TemplateStatic then
|
||||||
self.SpawnTemplatePrefix = SpawnTemplatePrefix
|
self.SpawnTemplatePrefix = SpawnTemplatePrefix
|
||||||
self.CountryID = CountryID
|
self.CountryID = SpawnCountryID or CountryID
|
||||||
|
self.CategoryID = CategoryID
|
||||||
|
self.CoalitionID = SpawnCoalitionID or CoalitionID
|
||||||
self.SpawnIndex = 0
|
self.SpawnIndex = 0
|
||||||
else
|
else
|
||||||
error( "SPAWNSTATIC:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" )
|
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" )
|
||||||
end
|
end
|
||||||
|
|
||||||
self:SetEventPriority( 5 )
|
self:SetEventPriority( 5 )
|
||||||
@@ -103,12 +104,13 @@ end
|
|||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param #string SpawnTypeName is the name of the type.
|
-- @param #string SpawnTypeName is the name of the type.
|
||||||
-- @return #SPAWNSTATIC
|
-- @return #SPAWNSTATIC
|
||||||
function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory, CountryID ) --R2.1
|
function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory, SpawnCountryID, SpawnCoalitionID )
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
||||||
self:F( { SpawnTypeName } )
|
self:F( { SpawnTypeName } )
|
||||||
|
|
||||||
self.SpawnTypeName = SpawnTypeName
|
self.SpawnTypeName = SpawnTypeName
|
||||||
self.CountryID = CountryID
|
self.CountryID = SpawnCountryID
|
||||||
|
self.CoalitionID = SpawnCoalitionID
|
||||||
self.SpawnIndex = 0
|
self.SpawnIndex = 0
|
||||||
|
|
||||||
self:SetEventPriority( 5 )
|
self:SetEventPriority( 5 )
|
||||||
@@ -117,6 +119,36 @@ function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory,
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Creates a new @{Static} at the original position.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
||||||
|
-- @param #string (optional) The name of the new static.
|
||||||
|
-- @return #SPAWNSTATIC
|
||||||
|
function SPAWNSTATIC:Spawn( Heading, NewName ) --R2.3
|
||||||
|
self:F( { Heading, NewName } )
|
||||||
|
|
||||||
|
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
|
||||||
|
|
||||||
|
if StaticTemplate then
|
||||||
|
|
||||||
|
local StaticUnitTemplate = StaticTemplate.units[1]
|
||||||
|
|
||||||
|
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
|
||||||
|
StaticTemplate.heading = ( Heading / 180 ) * math.pi
|
||||||
|
|
||||||
|
_DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID )
|
||||||
|
|
||||||
|
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
|
||||||
|
|
||||||
|
self.SpawnIndex = self.SpawnIndex + 1
|
||||||
|
|
||||||
|
return _DATABASE:FindStatic(Static:getName())
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new @{Static} from a POINT_VEC2.
|
--- Creates a new @{Static} from a POINT_VEC2.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
|
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
|
||||||
@@ -126,27 +158,86 @@ end
|
|||||||
function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) --R2.1
|
function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) --R2.1
|
||||||
self:F( { PointVec2, Heading, NewName } )
|
self:F( { PointVec2, Heading, NewName } )
|
||||||
|
|
||||||
local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID]
|
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
|
||||||
|
|
||||||
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
|
if StaticTemplate then
|
||||||
|
|
||||||
StaticTemplate.x = PointVec2:GetLat()
|
local StaticUnitTemplate = StaticTemplate.units[1]
|
||||||
StaticTemplate.y = PointVec2:GetLon()
|
|
||||||
|
|
||||||
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
|
StaticUnitTemplate.x = PointVec2.x
|
||||||
StaticTemplate.heading = ( Heading / 180 ) * math.pi
|
StaticUnitTemplate.y = PointVec2.z
|
||||||
|
|
||||||
StaticTemplate.CountryID = nil
|
StaticTemplate.route = nil
|
||||||
StaticTemplate.CoalitionID = nil
|
StaticTemplate.groupId = nil
|
||||||
StaticTemplate.CategoryID = nil
|
|
||||||
|
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
|
||||||
local Static = coalition.addStaticObject( self.CountryID, StaticTemplate )
|
StaticUnitTemplate.name = StaticTemplate.name
|
||||||
|
StaticUnitTemplate.heading = ( Heading / 180 ) * math.pi
|
||||||
self.SpawnIndex = self.SpawnIndex + 1
|
|
||||||
|
_DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID)
|
||||||
|
|
||||||
|
self:F({StaticTemplate = StaticTemplate})
|
||||||
|
|
||||||
return Static
|
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
|
||||||
|
|
||||||
|
self.SpawnIndex = self.SpawnIndex + 1
|
||||||
|
|
||||||
|
return _DATABASE:FindStatic(Static:getName())
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Respawns the original @{Static}.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @return #SPAWNSTATIC
|
||||||
|
function SPAWNSTATIC:ReSpawn()
|
||||||
|
|
||||||
|
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
|
||||||
|
|
||||||
|
if StaticTemplate then
|
||||||
|
|
||||||
|
local StaticUnitTemplate = StaticTemplate.units[1]
|
||||||
|
StaticTemplate.route = nil
|
||||||
|
StaticTemplate.groupId = nil
|
||||||
|
|
||||||
|
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
|
||||||
|
|
||||||
|
return _DATABASE:FindStatic(Static:getName())
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Creates the original @{Static} at a POINT_VEC2.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate 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.
|
||||||
|
-- @return #SPAWNSTATIC
|
||||||
|
function SPAWNSTATIC:ReSpawnAt( Coordinate, Heading )
|
||||||
|
|
||||||
|
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
|
||||||
|
|
||||||
|
if StaticTemplate then
|
||||||
|
|
||||||
|
local StaticUnitTemplate = StaticTemplate.units[1]
|
||||||
|
|
||||||
|
StaticUnitTemplate.x = Coordinate.x
|
||||||
|
StaticUnitTemplate.y = Coordinate.z
|
||||||
|
|
||||||
|
StaticUnitTemplate.heading = Heading and ( ( Heading / 180 ) * math.pi ) or StaticTemplate.heading
|
||||||
|
|
||||||
|
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
|
||||||
|
|
||||||
|
return _DATABASE:FindStatic(Static:getName())
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new @{Static} from a @{Zone}.
|
--- Creates a new @{Static} from a @{Zone}.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static.
|
-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static.
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
--- **Core** -- Management of SPOT logistics, that can be transported from and to transportation carriers.
|
--- **Core** -- Management of SPOT logistics, that can be transported from and to transportation carriers.
|
||||||
--
|
--
|
||||||
-- 
|
-- ===
|
||||||
--
|
|
||||||
-- ====
|
|
||||||
--
|
--
|
||||||
-- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to:
|
-- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to:
|
||||||
--
|
--
|
||||||
-- * Spot for a defined duration.
|
-- * Spot for a defined duration.
|
||||||
-- * wiggle the spot at the target.
|
-- * wiggle the spot at the target.
|
||||||
-- * Provide a @{Unit} as a target, instead of a point.
|
-- * Provide a @{Wrapper.Unit} as a target, instead of a point.
|
||||||
-- * Implement a status machine, LaseOn, LaseOff.
|
-- * Implement a status machine, LaseOn, LaseOff.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # Demo Missions
|
-- # Demo Missions
|
||||||
--
|
--
|
||||||
@@ -21,24 +19,25 @@
|
|||||||
--
|
--
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # YouTube Channel
|
-- # YouTube Channel
|
||||||
--
|
--
|
||||||
-- ### [SPOT YouTube Channel]()
|
-- ### [SPOT YouTube Channel]()
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### 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.
|
-- * [**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
|
-- * [**EasyEB**](https://forums.eagle.ru/member.php?u=112055): Ideas and Beta Testing
|
||||||
-- * [**Wingthor**](https://forums.eagle.ru/member.php?u=123698): Beta Testing
|
-- * [**Wingthor**](https://forums.eagle.ru/member.php?u=123698): Beta Testing
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Spot
|
-- @module Core.Spot
|
||||||
|
-- @image Core_Spot.JPG
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -47,13 +46,11 @@ do
|
|||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
--- # SPOT class, extends @{Fsm#FSM}
|
--- Implements the target spotting or marking functionality, but adds additional luxury to be able to:
|
||||||
--
|
|
||||||
-- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to:
|
|
||||||
--
|
--
|
||||||
-- * Mark targets for a defined duration.
|
-- * Mark targets for a defined duration.
|
||||||
-- * wiggle the spot at the target.
|
-- * wiggle the spot at the target.
|
||||||
-- * Provide a @{Unit} as a target, instead of a point.
|
-- * Provide a @{Wrapper.Unit} as a target, instead of a point.
|
||||||
-- * Implement a status machine, LaseOn, LaseOff.
|
-- * Implement a status machine, LaseOn, LaseOff.
|
||||||
--
|
--
|
||||||
-- ## 1. SPOT constructor
|
-- ## 1. SPOT constructor
|
||||||
@@ -200,7 +197,7 @@ do
|
|||||||
-- @param #number LaserCode
|
-- @param #number LaserCode
|
||||||
-- @param #number Duration
|
-- @param #number Duration
|
||||||
function SPOT:onafterLaseOn( From, Event, To, Target, LaserCode, Duration )
|
function SPOT:onafterLaseOn( From, Event, To, Target, LaserCode, Duration )
|
||||||
self:E( { "LaseOn", Target, LaserCode, Duration } )
|
self:F( { "LaseOn", Target, LaserCode, Duration } )
|
||||||
|
|
||||||
local function StopLase( self )
|
local function StopLase( self )
|
||||||
self:LaseOff()
|
self:LaseOff()
|
||||||
@@ -228,10 +225,10 @@ do
|
|||||||
--- @param #SPOT self
|
--- @param #SPOT self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function SPOT:OnEventDead(EventData)
|
function SPOT:OnEventDead(EventData)
|
||||||
self:E( { Dead = EventData.IniDCSUnitName, Target = self.Target } )
|
self:F( { Dead = EventData.IniDCSUnitName, Target = self.Target } )
|
||||||
if self.Target then
|
if self.Target then
|
||||||
if EventData.IniDCSUnitName == self.Target:GetName() then
|
if EventData.IniDCSUnitName == self.Target:GetName() then
|
||||||
self:E( {"Target dead ", self.Target:GetName() } )
|
self:F( {"Target dead ", self.Target:GetName() } )
|
||||||
self:Destroyed()
|
self:Destroyed()
|
||||||
self:LaseOff()
|
self:LaseOff()
|
||||||
end
|
end
|
||||||
@@ -249,7 +246,7 @@ do
|
|||||||
self.SpotLaser:setPoint( self.Target:GetPointVec3():AddY(1):GetVec3() )
|
self.SpotLaser:setPoint( self.Target:GetPointVec3():AddY(1):GetVec3() )
|
||||||
self:__Lasing( -0.2 )
|
self:__Lasing( -0.2 )
|
||||||
else
|
else
|
||||||
self:E( { "Target is not alive", self.Target:IsAlive() } )
|
self:F( { "Target is not alive", self.Target:IsAlive() } )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -261,7 +258,7 @@ do
|
|||||||
-- @return #SPOT
|
-- @return #SPOT
|
||||||
function SPOT:onafterLaseOff( From, Event, To )
|
function SPOT:onafterLaseOff( From, Event, To )
|
||||||
|
|
||||||
self:E( {"Stopped lasing for ", self.Target:GetName() , SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
|
self:F( {"Stopped lasing for ", self.Target:GetName() , SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
|
||||||
|
|
||||||
self.Lasing = false
|
self.Lasing = false
|
||||||
|
|
||||||
|
|||||||
95
Moose Development/Moose/Core/UserFlag.lua
Normal file
95
Moose Development/Moose/Core/UserFlag.lua
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
--- **Core (WIP)** -- Manage user flags.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- Management of DCS User Flags.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Core.UserFlag
|
||||||
|
-- @image Core_Userflag.JPG
|
||||||
|
--
|
||||||
|
|
||||||
|
do -- UserFlag
|
||||||
|
|
||||||
|
--- @type USERFLAG
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
|
--- Management of DCS User Flags.
|
||||||
|
--
|
||||||
|
-- ## USERFLAG constructor
|
||||||
|
--
|
||||||
|
-- * @{#USERFLAG.New}(): Creates a new USERFLAG object.
|
||||||
|
--
|
||||||
|
-- @field #USERFLAG
|
||||||
|
USERFLAG = {
|
||||||
|
ClassName = "USERFLAG",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- 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
|
||||||
|
|
||||||
|
return self
|
||||||
|
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.
|
||||||
|
-- @return #USERFLAG The userflag instance.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
|
||||||
|
-- BlueVictory:Set( 100 ) -- Set the UserFlag VictoryBlue to 100.
|
||||||
|
--
|
||||||
|
function USERFLAG:Set( Number ) --R2.3
|
||||||
|
|
||||||
|
self:F( { Number = Number } )
|
||||||
|
|
||||||
|
trigger.action.setUserFlag( self.UserFlagName, Number )
|
||||||
|
|
||||||
|
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.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
|
||||||
|
-- local BlueVictoryValue = BlueVictory:Get() -- Get the UserFlag VictoryBlue value.
|
||||||
|
--
|
||||||
|
function USERFLAG:Get( Number ) --R2.3
|
||||||
|
|
||||||
|
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.
|
||||||
|
-- @return #boolean true if the Number is the value of the userflag.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
|
||||||
|
-- if BlueVictory:Is( 1 ) then
|
||||||
|
-- return "Blue has won"
|
||||||
|
-- end
|
||||||
|
function USERFLAG:Is( Number ) --R2.3
|
||||||
|
|
||||||
|
return trigger.misc.getUserFlag( self.UserFlagName ) == Number
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
128
Moose Development/Moose/Core/UserSound.lua
Normal file
128
Moose Development/Moose/Core/UserSound.lua
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
--- **Core (WIP)** -- Manage user sound.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- Management of DCS User Sound.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Core.UserSound
|
||||||
|
-- @image Core_Usersound.JPG
|
||||||
|
|
||||||
|
do -- UserSound
|
||||||
|
|
||||||
|
--- @type USERSOUND
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
|
--- Management of DCS User Sound.
|
||||||
|
--
|
||||||
|
-- ## USERSOUND constructor
|
||||||
|
--
|
||||||
|
-- * @{#USERSOUND.New}(): Creates a new USERSOUND object.
|
||||||
|
--
|
||||||
|
-- @field #USERSOUND
|
||||||
|
USERSOUND = {
|
||||||
|
ClassName = "USERSOUND",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- USERSOUND Constructor.
|
||||||
|
-- @param #USERSOUND self
|
||||||
|
-- @param #string UserSoundFileName The filename of the usersound.
|
||||||
|
-- @return #USERSOUND
|
||||||
|
function USERSOUND:New( UserSoundFileName ) --R2.3
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, BASE:New() ) -- #USERSOUND
|
||||||
|
|
||||||
|
self.UserSoundFileName = UserSoundFileName
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set usersound filename.
|
||||||
|
-- @param #USERSOUND self
|
||||||
|
-- @param #string UserSoundFileName The filename of the usersound.
|
||||||
|
-- @return #USERSOUND The usersound instance.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
|
-- BlueVictory:SetFileName( "BlueVictoryLoud.ogg" ) -- Set the BlueVictory to change the file name to play a louder sound.
|
||||||
|
--
|
||||||
|
function USERSOUND:SetFileName( UserSoundFileName ) --R2.3
|
||||||
|
|
||||||
|
self.UserSoundFileName = UserSoundFileName
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Play the usersound to all players.
|
||||||
|
-- @param #USERSOUND self
|
||||||
|
-- @return #USERSOUND The usersound instance.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
|
-- BlueVictory:ToAll() -- Play the sound that Blue has won.
|
||||||
|
--
|
||||||
|
function USERSOUND:ToAll() --R2.3
|
||||||
|
|
||||||
|
trigger.action.outSound( self.UserSoundFileName )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Play the usersound to the given coalition.
|
||||||
|
-- @param #USERSOUND self
|
||||||
|
-- @param DCS#coalition Coalition The coalition to play the usersound to.
|
||||||
|
-- @return #USERSOUND The usersound instance.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
|
-- BlueVictory:ToCoalition( coalition.side.BLUE ) -- Play the sound that Blue has won to the blue coalition.
|
||||||
|
--
|
||||||
|
function USERSOUND:ToCoalition( Coalition ) --R2.3
|
||||||
|
|
||||||
|
trigger.action.outSoundForCoalition(Coalition, self.UserSoundFileName )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Play the usersound to the given country.
|
||||||
|
-- @param #USERSOUND self
|
||||||
|
-- @param DCS#country Country The country to play the usersound to.
|
||||||
|
-- @return #USERSOUND The usersound instance.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
|
-- BlueVictory:ToCountry( country.id.USA ) -- Play the sound that Blue has won to the USA country.
|
||||||
|
--
|
||||||
|
function USERSOUND:ToCountry( Country ) --R2.3
|
||||||
|
|
||||||
|
trigger.action.outSoundForCountry( Country, self.UserSoundFileName )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Play the usersound to the given @{Wrapper.Group}.
|
||||||
|
-- @param #USERSOUND self
|
||||||
|
-- @param Wrapper.Group#GROUP Group The @{Wrapper.Group} to play the usersound to.
|
||||||
|
-- @return #USERSOUND The usersound instance.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
|
-- local PlayerGroup = GROUP:FindByName( "PlayerGroup" ) -- Search for the active group named "PlayerGroup", that contains a human player.
|
||||||
|
-- BlueVictory:ToGroup( PlayerGroup ) -- Play the sound that Blue has won to the player group.
|
||||||
|
--
|
||||||
|
function USERSOUND:ToGroup( Group ) --R2.3
|
||||||
|
|
||||||
|
trigger.action.outSoundForGroup( Group:GetID(), self.UserSoundFileName )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
183
Moose Development/Moose/Core/Velocity.lua
Normal file
183
Moose Development/Moose/Core/Velocity.lua
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
--- **Core** -- VELOCITY models a speed, which can be expressed in various formats according the Settings.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
-- ### Contributions:
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Core.Velocity
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
do -- Velocity
|
||||||
|
|
||||||
|
--- @type VELOCITY
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
|
--- VELOCITY models a speed, which can be expressed in various formats according the Settings.
|
||||||
|
--
|
||||||
|
-- ## VELOCITY constructor
|
||||||
|
--
|
||||||
|
-- * @{#VELOCITY.New}(): Creates a new VELOCITY object.
|
||||||
|
--
|
||||||
|
-- @field #VELOCITY
|
||||||
|
VELOCITY = {
|
||||||
|
ClassName = "VELOCITY",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- VELOCITY Constructor.
|
||||||
|
-- @param #VELOCITY self
|
||||||
|
-- @param #number VelocityMps The velocity in meters per second.
|
||||||
|
-- @return #VELOCITY
|
||||||
|
function VELOCITY:New( VelocityMps )
|
||||||
|
local self = BASE:Inherit( self, BASE:New() ) -- #VELOCITY
|
||||||
|
self:F( {} )
|
||||||
|
self.Velocity = VelocityMps
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the velocity in Mps (meters per second).
|
||||||
|
-- @param #VELOCITY self
|
||||||
|
-- @param #number VelocityMps The velocity in meters per second.
|
||||||
|
-- @return #VELOCITY
|
||||||
|
function VELOCITY:Set( VelocityMps )
|
||||||
|
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.
|
||||||
|
function VELOCITY:Get()
|
||||||
|
return self.Velocity
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the velocity in Kmph (kilometers per hour).
|
||||||
|
-- @param #VELOCITY self
|
||||||
|
-- @param #number VelocityKmph The velocity in kilometers per hour.
|
||||||
|
-- @return #VELOCITY
|
||||||
|
function VELOCITY:SetKmph( VelocityKmph )
|
||||||
|
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
|
||||||
|
|
||||||
|
--- Set the velocity in Miph (miles per hour).
|
||||||
|
-- @param #VELOCITY self
|
||||||
|
-- @param #number VelocityMiph The velocity in miles per hour.
|
||||||
|
-- @return #VELOCITY
|
||||||
|
function VELOCITY:SetMiph( VelocityMiph )
|
||||||
|
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.
|
||||||
|
function VELOCITY:GetMiph()
|
||||||
|
return UTILS.MpsToMiph( self.Velocity )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the velocity in text, according the player @{Settings}.
|
||||||
|
-- @param #VELOCITY self
|
||||||
|
-- @param Core.Settings#SETTINGS Settings
|
||||||
|
-- @return #string The velocity in text.
|
||||||
|
function VELOCITY:GetText( Settings )
|
||||||
|
local Settings = Settings or _SETTINGS
|
||||||
|
if self.Velocity ~= 0 then
|
||||||
|
if Settings:IsMetric() then
|
||||||
|
return string.format( "%d km/h", UTILS.MpsToKmph( self.Velocity ) )
|
||||||
|
else
|
||||||
|
return string.format( "%d mi/h", UTILS.MpsToMiph( self.Velocity ) )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return "stationary"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the velocity in text, according the player or default @{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}
|
||||||
|
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
|
||||||
|
return self:GetText( Settings )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
do -- VELOCITY_POSITIONABLE
|
||||||
|
|
||||||
|
--- @type VELOCITY_POSITIONABLE
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
|
--- # 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.
|
||||||
|
--
|
||||||
|
-- ## 1. VELOCITY_POSITIONABLE constructor
|
||||||
|
--
|
||||||
|
-- * @{#VELOCITY_POSITIONABLE.New}(): Creates a new VELOCITY_POSITIONABLE object.
|
||||||
|
--
|
||||||
|
-- @field #VELOCITY_POSITIONABLE
|
||||||
|
VELOCITY_POSITIONABLE = {
|
||||||
|
ClassName = "VELOCITY_POSITIONABLE",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- VELOCITY_POSITIONABLE Constructor.
|
||||||
|
-- @param #VELOCITY_POSITIONABLE self
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE Positionable The Positionable to monitor the speed.
|
||||||
|
-- @return #VELOCITY_POSITIONABLE
|
||||||
|
function VELOCITY_POSITIONABLE:New( Positionable )
|
||||||
|
local self = BASE:Inherit( self, VELOCITY:New() ) -- #VELOCITY_POSITIONABLE
|
||||||
|
self:F( {} )
|
||||||
|
self.Positionable = Positionable
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the velocity in Mps (meters per second).
|
||||||
|
-- @param #VELOCITY_POSITIONABLE self
|
||||||
|
-- @return #number The velocity in meters per second.
|
||||||
|
function VELOCITY_POSITIONABLE:Get()
|
||||||
|
return self.Positionable:GetVelocityMPS() or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the velocity in Kmph (kilometers per hour).
|
||||||
|
-- @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
|
||||||
|
|
||||||
|
--- Get the velocity in Miph (miles per hour).
|
||||||
|
-- @param #VELOCITY_POSITIONABLE self
|
||||||
|
-- @return #number The velocity in miles per hour.
|
||||||
|
function VELOCITY_POSITIONABLE:GetMiph()
|
||||||
|
return UTILS.MpsToMiph( self.Positionable:GetVelocityMPS() or 0 )
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the velocity in text, according the player or default @{Settings}.
|
||||||
|
-- @param #VELOCITY_POSITIONABLE self
|
||||||
|
-- @return #string The velocity in text according the player or default @{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
|
||||||
|
self.Velocity = self.Positionable:GetVelocityMPS()
|
||||||
|
return self:GetText( Settings )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
File diff suppressed because it is too large
Load Diff
1202
Moose Development/Moose/DCS.lua
Normal file
1202
Moose Development/Moose/DCS.lua
Normal file
File diff suppressed because it is too large
Load Diff
Submodule Moose Development/Moose/Dcs deleted from 53f6e5cd52
2311
Moose Development/Moose/Functional/ATC_Ground.lua
Normal file
2311
Moose Development/Moose/Functional/ATC_Ground.lua
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
4990
Moose Development/Moose/Functional/Artillery.lua
Normal file
4990
Moose Development/Moose/Functional/Artillery.lua
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,12 +2,13 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module CleanUp
|
-- @module Functional.CleanUp
|
||||||
|
-- @image CleanUp_Airbases.JPG
|
||||||
|
|
||||||
--- @type CLEANUP_AIRBASE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
|
--- @type CLEANUP_AIRBASE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
|
||||||
-- @field #map<#string,Wrapper.Airbase#AIRBASE> Airbases Map of Airbases.
|
-- @field #map<#string,Wrapper.Airbase#AIRBASE> Airbases Map of Airbases.
|
||||||
@@ -16,11 +17,8 @@
|
|||||||
--- @type CLEANUP_AIRBASE
|
--- @type CLEANUP_AIRBASE
|
||||||
-- @extends #CLEANUP_AIRBASE.__
|
-- @extends #CLEANUP_AIRBASE.__
|
||||||
|
|
||||||
--- # CLEANUP_AIRBASE, extends @{Base#BASE}
|
--- Keeps airbases clean, and tries to guarantee continuous airbase operations, even under combat.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The CLEANUP_AIRBASE class keeps airbases clean, and tries to guarantee continuous airbase operations, even under combat.
|
|
||||||
-- Specific airbases need to be provided that need to be guarded. Each airbase registered, will be guarded within a zone of 8 km around the airbase.
|
-- Specific airbases need to be provided that need to be guarded. Each airbase registered, will be guarded within a zone of 8 km around the airbase.
|
||||||
-- Any unit that fires a missile, or shoots within the zone of an airbase, will be monitored by CLEANUP_AIRBASE.
|
-- Any unit that fires a missile, or shoots within the zone of an airbase, will be monitored by CLEANUP_AIRBASE.
|
||||||
-- Within the 8km zone, units cannot fire any missile, which prevents the airbase runway to receive missile or bomb hits.
|
-- Within the 8km zone, units cannot fire any missile, which prevents the airbase runway to receive missile or bomb hits.
|
||||||
@@ -173,7 +171,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Destroys a @{Unit} from the simulator, but checks first if it is still existing!
|
--- Destroys a @{Wrapper.Unit} from the simulator, but checks first if it is still existing!
|
||||||
-- @param #CLEANUP_AIRBASE self
|
-- @param #CLEANUP_AIRBASE self
|
||||||
-- @param Wrapper.Unit#UNIT CleanUpUnit The object to be destroyed.
|
-- @param Wrapper.Unit#UNIT CleanUpUnit The object to be destroyed.
|
||||||
function CLEANUP_AIRBASE.__:DestroyUnit( CleanUpUnit )
|
function CLEANUP_AIRBASE.__:DestroyUnit( CleanUpUnit )
|
||||||
@@ -182,7 +180,7 @@ function CLEANUP_AIRBASE.__:DestroyUnit( CleanUpUnit )
|
|||||||
if CleanUpUnit then
|
if CleanUpUnit then
|
||||||
local CleanUpUnitName = CleanUpUnit:GetName()
|
local CleanUpUnitName = CleanUpUnit:GetName()
|
||||||
local CleanUpGroup = CleanUpUnit:GetGroup()
|
local CleanUpGroup = CleanUpUnit:GetGroup()
|
||||||
-- TODO Client bug in 1.5.3
|
-- TODO DCS BUG - Client bug in 1.5.3
|
||||||
if CleanUpGroup:IsAlive() then
|
if CleanUpGroup:IsAlive() then
|
||||||
local CleanUpGroupUnits = CleanUpGroup:GetUnits()
|
local CleanUpGroupUnits = CleanUpGroup:GetUnits()
|
||||||
if #CleanUpGroupUnits == 1 then
|
if #CleanUpGroupUnits == 1 then
|
||||||
@@ -200,7 +198,7 @@ end
|
|||||||
|
|
||||||
--- Destroys a missile from the simulator, but checks first if it is still existing!
|
--- Destroys a missile from the simulator, but checks first if it is still existing!
|
||||||
-- @param #CLEANUP_AIRBASE self
|
-- @param #CLEANUP_AIRBASE self
|
||||||
-- @param Dcs.DCSTypes#Weapon MissileObject
|
-- @param DCS#Weapon MissileObject
|
||||||
function CLEANUP_AIRBASE.__:DestroyMissile( MissileObject )
|
function CLEANUP_AIRBASE.__:DestroyMissile( MissileObject )
|
||||||
self:F( { MissileObject } )
|
self:F( { MissileObject } )
|
||||||
|
|
||||||
@@ -231,7 +229,7 @@ end
|
|||||||
function CLEANUP_AIRBASE.__:OnEventCrash( Event )
|
function CLEANUP_AIRBASE.__:OnEventCrash( Event )
|
||||||
self:F( { Event } )
|
self:F( { Event } )
|
||||||
|
|
||||||
--TODO: This stuff is not working due to a DCS bug. Burning units cannot be destroyed.
|
--TODO: DCS BUG - This stuff is not working due to a DCS bug. Burning units cannot be destroyed.
|
||||||
-- self:T("before getGroup")
|
-- self:T("before getGroup")
|
||||||
-- local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired
|
-- local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired
|
||||||
-- self:T("after getGroup")
|
-- self:T("after getGroup")
|
||||||
@@ -290,9 +288,9 @@ function CLEANUP_AIRBASE.__:OnEventHit( Event )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add the @{DCSWrapper.Unit#Unit} to the CleanUpList for CleanUp.
|
--- Add the @{DCS#Unit} to the CleanUpList for CleanUp.
|
||||||
-- @param #CLEANUP_AIRBASE self
|
-- @param #CLEANUP_AIRBASE self
|
||||||
-- @param Wrapper.Unit#UNIT CleanUpUnit
|
-- @param DCS#UNIT CleanUpUnit
|
||||||
-- @oaram #string CleanUpUnitName
|
-- @oaram #string CleanUpUnitName
|
||||||
function CLEANUP_AIRBASE.__:AddForCleanUp( CleanUpUnit, CleanUpUnitName )
|
function CLEANUP_AIRBASE.__:AddForCleanUp( CleanUpUnit, CleanUpUnitName )
|
||||||
self:F( { CleanUpUnit, CleanUpUnitName } )
|
self:F( { CleanUpUnit, CleanUpUnitName } )
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
--- **Functional** -- Management of target **Designation**. Lase, smoke and illuminate targets.
|
--- **Functional** -- Management of target **Designation**. Lase, smoke and illuminate targets.
|
||||||
--
|
--
|
||||||
-- --
|
|
||||||
--
|
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- DESIGNATE is orchestrating the designation of potential targets executed by a Recce group,
|
-- Orchestrate the designation of potential targets executed by a Recce group,
|
||||||
-- and communicates these to a dedicated attacking group of players,
|
-- and communicates these to a dedicated attacking group of players,
|
||||||
-- so that following a dynamically generated menu system,
|
-- so that following a dynamically generated menu system,
|
||||||
-- each detected set of potential targets can be lased or smoked...
|
-- each detected set of potential targets can be lased or smoked...
|
||||||
@@ -30,22 +28,18 @@
|
|||||||
--
|
--
|
||||||
-- * **FlightControl**: Design & Programming
|
-- * **FlightControl**: Design & Programming
|
||||||
--
|
--
|
||||||
-- @module Designate
|
-- @module Functional.Designate
|
||||||
|
-- @image Designation.JPG
|
||||||
|
|
||||||
do -- DESIGNATE
|
do -- DESIGNATE
|
||||||
|
|
||||||
--- @type DESIGNATE
|
--- @type DESIGNATE
|
||||||
-- @extends Core.Fsm#FSM_PROCESS
|
-- @extends Core.Fsm#FSM_PROCESS
|
||||||
|
|
||||||
--- # DESIGNATE class, extends @{Fsm#FSM}
|
--- Manage the designation of detected targets.
|
||||||
--
|
--
|
||||||
-- DESIGNATE is orchestrating the designation of potential targets executed by a Recce group,
|
-- Targets detected by recce will be communicated to a group of attacking players.
|
||||||
-- and communicates these to a dedicated attacking group of players,
|
-- A menu system is made available that allows to:
|
||||||
-- so that following a dynamically generated menu system,
|
|
||||||
-- each detected set of potential targets can be lased or smoked...
|
|
||||||
--
|
|
||||||
-- Targets can be:
|
|
||||||
--
|
--
|
||||||
-- * **Lased** for a period of time.
|
-- * **Lased** for a period of time.
|
||||||
-- * **Smoked**. Artillery or airplanes with Illuminatino ordonance need to be present. (WIP, but early demo ready.)
|
-- * **Smoked**. Artillery or airplanes with Illuminatino ordonance need to be present. (WIP, but early demo ready.)
|
||||||
@@ -55,8 +49,8 @@ do -- DESIGNATE
|
|||||||
--
|
--
|
||||||
-- * The **DesignateObject** is the object of the DESIGNATE class, which is this class explained in the document.
|
-- * The **DesignateObject** is the object of the DESIGNATE class, which is this class explained in the document.
|
||||||
-- * The **DetectionObject** is the object of a DETECTION_ class (DETECTION_TYPES, DETECTION_AREAS, DETECTION_UNITS), which is executing the detection and grouping of Targets into _DetectionItems_.
|
-- * The **DetectionObject** is the object of a DETECTION_ class (DETECTION_TYPES, DETECTION_AREAS, DETECTION_UNITS), which is executing the detection and grouping of Targets into _DetectionItems_.
|
||||||
-- * **DetectionItems** is the list of detected target groupings by the _DetectionObject_. Each _DetectionItem_ contains a _TargetSet_.
|
-- * **TargetGroups** is the list of detected target groupings by the _DetectionObject_. Each _TargetGroup_ contains a _TargetSet_.
|
||||||
-- * **DetectionItem** is one element of the _DetectionItems_ list, and contains a _TargetSet_.
|
-- * **TargetGroup** is one element of the __TargetGroups__ list, and contains a _TargetSet_.
|
||||||
-- * The **TargetSet** is a SET_UNITS collection of _Targets_, that have been detected by the _DetectionObject_.
|
-- * The **TargetSet** is a SET_UNITS collection of _Targets_, that have been detected by the _DetectionObject_.
|
||||||
-- * A **Target** is a detected UNIT object by the _DetectionObject_.
|
-- * A **Target** is a detected UNIT object by the _DetectionObject_.
|
||||||
-- * A **Threat Level** is a number from 0 to 10 that is calculated based on the threat of the Target in an Air to Ground battle scenario.
|
-- * A **Threat Level** is a number from 0 to 10 that is calculated based on the threat of the Target in an Air to Ground battle scenario.
|
||||||
@@ -67,39 +61,122 @@ do -- DESIGNATE
|
|||||||
-- * A **Player** is an active CLIENT object containing a human player.
|
-- * A **Player** is an active CLIENT object containing a human player.
|
||||||
-- * A **Designate Menu** is the menu that is dynamically created during the designation process for each _AttackGroup_.
|
-- * A **Designate Menu** is the menu that is dynamically created during the designation process for each _AttackGroup_.
|
||||||
--
|
--
|
||||||
-- The RecceSet is continuously detecting for potential Targets, executing its task as part of the DetectionObject.
|
-- ## 0. Player Manual
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- A typical mission setup would require Recce (a @{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.
|
||||||
|
--
|
||||||
|
-- **Recce** require to have Line of Sight (LOS) towards the targets.
|
||||||
|
-- The **Recce** will report any detected targets to the Players (on the picture Observers).
|
||||||
|
-- When targets are detected, a menu will be made available that allows those **TargetGroups** to be designated.
|
||||||
|
-- Designation can be done by Lasing, Smoking and Illumination.
|
||||||
|
-- Smoking is useful during the day, while illumination is recommended to be used during the night.
|
||||||
|
-- Smoking can designate specific targets, but not very precise, while lasing is very accurate and allows to
|
||||||
|
-- players to attack the targets using laser guided bombs or rockets.
|
||||||
|
-- Illumination will lighten up the Target Area.
|
||||||
|
--
|
||||||
|
-- **Recce** can be ground based or airborne. Airborne **Recce** (AFAC) can be really useful to designate a large amount of targets
|
||||||
|
-- in a wide open area, as airborne **Recce** has a large LOS.
|
||||||
|
-- However, ground based **Recce** are very useful to smoke or illuminate targets, as they can be much closer
|
||||||
|
-- to the Target Area.
|
||||||
|
--
|
||||||
|
-- It is recommended to make the **Recce** invisible and immortal using the Mission Editor in DCS World.
|
||||||
|
-- This will ensure that the detection process won't be interrupted and that targets can be designated.
|
||||||
|
-- However, you don't have to, so to simulate a more real-word situation or simulation, **Recce can also be destroyed**!
|
||||||
|
--
|
||||||
|
-- ### 0.1. Player View (Observer)
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- The RecceSet is continuously detecting for potential Targets,
|
||||||
|
-- executing its task as part of the DetectionObject.
|
||||||
-- Once Targets have been detected, the DesignateObject will trigger the **Detect Event**.
|
-- Once Targets have been detected, the DesignateObject will trigger the **Detect Event**.
|
||||||
--
|
--
|
||||||
-- In order to prevent an overflow in the DesignateObject of detected targets, there is a maximum
|
-- In order to prevent an overflow in the DesignateObject of detected targets,
|
||||||
-- amount of DetectionItems that can be put in **scope** of the DesignateObject.
|
-- there is a maximum amount of TargetGroups
|
||||||
|
-- that can be put in **scope** of the DesignateObject.
|
||||||
-- We call this the **MaximumDesignations** term.
|
-- We call this the **MaximumDesignations** term.
|
||||||
--
|
--
|
||||||
-- As part of the Detect Event, the DetectionItems list is used by the DesignateObject to provide the Players with:
|
-- ### 0.2. Designate Menu
|
||||||
--
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- For each detected TargetGroup, there is:
|
||||||
|
--
|
||||||
|
-- * A **Designate Menu** are created and continuously refreshed, containing the **DesignationID** and the **Designation Status**.
|
||||||
-- * The RecceGroups are reporting to each AttackGroup, sending **Messages** containing the Threat Level and the TargetSet composition.
|
-- * The RecceGroups are reporting to each AttackGroup, sending **Messages** containing the Threat Level and the TargetSet composition.
|
||||||
-- * **Menu options** are created and updated for each AttackGroup, containing the Detection ID and the Coordinates.
|
|
||||||
--
|
--
|
||||||
-- A Player can then select an action from the Designate Menu.
|
-- A Player can then select an action from the **Designate Menu**.
|
||||||
|
-- The Designation Status is shown between the ( ).
|
||||||
--
|
--
|
||||||
-- **Note that each selected action will be executed for a TargetSet, thus the Target grouping done by the DetectionObject.**
|
-- It indicates for each TargetGroup the current active designation action applied:
|
||||||
--
|
--
|
||||||
-- Each **Menu Option** in the Designate Menu has two modes:
|
-- * An "I" for Illumnation designation.
|
||||||
|
-- * An "S" for Smoking designation.
|
||||||
|
-- * An "L" for Lasing designation.
|
||||||
|
--
|
||||||
|
-- Note that multiple designation methods can be active at the same time!
|
||||||
|
-- Note the **Auto Lase** option. When switched on, the available **Recce** will lase
|
||||||
|
-- Targets when detected.
|
||||||
--
|
--
|
||||||
-- 1. If the TargetSet **is not being designated**, then the **Designate Menu** option for the target Set will provide options to **Lase** or **Smoke** the targets.
|
-- Targets are designated per **Threat Level**.
|
||||||
-- 2. If the Target Set **is being designated**, then the **Designate Menu** option will provide an option to stop or cancel the designation.
|
-- The most threatening targets from an Air to Ground perspective, are designated first!
|
||||||
|
-- This is for all designation methods.
|
||||||
--
|
--
|
||||||
-- While designating, the RecceGroups will report any change in TargetSet composition or Target presence.
|
-- 
|
||||||
--
|
--
|
||||||
-- The following logic is executed when a TargetSet is selected to be *lased* from the Designation Menu:
|
-- Each Designate Menu has a sub menu structure, which allows specific actions to be triggered:
|
||||||
--
|
--
|
||||||
-- * The RecceSet is searched for any Recce that is within *designation distance* from a Target in the TargetSet that is currently not being designated.
|
-- * Lase Targets using a specific laser code.
|
||||||
|
-- * Smoke Targets using a specific smoke color.
|
||||||
|
-- * Illuminate areas.
|
||||||
|
--
|
||||||
|
-- ### 0.3. Lasing Targets
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- Lasing targets is done as expected. Each available Recce can lase only ONE target through!
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- Lasing can be done for specific laser codes. The Su-25T requires laser code 1113, while the A-10A requires laser code 1680.
|
||||||
|
-- For those, specific menu options can be made available for players to lase with these codes.
|
||||||
|
-- Auto Lase (as explained above), will ensure continuous lasing of available targets.
|
||||||
|
-- The status report shows which targets are being designated.
|
||||||
|
--
|
||||||
|
-- The following logic is executed when a TargetGroup is selected to be *lased* from the Designation Menu:
|
||||||
|
--
|
||||||
|
-- * The RecceSet is searched for any Recce that is within *designation distance* from a Target in the TargetGroup that is currently not being designated.
|
||||||
-- * If there is a Recce found that is currently no designating a target, and is within designation distance from the Target, then that Target will be designated.
|
-- * If there is a Recce found that is currently no designating a target, and is within designation distance from the Target, then that Target will be designated.
|
||||||
-- * During designation, any Recce that does not have Line of Sight (LOS) and is not within disignation distance from the Target, will stop designating the Target, and a report is given.
|
-- * During designation, any Recce that does not have Line of Sight (LOS) and is not within disignation distance from the Target, will stop designating the Target, and a report is given.
|
||||||
-- * When a Recce is designating a Target, and that Target is destroyed, then the Recce will stop designating the Target, and will report the event.
|
-- * When a Recce is designating a Target, and that Target is destroyed, then the Recce will stop designating the Target, and will report the event.
|
||||||
-- * When a Recce is designating a Target, and that Recce is destroyed, then the Recce will be removed from the RecceSet and designation will stop without reporting.
|
-- * When a Recce is designating a Target, and that Recce is destroyed, then the Recce will be removed from the RecceSet and designation will stop without reporting.
|
||||||
-- * When all RecceGroups are destroyed from the RecceSet, then the DesignationObject will stop functioning, and nothing will be reported.
|
-- * When all RecceGroups are destroyed from the RecceSet, then the DesignationObject will stop functioning, and nothing will be reported.
|
||||||
--
|
--
|
||||||
-- In this way, the DesignationObject assists players to designate ground targets for a coordinated attack!
|
-- In this way, DESIGNATE assists players to designate ground targets for a coordinated attack!
|
||||||
|
--
|
||||||
|
-- ### 0.4. Illuminating Targets
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- Illumination bombs are fired between 500 and 700 meters altitude and will burn about 2 minutes, while slowly decending.
|
||||||
|
-- Each available recce within range will fire an illumination bomb.
|
||||||
|
-- Illumination bombs can be fired in while lasing targets.
|
||||||
|
-- When illumination bombs are fired, it will take about 2 minutes until a sequent bomb run can be requested using the menus.
|
||||||
|
--
|
||||||
|
-- ### 0.5. Smoking Targets
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- Smoke will fire for 5 minutes.
|
||||||
|
-- Each available recce within range will smoke a target.
|
||||||
|
-- Smoking can be requested while lasing targets.
|
||||||
|
-- Smoke will appear "around" the targets, because of accuracy limitations.
|
||||||
|
--
|
||||||
--
|
--
|
||||||
-- Have FUN!
|
-- Have FUN!
|
||||||
--
|
--
|
||||||
@@ -109,7 +186,7 @@ do -- DESIGNATE
|
|||||||
--
|
--
|
||||||
-- ## 2. DESIGNATE is a FSM
|
-- ## 2. DESIGNATE is a FSM
|
||||||
--
|
--
|
||||||
-- 
|
-- Designate is a finite state machine, which allows for controlled transitions of states.
|
||||||
--
|
--
|
||||||
-- ### 2.1 DESIGNATE States
|
-- ### 2.1 DESIGNATE States
|
||||||
--
|
--
|
||||||
@@ -190,7 +267,7 @@ do -- DESIGNATE
|
|||||||
--
|
--
|
||||||
-- ## 6. Designate Menu Location for a Mission
|
-- ## 6. Designate Menu Location for a Mission
|
||||||
--
|
--
|
||||||
-- You can make DESIGNATE work for a @{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.
|
-- 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 @{Mission} object for the designate function.
|
||||||
--
|
--
|
||||||
-- ## 7. Status Report
|
-- ## 7. Status Report
|
||||||
@@ -353,7 +430,8 @@ do -- DESIGNATE
|
|||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
|
|
||||||
self:AddTransition( "*", "Done", "*" )
|
self:AddTransition( "*", "DoneSmoking", "*" )
|
||||||
|
self:AddTransition( "*", "DoneIlluminating", "*" )
|
||||||
|
|
||||||
self:AddTransition( "*", "Status", "*" )
|
self:AddTransition( "*", "Status", "*" )
|
||||||
--- Status Handler OnBefore for DESIGNATE
|
--- Status Handler OnBefore for DESIGNATE
|
||||||
@@ -391,6 +469,7 @@ do -- DESIGNATE
|
|||||||
self.LaseDuration = 60
|
self.LaseDuration = 60
|
||||||
|
|
||||||
self:SetFlashStatusMenu( false )
|
self:SetFlashStatusMenu( false )
|
||||||
|
self:SetFlashDetectionMessages( true )
|
||||||
self:SetMission( Mission )
|
self:SetMission( Mission )
|
||||||
|
|
||||||
self:SetLaserCodes( { 1688, 1130, 4785, 6547, 1465, 4578 } ) -- set self.LaserCodes
|
self:SetLaserCodes( { 1688, 1130, 4785, 6547, 1465, 4578 } ) -- set self.LaserCodes
|
||||||
@@ -398,7 +477,7 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
self:SetThreatLevelPrioritization( false ) -- self.ThreatLevelPrioritization, default is threat level priorization off
|
self:SetThreatLevelPrioritization( false ) -- self.ThreatLevelPrioritization, default is threat level priorization off
|
||||||
self:SetMaximumDesignations( 5 ) -- Sets the maximum designations. The default is 5 designations.
|
self:SetMaximumDesignations( 5 ) -- Sets the maximum designations. The default is 5 designations.
|
||||||
self:SetMaximumDistanceDesignations( 12000 ) -- Sets the maximum distance on which designations can be accepted. The default is 8000 meters.
|
self:SetMaximumDistanceDesignations( 8000 ) -- Sets the maximum distance on which designations can be accepted. The default is 8000 meters.
|
||||||
self:SetMaximumMarkings( 2 ) -- Per target group, a maximum of 2 markings will be made by default.
|
self:SetMaximumMarkings( 2 ) -- Per target group, a maximum of 2 markings will be made by default.
|
||||||
|
|
||||||
self:SetDesignateMenu()
|
self:SetDesignateMenu()
|
||||||
@@ -416,17 +495,27 @@ do -- DESIGNATE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the flashing of the status menu.
|
--- Set the flashing of the status menu for all AttackGroups.
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
-- @param #boolean FlashMenu true: the status menu will be flashed every detection run; false: no flashing of the menu.
|
-- @param #boolean FlashMenu true: the status menu will be flashed every detection run; false: no flashing of the menu.
|
||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- Enable the designate status message flashing...
|
||||||
|
-- Designate:SetFlashStatusMenu( true )
|
||||||
|
--
|
||||||
|
-- -- Disable the designate statusmessage flashing...
|
||||||
|
-- Designate:SetFlashStatusMenu()
|
||||||
|
--
|
||||||
|
-- -- Disable the designate status message flashing...
|
||||||
|
-- Designate:SetFlashStatusMenu( false )
|
||||||
function DESIGNATE:SetFlashStatusMenu( FlashMenu ) --R2.1
|
function DESIGNATE:SetFlashStatusMenu( FlashMenu ) --R2.1
|
||||||
|
|
||||||
self.FlashStatusMenu = {}
|
self.FlashStatusMenu = {}
|
||||||
|
|
||||||
self.AttackSet:ForEachGroup(
|
self.AttackSet:ForEachGroupAlive(
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP GroupReport
|
--- @param Wrapper.Group#GROUP AttackGroup
|
||||||
function( AttackGroup )
|
function( AttackGroup )
|
||||||
self.FlashStatusMenu[AttackGroup] = FlashMenu
|
self.FlashStatusMenu[AttackGroup] = FlashMenu
|
||||||
end
|
end
|
||||||
@@ -435,6 +524,35 @@ do -- DESIGNATE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set the flashing of the new detection messages.
|
||||||
|
-- @param #DESIGNATE self
|
||||||
|
-- @param #boolean FlashDetectionMessage true: The detection message will be flashed every time a new detection was done; false: no messages will be displayed.
|
||||||
|
-- @return #DESIGNATE
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- Enable the message flashing...
|
||||||
|
-- Designate:SetFlashDetectionMessages( true )
|
||||||
|
--
|
||||||
|
-- -- Disable the message flashing...
|
||||||
|
-- Designate:SetFlashDetectionMessages()
|
||||||
|
--
|
||||||
|
-- -- Disable the message flashing...
|
||||||
|
-- Designate:SetFlashDetectionMessages( false )
|
||||||
|
function DESIGNATE:SetFlashDetectionMessages( FlashDetectionMessage )
|
||||||
|
|
||||||
|
self.FlashDetectionMessage = {}
|
||||||
|
|
||||||
|
self.AttackSet:ForEachGroupAlive(
|
||||||
|
|
||||||
|
--- @param Wrapper.Group#GROUP AttackGroup
|
||||||
|
function( AttackGroup )
|
||||||
|
self.FlashDetectionMessage[AttackGroup] = FlashDetectionMessage
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the maximum amount of designations.
|
--- Set the maximum amount of designations.
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
@@ -494,7 +612,7 @@ do -- DESIGNATE
|
|||||||
function DESIGNATE:SetLaserCodes( LaserCodes ) --R2.1
|
function DESIGNATE:SetLaserCodes( LaserCodes ) --R2.1
|
||||||
|
|
||||||
self.LaserCodes = ( type( LaserCodes ) == "table" ) and LaserCodes or { LaserCodes }
|
self.LaserCodes = ( type( LaserCodes ) == "table" ) and LaserCodes or { LaserCodes }
|
||||||
self:E( { LaserCodes = self.LaserCodes } )
|
self:F( { LaserCodes = self.LaserCodes } )
|
||||||
|
|
||||||
self.LaserCodesUsed = {}
|
self.LaserCodesUsed = {}
|
||||||
|
|
||||||
@@ -674,24 +792,27 @@ do -- DESIGNATE
|
|||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
function DESIGNATE:DesignationScope()
|
function DESIGNATE:DesignationScope()
|
||||||
|
|
||||||
local DetectedItems = self.Detection:GetDetectedItems()
|
local DetectedItems = self.Detection:GetDetectedItemsByIndex()
|
||||||
|
|
||||||
local DetectedItemCount = 0
|
local DetectedItemCount = 0
|
||||||
|
|
||||||
for DesignateIndex, Designating in pairs( self.Designating ) do
|
for DesignateIndex, Designating in pairs( self.Designating ) do
|
||||||
local DetectedItem = DetectedItems[DesignateIndex]
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( DesignateIndex )
|
||||||
if DetectedItem then
|
if DetectedItem then
|
||||||
-- Check LOS...
|
-- Check LOS...
|
||||||
local IsDetected = self.Detection:IsDetectedItemDetected( DetectedItem )
|
local IsDetected = self.Detection:IsDetectedItemDetected( DetectedItem )
|
||||||
self:F({IsDetected = IsDetected, DetectedItem })
|
self:F({IsDetected = IsDetected })
|
||||||
if IsDetected == false then
|
if IsDetected == false then
|
||||||
self:F("Removing")
|
self:F("Removing")
|
||||||
-- This Detection is obsolete, remove from the designate scope
|
-- This Detection is obsolete, remove from the designate scope
|
||||||
self.Designating[DesignateIndex] = nil
|
self.Designating[DesignateIndex] = nil
|
||||||
self.AttackSet:ForEachGroup(
|
self.AttackSet:ForEachGroupAlive(
|
||||||
|
--- @param Wrapper.Group#GROUP AttackGroup
|
||||||
function( AttackGroup )
|
function( AttackGroup )
|
||||||
local DetectionText = self.Detection:DetectedItemReportSummary( DesignateIndex, AttackGroup ):Text( ", " )
|
if AttackGroup:IsAlive() == true then
|
||||||
self.CC:GetPositionable():MessageToGroup( "Targets out of LOS\n" .. DetectionText, 10, AttackGroup, self.DesignateName )
|
local DetectionText = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup ):Text( ", " )
|
||||||
|
self.CC:GetPositionable():MessageToGroup( "Targets out of LOS\n" .. DetectionText, 10, AttackGroup, self.DesignateName )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
@@ -711,13 +832,19 @@ do -- DESIGNATE
|
|||||||
if DetectedItem.DistanceRecce <= self.MaximumDistanceDesignations then
|
if DetectedItem.DistanceRecce <= self.MaximumDistanceDesignations then
|
||||||
if self.Designating[DesignateIndex] == nil then
|
if self.Designating[DesignateIndex] == nil then
|
||||||
-- ok, we added one item to the designate scope.
|
-- ok, we added one item to the designate scope.
|
||||||
self.AttackSet:ForEachGroup(
|
self.AttackSet:ForEachGroupAlive(
|
||||||
function( AttackGroup )
|
function( AttackGroup )
|
||||||
local DetectionText = self.Detection:DetectedItemReportSummary( DesignateIndex, AttackGroup ):Text( ", " )
|
if self.FlashDetectionMessage[AttackGroup] == true then
|
||||||
self.CC:GetPositionable():MessageToGroup( "Targets detected at \n" .. DetectionText, 10, AttackGroup, self.DesignateName )
|
local DetectionText = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup ):Text( ", " )
|
||||||
|
self.CC:GetPositionable():MessageToGroup( "Targets detected at \n" .. DetectionText, 10, AttackGroup, self.DesignateName )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
self.Designating[DesignateIndex] = ""
|
self.Designating[DesignateIndex] = ""
|
||||||
|
|
||||||
|
-- When we found an item for designation, we stop the loop.
|
||||||
|
-- So each iteration over the detected items, a new detected item will be selected to be designated.
|
||||||
|
-- Until all detected items were found or until there are about 5 designations allocated.
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -733,7 +860,7 @@ do -- DESIGNATE
|
|||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
function DESIGNATE:CoordinateLase()
|
function DESIGNATE:CoordinateLase()
|
||||||
|
|
||||||
local DetectedItems = self.Detection:GetDetectedItems()
|
local DetectedItems = self.Detection:GetDetectedItemsByIndex()
|
||||||
|
|
||||||
for DesignateIndex, Designating in pairs( self.Designating ) do
|
for DesignateIndex, Designating in pairs( self.Designating ) do
|
||||||
local DetectedItem = DetectedItems[DesignateIndex]
|
local DetectedItem = DetectedItems[DesignateIndex]
|
||||||
@@ -753,11 +880,9 @@ do -- DESIGNATE
|
|||||||
-- @param Wrapper.Group#GROUP AttackGroup
|
-- @param Wrapper.Group#GROUP AttackGroup
|
||||||
-- @param #number Duration The time in seconds the report should be visible.
|
-- @param #number Duration The time in seconds the report should be visible.
|
||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
function DESIGNATE:SendStatus( MenuAttackGroup, Duration )
|
function DESIGNATE:SendStatus( MenuAttackGroup )
|
||||||
|
|
||||||
Duration = Duration or 10
|
self.AttackSet:ForEachGroupAlive(
|
||||||
|
|
||||||
self.AttackSet:ForEachGroup(
|
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP GroupReport
|
--- @param Wrapper.Group#GROUP GroupReport
|
||||||
function( AttackGroup )
|
function( AttackGroup )
|
||||||
@@ -765,24 +890,33 @@ do -- DESIGNATE
|
|||||||
if self.FlashStatusMenu[AttackGroup] or ( MenuAttackGroup and ( AttackGroup:GetName() == MenuAttackGroup:GetName() ) ) then
|
if self.FlashStatusMenu[AttackGroup] or ( MenuAttackGroup and ( AttackGroup:GetName() == MenuAttackGroup:GetName() ) ) then
|
||||||
|
|
||||||
local DetectedReport = REPORT:New( "Targets ready for Designation:" )
|
local DetectedReport = REPORT:New( "Targets ready for Designation:" )
|
||||||
local DetectedItems = self.Detection:GetDetectedItems()
|
local DetectedItems = self.Detection:GetDetectedItemsByIndex()
|
||||||
|
|
||||||
for DesignateIndex, Designating in pairs( self.Designating ) do
|
for DesignateIndex, Designating in pairs( self.Designating ) do
|
||||||
local DetectedItem = DetectedItems[DesignateIndex]
|
local DetectedItem = DetectedItems[DesignateIndex]
|
||||||
if DetectedItem then
|
if DetectedItem then
|
||||||
local Report = self.Detection:DetectedItemReportSummary( DesignateIndex, AttackGroup ):Text( ", " )
|
local Report = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup ):Text( ", " )
|
||||||
DetectedReport:Add( string.rep( "-", 140 ) )
|
DetectedReport:Add( string.rep( "-", 140 ) )
|
||||||
DetectedReport:Add( " - " .. Report )
|
DetectedReport:Add( " - " .. Report )
|
||||||
|
if string.find( Designating, "L" ) then
|
||||||
|
DetectedReport:Add( " - " .. "Lasing Targets" )
|
||||||
|
end
|
||||||
|
if string.find( Designating, "S" ) then
|
||||||
|
DetectedReport:Add( " - " .. "Smoking Targets" )
|
||||||
|
end
|
||||||
|
if string.find( Designating, "I" ) then
|
||||||
|
DetectedReport:Add( " - " .. "Illuminating Area" )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local CC = self.CC:GetPositionable()
|
local CC = self.CC:GetPositionable()
|
||||||
|
|
||||||
CC:MessageToGroup( DetectedReport:Text( "\n" ), Duration, AttackGroup, self.DesignateName )
|
CC:MessageTypeToGroup( DetectedReport:Text( "\n" ), MESSAGE.Type.Information, AttackGroup, self.DesignateName )
|
||||||
|
|
||||||
local DesignationReport = REPORT:New( "Marking Targets:\n" )
|
local DesignationReport = REPORT:New( "Marking Targets:" )
|
||||||
|
|
||||||
self.RecceSet:ForEachGroup(
|
self.RecceSet:ForEachGroupAlive(
|
||||||
function( RecceGroup )
|
function( RecceGroup )
|
||||||
local RecceUnits = RecceGroup:GetUnits()
|
local RecceUnits = RecceGroup:GetUnits()
|
||||||
for UnitID, RecceData in pairs( RecceUnits ) do
|
for UnitID, RecceData in pairs( RecceUnits ) do
|
||||||
@@ -794,7 +928,7 @@ do -- DESIGNATE
|
|||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
CC:MessageToGroup( DesignationReport:Text(), Duration, AttackGroup, self.DesignateName )
|
CC:MessageTypeToGroup( DesignationReport:Text(), MESSAGE.Type.Information, AttackGroup, self.DesignateName )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
@@ -802,91 +936,112 @@ do -- DESIGNATE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets the Designate Menu.
|
|
||||||
|
--- Sets the Designate Menu for one attack groups.
|
||||||
|
-- @param #DESIGNATE self
|
||||||
|
-- @return #DESIGNATE
|
||||||
|
function DESIGNATE:SetMenu( AttackGroup )
|
||||||
|
|
||||||
|
self.MenuDesignate = self.MenuDesignate or {}
|
||||||
|
|
||||||
|
local MissionMenu = nil
|
||||||
|
|
||||||
|
if self.Mission then
|
||||||
|
--MissionMenu = self.Mission:GetRootMenu( AttackGroup )
|
||||||
|
MissionMenu = self.Mission:GetMenu( AttackGroup )
|
||||||
|
end
|
||||||
|
|
||||||
|
local MenuTime = timer.getTime()
|
||||||
|
|
||||||
|
self.MenuDesignate[AttackGroup] = MENU_GROUP_DELAYED:New( AttackGroup, self.DesignateName, MissionMenu ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
local MenuDesignate = self.MenuDesignate[AttackGroup] -- Core.Menu#MENU_GROUP_DELAYED
|
||||||
|
|
||||||
|
-- Set Menu option for auto lase
|
||||||
|
|
||||||
|
if self.AutoLase then
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Auto Lase Off", MenuDesignate, self.MenuAutoLase, self, false ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
else
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Auto Lase On", MenuDesignate, self.MenuAutoLase, self, true ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
end
|
||||||
|
|
||||||
|
local StatusMenu = MENU_GROUP_DELAYED:New( AttackGroup, "Status", MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Report Status", StatusMenu, self.MenuStatus, self, AttackGroup ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
|
||||||
|
if self.FlashStatusMenu[AttackGroup] then
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Flash Status Report Off", StatusMenu, self.MenuFlashStatus, self, AttackGroup, false ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
else
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Flash Status Report On", StatusMenu, self.MenuFlashStatus, self, AttackGroup, true ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
end
|
||||||
|
|
||||||
|
local DesignateCount = 0
|
||||||
|
|
||||||
|
for DesignateIndex, Designating in pairs( self.Designating ) do
|
||||||
|
|
||||||
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( DesignateIndex )
|
||||||
|
|
||||||
|
if DetectedItem then
|
||||||
|
|
||||||
|
local Coord = self.Detection:GetDetectedItemCoordinate( DetectedItem )
|
||||||
|
local ID = self.Detection:GetDetectedItemID( DetectedItem )
|
||||||
|
local MenuText = ID --.. ", " .. Coord:ToStringA2G( AttackGroup )
|
||||||
|
|
||||||
|
MenuText = string.format( "(%3s) %s", Designating, MenuText )
|
||||||
|
local DetectedMenu = MENU_GROUP_DELAYED:New( AttackGroup, MenuText, MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
|
||||||
|
-- Build the Lasing menu.
|
||||||
|
if string.find( Designating, "L", 1, true ) == nil then
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Search other target", DetectedMenu, self.MenuForget, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
for LaserCode, MenuText in pairs( self.MenuLaserCodes ) do
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, string.format( MenuText, LaserCode ), DetectedMenu, self.MenuLaseCode, self, DesignateIndex, 60, LaserCode ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
end
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Lase with random laser code(s)", DetectedMenu, self.MenuLaseOn, self, DesignateIndex, 60 ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
else
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Stop lasing", DetectedMenu, self.MenuLaseOff, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Build the Smoking menu.
|
||||||
|
if string.find( Designating, "S", 1, true ) == nil then
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Smoke red", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Red ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Smoke blue", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Blue ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Smoke green", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Green ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Smoke white", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.White ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Smoke orange", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Orange ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Build the Illuminate menu.
|
||||||
|
if string.find( Designating, "I", 1, true ) == nil then
|
||||||
|
MENU_GROUP_COMMAND_DELAYED:New( AttackGroup, "Illuminate", DetectedMenu, self.MenuIlluminate, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DesignateCount = DesignateCount + 1
|
||||||
|
if DesignateCount > 10 then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MenuDesignate:Remove( MenuTime, self.DesignateName )
|
||||||
|
MenuDesignate:Set()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Sets the Designate Menu for all the attack groups.
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
function DESIGNATE:SetDesignateMenu()
|
function DESIGNATE:SetDesignateMenu()
|
||||||
|
|
||||||
self.AttackSet:Flush()
|
self.AttackSet:Flush( self )
|
||||||
|
|
||||||
|
local Delay = 1
|
||||||
|
|
||||||
self.AttackSet:ForEachGroup(
|
self.AttackSet:ForEachGroupAlive(
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP GroupReport
|
--- @param Wrapper.Group#GROUP GroupReport
|
||||||
function( AttackGroup )
|
function( AttackGroup )
|
||||||
self.MenuDesignate = self.MenuDesignate or {}
|
|
||||||
|
|
||||||
local MissionMenu = nil
|
|
||||||
|
|
||||||
if self.Mission then
|
|
||||||
MissionMenu = self.Mission:GetRootMenu( AttackGroup )
|
|
||||||
end
|
|
||||||
|
|
||||||
local MenuTime = timer.getTime()
|
|
||||||
|
|
||||||
self.MenuDesignate[AttackGroup] = MENU_GROUP:New( AttackGroup, self.DesignateName, MissionMenu ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
local MenuDesignate = self.MenuDesignate[AttackGroup] -- Core.Menu#MENU_GROUP
|
|
||||||
|
|
||||||
-- Set Menu option for auto lase
|
|
||||||
|
|
||||||
if self.AutoLase then
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Auto Lase Off", MenuDesignate, self.MenuAutoLase, self, false ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
else
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Auto Lase On", MenuDesignate, self.MenuAutoLase, self, true ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
end
|
|
||||||
|
|
||||||
local StatusMenu = MENU_GROUP:New( AttackGroup, "Status", MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Report Status 15s", StatusMenu, self.MenuStatus, self, AttackGroup, 15 ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Report Status 30s", StatusMenu, self.MenuStatus, self, AttackGroup, 30 ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Report Status 60s", StatusMenu, self.MenuStatus, self, AttackGroup, 60 ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
|
|
||||||
if self.FlashStatusMenu[AttackGroup] then
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Flash Status Report Off", StatusMenu, self.MenuFlashStatus, self, AttackGroup, false ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
else
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Flash Status Report On", StatusMenu, self.MenuFlashStatus, self, AttackGroup, true ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
end
|
|
||||||
|
|
||||||
for DesignateIndex, Designating in pairs( self.Designating ) do
|
self:ScheduleOnce( Delay, self.SetMenu, self, AttackGroup )
|
||||||
|
Delay = Delay + 1
|
||||||
local DetectedItem = self.Detection:GetDetectedItem( DesignateIndex )
|
end
|
||||||
|
|
||||||
if DetectedItem then
|
|
||||||
|
|
||||||
local Coord = self.Detection:GetDetectedItemCoordinate( DesignateIndex )
|
|
||||||
local ID = self.Detection:GetDetectedItemID( DesignateIndex )
|
|
||||||
local MenuText = ID .. ", " .. Coord:ToStringA2G( AttackGroup )
|
|
||||||
|
|
||||||
if Designating == "" then
|
|
||||||
MenuText = "(-) " .. MenuText
|
|
||||||
local DetectedMenu = MENU_GROUP:New( AttackGroup, MenuText, MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Search other target", DetectedMenu, self.MenuForget, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
for LaserCode, MenuText in pairs( self.MenuLaserCodes ) do
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, string.format( MenuText, LaserCode ), DetectedMenu, self.MenuLaseCode, self, DesignateIndex, 60, LaserCode ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
end
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Lase with random laser code(s)", DetectedMenu, self.MenuLaseOn, self, DesignateIndex, 60 ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke red", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Red ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke blue", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Blue ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke green", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Green ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke white", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.White ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke orange", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Orange ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Illuminate", DetectedMenu, self.MenuIlluminate, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
else
|
|
||||||
if Designating == "Laser" then
|
|
||||||
MenuText = "(L) " .. MenuText
|
|
||||||
elseif Designating == "Smoke" then
|
|
||||||
MenuText = "(S) " .. MenuText
|
|
||||||
elseif Designating == "Illuminate" then
|
|
||||||
MenuText = "(I) " .. MenuText
|
|
||||||
end
|
|
||||||
local DetectedMenu = MENU_GROUP:New( AttackGroup, MenuText, MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
if Designating == "Laser" then
|
|
||||||
MENU_GROUP_COMMAND:New( AttackGroup, "Stop lasing", DetectedMenu, self.MenuLaseOff, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
|
||||||
else
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
MenuDesignate:Remove( MenuTime, self.DesignateName )
|
|
||||||
end
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -894,18 +1049,18 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
---
|
---
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
function DESIGNATE:MenuStatus( AttackGroup, Duration )
|
function DESIGNATE:MenuStatus( AttackGroup )
|
||||||
|
|
||||||
self:E("Status")
|
self:F("Status")
|
||||||
|
|
||||||
self:SendStatus( AttackGroup, Duration )
|
self:SendStatus( AttackGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
function DESIGNATE:MenuFlashStatus( AttackGroup, Flash )
|
function DESIGNATE:MenuFlashStatus( AttackGroup, Flash )
|
||||||
|
|
||||||
self:E("Flash Status")
|
self:F("Flash Status")
|
||||||
|
|
||||||
self.FlashStatusMenu[AttackGroup] = Flash
|
self.FlashStatusMenu[AttackGroup] = Flash
|
||||||
self:SetDesignateMenu()
|
self:SetDesignateMenu()
|
||||||
@@ -916,9 +1071,9 @@ do -- DESIGNATE
|
|||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
function DESIGNATE:MenuForget( Index )
|
function DESIGNATE:MenuForget( Index )
|
||||||
|
|
||||||
self:E("Forget")
|
self:F("Forget")
|
||||||
|
|
||||||
self.Designating[Index] = nil
|
self.Designating[Index] = ""
|
||||||
self:SetDesignateMenu()
|
self:SetDesignateMenu()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -926,7 +1081,7 @@ do -- DESIGNATE
|
|||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
function DESIGNATE:MenuAutoLase( AutoLase )
|
function DESIGNATE:MenuAutoLase( AutoLase )
|
||||||
|
|
||||||
self:E("AutoLase")
|
self:F("AutoLase")
|
||||||
|
|
||||||
self:SetAutoLase( AutoLase, true )
|
self:SetAutoLase( AutoLase, true )
|
||||||
end
|
end
|
||||||
@@ -935,28 +1090,34 @@ do -- DESIGNATE
|
|||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
function DESIGNATE:MenuSmoke( Index, Color )
|
function DESIGNATE:MenuSmoke( Index, Color )
|
||||||
|
|
||||||
self:E("Designate through Smoke")
|
self:F("Designate through Smoke")
|
||||||
|
|
||||||
self.Designating[Index] = "Smoke"
|
if string.find( self.Designating[Index], "S" ) == nil then
|
||||||
|
self.Designating[Index] = self.Designating[Index] .. "S"
|
||||||
|
end
|
||||||
self:Smoke( Index, Color )
|
self:Smoke( Index, Color )
|
||||||
|
self:SetDesignateMenu()
|
||||||
end
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
function DESIGNATE:MenuIlluminate( Index )
|
function DESIGNATE:MenuIlluminate( Index )
|
||||||
|
|
||||||
self:E("Designate through Illumination")
|
self:F("Designate through Illumination")
|
||||||
|
|
||||||
self.Designating[Index] = "Illuminate"
|
if string.find( self.Designating[Index], "I", 1, true ) == nil then
|
||||||
|
self.Designating[Index] = self.Designating[Index] .. "I"
|
||||||
|
end
|
||||||
|
|
||||||
self:__Illuminate( 1, Index )
|
self:__Illuminate( 1, Index )
|
||||||
|
self:SetDesignateMenu()
|
||||||
end
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
function DESIGNATE:MenuLaseOn( Index, Duration )
|
function DESIGNATE:MenuLaseOn( Index, Duration )
|
||||||
|
|
||||||
self:E("Designate through Lase")
|
self:F("Designate through Lase")
|
||||||
|
|
||||||
self:__LaseOn( 1, Index, Duration )
|
self:__LaseOn( 1, Index, Duration )
|
||||||
self:SetDesignateMenu()
|
self:SetDesignateMenu()
|
||||||
@@ -967,7 +1128,7 @@ do -- DESIGNATE
|
|||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
function DESIGNATE:MenuLaseCode( Index, Duration, LaserCode )
|
function DESIGNATE:MenuLaseCode( Index, Duration, LaserCode )
|
||||||
|
|
||||||
self:E( "Designate through Lase using " .. LaserCode )
|
self:F( "Designate through Lase using " .. LaserCode )
|
||||||
|
|
||||||
self:__LaseOn( 1, Index, Duration, LaserCode )
|
self:__LaseOn( 1, Index, Duration, LaserCode )
|
||||||
self:SetDesignateMenu()
|
self:SetDesignateMenu()
|
||||||
@@ -978,9 +1139,9 @@ do -- DESIGNATE
|
|||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
function DESIGNATE:MenuLaseOff( Index, Duration )
|
function DESIGNATE:MenuLaseOff( Index, Duration )
|
||||||
|
|
||||||
self:E("Lasing off")
|
self:F("Lasing off")
|
||||||
|
|
||||||
self.Designating[Index] = ""
|
self.Designating[Index] = string.gsub( self.Designating[Index], "L", "" )
|
||||||
self:__LaseOff( 1, Index )
|
self:__LaseOff( 1, Index )
|
||||||
self:SetDesignateMenu()
|
self:SetDesignateMenu()
|
||||||
end
|
end
|
||||||
@@ -989,10 +1150,12 @@ do -- DESIGNATE
|
|||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
function DESIGNATE:onafterLaseOn( From, Event, To, Index, Duration, LaserCode )
|
function DESIGNATE:onafterLaseOn( From, Event, To, Index, Duration, LaserCode )
|
||||||
|
|
||||||
self.Designating[Index] = "Laser"
|
if string.find( self.Designating[Index], "L", 1, true ) == nil then
|
||||||
|
self.Designating[Index] = self.Designating[Index] .. "L"
|
||||||
|
end
|
||||||
self.LaseStart = timer.getTime()
|
self.LaseStart = timer.getTime()
|
||||||
self.LaseDuration = Duration
|
self.LaseDuration = Duration
|
||||||
self:__Lasing( -1, Index, Duration, LaserCode )
|
self:Lasing( Index, Duration, LaserCode )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -1002,14 +1165,15 @@ do -- DESIGNATE
|
|||||||
function DESIGNATE:onafterLasing( From, Event, To, Index, Duration, LaserCodeRequested )
|
function DESIGNATE:onafterLasing( From, Event, To, Index, Duration, LaserCodeRequested )
|
||||||
|
|
||||||
|
|
||||||
local TargetSetUnit = self.Detection:GetDetectedSet( Index )
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
|
||||||
|
local TargetSetUnit = self.Detection:GetDetectedSet( DetectedItem )
|
||||||
|
|
||||||
local MarkingCount = 0
|
local MarkingCount = 0
|
||||||
local MarkedTypes = {}
|
local MarkedTypes = {}
|
||||||
local ReportTypes = REPORT:New()
|
local ReportTypes = REPORT:New()
|
||||||
local ReportLaserCodes = REPORT:New()
|
local ReportLaserCodes = REPORT:New()
|
||||||
|
|
||||||
TargetSetUnit:Flush()
|
TargetSetUnit:Flush( self )
|
||||||
|
|
||||||
--self:F( { Recces = self.Recces } )
|
--self:F( { Recces = self.Recces } )
|
||||||
for TargetUnit, RecceData in pairs( self.Recces ) do
|
for TargetUnit, RecceData in pairs( self.Recces ) do
|
||||||
@@ -1056,8 +1220,8 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
if not Recce then
|
if not Recce then
|
||||||
|
|
||||||
self:E( "Lasing..." )
|
self:F( "Lasing..." )
|
||||||
self.RecceSet:Flush()
|
self.RecceSet:Flush( self)
|
||||||
|
|
||||||
for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do
|
for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do
|
||||||
for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do
|
for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do
|
||||||
@@ -1085,17 +1249,19 @@ do -- DESIGNATE
|
|||||||
self.LaserCodesUsed[LaserCode] = LaserCodeIndex
|
self.LaserCodesUsed[LaserCode] = LaserCodeIndex
|
||||||
local Spot = RecceUnit:LaseUnit( TargetUnit, LaserCode, Duration )
|
local Spot = RecceUnit:LaseUnit( TargetUnit, LaserCode, Duration )
|
||||||
local AttackSet = self.AttackSet
|
local AttackSet = self.AttackSet
|
||||||
|
local DesignateName = self.DesignateName
|
||||||
|
|
||||||
function Spot:OnAfterDestroyed( From, Event, To )
|
function Spot:OnAfterDestroyed( From, Event, To )
|
||||||
self:E( "Destroyed Message" )
|
self.Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() .. " destroyed. " .. TargetSetUnit:Count() .. " targets left.",
|
||||||
self.Recce:ToSetGroup( "Target " .. TargetUnit:GetTypeName() .. " destroyed. " .. TargetSetUnit:Count() .. " targets left.", 5, AttackSet, self.DesignateName )
|
5, AttackSet, self.DesignateName )
|
||||||
end
|
end
|
||||||
|
|
||||||
self.Recces[TargetUnit] = RecceUnit
|
self.Recces[TargetUnit] = RecceUnit
|
||||||
RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.", 5, self.AttackSet, self.DesignateName )
|
|
||||||
-- OK. We have assigned for the Recce a TargetUnit. We can exit the function.
|
-- OK. We have assigned for the Recce a TargetUnit. We can exit the function.
|
||||||
MarkingCount = MarkingCount + 1
|
MarkingCount = MarkingCount + 1
|
||||||
local TargetUnitType = TargetUnit:GetTypeName()
|
local TargetUnitType = TargetUnit:GetTypeName()
|
||||||
|
--RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.",
|
||||||
|
-- 5, self.AttackSet, DesignateName )
|
||||||
if not MarkedTypes[TargetUnitType] then
|
if not MarkedTypes[TargetUnitType] then
|
||||||
MarkedTypes[TargetUnitType] = true
|
MarkedTypes[TargetUnitType] = true
|
||||||
ReportTypes:Add(TargetUnitType)
|
ReportTypes:Add(TargetUnitType)
|
||||||
@@ -1118,7 +1284,7 @@ do -- DESIGNATE
|
|||||||
Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 5, self.AttackSet, self.DesignateName )
|
Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 5, self.AttackSet, self.DesignateName )
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
MarkingCount = MarkingCount + 1
|
--MarkingCount = MarkingCount + 1
|
||||||
local TargetUnitType = TargetUnit:GetTypeName()
|
local TargetUnitType = TargetUnit:GetTypeName()
|
||||||
if not MarkedTypes[TargetUnitType] then
|
if not MarkedTypes[TargetUnitType] then
|
||||||
MarkedTypes[TargetUnitType] = true
|
MarkedTypes[TargetUnitType] = true
|
||||||
@@ -1146,16 +1312,14 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
local MarkedTypesText = ReportTypes:Text(', ')
|
local MarkedTypesText = ReportTypes:Text(', ')
|
||||||
local MarkedLaserCodesText = ReportLaserCodes:Text(', ')
|
local MarkedLaserCodesText = ReportLaserCodes:Text(', ')
|
||||||
for MarkedType, MarketCount in pairs( MarkedTypes ) do
|
self.CC:GetPositionable():MessageToSetGroup( "Marking " .. MarkingCount .. " x " .. MarkedTypesText .. ", code " .. MarkedLaserCodesText .. ".", 5, self.AttackSet, self.DesignateName )
|
||||||
self.CC:GetPositionable():MessageToSetGroup( "Marking " .. MarkingCount .. " x " .. MarkedTypesText .. " with lasers " .. MarkedLaserCodesText .. ".", 5, self.AttackSet, self.DesignateName )
|
|
||||||
end
|
|
||||||
|
|
||||||
self:__Lasing( -30, Index, Duration, LaserCodeRequested )
|
self:__Lasing( -30, Index, Duration, LaserCodeRequested )
|
||||||
|
|
||||||
self:SetDesignateMenu()
|
self:SetDesignateMenu()
|
||||||
|
|
||||||
else
|
else
|
||||||
self:__LaseOff( 1 )
|
self:LaseOff( Index )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1171,7 +1335,8 @@ do -- DESIGNATE
|
|||||||
CC:MessageToSetGroup( "Stopped lasing.", 5, self.AttackSet, self.DesignateName )
|
CC:MessageToSetGroup( "Stopped lasing.", 5, self.AttackSet, self.DesignateName )
|
||||||
end
|
end
|
||||||
|
|
||||||
local TargetSetUnit = self.Detection:GetDetectedSet( Index )
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
|
||||||
|
local TargetSetUnit = self.Detection:GetDetectedSet( DetectedItem )
|
||||||
|
|
||||||
local Recces = self.Recces
|
local Recces = self.Recces
|
||||||
|
|
||||||
@@ -1185,6 +1350,7 @@ do -- DESIGNATE
|
|||||||
self.Recces = {}
|
self.Recces = {}
|
||||||
self.LaserCodesUsed = {}
|
self.LaserCodesUsed = {}
|
||||||
|
|
||||||
|
self.Designating[Index] = string.gsub( self.Designating[Index], "L", "" )
|
||||||
self:SetDesignateMenu()
|
self:SetDesignateMenu()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1194,7 +1360,8 @@ do -- DESIGNATE
|
|||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
function DESIGNATE:onafterSmoke( From, Event, To, Index, Color )
|
function DESIGNATE:onafterSmoke( From, Event, To, Index, Color )
|
||||||
|
|
||||||
local TargetSetUnit = self.Detection:GetDetectedSet( Index )
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
|
||||||
|
local TargetSetUnit = self.Detection:GetDetectedSet( DetectedItem )
|
||||||
local TargetSetUnitCount = TargetSetUnit:Count()
|
local TargetSetUnitCount = TargetSetUnit:Count()
|
||||||
|
|
||||||
local MarkedCount = 0
|
local MarkedCount = 0
|
||||||
@@ -1207,7 +1374,7 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
MarkedCount = MarkedCount + 1
|
MarkedCount = MarkedCount + 1
|
||||||
|
|
||||||
self:E( "Smoking ..." )
|
self:F( "Smoking ..." )
|
||||||
|
|
||||||
local RecceGroup = self.RecceSet:FindNearestGroupFromPointVec2(SmokeUnit:GetPointVec2())
|
local RecceGroup = self.RecceSet:FindNearestGroupFromPointVec2(SmokeUnit:GetPointVec2())
|
||||||
local RecceUnit = RecceGroup:GetUnit( 1 )
|
local RecceUnit = RecceGroup:GetUnit( 1 )
|
||||||
@@ -1216,13 +1383,14 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
RecceUnit:MessageToSetGroup( "Smoking " .. SmokeUnit:GetTypeName() .. ".", 5, self.AttackSet, self.DesignateName )
|
RecceUnit:MessageToSetGroup( "Smoking " .. SmokeUnit:GetTypeName() .. ".", 5, self.AttackSet, self.DesignateName )
|
||||||
|
|
||||||
|
if SmokeUnit:IsAlive() then
|
||||||
|
SmokeUnit:Smoke( Color, 50, 2 )
|
||||||
|
end
|
||||||
|
|
||||||
self.MarkScheduler:Schedule( self,
|
self.MarkScheduler:Schedule( self,
|
||||||
function()
|
function()
|
||||||
if SmokeUnit:IsAlive() then
|
self:DoneSmoking( Index )
|
||||||
SmokeUnit:Smoke( Color, 50, 2 )
|
end, {}, math.random( 180, 240 )
|
||||||
end
|
|
||||||
self:Done( Index )
|
|
||||||
end, {}, math.random( 5, 20 )
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1237,7 +1405,8 @@ do -- DESIGNATE
|
|||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
function DESIGNATE:onafterIlluminate( From, Event, To, Index )
|
function DESIGNATE:onafterIlluminate( From, Event, To, Index )
|
||||||
|
|
||||||
local TargetSetUnit = self.Detection:GetDetectedSet( Index )
|
local DetectedItem = self.Detection:GetDetectedItemByIndex( Index )
|
||||||
|
local TargetSetUnit = self.Detection:GetDetectedSet( DetectedItem )
|
||||||
local TargetUnit = TargetSetUnit:GetFirst()
|
local TargetUnit = TargetSetUnit:GetFirst()
|
||||||
|
|
||||||
if TargetUnit then
|
if TargetUnit then
|
||||||
@@ -1245,28 +1414,38 @@ do -- DESIGNATE
|
|||||||
local RecceUnit = RecceGroup:GetUnit( 1 )
|
local RecceUnit = RecceGroup:GetUnit( 1 )
|
||||||
if RecceUnit then
|
if RecceUnit then
|
||||||
RecceUnit:MessageToSetGroup( "Illuminating " .. TargetUnit:GetTypeName() .. ".", 5, self.AttackSet, self.DesignateName )
|
RecceUnit:MessageToSetGroup( "Illuminating " .. TargetUnit:GetTypeName() .. ".", 5, self.AttackSet, self.DesignateName )
|
||||||
|
if TargetUnit:IsAlive() then
|
||||||
|
-- Fire 2 illumination bombs at random locations.
|
||||||
|
TargetUnit:GetPointVec3():AddY(math.random( 350, 500) ):AddX(math.random(-50,50) ):AddZ(math.random(-50,50) ):IlluminationBomb()
|
||||||
|
TargetUnit:GetPointVec3():AddY(math.random( 350, 500) ):AddX(math.random(-50,50) ):AddZ(math.random(-50,50) ):IlluminationBomb()
|
||||||
|
end
|
||||||
self.MarkScheduler:Schedule( self,
|
self.MarkScheduler:Schedule( self,
|
||||||
function()
|
function()
|
||||||
if TargetUnit:IsAlive() then
|
self:DoneIlluminating( Index )
|
||||||
TargetUnit:GetPointVec3():AddY(300):IlluminationBomb()
|
end, {}, math.random( 60, 90 )
|
||||||
end
|
|
||||||
self:Done( Index )
|
|
||||||
end, {}, math.random( 5, 20 )
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Done
|
--- DoneSmoking
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
function DESIGNATE:onafterDone( From, Event, To, Index )
|
function DESIGNATE:onafterDoneSmoking( From, Event, To, Index )
|
||||||
|
|
||||||
self.Designating[Index] = nil
|
self.Designating[Index] = string.gsub( self.Designating[Index], "S", "" )
|
||||||
|
self:SetDesignateMenu()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- DoneIlluminating
|
||||||
|
-- @param #DESIGNATE self
|
||||||
|
-- @return #DESIGNATE
|
||||||
|
function DESIGNATE:onafterDoneIlluminating( From, Event, To, Index )
|
||||||
|
|
||||||
|
self.Designating[Index] = string.gsub( self.Designating[Index], "I", "" )
|
||||||
self:SetDesignateMenu()
|
self:SetDesignateMenu()
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Help from Ciribob
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,62 +1,61 @@
|
|||||||
--- **Functional** -- Taking the lead of AI escorting your flight.
|
--- **Functional** -- Taking the lead of AI escorting your flight.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
|
--
|
||||||
|
-- Allows you to interact with escorting AI on your flight and take the lead.
|
||||||
--
|
--
|
||||||
-- @{#ESCORT} class
|
|
||||||
-- ================
|
|
||||||
-- The @{#ESCORT} class allows you to interact with escorting AI on your flight and take the lead.
|
|
||||||
-- Each escorting group can be commanded with a whole set of radio commands (radio menu in your flight, and then F10).
|
-- Each escorting group can be commanded with a whole set of radio commands (radio menu in your flight, and then F10).
|
||||||
--
|
--
|
||||||
-- The radio commands will vary according the category of the group. The richest set of commands are with Helicopters and AirPlanes.
|
-- The radio commands will vary according the category of the group. The richest set of commands are with Helicopters and AirPlanes.
|
||||||
-- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts.
|
-- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts.
|
||||||
--
|
--
|
||||||
-- RADIO MENUs that can be created:
|
-- # RADIO MENUs that can be created:
|
||||||
-- ================================
|
--
|
||||||
-- Find a summary below of the current available commands:
|
-- Find a summary below of the current available commands:
|
||||||
--
|
--
|
||||||
-- Navigation ...:
|
-- ## Navigation ...:
|
||||||
-- ---------------
|
--
|
||||||
-- Escort group navigation functions:
|
-- Escort group navigation functions:
|
||||||
--
|
--
|
||||||
-- * **"Join-Up and Follow at x meters":** The escort group fill follow you at about x meters, and they will follow you.
|
-- * **"Join-Up and Follow at x meters":** The escort group fill follow you at about x meters, and they will follow you.
|
||||||
-- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color.
|
-- * **"Flare":** Provides menu commands to let the escort group shoot a flare in the air in a color.
|
||||||
-- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops.
|
-- * **"Smoke":** Provides menu commands to let the escort group smoke the air in a color. Note that smoking is only available for ground and naval troops.
|
||||||
--
|
--
|
||||||
-- Hold position ...:
|
-- ## Hold position ...:
|
||||||
-- ------------------
|
--
|
||||||
-- Escort group navigation functions:
|
-- Escort group navigation functions:
|
||||||
--
|
--
|
||||||
-- * **"At current location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped.
|
-- * **"At current location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped.
|
||||||
-- * **"At client location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped.
|
-- * **"At client location":** Stops the escort group and they will hover 30 meters above the ground at the position they stopped.
|
||||||
--
|
--
|
||||||
-- Report targets ...:
|
-- ## Report targets ...:
|
||||||
-- -------------------
|
--
|
||||||
-- Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below).
|
-- Report targets will make the escort group to report any target that it identifies within a 8km range. Any detected target can be attacked using the 4. Attack nearby targets function. (see below).
|
||||||
--
|
--
|
||||||
-- * **"Report now":** Will report the current detected targets.
|
-- * **"Report now":** Will report the current detected targets.
|
||||||
-- * **"Report targets on":** Will make the escort group to report detected targets and will fill the "Attack nearby targets" menu list.
|
-- * **"Report targets on":** Will make the escort group to report detected targets and will fill the "Attack nearby targets" menu list.
|
||||||
-- * **"Report targets off":** Will stop detecting targets.
|
-- * **"Report targets off":** Will stop detecting targets.
|
||||||
--
|
--
|
||||||
-- Scan targets ...:
|
-- ## Scan targets ...:
|
||||||
-- -----------------
|
--
|
||||||
-- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task.
|
-- Menu items to pop-up the escort group for target scanning. After scanning, the escort group will resume with the mission or defined task.
|
||||||
--
|
--
|
||||||
-- * **"Scan targets 30 seconds":** Scan 30 seconds for targets.
|
-- * **"Scan targets 30 seconds":** Scan 30 seconds for targets.
|
||||||
-- * **"Scan targets 60 seconds":** Scan 60 seconds for targets.
|
-- * **"Scan targets 60 seconds":** Scan 60 seconds for targets.
|
||||||
--
|
--
|
||||||
-- Attack targets ...:
|
-- ## Attack targets ...:
|
||||||
-- -------------------
|
--
|
||||||
-- This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed.
|
-- This menu item will list all detected targets within a 15km range. Depending on the level of detection (known/unknown) and visuality, the targets type will also be listed.
|
||||||
--
|
--
|
||||||
-- Request assistance from ...:
|
-- ## Request assistance from ...:
|
||||||
-- ----------------------------
|
--
|
||||||
-- This menu item will list all detected targets within a 15km range, as with the menu item **Attack Targets**.
|
-- This menu item will list all detected targets within a 15km range, as with the menu item **Attack Targets**.
|
||||||
-- This menu item allows to request attack support from other escorts supporting the current client group.
|
-- This menu item allows to request attack support from other escorts supporting the current client group.
|
||||||
-- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles.
|
-- eg. the function allows a player to request support from the Ship escort to attack a target identified by the Plane escort with its Tomahawk missiles.
|
||||||
-- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area.
|
-- eg. the function allows a player to request support from other Planes escorting to bomb the unit with illumination missiles or bombs, so that the main plane escort can attack the area.
|
||||||
--
|
--
|
||||||
-- ROE ...:
|
-- ## ROE ...:
|
||||||
-- --------
|
--
|
||||||
-- Sets the Rules of Engagement (ROE) of the escort group when in flight.
|
-- Sets the Rules of Engagement (ROE) of the escort group when in flight.
|
||||||
--
|
--
|
||||||
-- * **"Hold Fire":** The escort group will hold fire.
|
-- * **"Hold Fire":** The escort group will hold fire.
|
||||||
@@ -64,8 +63,8 @@
|
|||||||
-- * **"Open Fire":** The escort group will open fire on designated targets.
|
-- * **"Open Fire":** The escort group will open fire on designated targets.
|
||||||
-- * **"Weapon Free":** The escort group will engage with any target.
|
-- * **"Weapon Free":** The escort group will engage with any target.
|
||||||
--
|
--
|
||||||
-- Evasion ...:
|
-- ## Evasion ...:
|
||||||
-- ------------
|
--
|
||||||
-- Will define the evasion techniques that the escort group will perform during flight or combat.
|
-- Will define the evasion techniques that the escort group will perform during flight or combat.
|
||||||
--
|
--
|
||||||
-- * **"Fight until death":** The escort group will have no reaction to threats.
|
-- * **"Fight until death":** The escort group will have no reaction to threats.
|
||||||
@@ -73,19 +72,19 @@
|
|||||||
-- * **"Evade enemy fire":** The rescort group will evade enemy fire before firing.
|
-- * **"Evade enemy fire":** The rescort group will evade enemy fire before firing.
|
||||||
-- * **"Go below radar and evade fire":** The escort group will perform evasive vertical manoeuvres.
|
-- * **"Go below radar and evade fire":** The escort group will perform evasive vertical manoeuvres.
|
||||||
--
|
--
|
||||||
-- Resume Mission ...:
|
-- ## Resume Mission ...:
|
||||||
-- -------------------
|
--
|
||||||
-- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint.
|
-- 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.
|
-- 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.
|
||||||
--
|
--
|
||||||
-- ESCORT construction methods.
|
-- # ESCORT construction methods.
|
||||||
-- ============================
|
--
|
||||||
-- Create a new SPAWN object with the @{#ESCORT.New} method:
|
-- Create a new SPAWN object with the @{#ESCORT.New} method:
|
||||||
--
|
--
|
||||||
-- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Group#GROUP} for a @{Client#CLIENT}, with an optional briefing text.
|
-- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Wrapper.Group#GROUP} for a @{Wrapper.Client#CLIENT}, with an optional briefing text.
|
||||||
--
|
--
|
||||||
-- ESCORT initialization methods.
|
-- # ESCORT initialization methods.
|
||||||
-- ==============================
|
--
|
||||||
-- The following menus are created within the RADIO MENU (F10) of an active unit hosted by a player:
|
-- The following menus are created within the RADIO MENU (F10) of an active unit hosted by a player:
|
||||||
--
|
--
|
||||||
-- * @{#ESCORT.MenuFollowAt}: Creates a menu to make the escort follow the client.
|
-- * @{#ESCORT.MenuFollowAt}: Creates a menu to make the escort follow the client.
|
||||||
@@ -114,8 +113,8 @@
|
|||||||
--
|
--
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- @module Escort
|
-- @module Functional.Escort
|
||||||
-- @author FlightControl
|
-- @image Escorting.JPG
|
||||||
|
|
||||||
--- ESCORT class
|
--- ESCORT class
|
||||||
-- @type ESCORT
|
-- @type ESCORT
|
||||||
@@ -127,10 +126,9 @@
|
|||||||
-- @field Core.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 #number FollowDistance The current follow distance.
|
||||||
-- @field #boolean ReportTargets If true, nearby targets are reported.
|
-- @field #boolean ReportTargets If true, nearby targets are reported.
|
||||||
-- @Field Dcs.DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup.
|
-- @Field DCS#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup.
|
||||||
-- @field Dcs.DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup.
|
-- @field DCS#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup.
|
||||||
-- @field Core.Menu#MENU_CLIENT EscortMenuResumeMission
|
-- @field FunctionalMENU_GROUPDETECTION_BASE Detection
|
||||||
-- @field Functional.Detection#DETECTION_BASE Detection
|
|
||||||
ESCORT = {
|
ESCORT = {
|
||||||
ClassName = "ESCORT",
|
ClassName = "ESCORT",
|
||||||
EscortName = nil, -- The Escort Name
|
EscortName = nil, -- The Escort Name
|
||||||
@@ -207,7 +205,7 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
|
|||||||
self.EscortClient._EscortGroups[EscortGroup:GetName()].Detection = self.EscortGroup.Detection
|
self.EscortClient._EscortGroups[EscortGroup:GetName()].Detection = self.EscortGroup.Detection
|
||||||
end
|
end
|
||||||
|
|
||||||
self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName )
|
self.EscortMenu = MENU_GROUP:New( self.EscortClient:GetGroup(), self.EscortName )
|
||||||
|
|
||||||
self.EscortGroup:WayPointInitialize(1)
|
self.EscortGroup:WayPointInitialize(1)
|
||||||
|
|
||||||
@@ -296,21 +294,21 @@ end
|
|||||||
--- Defines a menu slot to let the escort Join and Follow you at a certain distance.
|
--- Defines a menu slot to let the escort Join and Follow you at a certain distance.
|
||||||
-- This menu will appear under **Navigation**.
|
-- This menu will appear under **Navigation**.
|
||||||
-- @param #ESCORT self
|
-- @param #ESCORT self
|
||||||
-- @param Dcs.DCSTypes#Distance Distance The distance in meters that the escort needs to follow the client.
|
-- @param DCS#Distance Distance The distance in meters that the escort needs to follow the client.
|
||||||
-- @return #ESCORT
|
-- @return #ESCORT
|
||||||
function ESCORT:MenuFollowAt( Distance )
|
function ESCORT:MenuFollowAt( Distance )
|
||||||
self:F(Distance)
|
self:F(Distance)
|
||||||
|
|
||||||
if self.EscortGroup:IsAir() then
|
if self.EscortGroup:IsAir() then
|
||||||
if not self.EscortMenuReportNavigation then
|
if not self.EscortMenuReportNavigation then
|
||||||
self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu )
|
self.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortClient:GetGroup(), "Navigation", self.EscortMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.EscortMenuJoinUpAndFollow then
|
if not self.EscortMenuJoinUpAndFollow then
|
||||||
self.EscortMenuJoinUpAndFollow = {}
|
self.EscortMenuJoinUpAndFollow = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1] = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at " .. Distance, self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, self, Distance )
|
self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1] = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Join-Up and Follow at " .. Distance, self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, self, Distance )
|
||||||
|
|
||||||
self.EscortMode = ESCORT.MODE.FOLLOW
|
self.EscortMode = ESCORT.MODE.FOLLOW
|
||||||
end
|
end
|
||||||
@@ -321,8 +319,8 @@ end
|
|||||||
--- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds.
|
--- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds.
|
||||||
-- This menu will appear under **Hold position**.
|
-- This menu will appear under **Hold position**.
|
||||||
-- @param #ESCORT self
|
-- @param #ESCORT self
|
||||||
-- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
|
-- @param DCS#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
|
||||||
-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
|
-- @param DCS#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
|
||||||
-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.
|
-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.
|
||||||
-- @return #ESCORT
|
-- @return #ESCORT
|
||||||
-- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function.
|
-- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function.
|
||||||
@@ -332,7 +330,7 @@ function ESCORT:MenuHoldAtEscortPosition( Height, Seconds, MenuTextFormat )
|
|||||||
if self.EscortGroup:IsAir() then
|
if self.EscortGroup:IsAir() then
|
||||||
|
|
||||||
if not self.EscortMenuHold then
|
if not self.EscortMenuHold then
|
||||||
self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu )
|
self.EscortMenuHold = MENU_GROUP:New( self.EscortClient:GetGroup(), "Hold position", self.EscortMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
if not Height then
|
if not Height then
|
||||||
@@ -362,9 +360,9 @@ function ESCORT:MenuHoldAtEscortPosition( Height, Seconds, MenuTextFormat )
|
|||||||
self.EscortMenuHoldPosition = {}
|
self.EscortMenuHoldPosition = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1] = MENU_CLIENT_COMMAND
|
self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1] = MENU_GROUP_COMMAND
|
||||||
:New(
|
:New(
|
||||||
self.EscortClient,
|
self.EscortClient:GetGroup(),
|
||||||
MenuText,
|
MenuText,
|
||||||
self.EscortMenuHold,
|
self.EscortMenuHold,
|
||||||
ESCORT._HoldPosition,
|
ESCORT._HoldPosition,
|
||||||
@@ -382,8 +380,8 @@ end
|
|||||||
--- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds.
|
--- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds.
|
||||||
-- This menu will appear under **Navigation**.
|
-- This menu will appear under **Navigation**.
|
||||||
-- @param #ESCORT self
|
-- @param #ESCORT self
|
||||||
-- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
|
-- @param DCS#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
|
||||||
-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
|
-- @param DCS#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
|
||||||
-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.
|
-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.
|
||||||
-- @return #ESCORT
|
-- @return #ESCORT
|
||||||
-- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function.
|
-- TODO: Implement Seconds parameter. Challenge is to first develop the "continue from last activity" function.
|
||||||
@@ -393,7 +391,7 @@ function ESCORT:MenuHoldAtLeaderPosition( Height, Seconds, MenuTextFormat )
|
|||||||
if self.EscortGroup:IsAir() then
|
if self.EscortGroup:IsAir() then
|
||||||
|
|
||||||
if not self.EscortMenuHold then
|
if not self.EscortMenuHold then
|
||||||
self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu )
|
self.EscortMenuHold = MENU_GROUP:New( self.EscortClient:GetGroup(), "Hold position", self.EscortMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
if not Height then
|
if not Height then
|
||||||
@@ -423,9 +421,9 @@ function ESCORT:MenuHoldAtLeaderPosition( Height, Seconds, MenuTextFormat )
|
|||||||
self.EscortMenuHoldAtLeaderPosition = {}
|
self.EscortMenuHoldAtLeaderPosition = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_CLIENT_COMMAND
|
self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_GROUP_COMMAND
|
||||||
:New(
|
:New(
|
||||||
self.EscortClient,
|
self.EscortClient:GetGroup(),
|
||||||
MenuText,
|
MenuText,
|
||||||
self.EscortMenuHold,
|
self.EscortMenuHold,
|
||||||
ESCORT._HoldPosition,
|
ESCORT._HoldPosition,
|
||||||
@@ -443,8 +441,8 @@ end
|
|||||||
--- Defines a menu slot to let the escort scan for targets at a certain height for a certain time in seconds.
|
--- Defines a menu slot to let the escort scan for targets at a certain height for a certain time in seconds.
|
||||||
-- This menu will appear under **Scan targets**.
|
-- This menu will appear under **Scan targets**.
|
||||||
-- @param #ESCORT self
|
-- @param #ESCORT self
|
||||||
-- @param Dcs.DCSTypes#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
|
-- @param DCS#Distance Height Optional parameter that sets the height in meters to let the escort orbit at the current location. The default value is 30 meters.
|
||||||
-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
|
-- @param DCS#Time Seconds Optional parameter that lets the escort orbit at the current position for a specified time. (not implemented yet). The default value is 0 seconds, meaning, that the escort will orbit forever until a sequent command is given.
|
||||||
-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.
|
-- @param #string MenuTextFormat Optional parameter that shows the menu option text. The text string is formatted, and should contain one or two %d tokens in the string. The first for the Height, the second for the Time (if given). If no text is given, the default text will be displayed.
|
||||||
-- @return #ESCORT
|
-- @return #ESCORT
|
||||||
function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat )
|
function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat )
|
||||||
@@ -452,7 +450,7 @@ function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat )
|
|||||||
|
|
||||||
if self.EscortGroup:IsAir() then
|
if self.EscortGroup:IsAir() then
|
||||||
if not self.EscortMenuScan then
|
if not self.EscortMenuScan then
|
||||||
self.EscortMenuScan = MENU_CLIENT:New( self.EscortClient, "Scan for targets", self.EscortMenu )
|
self.EscortMenuScan = MENU_GROUP:New( self.EscortClient:GetGroup(), "Scan for targets", self.EscortMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
if not Height then
|
if not Height then
|
||||||
@@ -482,9 +480,9 @@ function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat )
|
|||||||
self.EscortMenuScanForTargets = {}
|
self.EscortMenuScanForTargets = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_CLIENT_COMMAND
|
self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_GROUP_COMMAND
|
||||||
:New(
|
:New(
|
||||||
self.EscortClient,
|
self.EscortClient:GetGroup(),
|
||||||
MenuText,
|
MenuText,
|
||||||
self.EscortMenuScan,
|
self.EscortMenuScan,
|
||||||
ESCORT._ScanTargets,
|
ESCORT._ScanTargets,
|
||||||
@@ -508,7 +506,7 @@ function ESCORT:MenuFlare( MenuTextFormat )
|
|||||||
self:F()
|
self:F()
|
||||||
|
|
||||||
if not self.EscortMenuReportNavigation then
|
if not self.EscortMenuReportNavigation then
|
||||||
self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu )
|
self.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortClient:GetGroup(), "Navigation", self.EscortMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
local MenuText = ""
|
local MenuText = ""
|
||||||
@@ -519,11 +517,11 @@ function ESCORT:MenuFlare( MenuTextFormat )
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not self.EscortMenuFlare then
|
if not self.EscortMenuFlare then
|
||||||
self.EscortMenuFlare = MENU_CLIENT:New( self.EscortClient, MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, self )
|
self.EscortMenuFlare = MENU_GROUP:New( self.EscortClient:GetGroup(), MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, self )
|
||||||
self.EscortMenuFlareGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Green, "Released a green flare!" )
|
self.EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release green flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Green, "Released a green flare!" )
|
||||||
self.EscortMenuFlareRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Red, "Released a red flare!" )
|
self.EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release red flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Red, "Released a red flare!" )
|
||||||
self.EscortMenuFlareWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.White, "Released a white flare!" )
|
self.EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release white flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.White, "Released a white flare!" )
|
||||||
self.EscortMenuFlareYellow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Yellow, "Released a yellow flare!" )
|
self.EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Yellow, "Released a yellow flare!" )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -541,7 +539,7 @@ function ESCORT:MenuSmoke( MenuTextFormat )
|
|||||||
|
|
||||||
if not self.EscortGroup:IsAir() then
|
if not self.EscortGroup:IsAir() then
|
||||||
if not self.EscortMenuReportNavigation then
|
if not self.EscortMenuReportNavigation then
|
||||||
self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu )
|
self.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortClient:GetGroup(), "Navigation", self.EscortMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
local MenuText = ""
|
local MenuText = ""
|
||||||
@@ -552,12 +550,12 @@ function ESCORT:MenuSmoke( MenuTextFormat )
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not self.EscortMenuSmoke then
|
if not self.EscortMenuSmoke then
|
||||||
self.EscortMenuSmoke = MENU_CLIENT:New( self.EscortClient, "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, self )
|
self.EscortMenuSmoke = MENU_GROUP:New( self.EscortClient:GetGroup(), "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, self )
|
||||||
self.EscortMenuSmokeGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Green, "Releasing green smoke!" )
|
self.EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Green, "Releasing green smoke!" )
|
||||||
self.EscortMenuSmokeRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Red, "Releasing red smoke!" )
|
self.EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Red, "Releasing red smoke!" )
|
||||||
self.EscortMenuSmokeWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.White, "Releasing white smoke!" )
|
self.EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.White, "Releasing white smoke!" )
|
||||||
self.EscortMenuSmokeOrange = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" )
|
self.EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" )
|
||||||
self.EscortMenuSmokeBlue = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" )
|
self.EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -568,13 +566,13 @@ end
|
|||||||
-- This menu will appear under **Report targets**.
|
-- This menu will appear under **Report targets**.
|
||||||
-- Note that if a report targets menu is not specified, no targets will be detected by the escort, and the attack and assisted attack menus will not be displayed.
|
-- Note that if a report targets menu is not specified, no targets will be detected by the escort, and the attack and assisted attack menus will not be displayed.
|
||||||
-- @param #ESCORT self
|
-- @param #ESCORT self
|
||||||
-- @param Dcs.DCSTypes#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds.
|
-- @param DCS#Time Seconds Optional parameter that lets the escort report their current detected targets after specified time interval in seconds. The default time is 30 seconds.
|
||||||
-- @return #ESCORT
|
-- @return #ESCORT
|
||||||
function ESCORT:MenuReportTargets( Seconds )
|
function ESCORT:MenuReportTargets( Seconds )
|
||||||
self:F( { Seconds } )
|
self:F( { Seconds } )
|
||||||
|
|
||||||
if not self.EscortMenuReportNearbyTargets then
|
if not self.EscortMenuReportNearbyTargets then
|
||||||
self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu )
|
self.EscortMenuReportNearbyTargets = MENU_GROUP:New( self.EscortClient:GetGroup(), "Report targets", self.EscortMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
if not Seconds then
|
if not Seconds then
|
||||||
@@ -582,12 +580,12 @@ function ESCORT:MenuReportTargets( Seconds )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Report Targets
|
-- Report Targets
|
||||||
self.EscortMenuReportNearbyTargetsNow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, self )
|
self.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, self )
|
||||||
self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, true )
|
self.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, true )
|
||||||
self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, false )
|
self.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, false )
|
||||||
|
|
||||||
-- Attack Targets
|
-- Attack Targets
|
||||||
self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack targets", self.EscortMenu )
|
self.EscortMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortClient:GetGroup(), "Attack targets", self.EscortMenu )
|
||||||
|
|
||||||
|
|
||||||
self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds )
|
self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds )
|
||||||
@@ -605,7 +603,7 @@ function ESCORT:MenuAssistedAttack()
|
|||||||
|
|
||||||
-- Request assistance from other escorts.
|
-- Request assistance from other escorts.
|
||||||
-- This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane...
|
-- This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane...
|
||||||
self.EscortMenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, "Request assistance from", self.EscortMenu )
|
self.EscortMenuTargetAssistance = MENU_GROUP:New( self.EscortClient:GetGroup(), "Request assistance from", self.EscortMenu )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -619,18 +617,18 @@ function ESCORT:MenuROE( MenuTextFormat )
|
|||||||
|
|
||||||
if not self.EscortMenuROE then
|
if not self.EscortMenuROE then
|
||||||
-- Rules of Engagement
|
-- Rules of Engagement
|
||||||
self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu )
|
self.EscortMenuROE = MENU_GROUP:New( self.EscortClient:GetGroup(), "ROE", self.EscortMenu )
|
||||||
if self.EscortGroup:OptionROEHoldFirePossible() then
|
if self.EscortGroup:OptionROEHoldFirePossible() then
|
||||||
self.EscortMenuROEHoldFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEHoldFire(), "Holding weapons!" )
|
self.EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Hold Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEHoldFire(), "Holding weapons!" )
|
||||||
end
|
end
|
||||||
if self.EscortGroup:OptionROEReturnFirePossible() then
|
if self.EscortGroup:OptionROEReturnFirePossible() then
|
||||||
self.EscortMenuROEReturnFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEReturnFire(), "Returning fire!" )
|
self.EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Return Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEReturnFire(), "Returning fire!" )
|
||||||
end
|
end
|
||||||
if self.EscortGroup:OptionROEOpenFirePossible() then
|
if self.EscortGroup:OptionROEOpenFirePossible() then
|
||||||
self.EscortMenuROEOpenFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEOpenFire(), "Opening fire on designated targets!!" )
|
self.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Open Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEOpenFire(), "Opening fire on designated targets!!" )
|
||||||
end
|
end
|
||||||
if self.EscortGroup:OptionROEWeaponFreePossible() then
|
if self.EscortGroup:OptionROEWeaponFreePossible() then
|
||||||
self.EscortMenuROEWeaponFree = MENU_CLIENT_COMMAND:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEWeaponFree(), "Opening fire on targets of opportunity!" )
|
self.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Weapon Free", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEWeaponFree(), "Opening fire on targets of opportunity!" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -648,18 +646,18 @@ function ESCORT:MenuEvasion( MenuTextFormat )
|
|||||||
if self.EscortGroup:IsAir() then
|
if self.EscortGroup:IsAir() then
|
||||||
if not self.EscortMenuEvasion then
|
if not self.EscortMenuEvasion then
|
||||||
-- Reaction to Threats
|
-- Reaction to Threats
|
||||||
self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu )
|
self.EscortMenuEvasion = MENU_GROUP:New( self.EscortClient:GetGroup(), "Evasion", self.EscortMenu )
|
||||||
if self.EscortGroup:OptionROTNoReactionPossible() then
|
if self.EscortGroup:OptionROTNoReactionPossible() then
|
||||||
self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTNoReaction(), "Fighting until death!" )
|
self.EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTNoReaction(), "Fighting until death!" )
|
||||||
end
|
end
|
||||||
if self.EscortGroup:OptionROTPassiveDefensePossible() then
|
if self.EscortGroup:OptionROTPassiveDefensePossible() then
|
||||||
self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTPassiveDefense(), "Defending using jammers, chaff and flares!" )
|
self.EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTPassiveDefense(), "Defending using jammers, chaff and flares!" )
|
||||||
end
|
end
|
||||||
if self.EscortGroup:OptionROTEvadeFirePossible() then
|
if self.EscortGroup:OptionROTEvadeFirePossible() then
|
||||||
self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTEvadeFire(), "Evading on enemy fire!" )
|
self.EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTEvadeFire(), "Evading on enemy fire!" )
|
||||||
end
|
end
|
||||||
if self.EscortGroup:OptionROTVerticalPossible() then
|
if self.EscortGroup:OptionROTVerticalPossible() then
|
||||||
self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTVertical(), "Evading on enemy fire with vertical manoeuvres!" )
|
self.EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTVertical(), "Evading on enemy fire with vertical manoeuvres!" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -676,7 +674,7 @@ function ESCORT:MenuResumeMission()
|
|||||||
|
|
||||||
if not self.EscortMenuResumeMission then
|
if not self.EscortMenuResumeMission then
|
||||||
-- Mission Resume Menu Root
|
-- Mission Resume Menu Root
|
||||||
self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume mission from", self.EscortMenu )
|
self.EscortMenuResumeMission = MENU_GROUP:New( self.EscortClient:GetGroup(), "Resume mission from", self.EscortMenu )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -738,7 +736,7 @@ end
|
|||||||
-- @param Functional.Escort#ESCORT self
|
-- @param Functional.Escort#ESCORT self
|
||||||
-- @param Wrapper.Group#GROUP EscortGroup
|
-- @param Wrapper.Group#GROUP EscortGroup
|
||||||
-- @param Wrapper.Client#CLIENT EscortClient
|
-- @param Wrapper.Client#CLIENT EscortClient
|
||||||
-- @param Dcs.DCSTypes#Distance Distance
|
-- @param DCS#Distance Distance
|
||||||
function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance )
|
function ESCORT:JoinUpAndFollow( EscortGroup, EscortClient, Distance )
|
||||||
self:F( { EscortGroup, EscortClient, Distance } )
|
self:F( { EscortGroup, EscortClient, Distance } )
|
||||||
|
|
||||||
@@ -847,11 +845,11 @@ function _Resume( EscortGroup )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- @param #ESCORT self
|
--- @param #ESCORT self
|
||||||
-- @param #number DetectedItemID
|
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
||||||
function ESCORT:_AttackTarget( DetectedItemID )
|
function ESCORT:_AttackTarget( DetectedItem )
|
||||||
|
|
||||||
local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP
|
local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP
|
||||||
self:E( EscortGroup )
|
self:F( EscortGroup )
|
||||||
|
|
||||||
local EscortClient = self.EscortClient
|
local EscortClient = self.EscortClient
|
||||||
|
|
||||||
@@ -862,7 +860,7 @@ function ESCORT:_AttackTarget( DetectedItemID )
|
|||||||
EscortGroup:OptionROTPassiveDefense()
|
EscortGroup:OptionROTPassiveDefense()
|
||||||
EscortGroup:SetState( EscortGroup, "Escort", self )
|
EscortGroup:SetState( EscortGroup, "Escort", self )
|
||||||
|
|
||||||
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
|
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
|
||||||
|
|
||||||
local Tasks = {}
|
local Tasks = {}
|
||||||
|
|
||||||
@@ -885,7 +883,7 @@ function ESCORT:_AttackTarget( DetectedItemID )
|
|||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
|
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
|
||||||
|
|
||||||
local Tasks = {}
|
local Tasks = {}
|
||||||
|
|
||||||
@@ -911,8 +909,9 @@ function ESCORT:_AttackTarget( DetectedItemID )
|
|||||||
end
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @param #number DetectedItemID
|
--- @param #ESCORT self
|
||||||
function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItemID )
|
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
||||||
|
function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
|
||||||
|
|
||||||
local EscortGroup = self.EscortGroup
|
local EscortGroup = self.EscortGroup
|
||||||
local EscortClient = self.EscortClient
|
local EscortClient = self.EscortClient
|
||||||
@@ -923,7 +922,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItemID )
|
|||||||
EscortGroupAttack:OptionROEOpenFire()
|
EscortGroupAttack:OptionROEOpenFire()
|
||||||
EscortGroupAttack:OptionROTVertical()
|
EscortGroupAttack:OptionROTVertical()
|
||||||
|
|
||||||
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
|
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
|
||||||
|
|
||||||
local Tasks = {}
|
local Tasks = {}
|
||||||
|
|
||||||
@@ -945,7 +944,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItemID )
|
|||||||
)
|
)
|
||||||
|
|
||||||
else
|
else
|
||||||
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
|
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
|
||||||
|
|
||||||
local Tasks = {}
|
local Tasks = {}
|
||||||
|
|
||||||
@@ -1152,7 +1151,7 @@ function ESCORT:_ReportTargetsScheduler()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local DetectedItems = self.Detection:GetDetectedItems()
|
local DetectedItems = self.Detection:GetDetectedItems()
|
||||||
self:E( DetectedItems )
|
self:F( DetectedItems )
|
||||||
|
|
||||||
local DetectedTargets = false
|
local DetectedTargets = false
|
||||||
|
|
||||||
@@ -1163,11 +1162,11 @@ function ESCORT:_ReportTargetsScheduler()
|
|||||||
local ClientEscortTargets = EscortGroupData.Detection
|
local ClientEscortTargets = EscortGroupData.Detection
|
||||||
--local EscortUnit = EscortGroupData:GetUnit( 1 )
|
--local EscortUnit = EscortGroupData:GetUnit( 1 )
|
||||||
|
|
||||||
for DetectedItemID, DetectedItem in pairs( DetectedItems ) do
|
for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do
|
||||||
self:E( { DetectedItemID, DetectedItem } )
|
self:F( { DetectedItemIndex, DetectedItem } )
|
||||||
-- Remove the sub menus of the Attack menu of the Escort for the EscortGroup.
|
-- Remove the sub menus of the Attack menu of the Escort for the EscortGroup.
|
||||||
|
|
||||||
local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItemID, EscortGroupData.EscortGroup, _DATABASE:GetPlayerSettings( self.EscortClient:GetPlayerName() ) )
|
local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItem, EscortGroupData.EscortGroup, _DATABASE:GetPlayerSettings( self.EscortClient:GetPlayerName() ) )
|
||||||
|
|
||||||
if ClientEscortGroupName == EscortGroupName then
|
if ClientEscortGroupName == EscortGroupName then
|
||||||
|
|
||||||
@@ -1176,12 +1175,12 @@ function ESCORT:_ReportTargetsScheduler()
|
|||||||
|
|
||||||
self:T( DetectedMsg )
|
self:T( DetectedMsg )
|
||||||
|
|
||||||
MENU_CLIENT_COMMAND:New( self.EscortClient,
|
MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(),
|
||||||
DetectedMsg,
|
DetectedMsg,
|
||||||
self.EscortMenuAttackNearbyTargets,
|
self.EscortMenuAttackNearbyTargets,
|
||||||
ESCORT._AttackTarget,
|
ESCORT._AttackTarget,
|
||||||
self,
|
self,
|
||||||
DetectedItemID
|
DetectedItem
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
if self.EscortMenuTargetAssistance then
|
if self.EscortMenuTargetAssistance then
|
||||||
@@ -1189,14 +1188,14 @@ function ESCORT:_ReportTargetsScheduler()
|
|||||||
local DetectedMsg = DetectedItemReportSummary:Text("\n")
|
local DetectedMsg = DetectedItemReportSummary:Text("\n")
|
||||||
self:T( DetectedMsg )
|
self:T( DetectedMsg )
|
||||||
|
|
||||||
local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
|
local MenuTargetAssistance = MENU_GROUP:New( self.EscortClient:GetGroup(), EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
|
||||||
MENU_CLIENT_COMMAND:New( self.EscortClient,
|
MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(),
|
||||||
DetectedMsg,
|
DetectedMsg,
|
||||||
MenuTargetAssistance,
|
MenuTargetAssistance,
|
||||||
ESCORT._AssistTarget,
|
ESCORT._AssistTarget,
|
||||||
self,
|
self,
|
||||||
EscortGroupData.EscortGroup,
|
EscortGroupData.EscortGroup,
|
||||||
DetectedItemID
|
DetectedItem
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1205,7 +1204,7 @@ function ESCORT:_ReportTargetsScheduler()
|
|||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:E( DetectedMsgs )
|
self:F( DetectedMsgs )
|
||||||
if DetectedTargets then
|
if DetectedTargets then
|
||||||
self.EscortGroup:MessageToClient( "Reporting detected targets:\n" .. table.concat( DetectedMsgs, "\n" ), 20, self.EscortClient )
|
self.EscortGroup:MessageToClient( "Reporting detected targets:\n" .. table.concat( DetectedMsgs, "\n" ), 20, self.EscortClient )
|
||||||
else
|
else
|
||||||
@@ -1327,7 +1326,7 @@ function ESCORT:_ReportTargetsScheduler()
|
|||||||
--
|
--
|
||||||
-- if ClientEscortGroupName == EscortGroupName then
|
-- if ClientEscortGroupName == EscortGroupName then
|
||||||
--
|
--
|
||||||
-- MENU_CLIENT_COMMAND:New( self.EscortClient,
|
-- MENU_GROUP_COMMAND:New( self.EscortClient,
|
||||||
-- EscortTargetMessage,
|
-- EscortTargetMessage,
|
||||||
-- self.EscortMenuAttackNearbyTargets,
|
-- self.EscortMenuAttackNearbyTargets,
|
||||||
-- ESCORT._AttackTarget,
|
-- ESCORT._AttackTarget,
|
||||||
@@ -1338,8 +1337,8 @@ function ESCORT:_ReportTargetsScheduler()
|
|||||||
-- EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage
|
-- EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage
|
||||||
-- else
|
-- else
|
||||||
-- if self.EscortMenuTargetAssistance then
|
-- if self.EscortMenuTargetAssistance then
|
||||||
-- local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
|
-- local MenuTargetAssistance = MENU_GROUP:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
|
||||||
-- MENU_CLIENT_COMMAND:New( self.EscortClient,
|
-- MENU_GROUP_COMMAND:New( self.EscortClient,
|
||||||
-- EscortTargetMessage,
|
-- EscortTargetMessage,
|
||||||
-- MenuTargetAssistance,
|
-- MenuTargetAssistance,
|
||||||
-- ESCORT._AssistTarget,
|
-- ESCORT._AssistTarget,
|
||||||
@@ -1378,7 +1377,7 @@ function ESCORT:_ReportTargetsScheduler()
|
|||||||
-- local Distance = ( ( WayPoint.x - EscortVec3.x )^2 +
|
-- local Distance = ( ( WayPoint.x - EscortVec3.x )^2 +
|
||||||
-- ( WayPoint.y - EscortVec3.z )^2
|
-- ( WayPoint.y - EscortVec3.z )^2
|
||||||
-- ) ^ 0.5 / 1000
|
-- ) ^ 0.5 / 1000
|
||||||
-- MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
|
-- MENU_GROUP_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
|
||||||
-- end
|
-- end
|
||||||
-- end
|
-- end
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 1) @{MissileTrainer#MISSILETRAINER} class, extends @{Base#BASE}
|
|
||||||
-- ===============================================================
|
|
||||||
-- The @{#MISSILETRAINER} class uses the DCS world messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft,
|
-- The @{#MISSILETRAINER} class uses the DCS world messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft,
|
||||||
-- the class will destroy the missile within a certain range, to avoid damage to your aircraft.
|
-- the class will destroy the missile within a certain range, to avoid damage to your aircraft.
|
||||||
-- It suports the following functionality:
|
-- It suports the following functionality:
|
||||||
@@ -71,14 +69,14 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- CREDITS
|
-- CREDITS
|
||||||
-- =======
|
-- ===
|
||||||
-- **Stuka (Danny)** Who you can search on the Eagle Dynamics Forums.
|
-- **Stuka (Danny)** Who you can search on the Eagle Dynamics Forums.
|
||||||
-- Working together with Danny has resulted in the MISSILETRAINER class.
|
-- Working together with Danny has resulted in the MISSILETRAINER class.
|
||||||
-- Danny has shared his ideas and together we made a design.
|
-- Danny has shared his ideas and together we made a design.
|
||||||
-- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback!
|
-- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback!
|
||||||
--
|
--
|
||||||
-- @module MissileTrainer
|
-- @module Functional.MissileTrainer
|
||||||
-- @author FlightControl
|
-- @image Missile_Trainer.JPG
|
||||||
|
|
||||||
|
|
||||||
--- The MISSILETRAINER class
|
--- The MISSILETRAINER class
|
||||||
@@ -99,39 +97,39 @@ function MISSILETRAINER._Alive( Client, self )
|
|||||||
if self.MenusOnOff == true then
|
if self.MenusOnOff == true then
|
||||||
Client:Message( "Use the 'Radio Menu' -> 'Other (F10)' -> 'Missile Trainer' menu options to change the Missile Trainer settings (for all players).", 15, "Trainer" )
|
Client:Message( "Use the 'Radio Menu' -> 'Other (F10)' -> 'Missile Trainer' menu options to change the Missile Trainer settings (for all players).", 15, "Trainer" )
|
||||||
|
|
||||||
Client.MainMenu = MENU_CLIENT:New( Client, "Missile Trainer", nil ) -- Menu#MENU_CLIENT
|
Client.MainMenu = MENU_GROUP:New( Client:GetGroup(), "Missile Trainer", nil ) -- Menu#MENU_GROUP
|
||||||
|
|
||||||
Client.MenuMessages = MENU_CLIENT:New( Client, "Messages", Client.MainMenu )
|
Client.MenuMessages = MENU_GROUP:New( Client:GetGroup(), "Messages", Client.MainMenu )
|
||||||
Client.MenuOn = MENU_CLIENT_COMMAND:New( Client, "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } )
|
Client.MenuOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } )
|
||||||
Client.MenuOff = MENU_CLIENT_COMMAND:New( Client, "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } )
|
Client.MenuOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } )
|
||||||
|
|
||||||
Client.MenuTracking = MENU_CLIENT:New( Client, "Tracking", Client.MainMenu )
|
Client.MenuTracking = MENU_GROUP:New( Client:GetGroup(), "Tracking", Client.MainMenu )
|
||||||
Client.MenuTrackingToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } )
|
Client.MenuTrackingToAll = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } )
|
||||||
Client.MenuTrackingToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } )
|
Client.MenuTrackingToTarget = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } )
|
||||||
Client.MenuTrackOn = MENU_CLIENT_COMMAND:New( Client, "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = true } )
|
Client.MenuTrackOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = true } )
|
||||||
Client.MenuTrackOff = MENU_CLIENT_COMMAND:New( Client, "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = false } )
|
Client.MenuTrackOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = false } )
|
||||||
Client.MenuTrackIncrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Increase", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = -1 } )
|
Client.MenuTrackIncrease = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Frequency Increase", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = -1 } )
|
||||||
Client.MenuTrackDecrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Decrease", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = 1 } )
|
Client.MenuTrackDecrease = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Frequency Decrease", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = 1 } )
|
||||||
|
|
||||||
Client.MenuAlerts = MENU_CLIENT:New( Client, "Alerts", Client.MainMenu )
|
Client.MenuAlerts = MENU_GROUP:New( Client:GetGroup(), "Alerts", Client.MainMenu )
|
||||||
Client.MenuAlertsToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } )
|
Client.MenuAlertsToAll = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } )
|
||||||
Client.MenuAlertsToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } )
|
Client.MenuAlertsToTarget = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } )
|
||||||
Client.MenuHitsOn = MENU_CLIENT_COMMAND:New( Client, "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = true } )
|
Client.MenuHitsOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = true } )
|
||||||
Client.MenuHitsOff = MENU_CLIENT_COMMAND:New( Client, "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = false } )
|
Client.MenuHitsOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = false } )
|
||||||
Client.MenuLaunchesOn = MENU_CLIENT_COMMAND:New( Client, "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = true } )
|
Client.MenuLaunchesOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = true } )
|
||||||
Client.MenuLaunchesOff = MENU_CLIENT_COMMAND:New( Client, "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = false } )
|
Client.MenuLaunchesOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = false } )
|
||||||
|
|
||||||
Client.MenuDetails = MENU_CLIENT:New( Client, "Details", Client.MainMenu )
|
Client.MenuDetails = MENU_GROUP:New( Client:GetGroup(), "Details", Client.MainMenu )
|
||||||
Client.MenuDetailsDistanceOn = MENU_CLIENT_COMMAND:New( Client, "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = true } )
|
Client.MenuDetailsDistanceOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = true } )
|
||||||
Client.MenuDetailsDistanceOff = MENU_CLIENT_COMMAND:New( Client, "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = false } )
|
Client.MenuDetailsDistanceOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = false } )
|
||||||
Client.MenuDetailsBearingOn = MENU_CLIENT_COMMAND:New( Client, "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = true } )
|
Client.MenuDetailsBearingOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = true } )
|
||||||
Client.MenuDetailsBearingOff = MENU_CLIENT_COMMAND:New( Client, "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = false } )
|
Client.MenuDetailsBearingOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = false } )
|
||||||
|
|
||||||
Client.MenuDistance = MENU_CLIENT:New( Client, "Set distance to plane", Client.MainMenu )
|
Client.MenuDistance = MENU_GROUP:New( Client:GetGroup(), "Set distance to plane", Client.MainMenu )
|
||||||
Client.MenuDistance50 = MENU_CLIENT_COMMAND:New( Client, "50 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 50 / 1000 } )
|
Client.MenuDistance50 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "50 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 50 / 1000 } )
|
||||||
Client.MenuDistance100 = MENU_CLIENT_COMMAND:New( Client, "100 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 100 / 1000 } )
|
Client.MenuDistance100 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "100 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 100 / 1000 } )
|
||||||
Client.MenuDistance150 = MENU_CLIENT_COMMAND:New( Client, "150 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 150 / 1000 } )
|
Client.MenuDistance150 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "150 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 150 / 1000 } )
|
||||||
Client.MenuDistance200 = MENU_CLIENT_COMMAND:New( Client, "200 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 200 / 1000 } )
|
Client.MenuDistance200 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "200 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 200 / 1000 } )
|
||||||
else
|
else
|
||||||
if Client.MainMenu then
|
if Client.MainMenu then
|
||||||
Client.MainMenu:Remove()
|
Client.MainMenu:Remove()
|
||||||
@@ -177,13 +175,13 @@ function MISSILETRAINER:New( Distance, Briefing )
|
|||||||
|
|
||||||
|
|
||||||
-- for ClientID, Client in pairs( self.DBClients.Database ) do
|
-- for ClientID, Client in pairs( self.DBClients.Database ) do
|
||||||
-- self:E( "ForEach:" .. Client.UnitName )
|
-- self:F( "ForEach:" .. Client.UnitName )
|
||||||
-- Client:Alive( self._Alive, self )
|
-- Client:Alive( self._Alive, self )
|
||||||
-- end
|
-- end
|
||||||
--
|
--
|
||||||
self.DBClients:ForEachClient(
|
self.DBClients:ForEachClient(
|
||||||
function( Client )
|
function( Client )
|
||||||
self:E( "ForEach:" .. Client.UnitName )
|
self:F( "ForEach:" .. Client.UnitName )
|
||||||
Client:Alive( self._Alive, self )
|
Client:Alive( self._Alive, self )
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
--- **Functional** -- Limit the MOVEMENT of simulaneous moving ground vehicles.
|
--- **Functional** -- Limit the MOVEMENT of simulaneous moving ground vehicles.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- Limit the simultaneous movement of Groups within a running Mission.
|
-- Limit the simultaneous movement of Groups within a running Mission.
|
||||||
-- This module is defined to improve the performance in missions, and to bring additional realism for GROUND vehicles.
|
-- This module is defined to improve the performance in missions, and to bring additional realism for GROUND vehicles.
|
||||||
-- Performance: If in a DCSRTE there are a lot of moving GROUND units, then in a multi player mission, this WILL create lag if
|
-- Performance: If in a DCSRTE there are a lot of moving GROUND units, then in a multi player mission, this WILL create lag if
|
||||||
-- the main DCS execution core of your CPU is fully utilized. So, this class will limit the amount of simultaneous moving GROUND units
|
-- the main DCS execution core of your CPU is fully utilized. So, this class will limit the amount of simultaneous moving GROUND units
|
||||||
-- on defined intervals (currently every minute).
|
-- on defined intervals (currently every minute).
|
||||||
-- @module Movement
|
-- @module Functional.Movement
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
--- the MOVEMENT class
|
--- the MOVEMENT class
|
||||||
-- @type MOVEMENT
|
-- @type MOVEMENT
|
||||||
|
|||||||
1000
Moose Development/Moose/Functional/PseudoATC.lua
Normal file
1000
Moose Development/Moose/Functional/PseudoATC.lua
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2480
Moose Development/Moose/Functional/Range.lua
Normal file
2480
Moose Development/Moose/Functional/Range.lua
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,12 @@
|
|||||||
--- **Functional** -- **Administer the SCORING of player achievements,
|
--- **Functional** -- (R2.0) - Administer the scoring of player achievements, and create a CSV file logging the scoring events for use at team or squadron websites.
|
||||||
-- and create a CSV file logging the scoring events for use at team or squadron websites.**
|
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- The @{#SCORING} class administers the scoring of player achievements,
|
-- Administers the scoring of player achievements,
|
||||||
-- and creates a CSV file logging the scoring events and results for use at team or squadron websites.
|
-- 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,
|
-- SCORING automatically calculates the threat level of the objects hit and destroyed by players,
|
||||||
-- which can be @{Unit}, @{Static) and @{Scenery} objects.
|
-- which can be @{Wrapper.Unit}, @{Static) and @{Scenery} objects.
|
||||||
--
|
--
|
||||||
-- Positive score points are granted when enemy or neutral targets are destroyed.
|
-- 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.
|
-- Negative score points or penalties are given when a friendly target is hit or destroyed.
|
||||||
@@ -55,7 +52,7 @@
|
|||||||
-- Use the radio menu F10 to consult the scores while running the mission.
|
-- Use the radio menu F10 to consult the scores while running the mission.
|
||||||
-- Scores can be reported for your user, or an overall score can be reported of all players currently active in the mission.
|
-- Scores can be reported for your user, or an overall score can be reported of all players currently active in the mission.
|
||||||
--
|
--
|
||||||
-- # 1) @{Scoring#SCORING} class, extends @{Base#BASE}
|
-- # 1) @{Functional.Scoring#SCORING} class, extends @{Core.Base#BASE}
|
||||||
--
|
--
|
||||||
-- ## 1.1) Set the destroy score or penalty scale
|
-- ## 1.1) Set the destroy score or penalty scale
|
||||||
--
|
--
|
||||||
@@ -73,9 +70,9 @@
|
|||||||
-- ## 1.2) Define special targets that will give extra scores.
|
-- ## 1.2) Define special targets that will give extra scores.
|
||||||
--
|
--
|
||||||
-- Special targets can be set that will give extra scores to the players when these are destroyed.
|
-- 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 @{Unit}s.
|
-- 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 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 @{Group}s.
|
-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Wrapper.Group}s.
|
||||||
--
|
--
|
||||||
-- local Scoring = SCORING:New( "Scoring File" )
|
-- local Scoring = SCORING:New( "Scoring File" )
|
||||||
-- Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 )
|
-- Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 )
|
||||||
@@ -92,7 +89,7 @@
|
|||||||
-- Define zones of destruction. Any object destroyed within the zone of the given category will give extra points.
|
-- 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.AddZoneScore}() to add a @{Zone} for additional scoring.
|
||||||
-- Use the method @{#SCORING.RemoveZoneScore}() to remove 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 @{Zone#ZONE_UNIT},
|
-- 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.
|
-- 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},
|
-- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Zone},
|
||||||
-- just large enough around that building.
|
-- just large enough around that building.
|
||||||
@@ -102,7 +99,9 @@
|
|||||||
-- A mission has goals and achievements. The scoring system provides an API to set additional scores when a goal or achievement event happens.
|
-- A mission has goals and achievements. The scoring system provides an API to set additional scores when a goal or achievement event happens.
|
||||||
-- Use the method @{#SCORING.AddGoalScore}() to add a score for a Player at any time in your mission.
|
-- Use the method @{#SCORING.AddGoalScore}() to add a score for a Player at any time in your mission.
|
||||||
--
|
--
|
||||||
-- ## 1.5) Configure fratricide level.
|
-- ## 1.5) (Decommissioned) Configure fratricide level.
|
||||||
|
--
|
||||||
|
-- **This functionality is decomissioned until the DCS bug concerning Unit:destroy() not being functional in multi player for player units has been fixed by ED**.
|
||||||
--
|
--
|
||||||
-- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
|
-- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
|
||||||
-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked.
|
-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked.
|
||||||
@@ -176,7 +175,7 @@
|
|||||||
-- * @{#SCORING.SetMessagesToCoalition}(): Configure to send messages to only those players within the same coalition as the player.
|
-- * @{#SCORING.SetMessagesToCoalition}(): Configure to send messages to only those players within the same coalition as the player.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- # **API CHANGE HISTORY**
|
-- # **API CHANGE HISTORY**
|
||||||
--
|
--
|
||||||
@@ -203,7 +202,8 @@
|
|||||||
--
|
--
|
||||||
-- * **FlightControl**: Concept, Design & Programming.
|
-- * **FlightControl**: Concept, Design & Programming.
|
||||||
--
|
--
|
||||||
-- @module Scoring
|
-- @module Functional.Scoring
|
||||||
|
-- @image Scoring.JPG
|
||||||
|
|
||||||
|
|
||||||
--- The Scoring class
|
--- The Scoring class
|
||||||
@@ -258,7 +258,7 @@ function SCORING:New( GameName )
|
|||||||
|
|
||||||
-- Configure Messages
|
-- Configure Messages
|
||||||
self:SetMessagesToAll()
|
self:SetMessagesToAll()
|
||||||
self:SetMessagesHit( true )
|
self:SetMessagesHit( false )
|
||||||
self:SetMessagesDestroy( true )
|
self:SetMessagesDestroy( true )
|
||||||
self:SetMessagesScore( true )
|
self:SetMessagesScore( true )
|
||||||
self:SetMessagesZone( true )
|
self:SetMessagesZone( true )
|
||||||
@@ -279,8 +279,22 @@ function SCORING:New( GameName )
|
|||||||
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
|
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
|
||||||
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
||||||
self:HandleEvent( EVENTS.Hit, self._EventOnHit )
|
self:HandleEvent( EVENTS.Hit, self._EventOnHit )
|
||||||
self:HandleEvent( EVENTS.PlayerEnterUnit )
|
self:HandleEvent( EVENTS.Birth )
|
||||||
|
--self:HandleEvent( EVENTS.PlayerEnterUnit )
|
||||||
self:HandleEvent( EVENTS.PlayerLeaveUnit )
|
self:HandleEvent( EVENTS.PlayerLeaveUnit )
|
||||||
|
|
||||||
|
-- During mission startup, especially for single player,
|
||||||
|
-- iterate the database for the player that has joined, and add him to the scoring, and set the menu.
|
||||||
|
-- But this can only be started one second after the mission has started, so i need to schedule this ...
|
||||||
|
self.ScoringPlayerScan = BASE:ScheduleOnce( 1,
|
||||||
|
function()
|
||||||
|
for PlayerName, PlayerUnit in pairs( _DATABASE:GetPlayerUnits() ) do
|
||||||
|
self:_AddPlayerFromUnit( PlayerUnit )
|
||||||
|
self:SetScoringMenu( PlayerUnit:GetGroup() )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
-- Create the CSV file.
|
-- Create the CSV file.
|
||||||
self:OpenCSV( GameName )
|
self:OpenCSV( GameName )
|
||||||
@@ -322,11 +336,11 @@ function SCORING:SetScaleDestroyPenalty( Scale )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a @{Unit} for additional scoring when the @{Unit} is destroyed.
|
--- Add a @{Wrapper.Unit} for additional scoring when the @{Wrapper.Unit} is destroyed.
|
||||||
-- Note that if there was already a @{Unit} declared within the scoring with the same name,
|
-- Note that if there was already a @{Wrapper.Unit} declared within the scoring with the same name,
|
||||||
-- then the old @{Unit} will be replaced with the new @{Unit}.
|
-- then the old @{Wrapper.Unit} will be replaced with the new @{Wrapper.Unit}.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Unit#UNIT ScoreUnit The @{Unit} for which the Score needs to be given.
|
-- @param Wrapper.Unit#UNIT ScoreUnit The @{Wrapper.Unit} for which the Score needs to be given.
|
||||||
-- @param #number Score The Score value.
|
-- @param #number Score The Score value.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
function SCORING:AddUnitScore( ScoreUnit, Score )
|
function SCORING:AddUnitScore( ScoreUnit, Score )
|
||||||
@@ -338,9 +352,9 @@ function SCORING:AddUnitScore( ScoreUnit, Score )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes a @{Unit} for additional scoring when the @{Unit} is destroyed.
|
--- Removes a @{Wrapper.Unit} for additional scoring when the @{Wrapper.Unit} is destroyed.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Unit#UNIT ScoreUnit The @{Unit} for which the Score needs to be given.
|
-- @param Wrapper.Unit#UNIT ScoreUnit The @{Wrapper.Unit} for which the Score needs to be given.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
function SCORING:RemoveUnitScore( ScoreUnit )
|
function SCORING:RemoveUnitScore( ScoreUnit )
|
||||||
|
|
||||||
@@ -381,9 +395,9 @@ function SCORING:RemoveStaticScore( ScoreStatic )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Specify a special additional score for a @{Group}.
|
--- Specify a special additional score for a @{Wrapper.Group}.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Group#GROUP ScoreGroup The @{Group} for which each @{Unit} a Score is given.
|
-- @param Wrapper.Group#GROUP ScoreGroup The @{Wrapper.Group} for which each @{Wrapper.Unit} a Score is given.
|
||||||
-- @param #number Score The Score value.
|
-- @param #number Score The Score value.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
function SCORING:AddScoreGroup( ScoreGroup, Score )
|
function SCORING:AddScoreGroup( ScoreGroup, Score )
|
||||||
@@ -567,6 +581,19 @@ function SCORING:SetCoalitionChangePenalty( CoalitionChangePenalty )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Sets the scoring menu.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:SetScoringMenu( ScoringGroup )
|
||||||
|
local Menu = MENU_GROUP:New( ScoringGroup, 'Scoring and Statistics' )
|
||||||
|
local ReportGroupSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report players in group', Menu, SCORING.ReportScoreGroupSummary, self, ScoringGroup )
|
||||||
|
local ReportGroupDetailed = MENU_GROUP_COMMAND:New( ScoringGroup, 'Detailed report players in group', Menu, SCORING.ReportScoreGroupDetailed, self, ScoringGroup )
|
||||||
|
local ReportToAllSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report all players', Menu, SCORING.ReportScoreAllSummary, self, ScoringGroup )
|
||||||
|
self:SetState( ScoringGroup, "ScoringMenu", Menu )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Add a new player entering a Unit.
|
--- Add a new player entering a Unit.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Unit#UNIT UnitData
|
-- @param Wrapper.Unit#UNIT UnitData
|
||||||
@@ -616,6 +643,7 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
|||||||
UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
|
UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.Players[PlayerName].UnitName = UnitName
|
self.Players[PlayerName].UnitName = UnitName
|
||||||
self.Players[PlayerName].UnitCoalition = UnitCoalition
|
self.Players[PlayerName].UnitCoalition = UnitCoalition
|
||||||
self.Players[PlayerName].UnitCategory = UnitCategory
|
self.Players[PlayerName].UnitCategory = UnitCategory
|
||||||
@@ -624,6 +652,8 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
|||||||
self.Players[PlayerName].ThreatLevel = UnitThreatLevel
|
self.Players[PlayerName].ThreatLevel = UnitThreatLevel
|
||||||
self.Players[PlayerName].ThreatType = UnitThreatType
|
self.Players[PlayerName].ThreatType = UnitThreatType
|
||||||
|
|
||||||
|
-- TODO: DCS bug concerning Units with skill level client don't get destroyed in multi player. This logic is deactivated until this bug gets fixed.
|
||||||
|
--[[
|
||||||
if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 then
|
if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 then
|
||||||
if self.Players[PlayerName].PenaltyWarning < 1 then
|
if self.Players[PlayerName].PenaltyWarning < 1 then
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty,
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty,
|
||||||
@@ -639,18 +669,49 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
|||||||
):ToAll()
|
):ToAll()
|
||||||
UnitData:GetGroup():Destroy()
|
UnitData:GetGroup():Destroy()
|
||||||
end
|
end
|
||||||
|
--]]
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add a goal score for a player.
|
||||||
|
-- The method takes the Player name for which the Goal score needs to be set.
|
||||||
|
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
|
||||||
|
-- A free text can be given that is shown to the players.
|
||||||
|
-- The Score can be both positive and negative.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param #string PlayerName The name of the Player.
|
||||||
|
-- @param #string GoalTag The string or identifier that is used in the CSV file to identify the goal (sort or group later in Excel).
|
||||||
|
-- @param #string Text A free text that is shown to the players.
|
||||||
|
-- @param #number Score The score can be both positive or negative ( Penalty ).
|
||||||
|
function SCORING:AddGoalScorePlayer( PlayerName, GoalTag, Text, Score )
|
||||||
|
|
||||||
|
self:F( { PlayerName, PlayerName, GoalTag, Text, Score } )
|
||||||
|
|
||||||
|
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
|
||||||
|
if PlayerName then
|
||||||
|
local PlayerData = self.Players[PlayerName]
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, nil )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Add a goal score for a player.
|
--- Add a goal score for a player.
|
||||||
-- The method takes the PlayerUnit for which the Goal score needs to be set.
|
-- The method takes the PlayerUnit for which the Goal score needs to be set.
|
||||||
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
|
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
|
||||||
-- A free text can be given that is shown to the players.
|
-- A free text can be given that is shown to the players.
|
||||||
-- The Score can be both positive and negative.
|
-- The Score can be both positive and negative.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the Player. Other Properties for the scoring are taken from this PlayerUnit, like coalition, type etc.
|
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Wrapper.Unit} of the Player. Other Properties for the scoring are taken from this PlayerUnit, like coalition, type etc.
|
||||||
-- @param #string GoalTag The string or identifier that is used in the CSV file to identify the goal (sort or group later in Excel).
|
-- @param #string GoalTag The string or identifier that is used in the CSV file to identify the goal (sort or group later in Excel).
|
||||||
-- @param #string Text A free text that is shown to the players.
|
-- @param #string Text A free text that is shown to the players.
|
||||||
-- @param #number Score The score can be both positive or negative ( Penalty ).
|
-- @param #number Score The score can be both positive or negative ( Penalty ).
|
||||||
@@ -658,7 +719,7 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score )
|
|||||||
|
|
||||||
local PlayerName = PlayerUnit:GetPlayerName()
|
local PlayerName = PlayerUnit:GetPlayerName()
|
||||||
|
|
||||||
self:E( { PlayerUnit.UnitName, PlayerName, GoalTag, Text, Score } )
|
self:F( { PlayerUnit.UnitName, PlayerName, GoalTag, Text, Score } )
|
||||||
|
|
||||||
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
|
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
|
||||||
if PlayerName then
|
if PlayerName then
|
||||||
@@ -686,7 +747,7 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
|
|||||||
local PlayerName = PlayerUnit:GetPlayerName()
|
local PlayerName = PlayerUnit:GetPlayerName()
|
||||||
local MissionName = Mission:GetName()
|
local MissionName = Mission:GetName()
|
||||||
|
|
||||||
self:E( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } )
|
self:F( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } )
|
||||||
|
|
||||||
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
|
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
|
||||||
if PlayerName then
|
if PlayerName then
|
||||||
@@ -704,12 +765,45 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
|
|||||||
PlayerData.Score = self.Players[PlayerName].Score + Score
|
PlayerData.Score = self.Players[PlayerName].Score + Score
|
||||||
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
|
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
|
||||||
|
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. MissionName .. " : " .. Text .. " Score: " .. Score, MESSAGE.Type.Information ):ToAll()
|
MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score, MESSAGE.Type.Information ):ToAll()
|
||||||
|
|
||||||
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
|
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Registers Scores the players completing a Mission Task.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param Tasking.Mission#MISSION Mission
|
||||||
|
-- @param #string PlayerName
|
||||||
|
-- @param #string Text
|
||||||
|
-- @param #number Score
|
||||||
|
function SCORING:_AddMissionGoalScore( Mission, PlayerName, Text, Score )
|
||||||
|
|
||||||
|
local MissionName = Mission:GetName()
|
||||||
|
|
||||||
|
self:F( { Mission:GetName(), PlayerName, Text, Score } )
|
||||||
|
|
||||||
|
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
|
||||||
|
if PlayerName then
|
||||||
|
local PlayerData = self.Players[PlayerName]
|
||||||
|
|
||||||
|
if not PlayerData.Mission[MissionName] then
|
||||||
|
PlayerData.Mission[MissionName] = {}
|
||||||
|
PlayerData.Mission[MissionName].ScoreTask = 0
|
||||||
|
PlayerData.Mission[MissionName].ScoreMission = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
self:T( PlayerName )
|
||||||
|
self:T( PlayerData.Mission[MissionName] )
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Registers Mission Scores for possible multiple players that contributed in the Mission.
|
--- Registers Mission Scores for possible multiple players that contributed in the Mission.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
@@ -721,18 +815,18 @@ function SCORING:_AddMissionScore( Mission, Text, Score )
|
|||||||
|
|
||||||
local MissionName = Mission:GetName()
|
local MissionName = Mission:GetName()
|
||||||
|
|
||||||
self:E( { Mission, Text, Score } )
|
self:F( { Mission, Text, Score } )
|
||||||
self:E( self.Players )
|
self:F( self.Players )
|
||||||
|
|
||||||
for PlayerName, PlayerData in pairs( self.Players ) do
|
for PlayerName, PlayerData in pairs( self.Players ) do
|
||||||
|
|
||||||
self:E( PlayerData )
|
self:F( PlayerData )
|
||||||
if PlayerData.Mission[MissionName] then
|
if PlayerData.Mission[MissionName] then
|
||||||
|
|
||||||
PlayerData.Score = PlayerData.Score + Score
|
PlayerData.Score = PlayerData.Score + Score
|
||||||
PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score
|
PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score
|
||||||
|
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in " .. Mission:GetText() .. ". " ..
|
||||||
Score .. " mission score!",
|
Score .. " mission score!",
|
||||||
MESSAGE.Type.Information ):ToAll()
|
MESSAGE.Type.Information ):ToAll()
|
||||||
|
|
||||||
@@ -742,17 +836,30 @@ function SCORING:_AddMissionScore( Mission, Text, Score )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Handles the OnPlayerEnterUnit event for the scoring.
|
--- Handles the OnPlayerEnterUnit event for the scoring.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event
|
||||||
function SCORING:OnEventPlayerEnterUnit( Event )
|
--function SCORING:OnEventPlayerEnterUnit( Event )
|
||||||
|
-- if Event.IniUnit then
|
||||||
|
-- self:_AddPlayerFromUnit( Event.IniUnit )
|
||||||
|
-- self:SetScoringMenu( Event.IniGroup )
|
||||||
|
-- end
|
||||||
|
--end
|
||||||
|
|
||||||
|
--- Handles the OnBirth event for the scoring.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param Core.Event#EVENTDATA Event
|
||||||
|
function SCORING:OnEventBirth( Event )
|
||||||
|
|
||||||
if Event.IniUnit then
|
if Event.IniUnit then
|
||||||
self:_AddPlayerFromUnit( Event.IniUnit )
|
if Event.IniObjectCategory == 1 then
|
||||||
local Menu = MENU_GROUP:New( Event.IniGroup, 'Scoring' )
|
local PlayerName = Event.IniUnit:GetPlayerName()
|
||||||
local ReportGroupSummary = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Summary report players in group', Menu, SCORING.ReportScoreGroupSummary, self, Event.IniGroup )
|
if PlayerName then
|
||||||
local ReportGroupDetailed = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Detailed report players in group', Menu, SCORING.ReportScoreGroupDetailed, self, Event.IniGroup )
|
self:_AddPlayerFromUnit( Event.IniUnit )
|
||||||
local ReportToAllSummary = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Summary report all players', Menu, SCORING.ReportScoreAllSummary, self, Event.IniGroup )
|
self:SetScoringMenu( Event.IniGroup )
|
||||||
self:SetState( Event.IniUnit, "ScoringMenu", Menu )
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -761,7 +868,7 @@ end
|
|||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event
|
||||||
function SCORING:OnEventPlayerLeaveUnit( Event )
|
function SCORING:OnEventPlayerLeaveUnit( Event )
|
||||||
if Event.IniUnit then
|
if Event.IniUnit then
|
||||||
local Menu = self:GetState( Event.IniUnit, "ScoringMenu" ) -- Core.Menu#MENU_GROUP
|
local Menu = self:GetState( Event.IniUnit:GetGroup(), "ScoringMenu" ) -- Core.Menu#MENU_GROUP
|
||||||
if Menu then
|
if Menu then
|
||||||
-- TODO: Check if this fixes #281.
|
-- TODO: Check if this fixes #281.
|
||||||
--Menu:Remove()
|
--Menu:Remove()
|
||||||
@@ -1123,7 +1230,7 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
local ThreatTypeTarget = TargetThreatType
|
local ThreatTypeTarget = TargetThreatType
|
||||||
local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1
|
local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1
|
||||||
local ThreatPenalty = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyPenalty / 10 )
|
local ThreatPenalty = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyPenalty / 10 )
|
||||||
self:E( { ThreatLevel = ThreatPenalty, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } )
|
self:F( { ThreatLevel = ThreatPenalty, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } )
|
||||||
|
|
||||||
Player.Penalty = Player.Penalty + ThreatPenalty
|
Player.Penalty = Player.Penalty + ThreatPenalty
|
||||||
TargetDestroy.Penalty = TargetDestroy.Penalty + ThreatPenalty
|
TargetDestroy.Penalty = TargetDestroy.Penalty + ThreatPenalty
|
||||||
@@ -1158,7 +1265,7 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1
|
local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1
|
||||||
local ThreatScore = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyScore / 10 )
|
local ThreatScore = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyScore / 10 )
|
||||||
|
|
||||||
self:E( { ThreatLevel = ThreatScore, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } )
|
self:F( { ThreatLevel = ThreatScore, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } )
|
||||||
|
|
||||||
Player.Score = Player.Score + ThreatScore
|
Player.Score = Player.Score + ThreatScore
|
||||||
TargetDestroy.Score = TargetDestroy.Score + ThreatScore
|
TargetDestroy.Score = TargetDestroy.Score + ThreatScore
|
||||||
@@ -1203,7 +1310,7 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
|
|
||||||
-- Check if there are Zones where the destruction happened.
|
-- Check if there are Zones where the destruction happened.
|
||||||
for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do
|
for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do
|
||||||
self:E( { ScoringZone = ScoreZoneData } )
|
self:F( { ScoringZone = ScoreZoneData } )
|
||||||
local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE
|
local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE
|
||||||
local Score = ScoreZoneData.Score
|
local Score = ScoreZoneData.Score
|
||||||
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
|
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
|
||||||
@@ -1225,7 +1332,7 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
else
|
else
|
||||||
-- Check if there are Zones where the destruction happened.
|
-- Check if there are Zones where the destruction happened.
|
||||||
for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do
|
for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do
|
||||||
self:E( { ScoringZone = ScoreZoneData } )
|
self:F( { ScoringZone = ScoreZoneData } )
|
||||||
local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE
|
local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE
|
||||||
local Score = ScoreZoneData.Score
|
local Score = ScoreZoneData.Score
|
||||||
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
|
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
|
||||||
@@ -1340,7 +1447,7 @@ function SCORING:ReportDetailedPlayerDestroys( PlayerName )
|
|||||||
local PenaltyDestroy = 0
|
local PenaltyDestroy = 0
|
||||||
|
|
||||||
for UnitName, UnitData in pairs( PlayerData.Destroy[CategoryID] ) do
|
for UnitName, UnitData in pairs( PlayerData.Destroy[CategoryID] ) do
|
||||||
self:E( { UnitData = UnitData } )
|
self:F( { UnitData = UnitData } )
|
||||||
if UnitData ~= {} then
|
if UnitData ~= {} then
|
||||||
Score = Score + UnitData.Score
|
Score = Score + UnitData.Score
|
||||||
ScoreDestroy = ScoreDestroy + UnitData.ScoreDestroy
|
ScoreDestroy = ScoreDestroy + UnitData.ScoreDestroy
|
||||||
@@ -1494,23 +1601,23 @@ function SCORING:ReportScoreGroupSummary( PlayerGroup )
|
|||||||
|
|
||||||
local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName )
|
local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName )
|
||||||
ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits
|
ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits
|
||||||
self:E( { ReportHits, ScoreHits, PenaltyHits } )
|
self:F( { ReportHits, ScoreHits, PenaltyHits } )
|
||||||
|
|
||||||
local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName )
|
local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName )
|
||||||
ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys
|
ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys
|
||||||
self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
|
self:F( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
|
||||||
|
|
||||||
local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName )
|
local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName )
|
||||||
ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges
|
ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges
|
||||||
self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
|
self:F( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
|
||||||
|
|
||||||
local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName )
|
local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName )
|
||||||
ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals
|
ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals
|
||||||
self:E( { ReportGoals, ScoreGoals, PenaltyGoals } )
|
self:F( { ReportGoals, ScoreGoals, PenaltyGoals } )
|
||||||
|
|
||||||
local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName )
|
local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName )
|
||||||
ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions
|
ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions
|
||||||
self:E( { ReportMissions, ScoreMissions, PenaltyMissions } )
|
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
|
||||||
|
|
||||||
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
||||||
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
|
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
|
||||||
@@ -1546,23 +1653,23 @@ function SCORING:ReportScoreGroupDetailed( PlayerGroup )
|
|||||||
|
|
||||||
local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName )
|
local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName )
|
||||||
ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits
|
ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits
|
||||||
self:E( { ReportHits, ScoreHits, PenaltyHits } )
|
self:F( { ReportHits, ScoreHits, PenaltyHits } )
|
||||||
|
|
||||||
local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName )
|
local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName )
|
||||||
ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys
|
ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys
|
||||||
self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
|
self:F( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
|
||||||
|
|
||||||
local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName )
|
local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName )
|
||||||
ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges
|
ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges
|
||||||
self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
|
self:F( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
|
||||||
|
|
||||||
local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName )
|
local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName )
|
||||||
ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals
|
ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals
|
||||||
self:E( { ReportGoals, ScoreGoals, PenaltyGoals } )
|
self:F( { ReportGoals, ScoreGoals, PenaltyGoals } )
|
||||||
|
|
||||||
local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName )
|
local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName )
|
||||||
ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions
|
ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions
|
||||||
self:E( { ReportMissions, ScoreMissions, PenaltyMissions } )
|
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
|
||||||
|
|
||||||
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
||||||
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
|
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
|
||||||
@@ -1592,31 +1699,33 @@ function SCORING:ReportScoreAllSummary( PlayerGroup )
|
|||||||
|
|
||||||
local PlayerMessage = ""
|
local PlayerMessage = ""
|
||||||
|
|
||||||
self:T( "Report Score All Players" )
|
self:T( { "Summary Score Report of All Players", Players = self.Players } )
|
||||||
|
|
||||||
for PlayerName, PlayerData in pairs( self.Players ) do
|
for PlayerName, PlayerData in pairs( self.Players ) do
|
||||||
|
|
||||||
|
self:T( { PlayerName = PlayerName, PlayerGroup = PlayerGroup } )
|
||||||
|
|
||||||
if PlayerName then
|
if PlayerName then
|
||||||
|
|
||||||
local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName )
|
local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName )
|
||||||
ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits
|
ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits
|
||||||
self:E( { ReportHits, ScoreHits, PenaltyHits } )
|
self:F( { ReportHits, ScoreHits, PenaltyHits } )
|
||||||
|
|
||||||
local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName )
|
local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName )
|
||||||
ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys
|
ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys
|
||||||
self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
|
self:F( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
|
||||||
|
|
||||||
local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName )
|
local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName )
|
||||||
ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges
|
ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges
|
||||||
self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
|
self:F( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
|
||||||
|
|
||||||
local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName )
|
local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName )
|
||||||
ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals
|
ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals
|
||||||
self:E( { ReportGoals, ScoreGoals, PenaltyGoals } )
|
self:F( { ReportGoals, ScoreGoals, PenaltyGoals } )
|
||||||
|
|
||||||
local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName )
|
local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName )
|
||||||
ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions
|
ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions
|
||||||
self:E( { ReportMissions, ScoreMissions, PenaltyMissions } )
|
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
|
||||||
|
|
||||||
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
||||||
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
|
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
|
||||||
@@ -1676,7 +1785,7 @@ function SCORING:OpenCSV( ScoringCSV )
|
|||||||
error( "A string containing the CSV file name must be given." )
|
error( "A string containing the CSV file name must be given." )
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:E( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." )
|
self:F( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." )
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
--- **Functional** -- Provides defensive behaviour to a set of SAM sites within a running Mission.
|
--- **Functional** -- Provides defensive behaviour to a set of SAM sites within a running Mission.
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Sead
|
-- @module Functional.Sead
|
||||||
|
-- @image SEAD.JPG
|
||||||
|
|
||||||
--- The SEAD class
|
--- The SEAD class
|
||||||
-- @type SEAD
|
-- @type SEAD
|
||||||
|
|||||||
1842
Moose Development/Moose/Functional/Suppression.lua
Normal file
1842
Moose Development/Moose/Functional/Suppression.lua
Normal file
File diff suppressed because it is too large
Load Diff
7215
Moose Development/Moose/Functional/Warehouse.lua
Normal file
7215
Moose Development/Moose/Functional/Warehouse.lua
Normal file
File diff suppressed because it is too large
Load Diff
758
Moose Development/Moose/Functional/ZoneCaptureCoalition.lua
Normal file
758
Moose Development/Moose/Functional/ZoneCaptureCoalition.lua
Normal file
@@ -0,0 +1,758 @@
|
|||||||
|
--- **Functional** -- (R2.3) Models the process to zone guarding and capturing.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAZ - Capture Zones)
|
||||||
|
--
|
||||||
|
-- - CAZ-000 - Capture Zone: Demonstrates the basic concept of capturing a zone.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### [YouTube Playlist](https://www.youtube.com/watch?v=0m6K6Yxa-os&list=PL7ZUrU4zZUl0qqJsfa8DPvZWDY-OyDumE)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
-- ### Contributions: **Millertime** - Concept
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Functional.ZoneCaptureCoalition
|
||||||
|
-- @image Capture_Zones.JPG
|
||||||
|
|
||||||
|
do -- ZONE_CAPTURE_COALITION
|
||||||
|
|
||||||
|
--- @type ZONE_CAPTURE_COALITION
|
||||||
|
-- @extends Functional.ZoneGoalCoalition#ZONE_GOAL_COALITION
|
||||||
|
|
||||||
|
|
||||||
|
--- Models the process to capture a Zone for a Coalition, which is guarded by another Coalition.
|
||||||
|
-- This is a powerful concept that allows to create very dynamic missions based on the different state transitions of various zones.
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- # 0. Player Experience
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- The above models the possible state transitions between the **Guarded**, **Attacked**, **Empty** and **Captured** states.
|
||||||
|
-- A zone has an __owning coalition__, that means that at a specific point in time, a zone can be owned by the red or blue coalition.
|
||||||
|
--
|
||||||
|
-- The Zone can be in the state **Guarded** by the __owning coalition__, which is the coalition that initially occupies the zone with units of its coalition.
|
||||||
|
-- Once units of an other coalition are entering the Zone, the state will change to **Attacked**. As long as these units remain in the zone, the state keeps set to Attacked.
|
||||||
|
-- When all units are destroyed in the Zone, the state will change to **Empty**, which expresses that the Zone is empty, and can be captured.
|
||||||
|
-- When units of the other coalition are in the Zone, and no other units of the owning coalition is in the Zone, the Zone is captured, and its state will change to **Captured**.
|
||||||
|
--
|
||||||
|
-- The zone needs to be monitored regularly for the presence of units to interprete the correct state transition required.
|
||||||
|
-- This monitoring process MUST be started using the @{#ZONE_CAPTURE_COALITION.Start}() method.
|
||||||
|
-- Otherwise no monitoring will be active and the zone will stay in the current state forever.
|
||||||
|
-- See further in chapter 3.3 for more information about this.
|
||||||
|
--
|
||||||
|
-- ## 1. ZONE\_CAPTURE\_COALITION constructor
|
||||||
|
--
|
||||||
|
-- * @{#ZONE_CAPTURE_COALITION.New}(): Creates a new ZONE\_CAPTURE\_COALITION object.
|
||||||
|
--
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- Ensure that during the life cycle of the ZONE\_CAPTURE\_COALITION object, the object keeps alive.
|
||||||
|
-- It is best to declare the object globally within your script.
|
||||||
|
--
|
||||||
|
-- ## 2. ZONE\_CAPTURE\_COALITION is a finite state machine (FSM).
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- ### 2.1 ZONE\_CAPTURE\_COALITION States
|
||||||
|
--
|
||||||
|
-- * **Captured**: The Zone has been captured by an other coalition.
|
||||||
|
-- * **Attacked**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
|
||||||
|
-- * **Guarded**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
|
||||||
|
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
|
||||||
|
--
|
||||||
|
-- ### 2.2 ZONE\_CAPTURE\_COALITION Events
|
||||||
|
--
|
||||||
|
-- * **Capture**: The Zone has been captured by an other coalition.
|
||||||
|
-- * **Attack**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
|
||||||
|
-- * **Guard**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
|
||||||
|
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
|
||||||
|
--
|
||||||
|
-- ## 3. "Script It"
|
||||||
|
--
|
||||||
|
-- ZONE\_CAPTURE\_COALITION allows to take action on the various state transitions and add your custom code and logic.
|
||||||
|
--
|
||||||
|
-- ### 3.1. Take action using state- and event handlers.
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- The most important to understand is how states and events can be tailored.
|
||||||
|
-- Carefully study the diagram and the explanations.
|
||||||
|
--
|
||||||
|
-- **State Handlers** capture the moment:
|
||||||
|
--
|
||||||
|
-- - On Leave from the old state. Return false to cancel the transition.
|
||||||
|
-- - On Enter to the new state.
|
||||||
|
--
|
||||||
|
-- **Event Handlers** capture the moment:
|
||||||
|
--
|
||||||
|
-- - On Before the event is triggered. Return false to cancel the transition.
|
||||||
|
-- - On After the event is triggered.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- Each handler can receive optionally 3 parameters:
|
||||||
|
--
|
||||||
|
-- - **From**: A string containing the From State.
|
||||||
|
-- - **Event**: A string containing the Event.
|
||||||
|
-- - **To**: A string containing the To State.
|
||||||
|
--
|
||||||
|
-- The mission designer can use these values to alter the logic.
|
||||||
|
-- For example:
|
||||||
|
--
|
||||||
|
-- --- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
|
||||||
|
-- function ZoneCaptureCoalition:OnEnterGuarded( From, Event, To )
|
||||||
|
-- if From ~= "Empty" then
|
||||||
|
-- -- Display a message
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- This code checks that when the __Guarded__ state has been reached, that if the **From** state was __Empty__, then display a message.
|
||||||
|
--
|
||||||
|
-- ### 3.2. Example Event Handler.
|
||||||
|
--
|
||||||
|
-- --- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
|
||||||
|
-- function ZoneCaptureCoalition:OnEnterGuarded( From, Event, To )
|
||||||
|
-- if From ~= To then
|
||||||
|
-- local Coalition = self:GetCoalition()
|
||||||
|
-- self:E( { Coalition = Coalition } )
|
||||||
|
-- if Coalition == coalition.side.BLUE then
|
||||||
|
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.Blue )
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "%s is under protection of the USA", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "%s is under protection of the USA", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- else
|
||||||
|
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.Red )
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "%s is under protection of Russia", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "%s is under protection of Russia", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- ### 3.3. Stop and Start the zone monitoring process.
|
||||||
|
--
|
||||||
|
-- At regular intervals, the state of the zone needs to be monitored.
|
||||||
|
-- The zone needs to be scanned for the presence of units within the zone boundaries.
|
||||||
|
-- Depending on the owning coalition of the zone and the presence of units (of the owning and/or other coalition(s)), the zone will transition to another state.
|
||||||
|
--
|
||||||
|
-- However, ... this scanning process is rather CPU intensive. Imagine you have 10 of these capture zone objects setup within your mission.
|
||||||
|
-- That would mean that your mission would check 10 capture zones simultaneously, each checking for the presence of units.
|
||||||
|
-- It would be highly **CPU inefficient**, as some of these zones are not required to be monitored (yet).
|
||||||
|
--
|
||||||
|
-- Therefore, the mission designer is given 2 methods that allow to take control of the CPU utilization efficiency:
|
||||||
|
--
|
||||||
|
-- - @{#ZONE_CAPTURE_COALITION.Start()}(): This starts the monitoring process.
|
||||||
|
-- - @{#ZONE_CAPTURE_COALITION.Stop()}(): This stops the monitoring process.
|
||||||
|
--
|
||||||
|
-- ### IMPORTANT
|
||||||
|
--
|
||||||
|
-- **Each capture zone object must have the monitoring process started specifically.
|
||||||
|
-- The monitoring process is NOT started by default!!!**
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ## 4. Full Example
|
||||||
|
--
|
||||||
|
-- The following annotated code shows a real example of how ZONE\_CAPTURE\_COALITION can be applied.
|
||||||
|
--
|
||||||
|
-- The concept is simple.
|
||||||
|
--
|
||||||
|
-- The USA (US), blue coalition, needs to capture the Russian (RU), red coalition, zone, which is near groom lake.
|
||||||
|
--
|
||||||
|
-- A capture zone has been setup that guards the presence of the troops.
|
||||||
|
-- Troops are guarded by red forces. Blue is required to destroy the red forces and capture the zones.
|
||||||
|
--
|
||||||
|
-- At first, we setup the Command Centers
|
||||||
|
--
|
||||||
|
-- do
|
||||||
|
--
|
||||||
|
-- RU_CC = COMMANDCENTER:New( GROUP:FindByName( "REDHQ" ), "Russia HQ" )
|
||||||
|
-- US_CC = COMMANDCENTER:New( GROUP:FindByName( "BLUEHQ" ), "USA HQ" )
|
||||||
|
--
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- Next, we define the mission, and add some scoring to it.
|
||||||
|
--
|
||||||
|
-- do -- Missions
|
||||||
|
--
|
||||||
|
-- US_Mission_EchoBay = MISSION:New( US_CC, "Echo Bay", "Primary",
|
||||||
|
-- "Welcome trainee. The airport Groom Lake in Echo Bay needs to be captured.\n" ..
|
||||||
|
-- "There are five random capture zones located at the airbase.\n" ..
|
||||||
|
-- "Move to one of the capture zones, destroy the fuel tanks in the capture zone, " ..
|
||||||
|
-- "and occupy each capture zone with a platoon.\n " ..
|
||||||
|
-- "Your orders are to hold position until all capture zones are taken.\n" ..
|
||||||
|
-- "Use the map (F10) for a clear indication of the location of each capture zone.\n" ..
|
||||||
|
-- "Note that heavy resistance can be expected at the airbase!\n" ..
|
||||||
|
-- "Mission 'Echo Bay' is complete when all five capture zones are taken, and held for at least 5 minutes!"
|
||||||
|
-- , coalition.side.RED )
|
||||||
|
--
|
||||||
|
-- US_Mission_EchoBay:Start()
|
||||||
|
--
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- Now the real work starts.
|
||||||
|
-- We define a **CaptureZone** object, which is a ZONE object.
|
||||||
|
-- Within the mission, a trigger zone is created with the name __CaptureZone__, with the defined radius within the mission editor.
|
||||||
|
--
|
||||||
|
-- CaptureZone = ZONE:New( "CaptureZone" )
|
||||||
|
--
|
||||||
|
-- Next, we define the **ZoneCaptureCoalition** object, as explained above.
|
||||||
|
--
|
||||||
|
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( CaptureZone, coalition.side.RED )
|
||||||
|
--
|
||||||
|
-- Of course, we want to let the **ZoneCaptureCoalition** object do something when the state transitions.
|
||||||
|
-- Do accomodate this, it is very simple, as explained above.
|
||||||
|
-- We use **Event Handlers** to tailor the logic.
|
||||||
|
--
|
||||||
|
-- Here we place an Event Handler at the Guarded event. So when the **Guarded** event is triggered, then this method is called!
|
||||||
|
-- With the variables **From**, **Event**, **To**. Each of these variables containing a string.
|
||||||
|
--
|
||||||
|
-- We check if the previous state wasn't Guarded also.
|
||||||
|
-- If not, we retrieve the owning Coalition of the **ZoneCaptureCoalition**, using `self:GetCoalition()`.
|
||||||
|
-- So **Coalition** will contain the current owning coalition of the zone.
|
||||||
|
--
|
||||||
|
-- Depending on the zone ownership, different messages are sent.
|
||||||
|
-- Note the methods `ZoneCaptureCoalition:GetZoneName()`.
|
||||||
|
--
|
||||||
|
-- --- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
|
||||||
|
-- function ZoneCaptureCoalition:OnEnterGuarded( From, Event, To )
|
||||||
|
-- if From ~= To then
|
||||||
|
-- local Coalition = self:GetCoalition()
|
||||||
|
-- self:E( { Coalition = Coalition } )
|
||||||
|
-- if Coalition == coalition.side.BLUE then
|
||||||
|
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.Blue )
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "%s is under protection of the USA", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "%s is under protection of the USA", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- else
|
||||||
|
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.Red )
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "%s is under protection of Russia", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "%s is under protection of Russia", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- As you can see, not a rocket science.
|
||||||
|
-- Next is the Event Handler when the **Empty** state transition is triggered.
|
||||||
|
-- Now we smoke the ZoneCaptureCoalition with a green color, using `self:Smoke( SMOKECOLOR.Green )`.
|
||||||
|
--
|
||||||
|
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
|
||||||
|
-- function ZoneCaptureCoalition:OnEnterEmpty()
|
||||||
|
-- self:Smoke( SMOKECOLOR.Green )
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "%s is unprotected, and can be captured!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "%s is unprotected, and can be captured!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- The next Event Handlers speak for itself.
|
||||||
|
-- When the zone is Attacked, we smoke the zone white and send some messages to each coalition.
|
||||||
|
--
|
||||||
|
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
|
||||||
|
-- function ZoneCaptureCoalition:OnEnterAttacked()
|
||||||
|
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.White )
|
||||||
|
-- local Coalition = self:GetCoalition()
|
||||||
|
-- self:E({Coalition = Coalition})
|
||||||
|
-- if Coalition == coalition.side.BLUE then
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "%s is under attack by Russia", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "We are attacking %s", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- else
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "%s is under attack by the USA", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "We are attacking %s", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- When the zone is Captured, we send some victory or loss messages to the correct coalition.
|
||||||
|
-- And we add some score.
|
||||||
|
--
|
||||||
|
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
|
||||||
|
-- function ZoneCaptureCoalition:OnEnterCaptured()
|
||||||
|
-- local Coalition = self:GetCoalition()
|
||||||
|
-- self:E({Coalition = Coalition})
|
||||||
|
-- if Coalition == coalition.side.BLUE then
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "%s is captured by the USA, we lost it!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "We captured %s, Excellent job!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- else
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "%s is captured by Russia, we lost it!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "We captured %s, Excellent job!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- self:__Guard( 30 )
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- And this call is the most important of all!
|
||||||
|
-- In the context of the mission, we need to start the zone capture monitoring process.
|
||||||
|
-- Or nothing will be monitored and the zone won't change states.
|
||||||
|
-- We start the monitoring after 5 seconds, and will repeat every 30 seconds a check.
|
||||||
|
--
|
||||||
|
-- ZoneCaptureCoalition:Start( 5, 30 )
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #ZONE_CAPTURE_COALITION
|
||||||
|
ZONE_CAPTURE_COALITION = {
|
||||||
|
ClassName = "ZONE_CAPTURE_COALITION",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- @field #table ZONE_CAPTURE_COALITION.States
|
||||||
|
ZONE_CAPTURE_COALITION.States = {}
|
||||||
|
|
||||||
|
--- 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.
|
||||||
|
-- @return #ZONE_CAPTURE_COALITION
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- AttackZone = ZONE:New( "AttackZone" )
|
||||||
|
--
|
||||||
|
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( AttackZone, coalition.side.RED ) -- Create a new ZONE_CAPTURE_COALITION object of zone AttackZone with ownership RED coalition.
|
||||||
|
-- ZoneCaptureCoalition:__Guard( 1 ) -- Start the Guarding of the AttackZone.
|
||||||
|
--
|
||||||
|
function ZONE_CAPTURE_COALITION:New( Zone, Coalition )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, ZONE_GOAL_COALITION:New( Zone, Coalition ) ) -- #ZONE_CAPTURE_COALITION
|
||||||
|
|
||||||
|
self:F( { Zone = Zone, Coalition = Coalition } )
|
||||||
|
|
||||||
|
do
|
||||||
|
|
||||||
|
--- Captured State Handler OnLeave for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveCaptured
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Captured State Handler OnEnter for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterCaptured
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
|
||||||
|
--- Attacked State Handler OnLeave for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveAttacked
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Attacked State Handler OnEnter for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterAttacked
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
|
||||||
|
--- Guarded State Handler OnLeave for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveGuarded
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Guarded State Handler OnEnter for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterGuarded
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
|
||||||
|
--- Empty State Handler OnLeave for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveEmpty
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Empty State Handler OnEnter for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterEmpty
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Guard", "Guarded" )
|
||||||
|
|
||||||
|
--- Guard Handler OnBefore for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeGuard
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Guard Handler OnAfter for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterGuard
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
--- Guard Trigger for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] Guard
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
|
||||||
|
--- Guard Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] __Guard
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #number Delay
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Empty", "Empty" )
|
||||||
|
|
||||||
|
--- Empty Handler OnBefore for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeEmpty
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Empty Handler OnAfter for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterEmpty
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
--- Empty Trigger for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] Empty
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
|
||||||
|
--- Empty Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] __Empty
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #number Delay
|
||||||
|
|
||||||
|
|
||||||
|
self:AddTransition( { "Guarded", "Empty" }, "Attack", "Attacked" )
|
||||||
|
|
||||||
|
--- Attack Handler OnBefore for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeAttack
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Attack Handler OnAfter for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterAttack
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
--- Attack Trigger for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] Attack
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
|
||||||
|
--- Attack Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] __Attack
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #number Delay
|
||||||
|
|
||||||
|
self:AddTransition( { "Guarded", "Attacked", "Empty" }, "Capture", "Captured" )
|
||||||
|
|
||||||
|
--- Capture Handler OnBefore for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeCapture
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Capture Handler OnAfter for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterCapture
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
--- Capture Trigger for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] Capture
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
|
||||||
|
--- Capture Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
|
||||||
|
-- @function [parent=#ZONE_CAPTURE_COALITION] __Capture
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #number Delay
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
function ZONE_CAPTURE_COALITION:onenterCaptured()
|
||||||
|
|
||||||
|
self:GetParent( self, ZONE_CAPTURE_COALITION ).onenterCaptured( self )
|
||||||
|
|
||||||
|
self.Goal:Achieved()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_CAPTURE_COALITION:IsGuarded()
|
||||||
|
|
||||||
|
local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition )
|
||||||
|
self:F( { IsGuarded = IsGuarded } )
|
||||||
|
return IsGuarded
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_CAPTURE_COALITION:IsEmpty()
|
||||||
|
|
||||||
|
local IsEmpty = self.Zone:IsNoneInZone()
|
||||||
|
self:F( { IsEmpty = IsEmpty } )
|
||||||
|
return IsEmpty
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_CAPTURE_COALITION:IsCaptured()
|
||||||
|
|
||||||
|
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||||
|
self:F( { IsCaptured = IsCaptured } )
|
||||||
|
return IsCaptured
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_CAPTURE_COALITION:IsAttacked()
|
||||||
|
|
||||||
|
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||||
|
self:F( { IsAttacked = IsAttacked } )
|
||||||
|
return IsAttacked
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Mark.
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
function ZONE_CAPTURE_COALITION:Mark()
|
||||||
|
|
||||||
|
local Coord = self.Zone:GetCoordinate()
|
||||||
|
local ZoneName = self:GetZoneName()
|
||||||
|
local State = self:GetState()
|
||||||
|
|
||||||
|
if self.MarkRed and self.MarkBlue then
|
||||||
|
self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } )
|
||||||
|
Coord:RemoveMark( self.MarkRed )
|
||||||
|
Coord:RemoveMark( self.MarkBlue )
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.Coalition == coalition.side.BLUE then
|
||||||
|
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||||
|
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||||
|
else
|
||||||
|
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Red\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||||
|
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Red\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Bound.
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
function ZONE_CAPTURE_COALITION:onenterGuarded()
|
||||||
|
|
||||||
|
--self:GetParent( self ):onenterGuarded()
|
||||||
|
|
||||||
|
if self.Coalition == coalition.side.BLUE then
|
||||||
|
--elf.ProtectZone:BoundZone( 12, country.id.USA )
|
||||||
|
else
|
||||||
|
--self.ProtectZone:BoundZone( 12, country.id.RUSSIA )
|
||||||
|
end
|
||||||
|
|
||||||
|
self:Mark()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ZONE_CAPTURE_COALITION:onenterCaptured()
|
||||||
|
|
||||||
|
--self:GetParent( self ):onenterCaptured()
|
||||||
|
|
||||||
|
local NewCoalition = self.Zone:GetScannedCoalition()
|
||||||
|
self:F( { NewCoalition = NewCoalition } )
|
||||||
|
self:SetCoalition( NewCoalition )
|
||||||
|
|
||||||
|
self:Mark()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_CAPTURE_COALITION:onenterEmpty()
|
||||||
|
|
||||||
|
--self:GetParent( self ):onenterEmpty()
|
||||||
|
|
||||||
|
self:Mark()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_CAPTURE_COALITION:onenterAttacked()
|
||||||
|
|
||||||
|
--self:GetParent( self ):onenterAttacked()
|
||||||
|
|
||||||
|
self:Mark()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- When started, check the Coalition status.
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
function ZONE_CAPTURE_COALITION:onafterGuard()
|
||||||
|
|
||||||
|
--self:F({BASE:GetParent( self )})
|
||||||
|
--BASE:GetParent( self ).onafterGuard( self )
|
||||||
|
|
||||||
|
if not self.SmokeScheduler then
|
||||||
|
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_CAPTURE_COALITION:IsCaptured()
|
||||||
|
|
||||||
|
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||||
|
self:F( { IsCaptured = IsCaptured } )
|
||||||
|
return IsCaptured
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_CAPTURE_COALITION:IsAttacked()
|
||||||
|
|
||||||
|
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||||
|
self:F( { IsAttacked = IsAttacked } )
|
||||||
|
return IsAttacked
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check status Coalition ownership.
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
function ZONE_CAPTURE_COALITION:StatusZone()
|
||||||
|
|
||||||
|
local State = self:GetState()
|
||||||
|
self:F( { State = self:GetState() } )
|
||||||
|
|
||||||
|
self:GetParent( self, ZONE_CAPTURE_COALITION ).StatusZone( self )
|
||||||
|
|
||||||
|
if State ~= "Guarded" and self:IsGuarded() then
|
||||||
|
self:Guard()
|
||||||
|
end
|
||||||
|
|
||||||
|
if State ~= "Empty" and self:IsEmpty() then
|
||||||
|
self:Empty()
|
||||||
|
end
|
||||||
|
|
||||||
|
if State ~= "Attacked" and self:IsAttacked() then
|
||||||
|
self:Attack()
|
||||||
|
end
|
||||||
|
|
||||||
|
if State ~= "Captured" and self:IsCaptured() then
|
||||||
|
self:Capture()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Starts the zone capturing monitoring process.
|
||||||
|
-- This process can be CPU intensive, ensure that you specify reasonable time intervals for the monitoring process.
|
||||||
|
-- Note that the monitoring process is NOT started automatically during the `:New()` constructor.
|
||||||
|
-- It is advised that the zone monitoring process is only started when the monitoring is of relevance in context of the current mission goals.
|
||||||
|
-- When the zone is of no relevance, it is advised NOT to start the monitoring process, or to stop the monitoring process to save CPU resources.
|
||||||
|
-- Therefore, the mission designer will need to use the `:Start()` method within his script to start the monitoring process specifically.
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @param #number StartInterval (optional) Specifies the start time interval in seconds when the zone state will be checked for the first time.
|
||||||
|
-- @param #number RepeatInterval (optional) Specifies the repeat time interval in seconds when the zone state will be checked repeatedly.
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- Setup the zone.
|
||||||
|
-- CaptureZone = ZONE:New( "CaptureZone" )
|
||||||
|
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( CaptureZone, coalition.side.RED )
|
||||||
|
--
|
||||||
|
-- -- This starts the monitoring process within 15 seconds, repeating every 15 seconds.
|
||||||
|
-- ZoneCaptureCoalition:Start()
|
||||||
|
--
|
||||||
|
-- -- This starts the monitoring process immediately, but repeats every 30 seconds.
|
||||||
|
-- ZoneCaptureCoalition:Start( 0, 30 )
|
||||||
|
--
|
||||||
|
function ZONE_CAPTURE_COALITION:Start( StartInterval, RepeatInterval )
|
||||||
|
|
||||||
|
StartInterval = StartInterval or 15
|
||||||
|
RepeatInterval = RepeatInterval or 15
|
||||||
|
|
||||||
|
if self.ScheduleStatusZone then
|
||||||
|
self:ScheduleStop( self.ScheduleStatusZone )
|
||||||
|
end
|
||||||
|
self.ScheduleStatusZone = self:ScheduleRepeat( StartInterval, RepeatInterval, 0.1, nil, self.StatusZone, self )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Stops the zone capturing monitoring process.
|
||||||
|
-- When the zone capturing monitor process is stopped, there won't be any changes anymore in the state and the owning coalition of the zone.
|
||||||
|
-- This method becomes really useful when the zone is of no relevance anymore within a long lasting mission.
|
||||||
|
-- In this case, it is advised to stop the monitoring process, not to consume unnecessary the CPU intensive scanning of units presence within the zone.
|
||||||
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
|
-- @usage
|
||||||
|
-- -- Setup the zone.
|
||||||
|
-- CaptureZone = ZONE:New( "CaptureZone" )
|
||||||
|
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( CaptureZone, coalition.side.RED )
|
||||||
|
--
|
||||||
|
-- -- This starts the monitoring process within 15 seconds, repeating every 15 seconds.
|
||||||
|
-- ZoneCaptureCoalition:Start()
|
||||||
|
--
|
||||||
|
-- -- When the zone capturing is of no relevance anymore, stop the monitoring!
|
||||||
|
-- ZoneCaptureCoalition:Stop()
|
||||||
|
--
|
||||||
|
-- @usage
|
||||||
|
-- -- For example, one could stop the monitoring when the zone was captured!
|
||||||
|
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
|
||||||
|
-- function ZoneCaptureCoalition:OnEnterCaptured()
|
||||||
|
-- local Coalition = self:GetCoalition()
|
||||||
|
-- self:E({Coalition = Coalition})
|
||||||
|
-- if Coalition == coalition.side.BLUE then
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "%s is captured by the USA, we lost it!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "We captured %s, Excellent job!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- else
|
||||||
|
-- US_CC:MessageTypeToCoalition( string.format( "%s is captured by Russia, we lost it!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- RU_CC:MessageTypeToCoalition( string.format( "We captured %s, Excellent job!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- self:AddScore( "Captured", "Zone captured: Extra points granted.", 200 )
|
||||||
|
--
|
||||||
|
-- self:Stop()
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
function ZONE_CAPTURE_COALITION:Stop()
|
||||||
|
|
||||||
|
if self.ScheduleStatusZone then
|
||||||
|
self:ScheduleStop( self.ScheduleStatusZone )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
176
Moose Development/Moose/Functional/ZoneGoal.lua
Normal file
176
Moose Development/Moose/Functional/ZoneGoal.lua
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ZONE_GOAL models processes that have a Goal with a defined achievement involving a Zone.
|
||||||
|
-- Derived classes implement the ways how the achievements can be realized.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Functional.ZoneGoal
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
do -- Zone
|
||||||
|
|
||||||
|
--- @type ZONE_GOAL
|
||||||
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
|
-- Models processes that have a Goal with a defined achievement involving a Zone.
|
||||||
|
-- Derived classes implement the ways how the achievements can be realized.
|
||||||
|
--
|
||||||
|
-- ## 1. ZONE_GOAL constructor
|
||||||
|
--
|
||||||
|
-- * @{#ZONE_GOAL.New}(): Creates a new ZONE_GOAL object.
|
||||||
|
--
|
||||||
|
-- ## 2. ZONE_GOAL is a finite state machine (FSM).
|
||||||
|
--
|
||||||
|
-- ### 2.1 ZONE_GOAL States
|
||||||
|
--
|
||||||
|
-- * None: Initial State
|
||||||
|
--
|
||||||
|
-- ### 2.2 ZONE_GOAL Events
|
||||||
|
--
|
||||||
|
-- * DestroyedUnit: A @{Wrapper.Unit} is destroyed in the Zone. The event will only get triggered if the method @{#ZONE_GOAL.MonitorDestroyedUnits}() is used.
|
||||||
|
--
|
||||||
|
-- @field #ZONE_GOAL
|
||||||
|
ZONE_GOAL = {
|
||||||
|
ClassName = "ZONE_GOAL",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- ZONE_GOAL Constructor.
|
||||||
|
-- @param #ZONE_GOAL self
|
||||||
|
-- @param Core.Zone#ZONE_BASE Zone A @{Zone} object with the goal to be achieved.
|
||||||
|
-- @return #ZONE_GOAL
|
||||||
|
function ZONE_GOAL:New( Zone )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, FSM:New() ) -- #ZONE_GOAL
|
||||||
|
self:F( { Zone = Zone } )
|
||||||
|
|
||||||
|
self.Zone = Zone -- Core.Zone#ZONE_BASE
|
||||||
|
self.Goal = GOAL:New()
|
||||||
|
|
||||||
|
self.SmokeTime = nil
|
||||||
|
|
||||||
|
self:AddTransition( "*", "DestroyedUnit", "*" )
|
||||||
|
|
||||||
|
--- DestroyedUnit Handler OnAfter for ZONE_GOAL
|
||||||
|
-- @function [parent=#ZONE_GOAL] OnAfterDestroyedUnit
|
||||||
|
-- @param #ZONE_GOAL self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Wrapper.Unit#UNIT DestroyedUnit The destroyed unit.
|
||||||
|
-- @param #string PlayerName The name of the player.
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the Zone
|
||||||
|
-- @param #ZONE_GOAL self
|
||||||
|
-- @return Core.Zone#ZONE_BASE
|
||||||
|
function ZONE_GOAL:GetZone()
|
||||||
|
return self.Zone
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the name of the ProtectZone
|
||||||
|
-- @param #ZONE_GOAL self
|
||||||
|
-- @return #string
|
||||||
|
function ZONE_GOAL:GetZoneName()
|
||||||
|
return self.Zone:GetName()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Smoke the center of theh zone.
|
||||||
|
-- @param #ZONE_GOAL self
|
||||||
|
-- @param #SMOKECOLOR.Color SmokeColor
|
||||||
|
function ZONE_GOAL:Smoke( SmokeColor )
|
||||||
|
|
||||||
|
self:F( { SmokeColor = SmokeColor} )
|
||||||
|
|
||||||
|
self.SmokeColor = SmokeColor
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Flare the center of the zone.
|
||||||
|
-- @param #ZONE_GOAL self
|
||||||
|
-- @param #SMOKECOLOR.Color FlareColor
|
||||||
|
function ZONE_GOAL:Flare( FlareColor )
|
||||||
|
self.Zone:FlareZone( FlareColor, math.random( 1, 360 ) )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- When started, check the Smoke and the Zone status.
|
||||||
|
-- @param #ZONE_GOAL self
|
||||||
|
function ZONE_GOAL:onafterGuard()
|
||||||
|
|
||||||
|
--self:GetParent( self ):onafterStart()
|
||||||
|
|
||||||
|
self:F("Guard")
|
||||||
|
|
||||||
|
--self:ScheduleRepeat( 15, 15, 0.1, nil, self.StatusZone, self )
|
||||||
|
if not self.SmokeScheduler then
|
||||||
|
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check status Smoke.
|
||||||
|
-- @param #ZONE_GOAL self
|
||||||
|
function ZONE_GOAL:StatusSmoke()
|
||||||
|
|
||||||
|
self:F({self.SmokeTime, self.SmokeColor})
|
||||||
|
|
||||||
|
local CurrentTime = timer.getTime()
|
||||||
|
|
||||||
|
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
|
||||||
|
if self.SmokeColor then
|
||||||
|
self.Zone:GetCoordinate():Smoke( self.SmokeColor )
|
||||||
|
--self.SmokeColor = nil
|
||||||
|
self.SmokeTime = CurrentTime
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #ZONE_GOAL self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function ZONE_GOAL:__Destroyed( EventData )
|
||||||
|
self:F( { "EventDead", EventData } )
|
||||||
|
|
||||||
|
self:F( { EventData.IniUnit } )
|
||||||
|
|
||||||
|
local Vec3 = EventData.IniDCSUnit:getPosition().p
|
||||||
|
self:F( { Vec3 = Vec3 } )
|
||||||
|
local ZoneGoal = self:GetZone()
|
||||||
|
self:F({ZoneGoal})
|
||||||
|
|
||||||
|
if EventData.IniDCSUnit then
|
||||||
|
if ZoneGoal: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
|
||||||
451
Moose Development/Moose/Functional/ZoneGoalCargo.lua
Normal file
451
Moose Development/Moose/Functional/ZoneGoalCargo.lua
Normal file
@@ -0,0 +1,451 @@
|
|||||||
|
--- **Functional (WIP)** -- 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.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Functional.ZoneGoalCargo
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
do -- ZoneGoal
|
||||||
|
|
||||||
|
--- @type ZONE_GOAL_CARGO
|
||||||
|
-- @extends Functional.ZoneGoal#ZONE_GOAL
|
||||||
|
|
||||||
|
|
||||||
|
--- 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.
|
||||||
|
--
|
||||||
|
-- ## 1. ZONE_GOAL_CARGO constructor
|
||||||
|
--
|
||||||
|
-- * @{#ZONE_GOAL_CARGO.New}(): Creates a new ZONE_GOAL_CARGO object.
|
||||||
|
--
|
||||||
|
-- ## 2. ZONE_GOAL_CARGO is a finite state machine (FSM).
|
||||||
|
--
|
||||||
|
-- ### 2.1 ZONE_GOAL_CARGO States
|
||||||
|
--
|
||||||
|
-- * **Deployed**: The Zone has been captured by an other coalition.
|
||||||
|
-- * **Airborne**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
|
||||||
|
-- * **Loaded**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
|
||||||
|
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
|
||||||
|
--
|
||||||
|
-- ### 2.2 ZONE_GOAL_CARGO Events
|
||||||
|
--
|
||||||
|
-- * **Capture**: The Zone has been captured by an other coalition.
|
||||||
|
-- * **Attack**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
|
||||||
|
-- * **Guard**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
|
||||||
|
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
|
||||||
|
--
|
||||||
|
-- ### 2.3 ZONE_GOAL_CARGO State Machine
|
||||||
|
--
|
||||||
|
-- @field #ZONE_GOAL_CARGO
|
||||||
|
ZONE_GOAL_CARGO = {
|
||||||
|
ClassName = "ZONE_GOAL_CARGO",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- @field #table ZONE_GOAL_CARGO.States
|
||||||
|
ZONE_GOAL_CARGO.States = {}
|
||||||
|
|
||||||
|
--- 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.
|
||||||
|
-- @return #ZONE_GOAL_CARGO
|
||||||
|
function ZONE_GOAL_CARGO:New( Zone, Coalition )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, ZONE_GOAL:New( Zone ) ) -- #ZONE_GOAL_CARGO
|
||||||
|
self:F( { Zone = Zone, Coalition = Coalition } )
|
||||||
|
|
||||||
|
self:SetCoalition( Coalition )
|
||||||
|
|
||||||
|
do
|
||||||
|
|
||||||
|
--- Captured State Handler OnLeave for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveCaptured
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Captured State Handler OnEnter for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterCaptured
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
|
||||||
|
--- Attacked State Handler OnLeave for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveAttacked
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Attacked State Handler OnEnter for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterAttacked
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
|
||||||
|
--- Guarded State Handler OnLeave for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveGuarded
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Guarded State Handler OnEnter for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterGuarded
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
|
||||||
|
--- Empty State Handler OnLeave for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveEmpty
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Empty State Handler OnEnter for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterEmpty
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Guard", "Guarded" )
|
||||||
|
|
||||||
|
--- Guard Handler OnBefore for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeGuard
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Guard Handler OnAfter for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterGuard
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
--- Guard Trigger for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] Guard
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
|
||||||
|
--- Guard Asynchronous Trigger for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] __Guard
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #number Delay
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Empty", "Empty" )
|
||||||
|
|
||||||
|
--- Empty Handler OnBefore for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeEmpty
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Empty Handler OnAfter for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterEmpty
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
--- Empty Trigger for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] Empty
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
|
||||||
|
--- Empty Asynchronous Trigger for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] __Empty
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #number Delay
|
||||||
|
|
||||||
|
|
||||||
|
self:AddTransition( { "Guarded", "Empty" }, "Attack", "Attacked" )
|
||||||
|
|
||||||
|
--- Attack Handler OnBefore for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeAttack
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Attack Handler OnAfter for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterAttack
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
--- Attack Trigger for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] Attack
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
|
||||||
|
--- Attack Asynchronous Trigger for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] __Attack
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #number Delay
|
||||||
|
|
||||||
|
self:AddTransition( { "Guarded", "Attacked", "Empty" }, "Capture", "Captured" )
|
||||||
|
|
||||||
|
--- Capture Handler OnBefore for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeCapture
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- Capture Handler OnAfter for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterCapture
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
|
--- Capture Trigger for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] Capture
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
|
||||||
|
--- Capture Asynchronous Trigger for ZONE_GOAL_CARGO
|
||||||
|
-- @function [parent=#ZONE_GOAL_CARGO] __Capture
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param #number Delay
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set the owning coalition of the zone.
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @param DCSCoalition.DCSCoalition#coalition Coalition
|
||||||
|
function ZONE_GOAL_CARGO:SetCoalition( Coalition )
|
||||||
|
self.Coalition = Coalition
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the owning coalition of the zone.
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||||
|
function ZONE_GOAL_CARGO:GetCoalition()
|
||||||
|
return self.Coalition
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the owning coalition name of the zone.
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
-- @return #string Coalition name.
|
||||||
|
function ZONE_GOAL_CARGO:GetCoalitionName()
|
||||||
|
|
||||||
|
if self.Coalition == coalition.side.BLUE then
|
||||||
|
return "Blue"
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.Coalition == coalition.side.RED then
|
||||||
|
return "Red"
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.Coalition == coalition.side.NEUTRAL then
|
||||||
|
return "Neutral"
|
||||||
|
end
|
||||||
|
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_GOAL_CARGO:IsGuarded()
|
||||||
|
|
||||||
|
local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition )
|
||||||
|
self:F( { IsGuarded = IsGuarded } )
|
||||||
|
return IsGuarded
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_GOAL_CARGO:IsEmpty()
|
||||||
|
|
||||||
|
local IsEmpty = self.Zone:IsNoneInZone()
|
||||||
|
self:F( { IsEmpty = IsEmpty } )
|
||||||
|
return IsEmpty
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_GOAL_CARGO:IsCaptured()
|
||||||
|
|
||||||
|
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||||
|
self:F( { IsCaptured = IsCaptured } )
|
||||||
|
return IsCaptured
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_GOAL_CARGO:IsAttacked()
|
||||||
|
|
||||||
|
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||||
|
self:F( { IsAttacked = IsAttacked } )
|
||||||
|
return IsAttacked
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Mark.
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
function ZONE_GOAL_CARGO:Mark()
|
||||||
|
|
||||||
|
local Coord = self.Zone:GetCoordinate()
|
||||||
|
local ZoneName = self:GetZoneName()
|
||||||
|
local State = self:GetState()
|
||||||
|
|
||||||
|
if self.MarkRed and self.MarkBlue then
|
||||||
|
self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } )
|
||||||
|
Coord:RemoveMark( self.MarkRed )
|
||||||
|
Coord:RemoveMark( self.MarkBlue )
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.Coalition == coalition.side.BLUE then
|
||||||
|
self.MarkBlue = Coord:MarkToCoalitionBlue( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||||
|
self.MarkRed = Coord:MarkToCoalitionRed( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||||
|
else
|
||||||
|
self.MarkRed = Coord:MarkToCoalitionRed( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||||
|
self.MarkBlue = Coord:MarkToCoalitionBlue( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Bound.
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
function ZONE_GOAL_CARGO:onenterGuarded()
|
||||||
|
|
||||||
|
--self:GetParent( self ):onenterGuarded()
|
||||||
|
|
||||||
|
if self.Coalition == coalition.side.BLUE then
|
||||||
|
--elf.ProtectZone:BoundZone( 12, country.id.USA )
|
||||||
|
else
|
||||||
|
--self.ProtectZone:BoundZone( 12, country.id.RUSSIA )
|
||||||
|
end
|
||||||
|
|
||||||
|
self:Mark()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ZONE_GOAL_CARGO:onenterCaptured()
|
||||||
|
|
||||||
|
--self:GetParent( self ):onenterCaptured()
|
||||||
|
|
||||||
|
local NewCoalition = self.Zone:GetCoalition()
|
||||||
|
self:F( { NewCoalition = NewCoalition } )
|
||||||
|
self:SetCoalition( NewCoalition )
|
||||||
|
|
||||||
|
self:Mark()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_GOAL_CARGO:onenterEmpty()
|
||||||
|
|
||||||
|
--self:GetParent( self ):onenterEmpty()
|
||||||
|
|
||||||
|
self:Mark()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_GOAL_CARGO:onenterAttacked()
|
||||||
|
|
||||||
|
--self:GetParent( self ):onenterAttacked()
|
||||||
|
|
||||||
|
self:Mark()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- When started, check the Coalition status.
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
function ZONE_GOAL_CARGO:onafterGuard()
|
||||||
|
|
||||||
|
--self:F({BASE:GetParent( self )})
|
||||||
|
--BASE:GetParent( self ).onafterGuard( self )
|
||||||
|
|
||||||
|
if not self.SmokeScheduler then
|
||||||
|
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self )
|
||||||
|
end
|
||||||
|
if not self.ScheduleStatusZone then
|
||||||
|
self.ScheduleStatusZone = self:ScheduleRepeat( 15, 15, 0.1, nil, self.StatusZone, self )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_GOAL_CARGO:IsCaptured()
|
||||||
|
|
||||||
|
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||||
|
self:F( { IsCaptured = IsCaptured } )
|
||||||
|
return IsCaptured
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ZONE_GOAL_CARGO:IsAttacked()
|
||||||
|
|
||||||
|
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||||
|
self:F( { IsAttacked = IsAttacked } )
|
||||||
|
return IsAttacked
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check status Coalition ownership.
|
||||||
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
|
function ZONE_GOAL_CARGO:StatusZone()
|
||||||
|
|
||||||
|
local State = self:GetState()
|
||||||
|
self:F( { State = self:GetState() } )
|
||||||
|
|
||||||
|
self.Zone:Scan()
|
||||||
|
|
||||||
|
if State ~= "Guarded" and self:IsGuarded() then
|
||||||
|
self:Guard()
|
||||||
|
end
|
||||||
|
|
||||||
|
if State ~= "Empty" and self:IsEmpty() then
|
||||||
|
self:Empty()
|
||||||
|
end
|
||||||
|
|
||||||
|
if State ~= "Attacked" and self:IsAttacked() then
|
||||||
|
self:Attack()
|
||||||
|
end
|
||||||
|
|
||||||
|
if State ~= "Captured" and self:IsCaptured() then
|
||||||
|
self:Capture()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
112
Moose Development/Moose/Functional/ZoneGoalCoalition.lua
Normal file
112
Moose Development/Moose/Functional/ZoneGoalCoalition.lua
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone for a Coalition.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition.
|
||||||
|
-- Derived classes implement the ways how the achievements can be realized.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Functional.ZoneGoalCoalition
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
do -- ZoneGoal
|
||||||
|
|
||||||
|
--- @type ZONE_GOAL_COALITION
|
||||||
|
-- @extends Functional.ZoneGoal#ZONE_GOAL
|
||||||
|
|
||||||
|
|
||||||
|
--- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition.
|
||||||
|
-- Derived classes implement the ways how the achievements can be realized.
|
||||||
|
--
|
||||||
|
-- ## 1. ZONE_GOAL_COALITION constructor
|
||||||
|
--
|
||||||
|
-- * @{#ZONE_GOAL_COALITION.New}(): Creates a new ZONE_GOAL_COALITION object.
|
||||||
|
--
|
||||||
|
-- ## 2. ZONE_GOAL_COALITION is a finite state machine (FSM).
|
||||||
|
--
|
||||||
|
-- ### 2.1 ZONE_GOAL_COALITION States
|
||||||
|
--
|
||||||
|
-- ### 2.2 ZONE_GOAL_COALITION Events
|
||||||
|
--
|
||||||
|
-- ### 2.3 ZONE_GOAL_COALITION State Machine
|
||||||
|
--
|
||||||
|
-- @field #ZONE_GOAL_COALITION
|
||||||
|
ZONE_GOAL_COALITION = {
|
||||||
|
ClassName = "ZONE_GOAL_COALITION",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- @field #table ZONE_GOAL_COALITION.States
|
||||||
|
ZONE_GOAL_COALITION.States = {}
|
||||||
|
|
||||||
|
--- ZONE_GOAL_COALITION Constructor.
|
||||||
|
-- @param #ZONE_GOAL_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.
|
||||||
|
-- @return #ZONE_GOAL_COALITION
|
||||||
|
function ZONE_GOAL_COALITION:New( Zone, Coalition )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, ZONE_GOAL:New( Zone ) ) -- #ZONE_GOAL_COALITION
|
||||||
|
self:F( { Zone = Zone, Coalition = Coalition } )
|
||||||
|
|
||||||
|
self:SetCoalition( Coalition )
|
||||||
|
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set the owning coalition of the zone.
|
||||||
|
-- @param #ZONE_GOAL_COALITION self
|
||||||
|
-- @param DCSCoalition.DCSCoalition#coalition Coalition
|
||||||
|
function ZONE_GOAL_COALITION:SetCoalition( Coalition )
|
||||||
|
self.Coalition = Coalition
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the owning coalition of the zone.
|
||||||
|
-- @param #ZONE_GOAL_COALITION self
|
||||||
|
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||||
|
function ZONE_GOAL_COALITION:GetCoalition()
|
||||||
|
return self.Coalition
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the owning coalition name of the zone.
|
||||||
|
-- @param #ZONE_GOAL_COALITION self
|
||||||
|
-- @return #string Coalition name.
|
||||||
|
function ZONE_GOAL_COALITION:GetCoalitionName()
|
||||||
|
|
||||||
|
if self.Coalition == coalition.side.BLUE then
|
||||||
|
return "Blue"
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.Coalition == coalition.side.RED then
|
||||||
|
return "Red"
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.Coalition == coalition.side.NEUTRAL then
|
||||||
|
return "Neutral"
|
||||||
|
end
|
||||||
|
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check status Coalition ownership.
|
||||||
|
-- @param #ZONE_GOAL_COALITION self
|
||||||
|
function ZONE_GOAL_COALITION:StatusZone()
|
||||||
|
|
||||||
|
local State = self:GetState()
|
||||||
|
self:F( { State = self:GetState() } )
|
||||||
|
|
||||||
|
self.Zone:Scan( { Object.Category.UNIT, Object.Category.STATIC } )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
-- The order of the declarations is important here. Don't touch it.
|
-- The order of the declarations is important here. Don't touch it.
|
||||||
|
|
||||||
|
|
||||||
--- Declare the event dispatcher based on the EVENT class
|
--- Declare the event dispatcher based on the EVENT class
|
||||||
_EVENTDISPATCHER = EVENT:New() -- Core.Event#EVENT
|
_EVENTDISPATCHER = EVENT:New() -- Core.Event#EVENT
|
||||||
|
|
||||||
@@ -10,4 +11,8 @@ _SCHEDULEDISPATCHER = SCHEDULEDISPATCHER:New() -- Core.Timer#SCHEDULEDISPATCHER
|
|||||||
_DATABASE = DATABASE:New() -- Core.Database#DATABASE
|
_DATABASE = DATABASE:New() -- Core.Database#DATABASE
|
||||||
|
|
||||||
_SETTINGS = SETTINGS:Set()
|
_SETTINGS = SETTINGS:Set()
|
||||||
|
_SETTINGS:SetPlayerMenuOn()
|
||||||
|
|
||||||
|
_DATABASE:_RegisterCargos()
|
||||||
|
_DATABASE:_RegisterZones()
|
||||||
|
|
||||||
|
|||||||
@@ -1,45 +1,122 @@
|
|||||||
--- **Tasking** -- A COMMANDCENTER is the owner of multiple missions within MOOSE.
|
--- **Tasking** -- A command center governs multiple missions, and takes care of the reporting and communications.
|
||||||
-- A COMMANDCENTER governs multiple missions, the tasking and the reporting.
|
--
|
||||||
|
-- **Features:**
|
||||||
|
--
|
||||||
|
-- * Govern multiple missions.
|
||||||
|
-- * Communicate to coalitions, groups.
|
||||||
|
-- * Assign tasks.
|
||||||
|
-- * Manage the menus.
|
||||||
|
-- * Manage reference zones.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- ### Author: **FlightControl**
|
||||||
--
|
--
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- ====
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module CommandCenter
|
-- @module Tasking.CommandCenter
|
||||||
|
-- @image Task_Command_Center.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- The COMMANDCENTER class
|
--- The COMMANDCENTER class
|
||||||
-- @type COMMANDCENTER
|
-- @type COMMANDCENTER
|
||||||
-- @field Wrapper.Group#GROUP HQ
|
-- @field Wrapper.Group#GROUP HQ
|
||||||
-- @field Dcs.DCSCoalitionWrapper.Object#coalition CommandCenterCoalition
|
-- @field DCS#coalition CommandCenterCoalition
|
||||||
-- @list<Tasking.Mission#MISSION> Missions
|
-- @list<Tasking.Mission#MISSION> Missions
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
--- # COMMANDCENTER class, extends @{Base#BASE}
|
--- Governs multiple missions, the tasking and the reporting.
|
||||||
--
|
|
||||||
-- The COMMANDCENTER class governs multiple missions, the tasking and the reporting.
|
|
||||||
--
|
--
|
||||||
-- The commandcenter communicates important messages between the various groups of human players executing tasks in missions.
|
-- Command centers govern missions, communicates the task assignments between human players of the coalition, and manages the menu flow.
|
||||||
|
-- It can assign a random task to a player when requested.
|
||||||
|
-- The commandcenter provides the facilitites to communicate between human players online, executing a task.
|
||||||
--
|
--
|
||||||
-- ## COMMANDCENTER constructor
|
-- ## 1. Create a command center object.
|
||||||
--
|
--
|
||||||
-- * @{#COMMANDCENTER.New}(): Creates a new COMMANDCENTER object.
|
-- * @{#COMMANDCENTER.New}(): Creates a new COMMANDCENTER object.
|
||||||
--
|
--
|
||||||
-- ## Mission Management
|
-- ## 2. Command center mission management.
|
||||||
|
--
|
||||||
|
-- Command centers manage missions. These can be added, removed and provides means to retrieve missions.
|
||||||
|
-- These methods are heavily used by the task dispatcher classes.
|
||||||
--
|
--
|
||||||
-- * @{#COMMANDCENTER.AddMission}(): Adds a mission to the commandcenter control.
|
-- * @{#COMMANDCENTER.AddMission}(): Adds a mission to the commandcenter control.
|
||||||
-- * @{#COMMANDCENTER.RemoveMission}(): Removes a mission to the commandcenter control.
|
-- * @{#COMMANDCENTER.RemoveMission}(): Removes a mission to the commandcenter control.
|
||||||
-- * @{#COMMANDCENTER.GetMissions}(): Retrieves the missions table controlled by the commandcenter.
|
-- * @{#COMMANDCENTER.GetMissions}(): Retrieves the missions table controlled by the commandcenter.
|
||||||
--
|
--
|
||||||
-- ## Reference Zones
|
-- ## 3. Communication management between players.
|
||||||
|
--
|
||||||
|
-- Command center provide means of communication between players.
|
||||||
|
-- Because a command center is a central object governing multiple missions,
|
||||||
|
-- there are several levels at which communication needs to be done.
|
||||||
|
-- Within MOOSE, communication is facilitated using the message system within the DCS simulator.
|
||||||
|
--
|
||||||
|
-- Messages can be sent between players at various levels:
|
||||||
|
--
|
||||||
|
-- - On a global level, to all players.
|
||||||
|
-- - On a coalition level, only to the players belonging to the same coalition.
|
||||||
|
-- - On a group level, to the players belonging to the same group.
|
||||||
|
--
|
||||||
|
-- Messages can be sent to **all players** by the command center using the method @{Tasking.CommandCenter#COMMANDCENTER.MessageToAll}().
|
||||||
|
--
|
||||||
|
-- To send messages to **the coalition of the command center**, there are two methods available:
|
||||||
|
--
|
||||||
|
-- - Use the method @{Tasking.CommandCenter#COMMANDCENTER.MessageToCoalition}() to send a specific message to the coalition, with a given message display duration.
|
||||||
|
-- - You can send a specific type of message using the method @{Tasking.CommandCenter#COMMANDCENTER.MessageTypeToCoalition}().
|
||||||
|
-- This will send a message of a specific type to the coalition, and as a result its display duration will be flexible according the message display time selection by the human player.
|
||||||
|
--
|
||||||
|
-- To send messages **to the group** of human players, there are also two methods available:
|
||||||
|
--
|
||||||
|
-- - Use the method @{Tasking.CommandCenter#COMMANDCENTER.MessageToGroup}() to send a specific message to a group, with a given message display duration.
|
||||||
|
-- - You can send a specific type of message using the method @{Tasking.CommandCenter#COMMANDCENTER.MessageTypeToGroup}().
|
||||||
|
-- This will send a message of a specific type to the group, and as a result its display duration will be flexible according the message display time selection by the human player .
|
||||||
|
--
|
||||||
|
-- Messages are considered to be sometimes disturbing for human players, therefore, the settings menu provides the means to activate or deactivate messages.
|
||||||
|
-- For more information on the message types and display timings that can be selected and configured using the menu, refer to the @{Core.Settings} menu description.
|
||||||
|
--
|
||||||
|
-- ## 4. Command center detailed methods.
|
||||||
|
--
|
||||||
|
-- Various methods are added to manage command centers.
|
||||||
|
--
|
||||||
|
-- ### 4.1. Naming and description.
|
||||||
|
--
|
||||||
|
-- There are 3 methods that can be used to retrieve the description of a command center:
|
||||||
|
--
|
||||||
|
-- - Use the method @{Tasking.CommandCenter#COMMANDCENTER.GetName}() to retrieve the name of the command center.
|
||||||
|
-- This is the name given as part of the @{Tasking.CommandCenter#COMMANDCENTER.New}() constructor.
|
||||||
|
-- The returned name using this method, is not to be used for message communication.
|
||||||
|
--
|
||||||
|
-- A textual description can be retrieved that provides the command center name to be used within message communication:
|
||||||
|
--
|
||||||
|
-- - @{Tasking.CommandCenter#COMMANDCENTER.GetShortText}() returns the command center name as `CC [CommandCenterName]`.
|
||||||
|
-- - @{Tasking.CommandCenter#COMMANDCENTER.GetText}() returns the command center name as `Command Center [CommandCenterName]`.
|
||||||
|
--
|
||||||
|
-- ### 4.2. The coalition of the command center.
|
||||||
|
--
|
||||||
|
-- The method @{Tasking.CommandCenter#COMMANDCENTER.GetCoalition}() returns the coalition of the command center.
|
||||||
|
-- The return value is an enumeration of the type @{DCS#coalition.side}, which contains the RED, BLUE and NEUTRAL coalition.
|
||||||
|
--
|
||||||
|
-- ### 4.3. The command center is a real object.
|
||||||
|
--
|
||||||
|
-- The command center must be represented by a live object within the DCS simulator. As a result, the command center
|
||||||
|
-- can be a @{Wrapper.Unit}, a @{Wrapper.Group}, an @{Wrapper.Airbase} or a @{Wrapper.Static} object.
|
||||||
|
--
|
||||||
|
-- Using the method @{Tasking.CommandCenter#COMMANDCENTER.GetPositionable}() you retrieve the polymorphic positionable object representing
|
||||||
|
-- the command center, but just be aware that you should be able to use the representable object derivation methods.
|
||||||
|
--
|
||||||
|
-- ### 5. Command center reports.
|
||||||
|
--
|
||||||
|
-- Because a command center giverns multiple missions, there are several reports available that are generated by command centers.
|
||||||
|
-- These reports are generated using the following methods:
|
||||||
|
--
|
||||||
|
-- - @{Tasking.CommandCenter#COMMANDCENTER.ReportSummary}(): Creates a summary report of all missions governed by the command center.
|
||||||
|
-- - @{Tasking.CommandCenter#COMMANDCENTER.ReportDetails}(): Creates a detailed report of all missions governed by the command center.
|
||||||
|
-- - @{Tasking.CommandCenter#COMMANDCENTER.ReportMissionPlayers}(): Creates a report listing the players active at the missions governed by the command center.
|
||||||
|
--
|
||||||
|
-- ## 6. Reference Zones.
|
||||||
--
|
--
|
||||||
-- Command Centers may be aware of certain Reference Zones within the battleground. These Reference Zones can refer to
|
-- Command Centers may be aware of certain Reference Zones within the battleground. These Reference Zones can refer to
|
||||||
-- known areas, recognizable buildings or sites, or any other point of interest.
|
-- known areas, recognizable buildings or sites, or any other point of interest.
|
||||||
@@ -86,11 +163,13 @@ COMMANDCENTER = {
|
|||||||
-- @return #COMMANDCENTER
|
-- @return #COMMANDCENTER
|
||||||
function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, BASE:New() ) -- #COMMANDCENTER
|
||||||
|
|
||||||
self.CommandCenterPositionable = CommandCenterPositionable
|
self.CommandCenterPositionable = CommandCenterPositionable
|
||||||
self.CommandCenterName = CommandCenterName or CommandCenterPositionable:GetName()
|
self.CommandCenterName = CommandCenterName or CommandCenterPositionable:GetName()
|
||||||
self.CommandCenterCoalition = CommandCenterPositionable:GetCoalition()
|
self.CommandCenterCoalition = CommandCenterPositionable:GetCoalition()
|
||||||
|
|
||||||
|
self.AutoAssignTasks = false
|
||||||
|
|
||||||
self.Missions = {}
|
self.Missions = {}
|
||||||
|
|
||||||
@@ -100,8 +179,10 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
|||||||
function( self, EventData )
|
function( self, EventData )
|
||||||
if EventData.IniObjectCategory == 1 then
|
if EventData.IniObjectCategory == 1 then
|
||||||
local EventGroup = GROUP:Find( EventData.IniDCSGroup )
|
local EventGroup = GROUP:Find( EventData.IniDCSGroup )
|
||||||
|
self:E( { CommandCenter = self:GetName(), EventGroup = EventGroup:GetName(), HasGroup = self:HasGroup( EventGroup ), EventData = EventData } )
|
||||||
if EventGroup and self:HasGroup( EventGroup ) then
|
if EventGroup and self:HasGroup( EventGroup ) then
|
||||||
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", self.CommandCenterMenu )
|
local CommandCenterMenu = MENU_GROUP:New( EventGroup, self:GetText() )
|
||||||
|
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", CommandCenterMenu )
|
||||||
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportMissionsStatus, self, EventGroup )
|
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportMissionsStatus, self, EventGroup )
|
||||||
local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Players Report", MenuReporting, self.ReportMissionsPlayers, self, EventGroup )
|
local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Players Report", MenuReporting, self.ReportMissionsPlayers, self, EventGroup )
|
||||||
self:ReportSummary( EventGroup )
|
self:ReportSummary( EventGroup )
|
||||||
@@ -112,31 +193,30 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
|||||||
Mission:JoinUnit( PlayerUnit, PlayerGroup )
|
Mission:JoinUnit( PlayerUnit, PlayerGroup )
|
||||||
end
|
end
|
||||||
self:SetMenu()
|
self:SetMenu()
|
||||||
_DATABASE:PlayerSettingsMenu( PlayerUnit )
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
-- When a player enters a client or a unit, the CommandCenter will check for each Mission and each Task in the Mission if the player has things to do.
|
-- -- When a player enters a client or a unit, the CommandCenter will check for each Mission and each Task in the Mission if the player has things to do.
|
||||||
-- For these elements, it will=
|
-- -- For these elements, it will=
|
||||||
-- - Set the correct menu.
|
-- -- - Set the correct menu.
|
||||||
-- - Assign the PlayerUnit to the Task if required.
|
-- -- - Assign the PlayerUnit to the Task if required.
|
||||||
-- - Send a message to the other players in the group that this player has joined.
|
-- -- - Send a message to the other players in the group that this player has joined.
|
||||||
self:HandleEvent( EVENTS.PlayerEnterUnit,
|
-- self:HandleEvent( EVENTS.PlayerEnterUnit,
|
||||||
--- @param #COMMANDCENTER self
|
-- --- @param #COMMANDCENTER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- -- @param Core.Event#EVENTDATA EventData
|
||||||
function( self, EventData )
|
-- function( self, EventData )
|
||||||
local PlayerUnit = EventData.IniUnit
|
-- local PlayerUnit = EventData.IniUnit
|
||||||
for MissionID, Mission in pairs( self:GetMissions() ) do
|
-- for MissionID, Mission in pairs( self:GetMissions() ) do
|
||||||
local Mission = Mission -- Tasking.Mission#MISSION
|
-- local Mission = Mission -- Tasking.Mission#MISSION
|
||||||
local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
|
-- local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
|
||||||
Mission:JoinUnit( PlayerUnit, PlayerGroup )
|
-- Mission:JoinUnit( PlayerUnit, PlayerGroup )
|
||||||
end
|
-- end
|
||||||
self:SetMenu()
|
-- self:SetMenu()
|
||||||
end
|
-- end
|
||||||
)
|
-- )
|
||||||
|
|
||||||
-- Handle when a player leaves a slot and goes back to spectators ...
|
-- Handle when a player leaves a slot and goes back to spectators ...
|
||||||
-- The PlayerUnit will be UnAssigned from the Task.
|
-- The PlayerUnit will be UnAssigned from the Task.
|
||||||
@@ -170,7 +250,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
|||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
-- Handle when a player leaves a slot and goes back to spectators ...
|
-- Handle when a player crashes ...
|
||||||
-- The PlayerUnit will be UnAssigned from the Task.
|
-- The PlayerUnit will be UnAssigned from the Task.
|
||||||
-- When there is no Unit left running the Task, the Task goes into Abort...
|
-- When there is no Unit left running the Task, the Task goes into Abort...
|
||||||
self:HandleEvent( EVENTS.Crash,
|
self:HandleEvent( EVENTS.Crash,
|
||||||
@@ -190,6 +270,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
|||||||
self:SetMenu()
|
self:SetMenu()
|
||||||
|
|
||||||
_SETTINGS:SetSystemMenu( CommandCenterPositionable )
|
_SETTINGS:SetSystemMenu( CommandCenterPositionable )
|
||||||
|
|
||||||
|
self:SetCommandMenu()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -202,6 +284,32 @@ function COMMANDCENTER:GetName()
|
|||||||
return self.CommandCenterName
|
return self.CommandCenterName
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Gets the text string of the HQ command center.
|
||||||
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @return #string
|
||||||
|
function COMMANDCENTER:GetText()
|
||||||
|
|
||||||
|
return "Command Center [" .. self.CommandCenterName .. "]"
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the short text string of the HQ command center.
|
||||||
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @return #string
|
||||||
|
function COMMANDCENTER:GetShortText()
|
||||||
|
|
||||||
|
return "CC [" .. self.CommandCenterName .. "]"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Gets the coalition of the command center.
|
||||||
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @return DCScoalition#coalition
|
||||||
|
function COMMANDCENTER:GetCoalition()
|
||||||
|
|
||||||
|
return self.CommandCenterCoalition
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Gets the POSITIONABLE of the HQ command center.
|
--- Gets the POSITIONABLE of the HQ command center.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
-- @return Wrapper.Positionable#POSITIONABLE
|
-- @return Wrapper.Positionable#POSITIONABLE
|
||||||
@@ -214,7 +322,7 @@ end
|
|||||||
-- @return #list<Tasking.Mission#MISSION>
|
-- @return #list<Tasking.Mission#MISSION>
|
||||||
function COMMANDCENTER:GetMissions()
|
function COMMANDCENTER:GetMissions()
|
||||||
|
|
||||||
return self.Missions
|
return self.Missions or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a MISSION to be governed by the HQ command center.
|
--- Add a MISSION to be governed by the HQ command center.
|
||||||
@@ -303,9 +411,7 @@ end
|
|||||||
--- Sets the menu structure of the Missions governed by the HQ command center.
|
--- Sets the menu structure of the Missions governed by the HQ command center.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
function COMMANDCENTER:SetMenu()
|
function COMMANDCENTER:SetMenu()
|
||||||
self:F()
|
self:F2()
|
||||||
|
|
||||||
self.CommandCenterMenu = self.CommandCenterMenu or MENU_COALITION:New( self.CommandCenterCoalition, "Command Center (" .. self:GetName() .. ")" )
|
|
||||||
|
|
||||||
local MenuTime = timer.getTime()
|
local MenuTime = timer.getTime()
|
||||||
for MissionID, Mission in pairs( self:GetMissions() or {} ) do
|
for MissionID, Mission in pairs( self:GetMissions() or {} ) do
|
||||||
@@ -314,7 +420,7 @@ function COMMANDCENTER:SetMenu()
|
|||||||
end
|
end
|
||||||
|
|
||||||
for MissionID, Mission in pairs( self:GetMissions() or {} ) do
|
for MissionID, Mission in pairs( self:GetMissions() or {} ) do
|
||||||
local Mission = Mission -- Tasking.Mission#MISSION
|
Mission = Mission -- Tasking.Mission#MISSION
|
||||||
Mission:RemoveMenu( MenuTime )
|
Mission:RemoveMenu( MenuTime )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -322,14 +428,160 @@ end
|
|||||||
|
|
||||||
--- Gets the commandcenter menu structure governed by the HQ command center.
|
--- Gets the commandcenter menu structure governed by the HQ command center.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @param Wrapper.Group#Group TaskGroup Task Group.
|
||||||
-- @return Core.Menu#MENU_COALITION
|
-- @return Core.Menu#MENU_COALITION
|
||||||
function COMMANDCENTER:GetMenu()
|
function COMMANDCENTER:GetMenu( TaskGroup )
|
||||||
return self.CommandCenterMenu
|
|
||||||
|
local MenuTime = timer.getTime()
|
||||||
|
|
||||||
|
self.CommandCenterMenus = self.CommandCenterMenus or {}
|
||||||
|
local CommandCenterMenu
|
||||||
|
|
||||||
|
local CommandCenterText = self:GetText()
|
||||||
|
CommandCenterMenu = MENU_GROUP:New( TaskGroup, CommandCenterText ):SetTime(MenuTime)
|
||||||
|
self.CommandCenterMenus[TaskGroup] = CommandCenterMenu
|
||||||
|
|
||||||
|
if self.AutoAssignTasks == false then
|
||||||
|
local AssignTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Assign Task", CommandCenterMenu, self.AssignRandomTask, self, TaskGroup ):SetTime(MenuTime):SetTag("AutoTask")
|
||||||
|
end
|
||||||
|
CommandCenterMenu:Remove( MenuTime, "AutoTask" )
|
||||||
|
|
||||||
|
return self.CommandCenterMenus[TaskGroup]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Checks of the COMMANDCENTER has a GROUP.
|
|
||||||
|
--- Assigns a random task to a TaskGroup.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
-- @param Wrapper.Group#GROUP
|
-- @return #COMMANDCENTER
|
||||||
|
function COMMANDCENTER:AssignRandomTask( TaskGroup )
|
||||||
|
|
||||||
|
local Tasks = {}
|
||||||
|
|
||||||
|
for MissionID, Mission in pairs( self:GetMissions() ) do
|
||||||
|
local Mission = Mission -- Tasking.Mission#MISSION
|
||||||
|
local MissionTasks = Mission:GetGroupTasks( TaskGroup )
|
||||||
|
for MissionTaskName, MissionTask in pairs( MissionTasks or {} ) do
|
||||||
|
Tasks[#Tasks+1] = MissionTask
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local Task = Tasks[ math.random( 1, #Tasks ) ] -- Tasking.Task#TASK
|
||||||
|
|
||||||
|
Task:SetAssignMethod( ACT_ASSIGN_MENU_ACCEPT:New( Task.TaskBriefing ) )
|
||||||
|
|
||||||
|
Task:AssignToGroup( TaskGroup )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Sets the menu of the command center.
|
||||||
|
-- This command is called within the :New() method.
|
||||||
|
-- @param #COMMANDCENTER self
|
||||||
|
function COMMANDCENTER:SetCommandMenu()
|
||||||
|
|
||||||
|
local MenuTime = timer.getTime()
|
||||||
|
|
||||||
|
if self.CommandCenterPositionable and self.CommandCenterPositionable:IsInstanceOf(GROUP) then
|
||||||
|
local CommandCenterText = self:GetText()
|
||||||
|
local CommandCenterMenu = MENU_GROUP:New( self.CommandCenterPositionable, CommandCenterText ):SetTime(MenuTime)
|
||||||
|
|
||||||
|
if self.AutoAssignTasks == false then
|
||||||
|
local AutoAssignTaskMenu = MENU_GROUP_COMMAND:New( self.CommandCenterPositionable, "Assign Task On", CommandCenterMenu, self.SetAutoAssignTasks, self, true ):SetTime(MenuTime):SetTag("AutoTask")
|
||||||
|
else
|
||||||
|
local AutoAssignTaskMenu = MENU_GROUP_COMMAND:New( self.CommandCenterPositionable, "Assign Task Off", CommandCenterMenu, self.SetAutoAssignTasks, self, false ):SetTime(MenuTime):SetTag("AutoTask")
|
||||||
|
end
|
||||||
|
CommandCenterMenu:Remove( MenuTime, "AutoTask" )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Automatically assigns tasks to all TaskGroups.
|
||||||
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @param #boolean AutoAssign true for ON and false or nil for OFF.
|
||||||
|
function COMMANDCENTER:SetAutoAssignTasks( AutoAssign )
|
||||||
|
|
||||||
|
self.AutoAssignTasks = AutoAssign or false
|
||||||
|
|
||||||
|
local GroupSet = self:AddGroups()
|
||||||
|
|
||||||
|
for GroupID, TaskGroup in pairs( GroupSet:GetSet() ) do
|
||||||
|
local TaskGroup = TaskGroup -- Wrapper.Group#GROUP
|
||||||
|
self:GetMenu( TaskGroup )
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.AutoAssignTasks == true then
|
||||||
|
self:ScheduleRepeat( 10, 30, 0, nil, self.AssignTasks, self )
|
||||||
|
else
|
||||||
|
self:ScheduleStop( self.AssignTasks )
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetCommandCenterMenu()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Automatically assigns tasks to all TaskGroups.
|
||||||
|
-- @param #COMMANDCENTER self
|
||||||
|
function COMMANDCENTER:AssignTasks()
|
||||||
|
|
||||||
|
local GroupSet = self:AddGroups()
|
||||||
|
|
||||||
|
for GroupID, TaskGroup in pairs( GroupSet:GetSet() ) do
|
||||||
|
local TaskGroup = TaskGroup -- Wrapper.Group#GROUP
|
||||||
|
|
||||||
|
if self:IsGroupAssigned( TaskGroup ) then
|
||||||
|
else
|
||||||
|
-- Only groups with planes or helicopters will receive automatic tasks.
|
||||||
|
-- TODO Workaround DCS-BUG-3 - https://github.com/FlightControl-Master/MOOSE/issues/696
|
||||||
|
if TaskGroup:IsAir() then
|
||||||
|
self:AssignRandomTask( TaskGroup )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get all the Groups active within the command center.
|
||||||
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @return Core.Set#SET_GROUP The set of groups active within the command center.
|
||||||
|
function COMMANDCENTER:AddGroups()
|
||||||
|
|
||||||
|
local GroupSet = SET_GROUP:New()
|
||||||
|
|
||||||
|
for MissionID, Mission in pairs( self.Missions ) do
|
||||||
|
local Mission = Mission -- Tasking.Mission#MISSION
|
||||||
|
GroupSet = Mission:AddGroups( GroupSet )
|
||||||
|
end
|
||||||
|
|
||||||
|
return GroupSet
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Checks of the TaskGroup has a Task.
|
||||||
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @return #boolean When true, the TaskGroup has a Task, otherwise the returned value will be false.
|
||||||
|
function COMMANDCENTER:IsGroupAssigned( TaskGroup )
|
||||||
|
|
||||||
|
local Assigned = false
|
||||||
|
|
||||||
|
for MissionID, Mission in pairs( self.Missions ) do
|
||||||
|
local Mission = Mission -- Tasking.Mission#MISSION
|
||||||
|
if Mission:IsGroupAssigned( TaskGroup ) then
|
||||||
|
Assigned = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Assigned
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Checks of the command center has the given MissionGroup.
|
||||||
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @param Wrapper.Group#GROUP MissionGroup The group active within one of the missions governed by the command center.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
function COMMANDCENTER:HasGroup( MissionGroup )
|
function COMMANDCENTER:HasGroup( MissionGroup )
|
||||||
|
|
||||||
@@ -346,84 +598,90 @@ function COMMANDCENTER:HasGroup( MissionGroup )
|
|||||||
return Has
|
return Has
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Send a CC message to the coalition of the CC.
|
--- Let the command center send a Message to all players.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @param #string Message The message text.
|
||||||
function COMMANDCENTER:MessageToAll( Message )
|
function COMMANDCENTER:MessageToAll( Message )
|
||||||
|
|
||||||
self:GetPositionable():MessageToAll( Message, 20, self:GetName() )
|
self:GetPositionable():MessageToAll( Message, 20, self:GetName() )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Send a CC message to a GROUP.
|
--- Let the command center send a message to the MessageGroup.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
-- @param #string Message
|
-- @param #string Message The message text.
|
||||||
-- @param Wrapper.Group#GROUP TaskGroup
|
-- @param Wrapper.Group#GROUP MessageGroup The group to receive the message.
|
||||||
function COMMANDCENTER:MessageToGroup( Message, TaskGroup )
|
function COMMANDCENTER:MessageToGroup( Message, MessageGroup )
|
||||||
|
|
||||||
self:GetPositionable():MessageToGroup( Message, 15, TaskGroup, self:GetName() )
|
self:GetPositionable():MessageToGroup( Message, 15, MessageGroup, self:GetShortText() )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Send a CC message of a specified type to a GROUP.
|
--- Let the command center send a message to the MessageGroup.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
-- @param #string Message
|
-- @param #string Message The message text.
|
||||||
-- @param Wrapper.Group#GROUP TaskGroup
|
-- @param Wrapper.Group#GROUP MessageGroup The group to receive the message.
|
||||||
-- @param Core.Message#MESSAGE.MessageType MessageType The type of the message, resulting in automatic time duration and prefix of the message.
|
-- @param Core.Message#MESSAGE.MessageType MessageType The type of the message, resulting in automatic time duration and prefix of the message.
|
||||||
function COMMANDCENTER:MessageTypeToGroup( Message, TaskGroup, MessageType )
|
function COMMANDCENTER:MessageTypeToGroup( Message, MessageGroup, MessageType )
|
||||||
|
|
||||||
self:GetPositionable():MessageTypeToGroup( Message, MessageType, TaskGroup, self:GetName() )
|
self:GetPositionable():MessageTypeToGroup( Message, MessageType, MessageGroup, self:GetShortText() )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Send a CC message to the coalition of the CC.
|
--- Let the command center send a message to the coalition of the command center.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @param #string Message The message text.
|
||||||
function COMMANDCENTER:MessageToCoalition( Message )
|
function COMMANDCENTER:MessageToCoalition( Message )
|
||||||
|
|
||||||
local CCCoalition = self:GetPositionable():GetCoalition()
|
local CCCoalition = self:GetPositionable():GetCoalition()
|
||||||
--TODO: Fix coalition bug!
|
--TODO: Fix coalition bug!
|
||||||
|
|
||||||
self:GetPositionable():MessageToCoalition( Message, 15, CCCoalition )
|
self:GetPositionable():MessageToCoalition( Message, 15, CCCoalition, self:GetShortText() )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Send a CC message of a specified type to the coalition of the CC.
|
--- Let the command center send a message of a specified type to the coalition of the command center.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
-- @param #string Message The message.
|
-- @param #string Message The message text.
|
||||||
-- @param Core.Message#MESSAGE.MessageType MessageType The type of the message, resulting in automatic time duration and prefix of the message.
|
-- @param Core.Message#MESSAGE.MessageType MessageType The type of the message, resulting in automatic time duration and prefix of the message.
|
||||||
function COMMANDCENTER:MessageTypeToCoalition( Message, MessageType )
|
function COMMANDCENTER:MessageTypeToCoalition( Message, MessageType )
|
||||||
|
|
||||||
local CCCoalition = self:GetPositionable():GetCoalition()
|
local CCCoalition = self:GetPositionable():GetCoalition()
|
||||||
--TODO: Fix coalition bug!
|
--TODO: Fix coalition bug!
|
||||||
|
|
||||||
self:GetPositionable():MessageTypeToCoalition( Message, MessageType, CCCoalition )
|
self:GetPositionable():MessageTypeToCoalition( Message, MessageType, CCCoalition, self:GetShortText() )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Report the status of all MISSIONs to a GROUP.
|
--- Let the command center send a report of the status of all missions to a group.
|
||||||
-- Each Mission is listed, with an indication how many Tasks are still to be completed.
|
-- Each Mission is listed, with an indication how many Tasks are still to be completed.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
function COMMANDCENTER:ReportMissionsStatus( ReportGroup )
|
-- @param Wrapper.Group#GROUP ReportGroup The group to receive the report.
|
||||||
self:E( ReportGroup )
|
function COMMANDCENTER:ReportSummary( ReportGroup )
|
||||||
|
self:F( ReportGroup )
|
||||||
|
|
||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
|
|
||||||
Report:Add( "Status report of all missions." )
|
-- List the name of the mission.
|
||||||
|
local Name = self:GetName()
|
||||||
|
Report:Add( string.format( '%s - Report Summary Missions', Name ) )
|
||||||
|
|
||||||
for MissionID, Mission in pairs( self.Missions ) do
|
for MissionID, Mission in pairs( self.Missions ) do
|
||||||
local Mission = Mission -- Tasking.Mission#MISSION
|
local Mission = Mission -- Tasking.Mission#MISSION
|
||||||
Report:Add( " - " .. Mission:ReportStatus() )
|
Report:Add( " - " .. Mission:ReportSummary( ReportGroup ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
self:MessageToGroup( Report:Text(), ReportGroup )
|
self:MessageToGroup( Report:Text(), ReportGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Report the players of all MISSIONs to a GROUP.
|
--- Let the command center send a report of the players of all missions to a group.
|
||||||
-- Each Mission is listed, with an indication how many Tasks are still to be completed.
|
-- Each Mission is listed, with an indication how many Tasks are still to be completed.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @param Wrapper.Group#GROUP ReportGroup The group to receive the report.
|
||||||
function COMMANDCENTER:ReportMissionsPlayers( ReportGroup )
|
function COMMANDCENTER:ReportMissionsPlayers( ReportGroup )
|
||||||
self:E( ReportGroup )
|
self:F( ReportGroup )
|
||||||
|
|
||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
|
|
||||||
@@ -437,11 +695,13 @@ function COMMANDCENTER:ReportMissionsPlayers( ReportGroup )
|
|||||||
self:MessageToGroup( Report:Text(), ReportGroup )
|
self:MessageToGroup( Report:Text(), ReportGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Report the status of a Task to a Group.
|
--- Let the command center send a report of the status of a task to a group.
|
||||||
-- Report the details of a Mission, listing the Mission, and all the Task details.
|
-- Report the details of a Mission, listing the Mission, and all the Task details.
|
||||||
-- @param #COMMANDCENTER self
|
-- @param #COMMANDCENTER self
|
||||||
|
-- @param Wrapper.Group#GROUP ReportGroup The group to receive the report.
|
||||||
|
-- @param Tasking.Task#TASK Task The task to be reported.
|
||||||
function COMMANDCENTER:ReportDetails( ReportGroup, Task )
|
function COMMANDCENTER:ReportDetails( ReportGroup, Task )
|
||||||
self:E( ReportGroup )
|
self:F( ReportGroup )
|
||||||
|
|
||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +1,36 @@
|
|||||||
--- This module contains the DETECTION_MANAGER class and derived classes.
|
--- **Tasking** - This module contains the DETECTION_MANAGER class and derived classes.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 1) @{DetectionManager#DETECTION_MANAGER} class, extends @{Fsm#FSM}
|
-- The @{#DETECTION_MANAGER} class defines the core functions to report detected objects to groups.
|
||||||
-- ====================================================================
|
|
||||||
-- The @{DetectionManager#DETECTION_MANAGER} class defines the core functions to report detected objects to groups.
|
|
||||||
-- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour.
|
-- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour.
|
||||||
--
|
--
|
||||||
-- 1.1) DETECTION_MANAGER constructor:
|
-- 1.1) DETECTION_MANAGER constructor:
|
||||||
-- -----------------------------------
|
-- -----------------------------------
|
||||||
-- * @{DetectionManager#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance.
|
-- * @{#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance.
|
||||||
--
|
--
|
||||||
-- 1.2) DETECTION_MANAGER reporting:
|
-- 1.2) DETECTION_MANAGER reporting:
|
||||||
-- ---------------------------------
|
-- ---------------------------------
|
||||||
-- Derived DETECTION_MANAGER classes will reports detected units using the method @{DetectionManager#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour.
|
-- Derived DETECTION_MANAGER classes will reports detected units using the method @{#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour.
|
||||||
--
|
--
|
||||||
-- The time interval in seconds of the reporting can be changed using the methods @{DetectionManager#DETECTION_MANAGER.SetRefreshTimeInterval}().
|
-- The time interval in seconds of the reporting can be changed using the methods @{#DETECTION_MANAGER.SetRefreshTimeInterval}().
|
||||||
-- To control how long a reporting message is displayed, use @{DetectionManager#DETECTION_MANAGER.SetReportDisplayTime}().
|
-- To control how long a reporting message is displayed, use @{#DETECTION_MANAGER.SetReportDisplayTime}().
|
||||||
-- Derived classes need to implement the method @{DetectionManager#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report.
|
-- Derived classes need to implement the method @{#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report.
|
||||||
--
|
--
|
||||||
-- Reporting can be started and stopped using the methods @{DetectionManager#DETECTION_MANAGER.StartReporting}() and @{DetectionManager#DETECTION_MANAGER.StopReporting}() respectively.
|
-- Reporting can be started and stopped using the methods @{#DETECTION_MANAGER.StartReporting}() and @{#DETECTION_MANAGER.StopReporting}() respectively.
|
||||||
-- If an ad-hoc report is requested, use the method @{DetectionManager#DETECTION_MANAGER#ReportNow}().
|
-- If an ad-hoc report is requested, use the method @{#DETECTION_MANAGER#ReportNow}().
|
||||||
--
|
--
|
||||||
-- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds.
|
-- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 2) @{DetectionManager#DETECTION_REPORTING} class, extends @{DetectionManager#DETECTION_MANAGER}
|
-- 2) @{#DETECTION_REPORTING} class, extends @{#DETECTION_MANAGER}
|
||||||
-- =========================================================================================
|
-- ===
|
||||||
-- The @{DetectionManager#DETECTION_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{DetectionManager#DETECTION_MANAGER} class.
|
-- The @{#DETECTION_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{Tasking.DetectionManager#DETECTION_MANAGER} class.
|
||||||
--
|
--
|
||||||
-- 2.1) DETECTION_REPORTING constructor:
|
-- 2.1) DETECTION_REPORTING constructor:
|
||||||
-- -------------------------------
|
-- -------------------------------
|
||||||
-- The @{DetectionManager#DETECTION_REPORTING.New}() method creates a new DETECTION_REPORTING instance.
|
-- The @{#DETECTION_REPORTING.New}() method creates a new DETECTION_REPORTING instance.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -40,15 +38,18 @@
|
|||||||
-- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing
|
-- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing
|
||||||
-- ### Author: FlightControl - Framework Design & Programming
|
-- ### Author: FlightControl - Framework Design & Programming
|
||||||
--
|
--
|
||||||
-- @module DetectionManager
|
-- @module Tasking.DetectionManager
|
||||||
|
-- @image Task_Detection_Manager.JPG
|
||||||
|
|
||||||
do -- DETECTION MANAGER
|
do -- DETECTION MANAGER
|
||||||
|
|
||||||
--- DETECTION_MANAGER class.
|
--- @type DETECTION_MANAGER
|
||||||
-- @type DETECTION_MANAGER
|
-- @field Core.Set#SET_GROUP SetGroup The groups to which the FAC will report to.
|
||||||
-- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to.
|
|
||||||
-- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
|
-- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
--- DETECTION_MANAGER class.
|
||||||
|
-- @field #DETECTION_MANAGER
|
||||||
DETECTION_MANAGER = {
|
DETECTION_MANAGER = {
|
||||||
ClassName = "DETECTION_MANAGER",
|
ClassName = "DETECTION_MANAGER",
|
||||||
SetGroup = nil,
|
SetGroup = nil,
|
||||||
@@ -57,7 +58,7 @@ do -- DETECTION MANAGER
|
|||||||
|
|
||||||
--- FAC constructor.
|
--- FAC constructor.
|
||||||
-- @param #DETECTION_MANAGER self
|
-- @param #DETECTION_MANAGER self
|
||||||
-- @param Set#SET_GROUP SetGroup
|
-- @param Core.Set#SET_GROUP SetGroup
|
||||||
-- @param Functional.Detection#DETECTION_BASE Detection
|
-- @param Functional.Detection#DETECTION_BASE Detection
|
||||||
-- @return #DETECTION_MANAGER self
|
-- @return #DETECTION_MANAGER self
|
||||||
function DETECTION_MANAGER:New( SetGroup, Detection )
|
function DETECTION_MANAGER:New( SetGroup, Detection )
|
||||||
@@ -122,6 +123,48 @@ do -- DETECTION MANAGER
|
|||||||
-- @function [parent=#DETECTION_MANAGER] __Stop
|
-- @function [parent=#DETECTION_MANAGER] __Stop
|
||||||
-- @param #DETECTION_MANAGER self
|
-- @param #DETECTION_MANAGER self
|
||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
|
|
||||||
|
self:AddTransition( "Started", "Success", "Started" )
|
||||||
|
|
||||||
|
--- Success Handler OnAfter for DETECTION_MANAGER
|
||||||
|
-- @function [parent=#DETECTION_MANAGER] OnAfterSuccess
|
||||||
|
-- @param #DETECTION_MANAGER self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Tasking.Task#TASK Task
|
||||||
|
|
||||||
|
|
||||||
|
self:AddTransition( "Started", "Failed", "Started" )
|
||||||
|
|
||||||
|
--- Failed Handler OnAfter for DETECTION_MANAGER
|
||||||
|
-- @function [parent=#DETECTION_MANAGER] OnAfterFailed
|
||||||
|
-- @param #DETECTION_MANAGER self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Tasking.Task#TASK Task
|
||||||
|
|
||||||
|
|
||||||
|
self:AddTransition( "Started", "Aborted", "Started" )
|
||||||
|
|
||||||
|
--- Aborted Handler OnAfter for DETECTION_MANAGER
|
||||||
|
-- @function [parent=#DETECTION_MANAGER] OnAfterAborted
|
||||||
|
-- @param #DETECTION_MANAGER self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Tasking.Task#TASK Task
|
||||||
|
|
||||||
|
self:AddTransition( "Started", "Cancelled", "Started" )
|
||||||
|
|
||||||
|
--- Cancelled Handler OnAfter for DETECTION_MANAGER
|
||||||
|
-- @function [parent=#DETECTION_MANAGER] OnAfterCancelled
|
||||||
|
-- @param #DETECTION_MANAGER self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Tasking.Task#TASK Task
|
||||||
|
|
||||||
|
|
||||||
self:AddTransition( "Started", "Report", "Started" )
|
self:AddTransition( "Started", "Report", "Started" )
|
||||||
@@ -129,7 +172,6 @@ do -- DETECTION MANAGER
|
|||||||
self:SetRefreshTimeInterval( 30 )
|
self:SetRefreshTimeInterval( 30 )
|
||||||
self:SetReportDisplayTime( 25 )
|
self:SetReportDisplayTime( 25 )
|
||||||
|
|
||||||
self:E( { Detection = Detection } )
|
|
||||||
Detection:__Start( 3 )
|
Detection:__Start( 3 )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -141,8 +183,6 @@ do -- DETECTION MANAGER
|
|||||||
|
|
||||||
function DETECTION_MANAGER:onafterReport( From, Event, To )
|
function DETECTION_MANAGER:onafterReport( From, Event, To )
|
||||||
|
|
||||||
self:E( "onafterReport" )
|
|
||||||
|
|
||||||
self:__Report( -self._RefreshTimeInterval )
|
self:__Report( -self._RefreshTimeInterval )
|
||||||
|
|
||||||
self:ProcessDetected( self.Detection )
|
self:ProcessDetected( self.Detection )
|
||||||
@@ -178,7 +218,7 @@ do -- DETECTION MANAGER
|
|||||||
return self._ReportDisplayTime
|
return self._ReportDisplayTime
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Reports the detected items to the @{Set#SET_GROUP}.
|
--- Reports the detected items to the @{Core.Set#SET_GROUP}.
|
||||||
-- @param #DETECTION_MANAGER self
|
-- @param #DETECTION_MANAGER self
|
||||||
-- @param Functional.Detection#DETECTION_BASE Detection
|
-- @param Functional.Detection#DETECTION_BASE Detection
|
||||||
-- @return #DETECTION_MANAGER self
|
-- @return #DETECTION_MANAGER self
|
||||||
@@ -194,7 +234,7 @@ do -- DETECTION_REPORTING
|
|||||||
|
|
||||||
--- DETECTION_REPORTING class.
|
--- DETECTION_REPORTING class.
|
||||||
-- @type DETECTION_REPORTING
|
-- @type DETECTION_REPORTING
|
||||||
-- @field Set#SET_GROUP SetGroup The groups to which the FAC will report to.
|
-- @field Core.Set#SET_GROUP SetGroup The groups to which the FAC will report to.
|
||||||
-- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
|
-- @field Functional.Detection#DETECTION_BASE Detection The DETECTION_BASE object that is used to report the detected objects.
|
||||||
-- @extends #DETECTION_MANAGER
|
-- @extends #DETECTION_MANAGER
|
||||||
DETECTION_REPORTING = {
|
DETECTION_REPORTING = {
|
||||||
@@ -204,7 +244,7 @@ do -- DETECTION_REPORTING
|
|||||||
|
|
||||||
--- DETECTION_REPORTING constructor.
|
--- DETECTION_REPORTING constructor.
|
||||||
-- @param #DETECTION_REPORTING self
|
-- @param #DETECTION_REPORTING self
|
||||||
-- @param Set#SET_GROUP SetGroup
|
-- @param Core.Set#SET_GROUP SetGroup
|
||||||
-- @param Functional.Detection#DETECTION_AREAS Detection
|
-- @param Functional.Detection#DETECTION_AREAS Detection
|
||||||
-- @return #DETECTION_REPORTING self
|
-- @return #DETECTION_REPORTING self
|
||||||
function DETECTION_REPORTING:New( SetGroup, Detection )
|
function DETECTION_REPORTING:New( SetGroup, Detection )
|
||||||
@@ -218,7 +258,7 @@ do -- DETECTION_REPORTING
|
|||||||
|
|
||||||
--- Creates a string of the detected items in a @{Detection}.
|
--- Creates a string of the detected items in a @{Detection}.
|
||||||
-- @param #DETECTION_MANAGER self
|
-- @param #DETECTION_MANAGER self
|
||||||
-- @param Set#SET_UNIT DetectedSet The detected Set created by the @{Detection#DETECTION_BASE} object.
|
-- @param Core.Set#SET_UNIT DetectedSet The detected Set created by the @{Functional.Detection#DETECTION_BASE} object.
|
||||||
-- @return #DETECTION_MANAGER self
|
-- @return #DETECTION_MANAGER self
|
||||||
function DETECTION_REPORTING:GetDetectedItemsText( DetectedSet )
|
function DETECTION_REPORTING:GetDetectedItemsText( DetectedSet )
|
||||||
self:F2()
|
self:F2()
|
||||||
@@ -248,15 +288,14 @@ do -- DETECTION_REPORTING
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Reports the detected items to the @{Set#SET_GROUP}.
|
--- Reports the detected items to the @{Core.Set#SET_GROUP}.
|
||||||
-- @param #DETECTION_REPORTING self
|
-- @param #DETECTION_REPORTING self
|
||||||
-- @param Wrapper.Group#GROUP Group The @{Group} object to where the report needs to go.
|
-- @param Wrapper.Group#GROUP Group The @{Wrapper.Group} object to where the report needs to go.
|
||||||
-- @param Functional.Detection#DETECTION_AREAS Detection The detection created by the @{Detection#DETECTION_BASE} object.
|
-- @param Functional.Detection#DETECTION_AREAS Detection The detection created by the @{Functional.Detection#DETECTION_BASE} object.
|
||||||
-- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop.
|
-- @return #boolean Return true if you want the reporting to continue... false will cancel the reporting loop.
|
||||||
function DETECTION_REPORTING:ProcessDetected( Group, Detection )
|
function DETECTION_REPORTING:ProcessDetected( Group, Detection )
|
||||||
self:F2( Group )
|
self:F2( Group )
|
||||||
|
|
||||||
self:E( Group )
|
|
||||||
local DetectedMsg = {}
|
local DetectedMsg = {}
|
||||||
for DetectedAreaID, DetectedAreaData in pairs( Detection:GetDetectedAreas() ) do
|
for DetectedAreaID, DetectedAreaData in pairs( Detection:GetDetectedAreas() ) do
|
||||||
local DetectedArea = DetectedAreaData -- Functional.Detection#DETECTION_AREAS.DetectedArea
|
local DetectedArea = DetectedAreaData -- Functional.Detection#DETECTION_AREAS.DetectedArea
|
||||||
|
|||||||
@@ -1,21 +1,124 @@
|
|||||||
--- **Tasking** -- A MISSION is the main owner of a Mission orchestration within MOOSE.
|
--- **Tasking** -- A mission models a goal to be achieved through the execution and completion of tasks by human players.
|
||||||
--
|
--
|
||||||
-- ====
|
-- **Features:**
|
||||||
--
|
--
|
||||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
-- * A mission has a goal to be achieved, through the execution and completion of tasks of different categories by human players.
|
||||||
|
-- * A mission manages these tasks.
|
||||||
|
-- * A mission has a state, that indicates the fase of the mission.
|
||||||
|
-- * A mission has a menu structure, that facilitates mission reports and tasking menus.
|
||||||
|
-- * A mission can assign a task to a player.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
--
|
--
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Mission
|
-- @module Tasking.Mission
|
||||||
|
-- @image Task_Mission.JPG
|
||||||
|
|
||||||
--- The MISSION class
|
--- @type MISSION
|
||||||
-- @type MISSION
|
|
||||||
-- @field #MISSION.Clients _Clients
|
-- @field #MISSION.Clients _Clients
|
||||||
-- @field Core.Menu#MENU_COALITION MissionMenu
|
-- @field Core.Menu#MENU_COALITION MissionMenu
|
||||||
-- @field #string MissionBriefing
|
-- @field #string MissionBriefing
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
--- Models goals to be achieved and can contain multiple tasks to be executed to achieve the goals.
|
||||||
|
--
|
||||||
|
-- A mission contains multiple tasks and can be of different task types.
|
||||||
|
-- These tasks need to be assigned to human players to be executed.
|
||||||
|
--
|
||||||
|
-- A mission can have multiple states, which will evolve as the mission progresses during the DCS simulation.
|
||||||
|
--
|
||||||
|
-- - **IDLE**: The mission is defined, but not started yet. No task has yet been joined by a human player as part of the mission.
|
||||||
|
-- - **ENGAGED**: The mission is ongoing, players have joined tasks to be executed.
|
||||||
|
-- - **COMPLETED**: The goals of the mission has been successfully reached, and the mission is flagged as completed.
|
||||||
|
-- - **FAILED**: For a certain reason, the goals of the mission has not been reached, and the mission is flagged as failed.
|
||||||
|
-- - **HOLD**: The mission was enaged, but for some reason it has been put on hold.
|
||||||
|
--
|
||||||
|
-- Note that a mission goals need to be checked by a goal check trigger: @{#MISSION.OnBeforeMissionGoals}(), which may return false if the goal has not been reached.
|
||||||
|
-- This goal is checked automatically by the mission object every x seconds.
|
||||||
|
--
|
||||||
|
-- - @{#MISSION.Start}() or @{#MISSION.__Start}() will start the mission, and will bring it from **IDLE** state to **ENGAGED** state.
|
||||||
|
-- - @{#MISSION.Stop}() or @{#MISSION.__Stop}() will stop the mission, and will bring it from **ENGAGED** state to **IDLE** state.
|
||||||
|
-- - @{#MISSION.Complete}() or @{#MISSION.__Complete}() will complete the mission, and will bring the mission state to **COMPLETED**.
|
||||||
|
-- Note that the mission must be in state **ENGAGED** to be able to complete the mission.
|
||||||
|
-- - @{#MISSION.Fail}() or @{#MISSION.__Fail}() will fail the mission, and will bring the mission state to **FAILED**.
|
||||||
|
-- Note that the mission must be in state **ENGAGED** to be able to fail the mission.
|
||||||
|
-- - @{#MISSION.Hold}() or @{#MISSION.__Hold}() will hold the mission, and will bring the mission state to **HOLD**.
|
||||||
|
-- Note that the mission must be in state **ENGAGED** to be able to hold the mission.
|
||||||
|
-- Re-engage the mission using the engage trigger.
|
||||||
|
--
|
||||||
|
-- The following sections provide an overview of the most important methods that can be used as part of a mission object.
|
||||||
|
-- Note that the @{Tasking.CommandCenter} system is using most of these methods to manage the missions in its system.
|
||||||
|
--
|
||||||
|
-- ## 1. Create a mission object.
|
||||||
|
--
|
||||||
|
-- - @{#MISSION.New}(): Creates a new MISSION object.
|
||||||
|
--
|
||||||
|
-- ## 2. Mission task management.
|
||||||
|
--
|
||||||
|
-- Missions maintain tasks, which can be added or removed, or enquired.
|
||||||
|
--
|
||||||
|
-- - @{#MISSION.AddTask}(): Adds a task to the mission.
|
||||||
|
-- - @{#MISSION.RemoveTask}(): Removes a task from the mission.
|
||||||
|
--
|
||||||
|
-- ## 3. Mission detailed methods.
|
||||||
|
--
|
||||||
|
-- Various methods are added to manage missions.
|
||||||
|
--
|
||||||
|
-- ### 3.1. Naming and description.
|
||||||
|
--
|
||||||
|
-- There are several methods that can be used to retrieve the properties of a mission:
|
||||||
|
--
|
||||||
|
-- - Use the method @{#MISSION.GetName}() to retrieve the name of the mission.
|
||||||
|
-- This is the name given as part of the @{#MISSION.New}() constructor.
|
||||||
|
--
|
||||||
|
-- A textual description can be retrieved that provides the mission name to be used within message communication:
|
||||||
|
--
|
||||||
|
-- - @{#MISSION.GetShortText}() returns the mission name as `Mission "MissionName"`.
|
||||||
|
-- - @{#MISSION.GetText}() returns the mission name as `Mission "MissionName (MissionPriority)"`. A longer version including the priority text of the mission.
|
||||||
|
--
|
||||||
|
-- ### 3.2. Get task information.
|
||||||
|
--
|
||||||
|
-- - @{#MISSION.GetTasks}(): Retrieves a list of the tasks controlled by the mission.
|
||||||
|
-- - @{#MISSION.GetTask}(): Retrieves a specific task controlled by the mission.
|
||||||
|
-- - @{#MISSION.GetTasksRemaining}(): Retrieve a list of the tasks that aren't finished or failed, and are governed by the mission.
|
||||||
|
-- - @{#MISSION.GetGroupTasks}(): Retrieve a list of the tasks that can be asigned to a @{Wrapper.Group}.
|
||||||
|
-- - @{#MISSION.GetTaskTypes}(): Retrieve a list of the different task types governed by the mission.
|
||||||
|
--
|
||||||
|
-- ### 3.3. Get the command center.
|
||||||
|
--
|
||||||
|
-- - @{#MISSION.GetCommandCenter}(): Retrieves the @{Tasking.CommandCenter} governing the mission.
|
||||||
|
--
|
||||||
|
-- ### 3.4. Get the groups active in the mission as a @{Core.Set}.
|
||||||
|
--
|
||||||
|
-- - @{#MISSION.GetGroups}(): Retrieves a @{Core.Set#SET_GROUP} of all the groups active in the mission (as part of the tasks).
|
||||||
|
--
|
||||||
|
-- ### 3.5. Get the names of the players.
|
||||||
|
--
|
||||||
|
-- - @{#MISSION.GetPlayerNames}(): Retrieves the list of the players that were active within th mission..
|
||||||
|
--
|
||||||
|
-- ## 4. Menu management.
|
||||||
|
--
|
||||||
|
-- A mission object is able to manage its own menu structure. Use the @{#MISSION.GetMenu}() and @{#MISSION.SetMenu}() to manage the underlying submenu
|
||||||
|
-- structure managing the tasks of the mission.
|
||||||
|
--
|
||||||
|
-- ## 5. Reporting management.
|
||||||
|
--
|
||||||
|
-- Several reports can be generated for a mission, and will return a text string that can be used to display using the @{Core.Message} system.
|
||||||
|
--
|
||||||
|
-- - @{#MISSION.ReportBriefing}(): Generates the briefing for the mission.
|
||||||
|
-- - @{#MISSION.ReportOverview}(): Generates an overview of the tasks and status of the mission.
|
||||||
|
-- - @{#MISSION.ReportDetails}(): Generates a detailed report of the tasks of the mission.
|
||||||
|
-- - @{#MISSION.ReportSummary}(): Generates a summary report of the tasks of the mission.
|
||||||
|
-- - @{#MISSION.ReportPlayersPerTask}(): Generates a report showing the active players per task.
|
||||||
|
-- - @{#MISSION.ReportPlayersProgress}(): Generates a report showing the task progress per player.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #MISSION
|
||||||
MISSION = {
|
MISSION = {
|
||||||
ClassName = "MISSION",
|
ClassName = "MISSION",
|
||||||
Name = "",
|
Name = "",
|
||||||
@@ -26,10 +129,10 @@ MISSION = {
|
|||||||
--- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc.
|
--- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc.
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
-- @param Tasking.CommandCenter#COMMANDCENTER CommandCenter
|
-- @param Tasking.CommandCenter#COMMANDCENTER CommandCenter
|
||||||
-- @param #string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players.
|
-- @param #string MissionName Name of the mission. This name will be used to reference the status of each mission by the players.
|
||||||
-- @param #string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field.
|
-- @param #string MissionPriority String indicating the "priority" of the Mission. e.g. "Primary", "Secondary". It is free format and up to the Mission designer to choose. There are no rules behind this field.
|
||||||
-- @param #string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}.
|
-- @param #string MissionBriefing String indicating the mission briefing to be shown when a player joins a @{CLIENT}.
|
||||||
-- @param Dcs.DCSCoalitionWrapper.Object#coalition MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"...
|
-- @param DCS#coaliton.side MissionCoalition Side of the coalition, i.e. and enumerator @{#DCS.coalition.side} corresponding to RED, BLUE or NEUTRAL.
|
||||||
-- @return #MISSION self
|
-- @return #MISSION self
|
||||||
function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition )
|
function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition )
|
||||||
|
|
||||||
@@ -46,6 +149,7 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi
|
|||||||
self.MissionCoalition = MissionCoalition
|
self.MissionCoalition = MissionCoalition
|
||||||
|
|
||||||
self.Tasks = {}
|
self.Tasks = {}
|
||||||
|
self.TaskNumber = 0
|
||||||
self.PlayerNames = {} -- These are the players that achieved progress in the mission.
|
self.PlayerNames = {} -- These are the players that achieved progress in the mission.
|
||||||
|
|
||||||
self:SetStartState( "IDLE" )
|
self:SetStartState( "IDLE" )
|
||||||
@@ -264,6 +368,8 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- FSM function for a MISSION
|
--- FSM function for a MISSION
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
@@ -271,16 +377,33 @@ end
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
function MISSION:onenterCOMPLETED( From, Event, To )
|
function MISSION:onenterCOMPLETED( From, Event, To )
|
||||||
|
|
||||||
self:GetCommandCenter():MessageTypeToCoalition( self:GetName() .. " has been completed! Good job guys!", MESSAGE.Type.Information )
|
self:GetCommandCenter():MessageTypeToCoalition( self:GetText() .. " has been completed! Good job guys!", MESSAGE.Type.Information )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Gets the mission name.
|
--- Gets the mission name.
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
-- @return #MISSION self
|
-- @return #MISSION self
|
||||||
function MISSION:GetName()
|
function MISSION:GetName()
|
||||||
|
return self.Name
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Gets the mission text.
|
||||||
|
-- @param #MISSION self
|
||||||
|
-- @return #MISSION self
|
||||||
|
function MISSION:GetText()
|
||||||
return string.format( 'Mission "%s (%s)"', self.Name, self.MissionPriority )
|
return string.format( 'Mission "%s (%s)"', self.Name, self.MissionPriority )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Gets the short mission text.
|
||||||
|
-- @param #MISSION self
|
||||||
|
-- @return #MISSION self
|
||||||
|
function MISSION:GetShortText()
|
||||||
|
return string.format( 'Mission "%s"', self.Name )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Add a Unit to join the Mission.
|
--- Add a Unit to join the Mission.
|
||||||
-- For each Task within the Mission, the Unit is joined with the Task.
|
-- For each Task within the Mission, the Unit is joined with the Task.
|
||||||
-- If the Unit was not part of a Task in the Mission, false is returned.
|
-- If the Unit was not part of a Task in the Mission, false is returned.
|
||||||
@@ -290,7 +413,7 @@ end
|
|||||||
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
|
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
|
||||||
-- @return #boolean true if Unit is part of a Task in the Mission.
|
-- @return #boolean true if Unit is part of a Task in the Mission.
|
||||||
function MISSION:JoinUnit( PlayerUnit, PlayerGroup )
|
function MISSION:JoinUnit( PlayerUnit, PlayerGroup )
|
||||||
self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
|
self:I( { Mission = self:GetName(), PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
|
||||||
|
|
||||||
local PlayerUnitAdded = false
|
local PlayerUnitAdded = false
|
||||||
|
|
||||||
@@ -357,24 +480,30 @@ function MISSION:GetScoring()
|
|||||||
return self.Scoring
|
return self.Scoring
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the groups for which TASKS are given in the mission
|
--- Gets the groups for which TASKS are given in the mission
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
|
-- @param Core.Set#SET_GROUP GroupSet
|
||||||
-- @return Core.Set#SET_GROUP
|
-- @return Core.Set#SET_GROUP
|
||||||
function MISSION:GetGroups()
|
function MISSION:GetGroups()
|
||||||
|
|
||||||
local SetGroup = SET_GROUP:New()
|
return self:AddGroups()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Adds the groups for which TASKS are given in the mission
|
||||||
|
-- @param #MISSION self
|
||||||
|
-- @param Core.Set#SET_GROUP GroupSet
|
||||||
|
-- @return Core.Set#SET_GROUP
|
||||||
|
function MISSION:AddGroups( GroupSet )
|
||||||
|
|
||||||
|
GroupSet = GroupSet or SET_GROUP:New()
|
||||||
|
|
||||||
for TaskID, Task in pairs( self:GetTasks() ) do
|
for TaskID, Task in pairs( self:GetTasks() ) do
|
||||||
local Task = Task -- Tasking.Task#TASK
|
local Task = Task -- Tasking.Task#TASK
|
||||||
local GroupSet = Task:GetGroups()
|
GroupSet = Task:AddGroups( GroupSet )
|
||||||
GroupSet:ForEachGroup(
|
|
||||||
function( TaskGroup )
|
|
||||||
SetGroup:Add( TaskGroup, TaskGroup )
|
|
||||||
end
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return SetGroup
|
return GroupSet
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -385,9 +514,16 @@ end
|
|||||||
function MISSION:SetMenu( MenuTime )
|
function MISSION:SetMenu( MenuTime )
|
||||||
self:F( { self:GetName(), MenuTime } )
|
self:F( { self:GetName(), MenuTime } )
|
||||||
|
|
||||||
for _, TaskData in pairs( self:GetTasks() ) do
|
local MenuCount = {}
|
||||||
local Task = TaskData -- Tasking.Task#TASK
|
--for TaskID, Task in UTILS.spairs( self:GetTasks(), function( t, a, b ) return t[a]:ReportOrder( ReportGroup ) < t[b]:ReportOrder( ReportGroup ) end ) do
|
||||||
Task:SetMenu( MenuTime )
|
for TaskID, Task in pairs( self:GetTasks() ) do
|
||||||
|
local Task = Task -- Tasking.Task#TASK
|
||||||
|
local TaskType = Task:GetType()
|
||||||
|
MenuCount[TaskType] = MenuCount[TaskType] or 1
|
||||||
|
if MenuCount[TaskType] <= 10 then
|
||||||
|
Task:SetMenu( MenuTime )
|
||||||
|
MenuCount[TaskType] = MenuCount[TaskType] + 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -416,16 +552,16 @@ do -- Group Assignment
|
|||||||
local MissionGroupName = MissionGroup:GetName()
|
local MissionGroupName = MissionGroup:GetName()
|
||||||
|
|
||||||
if self.AssignedGroups[MissionGroupName] == MissionGroup then
|
if self.AssignedGroups[MissionGroupName] == MissionGroup then
|
||||||
self:T( { "Mission is assigned to:", MissionGroup:GetName() } )
|
self:T2( { "Mission is assigned to:", MissionGroup:GetName() } )
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T( { "Mission is not assigned to:", MissionGroup:GetName() } )
|
self:T2( { "Mission is not assigned to:", MissionGroup:GetName() } )
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set @{Group} assigned to the @{Mission}.
|
--- Set @{Wrapper.Group} assigned to the @{Mission}.
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
-- @param Wrapper.Group#GROUP MissionGroup
|
-- @param Wrapper.Group#GROUP MissionGroup
|
||||||
-- @return #MISSION
|
-- @return #MISSION
|
||||||
@@ -435,12 +571,12 @@ do -- Group Assignment
|
|||||||
local MissionGroupName = MissionGroup:GetName()
|
local MissionGroupName = MissionGroup:GetName()
|
||||||
|
|
||||||
self.AssignedGroups[MissionGroupName] = MissionGroup
|
self.AssignedGroups[MissionGroupName] = MissionGroup
|
||||||
self:E( string.format( "Mission %s is assigned to %s", MissionName, MissionGroupName ) )
|
self:I( string.format( "Mission %s is assigned to %s", MissionName, MissionGroupName ) )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Clear the @{Group} assignment from the @{Mission}.
|
--- Clear the @{Wrapper.Group} assignment from the @{Mission}.
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
-- @param Wrapper.Group#GROUP MissionGroup
|
-- @param Wrapper.Group#GROUP MissionGroup
|
||||||
-- @return #MISSION
|
-- @return #MISSION
|
||||||
@@ -475,53 +611,54 @@ function MISSION:RemoveTaskMenu( Task )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Gets the root mission menu for the TaskGroup.
|
--- Gets the root mission menu for the TaskGroup. Obsolete?! Originally no reference to TaskGroup parameter!
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
|
-- @param Wrapper.Group#GROUP TaskGroup Task group.
|
||||||
-- @return Core.Menu#MENU_COALITION self
|
-- @return Core.Menu#MENU_COALITION self
|
||||||
function MISSION:GetRootMenu( TaskGroup ) -- R2.2
|
function MISSION:GetRootMenu( TaskGroup ) -- R2.2
|
||||||
|
|
||||||
local CommandCenter = self:GetCommandCenter()
|
local CommandCenter = self:GetCommandCenter()
|
||||||
local CommandCenterMenu = CommandCenter:GetMenu()
|
local CommandCenterMenu = CommandCenter:GetMenu( TaskGroup )
|
||||||
|
|
||||||
local MissionName = self:GetName()
|
local MissionName = self:GetText()
|
||||||
--local MissionMenu = CommandCenterMenu:GetMenu( MissionName )
|
--local MissionMenu = CommandCenterMenu:GetMenu( MissionName )
|
||||||
|
|
||||||
self.MissionMenu = self.MissionMenu or MENU_COALITION:New( self.MissionCoalition, self:GetName(), CommandCenterMenu )
|
self.MissionMenu = MENU_COALITION:New( self.MissionCoalition, MissionName, CommandCenterMenu )
|
||||||
|
|
||||||
return self.MissionMenu
|
return self.MissionMenu
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Gets the mission menu for the TaskGroup.
|
--- Gets the mission menu for the TaskGroup.
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
|
-- @param Wrapper.Group#GROUP TaskGroup Task group.
|
||||||
-- @return Core.Menu#MENU_COALITION self
|
-- @return Core.Menu#MENU_COALITION self
|
||||||
function MISSION:GetMenu( TaskGroup ) -- R2.1 -- Changed Menu Structure
|
function MISSION:GetMenu( TaskGroup ) -- R2.1 -- Changed Menu Structure
|
||||||
|
|
||||||
local CommandCenter = self:GetCommandCenter()
|
local CommandCenter = self:GetCommandCenter()
|
||||||
local CommandCenterMenu = CommandCenter:GetMenu()
|
local CommandCenterMenu = CommandCenter:GetMenu( TaskGroup )
|
||||||
|
|
||||||
local MissionName = self:GetName()
|
|
||||||
--local MissionMenu = CommandCenterMenu:GetMenu( MissionName )
|
|
||||||
|
|
||||||
self.MissionGroupMenu = self.MissionGroupMenu or {}
|
self.MissionGroupMenu = self.MissionGroupMenu or {}
|
||||||
self.MissionGroupMenu[TaskGroup] = self.MissionGroupMenu[TaskGroup] or {}
|
self.MissionGroupMenu[TaskGroup] = self.MissionGroupMenu[TaskGroup] or {}
|
||||||
|
|
||||||
local GroupMenu = self.MissionGroupMenu[TaskGroup]
|
local GroupMenu = self.MissionGroupMenu[TaskGroup]
|
||||||
|
|
||||||
self.MissionMenu = self.MissionMenu or MENU_COALITION:New( self.MissionCoalition, self:GetName(), CommandCenterMenu )
|
local MissionText = self:GetText()
|
||||||
|
self.MissionMenu = MENU_GROUP:New( TaskGroup, MissionText, CommandCenterMenu )
|
||||||
|
|
||||||
GroupMenu.BriefingMenu = GroupMenu.BriefingMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Mission Briefing", self.MissionMenu, self.MenuReportBriefing, self, TaskGroup )
|
GroupMenu.BriefingMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Mission Briefing", self.MissionMenu, self.MenuReportBriefing, self, TaskGroup )
|
||||||
|
|
||||||
GroupMenu.TaskReportsMenu = GroupMenu.TaskReportsMenu or MENU_GROUP:New( TaskGroup, "Task Reports", self.MissionMenu )
|
GroupMenu.MarkTasks = MENU_GROUP_COMMAND:New( TaskGroup, "Mark Task Locations on Map", self.MissionMenu, self.MarkTargetLocations, self, TaskGroup )
|
||||||
GroupMenu.ReportTasksMenu = GroupMenu.ReportTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksSummary, self, TaskGroup )
|
GroupMenu.TaskReportsMenu = MENU_GROUP:New( TaskGroup, "Task Reports", self.MissionMenu )
|
||||||
GroupMenu.ReportPlannedTasksMenu = GroupMenu.ReportPlannedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Planned Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Planned" )
|
GroupMenu.ReportTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Tasks Summary", GroupMenu.TaskReportsMenu, self.MenuReportTasksSummary, self, TaskGroup )
|
||||||
GroupMenu.ReportAssignedTasksMenu = GroupMenu.ReportAssignedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Assigned Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Assigned" )
|
GroupMenu.ReportPlannedTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Planned Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Planned" )
|
||||||
GroupMenu.ReportSuccessTasksMenu = GroupMenu.ReportSuccessTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Successful Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Success" )
|
GroupMenu.ReportAssignedTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Assigned Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Assigned" )
|
||||||
GroupMenu.ReportFailedTasksMenu = GroupMenu.ReportFailedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Failed Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Failed" )
|
GroupMenu.ReportSuccessTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Successful Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Success" )
|
||||||
GroupMenu.ReportHeldTasksMenu = GroupMenu.ReportHeldTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Held Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Hold" )
|
GroupMenu.ReportFailedTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Failed Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Failed" )
|
||||||
|
GroupMenu.ReportHeldTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Held Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Hold" )
|
||||||
|
|
||||||
GroupMenu.PlayerReportsMenu = GroupMenu.PlayerReportsMenu or MENU_GROUP:New( TaskGroup, "Statistics Reports", self.MissionMenu )
|
GroupMenu.PlayerReportsMenu = MENU_GROUP:New( TaskGroup, "Statistics Reports", self.MissionMenu )
|
||||||
GroupMenu.ReportMissionHistory = GroupMenu.ReportPlayersHistory or MENU_GROUP_COMMAND:New( TaskGroup, "Report Mission Progress", GroupMenu.PlayerReportsMenu, self.MenuReportPlayersProgress, self, TaskGroup )
|
GroupMenu.ReportMissionHistory = MENU_GROUP_COMMAND:New( TaskGroup, "Report Mission Progress", GroupMenu.PlayerReportsMenu, self.MenuReportPlayersProgress, self, TaskGroup )
|
||||||
GroupMenu.ReportPlayersPerTaskMenu = GroupMenu.ReportPlayersPerTaskMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Players per Task", GroupMenu.PlayerReportsMenu, self.MenuReportPlayersPerTask, self, TaskGroup )
|
GroupMenu.ReportPlayersPerTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Players per Task", GroupMenu.PlayerReportsMenu, self.MenuReportPlayersPerTask, self, TaskGroup )
|
||||||
|
|
||||||
return self.MissionMenu
|
return self.MissionMenu
|
||||||
end
|
end
|
||||||
@@ -533,13 +670,25 @@ end
|
|||||||
-- @param #string TaskName The Name of the @{Task} within the @{Mission}.
|
-- @param #string TaskName The Name of the @{Task} within the @{Mission}.
|
||||||
-- @return Tasking.Task#TASK The Task
|
-- @return Tasking.Task#TASK The Task
|
||||||
-- @return #nil Returns nil if no task was found.
|
-- @return #nil Returns nil if no task was found.
|
||||||
function MISSION:GetTask( TaskName )
|
function MISSION:GetTask( TaskName )
|
||||||
self:F( { TaskName } )
|
self:F( { TaskName } )
|
||||||
|
|
||||||
return self.Tasks[TaskName]
|
return self.Tasks[TaskName]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Return the next @{Task} ID to be completed within the @{Mission}.
|
||||||
|
-- @param #MISSION self
|
||||||
|
-- @param Tasking.Task#TASK Task is the @{Task} object.
|
||||||
|
-- @return Tasking.Task#TASK The task added.
|
||||||
|
function MISSION:GetNextTaskID( Task )
|
||||||
|
|
||||||
|
self.TaskNumber = self.TaskNumber + 1
|
||||||
|
|
||||||
|
return self.TaskNumber
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Register a @{Task} to be completed within the @{Mission}.
|
--- Register a @{Task} to be completed within the @{Mission}.
|
||||||
-- Note that there can be multiple @{Task}s registered to be completed.
|
-- Note that there can be multiple @{Task}s registered to be completed.
|
||||||
-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached.
|
-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached.
|
||||||
@@ -549,9 +698,7 @@ end
|
|||||||
function MISSION:AddTask( Task )
|
function MISSION:AddTask( Task )
|
||||||
|
|
||||||
local TaskName = Task:GetTaskName()
|
local TaskName = Task:GetTaskName()
|
||||||
self:F( TaskName )
|
self:I( { "==> Adding TASK ", MissionName = self:GetName(), TaskName = TaskName } )
|
||||||
|
|
||||||
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
|
|
||||||
|
|
||||||
self.Tasks[TaskName] = Task
|
self.Tasks[TaskName] = Task
|
||||||
|
|
||||||
@@ -560,6 +707,7 @@ function MISSION:AddTask( Task )
|
|||||||
return Task
|
return Task
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Removes a @{Task} to be completed within the @{Mission}.
|
--- Removes a @{Task} to be completed within the @{Mission}.
|
||||||
-- Note that there can be multiple @{Task}s registered to be completed.
|
-- Note that there can be multiple @{Task}s registered to be completed.
|
||||||
-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached.
|
-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached.
|
||||||
@@ -569,6 +717,7 @@ end
|
|||||||
function MISSION:RemoveTask( Task )
|
function MISSION:RemoveTask( Task )
|
||||||
|
|
||||||
local TaskName = Task:GetTaskName()
|
local TaskName = Task:GetTaskName()
|
||||||
|
self:I( { "<== Removing TASK ", MissionName = self:GetName(), TaskName = TaskName } )
|
||||||
|
|
||||||
self:F( TaskName )
|
self:F( TaskName )
|
||||||
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
|
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
|
||||||
@@ -584,21 +733,6 @@ function MISSION:RemoveTask( Task )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return the next @{Task} ID to be completed within the @{Mission}.
|
|
||||||
-- @param #MISSION self
|
|
||||||
-- @param Tasking.Task#TASK Task is the @{Task} object.
|
|
||||||
-- @return Tasking.Task#TASK The task added.
|
|
||||||
function MISSION:GetNextTaskID( Task )
|
|
||||||
|
|
||||||
local TaskName = Task:GetTaskName()
|
|
||||||
self:F( TaskName )
|
|
||||||
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
|
|
||||||
|
|
||||||
self.Tasks[TaskName].n = self.Tasks[TaskName].n + 1
|
|
||||||
|
|
||||||
return self.Tasks[TaskName].n
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Is the @{Mission} **COMPLETED**.
|
--- Is the @{Mission} **COMPLETED**.
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
@@ -700,7 +834,7 @@ function MISSION:ReportBriefing()
|
|||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
|
|
||||||
-- List the name of the mission.
|
-- List the name of the mission.
|
||||||
local Name = self:GetName()
|
local Name = self:GetText()
|
||||||
|
|
||||||
-- Determine the status of the mission.
|
-- Determine the status of the mission.
|
||||||
local Status = "<" .. self:GetState() .. ">"
|
local Status = "<" .. self:GetState() .. ">"
|
||||||
@@ -713,57 +847,57 @@ function MISSION:ReportBriefing()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Create a status report of the Mission.
|
----- Create a status report of the Mission.
|
||||||
-- This reports provides a one liner of the mission status. It indicates how many players and how many Tasks.
|
---- This reports provides a one liner of the mission status. It indicates how many players and how many Tasks.
|
||||||
--
|
----
|
||||||
-- Mission "<MissionName>" - Status "<MissionStatus>"
|
---- Mission "<MissionName>" - Status "<MissionStatus>"
|
||||||
-- - Task Types: <TaskType>, <TaskType>
|
---- - Task Types: <TaskType>, <TaskType>
|
||||||
-- - <xx> Planned Tasks (xp)
|
---- - <xx> Planned Tasks (xp)
|
||||||
-- - <xx> Assigned Tasks(xp)
|
---- - <xx> Assigned Tasks(xp)
|
||||||
-- - <xx> Success Tasks (xp)
|
---- - <xx> Success Tasks (xp)
|
||||||
-- - <xx> Hold Tasks (xp)
|
---- - <xx> Hold Tasks (xp)
|
||||||
-- - <xx> Cancelled Tasks (xp)
|
---- - <xx> Cancelled Tasks (xp)
|
||||||
-- - <xx> Aborted Tasks (xp)
|
---- - <xx> Aborted Tasks (xp)
|
||||||
-- - <xx> Failed Tasks (xp)
|
---- - <xx> Failed Tasks (xp)
|
||||||
--
|
----
|
||||||
-- @param #MISSION self
|
---- @param #MISSION self
|
||||||
-- @return #string
|
---- @return #string
|
||||||
function MISSION:ReportStatus()
|
--function MISSION:ReportSummary()
|
||||||
|
--
|
||||||
local Report = REPORT:New()
|
-- local Report = REPORT:New()
|
||||||
|
--
|
||||||
-- List the name of the mission.
|
-- -- List the name of the mission.
|
||||||
local Name = self:GetName()
|
-- local Name = self:GetText()
|
||||||
|
--
|
||||||
-- Determine the status of the mission.
|
-- -- Determine the status of the mission.
|
||||||
local Status = "<" .. self:GetState() .. ">"
|
-- local Status = "<" .. self:GetState() .. ">"
|
||||||
|
--
|
||||||
Report:Add( string.format( '%s - Status "%s"', Name, Status ) )
|
-- Report:Add( string.format( '%s - Status "%s"', Name, Status ) )
|
||||||
|
--
|
||||||
local TaskTypes = self:GetTaskTypes()
|
-- local TaskTypes = self:GetTaskTypes()
|
||||||
|
--
|
||||||
Report:Add( string.format( " - Task Types: %s", table.concat(TaskTypes, ", " ) ) )
|
-- Report:Add( string.format( " - Task Types: %s", table.concat(TaskTypes, ", " ) ) )
|
||||||
|
--
|
||||||
local TaskStatusList = { "Planned", "Assigned", "Success", "Hold", "Cancelled", "Aborted", "Failed" }
|
-- local TaskStatusList = { "Planned", "Assigned", "Success", "Hold", "Cancelled", "Aborted", "Failed" }
|
||||||
|
--
|
||||||
for TaskStatusID, TaskStatus in pairs( TaskStatusList ) do
|
-- for TaskStatusID, TaskStatus in pairs( TaskStatusList ) do
|
||||||
local TaskCount = 0
|
-- local TaskCount = 0
|
||||||
local TaskPlayerCount = 0
|
-- local TaskPlayerCount = 0
|
||||||
-- Determine how many tasks are remaining.
|
-- -- Determine how many tasks are remaining.
|
||||||
for TaskID, Task in pairs( self:GetTasks() ) do
|
-- for TaskID, Task in pairs( self:GetTasks() ) do
|
||||||
local Task = Task -- Tasking.Task#TASK
|
-- local Task = Task -- Tasking.Task#TASK
|
||||||
if Task:Is( TaskStatus ) then
|
-- if Task:Is( TaskStatus ) then
|
||||||
TaskCount = TaskCount + 1
|
-- TaskCount = TaskCount + 1
|
||||||
TaskPlayerCount = TaskPlayerCount + Task:GetPlayerCount()
|
-- TaskPlayerCount = TaskPlayerCount + Task:GetPlayerCount()
|
||||||
end
|
-- end
|
||||||
end
|
-- end
|
||||||
if TaskCount > 0 then
|
-- if TaskCount > 0 then
|
||||||
Report:Add( string.format( " - %02d %s Tasks (%dp)", TaskCount, TaskStatus, TaskPlayerCount ) )
|
-- Report:Add( string.format( " - %02d %s Tasks (%dp)", TaskCount, TaskStatus, TaskPlayerCount ) )
|
||||||
end
|
-- end
|
||||||
end
|
-- end
|
||||||
|
--
|
||||||
return Report:Text()
|
-- return Report:Text()
|
||||||
end
|
--end
|
||||||
|
|
||||||
|
|
||||||
--- Create an active player report of the Mission.
|
--- Create an active player report of the Mission.
|
||||||
@@ -781,7 +915,7 @@ function MISSION:ReportPlayersPerTask( ReportGroup )
|
|||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
|
|
||||||
-- List the name of the mission.
|
-- List the name of the mission.
|
||||||
local Name = self:GetName()
|
local Name = self:GetText()
|
||||||
|
|
||||||
-- Determine the status of the mission.
|
-- Determine the status of the mission.
|
||||||
local Status = "<" .. self:GetState() .. ">"
|
local Status = "<" .. self:GetState() .. ">"
|
||||||
@@ -822,7 +956,7 @@ function MISSION:ReportPlayersProgress( ReportGroup )
|
|||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
|
|
||||||
-- List the name of the mission.
|
-- List the name of the mission.
|
||||||
local Name = self:GetName()
|
local Name = self:GetText()
|
||||||
|
|
||||||
-- Determine the status of the mission.
|
-- Determine the status of the mission.
|
||||||
local Status = "<" .. self:GetState() .. ">"
|
local Status = "<" .. self:GetState() .. ">"
|
||||||
@@ -858,6 +992,32 @@ function MISSION:ReportPlayersProgress( ReportGroup )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Mark all the target locations on the Map.
|
||||||
|
-- @param #MISSION self
|
||||||
|
-- @param Wrapper.Group#GROUP ReportGroup
|
||||||
|
-- @return #string
|
||||||
|
function MISSION:MarkTargetLocations( ReportGroup )
|
||||||
|
|
||||||
|
local Report = REPORT:New()
|
||||||
|
|
||||||
|
-- List the name of the mission.
|
||||||
|
local Name = self:GetText()
|
||||||
|
|
||||||
|
-- Determine the status of the mission.
|
||||||
|
local Status = "<" .. self:GetState() .. ">"
|
||||||
|
|
||||||
|
Report:Add( string.format( '%s - %s - All Tasks are marked on the map. Select a Task from the Mission Menu and Join the Task!!!', Name, Status ) )
|
||||||
|
|
||||||
|
-- Determine how many tasks are remaining.
|
||||||
|
for TaskID, Task in UTILS.spairs( self:GetTasks(), function( t, a, b ) return t[a]:ReportOrder( ReportGroup ) < t[b]:ReportOrder( ReportGroup ) end ) do
|
||||||
|
local Task = Task -- Tasking.Task#TASK
|
||||||
|
Task:MenuMarkToGroup( ReportGroup )
|
||||||
|
end
|
||||||
|
|
||||||
|
return Report:Text()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Create a summary report of the Mission (one line).
|
--- Create a summary report of the Mission (one line).
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
-- @param Wrapper.Group#GROUP ReportGroup
|
-- @param Wrapper.Group#GROUP ReportGroup
|
||||||
@@ -867,7 +1027,7 @@ function MISSION:ReportSummary( ReportGroup )
|
|||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
|
|
||||||
-- List the name of the mission.
|
-- List the name of the mission.
|
||||||
local Name = self:GetName()
|
local Name = self:GetText()
|
||||||
|
|
||||||
-- Determine the status of the mission.
|
-- Determine the status of the mission.
|
||||||
local Status = "<" .. self:GetState() .. ">"
|
local Status = "<" .. self:GetState() .. ">"
|
||||||
@@ -893,7 +1053,7 @@ function MISSION:ReportOverview( ReportGroup, TaskStatus )
|
|||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
|
|
||||||
-- List the name of the mission.
|
-- List the name of the mission.
|
||||||
local Name = self:GetName()
|
local Name = self:GetText()
|
||||||
|
|
||||||
-- Determine the status of the mission.
|
-- Determine the status of the mission.
|
||||||
local Status = "<" .. self:GetState() .. ">"
|
local Status = "<" .. self:GetState() .. ">"
|
||||||
@@ -906,7 +1066,7 @@ function MISSION:ReportOverview( ReportGroup, TaskStatus )
|
|||||||
local Task = Task -- Tasking.Task#TASK
|
local Task = Task -- Tasking.Task#TASK
|
||||||
if Task:Is( TaskStatus ) then
|
if Task:Is( TaskStatus ) then
|
||||||
Report:Add( string.rep( "-", 140 ) )
|
Report:Add( string.rep( "-", 140 ) )
|
||||||
Report:Add( " - " .. Task:ReportOverview( ReportGroup ) )
|
Report:Add( Task:ReportOverview( ReportGroup ) )
|
||||||
end
|
end
|
||||||
Tasks = Tasks + 1
|
Tasks = Tasks + 1
|
||||||
if Tasks >= 8 then
|
if Tasks >= 8 then
|
||||||
@@ -925,7 +1085,7 @@ function MISSION:ReportDetails( ReportGroup )
|
|||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
|
|
||||||
-- List the name of the mission.
|
-- List the name of the mission.
|
||||||
local Name = self:GetName()
|
local Name = self:GetText()
|
||||||
|
|
||||||
-- Determine the status of the mission.
|
-- Determine the status of the mission.
|
||||||
local Status = "<" .. self:GetState() .. ">"
|
local Status = "<" .. self:GetState() .. ">"
|
||||||
@@ -936,6 +1096,7 @@ function MISSION:ReportDetails( ReportGroup )
|
|||||||
local TasksRemaining = 0
|
local TasksRemaining = 0
|
||||||
for TaskID, Task in pairs( self:GetTasks() ) do
|
for TaskID, Task in pairs( self:GetTasks() ) do
|
||||||
local Task = Task -- Tasking.Task#TASK
|
local Task = Task -- Tasking.Task#TASK
|
||||||
|
Report:Add( string.rep( "-", 140 ) )
|
||||||
Report:Add( Task:ReportDetails( ReportGroup ) )
|
Report:Add( Task:ReportDetails( ReportGroup ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -950,9 +1111,28 @@ end
|
|||||||
-- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" )
|
-- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" )
|
||||||
function MISSION:GetTasks()
|
function MISSION:GetTasks()
|
||||||
|
|
||||||
return self.Tasks
|
return self.Tasks or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the relevant tasks of a TaskGroup.
|
||||||
|
-- @param #MISSION
|
||||||
|
-- @param Wrapper.Group#GROUP TaskGroup
|
||||||
|
-- @return #list<Tasking.Task#TASK>
|
||||||
|
function MISSION:GetGroupTasks( TaskGroup )
|
||||||
|
|
||||||
|
local Tasks = {}
|
||||||
|
|
||||||
|
for TaskID, Task in pairs( self:GetTasks() ) do
|
||||||
|
local Task = Task -- Tasking.Task#TASK
|
||||||
|
if Task:HasGroup( TaskGroup ) then
|
||||||
|
Tasks[#Tasks+1] = Task
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Tasks
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Reports the briefing.
|
--- Reports the briefing.
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
-- @param Wrapper.Group#GROUP ReportGroup The group to which the report needs to be sent.
|
-- @param Wrapper.Group#GROUP ReportGroup The group to which the report needs to be sent.
|
||||||
@@ -964,6 +1144,17 @@ function MISSION:MenuReportBriefing( ReportGroup )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Mark all the targets of the Mission on the Map.
|
||||||
|
-- @param #MISSION self
|
||||||
|
-- @param Wrapper.Group#GROUP ReportGroup
|
||||||
|
function MISSION:MenuMarkTargetLocations( ReportGroup )
|
||||||
|
|
||||||
|
local Report = self:MarkTargetLocations( ReportGroup )
|
||||||
|
|
||||||
|
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Overview )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Report the task summary.
|
--- Report the task summary.
|
||||||
-- @param #MISSION self
|
-- @param #MISSION self
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
371
Moose Development/Moose/Tasking/TaskInfo.lua
Normal file
371
Moose Development/Moose/Tasking/TaskInfo.lua
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
--- **Tasking** -- Controls the information of a Task.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ### Contributions:
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Tasking.TaskInfo
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
--- @type TASKINFO
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
---
|
||||||
|
-- # TASKINFO class, extends @{Core.Base#BASE}
|
||||||
|
--
|
||||||
|
-- ## The TASKINFO class implements the methods to contain information and display information of a task.
|
||||||
|
--
|
||||||
|
-- @field #TASKINFO
|
||||||
|
TASKINFO = {
|
||||||
|
ClassName = "TASKINFO",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- @type #TASKINFO.Detail #string A string that flags to document which level of detail needs to be shown in the report.
|
||||||
|
--
|
||||||
|
-- - "M" for Markings on the Map (F10).
|
||||||
|
-- - "S" for Summary Reports.
|
||||||
|
-- - "O" for Overview Reports.
|
||||||
|
-- - "D" for Detailed Reports.
|
||||||
|
TASKINFO.Detail = ""
|
||||||
|
|
||||||
|
--- Instantiates a new TASKINFO.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param Tasking.Task#TASK Task The task owning the information.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:New( Task )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, BASE:New() ) -- Core.Base#BASE
|
||||||
|
|
||||||
|
self.Task = Task
|
||||||
|
self.VolatileInfo = SET_BASE:New()
|
||||||
|
self.PersistentInfo = SET_BASE:New()
|
||||||
|
|
||||||
|
self.Info = self.VolatileInfo
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add taskinfo.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param #string The info key.
|
||||||
|
-- @param Data The data of the info.
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddInfo( Key, Data, Order, Detail, Keep )
|
||||||
|
self.VolatileInfo:Add( Key, { Data = Data, Order = Order, Detail = Detail } )
|
||||||
|
if Keep == true then
|
||||||
|
self.PersistentInfo:Add( Key, { Data = Data, Order = Order, Detail = Detail } )
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get taskinfo.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param #string The info key.
|
||||||
|
-- @return Data The data of the info.
|
||||||
|
-- @return #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @return #TASKINFO.Detail Detail The detail Level.
|
||||||
|
function TASKINFO:GetInfo( Key )
|
||||||
|
local Object = self:Get( Key )
|
||||||
|
return Object.Data, Object.Order, Object.Detail
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get data.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param #string The info key.
|
||||||
|
-- @return Data The data of the info.
|
||||||
|
function TASKINFO:GetData( Key )
|
||||||
|
local Object = self.Info:Get( Key )
|
||||||
|
return Object and Object.Data
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add Text.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param #string Key The key.
|
||||||
|
-- @param #string Text The text.
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddText( Key, Text, Order, Detail, Keep )
|
||||||
|
self:AddInfo( Key, Text, Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add the task name.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddTaskName( Order, Detail, Keep )
|
||||||
|
self:AddInfo( "TaskName", self.Task:GetName(), Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Add a Coordinate.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddCoordinate( Coordinate, Order, Detail, Keep )
|
||||||
|
self:AddInfo( "Coordinate", Coordinate, Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add Coordinates.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param #list<Core.Point#COORDINATE> Coordinates
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddCoordinates( Coordinates, Order, Detail, Keep )
|
||||||
|
self:AddInfo( "Coordinates", Coordinates, Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Add Threat.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param #string ThreatText The text of the Threat.
|
||||||
|
-- @param #string ThreatLevel The level of the Threat.
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddThreat( ThreatText, ThreatLevel, Order, Detail, Keep )
|
||||||
|
self:AddInfo( "Threat", ThreatText .. " [" .. string.rep( "■", ThreatLevel ) .. string.rep( "□", 10 - ThreatLevel ) .. "]", Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get Threat.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @return #string The threat
|
||||||
|
function TASKINFO:GetThreat()
|
||||||
|
self:GetInfo( "Threat" )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Add the Target count.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param #number TargetCount The amount of targets.
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddTargetCount( TargetCount, Order, Detail, Keep )
|
||||||
|
self:AddInfo( "Counting", string.format( "%d", TargetCount ), Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add the Targets.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param #number TargetCount The amount of targets.
|
||||||
|
-- @param #string TargetTypes The text containing the target types.
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddTargets( TargetCount, TargetTypes, Order, Detail, Keep )
|
||||||
|
self:AddInfo( "Targets", string.format( "%d of %s", TargetCount, TargetTypes ), Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get Targets.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @return #string The targets
|
||||||
|
function TASKINFO:GetTargets()
|
||||||
|
self:GetInfo( "Targets" )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Add the QFE at a Coordinate.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddQFEAtCoordinate( Coordinate, Order, Detail, Keep )
|
||||||
|
self:AddInfo( "QFE", Coordinate, Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add the Temperature at a Coordinate.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddTemperatureAtCoordinate( Coordinate, Order, Detail, Keep )
|
||||||
|
self:AddInfo( "Temperature", Coordinate, Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add the Wind at a Coordinate.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddWindAtCoordinate( Coordinate, Order, Detail, Keep )
|
||||||
|
self:AddInfo( "Wind", Coordinate, Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add Cargo.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param Core.Cargo#CARGO Cargo
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddCargo( Cargo, Order, Detail, Keep )
|
||||||
|
self:AddInfo( "Cargo", Cargo, Order, Detail, Keep )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add Cargo set.
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param Core.Set#SET_CARGO SetCargo
|
||||||
|
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:AddCargoSet( SetCargo, Order, Detail, Keep )
|
||||||
|
|
||||||
|
local CargoReport = REPORT:New()
|
||||||
|
CargoReport:Add( "" )
|
||||||
|
SetCargo:ForEachCargo(
|
||||||
|
--- @param Cargo.Cargo#CARGO Cargo
|
||||||
|
function( Cargo )
|
||||||
|
CargoReport:Add( string.format( ' - %s (%s) %s - status %s ', Cargo:GetName(), Cargo:GetType(), Cargo:GetTransportationMethod(), Cargo:GetCurrentState() ) )
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
self:AddInfo( "Cargo", CargoReport:Text(), Order, Detail, Keep )
|
||||||
|
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Create the taskinfo Report
|
||||||
|
-- @param #TASKINFO self
|
||||||
|
-- @param Core.Report#REPORT Report
|
||||||
|
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||||
|
-- @param Wrapper.Group#GROUP ReportGroup
|
||||||
|
-- @param Tasking.Task#TASK Task
|
||||||
|
-- @return #TASKINFO self
|
||||||
|
function TASKINFO:Report( Report, Detail, ReportGroup, Task )
|
||||||
|
|
||||||
|
local Line = 0
|
||||||
|
local LineReport = REPORT:New()
|
||||||
|
|
||||||
|
if not self.Task:IsStatePlanned() and not self.Task:IsStateAssigned() then
|
||||||
|
self.Info = self.PersistentInfo
|
||||||
|
end
|
||||||
|
|
||||||
|
for Key, Data in UTILS.spairs( self.Info.Set, function( t, a, b ) return t[a].Order < t[b].Order end ) do
|
||||||
|
|
||||||
|
self:F( { Key = Key, Detail = Detail, Data = Data } )
|
||||||
|
|
||||||
|
if Data.Detail:find( Detail ) then
|
||||||
|
local Text = ""
|
||||||
|
if Key == "TaskName" then
|
||||||
|
Key = nil
|
||||||
|
Text = Data.Data
|
||||||
|
end
|
||||||
|
if Key == "Coordinate" then
|
||||||
|
local Coordinate = Data.Data -- Core.Point#COORDINATE
|
||||||
|
Text = Coordinate:ToString( ReportGroup:GetUnit(1), nil, Task )
|
||||||
|
end
|
||||||
|
if Key == "Threat" then
|
||||||
|
local DataText = Data.Data -- #string
|
||||||
|
Text = DataText
|
||||||
|
end
|
||||||
|
if Key == "Counting" then
|
||||||
|
local DataText = Data.Data -- #string
|
||||||
|
Text = DataText
|
||||||
|
end
|
||||||
|
if Key == "Targets" then
|
||||||
|
local DataText = Data.Data -- #string
|
||||||
|
Text = DataText
|
||||||
|
end
|
||||||
|
if Key == "QFE" then
|
||||||
|
local Coordinate = Data.Data -- Core.Point#COORDINATE
|
||||||
|
Text = Coordinate:ToStringPressure( ReportGroup:GetUnit(1), nil, Task )
|
||||||
|
end
|
||||||
|
if Key == "Temperature" then
|
||||||
|
local Coordinate = Data.Data -- Core.Point#COORDINATE
|
||||||
|
Text = Coordinate:ToStringTemperature( ReportGroup:GetUnit(1), nil, Task )
|
||||||
|
end
|
||||||
|
if Key == "Wind" then
|
||||||
|
local Coordinate = Data.Data -- Core.Point#COORDINATE
|
||||||
|
Text = Coordinate:ToStringWind( ReportGroup:GetUnit(1), nil, Task )
|
||||||
|
end
|
||||||
|
if Key == "Cargo" then
|
||||||
|
local DataText = Data.Data -- #string
|
||||||
|
Text = DataText
|
||||||
|
end
|
||||||
|
if Key == "Friendlies" then
|
||||||
|
local DataText = Data.Data -- #string
|
||||||
|
Text = DataText
|
||||||
|
end
|
||||||
|
if Key == "Players" then
|
||||||
|
local DataText = Data.Data -- #string
|
||||||
|
Text = DataText
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if Line < math.floor( Data.Order / 10 ) then
|
||||||
|
if Line == 0 then
|
||||||
|
if Text ~= "" then
|
||||||
|
Report:AddIndent( LineReport:Text( ", " ), "-" )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if Text ~= "" then
|
||||||
|
Report:AddIndent( LineReport:Text( ", " ) )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
LineReport = REPORT:New()
|
||||||
|
Line = math.floor( Data.Order / 10 )
|
||||||
|
end
|
||||||
|
|
||||||
|
if Text ~= "" then
|
||||||
|
LineReport:Add( ( Key and ( Key .. ":" ) or "" ) .. Text )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Report:AddIndent( LineReport:Text( ", " ) )
|
||||||
|
|
||||||
|
end
|
||||||
261
Moose Development/Moose/Tasking/TaskZoneCapture.lua
Normal file
261
Moose Development/Moose/Tasking/TaskZoneCapture.lua
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
--- **Tasking** - The TASK_Protect models tasks for players to protect or capture specific zones.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **FlightControl**
|
||||||
|
--
|
||||||
|
-- ### Contributions: MillerTime
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Tasking.TaskZoneCapture
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
do -- TASK_ZONE_GOAL
|
||||||
|
|
||||||
|
--- The TASK_ZONE_GOAL class
|
||||||
|
-- @type TASK_ZONE_GOAL
|
||||||
|
-- @field Core.ZoneGoal#ZONE_GOAL ZoneGoal
|
||||||
|
-- @extends Tasking.Task#TASK
|
||||||
|
|
||||||
|
--- # TASK_ZONE_GOAL class, extends @{Tasking.Task#TASK}
|
||||||
|
--
|
||||||
|
-- The TASK_ZONE_GOAL class defines the task to protect or capture a protection zone.
|
||||||
|
-- The TASK_ZONE_GOAL is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
||||||
|
--
|
||||||
|
-- * **None**: Start of the process
|
||||||
|
-- * **Planned**: The A2G task is planned.
|
||||||
|
-- * **Assigned**: The A2G task is assigned to a @{Wrapper.Group#GROUP}.
|
||||||
|
-- * **Success**: The A2G task is successfully completed.
|
||||||
|
-- * **Failed**: The A2G task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ.
|
||||||
|
--
|
||||||
|
-- ## Set the scoring of achievements in an A2G attack.
|
||||||
|
--
|
||||||
|
-- Scoring or penalties can be given in the following circumstances:
|
||||||
|
--
|
||||||
|
-- * @{#TASK_ZONE_GOAL.SetScoreOnDestroy}(): Set a score when a target in scope of the A2G attack, has been destroyed.
|
||||||
|
-- * @{#TASK_ZONE_GOAL.SetScoreOnSuccess}(): Set a score when all the targets in scope of the A2G attack, have been destroyed.
|
||||||
|
-- * @{#TASK_ZONE_GOAL.SetPenaltyOnFailed}(): Set a penalty when the A2G attack has failed.
|
||||||
|
--
|
||||||
|
-- @field #TASK_ZONE_GOAL
|
||||||
|
TASK_ZONE_GOAL = {
|
||||||
|
ClassName = "TASK_ZONE_GOAL",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Instantiates a new TASK_ZONE_GOAL.
|
||||||
|
-- @param #TASK_ZONE_GOAL self
|
||||||
|
-- @param Tasking.Mission#MISSION Mission
|
||||||
|
-- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
|
||||||
|
-- @param #string TaskName The name of the Task.
|
||||||
|
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal
|
||||||
|
-- @return #TASK_ZONE_GOAL self
|
||||||
|
function TASK_ZONE_GOAL:New( Mission, SetGroup, TaskName, ZoneGoal, TaskType, TaskBriefing )
|
||||||
|
local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType, TaskBriefing ) ) -- #TASK_ZONE_GOAL
|
||||||
|
self:F()
|
||||||
|
|
||||||
|
self.ZoneGoal = ZoneGoal
|
||||||
|
self.TaskType = TaskType
|
||||||
|
|
||||||
|
local Fsm = self:GetUnitProcess()
|
||||||
|
|
||||||
|
|
||||||
|
Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "StartMonitoring", Rejected = "Reject" } )
|
||||||
|
|
||||||
|
Fsm:AddTransition( "Assigned", "StartMonitoring", "Monitoring" )
|
||||||
|
Fsm:AddTransition( "Monitoring", "Monitor", "Monitoring", {} )
|
||||||
|
Fsm:AddTransition( "Monitoring", "RouteTo", "Monitoring" )
|
||||||
|
Fsm:AddProcess( "Monitoring", "RouteToZone", ACT_ROUTE_ZONE:New(), {} )
|
||||||
|
|
||||||
|
--Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" )
|
||||||
|
--Fsm:AddTransition( "Accounted", "Success", "Success" )
|
||||||
|
Fsm:AddTransition( "Rejected", "Reject", "Aborted" )
|
||||||
|
Fsm:AddTransition( "Failed", "Fail", "Failed" )
|
||||||
|
|
||||||
|
self:SetTargetZone( self.ZoneGoal:GetZone() )
|
||||||
|
|
||||||
|
--- Test
|
||||||
|
-- @param #FSM_PROCESS self
|
||||||
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
|
-- @param Tasking.Task#TASK_ZONE_GOAL Task
|
||||||
|
function Fsm:onafterStartMonitoring( TaskUnit, Task )
|
||||||
|
self:F( { self } )
|
||||||
|
self:__Monitor( 0.1 )
|
||||||
|
self:__RouteTo( 0.1 )
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Monitor Loop
|
||||||
|
-- @param #FSM_PROCESS self
|
||||||
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
|
-- @param Tasking.Task#TASK_ZONE_GOAL Task
|
||||||
|
function Fsm:onafterMonitor( TaskUnit, Task )
|
||||||
|
self:F( { self } )
|
||||||
|
self:__Monitor( 15 )
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Test
|
||||||
|
-- @param #FSM_PROCESS self
|
||||||
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
|
-- @param Tasking.Task_A2G#TASK_ZONE_GOAL Task
|
||||||
|
function Fsm:onafterRouteTo( TaskUnit, Task )
|
||||||
|
self:F( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
|
||||||
|
-- Determine the first Unit from the self.TargetSetUnit
|
||||||
|
|
||||||
|
if Task:GetTargetZone( TaskUnit ) then
|
||||||
|
self:__RouteTo( 0.1 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param #TASK_ZONE_GOAL self
|
||||||
|
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal Engine.
|
||||||
|
function TASK_ZONE_GOAL:SetProtect( ZoneGoal )
|
||||||
|
|
||||||
|
self.ZoneGoal = ZoneGoal -- Core.ZoneGoal#ZONE_GOAL
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #TASK_ZONE_GOAL self
|
||||||
|
function TASK_ZONE_GOAL:GetPlannedMenuText()
|
||||||
|
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.ZoneGoal:GetZoneName() .. " )"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #TASK_ZONE_GOAL self
|
||||||
|
-- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map.
|
||||||
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
|
function TASK_ZONE_GOAL:SetTargetZone( TargetZone, TaskUnit )
|
||||||
|
|
||||||
|
local ProcessUnit = self:GetUnitProcess( TaskUnit )
|
||||||
|
|
||||||
|
local ActRouteZone = ProcessUnit:GetProcess( "Monitoring", "RouteToZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE
|
||||||
|
ActRouteZone:SetZone( TargetZone )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #TASK_ZONE_GOAL self
|
||||||
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
|
-- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map.
|
||||||
|
function TASK_ZONE_GOAL:GetTargetZone( TaskUnit )
|
||||||
|
|
||||||
|
local ProcessUnit = self:GetUnitProcess( TaskUnit )
|
||||||
|
|
||||||
|
local ActRouteZone = ProcessUnit:GetProcess( "Monitoring", "RouteToZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE
|
||||||
|
return ActRouteZone:GetZone()
|
||||||
|
end
|
||||||
|
|
||||||
|
function TASK_ZONE_GOAL:SetGoalTotal( GoalTotal )
|
||||||
|
|
||||||
|
self.GoalTotal = GoalTotal
|
||||||
|
end
|
||||||
|
|
||||||
|
function TASK_ZONE_GOAL:GetGoalTotal()
|
||||||
|
|
||||||
|
return self.GoalTotal
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- TASK_ZONE_CAPTURE
|
||||||
|
|
||||||
|
--- The TASK_ZONE_CAPTURE class
|
||||||
|
-- @type TASK_ZONE_CAPTURE
|
||||||
|
-- @field Core.ZoneGoalCoalition#ZONE_GOAL_COALITION ZoneGoal
|
||||||
|
-- @extends #TASK_ZONE_GOAL
|
||||||
|
|
||||||
|
--- # TASK_ZONE_CAPTURE class, extends @{Tasking.TaskZoneGoal#TASK_ZONE_GOAL}
|
||||||
|
--
|
||||||
|
-- The TASK_ZONE_CAPTURE class defines an Suppression or Extermination of Air Defenses task for a human player to be executed.
|
||||||
|
-- These tasks are important to be executed as they will help to achieve air superiority at the vicinity.
|
||||||
|
--
|
||||||
|
-- The TASK_ZONE_CAPTURE is used by the @{Tasking.Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create SEAD tasks
|
||||||
|
-- based on detected enemy ground targets.
|
||||||
|
--
|
||||||
|
-- @field #TASK_ZONE_CAPTURE
|
||||||
|
TASK_ZONE_CAPTURE = {
|
||||||
|
ClassName = "TASK_ZONE_CAPTURE",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
--- Instantiates a new TASK_ZONE_CAPTURE.
|
||||||
|
-- @param #TASK_ZONE_CAPTURE self
|
||||||
|
-- @param Tasking.Mission#MISSION Mission
|
||||||
|
-- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
|
||||||
|
-- @param #string TaskName The name of the Task.
|
||||||
|
-- @param Core.ZoneGoalCoalition#ZONE_GOAL_COALITION ZoneGoalCoalition
|
||||||
|
-- @param #string TaskBriefing The briefing of the task.
|
||||||
|
-- @return #TASK_ZONE_CAPTURE self
|
||||||
|
function TASK_ZONE_CAPTURE:New( Mission, SetGroup, TaskName, ZoneGoalCoalition, TaskBriefing)
|
||||||
|
local self = BASE:Inherit( self, TASK_ZONE_GOAL:New( Mission, SetGroup, TaskName, ZoneGoalCoalition, "CAPTURE", TaskBriefing ) ) -- #TASK_ZONE_CAPTURE
|
||||||
|
self:F()
|
||||||
|
|
||||||
|
Mission:AddTask( self )
|
||||||
|
|
||||||
|
self.TaskCoalition = ZoneGoalCoalition:GetCoalition()
|
||||||
|
self.TaskCoalitionName = ZoneGoalCoalition:GetCoalitionName()
|
||||||
|
self.TaskZoneName = ZoneGoalCoalition:GetZoneName()
|
||||||
|
|
||||||
|
ZoneGoalCoalition:MonitorDestroyedUnits()
|
||||||
|
|
||||||
|
self:SetBriefing(
|
||||||
|
TaskBriefing or
|
||||||
|
"Capture Zone " .. self.TaskZoneName
|
||||||
|
)
|
||||||
|
|
||||||
|
self:UpdateTaskInfo()
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Instantiates a new TASK_ZONE_CAPTURE.
|
||||||
|
-- @param #TASK_ZONE_CAPTURE self
|
||||||
|
function TASK_ZONE_CAPTURE:UpdateTaskInfo()
|
||||||
|
|
||||||
|
|
||||||
|
local ZoneCoordinate = self.ZoneGoal:GetZone():GetCoordinate()
|
||||||
|
self.TaskInfo:AddCoordinate( ZoneCoordinate, 0, "SOD" )
|
||||||
|
self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD" )
|
||||||
|
self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD" )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TASK_ZONE_CAPTURE:ReportOrder( ReportGroup )
|
||||||
|
local Coordinate = self:GetData( "Coordinate" )
|
||||||
|
--local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
|
||||||
|
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
|
||||||
|
|
||||||
|
return Distance
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #TASK_ZONE_CAPTURE self
|
||||||
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
|
function TASK_ZONE_CAPTURE:OnAfterGoal( From, Event, To, PlayerUnit, PlayerName )
|
||||||
|
|
||||||
|
self:F( { PlayerUnit = PlayerUnit } )
|
||||||
|
|
||||||
|
if self.ZoneGoal then
|
||||||
|
if self.ZoneGoal.Goal:IsAchieved() then
|
||||||
|
self:Success()
|
||||||
|
local TotalContributions = self.ZoneGoal.Goal:GetTotalContributions()
|
||||||
|
local PlayerContributions = self.ZoneGoal.Goal:GetPlayerContributions()
|
||||||
|
self:F( { TotalContributions = TotalContributions, PlayerContributions = PlayerContributions } )
|
||||||
|
for PlayerName, PlayerContribution in pairs( PlayerContributions ) do
|
||||||
|
local Scoring = self:GetScoring()
|
||||||
|
if Scoring then
|
||||||
|
Scoring:_AddMissionGoalScore( self.Mission, PlayerName, "Zone " .. self.ZoneGoal:GetZoneName() .." captured", PlayerContribution * 200 / TotalContributions )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:__Goal( -10, PlayerUnit, PlayerName )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user