mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Compare commits
347 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fac5ac9f0 | ||
|
|
d83cabbab6 | ||
|
|
5f9d4405b1 | ||
|
|
bdd9efa2cc | ||
|
|
a778e910f7 | ||
|
|
24b09e22f7 | ||
|
|
b40331b04e | ||
|
|
2d1fcb9be8 | ||
|
|
5fcd394ddd | ||
|
|
7a0f53ebf3 | ||
|
|
a2580122de | ||
|
|
a6de09a0ca | ||
|
|
5e3b50c158 | ||
|
|
2262f27d18 | ||
|
|
4668132b37 | ||
|
|
1fc526e80f | ||
|
|
ceb77e2837 | ||
|
|
6f7a29d372 | ||
|
|
137f0251fb | ||
|
|
e375f3a401 | ||
|
|
10986f8a0d | ||
|
|
16dc3860f7 | ||
|
|
1355f2f562 | ||
|
|
e620062a95 | ||
|
|
333ed629bb | ||
|
|
813b9d90aa | ||
|
|
c87e91d845 | ||
|
|
5fc39daa9d | ||
|
|
09372df86d | ||
|
|
7c0605e82f | ||
|
|
a847d890ba | ||
|
|
778ae1b8e5 | ||
|
|
1f1ab1664c | ||
|
|
6df4fffafd | ||
|
|
dade17a67f | ||
|
|
64be0ffee5 | ||
|
|
59ceb01d19 | ||
|
|
783e29f189 | ||
|
|
42d8a9f59d | ||
|
|
9e7caba089 | ||
|
|
af39a3ae9c | ||
|
|
399f9883a9 | ||
|
|
9815216bd5 | ||
|
|
ce01534535 | ||
|
|
aec65209d0 | ||
|
|
c985d40ca0 | ||
|
|
d0ca76926e | ||
|
|
1fd15bcd4d | ||
|
|
90b588420f | ||
|
|
073e619015 | ||
|
|
3a0d2a5c51 | ||
|
|
d9528292af | ||
|
|
07a76ced88 | ||
|
|
830dd05514 | ||
|
|
ca7949d8c4 | ||
|
|
a3805118a0 | ||
|
|
34fde09c12 | ||
|
|
983d518a69 | ||
|
|
c14dec7412 | ||
|
|
78ab7547f3 | ||
|
|
2e6957984f | ||
|
|
433a66d530 | ||
|
|
7081448c40 | ||
|
|
7d3ad15f39 | ||
|
|
c7c1bcfff4 | ||
|
|
d0728afee7 | ||
|
|
4f25c9a408 | ||
|
|
01330bf00c | ||
|
|
01de638b8e | ||
|
|
3e8c7ad1df | ||
|
|
22c6a03161 | ||
|
|
7868a2e9de | ||
|
|
b7db198125 | ||
|
|
dd8b2caa24 | ||
|
|
1e4cfd473c | ||
|
|
4364cb8e53 | ||
|
|
044fb66ca0 | ||
|
|
84857d2a32 | ||
|
|
cc17027a7a | ||
|
|
02db5ba532 | ||
|
|
fc52e06318 | ||
|
|
0f5f2658a6 | ||
|
|
27d36f3e0d | ||
|
|
9ce1b90eb1 | ||
|
|
38c19b1442 | ||
|
|
d3419d218a | ||
|
|
2f34526c55 | ||
|
|
f9dcc9d95c | ||
|
|
ebc355ee6a | ||
|
|
a0b49fbd67 | ||
|
|
ae213c4cf1 | ||
|
|
8dea86b921 | ||
|
|
44003a8fda | ||
|
|
b883bb1e62 | ||
|
|
db35a67bd7 | ||
|
|
1bfc98fa99 | ||
|
|
efb687cbb5 | ||
|
|
668f12391e | ||
|
|
dfaccd6aa5 | ||
|
|
2220f1829f | ||
|
|
76fde11f47 | ||
|
|
bc5946c76e | ||
|
|
1f041a8acf | ||
|
|
892cb90d62 | ||
|
|
3d7172fdf7 | ||
|
|
3fa3644e1e | ||
|
|
28411d2093 | ||
|
|
26deaca166 | ||
|
|
1346317ad9 | ||
|
|
e11bb71c2d | ||
|
|
95baed1aac | ||
|
|
3b364c7650 | ||
|
|
2a4e242eb2 | ||
|
|
39471212d3 | ||
|
|
8b2237d183 | ||
|
|
6c1a4f1e0d | ||
|
|
abc26b1e5c | ||
|
|
b338f486e5 | ||
|
|
b761078c18 | ||
|
|
202d649085 | ||
|
|
616690391c | ||
|
|
e1e0095d9b | ||
|
|
465c395294 | ||
|
|
a8cbf81851 | ||
|
|
0e78e9c92b | ||
|
|
7c4d640690 | ||
|
|
73bddddba4 | ||
|
|
833206a3b5 | ||
|
|
743baac945 | ||
|
|
0764d076db | ||
|
|
504aa19c03 | ||
|
|
9a3effd063 | ||
|
|
d4a49ae68b | ||
|
|
ca1018f80b | ||
|
|
b9bd8d88a9 | ||
|
|
21412e0061 | ||
|
|
5761e11157 | ||
|
|
7d3f1235e7 | ||
|
|
473001c95b | ||
|
|
532cc0b4df | ||
|
|
08fb4e3736 | ||
|
|
6b7e66efa5 | ||
|
|
18fd587ab0 | ||
|
|
5fd8139f00 | ||
|
|
ac68744deb | ||
|
|
cec02bc44f | ||
|
|
a924a0b641 | ||
|
|
ee15b04142 | ||
|
|
2c67a66d88 | ||
|
|
1fdb3b7daa | ||
|
|
181ed6046e | ||
|
|
ba14330281 | ||
|
|
4c890d18d1 | ||
|
|
2eb4118d56 | ||
|
|
67d53034df | ||
|
|
b4d1118c88 | ||
|
|
dcc15afb89 | ||
|
|
a5632ec3a4 | ||
|
|
0804a3567a | ||
|
|
ef8c71d27c | ||
|
|
879ea847e9 | ||
|
|
be3c418919 | ||
|
|
be3db86470 | ||
|
|
67b43e2c68 | ||
|
|
577fefab3a | ||
|
|
2ad111dd50 | ||
|
|
2c749bf5c9 | ||
|
|
24eaa7441c | ||
|
|
523375c765 | ||
|
|
ac42b56b8e | ||
|
|
82f4c9d526 | ||
|
|
5b8416d5fd | ||
|
|
874fa7ad69 | ||
|
|
2205100942 | ||
|
|
801475e146 | ||
|
|
d7ee243a00 | ||
|
|
a105ddba3d | ||
|
|
70c29de695 | ||
|
|
d5ceabadb0 | ||
|
|
8bd39b41f4 | ||
|
|
b263cddc07 | ||
|
|
a712d74e2e | ||
|
|
613d33d731 | ||
|
|
c7e694dfb8 | ||
|
|
d6c9195555 | ||
|
|
50298e4109 | ||
|
|
1253e241ff | ||
|
|
3389d3284a | ||
|
|
b10819220c | ||
|
|
244abe2bbb | ||
|
|
4b1a1cbcff | ||
|
|
378e76e45b | ||
|
|
f7f28877da | ||
|
|
e3d2dec91f | ||
|
|
470c4ef13c | ||
|
|
241b31fcec | ||
|
|
3dd069d7d6 | ||
|
|
77c4fd7696 | ||
|
|
aca4e4d7ca | ||
|
|
dcd278e2a1 | ||
|
|
2f81fcb0c0 | ||
|
|
8cf11de774 | ||
|
|
b62f2afd8d | ||
|
|
176bd0eb8b | ||
|
|
70ee6a1121 | ||
|
|
10edd2f9d0 | ||
|
|
408321decf | ||
|
|
11acb578f6 | ||
|
|
383eff4cd6 | ||
|
|
6cda61c9dd | ||
|
|
4d8abe7f57 | ||
|
|
c6bb7c8bbd | ||
|
|
bd3042410b | ||
|
|
7c9cf96d2e | ||
|
|
ef30bd36a5 | ||
|
|
5286926609 | ||
|
|
ab14fbd11c | ||
|
|
5bde0c7605 | ||
|
|
4f2d8144e9 | ||
|
|
cb61177252 | ||
|
|
736204d163 | ||
|
|
1e15509001 | ||
|
|
cca6b0cf55 | ||
|
|
bfa8719ec3 | ||
|
|
fd0e6053ee | ||
|
|
f99eac0de4 | ||
|
|
89b06fb7a6 | ||
|
|
3652376d42 | ||
|
|
3d1207a079 | ||
|
|
3953f0e7fc | ||
|
|
3e727f7777 | ||
|
|
5621579b5e | ||
|
|
091083b5aa | ||
|
|
b0d0fb9ae1 | ||
|
|
57ce6bcec2 | ||
|
|
7a1cfa9fe3 | ||
|
|
71b5492903 | ||
|
|
5ff4d84a9a | ||
|
|
c71d0ed7cf | ||
|
|
d64dadd9a9 | ||
|
|
370bfc893d | ||
|
|
0f30f3b1a0 | ||
|
|
50e55e1df2 | ||
|
|
51911d3292 | ||
|
|
bff60bdb69 | ||
|
|
219353faad | ||
|
|
4c4ecccb01 | ||
|
|
0e1cbe45b9 | ||
|
|
aac3f64638 | ||
|
|
34937c2cf6 | ||
|
|
74c19f1058 | ||
|
|
42ca05af57 | ||
|
|
1cbdafda65 | ||
|
|
960746245f | ||
|
|
595b9132e8 | ||
|
|
4b50d8f16f | ||
|
|
c320f1a0a7 | ||
|
|
82b5269040 | ||
|
|
45aebff48e | ||
|
|
80bf992806 | ||
|
|
f2e22579ed | ||
|
|
2dc908d926 | ||
|
|
1f9725530f | ||
|
|
d3e6b0366b | ||
|
|
1545add510 | ||
|
|
c85f575888 | ||
|
|
9f8428c7ba | ||
|
|
5eef138507 | ||
|
|
8c6c1e481b | ||
|
|
14d6085b69 | ||
|
|
d13173e336 | ||
|
|
ced01a993d | ||
|
|
fa80f0a162 | ||
|
|
02e59b23c5 | ||
|
|
80b2b26018 | ||
|
|
e3f523d648 | ||
|
|
5b86bf9605 | ||
|
|
c5ece16753 | ||
|
|
4c2a89ee29 | ||
|
|
4505b60859 | ||
|
|
e8c75b8795 | ||
|
|
7e21a1070a | ||
|
|
2ce9f26e26 | ||
|
|
bfaca9dd5f | ||
|
|
30819dad72 | ||
|
|
e946916fc0 | ||
|
|
2eeca4451c | ||
|
|
ee17d3e995 | ||
|
|
a48e09b434 | ||
|
|
27ea85ea57 | ||
|
|
3baf52d307 | ||
|
|
0faa0036ee | ||
|
|
79189d4d93 | ||
|
|
f859522052 | ||
|
|
8d886a75d6 | ||
|
|
5a772ad05e | ||
|
|
a16e22818d | ||
|
|
0cc959bf34 | ||
|
|
2fcb31f3ac | ||
|
|
aa948b57d8 | ||
|
|
6ca459b38c | ||
|
|
79da4cbf27 | ||
|
|
e5a60a2ef1 | ||
|
|
7e2ae60e43 | ||
|
|
51f134538d | ||
|
|
0ee7a38c61 | ||
|
|
15dd2cf735 | ||
|
|
e895642157 | ||
|
|
154026fbf8 | ||
|
|
d7969e9455 | ||
|
|
7dcff7ec9c | ||
|
|
0e6bf1f46b | ||
|
|
67e52120d4 | ||
|
|
4b84d227f0 | ||
|
|
2fce93d925 | ||
|
|
df0dbc9108 | ||
|
|
db6354b60d | ||
|
|
4307ddcad3 | ||
|
|
daa734009e | ||
|
|
86e13df303 | ||
|
|
65cf53ce28 | ||
|
|
2e167358bb | ||
|
|
78d1a215e4 | ||
|
|
14daca9a72 | ||
|
|
48dba742ad | ||
|
|
2ca847e845 | ||
|
|
11c74ddc17 | ||
|
|
c38917fa2f | ||
|
|
1847a2372c | ||
|
|
f10d676921 | ||
|
|
0532c54cd5 | ||
|
|
becaf47a66 | ||
|
|
9ea8443286 | ||
|
|
f76fa58a5f | ||
|
|
c8b36b8c99 | ||
|
|
5b37e7b249 | ||
|
|
cfca4fdc46 | ||
|
|
a4704d0e2f | ||
|
|
7538f63c00 | ||
|
|
bfaf88f017 | ||
|
|
b5965bbf81 | ||
|
|
bcbda4eb64 | ||
|
|
7306cc1102 | ||
|
|
6406ce696b | ||
|
|
0d9d0be0c3 | ||
|
|
059d8ccfc0 | ||
|
|
bd9022c010 |
1
.github/workflows/build-docs.yml
vendored
1
.github/workflows/build-docs.yml
vendored
@@ -57,6 +57,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Update apt-get (needed for act docker image)
|
- name: Update apt-get (needed for act docker image)
|
||||||
run: |
|
run: |
|
||||||
|
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
|
||||||
sudo apt-get -qq update
|
sudo apt-get -qq update
|
||||||
|
|
||||||
- name: Install tree
|
- name: Install tree
|
||||||
|
|||||||
1
.github/workflows/build-includes.yml
vendored
1
.github/workflows/build-includes.yml
vendored
@@ -47,6 +47,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Update apt-get (needed for act docker image)
|
- name: Update apt-get (needed for act docker image)
|
||||||
run: |
|
run: |
|
||||||
|
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
|
||||||
sudo apt-get -qq update
|
sudo apt-get -qq update
|
||||||
|
|
||||||
- name: Install tree
|
- name: Install tree
|
||||||
|
|||||||
10
.github/workflows/gh-pages.yml
vendored
10
.github/workflows/gh-pages.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
@@ -43,7 +43,7 @@ jobs:
|
|||||||
working-directory: docs/
|
working-directory: docs/
|
||||||
- name: Setup Pages
|
- name: Setup Pages
|
||||||
id: pages
|
id: pages
|
||||||
uses: actions/configure-pages@v3
|
uses: actions/configure-pages@v4
|
||||||
- name: Build with Jekyll
|
- name: Build with Jekyll
|
||||||
# Outputs to the './_site' directory by default
|
# Outputs to the './_site' directory by default
|
||||||
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
|
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
|
||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
working-directory: docs/
|
working-directory: docs/
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
# Automatically uploads an artifact from the './_site' directory by default
|
# Automatically uploads an artifact from the './_site' directory by default
|
||||||
uses: actions/upload-pages-artifact@v1
|
uses: actions/upload-pages-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: docs/_site/
|
path: docs/_site/
|
||||||
|
|
||||||
@@ -66,13 +66,13 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@v1
|
uses: actions/deploy-pages@v4
|
||||||
|
|
||||||
check:
|
check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: deploy
|
needs: deploy
|
||||||
steps:
|
steps:
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
- run: npm install linkinator
|
- run: npm install linkinator
|
||||||
- run: npx linkinator https://flightcontrol-master.github.io/MOOSE/ --verbosity error --timeout 5000 --recurse --skip "(java.com)" --retry-errors --retry-errors-count 3 --retry-errors-jitter
|
- run: npx linkinator https://flightcontrol-master.github.io/MOOSE/ --verbosity error --timeout 5000 --recurse --skip "(java.com)" --retry-errors --retry-errors-count 3 --retry-errors-jitter
|
||||||
|
|||||||
@@ -1151,14 +1151,14 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured.
|
local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured.
|
||||||
|
|
||||||
self:I( "Captured " .. AirbaseName )
|
self:T( "Captured " .. AirbaseName )
|
||||||
|
|
||||||
-- Now search for all squadrons located at the airbase, and sanitize them.
|
-- Now search for all squadrons located at the airbase, and sanitize them.
|
||||||
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
||||||
if Squadron.AirbaseName == AirbaseName then
|
if Squadron.AirbaseName == AirbaseName then
|
||||||
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
||||||
Squadron.Captured = true
|
Squadron.Captured = true
|
||||||
self:I( "Squadron " .. SquadronName .. " captured." )
|
self:T( "Squadron " .. SquadronName .. " captured." )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1828,7 +1828,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:I( { CAP = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageAltType } } )
|
self:T( { CAP = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, Zone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageAltType } } )
|
||||||
|
|
||||||
-- Add the CAP to the EWR network.
|
-- Add the CAP to the EWR network.
|
||||||
|
|
||||||
@@ -2085,7 +2085,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
Intercept.EngageCeilingAltitude = EngageCeilingAltitude
|
Intercept.EngageCeilingAltitude = EngageCeilingAltitude
|
||||||
Intercept.EngageAltType = EngageAltType
|
Intercept.EngageAltType = EngageAltType
|
||||||
|
|
||||||
self:I( { GCI = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
self:T( { GCI = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set squadron GCI.
|
--- Set squadron GCI.
|
||||||
@@ -3000,17 +3000,17 @@ do -- AI_A2A_DISPATCHER
|
|||||||
for FriendlyDistance, AIFriendly in UTILS.spairs( DefenderFriendlies or {} ) do
|
for FriendlyDistance, AIFriendly in UTILS.spairs( DefenderFriendlies or {} ) do
|
||||||
-- We only allow to ENGAGE targets as long as the Units on both sides are balanced.
|
-- We only allow to ENGAGE targets as long as the Units on both sides are balanced.
|
||||||
if AttackerCount > DefenderCount then
|
if AttackerCount > DefenderCount then
|
||||||
--self:I("***** AI_A2A_DISPATCHER:CountDefendersToBeEngaged() *****\nThis is supposed to be a UNIT:")
|
--self:T("***** AI_A2A_DISPATCHER:CountDefendersToBeEngaged() *****\nThis is supposed to be a UNIT:")
|
||||||
if AIFriendly then
|
if AIFriendly then
|
||||||
local classname = AIFriendly.ClassName or "No Class Name"
|
local classname = AIFriendly.ClassName or "No Class Name"
|
||||||
local unitname = AIFriendly.IdentifiableName or "No Unit Name"
|
local unitname = AIFriendly.IdentifiableName or "No Unit Name"
|
||||||
--self:I("Class Name: " .. classname)
|
--self:T("Class Name: " .. classname)
|
||||||
--self:I("Unit Name: " .. unitname)
|
--self:T("Unit Name: " .. unitname)
|
||||||
--self:I({AIFriendly})
|
--self:T({AIFriendly})
|
||||||
end
|
end
|
||||||
local Friendly = nil
|
local Friendly = nil
|
||||||
if AIFriendly and AIFriendly:IsAlive() then
|
if AIFriendly and AIFriendly:IsAlive() then
|
||||||
--self:I("AIFriendly alive, getting GROUP")
|
--self:T("AIFriendly alive, getting GROUP")
|
||||||
Friendly = AIFriendly:GetGroup() -- Wrapper.Group#GROUP
|
Friendly = AIFriendly:GetGroup() -- Wrapper.Group#GROUP
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3952,7 +3952,7 @@ end
|
|||||||
|
|
||||||
do
|
do
|
||||||
|
|
||||||
--- @type AI_A2A_GCICAP
|
-- @type AI_A2A_GCICAP
|
||||||
-- @extends #AI_A2A_DISPATCHER
|
-- @extends #AI_A2A_DISPATCHER
|
||||||
|
|
||||||
--- Create an automatic air defence system for a coalition setting up GCI and CAP air defenses.
|
--- Create an automatic air defence system for a coalition setting up GCI and CAP air defenses.
|
||||||
@@ -4322,23 +4322,23 @@ do
|
|||||||
|
|
||||||
-- Setup squadrons
|
-- Setup squadrons
|
||||||
|
|
||||||
self:I( { Airbases = AirbaseNames } )
|
self:T( { Airbases = AirbaseNames } )
|
||||||
|
|
||||||
self:I( "Defining Templates for Airbases ..." )
|
self:T( "Defining Templates for Airbases ..." )
|
||||||
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
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 } )
|
self:T( { 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
|
||||||
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() } )
|
self:T( { Template = Template:GetName() } )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if Templates then
|
if Templates then
|
||||||
@@ -4354,13 +4354,13 @@ do
|
|||||||
self.CAPTemplates:FilterPrefixes( CapPrefixes )
|
self.CAPTemplates:FilterPrefixes( CapPrefixes )
|
||||||
self.CAPTemplates:FilterOnce()
|
self.CAPTemplates:FilterOnce()
|
||||||
|
|
||||||
self:I( "Setting up CAP ..." )
|
self:T( "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 } )
|
self:T( { 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()
|
||||||
@@ -4368,7 +4368,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 } )
|
self:T( { AirbaseDistance = Distance } )
|
||||||
if Distance < AirbaseDistance then
|
if Distance < AirbaseDistance then
|
||||||
AirbaseDistance = Distance
|
AirbaseDistance = Distance
|
||||||
AirbaseClosest = Airbase
|
AirbaseClosest = Airbase
|
||||||
@@ -4376,7 +4376,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if AirbaseClosest then
|
if AirbaseClosest then
|
||||||
self:I( { CAPAirbase = AirbaseClosest:GetName() } )
|
self:T( { CAPAirbase = AirbaseClosest:GetName() } )
|
||||||
self:SetSquadronCap( AirbaseClosest:GetName(), CAPZone, 6000, 10000, 500, 800, 800, 1200, "RADIO" )
|
self: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
|
||||||
@@ -4384,14 +4384,14 @@ do
|
|||||||
|
|
||||||
-- Setup GCI.
|
-- Setup GCI.
|
||||||
-- GCI is setup for all Squadrons.
|
-- GCI is setup for all Squadrons.
|
||||||
self:I( "Setting up GCI ..." )
|
self:T( "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 } )
|
self:F( { Airbase = AirbaseName } )
|
||||||
if Squadron then
|
if Squadron then
|
||||||
self:I( { GCIAirbase = AirbaseName } )
|
self:T( { GCIAirbase = AirbaseName } )
|
||||||
self:SetSquadronGci( AirbaseName, 800, 1200 )
|
self:SetSquadronGci( AirbaseName, 800, 1200 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -904,14 +904,14 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- @type AI_A2G_DISPATCHER.DefenseCoordinates
|
-- @type AI_A2G_DISPATCHER.DefenseCoordinates
|
||||||
-- @map <#string,Core.Point#COORDINATE> A list of all defense coordinates mapped per defense coordinate name.
|
-- @map <#string,Core.Point#COORDINATE> A list of all defense coordinates mapped per defense coordinate name.
|
||||||
|
|
||||||
--- @field #AI_A2G_DISPATCHER.DefenseCoordinates DefenseCoordinates
|
-- @field #AI_A2G_DISPATCHER.DefenseCoordinates DefenseCoordinates
|
||||||
AI_A2G_DISPATCHER.DefenseCoordinates = {}
|
AI_A2G_DISPATCHER.DefenseCoordinates = {}
|
||||||
|
|
||||||
--- Enumerator for spawns at airbases.
|
--- Enumerator for spawns at airbases.
|
||||||
-- @type AI_A2G_DISPATCHER.Takeoff
|
-- @type AI_A2G_DISPATCHER.Takeoff
|
||||||
-- @extends Wrapper.Group#GROUP.Takeoff
|
-- @extends Wrapper.Group#GROUP.Takeoff
|
||||||
|
|
||||||
--- @field #AI_A2G_DISPATCHER.Takeoff Takeoff
|
-- @field #AI_A2G_DISPATCHER.Takeoff Takeoff
|
||||||
AI_A2G_DISPATCHER.Takeoff = GROUP.Takeoff
|
AI_A2G_DISPATCHER.Takeoff = GROUP.Takeoff
|
||||||
|
|
||||||
--- Defines Landing location.
|
--- Defines Landing location.
|
||||||
@@ -942,7 +942,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- @type AI_A2G_DISPATCHER.DefenseQueue
|
-- @type AI_A2G_DISPATCHER.DefenseQueue
|
||||||
-- @list<#AI_A2G_DISPATCHER.DefenseQueueItem> DefenseQueueItem A list of all defenses being queued ...
|
-- @list<#AI_A2G_DISPATCHER.DefenseQueueItem> DefenseQueueItem A list of all defenses being queued ...
|
||||||
|
|
||||||
--- @field #AI_A2G_DISPATCHER.DefenseQueue DefenseQueue
|
-- @field #AI_A2G_DISPATCHER.DefenseQueue DefenseQueue
|
||||||
AI_A2G_DISPATCHER.DefenseQueue = {}
|
AI_A2G_DISPATCHER.DefenseQueue = {}
|
||||||
|
|
||||||
--- Defense approach types.
|
--- Defense approach types.
|
||||||
@@ -1136,7 +1136,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_DISPATCHER:onafterStart( From, Event, To )
|
function AI_A2G_DISPATCHER:onafterStart( From, Event, To )
|
||||||
|
|
||||||
self:GetParent( self ).onafterStart( self, From, Event, To )
|
self:GetParent( self ).onafterStart( self, From, Event, To )
|
||||||
@@ -1147,7 +1147,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
for Resource = 1, DefenderSquadron.ResourceCount or 0 do
|
for Resource = 1, DefenderSquadron.ResourceCount or 0 do
|
||||||
self:ResourcePark( DefenderSquadron )
|
self:ResourcePark( DefenderSquadron )
|
||||||
end
|
end
|
||||||
self:I( "Parked resources for squadron " .. DefenderSquadron.Name )
|
self:T( "Parked resources for squadron " .. DefenderSquadron.Name )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1201,7 +1201,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_DISPATCHER:ResourcePark( DefenderSquadron )
|
function AI_A2G_DISPATCHER:ResourcePark( DefenderSquadron )
|
||||||
local TemplateID = math.random( 1, #DefenderSquadron.Spawn )
|
local TemplateID = math.random( 1, #DefenderSquadron.Spawn )
|
||||||
local Spawn = DefenderSquadron.Spawn[ TemplateID ] -- Core.Spawn#SPAWN
|
local Spawn = DefenderSquadron.Spawn[ TemplateID ] -- Core.Spawn#SPAWN
|
||||||
@@ -1218,33 +1218,33 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_A2G_DISPATCHER:OnEventBaseCaptured( EventData )
|
function AI_A2G_DISPATCHER:OnEventBaseCaptured( EventData )
|
||||||
|
|
||||||
local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured.
|
local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured.
|
||||||
|
|
||||||
self:I( "Captured " .. AirbaseName )
|
self:T( "Captured " .. AirbaseName )
|
||||||
|
|
||||||
-- Now search for all squadrons located at the airbase, and sanitize them.
|
-- Now search for all squadrons located at the airbase, and sanitize them.
|
||||||
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
||||||
if Squadron.AirbaseName == AirbaseName then
|
if Squadron.AirbaseName == AirbaseName then
|
||||||
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
||||||
Squadron.Captured = true
|
Squadron.Captured = true
|
||||||
self:I( "Squadron " .. SquadronName .. " captured." )
|
self:T( "Squadron " .. SquadronName .. " captured." )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_A2G_DISPATCHER:OnEventCrashOrDead( EventData )
|
function AI_A2G_DISPATCHER:OnEventCrashOrDead( EventData )
|
||||||
self.Detection:ForgetDetectedUnit( EventData.IniUnitName )
|
self.Detection:ForgetDetectedUnit( EventData.IniUnitName )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_A2G_DISPATCHER:OnEventLand( EventData )
|
function AI_A2G_DISPATCHER:OnEventLand( EventData )
|
||||||
self:F( "Landed" )
|
self:F( "Landed" )
|
||||||
@@ -1261,7 +1261,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
end
|
end
|
||||||
DefenderUnit:Destroy()
|
DefenderUnit:Destroy()
|
||||||
self:ResourcePark( Squadron, Defender )
|
self:ResourcePark( Squadron )
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if DefenderUnit:GetLife() ~= DefenderUnit:GetLife0() then
|
if DefenderUnit:GetLife() ~= DefenderUnit:GetLife0() then
|
||||||
@@ -1273,7 +1273,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_A2G_DISPATCHER:OnEventEngineShutdown( EventData )
|
function AI_A2G_DISPATCHER:OnEventEngineShutdown( EventData )
|
||||||
local DefenderUnit = EventData.IniUnit
|
local DefenderUnit = EventData.IniUnit
|
||||||
@@ -1289,7 +1289,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
end
|
end
|
||||||
DefenderUnit:Destroy()
|
DefenderUnit:Destroy()
|
||||||
self:ResourcePark( Squadron, Defender )
|
self:ResourcePark( Squadron )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1297,7 +1297,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
|
|
||||||
do -- Manage the defensive behaviour
|
do -- Manage the defensive behaviour
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string DefenseCoordinateName The name of the coordinate to be defended by A2G defenses.
|
-- @param #string DefenseCoordinateName The name of the coordinate to be defended by A2G defenses.
|
||||||
-- @param Core.Point#COORDINATE DefenseCoordinate The coordinate to be defended by A2G defenses.
|
-- @param Core.Point#COORDINATE DefenseCoordinate The coordinate to be defended by A2G defenses.
|
||||||
function AI_A2G_DISPATCHER:AddDefenseCoordinate( DefenseCoordinateName, DefenseCoordinate )
|
function AI_A2G_DISPATCHER:AddDefenseCoordinate( DefenseCoordinateName, DefenseCoordinate )
|
||||||
@@ -1305,19 +1305,19 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_DISPATCHER:SetDefenseReactivityLow()
|
function AI_A2G_DISPATCHER:SetDefenseReactivityLow()
|
||||||
self.DefenseReactivity = 0.05
|
self.DefenseReactivity = 0.05
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_DISPATCHER:SetDefenseReactivityMedium()
|
function AI_A2G_DISPATCHER:SetDefenseReactivityMedium()
|
||||||
self.DefenseReactivity = 0.15
|
self.DefenseReactivity = 0.15
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_DISPATCHER:SetDefenseReactivityHigh()
|
function AI_A2G_DISPATCHER:SetDefenseReactivityHigh()
|
||||||
self.DefenseReactivity = 0.5
|
self.DefenseReactivity = 0.5
|
||||||
end
|
end
|
||||||
@@ -1351,14 +1351,14 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- 1. the **distance of the closest airbase to target**, being smaller than the **Defend Radius**.
|
-- 1. the **distance of the closest airbase to target**, being smaller than the **Defend Radius**.
|
||||||
-- 2. the **distance to any defense reference point**.
|
-- 2. the **distance to any defense reference point**.
|
||||||
--
|
--
|
||||||
-- The **default** defense radius is defined as **400000** or **40km**. Override the default defense radius when the era of the warfare is early, or,
|
-- The **default** defense radius is defined as **40000** or **40km**. Override the default defense radius when the era of the warfare is early, or,
|
||||||
-- when you don't want to let the AI_A2G_DISPATCHER react immediately when a certain border or area is not being crossed.
|
-- when you don't want to let the AI_A2G_DISPATCHER react immediately when a certain border or area is not being crossed.
|
||||||
--
|
--
|
||||||
-- Use the method @{#AI_A2G_DISPATCHER.SetDefendRadius}() to set a specific defend radius for all squadrons,
|
-- Use the method @{#AI_A2G_DISPATCHER.SetDefendRadius}() to set a specific defend radius for all squadrons,
|
||||||
-- **the Defense Radius is defined for ALL squadrons which are operational.**
|
-- **the Defense Radius is defined for ALL squadrons which are operational.**
|
||||||
--
|
--
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #number DefenseRadius (Optional, Default = 200000) The defense radius to engage detected targets from the nearest capable and available squadron airbase.
|
-- @param #number DefenseRadius (Optional, Default = 20000) The defense radius to engage detected targets from the nearest capable and available squadron airbase.
|
||||||
-- @return #AI_A2G_DISPATCHER
|
-- @return #AI_A2G_DISPATCHER
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -1373,7 +1373,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
--
|
--
|
||||||
function AI_A2G_DISPATCHER:SetDefenseRadius( DefenseRadius )
|
function AI_A2G_DISPATCHER:SetDefenseRadius( DefenseRadius )
|
||||||
|
|
||||||
self.DefenseRadius = DefenseRadius or 100000
|
self.DefenseRadius = DefenseRadius or 40000
|
||||||
|
|
||||||
self.Detection:SetAcceptRange( self.DefenseRadius )
|
self.Detection:SetAcceptRange( self.DefenseRadius )
|
||||||
|
|
||||||
@@ -1868,7 +1868,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
-- @param #number TakeoffInterval Only Takeoff new units each specified interval in seconds in 10 seconds steps.
|
-- @param #number TakeoffInterval Only Takeoff new units each specified interval in seconds in 10 seconds steps.
|
||||||
-- @usage
|
-- @usage
|
||||||
@@ -2144,7 +2144,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
Sead.EngageAltType = EngageAltType
|
Sead.EngageAltType = EngageAltType
|
||||||
Sead.Defend = true
|
Sead.Defend = true
|
||||||
|
|
||||||
self:I( { SEAD = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
self:T( { SEAD = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -2234,7 +2234,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
|
|
||||||
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "SEAD" )
|
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "SEAD" )
|
||||||
|
|
||||||
self:I( { SEAD = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
self:T( { SEAD = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -2295,7 +2295,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
Cas.EngageAltType = EngageAltType
|
Cas.EngageAltType = EngageAltType
|
||||||
Cas.Defend = true
|
Cas.Defend = true
|
||||||
|
|
||||||
self:I( { CAS = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
self:T( { CAS = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -2385,7 +2385,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
|
|
||||||
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "CAS" )
|
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "CAS" )
|
||||||
|
|
||||||
self:I( { CAS = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
self:T( { CAS = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -2446,7 +2446,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
Bai.EngageAltType = EngageAltType
|
Bai.EngageAltType = EngageAltType
|
||||||
Bai.Defend = true
|
Bai.Defend = true
|
||||||
|
|
||||||
self:I( { BAI = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
self:T( { BAI = { SquadronName, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -2536,7 +2536,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
|
|
||||||
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "BAI" )
|
self:SetSquadronPatrolInterval( SquadronName, self.DefenderDefault.PatrolLimit, self.DefenderDefault.PatrolMinSeconds, self.DefenderDefault.PatrolMaxSeconds, 1, "BAI" )
|
||||||
|
|
||||||
self:I( { BAI = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
self:T( { BAI = { Zone:GetName(), PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType } } )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -3369,7 +3369,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_DISPATCHER:AddDefenderToSquadron( Squadron, Defender, Size )
|
function AI_A2G_DISPATCHER:AddDefenderToSquadron( Squadron, Defender, Size )
|
||||||
self.Defenders = self.Defenders or {}
|
self.Defenders = self.Defenders or {}
|
||||||
local DefenderName = Defender:GetName()
|
local DefenderName = Defender:GetName()
|
||||||
@@ -3380,7 +3380,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
self:F( { DefenderName = DefenderName, SquadronResourceCount = Squadron.ResourceCount } )
|
self:F( { DefenderName = DefenderName, SquadronResourceCount = Squadron.ResourceCount } )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_DISPATCHER:RemoveDefenderFromSquadron( Squadron, Defender )
|
function AI_A2G_DISPATCHER:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
self.Defenders = self.Defenders or {}
|
self.Defenders = self.Defenders or {}
|
||||||
local DefenderName = Defender:GetName()
|
local DefenderName = Defender:GetName()
|
||||||
@@ -3796,7 +3796,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_Fsm:onafterLostControl( DefenderGroup, From, Event, To )
|
function AI_A2G_Fsm:onafterLostControl( DefenderGroup, From, Event, To )
|
||||||
self:F({"LostControl", DefenderGroup:GetName()})
|
self:F({"LostControl", DefenderGroup:GetName()})
|
||||||
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
||||||
@@ -3813,7 +3813,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_Fsm:onafterHome( DefenderGroup, From, Event, To, Action )
|
function AI_A2G_Fsm:onafterHome( DefenderGroup, From, Event, To, Action )
|
||||||
self:F({"Home", DefenderGroup:GetName()})
|
self:F({"Home", DefenderGroup:GetName()})
|
||||||
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
||||||
@@ -3894,7 +3894,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
|
|
||||||
if Squadron then
|
if Squadron then
|
||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetRandomSurely()
|
||||||
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
if self.SetSendPlayerMessages then
|
if self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", on route to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", on route to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
||||||
@@ -3933,7 +3933,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_Fsm:onafterLostControl( DefenderGroup, From, Event, To )
|
function AI_A2G_Fsm:onafterLostControl( DefenderGroup, From, Event, To )
|
||||||
self:F({"Defender LostControl", DefenderGroup:GetName()})
|
self:F({"Defender LostControl", DefenderGroup:GetName()})
|
||||||
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
||||||
@@ -3950,7 +3950,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_Fsm:onafterHome( DefenderGroup, From, Event, To, Action )
|
function AI_A2G_Fsm:onafterHome( DefenderGroup, From, Event, To, Action )
|
||||||
self:F({"Defender Home", DefenderGroup:GetName()})
|
self:F({"Defender Home", DefenderGroup:GetName()})
|
||||||
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
-- @module AI.AI_Air
|
-- @module AI.AI_Air
|
||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
--- @type AI_AIR
|
-- @type AI_AIR
|
||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
--- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}.
|
--- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}.
|
||||||
@@ -264,7 +264,7 @@ function AI_AIR:New( AIGroup )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP self
|
-- @param Wrapper.Group#GROUP self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function GROUP:OnEventTakeoff( EventData, Fsm )
|
function GROUP:OnEventTakeoff( EventData, Fsm )
|
||||||
Fsm:Takeoff()
|
Fsm:Takeoff()
|
||||||
@@ -446,13 +446,13 @@ function AI_AIR:onafterReturn( Controllable, From, Event, To )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
function AI_AIR:onbeforeStatus()
|
function AI_AIR:onbeforeStatus()
|
||||||
|
|
||||||
return self.CheckStatus
|
return self.CheckStatus
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
function AI_AIR:onafterStatus()
|
function AI_AIR:onafterStatus()
|
||||||
|
|
||||||
if self.Controllable and self.Controllable:IsAlive() then
|
if self.Controllable and self.Controllable:IsAlive() then
|
||||||
@@ -465,7 +465,7 @@ function AI_AIR:onafterStatus()
|
|||||||
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
|
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
|
||||||
|
|
||||||
if DistanceFromHomeBase > self.DisengageRadius then
|
if DistanceFromHomeBase > self.DisengageRadius then
|
||||||
self:I( self.Controllable:GetName() .. " is too far from home base, RTB!" )
|
self:T( self.Controllable:GetName() .. " is too far from home base, RTB!" )
|
||||||
self:Hold( 300 )
|
self:Hold( 300 )
|
||||||
RTB = false
|
RTB = false
|
||||||
end
|
end
|
||||||
@@ -489,10 +489,10 @@ function AI_AIR:onafterStatus()
|
|||||||
if Fuel < self.FuelThresholdPercentage then
|
if Fuel < self.FuelThresholdPercentage then
|
||||||
|
|
||||||
if self.TankerName then
|
if self.TankerName then
|
||||||
self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
|
self:T( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
|
||||||
self:Refuel()
|
self:Refuel()
|
||||||
else
|
else
|
||||||
self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
|
self:T( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
|
||||||
local OldAIControllable = self.Controllable
|
local OldAIControllable = self.Controllable
|
||||||
|
|
||||||
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
||||||
@@ -518,7 +518,7 @@ function AI_AIR:onafterStatus()
|
|||||||
-- Note that a group can consist of more units, so if one unit is damaged of a group, the mission may continue.
|
-- Note that a group can consist of more units, so if one unit is damaged of a group, the mission may continue.
|
||||||
-- The damaged unit will RTB due to DCS logic, and the others will continue to engage.
|
-- The damaged unit will RTB due to DCS logic, and the others will continue to engage.
|
||||||
if ( Damage / InitialLife ) < self.PatrolDamageThreshold then
|
if ( Damage / InitialLife ) < self.PatrolDamageThreshold then
|
||||||
self:I( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" )
|
self:T( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" )
|
||||||
self:Damaged()
|
self:Damaged()
|
||||||
RTB = true
|
RTB = true
|
||||||
self:SetStatusOff()
|
self:SetStatusOff()
|
||||||
@@ -536,7 +536,7 @@ function AI_AIR:onafterStatus()
|
|||||||
if Damage ~= InitialLife then
|
if Damage ~= InitialLife then
|
||||||
self:Damaged()
|
self:Damaged()
|
||||||
else
|
else
|
||||||
self:I( self.Controllable:GetName() .. " control lost! " )
|
self:T( self.Controllable:GetName() .. " control lost! " )
|
||||||
|
|
||||||
self:LostControl()
|
self:LostControl()
|
||||||
end
|
end
|
||||||
@@ -560,7 +560,7 @@ function AI_AIR:onafterStatus()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
function AI_AIR.RTBRoute( AIGroup, Fsm )
|
function AI_AIR.RTBRoute( AIGroup, Fsm )
|
||||||
|
|
||||||
AIGroup:F( { "AI_AIR.RTBRoute:", AIGroup:GetName() } )
|
AIGroup:F( { "AI_AIR.RTBRoute:", AIGroup:GetName() } )
|
||||||
@@ -571,7 +571,7 @@ function AI_AIR.RTBRoute( AIGroup, Fsm )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
function AI_AIR.RTBHold( AIGroup, Fsm )
|
function AI_AIR.RTBHold( AIGroup, Fsm )
|
||||||
|
|
||||||
AIGroup:F( { "AI_AIR.RTBHold:", AIGroup:GetName() } )
|
AIGroup:F( { "AI_AIR.RTBHold:", AIGroup:GetName() } )
|
||||||
@@ -598,7 +598,7 @@ function AI_AIR:SetRTBSpeedFactors(MinFactor,MaxFactor)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
||||||
self:F( { AIGroup, From, Event, To } )
|
self:F( { AIGroup, From, Event, To } )
|
||||||
@@ -617,7 +617,10 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
|||||||
--- Calculate the target route point.
|
--- Calculate the target route point.
|
||||||
|
|
||||||
local FromCoord = AIGroup:GetCoordinate()
|
local FromCoord = AIGroup:GetCoordinate()
|
||||||
|
if not FromCoord then return end
|
||||||
|
|
||||||
local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!)
|
local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!)
|
||||||
|
|
||||||
local ToTargetVec3 = ToTargetCoord:GetVec3()
|
local ToTargetVec3 = ToTargetCoord:GetVec3()
|
||||||
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+3000 -- let's set this 1000m/3000 feet above ground
|
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+3000 -- let's set this 1000m/3000 feet above ground
|
||||||
local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 )
|
local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 )
|
||||||
@@ -638,13 +641,13 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
|||||||
local ToAirbaseCoord = ToTargetCoord2
|
local ToAirbaseCoord = ToTargetCoord2
|
||||||
|
|
||||||
if Distance < 5000 then
|
if Distance < 5000 then
|
||||||
self:I( "RTB and near the airbase!" )
|
self:T( "RTB and near the airbase!" )
|
||||||
self:Home()
|
self:Home()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if not AIGroup:InAir() == true then
|
if not AIGroup:InAir() == true then
|
||||||
self:I( "Not anymore in the air, considered Home." )
|
self:T( "Not anymore in the air, considered Home." )
|
||||||
self:Home()
|
self:Home()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -686,12 +689,12 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
function AI_AIR:onafterHome( AIGroup, From, Event, To )
|
function AI_AIR:onafterHome( AIGroup, From, Event, To )
|
||||||
self:F( { AIGroup, From, Event, To } )
|
self:F( { AIGroup, From, Event, To } )
|
||||||
|
|
||||||
self:I( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" )
|
self:T( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" )
|
||||||
|
|
||||||
if AIGroup and AIGroup:IsAlive() then
|
if AIGroup and AIGroup:IsAlive() then
|
||||||
end
|
end
|
||||||
@@ -700,15 +703,17 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
function AI_AIR:onafterHold( AIGroup, From, Event, To, HoldTime )
|
function AI_AIR:onafterHold( AIGroup, From, Event, To, HoldTime )
|
||||||
self:F( { AIGroup, From, Event, To } )
|
self:F( { AIGroup, From, Event, To } )
|
||||||
|
|
||||||
self:I( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" )
|
self:T( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" )
|
||||||
|
|
||||||
if AIGroup and AIGroup:IsAlive() then
|
if AIGroup and AIGroup:IsAlive() then
|
||||||
local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
local Coordinate = AIGroup:GetCoordinate()
|
||||||
|
if Coordinate == nil then return end
|
||||||
|
local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed, Coordinate )
|
||||||
local TimedOrbitTask = AIGroup:TaskControlled( OrbitTask, AIGroup:TaskCondition( nil, nil, nil, nil, HoldTime , nil ) )
|
local TimedOrbitTask = AIGroup:TaskControlled( OrbitTask, AIGroup:TaskCondition( nil, nil, nil, nil, HoldTime , nil ) )
|
||||||
|
|
||||||
local RTBTask = AIGroup:TaskFunction( "AI_AIR.RTBHold", self )
|
local RTBTask = AIGroup:TaskFunction( "AI_AIR.RTBHold", self )
|
||||||
@@ -722,17 +727,17 @@ function AI_AIR:onafterHold( AIGroup, From, Event, To, HoldTime )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
function AI_AIR.Resume( AIGroup, Fsm )
|
function AI_AIR.Resume( AIGroup, Fsm )
|
||||||
|
|
||||||
AIGroup:I( { "AI_AIR.Resume:", AIGroup:GetName() } )
|
AIGroup:T( { "AI_AIR.Resume:", AIGroup:GetName() } )
|
||||||
if AIGroup:IsAlive() then
|
if AIGroup:IsAlive() then
|
||||||
Fsm:__RTB( Fsm.TaskDelay )
|
Fsm:__RTB( Fsm.TaskDelay )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
function AI_AIR:onafterRefuel( AIGroup, From, Event, To )
|
function AI_AIR:onafterRefuel( AIGroup, From, Event, To )
|
||||||
self:F( { AIGroup, From, Event, To } )
|
self:F( { AIGroup, From, Event, To } )
|
||||||
@@ -744,7 +749,7 @@ function AI_AIR:onafterRefuel( AIGroup, From, Event, To )
|
|||||||
|
|
||||||
if Tanker and Tanker:IsAlive() and Tanker:IsAirPlane() then
|
if Tanker and Tanker:IsAlive() and Tanker:IsAirPlane() then
|
||||||
|
|
||||||
self:I( "Group " .. self.Controllable:GetName() .. " ... Refuelling! State=" .. self:GetState() .. ", Refuelling tanker " .. self.TankerName )
|
self:T( "Group " .. self.Controllable:GetName() .. " ... Refuelling! State=" .. self:GetState() .. ", Refuelling tanker " .. self.TankerName )
|
||||||
|
|
||||||
local RefuelRoute = {}
|
local RefuelRoute = {}
|
||||||
|
|
||||||
@@ -798,13 +803,13 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
function AI_AIR:onafterDead()
|
function AI_AIR:onafterDead()
|
||||||
self:SetStatusOff()
|
self:SetStatusOff()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_AIR:OnCrash( EventData )
|
function AI_AIR:OnCrash( EventData )
|
||||||
|
|
||||||
@@ -815,7 +820,7 @@ function AI_AIR:OnCrash( EventData )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_AIR:OnEjection( EventData )
|
function AI_AIR:OnEjection( EventData )
|
||||||
|
|
||||||
@@ -824,7 +829,7 @@ function AI_AIR:OnEjection( EventData )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_AIR:OnPilotDead( EventData )
|
function AI_AIR:OnPilotDead( EventData )
|
||||||
|
|
||||||
|
|||||||
@@ -900,14 +900,14 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- @type AI_AIR_DISPATCHER.DefenseCoordinates
|
-- @type AI_AIR_DISPATCHER.DefenseCoordinates
|
||||||
-- @map <#string,Core.Point#COORDINATE> A list of all defense coordinates mapped per defense coordinate name.
|
-- @map <#string,Core.Point#COORDINATE> A list of all defense coordinates mapped per defense coordinate name.
|
||||||
|
|
||||||
--- @field #AI_AIR_DISPATCHER.DefenseCoordinates DefenseCoordinates
|
-- @field #AI_AIR_DISPATCHER.DefenseCoordinates DefenseCoordinates
|
||||||
AI_AIR_DISPATCHER.DefenseCoordinates = {}
|
AI_AIR_DISPATCHER.DefenseCoordinates = {}
|
||||||
|
|
||||||
--- Enumerator for spawns at airbases
|
--- Enumerator for spawns at airbases
|
||||||
-- @type AI_AIR_DISPATCHER.Takeoff
|
-- @type AI_AIR_DISPATCHER.Takeoff
|
||||||
-- @extends Wrapper.Group#GROUP.Takeoff
|
-- @extends Wrapper.Group#GROUP.Takeoff
|
||||||
|
|
||||||
--- @field #AI_AIR_DISPATCHER.Takeoff Takeoff
|
-- @field #AI_AIR_DISPATCHER.Takeoff Takeoff
|
||||||
AI_AIR_DISPATCHER.Takeoff = GROUP.Takeoff
|
AI_AIR_DISPATCHER.Takeoff = GROUP.Takeoff
|
||||||
|
|
||||||
--- Defnes Landing location.
|
--- Defnes Landing location.
|
||||||
@@ -938,7 +938,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- @type AI_AIR_DISPATCHER.DefenseQueue
|
-- @type AI_AIR_DISPATCHER.DefenseQueue
|
||||||
-- @list<#AI_AIR_DISPATCHER.DefenseQueueItem> DefenseQueueItem A list of all defenses being queued ...
|
-- @list<#AI_AIR_DISPATCHER.DefenseQueueItem> DefenseQueueItem A list of all defenses being queued ...
|
||||||
|
|
||||||
--- @field #AI_AIR_DISPATCHER.DefenseQueue DefenseQueue
|
-- @field #AI_AIR_DISPATCHER.DefenseQueue DefenseQueue
|
||||||
AI_AIR_DISPATCHER.DefenseQueue = {}
|
AI_AIR_DISPATCHER.DefenseQueue = {}
|
||||||
|
|
||||||
--- Defense approach types
|
--- Defense approach types
|
||||||
@@ -1130,7 +1130,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
function AI_AIR_DISPATCHER:onafterStart( From, Event, To )
|
function AI_AIR_DISPATCHER:onafterStart( From, Event, To )
|
||||||
|
|
||||||
self:GetParent( self ).onafterStart( self, From, Event, To )
|
self:GetParent( self ).onafterStart( self, From, Event, To )
|
||||||
@@ -1141,7 +1141,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
for Resource = 1, DefenderSquadron.ResourceCount or 0 do
|
for Resource = 1, DefenderSquadron.ResourceCount or 0 do
|
||||||
self:ResourcePark( DefenderSquadron )
|
self:ResourcePark( DefenderSquadron )
|
||||||
end
|
end
|
||||||
self:I( "Parked resources for squadron " .. DefenderSquadron.Name )
|
self:T( "Parked resources for squadron " .. DefenderSquadron.Name )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1194,7 +1194,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
function AI_AIR_DISPATCHER:ResourcePark( DefenderSquadron )
|
function AI_AIR_DISPATCHER:ResourcePark( DefenderSquadron )
|
||||||
local TemplateID = math.random( 1, #DefenderSquadron.Spawn )
|
local TemplateID = math.random( 1, #DefenderSquadron.Spawn )
|
||||||
local Spawn = DefenderSquadron.Spawn[ TemplateID ] -- Core.Spawn#SPAWN
|
local Spawn = DefenderSquadron.Spawn[ TemplateID ] -- Core.Spawn#SPAWN
|
||||||
@@ -1211,31 +1211,31 @@ do -- AI_AIR_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_AIR_DISPATCHER:OnEventBaseCaptured( EventData )
|
function AI_AIR_DISPATCHER:OnEventBaseCaptured( EventData )
|
||||||
|
|
||||||
local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured.
|
local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured.
|
||||||
|
|
||||||
self:I( "Captured " .. AirbaseName )
|
self:T( "Captured " .. AirbaseName )
|
||||||
|
|
||||||
-- Now search for all squadrons located at the airbase, and sanitize them.
|
-- Now search for all squadrons located at the airbase, and sanitize them.
|
||||||
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
||||||
if Squadron.AirbaseName == AirbaseName then
|
if Squadron.AirbaseName == AirbaseName then
|
||||||
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
||||||
Squadron.Captured = true
|
Squadron.Captured = true
|
||||||
self:I( "Squadron " .. SquadronName .. " captured." )
|
self:T( "Squadron " .. SquadronName .. " captured." )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_AIR_DISPATCHER:OnEventCrashOrDead( EventData )
|
function AI_AIR_DISPATCHER:OnEventCrashOrDead( EventData )
|
||||||
self.Detection:ForgetDetectedUnit( EventData.IniUnitName )
|
self.Detection:ForgetDetectedUnit( EventData.IniUnitName )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_AIR_DISPATCHER:OnEventLand( EventData )
|
function AI_AIR_DISPATCHER:OnEventLand( EventData )
|
||||||
self:F( "Landed" )
|
self:F( "Landed" )
|
||||||
@@ -1252,7 +1252,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
end
|
end
|
||||||
DefenderUnit:Destroy()
|
DefenderUnit:Destroy()
|
||||||
self:ResourcePark( Squadron, Defender )
|
self:ResourcePark( Squadron )
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if DefenderUnit:GetLife() ~= DefenderUnit:GetLife0() then
|
if DefenderUnit:GetLife() ~= DefenderUnit:GetLife0() then
|
||||||
@@ -1263,7 +1263,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_AIR_DISPATCHER:OnEventEngineShutdown( EventData )
|
function AI_AIR_DISPATCHER:OnEventEngineShutdown( EventData )
|
||||||
local DefenderUnit = EventData.IniUnit
|
local DefenderUnit = EventData.IniUnit
|
||||||
@@ -1279,31 +1279,31 @@ do -- AI_AIR_DISPATCHER
|
|||||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
end
|
end
|
||||||
DefenderUnit:Destroy()
|
DefenderUnit:Destroy()
|
||||||
self:ResourcePark( Squadron, Defender )
|
self:ResourcePark( Squadron )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- Manage the defensive behaviour
|
do -- Manage the defensive behaviour
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param #string DefenseCoordinateName The name of the coordinate to be defended by AIR defenses.
|
-- @param #string DefenseCoordinateName The name of the coordinate to be defended by AIR defenses.
|
||||||
-- @param Core.Point#COORDINATE DefenseCoordinate The coordinate to be defended by AIR defenses.
|
-- @param Core.Point#COORDINATE DefenseCoordinate The coordinate to be defended by AIR defenses.
|
||||||
function AI_AIR_DISPATCHER:AddDefenseCoordinate( DefenseCoordinateName, DefenseCoordinate )
|
function AI_AIR_DISPATCHER:AddDefenseCoordinate( DefenseCoordinateName, DefenseCoordinate )
|
||||||
self.DefenseCoordinates[DefenseCoordinateName] = DefenseCoordinate
|
self.DefenseCoordinates[DefenseCoordinateName] = DefenseCoordinate
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
function AI_AIR_DISPATCHER:SetDefenseReactivityLow()
|
function AI_AIR_DISPATCHER:SetDefenseReactivityLow()
|
||||||
self.DefenseReactivity = 0.05
|
self.DefenseReactivity = 0.05
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
function AI_AIR_DISPATCHER:SetDefenseReactivityMedium()
|
function AI_AIR_DISPATCHER:SetDefenseReactivityMedium()
|
||||||
self.DefenseReactivity = 0.15
|
self.DefenseReactivity = 0.15
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
function AI_AIR_DISPATCHER:SetDefenseReactivityHigh()
|
function AI_AIR_DISPATCHER:SetDefenseReactivityHigh()
|
||||||
self.DefenseReactivity = 0.5
|
self.DefenseReactivity = 0.5
|
||||||
end
|
end
|
||||||
@@ -1867,7 +1867,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
-- @param #number TakeoffInterval Only Takeoff new units each specified interval in seconds in 10 seconds steps.
|
-- @param #number TakeoffInterval Only Takeoff new units each specified interval in seconds in 10 seconds steps.
|
||||||
-- @usage
|
-- @usage
|
||||||
@@ -2769,7 +2769,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
|
|
||||||
-- TODO: Need to model the resources in a squadron.
|
-- TODO: Need to model the resources in a squadron.
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param AI.AI_Air_Squadron#AI_AIR_SQUADRON Squadron
|
-- @param AI.AI_Air_Squadron#AI_AIR_SQUADRON Squadron
|
||||||
function AI_AIR_DISPATCHER:AddDefenderToSquadron( Squadron, Defender, Size )
|
function AI_AIR_DISPATCHER:AddDefenderToSquadron( Squadron, Defender, Size )
|
||||||
self.Defenders = self.Defenders or {}
|
self.Defenders = self.Defenders or {}
|
||||||
@@ -2782,7 +2782,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
self:F( { DefenderName = DefenderName, SquadronResourceCount = Squadron.ResourceCount } )
|
self:F( { DefenderName = DefenderName, SquadronResourceCount = Squadron.ResourceCount } )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param AI.AI_Air_Squadron#AI_AIR_SQUADRON Squadron
|
-- @param AI.AI_Air_Squadron#AI_AIR_SQUADRON Squadron
|
||||||
function AI_AIR_DISPATCHER:RemoveDefenderFromSquadron( Squadron, Defender )
|
function AI_AIR_DISPATCHER:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
self.Defenders = self.Defenders or {}
|
self.Defenders = self.Defenders or {}
|
||||||
@@ -2795,7 +2795,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
self:F( { DefenderName = DefenderName, SquadronResourceCount = SquadronResourceCount } )
|
self:F( { DefenderName = DefenderName, SquadronResourceCount = SquadronResourceCount } )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param Wrapper.Group#GROUP Defender
|
-- @param Wrapper.Group#GROUP Defender
|
||||||
-- @return AI.AI_Air_Squadron#AI_AIR_SQUADRON The Squadron.
|
-- @return AI.AI_Air_Squadron#AI_AIR_SQUADRON The Squadron.
|
||||||
function AI_AIR_DISPATCHER:GetSquadronFromDefender( Defender )
|
function AI_AIR_DISPATCHER:GetSquadronFromDefender( Defender )
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_AIR_ENGAGE
|
-- @type AI_AIR_ENGAGE
|
||||||
-- @extends AI.AI_Air#AI_AIR
|
-- @extends AI.AI_AIR#AI_AIR
|
||||||
|
|
||||||
|
|
||||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||||
@@ -351,7 +351,7 @@ function AI_AIR_ENGAGE:onafterAbort( AIGroup, From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR_ENGAGE self
|
-- @param #AI_AIR_ENGAGE self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM.
|
-- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
@@ -361,7 +361,7 @@ function AI_AIR_ENGAGE:onafterAccomplish( AIGroup, From, Event, To )
|
|||||||
--self:SetDetectionOff()
|
--self:SetDetectionOff()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_ENGAGE self
|
-- @param #AI_AIR_ENGAGE self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM.
|
-- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
@@ -374,7 +374,7 @@ function AI_AIR_ENGAGE:onafterDestroy( AIGroup, From, Event, To, EventData )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR_ENGAGE self
|
-- @param #AI_AIR_ENGAGE self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_AIR_ENGAGE:OnEventDead( EventData )
|
function AI_AIR_ENGAGE:OnEventDead( EventData )
|
||||||
self:F( { "EventDead", EventData } )
|
self:F( { "EventDead", EventData } )
|
||||||
@@ -387,9 +387,9 @@ function AI_AIR_ENGAGE:OnEventDead( EventData )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AIControllable
|
-- @param Wrapper.Group#GROUP AIControllable
|
||||||
function AI_AIR_ENGAGE.___EngageRoute( AIGroup, Fsm, AttackSetUnit )
|
function AI_AIR_ENGAGE.___EngageRoute( AIGroup, Fsm, AttackSetUnit )
|
||||||
Fsm:I(string.format("AI_AIR_ENGAGE.___EngageRoute: %s", tostring(AIGroup:GetName())))
|
Fsm:T(string.format("AI_AIR_ENGAGE.___EngageRoute: %s", tostring(AIGroup:GetName())))
|
||||||
|
|
||||||
if AIGroup and AIGroup:IsAlive() then
|
if AIGroup and AIGroup:IsAlive() then
|
||||||
Fsm:__EngageRoute( Fsm.TaskDelay or 0.1, AttackSetUnit )
|
Fsm:__EngageRoute( Fsm.TaskDelay or 0.1, AttackSetUnit )
|
||||||
@@ -397,14 +397,14 @@ function AI_AIR_ENGAGE.___EngageRoute( AIGroup, Fsm, AttackSetUnit )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR_ENGAGE self
|
-- @param #AI_AIR_ENGAGE self
|
||||||
-- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup managed by the FSM.
|
-- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup 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.
|
||||||
-- @param Core.Set#SET_UNIT AttackSetUnit Unit set to be attacked.
|
-- @param Core.Set#SET_UNIT AttackSetUnit Unit set to be attacked.
|
||||||
function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit )
|
function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit )
|
||||||
self:I( { DefenderGroup, From, Event, To, AttackSetUnit } )
|
self:T( { DefenderGroup, From, Event, To, AttackSetUnit } )
|
||||||
|
|
||||||
local DefenderGroupName = DefenderGroup:GetName()
|
local DefenderGroupName = DefenderGroup:GetName()
|
||||||
|
|
||||||
@@ -426,7 +426,13 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
|||||||
local DefenderCoord = DefenderGroup:GetPointVec3()
|
local DefenderCoord = DefenderGroup:GetPointVec3()
|
||||||
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
||||||
|
|
||||||
local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3()
|
local TargetCoord = AttackSetUnit:GetRandomSurely():GetPointVec3()
|
||||||
|
|
||||||
|
if TargetCoord == nil then
|
||||||
|
self:Return()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
||||||
|
|
||||||
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
|
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
|
||||||
@@ -435,12 +441,12 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
|||||||
-- TODO: A factor of * 3 is way too close. This causes the AI not to engange until merged sometimes!
|
-- TODO: A factor of * 3 is way too close. This causes the AI not to engange until merged sometimes!
|
||||||
if TargetDistance <= EngageDistance * 9 then
|
if TargetDistance <= EngageDistance * 9 then
|
||||||
|
|
||||||
--self:I(string.format("AI_AIR_ENGAGE onafterEngageRoute ==> __Engage - target distance = %.1f km", TargetDistance/1000))
|
--self:T(string.format("AI_AIR_ENGAGE onafterEngageRoute ==> __Engage - target distance = %.1f km", TargetDistance/1000))
|
||||||
self:__Engage( 0.1, AttackSetUnit )
|
self:__Engage( 0.1, AttackSetUnit )
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
--self:I(string.format("FF AI_AIR_ENGAGE onafterEngageRoute ==> Routing - target distance = %.1f km", TargetDistance/1000))
|
--self:T(string.format("FF AI_AIR_ENGAGE onafterEngageRoute ==> Routing - target distance = %.1f km", TargetDistance/1000))
|
||||||
|
|
||||||
local EngageRoute = {}
|
local EngageRoute = {}
|
||||||
local AttackTasks = {}
|
local AttackTasks = {}
|
||||||
@@ -472,16 +478,16 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- TODO: This will make an A2A Dispatcher CAP flight to return rather than going back to patrolling!
|
-- TODO: This will make an A2A Dispatcher CAP flight to return rather than going back to patrolling!
|
||||||
self:I( DefenderGroupName .. ": No targets found -> Going RTB")
|
self:T( DefenderGroupName .. ": No targets found -> Going RTB")
|
||||||
self:Return()
|
self:Return()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AIControllable
|
-- @param Wrapper.Group#GROUP AIControllable
|
||||||
function AI_AIR_ENGAGE.___Engage( AIGroup, Fsm, AttackSetUnit )
|
function AI_AIR_ENGAGE.___Engage( AIGroup, Fsm, AttackSetUnit )
|
||||||
|
|
||||||
Fsm:I(string.format("AI_AIR_ENGAGE.___Engage: %s", tostring(AIGroup:GetName())))
|
Fsm:T(string.format("AI_AIR_ENGAGE.___Engage: %s", tostring(AIGroup:GetName())))
|
||||||
|
|
||||||
if AIGroup and AIGroup:IsAlive() then
|
if AIGroup and AIGroup:IsAlive() then
|
||||||
local delay=Fsm.TaskDelay or 0.1
|
local delay=Fsm.TaskDelay or 0.1
|
||||||
@@ -490,7 +496,7 @@ function AI_AIR_ENGAGE.___Engage( AIGroup, Fsm, AttackSetUnit )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR_ENGAGE self
|
-- @param #AI_AIR_ENGAGE self
|
||||||
-- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup managed by the FSM.
|
-- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup 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.
|
||||||
@@ -516,7 +522,7 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
|||||||
local DefenderCoord = DefenderGroup:GetPointVec3()
|
local DefenderCoord = DefenderGroup:GetPointVec3()
|
||||||
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
||||||
|
|
||||||
local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3()
|
local TargetCoord = AttackSetUnit:GetRandomSurely():GetPointVec3()
|
||||||
if not TargetCoord then
|
if not TargetCoord then
|
||||||
self:Return()
|
self:Return()
|
||||||
return
|
return
|
||||||
@@ -547,12 +553,12 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
|||||||
local AttackUnitTasks = self:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude ) -- Polymorphic
|
local AttackUnitTasks = self:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude ) -- Polymorphic
|
||||||
|
|
||||||
if #AttackUnitTasks == 0 then
|
if #AttackUnitTasks == 0 then
|
||||||
self:I( DefenderGroupName .. ": No valid targets found -> Going RTB")
|
self:T( DefenderGroupName .. ": No valid targets found -> Going RTB")
|
||||||
self:Return()
|
self:Return()
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
local text=string.format("%s: Engaging targets at distance %.2f NM", DefenderGroupName, UTILS.MetersToNM(TargetDistance))
|
local text=string.format("%s: Engaging targets at distance %.2f NM", DefenderGroupName, UTILS.MetersToNM(TargetDistance))
|
||||||
self:I(text)
|
self:T(text)
|
||||||
DefenderGroup:OptionROEOpenFire()
|
DefenderGroup:OptionROEOpenFire()
|
||||||
DefenderGroup:OptionROTEvadeFire()
|
DefenderGroup:OptionROTEvadeFire()
|
||||||
DefenderGroup:OptionKeepWeaponsOnThreat()
|
DefenderGroup:OptionKeepWeaponsOnThreat()
|
||||||
@@ -569,13 +575,13 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- TODO: This will make an A2A Dispatcher CAP flight to return rather than going back to patrolling!
|
-- TODO: This will make an A2A Dispatcher CAP flight to return rather than going back to patrolling!
|
||||||
self:I( DefenderGroupName .. ": No targets found -> returning.")
|
self:T( DefenderGroupName .. ": No targets found -> returning.")
|
||||||
self:Return()
|
self:Return()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AIEngage
|
-- @param Wrapper.Group#GROUP AIEngage
|
||||||
function AI_AIR_ENGAGE.Resume( AIEngage, Fsm )
|
function AI_AIR_ENGAGE.Resume( AIEngage, Fsm )
|
||||||
|
|
||||||
AIEngage:F( { "Resume:", AIEngage:GetName() } )
|
AIEngage:F( { "Resume:", AIEngage:GetName() } )
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_AIR_SQUADRON
|
-- @type AI_AIR_SQUADRON
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ AI_AIR_SQUADRON = {
|
|||||||
-- @return #AI_AIR_SQUADRON
|
-- @return #AI_AIR_SQUADRON
|
||||||
function AI_AIR_SQUADRON:New( SquadronName, AirbaseName, TemplatePrefixes, ResourceCount )
|
function AI_AIR_SQUADRON:New( SquadronName, AirbaseName, TemplatePrefixes, ResourceCount )
|
||||||
|
|
||||||
self:I( { Air_Squadron = { SquadronName, AirbaseName, TemplatePrefixes, ResourceCount } } )
|
self:T( { Air_Squadron = { SquadronName, AirbaseName, TemplatePrefixes, ResourceCount } } )
|
||||||
|
|
||||||
local AI_Air_Squadron = BASE:New() -- #AI_AIR_SQUADRON
|
local AI_Air_Squadron = BASE:New() -- #AI_AIR_SQUADRON
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
-- @module AI.AI_Cargo
|
-- @module AI.AI_Cargo
|
||||||
-- @image Cargo.JPG
|
-- @image Cargo.JPG
|
||||||
|
|
||||||
--- @type AI_CARGO
|
-- @type AI_CARGO
|
||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
|
|
||||||
@@ -547,7 +547,7 @@ function AI_CARGO:onafterUnloaded( Carrier, From, Event, To, Cargo, CarrierUnit,
|
|||||||
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
|
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
|
||||||
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
|
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
|
||||||
local IsEmpty = CarrierUnit:IsCargoEmpty()
|
local IsEmpty = CarrierUnit:IsCargoEmpty()
|
||||||
self:I({ IsEmpty = IsEmpty })
|
self:T({ IsEmpty = IsEmpty })
|
||||||
if not IsEmpty then
|
if not IsEmpty then
|
||||||
AllUnloaded = false
|
AllUnloaded = false
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -116,7 +116,7 @@
|
|||||||
-- @image AI_Cargo_Dispatcher.JPG
|
-- @image AI_Cargo_Dispatcher.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_CARGO_DISPATCHER
|
-- @type AI_CARGO_DISPATCHER
|
||||||
-- @field Core.Set#SET_GROUP CarrierSet The set of @{Wrapper.Group#GROUP} objects of carriers that will transport the cargo.
|
-- @field Core.Set#SET_GROUP CarrierSet The set of @{Wrapper.Group#GROUP} objects of carriers that will transport the cargo.
|
||||||
-- @field Core.Set#SET_CARGO CargoSet The set of @{Cargo.Cargo#CARGO} objects, which can be CARGO_GROUP, CARGO_CRATE, CARGO_SLINGLOAD objects.
|
-- @field Core.Set#SET_CARGO CargoSet The set of @{Cargo.Cargo#CARGO} objects, which can be CARGO_GROUP, CARGO_CRATE, CARGO_SLINGLOAD objects.
|
||||||
-- @field Core.Zone#SET_ZONE PickupZoneSet The set of pickup zones, which are used to where the cargo can be picked up by the carriers. If nil, then cargo can be picked up everywhere.
|
-- @field Core.Zone#SET_ZONE PickupZoneSet The set of pickup zones, which are used to where the cargo can be picked up by the carriers. If nil, then cargo can be picked up everywhere.
|
||||||
@@ -1161,7 +1161,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
|
|||||||
else
|
else
|
||||||
local text=string.format("WARNING: Cargo %s is too heavy to be loaded into transport. Cargo weight %.1f > %.1f load capacity of carrier %s.",
|
local text=string.format("WARNING: Cargo %s is too heavy to be loaded into transport. Cargo weight %.1f > %.1f load capacity of carrier %s.",
|
||||||
tostring(Cargo:GetName()), Cargo:GetWeight(), LargestLoadCapacity, tostring(Carrier:GetName()))
|
tostring(Cargo:GetName()), Cargo:GetWeight(), LargestLoadCapacity, tostring(Carrier:GetName()))
|
||||||
self:I(text)
|
self:T(text)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -556,7 +556,7 @@ function AI_ESCORT:SetFlightMenuFormation( Formation )
|
|||||||
|
|
||||||
if MenuFormation then
|
if MenuFormation then
|
||||||
local Arguments = MenuFormation.Arguments
|
local Arguments = MenuFormation.Arguments
|
||||||
--self:I({Arguments=unpack(Arguments)})
|
--self:T({Arguments=unpack(Arguments)})
|
||||||
local FlightMenuFormation = MENU_GROUP:New( self.PlayerGroup, "Formation", self.MainMenu )
|
local FlightMenuFormation = MENU_GROUP:New( self.PlayerGroup, "Formation", self.MainMenu )
|
||||||
local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation,
|
local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation,
|
||||||
function ( self, Formation, ... )
|
function ( self, Formation, ... )
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_ESCORT_DISPATCHER
|
-- @type AI_ESCORT_DISPATCHER
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ AI_ESCORT_DISPATCHER = {
|
|||||||
ClassName = "AI_ESCORT_DISPATCHER",
|
ClassName = "AI_ESCORT_DISPATCHER",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- @field #list
|
-- @field #list
|
||||||
AI_ESCORT_DISPATCHER.AI_Escorts = {}
|
AI_ESCORT_DISPATCHER.AI_Escorts = {}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ function AI_ESCORT_DISPATCHER:onafterStart( From, Event, To )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_ESCORT_DISPATCHER self
|
-- @param #AI_ESCORT_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_ESCORT_DISPATCHER:OnEventExit( EventData )
|
function AI_ESCORT_DISPATCHER:OnEventExit( EventData )
|
||||||
|
|
||||||
@@ -110,11 +110,11 @@ function AI_ESCORT_DISPATCHER:OnEventExit( EventData )
|
|||||||
local PlayerGroup = EventData.IniGroup
|
local PlayerGroup = EventData.IniGroup
|
||||||
local PlayerUnit = EventData.IniUnit
|
local PlayerUnit = EventData.IniUnit
|
||||||
|
|
||||||
self:I({EscortAirbase= self.EscortAirbase } )
|
self:T({EscortAirbase= self.EscortAirbase } )
|
||||||
self:I({PlayerGroupName = PlayerGroupName } )
|
self:T({PlayerGroupName = PlayerGroupName } )
|
||||||
self:I({PlayerGroup = PlayerGroup})
|
self:T({PlayerGroup = PlayerGroup})
|
||||||
self:I({FirstGroup = self.CarrierSet:GetFirst()})
|
self:T({FirstGroup = self.CarrierSet:GetFirst()})
|
||||||
self:I({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
|
self:T({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
|
||||||
|
|
||||||
if self.CarrierSet:FindGroup( PlayerGroupName ) then
|
if self.CarrierSet:FindGroup( PlayerGroupName ) then
|
||||||
if self.AI_Escorts[PlayerGroupName] then
|
if self.AI_Escorts[PlayerGroupName] then
|
||||||
@@ -125,7 +125,7 @@ function AI_ESCORT_DISPATCHER:OnEventExit( EventData )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_ESCORT_DISPATCHER self
|
-- @param #AI_ESCORT_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_ESCORT_DISPATCHER:OnEventBirth( EventData )
|
function AI_ESCORT_DISPATCHER:OnEventBirth( EventData )
|
||||||
|
|
||||||
@@ -133,17 +133,17 @@ function AI_ESCORT_DISPATCHER:OnEventBirth( EventData )
|
|||||||
local PlayerGroup = EventData.IniGroup
|
local PlayerGroup = EventData.IniGroup
|
||||||
local PlayerUnit = EventData.IniUnit
|
local PlayerUnit = EventData.IniUnit
|
||||||
|
|
||||||
self:I({EscortAirbase= self.EscortAirbase } )
|
self:T({EscortAirbase= self.EscortAirbase } )
|
||||||
self:I({PlayerGroupName = PlayerGroupName } )
|
self:T({PlayerGroupName = PlayerGroupName } )
|
||||||
self:I({PlayerGroup = PlayerGroup})
|
self:T({PlayerGroup = PlayerGroup})
|
||||||
self:I({FirstGroup = self.CarrierSet:GetFirst()})
|
self:T({FirstGroup = self.CarrierSet:GetFirst()})
|
||||||
self:I({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
|
self:T({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
|
||||||
|
|
||||||
if self.CarrierSet:FindGroup( PlayerGroupName ) then
|
if self.CarrierSet:FindGroup( PlayerGroupName ) then
|
||||||
if not self.AI_Escorts[PlayerGroupName] then
|
if not self.AI_Escorts[PlayerGroupName] then
|
||||||
local LeaderUnit = PlayerUnit
|
local LeaderUnit = PlayerUnit
|
||||||
local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Hot )
|
local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Hot )
|
||||||
self:I({EscortGroup = EscortGroup})
|
self:T({EscortGroup = EscortGroup})
|
||||||
|
|
||||||
self:ScheduleOnce( 1,
|
self:ScheduleOnce( 1,
|
||||||
function( EscortGroup )
|
function( EscortGroup )
|
||||||
|
|||||||
@@ -652,15 +652,15 @@ function AI_PATROL_ZONE:onafterStart( Controllable, From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
--- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable+
|
||||||
function AI_PATROL_ZONE:onbeforeDetect( Controllable, From, Event, To )
|
function AI_PATROL_ZONE:onbeforeDetect( Controllable, From, Event, To )
|
||||||
|
|
||||||
return self.DetectOn and self.DetectActivated
|
return self.DetectOn and self.DetectActivated
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
--- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
|
function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
|
||||||
|
|
||||||
local Detected = false
|
local Detected = false
|
||||||
@@ -705,7 +705,7 @@ function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
|
-- @param Wrapper.Controllable#CONTROLLABLE AIControllable
|
||||||
-- This static method is called from the route path within the last task at the last waypoint of the Controllable.
|
-- This static method is called from the route path within the last task at the last waypoint of the Controllable.
|
||||||
-- Note that this method is required, as triggers the next route when patrolling for the Controllable.
|
-- Note that this method is required, as triggers the next route when patrolling for the Controllable.
|
||||||
function AI_PATROL_ZONE:_NewPatrolRoute( AIControllable )
|
function AI_PATROL_ZONE:_NewPatrolRoute( AIControllable )
|
||||||
@@ -822,13 +822,13 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:onbeforeStatus()
|
function AI_PATROL_ZONE:onbeforeStatus()
|
||||||
|
|
||||||
return self.CheckStatus
|
return self.CheckStatus
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:onafterStatus()
|
function AI_PATROL_ZONE:onafterStatus()
|
||||||
self:F2()
|
self:F2()
|
||||||
|
|
||||||
@@ -838,7 +838,7 @@ function AI_PATROL_ZONE:onafterStatus()
|
|||||||
|
|
||||||
local Fuel = self.Controllable:GetFuelMin()
|
local Fuel = self.Controllable:GetFuelMin()
|
||||||
if Fuel < self.PatrolFuelThresholdPercentage then
|
if Fuel < self.PatrolFuelThresholdPercentage then
|
||||||
self:I( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
|
self:T( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
|
||||||
local OldAIControllable = self.Controllable
|
local OldAIControllable = self.Controllable
|
||||||
|
|
||||||
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
||||||
@@ -852,7 +852,7 @@ function AI_PATROL_ZONE:onafterStatus()
|
|||||||
-- TODO: Check GROUP damage function.
|
-- TODO: Check GROUP damage function.
|
||||||
local Damage = self.Controllable:GetLife()
|
local Damage = self.Controllable:GetLife()
|
||||||
if Damage <= self.PatrolDamageThreshold then
|
if Damage <= self.PatrolDamageThreshold then
|
||||||
self:I( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" )
|
self:T( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" )
|
||||||
RTB = true
|
RTB = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -864,7 +864,7 @@ function AI_PATROL_ZONE:onafterStatus()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:onafterRTB()
|
function AI_PATROL_ZONE:onafterRTB()
|
||||||
self:F2()
|
self:F2()
|
||||||
|
|
||||||
@@ -903,13 +903,13 @@ function AI_PATROL_ZONE:onafterRTB()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:onafterDead()
|
function AI_PATROL_ZONE:onafterDead()
|
||||||
self:SetDetectionOff()
|
self:SetDetectionOff()
|
||||||
self:SetStatusOff()
|
self:SetStatusOff()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_PATROL_ZONE:OnCrash( EventData )
|
function AI_PATROL_ZONE:OnCrash( EventData )
|
||||||
|
|
||||||
@@ -920,7 +920,7 @@ function AI_PATROL_ZONE:OnCrash( EventData )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_PATROL_ZONE:OnEjection( EventData )
|
function AI_PATROL_ZONE:OnEjection( EventData )
|
||||||
|
|
||||||
@@ -929,7 +929,7 @@ function AI_PATROL_ZONE:OnEjection( EventData )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_PATROL_ZONE:OnPilotDead( EventData )
|
function AI_PATROL_ZONE:OnPilotDead( EventData )
|
||||||
|
|
||||||
|
|||||||
@@ -1144,6 +1144,28 @@ function BASE:TraceClassMethod( Class, Method )
|
|||||||
self:I( "Tracing method " .. Method .. " of class " .. Class )
|
self:I( "Tracing method " .. Method .. " of class " .. Class )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (Internal) Serialize arguments
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param #table Arguments
|
||||||
|
-- @return #string Text
|
||||||
|
function BASE:_Serialize(Arguments)
|
||||||
|
local text = UTILS.PrintTableToLog({Arguments}, 0, true)
|
||||||
|
text = string.gsub(text,"(\n+)","")
|
||||||
|
text = string.gsub(text,"%(%(","%(")
|
||||||
|
text = string.gsub(text,"%)%)","%)")
|
||||||
|
text = string.gsub(text,"(%s+)"," ")
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
----- (Internal) Serialize arguments
|
||||||
|
---- @param #BASE self
|
||||||
|
---- @param #table Arguments
|
||||||
|
---- @return #string Text
|
||||||
|
--function BASE:_Serialize(Arguments)
|
||||||
|
-- local text=UTILS.BasicSerialize(Arguments)
|
||||||
|
-- return text
|
||||||
|
--end
|
||||||
|
|
||||||
--- Trace a function call. This function is private.
|
--- Trace a function call. This function is private.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Arguments A #table or any field.
|
-- @param Arguments A #table or any field.
|
||||||
@@ -1168,7 +1190,7 @@ function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
|||||||
if DebugInfoFrom then
|
if DebugInfoFrom then
|
||||||
LineFrom = DebugInfoFrom.currentline
|
LineFrom = DebugInfoFrom.currentline
|
||||||
end
|
end
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, BASE:_Serialize(Arguments) ) )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1242,7 +1264,7 @@ function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
|||||||
if DebugInfoFrom then
|
if DebugInfoFrom then
|
||||||
LineFrom = DebugInfoFrom.currentline
|
LineFrom = DebugInfoFrom.currentline
|
||||||
end
|
end
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s", LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s", LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, BASE:_Serialize(Arguments) ) )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1314,7 +1336,7 @@ function BASE:E( Arguments )
|
|||||||
|
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
||||||
else
|
else
|
||||||
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, BASE:_Serialize(Arguments) ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1341,39 +1363,8 @@ function BASE:I( Arguments )
|
|||||||
|
|
||||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
||||||
else
|
else
|
||||||
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, UTILS.BasicSerialize( Arguments ) ) )
|
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, BASE:_Serialize(Arguments)) )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- old stuff
|
|
||||||
|
|
||||||
-- function BASE:_Destructor()
|
|
||||||
-- --self:E("_Destructor")
|
|
||||||
--
|
|
||||||
-- --self:EventRemoveAll()
|
|
||||||
-- end
|
|
||||||
|
|
||||||
-- THIS IS WHY WE NEED LUA 5.2 ...
|
|
||||||
-- function BASE:_SetDestructor()
|
|
||||||
--
|
|
||||||
-- -- TODO: Okay, this is really technical...
|
|
||||||
-- -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
|
|
||||||
-- -- Therefore, I am parking this logic until I've properly discussed all this with the community.
|
|
||||||
--
|
|
||||||
-- local proxy = newproxy(true)
|
|
||||||
-- local proxyMeta = getmetatable(proxy)
|
|
||||||
--
|
|
||||||
-- proxyMeta.__gc = function ()
|
|
||||||
-- env.info("In __gc for " .. self:GetClassNameAndID() )
|
|
||||||
-- if self._Destructor then
|
|
||||||
-- self:_Destructor()
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
-- -- keep the userdata from newproxy reachable until the object
|
|
||||||
-- -- table is about to be garbage-collected - then the __gc hook
|
|
||||||
-- -- will be invoked and the destructor called
|
|
||||||
-- rawset( self, '__proxy', proxy )
|
|
||||||
--
|
|
||||||
-- end
|
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Core/Beacon)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- ### Authors: Hugues "Grey_Echo" Bousquet, funkyfranky
|
-- ### Authors: Hugues "Grey_Echo" Bousquet, funkyfranky
|
||||||
--
|
--
|
||||||
-- @module Core.Beacon
|
-- @module Core.Beacon
|
||||||
@@ -34,11 +38,13 @@
|
|||||||
-- @type BEACON
|
-- @type BEACON
|
||||||
-- @field #string ClassName Name of the class "BEACON".
|
-- @field #string ClassName Name of the class "BEACON".
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{Wrapper.Controllable#CONTROLLABLE} that will receive radio capabilities.
|
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{Wrapper.Controllable#CONTROLLABLE} that will receive radio capabilities.
|
||||||
|
-- @field #number UniqueName Counter to make the unique naming work.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
BEACON = {
|
BEACON = {
|
||||||
ClassName = "BEACON",
|
ClassName = "BEACON",
|
||||||
Positionable = nil,
|
Positionable = nil,
|
||||||
name = nil,
|
name = nil,
|
||||||
|
UniqueName = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Beacon types supported by DCS.
|
--- Beacon types supported by DCS.
|
||||||
@@ -286,6 +292,7 @@ end
|
|||||||
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
||||||
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||||
self:F({TACANChannel, Message, Bearing, BeaconDuration})
|
self:F({TACANChannel, Message, Bearing, BeaconDuration})
|
||||||
|
self:E("This method is DEPRECATED! Please use ActivateTACAN() instead.")
|
||||||
|
|
||||||
local IsValid = true
|
local IsValid = true
|
||||||
|
|
||||||
@@ -380,6 +387,8 @@ function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDurati
|
|||||||
self:F({FileName, Frequency, Modulation, Power, BeaconDuration})
|
self:F({FileName, Frequency, Modulation, Power, BeaconDuration})
|
||||||
local IsValid = false
|
local IsValid = false
|
||||||
|
|
||||||
|
Modulation = Modulation or radio.modulation.AM
|
||||||
|
|
||||||
-- Check the filename
|
-- Check the filename
|
||||||
if type(FileName) == "string" then
|
if type(FileName) == "string" then
|
||||||
if FileName:find(".ogg") or FileName:find(".wav") then
|
if FileName:find(".ogg") or FileName:find(".wav") then
|
||||||
@@ -390,7 +399,7 @@ function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDurati
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not IsValid then
|
if not IsValid then
|
||||||
self:E({"File name invalid. Maybe something wrong with the extension ? ", FileName})
|
self:E({"File name invalid. Maybe something wrong with the extension? ", FileName})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check the Frequency
|
-- Check the Frequency
|
||||||
@@ -416,7 +425,9 @@ function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDurati
|
|||||||
if IsValid then
|
if IsValid then
|
||||||
self:T2({"Activating Beacon on ", Frequency, Modulation})
|
self:T2({"Activating Beacon on ", Frequency, Modulation})
|
||||||
-- Note that this is looped. I have to give this transmission a unique name, I use the class ID
|
-- Note that this is looped. I have to give this transmission a unique name, I use the class ID
|
||||||
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring(self.ID))
|
BEACON.UniqueName = BEACON.UniqueName + 1
|
||||||
|
self.BeaconName = "MooseBeacon"..tostring(BEACON.UniqueName)
|
||||||
|
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, self.BeaconName)
|
||||||
|
|
||||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||||
SCHEDULER:New( nil,
|
SCHEDULER:New( nil,
|
||||||
@@ -425,6 +436,7 @@ function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDurati
|
|||||||
end, {}, BeaconDuration)
|
end, {}, BeaconDuration)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stops the Radio Beacon
|
--- Stops the Radio Beacon
|
||||||
@@ -433,7 +445,7 @@ end
|
|||||||
function BEACON:StopRadioBeacon()
|
function BEACON:StopRadioBeacon()
|
||||||
self:F()
|
self:F()
|
||||||
-- The unique name of the transmission is the class ID
|
-- The unique name of the transmission is the class ID
|
||||||
trigger.action.stopRadioTransmission(tostring(self.ID))
|
trigger.action.stopRadioTransmission(self.BeaconName)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
--
|
--
|
||||||
-- @module Core.ClientMenu
|
-- @module Core.ClientMenu
|
||||||
-- @image Core_Menu.JPG
|
-- @image Core_Menu.JPG
|
||||||
-- last change: Oct 2023
|
-- last change: May 2024
|
||||||
|
|
||||||
-- TODO
|
-- TODO
|
||||||
----------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------
|
||||||
@@ -51,6 +51,7 @@
|
|||||||
-- @field #boolean Generic
|
-- @field #boolean Generic
|
||||||
-- @field #boolean debug
|
-- @field #boolean debug
|
||||||
-- @field #CLIENTMENUMANAGER Controller
|
-- @field #CLIENTMENUMANAGER Controller
|
||||||
|
-- @field #active boolean
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
CLIENTMENU = {
|
CLIENTMENU = {
|
||||||
ClassName = "CLIENTMENUE",
|
ClassName = "CLIENTMENUE",
|
||||||
lid = "",
|
lid = "",
|
||||||
version = "0.1.1",
|
version = "0.1.2",
|
||||||
name = nil,
|
name = nil,
|
||||||
path = nil,
|
path = nil,
|
||||||
group = nil,
|
group = nil,
|
||||||
@@ -70,6 +71,7 @@ CLIENTMENU = {
|
|||||||
debug = false,
|
debug = false,
|
||||||
Controller = nil,
|
Controller = nil,
|
||||||
groupname = nil,
|
groupname = nil,
|
||||||
|
active = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -78,7 +80,7 @@ CLIENTMENU_ID = 0
|
|||||||
|
|
||||||
--- Create an new CLIENTMENU object.
|
--- Create an new CLIENTMENU object.
|
||||||
-- @param #CLIENTMENU self
|
-- @param #CLIENTMENU self
|
||||||
-- @param Wrapper.Client#CLIENT Client The client for whom this entry is.
|
-- @param Wrapper.Client#CLIENT Client The client for whom this entry is. Leave as nil for a generic entry.
|
||||||
-- @param #string Text Text of the F10 menu entry.
|
-- @param #string Text Text of the F10 menu entry.
|
||||||
-- @param #CLIENTMENU Parent The parent menu entry.
|
-- @param #CLIENTMENU Parent The parent menu entry.
|
||||||
-- @param #string Function (optional) Function to call when the entry is used.
|
-- @param #string Function (optional) Function to call when the entry is used.
|
||||||
@@ -114,7 +116,7 @@ function CLIENTMENU:NewEntry(Client,Text,Parent,Function,...)
|
|||||||
if self.Functionargs and self.debug then
|
if self.Functionargs and self.debug then
|
||||||
self:T({"Functionargs",self.Functionargs})
|
self:T({"Functionargs",self.Functionargs})
|
||||||
end
|
end
|
||||||
if not self.Generic then
|
if not self.Generic and self.active == false then
|
||||||
if Function ~= nil then
|
if Function ~= nil then
|
||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
env.info( "MOOSE Error in CLIENTMENU COMMAND function: " .. errmsg )
|
env.info( "MOOSE Error in CLIENTMENU COMMAND function: " .. errmsg )
|
||||||
@@ -133,8 +135,10 @@ function CLIENTMENU:NewEntry(Client,Text,Parent,Function,...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.path = missionCommands.addCommandForGroup(self.GroupID,Text,self.parentpath, self.CallHandler)
|
self.path = missionCommands.addCommandForGroup(self.GroupID,Text,self.parentpath, self.CallHandler)
|
||||||
|
self.active = true
|
||||||
else
|
else
|
||||||
self.path = missionCommands.addSubMenuForGroup(self.GroupID,Text,self.parentpath)
|
self.path = missionCommands.addSubMenuForGroup(self.GroupID,Text,self.parentpath)
|
||||||
|
self.active = true
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if self.parentpath then
|
if self.parentpath then
|
||||||
@@ -200,6 +204,7 @@ function CLIENTMENU:RemoveF10()
|
|||||||
if not status then
|
if not status then
|
||||||
self:I(string.format("**** Error Removing Menu Entry %s for %s!",tostring(self.name),self.groupname))
|
self:I(string.format("**** Error Removing Menu Entry %s for %s!",tostring(self.name),self.groupname))
|
||||||
end
|
end
|
||||||
|
self.active = false
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -324,6 +329,22 @@ end
|
|||||||
--
|
--
|
||||||
-- Many functions can either change the tree for one client or for all clients.
|
-- Many functions can either change the tree for one client or for all clients.
|
||||||
--
|
--
|
||||||
|
-- ## Conceptual remarks
|
||||||
|
--
|
||||||
|
-- There's a couple of things to fully understand:
|
||||||
|
--
|
||||||
|
-- 1) **CLIENTMENUMANAGER** manages a set of entries from **CLIENTMENU**, it's main purpose is to administer the *shadow menu tree*, ie. a menu structure which is not
|
||||||
|
-- (yet) visible to any client
|
||||||
|
-- 2) The entries are **CLIENTMENU** objects, which are linked in a tree form. There's two ways to create them:
|
||||||
|
-- A) in the manager with ":NewEntry()" which initially
|
||||||
|
-- adds it to the shadow menu **only**
|
||||||
|
-- B) stand-alone directly as `CLIENTMENU:NewEntry()` - here it depends on whether or not you gave a CLIENT object if the entry is created as generic entry or pushed
|
||||||
|
-- a **specific** client. **Be aware** though that the entries are not managed by the CLIENTMANAGER before the next step!
|
||||||
|
-- A generic entry can be added to the manager (and the shadow tree) with `:AddEntry()` - this will also push it to all clients(!) if no client is given, or a specific client only.
|
||||||
|
-- 3) Pushing only works for alive clients.
|
||||||
|
-- 4) Live and shadow tree entries are managed via the CLIENTMENUMANAGER object.
|
||||||
|
-- 5) `Propagate()`refreshes the menu tree for all, or a single client.
|
||||||
|
--
|
||||||
-- ## Create a base reference tree and send to all clients
|
-- ## Create a base reference tree and send to all clients
|
||||||
--
|
--
|
||||||
-- local clientset = SET_CLIENT:New():FilterStart()
|
-- local clientset = SET_CLIENT:New():FilterStart()
|
||||||
@@ -396,7 +417,7 @@ end
|
|||||||
CLIENTMENUMANAGER = {
|
CLIENTMENUMANAGER = {
|
||||||
ClassName = "CLIENTMENUMANAGER",
|
ClassName = "CLIENTMENUMANAGER",
|
||||||
lid = "",
|
lid = "",
|
||||||
version = "0.1.4",
|
version = "0.1.5a",
|
||||||
name = nil,
|
name = nil,
|
||||||
clientset = nil,
|
clientset = nil,
|
||||||
menutree = {},
|
menutree = {},
|
||||||
@@ -492,7 +513,7 @@ function CLIENTMENUMANAGER:_EventHandler(EventData)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set this Client Manager to auto-propagate menus to newly joined players. Useful if you have **one** menu structure only.
|
--- Set this Client Manager to auto-propagate menus **once** to newly joined players. Useful if you have **one** menu structure only. Does not automatically push follow-up changes to the client(s).
|
||||||
-- @param #CLIENTMENUMANAGER self
|
-- @param #CLIENTMENUMANAGER self
|
||||||
-- @return #CLIENTMENUMANAGER self
|
-- @return #CLIENTMENUMANAGER self
|
||||||
function CLIENTMENUMANAGER:InitAutoPropagation()
|
function CLIENTMENUMANAGER:InitAutoPropagation()
|
||||||
@@ -507,7 +528,7 @@ function CLIENTMENUMANAGER:InitAutoPropagation()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a new entry in the generic structure.
|
--- Create a new entry in the **generic** structure.
|
||||||
-- @param #CLIENTMENUMANAGER self
|
-- @param #CLIENTMENUMANAGER self
|
||||||
-- @param #string Text Text of the F10 menu entry.
|
-- @param #string Text Text of the F10 menu entry.
|
||||||
-- @param #CLIENTMENU Parent The parent menu entry.
|
-- @param #CLIENTMENU Parent The parent menu entry.
|
||||||
@@ -660,6 +681,7 @@ end
|
|||||||
function CLIENTMENUMANAGER:Propagate(Client)
|
function CLIENTMENUMANAGER:Propagate(Client)
|
||||||
self:T(self.lid.."Propagate")
|
self:T(self.lid.."Propagate")
|
||||||
--self:I(UTILS.PrintTableToLog(Client,1))
|
--self:I(UTILS.PrintTableToLog(Client,1))
|
||||||
|
local knownunits = {} -- track so we can ID multi seated
|
||||||
local Set = self.clientset.Set
|
local Set = self.clientset.Set
|
||||||
if Client then
|
if Client then
|
||||||
Set = {Client}
|
Set = {Client}
|
||||||
@@ -668,34 +690,42 @@ function CLIENTMENUMANAGER:Propagate(Client)
|
|||||||
for _,_client in pairs(Set) do
|
for _,_client in pairs(Set) do
|
||||||
local client = _client -- Wrapper.Client#CLIENT
|
local client = _client -- Wrapper.Client#CLIENT
|
||||||
if client and client:IsAlive() then
|
if client and client:IsAlive() then
|
||||||
|
local playerunit = client:GetName()
|
||||||
|
--local playergroup = client:GetGroup()
|
||||||
local playername = client:GetPlayerName() or "none"
|
local playername = client:GetPlayerName() or "none"
|
||||||
if not self.playertree[playername] then
|
if not knownunits[playerunit] then
|
||||||
self.playertree[playername] = {}
|
knownunits[playerunit] = true
|
||||||
end
|
else
|
||||||
for level,branch in pairs (self.menutree) do
|
self:I("Player in multi seat unit: "..playername)
|
||||||
self:T("Building branch:" .. level)
|
break -- multi seat already build
|
||||||
for _,leaf in pairs(branch) do
|
end
|
||||||
self:T("Building leaf:" .. leaf)
|
if not self.playertree[playername] then
|
||||||
local entry = self:FindEntryByUUID(leaf)
|
self.playertree[playername] = {}
|
||||||
if entry then
|
end
|
||||||
self:T("Found generic entry:" .. entry.UUID)
|
for level,branch in pairs (self.menutree) do
|
||||||
local parent = nil
|
self:T("Building branch:" .. level)
|
||||||
if entry.Parent and entry.Parent.UUID then
|
for _,leaf in pairs(branch) do
|
||||||
parent = self.playertree[playername][entry.Parent.UUID] or self:FindEntryByUUID(entry.Parent.UUID)
|
self:T("Building leaf:" .. leaf)
|
||||||
end
|
local entry = self:FindEntryByUUID(leaf)
|
||||||
self.playertree[playername][entry.UUID] = CLIENTMENU:NewEntry(client,entry.name,parent,entry.Function,unpack(entry.Functionargs))
|
if entry then
|
||||||
self.playertree[playername][entry.UUID].Once = entry.Once
|
self:T("Found generic entry:" .. entry.UUID)
|
||||||
else
|
local parent = nil
|
||||||
self:T("NO generic entry for:" .. leaf)
|
if entry.Parent and entry.Parent.UUID then
|
||||||
|
parent = self.playertree[playername][entry.Parent.UUID] or self:FindEntryByUUID(entry.Parent.UUID)
|
||||||
end
|
end
|
||||||
|
self.playertree[playername][entry.UUID] = CLIENTMENU:NewEntry(client,entry.name,parent,entry.Function,unpack(entry.Functionargs))
|
||||||
|
self.playertree[playername][entry.UUID].Once = entry.Once
|
||||||
|
else
|
||||||
|
self:T("NO generic entry for:" .. leaf)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Push a single previously created entry into the menu structure of all clients.
|
--- Push a single previously created entry into the F10 menu structure of all clients.
|
||||||
-- @param #CLIENTMENUMANAGER self
|
-- @param #CLIENTMENUMANAGER self
|
||||||
-- @param #CLIENTMENU Entry The entry to add.
|
-- @param #CLIENTMENU Entry The entry to add.
|
||||||
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client.
|
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client.
|
||||||
@@ -703,6 +733,7 @@ end
|
|||||||
function CLIENTMENUMANAGER:AddEntry(Entry,Client)
|
function CLIENTMENUMANAGER:AddEntry(Entry,Client)
|
||||||
self:T(self.lid.."AddEntry")
|
self:T(self.lid.."AddEntry")
|
||||||
local Set = self.clientset.Set
|
local Set = self.clientset.Set
|
||||||
|
local knownunits = {}
|
||||||
if Client then
|
if Client then
|
||||||
Set = {Client}
|
Set = {Client}
|
||||||
end
|
end
|
||||||
@@ -710,6 +741,13 @@ function CLIENTMENUMANAGER:AddEntry(Entry,Client)
|
|||||||
local client = _client -- Wrapper.Client#CLIENT
|
local client = _client -- Wrapper.Client#CLIENT
|
||||||
if client and client:IsAlive() then
|
if client and client:IsAlive() then
|
||||||
local playername = client:GetPlayerName()
|
local playername = client:GetPlayerName()
|
||||||
|
local unitname = client:GetName()
|
||||||
|
if not knownunits[unitname] then
|
||||||
|
knownunits[unitname] = true
|
||||||
|
else
|
||||||
|
self:I("Player in multi seat unit: "..playername)
|
||||||
|
break
|
||||||
|
end
|
||||||
if Entry then
|
if Entry then
|
||||||
self:T("Adding generic entry:" .. Entry.UUID)
|
self:T("Adding generic entry:" .. Entry.UUID)
|
||||||
local parent = nil
|
local parent = nil
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
-- @field #table Templates Templates: Units, Groups, Statics, ClientsByName, ClientsByID.
|
-- @field #table Templates Templates: Units, Groups, Statics, ClientsByName, ClientsByID.
|
||||||
-- @field #table CLIENTS Clients.
|
-- @field #table CLIENTS Clients.
|
||||||
-- @field #table STORAGES DCS warehouse storages.
|
-- @field #table STORAGES DCS warehouse storages.
|
||||||
|
-- @field #table STNS Used Link16 octal numbers for F16/15/18/AWACS planes.
|
||||||
|
-- @field #table SADL Used Link16 octal numbers for A10/C-II planes.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
|
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
|
||||||
@@ -93,6 +95,8 @@ DATABASE = {
|
|||||||
OPSZONES = {},
|
OPSZONES = {},
|
||||||
PATHLINES = {},
|
PATHLINES = {},
|
||||||
STORAGES = {},
|
STORAGES = {},
|
||||||
|
STNS={},
|
||||||
|
SADL={},
|
||||||
}
|
}
|
||||||
|
|
||||||
local _DATABASECoalition =
|
local _DATABASECoalition =
|
||||||
@@ -928,7 +932,7 @@ function DATABASE:Spawn( SpawnTemplate )
|
|||||||
SpawnTemplate.CountryID = nil
|
SpawnTemplate.CountryID = nil
|
||||||
SpawnTemplate.CategoryID = nil
|
SpawnTemplate.CategoryID = nil
|
||||||
|
|
||||||
self:_RegisterGroupTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID )
|
self:_RegisterGroupTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID, SpawnTemplate.name )
|
||||||
|
|
||||||
self:T3( SpawnTemplate )
|
self:T3( SpawnTemplate )
|
||||||
coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate )
|
coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate )
|
||||||
@@ -1030,6 +1034,27 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
|||||||
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
|
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if UnitTemplate.AddPropAircraft then
|
||||||
|
if UnitTemplate.AddPropAircraft.STN_L16 then
|
||||||
|
local stn = UTILS.OctalToDecimal(UnitTemplate.AddPropAircraft.STN_L16)
|
||||||
|
if stn == nil or stn < 1 then
|
||||||
|
self:E("WARNING: Invalid STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||||
|
else
|
||||||
|
self.STNS[stn] = UnitTemplate.name
|
||||||
|
self:I("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if UnitTemplate.AddPropAircraft.SADL_TN then
|
||||||
|
local sadl = UTILS.OctalToDecimal(UnitTemplate.AddPropAircraft.SADL_TN)
|
||||||
|
if sadl == nil or sadl < 1 then
|
||||||
|
self:E("WARNING: Invalid SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||||
|
else
|
||||||
|
self.SADL[sadl] = UnitTemplate.name
|
||||||
|
self:I("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1043,15 +1068,92 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get next (consecutive) free STN as octal number.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #number octal Starting octal.
|
||||||
|
-- @param #string unitname Name of the associated unit.
|
||||||
|
-- @return #number Octal
|
||||||
|
function DATABASE:GetNextSTN(octal,unitname)
|
||||||
|
local first = UTILS.OctalToDecimal(octal) or 0
|
||||||
|
if self.STNS[first] == unitname then return octal end
|
||||||
|
local nextoctal = 77777
|
||||||
|
local found = false
|
||||||
|
if 32767-first < 10 then
|
||||||
|
first = 0
|
||||||
|
end
|
||||||
|
for i=first+1,32767 do
|
||||||
|
if self.STNS[i] == nil then
|
||||||
|
found = true
|
||||||
|
nextoctal = UTILS.DecimalToOctal(i)
|
||||||
|
self.STNS[i] = unitname
|
||||||
|
self:T("Register STN "..tostring(nextoctal).." for ".. unitname)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not found then
|
||||||
|
self:E(string.format("WARNING: No next free STN past %05d found!",octal))
|
||||||
|
-- cleanup
|
||||||
|
local NewSTNS = {}
|
||||||
|
for _id,_name in pairs(self.STNS) do
|
||||||
|
if self.UNITS[_name] ~= nil then
|
||||||
|
NewSTNS[_id] = _name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.STNS = nil
|
||||||
|
self.STNS = NewSTNS
|
||||||
|
end
|
||||||
|
return nextoctal
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get next (consecutive) free SADL as octal number.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #number octal Starting octal.
|
||||||
|
-- @param #string unitname Name of the associated unit.
|
||||||
|
-- @return #number Octal
|
||||||
|
function DATABASE:GetNextSADL(octal,unitname)
|
||||||
|
local first = UTILS.OctalToDecimal(octal) or 0
|
||||||
|
if self.SADL[first] == unitname then return octal end
|
||||||
|
local nextoctal = 7777
|
||||||
|
local found = false
|
||||||
|
if 4095-first < 10 then
|
||||||
|
first = 0
|
||||||
|
end
|
||||||
|
for i=first+1,4095 do
|
||||||
|
if self.STNS[i] == nil then
|
||||||
|
found = true
|
||||||
|
nextoctal = UTILS.DecimalToOctal(i)
|
||||||
|
self.SADL[i] = unitname
|
||||||
|
self:T("Register SADL "..tostring(nextoctal).." for ".. unitname)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not found then
|
||||||
|
self:E(string.format("WARNING: No next free SADL past %04d found!",octal))
|
||||||
|
-- cleanup
|
||||||
|
local NewSTNS = {}
|
||||||
|
for _id,_name in pairs(self.SADL) do
|
||||||
|
if self.UNITS[_name] ~= nil then
|
||||||
|
NewSTNS[_id] = _name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.SADL = nil
|
||||||
|
self.SADL = NewSTNS
|
||||||
|
end
|
||||||
|
return nextoctal
|
||||||
|
end
|
||||||
|
|
||||||
--- Get group template.
|
--- Get group template.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param #string GroupName Group name.
|
-- @param #string GroupName Group name.
|
||||||
-- @return #table Group template table.
|
-- @return #table Group template table.
|
||||||
function DATABASE:GetGroupTemplate( GroupName )
|
function DATABASE:GetGroupTemplate( GroupName )
|
||||||
local GroupTemplate = self.Templates.Groups[GroupName].Template
|
local GroupTemplate=nil
|
||||||
GroupTemplate.SpawnCoalitionID = self.Templates.Groups[GroupName].CoalitionID
|
if self.Templates.Groups[GroupName] then
|
||||||
GroupTemplate.SpawnCategoryID = self.Templates.Groups[GroupName].CategoryID
|
GroupTemplate = self.Templates.Groups[GroupName].Template
|
||||||
GroupTemplate.SpawnCountryID = self.Templates.Groups[GroupName].CountryID
|
GroupTemplate.SpawnCoalitionID = self.Templates.Groups[GroupName].CoalitionID
|
||||||
|
GroupTemplate.SpawnCategoryID = self.Templates.Groups[GroupName].CategoryID
|
||||||
|
GroupTemplate.SpawnCountryID = self.Templates.Groups[GroupName].CountryID
|
||||||
|
end
|
||||||
return GroupTemplate
|
return GroupTemplate
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1586,7 +1688,7 @@ function DATABASE:_EventOnPlayerLeaveUnit( Event )
|
|||||||
if Event.IniObjectCategory == 1 then
|
if Event.IniObjectCategory == 1 then
|
||||||
|
|
||||||
-- Try to get the player name. This can be buggy for multicrew aircraft!
|
-- Try to get the player name. This can be buggy for multicrew aircraft!
|
||||||
local PlayerName = Event.IniUnit:GetPlayerName() or FindPlayerName(Event.IniUnitName)
|
local PlayerName = Event.IniPlayerName or Event.IniUnit:GetPlayerName() or FindPlayerName(Event.IniUnitName)
|
||||||
|
|
||||||
if PlayerName then
|
if PlayerName then
|
||||||
|
|
||||||
|
|||||||
@@ -1301,7 +1301,7 @@ function EVENT:onEvent( Event )
|
|||||||
-- STATIC
|
-- STATIC
|
||||||
---
|
---
|
||||||
Event.TgtDCSUnit = Event.target
|
Event.TgtDCSUnit = Event.target
|
||||||
if Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object
|
if Event.target.isExist and Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object, check that isExist exists (Kiowa Hellfire issue, Special K)
|
||||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
||||||
-- Workaround for borked target info on cruise missiles
|
-- Workaround for borked target info on cruise missiles
|
||||||
if Event.TgtDCSUnitName and Event.TgtDCSUnitName ~= "" then
|
if Event.TgtDCSUnitName and Event.TgtDCSUnitName ~= "" then
|
||||||
@@ -1378,6 +1378,7 @@ function EVENT:onEvent( Event )
|
|||||||
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
|
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
|
||||||
Event.MarkText=Event.text
|
Event.MarkText=Event.text
|
||||||
Event.MarkCoalition=Event.coalition
|
Event.MarkCoalition=Event.coalition
|
||||||
|
Event.IniCoalition=Event.coalition
|
||||||
Event.MarkGroupID = Event.groupID
|
Event.MarkGroupID = Event.groupID
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
-- ### Author: **Applevangelist**
|
-- ### Author: **Applevangelist**
|
||||||
--
|
--
|
||||||
-- Date: 5 May 2021
|
-- Date: 5 May 2021
|
||||||
-- Last Update: Feb 2023
|
-- Last Update: Mar 2023
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
---
|
---
|
||||||
@@ -50,7 +50,7 @@ MARKEROPS_BASE = {
|
|||||||
ClassName = "MARKEROPS",
|
ClassName = "MARKEROPS",
|
||||||
Tag = "mytag",
|
Tag = "mytag",
|
||||||
Keywords = {},
|
Keywords = {},
|
||||||
version = "0.1.1",
|
version = "0.1.3",
|
||||||
debug = false,
|
debug = false,
|
||||||
Casesensitive = true,
|
Casesensitive = true,
|
||||||
}
|
}
|
||||||
@@ -114,6 +114,8 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
|||||||
-- @param #string Text The text on the marker
|
-- @param #string Text The text on the marker
|
||||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
|
-- @param #number MarkerID Id of this marker
|
||||||
|
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||||
|
|
||||||
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
||||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
|
||||||
@@ -124,7 +126,8 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
|||||||
-- @param #string Text The text on the marker
|
-- @param #string Text The text on the marker
|
||||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
-- @param #number idx DCS Marker ID
|
-- @param #number MarkerID Id of this marker
|
||||||
|
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||||
|
|
||||||
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
|
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
|
||||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
|
||||||
@@ -133,7 +136,7 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
|||||||
-- @param #string Event The Event called
|
-- @param #string Event The Event called
|
||||||
-- @param #string To The To state
|
-- @param #string To The To state
|
||||||
|
|
||||||
--- "Stop" trigger. Used to stop the function an unhandle events
|
--- "Stop" trigger. Used to stop the function an unhandle events
|
||||||
-- @function [parent=#MARKEROPS_BASE] Stop
|
-- @function [parent=#MARKEROPS_BASE] Stop
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -155,29 +158,30 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
|||||||
local text = tostring(Event.text)
|
local text = tostring(Event.text)
|
||||||
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||||
end
|
end
|
||||||
|
local coalition = Event.MarkCoalition
|
||||||
-- decision
|
-- decision
|
||||||
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
||||||
self:T({event="S_EVENT_MARK_ADDED", carrier=self.groupname, vec3=Event.pos})
|
self:T({event="S_EVENT_MARK_ADDED", carrier=Event.IniGroupName, vec3=Event.pos})
|
||||||
-- Handle event
|
-- Handle event
|
||||||
local Eventtext = tostring(Event.text)
|
local Eventtext = tostring(Event.text)
|
||||||
if Eventtext~=nil then
|
if Eventtext~=nil then
|
||||||
if self:_MatchTag(Eventtext) then
|
if self:_MatchTag(Eventtext) then
|
||||||
local matchtable = self:_MatchKeywords(Eventtext)
|
local matchtable = self:_MatchKeywords(Eventtext)
|
||||||
self:MarkAdded(Eventtext,matchtable,coord)
|
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
||||||
self:T({event="S_EVENT_MARK_CHANGE", carrier=self.groupname, vec3=Event.pos})
|
self:T({event="S_EVENT_MARK_CHANGE", carrier=Event.IniGroupName, vec3=Event.pos})
|
||||||
-- Handle event.
|
-- Handle event.
|
||||||
local Eventtext = tostring(Event.text)
|
local Eventtext = tostring(Event.text)
|
||||||
if Eventtext~=nil then
|
if Eventtext~=nil then
|
||||||
if self:_MatchTag(Eventtext) then
|
if self:_MatchTag(Eventtext) then
|
||||||
local matchtable = self:_MatchKeywords(Eventtext)
|
local matchtable = self:_MatchKeywords(Eventtext)
|
||||||
self:MarkChanged(Eventtext,matchtable,coord,Event.idx)
|
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||||
self:T({event="S_EVENT_MARK_REMOVED", carrier=self.groupname, vec3=Event.pos})
|
self:T({event="S_EVENT_MARK_REMOVED", carrier=Event.IniGroupName, vec3=Event.pos})
|
||||||
-- Hande event.
|
-- Hande event.
|
||||||
local Eventtext = tostring(Event.text)
|
local Eventtext = tostring(Event.text)
|
||||||
if Eventtext~=nil then
|
if Eventtext~=nil then
|
||||||
@@ -230,8 +234,10 @@ end
|
|||||||
-- @param #string To The To state
|
-- @param #string To The To state
|
||||||
-- @param #string Text The text on the marker
|
-- @param #string Text The text on the marker
|
||||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
|
-- @param #number MarkerID Id of this marker
|
||||||
|
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord)
|
function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord,MarkerID,CoalitionNumber)
|
||||||
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -242,8 +248,10 @@ end
|
|||||||
-- @param #string To The To state
|
-- @param #string To The To state
|
||||||
-- @param #string Text The text on the marker
|
-- @param #string Text The text on the marker
|
||||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
|
-- @param #number MarkerID Id of this marker
|
||||||
|
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord)
|
function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord,MarkerID,CoalitionNumber)
|
||||||
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- * Setup mission sub menus.
|
-- * Setup mission sub menus.
|
||||||
-- * Setup mission command menus.
|
-- * Setup mission command menus.
|
||||||
@@ -44,7 +44,11 @@
|
|||||||
-- * @{Core.Menu#MENU_GROUP_COMMAND}: Manages command menus for GROUPs.
|
-- * @{Core.Menu#MENU_GROUP_COMMAND}: Manages command menus for GROUPs.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
---
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Core/Menu)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
@@ -166,7 +170,8 @@ function MENU_INDEX:Refresh( Group )
|
|||||||
end
|
end
|
||||||
|
|
||||||
do -- MENU_BASE
|
do -- MENU_BASE
|
||||||
--- @type MENU_BASE
|
---
|
||||||
|
-- @type MENU_BASE
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
--- Defines the main MENU class where other MENU classes are derived from.
|
--- Defines the main MENU class where other MENU classes are derived from.
|
||||||
-- This is an abstract class, so don't use it.
|
-- This is an abstract class, so don't use it.
|
||||||
@@ -206,6 +211,7 @@ do -- MENU_BASE
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_BASE:SetParentMenu( MenuText, Menu )
|
function MENU_BASE:SetParentMenu( MenuText, Menu )
|
||||||
if self.ParentMenu then
|
if self.ParentMenu then
|
||||||
self.ParentMenu.Menus = self.ParentMenu.Menus or {}
|
self.ParentMenu.Menus = self.ParentMenu.Menus or {}
|
||||||
@@ -277,8 +283,10 @@ do -- MENU_BASE
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
do -- MENU_COMMAND_BASE
|
do
|
||||||
--- @type MENU_COMMAND_BASE
|
---
|
||||||
|
-- MENU_COMMAND_BASE
|
||||||
|
-- @type MENU_COMMAND_BASE
|
||||||
-- @field #function MenuCallHandler
|
-- @field #function MenuCallHandler
|
||||||
-- @extends Core.Menu#MENU_BASE
|
-- @extends Core.Menu#MENU_BASE
|
||||||
|
|
||||||
@@ -343,8 +351,10 @@ do -- MENU_COMMAND_BASE
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- MENU_MISSION
|
do
|
||||||
--- @type MENU_MISSION
|
---
|
||||||
|
-- MENU_MISSION
|
||||||
|
-- @type MENU_MISSION
|
||||||
-- @extends Core.Menu#MENU_BASE
|
-- @extends Core.Menu#MENU_BASE
|
||||||
--- Manages the main menus for a complete mission.
|
--- Manages the main menus for a complete mission.
|
||||||
--
|
--
|
||||||
@@ -509,8 +519,9 @@ do -- MENU_MISSION_COMMAND
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
do -- MENU_COALITION
|
do
|
||||||
--- @type MENU_COALITION
|
--- MENU_COALITION
|
||||||
|
-- @type MENU_COALITION
|
||||||
-- @extends Core.Menu#MENU_BASE
|
-- @extends Core.Menu#MENU_BASE
|
||||||
|
|
||||||
--- Manages the main menus for DCS.coalition.
|
--- Manages the main menus for DCS.coalition.
|
||||||
@@ -635,9 +646,10 @@ do -- MENU_COALITION
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
do -- MENU_COALITION_COMMAND
|
do
|
||||||
|
|
||||||
--- @type MENU_COALITION_COMMAND
|
--- MENU_COALITION_COMMAND
|
||||||
|
-- @type MENU_COALITION_COMMAND
|
||||||
-- @extends Core.Menu#MENU_COMMAND_BASE
|
-- @extends Core.Menu#MENU_COMMAND_BASE
|
||||||
|
|
||||||
--- Manages the command menus for coalitions, which allow players to execute functions during mission execution.
|
--- Manages the command menus for coalitions, which allow players to execute functions during mission execution.
|
||||||
@@ -725,8 +737,11 @@ do
|
|||||||
-- So every menu for a client created must be tracked so that program logic accidentally does not create.
|
-- So every menu for a client created must be tracked so that program logic accidentally does not create.
|
||||||
-- the same menus twice during initialization logic.
|
-- the same menus twice during initialization logic.
|
||||||
-- These menu classes are handling this logic with this variable.
|
-- These menu classes are handling this logic with this variable.
|
||||||
|
|
||||||
local _MENUGROUPS = {}
|
local _MENUGROUPS = {}
|
||||||
--- @type MENU_GROUP
|
|
||||||
|
---
|
||||||
|
-- @type MENU_GROUP
|
||||||
-- @extends Core.Menu#MENU_BASE
|
-- @extends Core.Menu#MENU_BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -757,7 +772,7 @@ do
|
|||||||
-- MenuStatus[MenuGroupName]:Remove()
|
-- MenuStatus[MenuGroupName]:Remove()
|
||||||
-- end
|
-- end
|
||||||
--
|
--
|
||||||
-- --- @param Wrapper.Group#GROUP MenuGroup
|
-- -- @param Wrapper.Group#GROUP MenuGroup
|
||||||
-- local function AddStatusMenu( MenuGroup )
|
-- local function AddStatusMenu( MenuGroup )
|
||||||
-- local MenuGroupName = MenuGroup:GetName()
|
-- local MenuGroupName = MenuGroup:GetName()
|
||||||
-- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object.
|
-- -- This would create a menu for the red coalition under the MenuCoalitionRed menu object.
|
||||||
@@ -899,8 +914,8 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---
|
||||||
--- @type MENU_GROUP_COMMAND
|
-- @type MENU_GROUP_COMMAND
|
||||||
-- @extends Core.Menu#MENU_COMMAND_BASE
|
-- @extends Core.Menu#MENU_COMMAND_BASE
|
||||||
|
|
||||||
--- The @{Core.Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution.
|
--- The @{Core.Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution.
|
||||||
@@ -983,7 +998,8 @@ do
|
|||||||
end
|
end
|
||||||
--- MENU_GROUP_DELAYED
|
--- MENU_GROUP_DELAYED
|
||||||
do
|
do
|
||||||
--- @type MENU_GROUP_DELAYED
|
---
|
||||||
|
-- @type MENU_GROUP_DELAYED
|
||||||
-- @extends Core.Menu#MENU_BASE
|
-- @extends Core.Menu#MENU_BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -1034,6 +1050,7 @@ do
|
|||||||
-- @param #MENU_GROUP_DELAYED self
|
-- @param #MENU_GROUP_DELAYED self
|
||||||
-- @return #MENU_GROUP_DELAYED
|
-- @return #MENU_GROUP_DELAYED
|
||||||
function MENU_GROUP_DELAYED:Set()
|
function MENU_GROUP_DELAYED:Set()
|
||||||
|
if not self.GroupID then return end
|
||||||
do
|
do
|
||||||
if not self.MenuSet then
|
if not self.MenuSet then
|
||||||
missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath )
|
missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath )
|
||||||
@@ -1106,8 +1123,8 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---
|
||||||
--- @type MENU_GROUP_COMMAND_DELAYED
|
-- @type MENU_GROUP_COMMAND_DELAYED
|
||||||
-- @extends Core.Menu#MENU_COMMAND_BASE
|
-- @extends Core.Menu#MENU_COMMAND_BASE
|
||||||
|
|
||||||
--- Manages the command menus for coalitions, which allow players to execute functions during mission execution.
|
--- Manages the command menus for coalitions, which allow players to execute functions during mission execution.
|
||||||
|
|||||||
@@ -395,29 +395,36 @@ 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.
|
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
|
||||||
-- @return #MESSAGE
|
-- @param #number Delay (Optional) Delay in seconds before the message is send. Default instantly (`nil`).
|
||||||
|
-- @return #MESSAGE self
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Send a message created to all players.
|
-- -- Send a message created to all players.
|
||||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 ):ToAll()
|
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 ):ToAll()
|
||||||
-- or
|
-- or
|
||||||
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 ):ToAll()
|
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 ):ToAll()
|
||||||
-- or
|
-- or
|
||||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 )
|
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 )
|
||||||
-- MessageAll:ToAll()
|
-- MessageAll:ToAll()
|
||||||
--
|
--
|
||||||
function MESSAGE:ToAll( Settings )
|
function MESSAGE:ToAll( Settings, Delay )
|
||||||
self:F()
|
self:F()
|
||||||
|
|
||||||
if self.MessageType then
|
if Delay and Delay>0 then
|
||||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
self:ScheduleOnce(Delay, MESSAGE.ToAll, self, Settings, 0)
|
||||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
else
|
||||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
|
||||||
end
|
if self.MessageType then
|
||||||
|
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.MessageDuration ~= 0 then
|
||||||
|
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
|
||||||
|
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
||||||
|
end
|
||||||
|
|
||||||
if self.MessageDuration ~= 0 then
|
|
||||||
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
|
|
||||||
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -509,10 +516,10 @@ function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,G
|
|||||||
end
|
end
|
||||||
|
|
||||||
_MESSAGESRS.label = Label or MSRS.Label or "MESSAGE"
|
_MESSAGESRS.label = Label or MSRS.Label or "MESSAGE"
|
||||||
_MESSAGESRS.MSRS:SetLabel(Label or "MESSAGE")
|
_MESSAGESRS.MSRS:SetLabel(_MESSAGESRS.label)
|
||||||
|
|
||||||
_MESSAGESRS.port = Port or MSRS.port or 5002
|
_MESSAGESRS.port = Port or MSRS.port or 5002
|
||||||
_MESSAGESRS.MSRS:SetPort(Port or 5002)
|
_MESSAGESRS.MSRS:SetPort(_MESSAGESRS.port)
|
||||||
|
|
||||||
_MESSAGESRS.volume = Volume or MSRS.volume or 1
|
_MESSAGESRS.volume = Volume or MSRS.volume or 1
|
||||||
_MESSAGESRS.MSRS:SetVolume(_MESSAGESRS.volume)
|
_MESSAGESRS.MSRS:SetVolume(_MESSAGESRS.volume)
|
||||||
|
|||||||
@@ -703,6 +703,7 @@ do -- COORDINATE
|
|||||||
-- @return DCS#Distance The distance from the reference @{#COORDINATE} in meters.
|
-- @return DCS#Distance The distance from the reference @{#COORDINATE} in meters.
|
||||||
function COORDINATE:DistanceFromPointVec2( PointVec2Reference )
|
function COORDINATE:DistanceFromPointVec2( PointVec2Reference )
|
||||||
self:F2( PointVec2Reference )
|
self:F2( PointVec2Reference )
|
||||||
|
if not PointVec2Reference then return math.huge end
|
||||||
|
|
||||||
local Distance = ( ( PointVec2Reference.x - self.x ) ^ 2 + ( PointVec2Reference.z - self.z ) ^2 ) ^ 0.5
|
local Distance = ( ( PointVec2Reference.x - self.x ) ^ 2 + ( PointVec2Reference.z - self.z ) ^2 ) ^ 0.5
|
||||||
|
|
||||||
@@ -3147,17 +3148,18 @@ do -- COORDINATE
|
|||||||
-- @param #string Northing Meters northing - string in order to allow for leading zeros, e.g. "12340". Should be 5 digits.
|
-- @param #string Northing Meters northing - string in order to allow for leading zeros, e.g. "12340". Should be 5 digits.
|
||||||
-- @return #COORDINATE self
|
-- @return #COORDINATE self
|
||||||
function COORDINATE:NewFromMGRS( UTMZone, MGRSDigraph, Easting, Northing )
|
function COORDINATE:NewFromMGRS( UTMZone, MGRSDigraph, Easting, Northing )
|
||||||
if string.len(Easting) < 5 then Easting = Easting..string.rep("0",5-string.len(Easting) )end
|
if string.len(Easting) < 5 then Easting = tostring(Easting..string.rep("0",5-string.len(Easting) )) end
|
||||||
if string.len(Northing) < 5 then Northing = Northing..string.rep("0",5-string.len(Northing) )end
|
if string.len(Northing) < 5 then Northing = tostring(Northing..string.rep("0",5-string.len(Northing) )) end
|
||||||
local MGRS = {
|
local MGRS = {
|
||||||
UTMZone = UTMZone,
|
UTMZone = UTMZone,
|
||||||
MGRSDigraph = MGRSDigraph,
|
MGRSDigraph = MGRSDigraph,
|
||||||
Easting = Easting,
|
Easting = tostring(Easting),
|
||||||
Northing = Northing,
|
Northing = tostring(Northing),
|
||||||
}
|
}
|
||||||
local lat, lon = coord.MGRStoLL(MGRS)
|
local lat, lon = coord.MGRStoLL(MGRS)
|
||||||
local point = coord.LLtoLO(lat, lon, 0)
|
local point = coord.LLtoLO(lat, lon, 0)
|
||||||
local coord = COORDINATE:NewFromVec2({x=point.x,y=point.z})
|
local coord = COORDINATE:NewFromVec2({x=point.x,y=point.z})
|
||||||
|
return coord
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Provides a coordinate string of the point, based on a coordinate format system:
|
--- Provides a coordinate string of the point, based on a coordinate format system:
|
||||||
|
|||||||
@@ -1097,6 +1097,7 @@ do
|
|||||||
GroupPrefixes = nil,
|
GroupPrefixes = nil,
|
||||||
Zones = nil,
|
Zones = nil,
|
||||||
Functions = nil,
|
Functions = nil,
|
||||||
|
Alive = nil,
|
||||||
},
|
},
|
||||||
FilterMeta = {
|
FilterMeta = {
|
||||||
Coalitions = {
|
Coalitions = {
|
||||||
@@ -1470,7 +1471,7 @@ do
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Builds a set of groups that are only active.
|
--- Builds a set of groups that are active, ie in the mission but not yet activated (false) or actived (true).
|
||||||
-- Only the groups that are active will be included within the set.
|
-- Only the groups that are active will be included within the set.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param #boolean Active (Optional) Include only active groups to the set.
|
-- @param #boolean Active (Optional) Include only active groups to the set.
|
||||||
@@ -1496,6 +1497,14 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Build a set of groups that are alive.
|
||||||
|
-- @param #SET_GROUP self
|
||||||
|
-- @return #SET_GROUP self
|
||||||
|
function SET_GROUP:FilterAlive()
|
||||||
|
self.Filter.Alive = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Starts the filtering.
|
--- Starts the filtering.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @return #SET_GROUP self
|
-- @return #SET_GROUP self
|
||||||
@@ -1507,6 +1516,7 @@ do
|
|||||||
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.RemoveUnit, self._EventOnDeadOrCrash )
|
||||||
|
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnDeadOrCrash )
|
||||||
if self.Filter.Zones then
|
if self.Filter.Zones then
|
||||||
self.ZoneTimer = TIMER:New(self._ContinousZoneFilter,self)
|
self.ZoneTimer = TIMER:New(self._ContinousZoneFilter,self)
|
||||||
local timing = self.ZoneTimerInterval or 30
|
local timing = self.ZoneTimerInterval or 30
|
||||||
@@ -1994,6 +2004,15 @@ do
|
|||||||
self:F2( MGroup )
|
self:F2( MGroup )
|
||||||
local MGroupInclude = true
|
local MGroupInclude = true
|
||||||
|
|
||||||
|
if self.Filter.Alive == true then
|
||||||
|
local MGroupAlive = false
|
||||||
|
self:F( { Active = self.Filter.Active } )
|
||||||
|
if MGroup and MGroup:IsAlive() then
|
||||||
|
MGroupAlive = true
|
||||||
|
end
|
||||||
|
MGroupInclude = MGroupInclude and MGroupAlive
|
||||||
|
end
|
||||||
|
|
||||||
if self.Filter.Active ~= nil then
|
if self.Filter.Active ~= nil then
|
||||||
local MGroupActive = false
|
local MGroupActive = false
|
||||||
self:F( { Active = self.Filter.Active } )
|
self:F( { Active = self.Filter.Active } )
|
||||||
@@ -2997,7 +3016,7 @@ do -- SET_UNIT
|
|||||||
local velocity = self:GetVelocity() or 0
|
local velocity = self:GetVelocity() or 0
|
||||||
Coordinate:SetHeading( heading )
|
Coordinate:SetHeading( heading )
|
||||||
Coordinate:SetVelocity( velocity )
|
Coordinate:SetVelocity( velocity )
|
||||||
self:I(UTILS.PrintTableToLog(Coordinate))
|
self:T(UTILS.PrintTableToLog(Coordinate))
|
||||||
end
|
end
|
||||||
|
|
||||||
return Coordinate
|
return Coordinate
|
||||||
@@ -3459,7 +3478,7 @@ do -- SET_STATIC
|
|||||||
|
|
||||||
--- Add STATIC(s) to SET_STATIC.
|
--- Add STATIC(s) to SET_STATIC.
|
||||||
-- @param #SET_STATIC self
|
-- @param #SET_STATIC self
|
||||||
-- @param #string AddStatic A single STATIC.
|
-- @param Wrapper.Static#STATIC AddStatic A single STATIC.
|
||||||
-- @return #SET_STATIC self
|
-- @return #SET_STATIC self
|
||||||
function SET_STATIC:AddStatic( AddStatic )
|
function SET_STATIC:AddStatic( AddStatic )
|
||||||
self:F2( AddStatic:GetName() )
|
self:F2( AddStatic:GetName() )
|
||||||
@@ -4370,8 +4389,8 @@ do -- SET_CLIENT
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Builds a set of CLIENTs that contain the given string in their unit/pilot name.
|
--- Builds a set of CLIENTs that contain the given string in their **unit/pilot** name and **NOT** the group name!
|
||||||
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all clients that **contain** the string.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all clients that **contain** the string. Pattern matching applies.
|
||||||
-- @param #SET_CLIENT self
|
-- @param #SET_CLIENT self
|
||||||
-- @param #string Prefixes The string pattern(s) that needs to be contained in the unit/pilot name. Can also be passed as a `#table` of strings.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the unit/pilot name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_CLIENT self
|
-- @return #SET_CLIENT self
|
||||||
@@ -4521,7 +4540,7 @@ do -- SET_CLIENT
|
|||||||
if Event.IniObjectCategory == Object.Category.UNIT and Event.IniGroup and Event.IniGroup:IsGround() then
|
if Event.IniObjectCategory == Object.Category.UNIT and Event.IniGroup and Event.IniGroup:IsGround() then
|
||||||
-- CA Slot entered
|
-- CA Slot entered
|
||||||
local ObjectName, Object = self:AddInDatabase( Event )
|
local ObjectName, Object = self:AddInDatabase( Event )
|
||||||
self:I( ObjectName, UTILS.PrintTableToLog(Object) )
|
self:T( ObjectName, UTILS.PrintTableToLog(Object) )
|
||||||
if Object and self:IsIncludeObject( Object ) then
|
if Object and self:IsIncludeObject( Object ) then
|
||||||
self:Add( ObjectName, Object )
|
self:Add( ObjectName, Object )
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -200,6 +200,22 @@
|
|||||||
-- * @{#SPAWN.InitRepeat}() or @{#SPAWN.InitRepeatOnLanding}(): This method is used to re-spawn automatically the same group after it has landed.
|
-- * @{#SPAWN.InitRepeat}() or @{#SPAWN.InitRepeatOnLanding}(): This method is used to re-spawn automatically the same group after it has landed.
|
||||||
-- * @{#SPAWN.InitRepeatOnEngineShutDown}(): This method is used to re-spawn automatically the same group after it has landed and it shuts down the engines at the ramp.
|
-- * @{#SPAWN.InitRepeatOnEngineShutDown}(): This method is used to re-spawn automatically the same group after it has landed and it shuts down the engines at the ramp.
|
||||||
--
|
--
|
||||||
|
-- ### Link-16 Datalink STN and SADL IDs (limited at the moment to F15/16/18/AWACS/Tanker/B1B, but not the F15E for clients, SADL A10CII only)
|
||||||
|
--
|
||||||
|
-- * @{#SPAWN.InitSTN}(): Set the STN of the first unit in the group. All other units will have consecutive STNs, provided they have not been used yet.
|
||||||
|
-- * @{#SPAWN.InitSADL}(): Set the SADL of the first unit in the group. All other units will have consecutive SADLs, provided they have not been used yet.
|
||||||
|
--
|
||||||
|
-- ### Callsigns
|
||||||
|
--
|
||||||
|
-- * @{#SPAWN.InitRandomizeCallsign}(): Set a random callsign name per spawn.
|
||||||
|
-- * @{#SPAWN.SpawnInitCallSign}(): Set a specific callsign for a spawned group.
|
||||||
|
--
|
||||||
|
-- ### Speed
|
||||||
|
--
|
||||||
|
-- * @{#SPAWN.InitSpeedMps}(): Set the initial speed on spawning in meters per second.
|
||||||
|
-- * @{#SPAWN.InitSpeedKph}(): Set the initial speed on spawning in kilometers per hour.
|
||||||
|
-- * @{#SPAWN.InitSpeedKnots}(): Set the initial speed on spawning in knots.
|
||||||
|
--
|
||||||
-- ## SPAWN **Spawn** methods
|
-- ## SPAWN **Spawn** methods
|
||||||
--
|
--
|
||||||
-- Groups can be spawned at different times and methods:
|
-- Groups can be spawned at different times and methods:
|
||||||
@@ -276,9 +292,10 @@ SPAWN = {
|
|||||||
|
|
||||||
--- Enumerator for spawns at airbases
|
--- Enumerator for spawns at airbases
|
||||||
-- @type SPAWN.Takeoff
|
-- @type SPAWN.Takeoff
|
||||||
-- @extends Wrapper.Group#GROUP.Takeoff
|
-- @field #number Air Take off happens in air.
|
||||||
|
-- @field #number Runway Spawn on runway. Does not work in MP!
|
||||||
-- @field #SPAWN.Takeoff Takeoff
|
-- @field #number Hot Spawn at parking with engines on.
|
||||||
|
-- @field #number Cold Spawn at parking with engines off.
|
||||||
SPAWN.Takeoff = {
|
SPAWN.Takeoff = {
|
||||||
Air = 1,
|
Air = 1,
|
||||||
Runway = 2,
|
Runway = 2,
|
||||||
@@ -520,7 +537,7 @@ function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPr
|
|||||||
end
|
end
|
||||||
|
|
||||||
if SpawnTemplate then
|
if SpawnTemplate then
|
||||||
self.SpawnTemplate = SpawnTemplate -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!!
|
self.SpawnTemplate = UTILS.DeepCopy(SpawnTemplate) -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!!
|
||||||
self.SpawnTemplatePrefix = SpawnTemplatePrefix
|
self.SpawnTemplatePrefix = SpawnTemplatePrefix
|
||||||
self.SpawnAliasPrefix = SpawnAliasPrefix or SpawnTemplatePrefix
|
self.SpawnAliasPrefix = SpawnAliasPrefix or SpawnTemplatePrefix
|
||||||
self.SpawnTemplate.name = SpawnTemplatePrefix
|
self.SpawnTemplate.name = SpawnTemplatePrefix
|
||||||
@@ -603,12 +620,14 @@ end
|
|||||||
-- and any spaces before and after the resulting name are removed.
|
-- and any spaces before and after the resulting name are removed.
|
||||||
-- IMPORTANT! This method MUST be the first used after :New !!!
|
-- IMPORTANT! This method MUST be the first used after :New !!!
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #boolean KeepUnitNames (optional) If true, the unit names are kept, false or not provided to make new unit names.
|
-- @param #boolean KeepUnitNames (optional) If true, the unit names are kept, false or not provided create new unit names.
|
||||||
-- @return #SPAWN self
|
-- @return #SPAWN self
|
||||||
function SPAWN:InitKeepUnitNames( KeepUnitNames )
|
function SPAWN:InitKeepUnitNames( KeepUnitNames )
|
||||||
self:F()
|
self:F()
|
||||||
|
|
||||||
self.SpawnInitKeepUnitNames = KeepUnitNames or true
|
self.SpawnInitKeepUnitNames = false
|
||||||
|
|
||||||
|
if KeepUnitNames == true then self.SpawnInitKeepUnitNames = true end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -724,7 +743,7 @@ end
|
|||||||
-- @param #number Country Country id as number or enumerator:
|
-- @param #number Country Country id as number or enumerator:
|
||||||
--
|
--
|
||||||
-- * @{DCS#country.id.RUSSIA}
|
-- * @{DCS#country.id.RUSSIA}
|
||||||
-- * @{DCS#county.id.USA}
|
-- * @{DCS#country.id.USA}
|
||||||
--
|
--
|
||||||
-- @return #SPAWN self
|
-- @return #SPAWN self
|
||||||
function SPAWN:InitCountry( Country )
|
function SPAWN:InitCountry( Country )
|
||||||
@@ -780,6 +799,82 @@ function SPAWN:InitSkill( Skill )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [Airplane - F15/16/18/AWACS/B1B/Tanker only] Set the STN Link16 starting number of the Group; each unit of the spawned group will have a consecutive STN set.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number Octal The octal number (digits 1..7, max 5 digits, i.e. 1..77777) to set the STN to. Every STN needs to be unique!
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitSTN(Octal)
|
||||||
|
self:F( { Octal = Octal } )
|
||||||
|
self.SpawnInitSTN = Octal or 77777
|
||||||
|
local num = UTILS.OctalToDecimal(Octal)
|
||||||
|
if num == nil or num < 1 then
|
||||||
|
self:E("WARNING - STN "..tostring(Octal).." is not valid!")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
if _DATABASE.STNS[num] ~= nil then
|
||||||
|
self:E("WARNING - STN already assigned: "..tostring(Octal).." is used for ".._DATABASE.STNS[Octal])
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Airplane - A10-C II only] Set the SADL TN starting number of the Group; each unit of the spawned group will have a consecutive SADL set.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number Octal The octal number (digits 1..7, max 4 digits, i.e. 1..7777) to set the SADL to. Every SADL needs to be unique!
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitSADL(Octal)
|
||||||
|
self:F( { Octal = Octal } )
|
||||||
|
self.SpawnInitSADL = Octal or 7777
|
||||||
|
local num = UTILS.OctalToDecimal(Octal)
|
||||||
|
if num == nil or num < 1 then
|
||||||
|
self:E("WARNING - SADL "..tostring(Octal).." is not valid!")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
if _DATABASE.SADL[num] ~= nil then
|
||||||
|
self:E("WARNING - SADL already assigned: "..tostring(Octal).." is used for ".._DATABASE.SADL[Octal])
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Airplane] Set the initial speed on spawning in meters per second. Useful when spawning in-air only.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number MPS The speed in MPS to use.
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitSpeedMps(MPS)
|
||||||
|
self:F( { MPS = MPS } )
|
||||||
|
if MPS == nil or tonumber(MPS)<0 then
|
||||||
|
MPS=125
|
||||||
|
end
|
||||||
|
self.InitSpeed = MPS
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Airplane] Set the initial speed on spawning in knots. Useful when spawning in-air only.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number Knots The speed in knots to use.
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitSpeedKnots(Knots)
|
||||||
|
self:F( { Knots = Knots } )
|
||||||
|
if Knots == nil or tonumber(Knots)<0 then
|
||||||
|
Knots=300
|
||||||
|
end
|
||||||
|
self.InitSpeed = UTILS.KnotsToMps(Knots)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Airplane] Set the initial speed on spawning in kilometers per hour. Useful when spawning in-air only.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #number KPH The speed in KPH to use.
|
||||||
|
-- @return #SPAWN self
|
||||||
|
function SPAWN:InitSpeedKph(KPH)
|
||||||
|
self:F( { KPH = KPH } )
|
||||||
|
if KPH == nil or tonumber(KPH)<0 then
|
||||||
|
KPH=UTILS.KnotsToKmph(300)
|
||||||
|
end
|
||||||
|
self.InitSpeed = UTILS.KmphToMps(KPH)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Sets the radio communication on or off. Same as checking/unchecking the COMM box in the mission editor.
|
--- Sets the radio communication on or off. Same as checking/unchecking the COMM box in the mission editor.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #number switch If true (or nil), enables the radio communication. If false, disables the radio for the spawned group.
|
-- @param #number switch If true (or nil), enables the radio communication. If false, disables the radio for the spawned group.
|
||||||
@@ -1116,11 +1211,12 @@ end
|
|||||||
-- @param #number Major Major number, i.e. the group number of this name, e.g. 1 - resulting in e.g. Texaco-2-1
|
-- @param #number Major Major number, i.e. the group number of this name, e.g. 1 - resulting in e.g. Texaco-2-1
|
||||||
-- @return #SPAWN self
|
-- @return #SPAWN self
|
||||||
function SPAWN:InitCallSign(ID,Name,Minor,Major)
|
function SPAWN:InitCallSign(ID,Name,Minor,Major)
|
||||||
|
local Name = Name or "Enfield"
|
||||||
self.SpawnInitCallSign = true
|
self.SpawnInitCallSign = true
|
||||||
self.SpawnInitCallSignID = ID or 1
|
self.SpawnInitCallSignID = ID or 1
|
||||||
self.SpawnInitCallSignMinor = Minor or 1
|
self.SpawnInitCallSignMinor = Minor or 1
|
||||||
self.SpawnInitCallSignMajor = Major or 1
|
self.SpawnInitCallSignMajor = Major or 1
|
||||||
self.SpawnInitCallSignName = string.lower(Name) or "enfield"
|
self.SpawnInitCallSignName=string.lower(Name):gsub("^%l", string.upper)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1375,6 +1471,30 @@ do -- Delay methods
|
|||||||
|
|
||||||
end -- Delay methods
|
end -- Delay methods
|
||||||
|
|
||||||
|
--- Hide the group on the map view (visible to game master slots!).
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @return #SPAWN The SPAWN object
|
||||||
|
function SPAWN:InitHiddenOnMap()
|
||||||
|
self.SpawnHiddenOnMap = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Hide the group on MFDs (visible to game master slots!).
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @return #SPAWN The SPAWN object
|
||||||
|
function SPAWN:InitHiddenOnMFD()
|
||||||
|
self.SpawnHiddenOnMFD = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Hide the group on planner (visible to game master slots!).
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @return #SPAWN The SPAWN object
|
||||||
|
function SPAWN:InitHiddenOnPlanner()
|
||||||
|
self.SpawnHiddenOnPlanner = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Will spawn a group based on the internal index.
|
--- Will spawn a group based on the internal index.
|
||||||
-- Note: This method uses the global _DATABASE object (an instance of @{Core.Database#DATABASE}), which contains ALL initial and new spawned objects in MOOSE.
|
-- Note: This method uses the global _DATABASE object (an instance of @{Core.Database#DATABASE}), which contains ALL initial and new spawned objects in MOOSE.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
@@ -1492,8 +1612,8 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
|||||||
RandomVec2 = PointVec3:GetRandomVec2InRadius( self.SpawnOuterRadius, self.SpawnInnerRadius )
|
RandomVec2 = PointVec3:GetRandomVec2InRadius( self.SpawnOuterRadius, self.SpawnInnerRadius )
|
||||||
numTries = numTries + 1
|
numTries = numTries + 1
|
||||||
inZone = SpawnZone:IsVec2InZone(RandomVec2)
|
inZone = SpawnZone:IsVec2InZone(RandomVec2)
|
||||||
self:I("Retrying " .. numTries .. "spawn " .. SpawnTemplate.name .. " in Zone " .. SpawnZone:GetName() .. "!")
|
--self:I("Retrying " .. numTries .. "spawn " .. SpawnTemplate.name .. " in Zone " .. SpawnZone:GetName() .. "!")
|
||||||
self:I(SpawnZone)
|
--self:I(SpawnZone)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if (not inZone) then
|
if (not inZone) then
|
||||||
@@ -1649,6 +1769,19 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
|||||||
SpawnTemplate.modulation = self.SpawnInitModu
|
SpawnTemplate.modulation = self.SpawnInitModu
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- hiding options
|
||||||
|
if self.SpawnHiddenOnPlanner then
|
||||||
|
SpawnTemplate.hiddenOnPlanner=true
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.SpawnHiddenOnMFD then
|
||||||
|
SpawnTemplate.hiddenOnMFD=true
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.SpawnHiddenOnMap then
|
||||||
|
SpawnTemplate.hidden=true
|
||||||
|
end
|
||||||
|
|
||||||
-- Set country, coalition and category.
|
-- Set country, coalition and category.
|
||||||
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
|
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
|
||||||
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
|
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
|
||||||
@@ -1699,6 +1832,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
|||||||
end
|
end
|
||||||
|
|
||||||
self.SpawnGroups[self.SpawnIndex].Spawned = true
|
self.SpawnGroups[self.SpawnIndex].Spawned = true
|
||||||
|
self.SpawnGroups[self.SpawnIndex].Group.TemplateDonor = self.SpawnTemplatePrefix
|
||||||
return self.SpawnGroups[self.SpawnIndex].Group
|
return self.SpawnGroups[self.SpawnIndex].Group
|
||||||
else
|
else
|
||||||
-- self:E( { self.SpawnTemplatePrefix, "No more Groups to Spawn:", SpawnIndex, self.SpawnMaxGroups } )
|
-- self:E( { self.SpawnTemplatePrefix, "No more Groups to Spawn:", SpawnIndex, self.SpawnMaxGroups } )
|
||||||
@@ -3145,7 +3279,7 @@ end
|
|||||||
--- Get the index from a given group.
|
--- Get the index from a given group.
|
||||||
-- The function will search the name of the group for a #, and will return the number behind the #-mark.
|
-- The function will search the name of the group for a #, and will return the number behind the #-mark.
|
||||||
function SPAWN:GetSpawnIndexFromGroup( SpawnGroup )
|
function SPAWN:GetSpawnIndexFromGroup( SpawnGroup )
|
||||||
self:F2( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } )
|
self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } )
|
||||||
|
|
||||||
local IndexString = string.match( SpawnGroup:GetName(), "#(%d*)$" ):sub( 2 )
|
local IndexString = string.match( SpawnGroup:GetName(), "#(%d*)$" ):sub( 2 )
|
||||||
local Index = tonumber( IndexString )
|
local Index = tonumber( IndexString )
|
||||||
@@ -3157,7 +3291,7 @@ end
|
|||||||
|
|
||||||
--- Return the last maximum index that can be used.
|
--- Return the last maximum index that can be used.
|
||||||
function SPAWN:_GetLastIndex()
|
function SPAWN:_GetLastIndex()
|
||||||
self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } )
|
self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } )
|
||||||
|
|
||||||
return self.SpawnMaxGroups
|
return self.SpawnMaxGroups
|
||||||
end
|
end
|
||||||
@@ -3306,15 +3440,27 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
|||||||
|
|
||||||
if self.SpawnInitKeepUnitNames == false then
|
if self.SpawnInitKeepUnitNames == false then
|
||||||
for UnitID = 1, #SpawnTemplate.units do
|
for UnitID = 1, #SpawnTemplate.units do
|
||||||
SpawnTemplate.units[UnitID].name = string.format( SpawnTemplate.name .. '-%02d', UnitID )
|
if not string.find(SpawnTemplate.units[UnitID].name,"#IFF_",1,true) then --Razbam IFF hack for F15E etc
|
||||||
|
SpawnTemplate.units[UnitID].name = string.format( SpawnTemplate.name .. '-%02d', UnitID )
|
||||||
|
end
|
||||||
SpawnTemplate.units[UnitID].unitId = nil
|
SpawnTemplate.units[UnitID].unitId = nil
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for UnitID = 1, #SpawnTemplate.units do
|
for UnitID = 1, #SpawnTemplate.units do
|
||||||
local UnitPrefix, Rest = string.match( SpawnTemplate.units[UnitID].name, "^([^#]+)#?" ):gsub( "^%s*(.-)%s*$", "%1" )
|
local SpawnInitKeepUnitIFF = false
|
||||||
self:T( { UnitPrefix, Rest } )
|
if string.find(SpawnTemplate.units[UnitID].name,"#IFF_",1,true) then --Razbam IFF hack for F15E etc
|
||||||
|
SpawnInitKeepUnitIFF = true
|
||||||
|
end
|
||||||
|
local UnitPrefix, Rest
|
||||||
|
if SpawnInitKeepUnitIFF == false then
|
||||||
|
UnitPrefix, Rest = string.match( SpawnTemplate.units[UnitID].name, "^([^#]+)#?" ):gsub( "^%s*(.-)%s*$", "%1" )
|
||||||
|
SpawnTemplate.units[UnitID].name = string.format( '%s#%03d-%02d', UnitPrefix, SpawnIndex, UnitID )
|
||||||
|
self:T( { UnitPrefix, Rest } )
|
||||||
|
--else
|
||||||
|
--UnitPrefix=SpawnTemplate.units[UnitID].name
|
||||||
|
end
|
||||||
|
--SpawnTemplate.units[UnitID].name = string.format( '%s#%03d-%02d', UnitPrefix, SpawnIndex, UnitID )
|
||||||
|
|
||||||
SpawnTemplate.units[UnitID].name = string.format( '%s#%03d-%02d', UnitPrefix, SpawnIndex, UnitID )
|
|
||||||
SpawnTemplate.units[UnitID].unitId = nil
|
SpawnTemplate.units[UnitID].unitId = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3395,34 +3541,58 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
|||||||
SpawnTemplate.units[UnitID].callsign = Callsign + SpawnIndex
|
SpawnTemplate.units[UnitID].callsign = Callsign + SpawnIndex
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- Speed
|
||||||
|
if self.InitSpeed then
|
||||||
|
SpawnTemplate.units[UnitID].speed = self.InitSpeed
|
||||||
|
end
|
||||||
-- Link16
|
-- Link16
|
||||||
local AddProps = SpawnTemplate.units[UnitID].AddPropAircraft
|
local AddProps = SpawnTemplate.units[UnitID].AddPropAircraft
|
||||||
if AddProps then
|
if AddProps then
|
||||||
if SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 then
|
if SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 then
|
||||||
-- 4 digit octal with leading 0
|
if self.SpawnInitSTN then
|
||||||
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16) ~= nil then
|
local octal = self.SpawnInitSTN
|
||||||
local octal = SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16
|
if UnitID > 1 then
|
||||||
local decimal = UTILS.OctalToDecimal(octal)+UnitID-1
|
octal = _DATABASE:GetNextSTN(self.SpawnInitSTN,SpawnTemplate.units[UnitID].name)
|
||||||
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",UTILS.DecimalToOctal(decimal))
|
end
|
||||||
else -- ED bug - chars in here
|
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",octal)
|
||||||
local STN = math.floor(UTILS.RandomGaussian(4088/2,nil,1000,4088))
|
else
|
||||||
STN = STN+UnitID-1
|
-- 5 digit octal with leading 0
|
||||||
local OSTN = UTILS.DecimalToOctal(STN)
|
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16) ~= nil then
|
||||||
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",OSTN)
|
local octal = SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16
|
||||||
|
local num = UTILS.OctalToDecimal(octal)
|
||||||
|
if _DATABASE.STNS[num] ~= nil or UnitID > 1 then -- STN taken or next unit
|
||||||
|
octal = _DATABASE:GetNextSTN(octal,SpawnTemplate.units[UnitID].name)
|
||||||
|
end
|
||||||
|
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",octal)
|
||||||
|
else -- ED bug - chars in here
|
||||||
|
local OSTN = _DATABASE:GetNextSTN(1,SpawnTemplate.units[UnitID].name)
|
||||||
|
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",OSTN)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- A10CII
|
-- A10CII
|
||||||
if SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN then
|
if SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN then
|
||||||
-- 3 digit octal with leading 0
|
-- 4 digit octal with leading 0
|
||||||
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN) ~= nil then
|
if self.SpawnInitSADL then
|
||||||
local octal = SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN
|
local octal = self.SpawnInitSADL
|
||||||
local decimal = UTILS.OctalToDecimal(octal)+UnitID-1
|
if UnitID > 1 then
|
||||||
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",UTILS.DecimalToOctal(decimal))
|
octal = _DATABASE:GetNextSADL(self.SpawnInitSADL,SpawnTemplate.units[UnitID].name)
|
||||||
else -- ED bug - chars in here
|
end
|
||||||
local STN = math.floor(UTILS.RandomGaussian(504/2,nil,100,504))
|
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",octal)
|
||||||
STN = STN+UnitID-1
|
else
|
||||||
local OSTN = UTILS.DecimalToOctal(STN)
|
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN) ~= nil then
|
||||||
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",OSTN)
|
local octal = SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN
|
||||||
|
local num = UTILS.OctalToDecimal(octal)
|
||||||
|
self.SpawnInitSADL = num -- we arrived here seeing that self.SpawnInitSADL == nil, but now that we have a SADL (num), we also need to set it to self.SpawnInitSADL in case
|
||||||
|
-- we need to get the next SADL from _DATABASE, or else UTILS.OctalToDecimal() will fail in GetNextSADL
|
||||||
|
if _DATABASE.SADL[num] ~= nil or UnitID > 1 then -- SADL taken or next unit
|
||||||
|
octal = _DATABASE:GetNextSADL(self.SpawnInitSADL,SpawnTemplate.units[UnitID].name)
|
||||||
|
end
|
||||||
|
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",octal)
|
||||||
|
else -- ED bug - chars in here
|
||||||
|
local OSTN = _DATABASE:GetNextSADL(1,SpawnTemplate.units[UnitID].name)
|
||||||
|
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",OSTN)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- VoiceCallsignNumber
|
-- VoiceCallsignNumber
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
--
|
--
|
||||||
-- # Demo Missions
|
-- # Demo Missions
|
||||||
--
|
--
|
||||||
-- ## [SPAWNSTATIC Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Core/SpawnStatic)
|
-- ## [SPAWNSTATIC Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Core/SpawnStatic)
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Core/Zone)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions: **Applevangelist**, **FunkyFranky**, **coconutcockpit**
|
-- ### Contributions: **Applevangelist**, **FunkyFranky**, **coconutcockpit**
|
||||||
--
|
--
|
||||||
@@ -326,14 +330,14 @@ function ZONE_BASE:GetRandomVec2()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone.
|
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
||||||
function ZONE_BASE:GetRandomPointVec2()
|
function ZONE_BASE:GetRandomPointVec2()
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC3} within the zone.
|
--- Define a random @{Core.Point#POINT_VEC3} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @return Core.Point#POINT_VEC3 The PointVec3 coordinates.
|
-- @return Core.Point#POINT_VEC3 The PointVec3 coordinates.
|
||||||
function ZONE_BASE:GetRandomPointVec3()
|
function ZONE_BASE:GetRandomPointVec3()
|
||||||
@@ -899,6 +903,7 @@ function ZONE_RADIUS:BoundZone( Points, CountryID, UnBound )
|
|||||||
|
|
||||||
local Point = {}
|
local Point = {}
|
||||||
local Vec2 = self:GetVec2()
|
local Vec2 = self:GetVec2()
|
||||||
|
local countryID = CountryID or country.id.USA
|
||||||
|
|
||||||
Points = Points and Points or 360
|
Points = Points and Points or 360
|
||||||
|
|
||||||
@@ -910,7 +915,7 @@ function ZONE_RADIUS:BoundZone( Points, CountryID, UnBound )
|
|||||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||||
|
|
||||||
local CountryName = _DATABASE.COUNTRY_NAME[CountryID]
|
local CountryName = _DATABASE.COUNTRY_NAME[countryID]
|
||||||
|
|
||||||
local Tire = {
|
local Tire = {
|
||||||
["country"] = CountryName,
|
["country"] = CountryName,
|
||||||
@@ -925,7 +930,7 @@ function ZONE_RADIUS:BoundZone( Points, CountryID, UnBound )
|
|||||||
["heading"] = 0,
|
["heading"] = 0,
|
||||||
} -- end of ["group"]
|
} -- end of ["group"]
|
||||||
|
|
||||||
local Group = coalition.addStaticObject( CountryID, Tire )
|
local Group = coalition.addStaticObject( countryID, Tire )
|
||||||
if UnBound and UnBound == true then
|
if UnBound and UnBound == true then
|
||||||
Group:destroy()
|
Group:destroy()
|
||||||
end
|
end
|
||||||
@@ -1175,7 +1180,7 @@ function ZONE_RADIUS:RemoveJunk()
|
|||||||
return n
|
return n
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Count the number of different coalitions inside the zone.
|
--- Get a table of scanned units.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @return #table Table of DCS units and DCS statics inside the zone.
|
-- @return #table Table of DCS units and DCS statics inside the zone.
|
||||||
function ZONE_RADIUS:GetScannedUnits()
|
function ZONE_RADIUS:GetScannedUnits()
|
||||||
@@ -1210,7 +1215,7 @@ function ZONE_RADIUS:GetScannedSetUnit()
|
|||||||
return SetUnit
|
return SetUnit
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get a set of scanned units.
|
--- Get a set of scanned groups.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @return Core.Set#SET_GROUP Set of groups.
|
-- @return Core.Set#SET_GROUP Set of groups.
|
||||||
function ZONE_RADIUS:GetScannedSetGroup()
|
function ZONE_RADIUS:GetScannedSetGroup()
|
||||||
@@ -1510,7 +1515,7 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
|||||||
return point
|
return point
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
@@ -1541,7 +1546,7 @@ function ZONE_RADIUS:GetRandomVec3( inner, outer )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC3} object reflecting a random 3D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC3} object reflecting a random 3D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
@@ -1985,7 +1990,7 @@ function ZONE_GROUP:GetRandomVec2()
|
|||||||
return Point
|
return Point
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_GROUP self
|
-- @param #ZONE_GROUP self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
@@ -2829,7 +2834,7 @@ function ZONE_POLYGON_BASE:GetRandomVec2()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return a @{Core.Point#POINT_VEC2} object representing a random 2D point at landheight within the zone.
|
--- Return a @{Core.Point#POINT_VEC2} object representing a random 2D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_POLYGON_BASE self
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
-- @return @{Core.Point#POINT_VEC2}
|
-- @return @{Core.Point#POINT_VEC2}
|
||||||
function ZONE_POLYGON_BASE:GetRandomPointVec2()
|
function ZONE_POLYGON_BASE:GetRandomPointVec2()
|
||||||
@@ -2842,7 +2847,7 @@ function ZONE_POLYGON_BASE:GetRandomPointVec2()
|
|||||||
return PointVec2
|
return PointVec2
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return a @{Core.Point#POINT_VEC3} object representing a random 3D point at landheight within the zone.
|
--- Return a @{Core.Point#POINT_VEC3} object representing a random 3D point at landheight within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_POLYGON_BASE self
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
-- @return @{Core.Point#POINT_VEC3}
|
-- @return @{Core.Point#POINT_VEC3}
|
||||||
function ZONE_POLYGON_BASE:GetRandomPointVec3()
|
function ZONE_POLYGON_BASE:GetRandomPointVec3()
|
||||||
@@ -3071,9 +3076,25 @@ function ZONE_POLYGON:NewFromDrawing(DrawingName)
|
|||||||
-- points for the drawings are saved in local space, so add the object's map x and y coordinates to get
|
-- points for the drawings are saved in local space, so add the object's map x and y coordinates to get
|
||||||
-- world space points we can use
|
-- world space points we can use
|
||||||
for _, point in UTILS.spairs(object["points"]) do
|
for _, point in UTILS.spairs(object["points"]) do
|
||||||
|
-- check if we want to skip adding a point
|
||||||
|
local skip = false
|
||||||
local p = {x = object["mapX"] + point["x"],
|
local p = {x = object["mapX"] + point["x"],
|
||||||
y = object["mapY"] + point["y"] }
|
y = object["mapY"] + point["y"] }
|
||||||
table.add(points, p)
|
|
||||||
|
-- Check if the same coordinates already exist in the list, skip if they do
|
||||||
|
-- This can happen when drawing a Polygon in Free mode, DCS adds points on
|
||||||
|
-- top of each other that are in the `mission` file, but not visible in the
|
||||||
|
-- Mission Editor
|
||||||
|
for _, pt in pairs(points) do
|
||||||
|
if pt.x == p.x and pt.y == p.y then
|
||||||
|
skip = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if it's a unique point, add it
|
||||||
|
if not skip then
|
||||||
|
table.add(points, p)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
elseif object["polygonMode"] == "rect" then
|
elseif object["polygonMode"] == "rect" then
|
||||||
-- the points for a rect are saved as local coordinates with an angle. To get the world space points from this
|
-- the points for a rect are saved as local coordinates with an angle. To get the world space points from this
|
||||||
@@ -3091,6 +3112,7 @@ function ZONE_POLYGON:NewFromDrawing(DrawingName)
|
|||||||
|
|
||||||
points = {p1, p2, p3, p4}
|
points = {p1, p2, p3, p4}
|
||||||
else
|
else
|
||||||
|
-- bring the Arrow code over from Shape/Polygon
|
||||||
-- something else that might be added in the future
|
-- something else that might be added in the future
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3830,18 +3852,18 @@ function ZONE_OVAL:GetRandomVec2()
|
|||||||
return {x=rx, y=ry}
|
return {x=rx, y=ry}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone.
|
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_OVAL self
|
-- @param #ZONE_OVAL self
|
||||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
||||||
function ZONE_OVAL:GetRandomPointVec2()
|
function ZONE_OVAL:GetRandomPointVec2()
|
||||||
return POINT_VEC2:NewFromVec2(self:GetRandomVec2())
|
return POINT_VEC2:NewFromVec2(self:GetRandomVec2())
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a random @{Core.Point#POINT_VEC2} within the zone.
|
--- Define a random @{Core.Point#POINT_VEC2} within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec3 table.
|
||||||
-- @param #ZONE_OVAL self
|
-- @param #ZONE_OVAL self
|
||||||
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
-- @return Core.Point#POINT_VEC2 The PointVec2 coordinates.
|
||||||
function ZONE_OVAL:GetRandomPointVec3()
|
function ZONE_OVAL:GetRandomPointVec3()
|
||||||
return POINT_VEC2:NewFromVec3(self:GetRandomVec2())
|
return POINT_VEC3:NewFromVec3(self:GetRandomVec2())
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Draw the zone on the F10 map.
|
--- Draw the zone on the F10 map.
|
||||||
@@ -3981,7 +4003,7 @@ do -- ZONE_AIRBASE
|
|||||||
return ZoneVec2
|
return ZoneVec2
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone. Note that this is actually a @{Core.Point#COORDINATE} type object, and not a simple Vec2 table.
|
||||||
-- @param #ZONE_AIRBASE self
|
-- @param #ZONE_AIRBASE self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
-- @image Designation.JPG
|
-- @image Designation.JPG
|
||||||
--
|
--
|
||||||
-- Date: 24 Oct 2021
|
-- Date: 24 Oct 2021
|
||||||
-- Last Update: Jan 2024
|
-- Last Update: May 2024
|
||||||
--
|
--
|
||||||
--- Class AUTOLASE
|
--- Class AUTOLASE
|
||||||
-- @type AUTOLASE
|
-- @type AUTOLASE
|
||||||
@@ -88,6 +88,7 @@
|
|||||||
-- @field #table LaserCodes
|
-- @field #table LaserCodes
|
||||||
-- @field #table playermenus
|
-- @field #table playermenus
|
||||||
-- @field #boolean smokemenu
|
-- @field #boolean smokemenu
|
||||||
|
-- @field #boolean threatmenu
|
||||||
-- @extends Ops.Intel#INTEL
|
-- @extends Ops.Intel#INTEL
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -117,7 +118,7 @@ AUTOLASE = {
|
|||||||
|
|
||||||
--- AUTOLASE class version.
|
--- AUTOLASE class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
AUTOLASE.version = "0.1.23"
|
AUTOLASE.version = "0.1.25"
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
-- Begin Functional.Autolase.lua
|
-- Begin Functional.Autolase.lua
|
||||||
@@ -205,6 +206,7 @@ function AUTOLASE:New(RecceSet, Coalition, Alias, PilotSet)
|
|||||||
self:SetLaserCodes( { 1688, 1130, 4785, 6547, 1465, 4578 } ) -- set self.LaserCodes
|
self:SetLaserCodes( { 1688, 1130, 4785, 6547, 1465, 4578 } ) -- set self.LaserCodes
|
||||||
self.playermenus = {}
|
self.playermenus = {}
|
||||||
self.smokemenu = true
|
self.smokemenu = true
|
||||||
|
self.threatmenu = true
|
||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("AUTOLASE %s (%s) | ", self.alias, self.coalition and UTILS.GetCoalitionName(self.coalition) or "unknown")
|
self.lid=string.format("AUTOLASE %s (%s) | ", self.alias, self.coalition and UTILS.GetCoalitionName(self.coalition) or "unknown")
|
||||||
@@ -323,39 +325,51 @@ end
|
|||||||
function AUTOLASE:SetPilotMenu()
|
function AUTOLASE:SetPilotMenu()
|
||||||
if self.usepilotset then
|
if self.usepilotset then
|
||||||
local pilottable = self.pilotset:GetSetObjects() or {}
|
local pilottable = self.pilotset:GetSetObjects() or {}
|
||||||
|
local grouptable = {}
|
||||||
for _,_unit in pairs (pilottable) do
|
for _,_unit in pairs (pilottable) do
|
||||||
local Unit = _unit -- Wrapper.Unit#UNIT
|
local Unit = _unit -- Wrapper.Unit#UNIT
|
||||||
if Unit and Unit:IsAlive() then
|
if Unit and Unit:IsAlive() then
|
||||||
local Group = Unit:GetGroup()
|
local Group = Unit:GetGroup()
|
||||||
|
local GroupName = Group:GetName() or "none"
|
||||||
local unitname = Unit:GetName()
|
local unitname = Unit:GetName()
|
||||||
if self.playermenus[unitname] then self.playermenus[unitname]:Remove() end
|
if not grouptable[GroupName] == true then
|
||||||
local lasetopm = MENU_GROUP:New(Group,"Autolase",nil)
|
if self.playermenus[unitname] then self.playermenus[unitname]:Remove() end -- menus
|
||||||
self.playermenus[unitname] = lasetopm
|
local lasetopm = MENU_GROUP:New(Group,"Autolase",nil)
|
||||||
local lasemenu = MENU_GROUP_COMMAND:New(Group,"Status",lasetopm,self.ShowStatus,self,Group,Unit)
|
self.playermenus[unitname] = lasetopm
|
||||||
if self.smokemenu then
|
local lasemenu = MENU_GROUP_COMMAND:New(Group,"Status",lasetopm,self.ShowStatus,self,Group,Unit)
|
||||||
local smoke = (self.smoketargets == true) and "off" or "on"
|
if self.smokemenu then
|
||||||
local smoketext = string.format("Switch smoke targets to %s",smoke)
|
local smoke = (self.smoketargets == true) and "off" or "on"
|
||||||
local smokemenu = MENU_GROUP_COMMAND:New(Group,smoketext,lasetopm,self.SetSmokeTargets,self,(not self.smoketargets))
|
local smoketext = string.format("Switch smoke targets to %s",smoke)
|
||||||
end
|
local smokemenu = MENU_GROUP_COMMAND:New(Group,smoketext,lasetopm,self.SetSmokeTargets,self,(not self.smoketargets))
|
||||||
for _,_grp in pairs(self.RecceSet.Set) do
|
end -- smokement
|
||||||
local grp = _grp -- Wrapper.Group#GROUP
|
if self.threatmenu then
|
||||||
local unit = grp:GetUnit(1)
|
local threatmenutop = MENU_GROUP:New(Group,"Set min lasing threat",lasetopm)
|
||||||
--local name = grp:GetName()
|
for i=0,10,2 do
|
||||||
if unit and unit:IsAlive() then
|
local text = "Threatlevel "..tostring(i)
|
||||||
local name = unit:GetName()
|
local threatmenu = MENU_GROUP_COMMAND:New(Group,text,threatmenutop,self.SetMinThreatLevel,self,i)
|
||||||
local mname = string.gsub(name,".%d+.%d+$","")
|
end -- threatlevel
|
||||||
local code = self:GetLaserCode(name)
|
end -- threatmenu
|
||||||
local unittop = MENU_GROUP:New(Group,"Change laser code for "..mname,lasetopm)
|
for _,_grp in pairs(self.RecceSet.Set) do
|
||||||
for _,_code in pairs(self.LaserCodes) do
|
local grp = _grp -- Wrapper.Group#GROUP
|
||||||
local text = tostring(_code)
|
local unit = grp:GetUnit(1)
|
||||||
if _code == code then text = text.."(*)" end
|
--local name = grp:GetName()
|
||||||
local changemenu = MENU_GROUP_COMMAND:New(Group,text,unittop,self.SetRecceLaserCode,self,name,_code,true)
|
if unit and unit:IsAlive() then
|
||||||
end
|
local name = unit:GetName()
|
||||||
end
|
local mname = string.gsub(name,".%d+.%d+$","")
|
||||||
end
|
local code = self:GetLaserCode(name)
|
||||||
|
local unittop = MENU_GROUP:New(Group,"Change laser code for "..mname,lasetopm)
|
||||||
|
for _,_code in pairs(self.LaserCodes) do
|
||||||
|
local text = tostring(_code)
|
||||||
|
if _code == code then text = text.."(*)" end
|
||||||
|
local changemenu = MENU_GROUP_COMMAND:New(Group,text,unittop,self.SetRecceLaserCode,self,name,_code,true)
|
||||||
|
end -- Codes
|
||||||
|
end -- unit alive
|
||||||
|
end -- Recceset
|
||||||
|
grouptable[GroupName] = true
|
||||||
|
end -- grouptable[GroupName]
|
||||||
--lasemenu:Refresh()
|
--lasemenu:Refresh()
|
||||||
end
|
end -- unit alive
|
||||||
end
|
end -- pilot loop
|
||||||
else
|
else
|
||||||
if not self.NoMenus then
|
if not self.NoMenus then
|
||||||
self.Menu = MENU_COALITION_COMMAND:New(self.coalition,"Autolase",nil,self.ShowStatus,self)
|
self.Menu = MENU_COALITION_COMMAND:New(self.coalition,"Autolase",nil,self.ShowStatus,self)
|
||||||
@@ -602,6 +616,21 @@ function AUTOLASE:DisableSmokeMenu()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (User) Show the "Switch min threat lasing..." menu entry for pilots. On by default.
|
||||||
|
-- @param #AUTOLASE self
|
||||||
|
-- @return #AUTOLASE self
|
||||||
|
function AUTOLASE:EnableThreatLevelMenu()
|
||||||
|
self.threatmenu = true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (User) Do not show the "Switch min threat lasing..." menu entry for pilots.
|
||||||
|
-- @param #AUTOLASE self
|
||||||
|
-- @return #AUTOLASE self
|
||||||
|
function AUTOLASE:DisableThreatLevelMenu()
|
||||||
|
self.threatmenu = false
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- (Internal) Function to calculate line of sight.
|
--- (Internal) Function to calculate line of sight.
|
||||||
-- @param #AUTOLASE self
|
-- @param #AUTOLASE self
|
||||||
@@ -730,6 +759,7 @@ function AUTOLASE:ShowStatus(Group,Unit)
|
|||||||
report:Add(string.format("Recce %s has code %d",name,code))
|
report:Add(string.format("Recce %s has code %d",name,code))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
report:Add(string.format("Lasing min threat level %d",self.minthreatlevel))
|
||||||
local lines = 0
|
local lines = 0
|
||||||
for _ind,_entry in pairs(self.CurrentLasing) do
|
for _ind,_entry in pairs(self.CurrentLasing) do
|
||||||
local entry = _entry -- #AUTOLASE.LaserSpot
|
local entry = _entry -- #AUTOLASE.LaserSpot
|
||||||
@@ -914,12 +944,12 @@ function AUTOLASE:onafterMonitor(From, Event, To)
|
|||||||
|
|
||||||
self:SetPilotMenu()
|
self:SetPilotMenu()
|
||||||
|
|
||||||
local detecteditems = self.Contacts or {} -- #table of Ops.Intelligence#INTEL.Contact
|
local detecteditems = self.Contacts or {} -- #table of Ops.Intel#INTEL.Contact
|
||||||
local groupsbythreat = {}
|
local groupsbythreat = {}
|
||||||
local report = REPORT:New("Detections")
|
local report = REPORT:New("Detections")
|
||||||
local lines = 0
|
local lines = 0
|
||||||
for _,_contact in pairs(detecteditems) do
|
for _,_contact in pairs(detecteditems) do
|
||||||
local contact = _contact -- Ops.Intelligence#INTEL.Contact
|
local contact = _contact -- Ops.Intel#INTEL.Contact
|
||||||
local grp = contact.group
|
local grp = contact.group
|
||||||
local coord = contact.position
|
local coord = contact.position
|
||||||
local reccename = contact.recce or "none"
|
local reccename = contact.recce or "none"
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
|
|
||||||
do -- DESIGNATE
|
do -- DESIGNATE
|
||||||
|
|
||||||
--- @type DESIGNATE
|
-- @type DESIGNATE
|
||||||
-- @extends Core.Fsm#FSM_PROCESS
|
-- @extends Core.Fsm#FSM_PROCESS
|
||||||
|
|
||||||
--- Manage the designation of detected targets.
|
--- Manage the designation of detected targets.
|
||||||
@@ -525,7 +525,7 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
self.AttackSet:ForEachGroupAlive(
|
self.AttackSet:ForEachGroupAlive(
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AttackGroup
|
-- @param Wrapper.Group#GROUP AttackGroup
|
||||||
function( AttackGroup )
|
function( AttackGroup )
|
||||||
self.FlashStatusMenu[AttackGroup] = FlashMenu
|
self.FlashStatusMenu[AttackGroup] = FlashMenu
|
||||||
end
|
end
|
||||||
@@ -554,7 +554,7 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
self.AttackSet:ForEachGroupAlive(
|
self.AttackSet:ForEachGroupAlive(
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AttackGroup
|
-- @param Wrapper.Group#GROUP AttackGroup
|
||||||
function( AttackGroup )
|
function( AttackGroup )
|
||||||
self.FlashDetectionMessage[AttackGroup] = FlashDetectionMessage
|
self.FlashDetectionMessage[AttackGroup] = FlashDetectionMessage
|
||||||
end
|
end
|
||||||
@@ -826,7 +826,7 @@ do -- DESIGNATE
|
|||||||
-- 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:ForEachGroupAlive(
|
self.AttackSet:ForEachGroupAlive(
|
||||||
--- @param Wrapper.Group#GROUP AttackGroup
|
-- @param Wrapper.Group#GROUP AttackGroup
|
||||||
function( AttackGroup )
|
function( AttackGroup )
|
||||||
if AttackGroup:IsAlive() == true then
|
if AttackGroup:IsAlive() == true then
|
||||||
local DetectionText = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup ):Text( ", " )
|
local DetectionText = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup ):Text( ", " )
|
||||||
@@ -903,7 +903,7 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
self.AttackSet:ForEachGroupAlive(
|
self.AttackSet:ForEachGroupAlive(
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP GroupReport
|
-- @param Wrapper.Group#GROUP GroupReport
|
||||||
function( AttackGroup )
|
function( AttackGroup )
|
||||||
|
|
||||||
if self.FlashStatusMenu[AttackGroup] or ( MenuAttackGroup and ( AttackGroup:GetName() == MenuAttackGroup:GetName() ) ) then
|
if self.FlashStatusMenu[AttackGroup] or ( MenuAttackGroup and ( AttackGroup:GetName() == MenuAttackGroup:GetName() ) ) then
|
||||||
@@ -1060,7 +1060,7 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
self.AttackSet:ForEachGroupAlive(
|
self.AttackSet:ForEachGroupAlive(
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP GroupReport
|
-- @param Wrapper.Group#GROUP GroupReport
|
||||||
function( AttackGroup )
|
function( AttackGroup )
|
||||||
|
|
||||||
self:ScheduleOnce( Delay, self.SetMenu, self, AttackGroup )
|
self:ScheduleOnce( Delay, self.SetMenu, self, AttackGroup )
|
||||||
@@ -1198,7 +1198,7 @@ do -- DESIGNATE
|
|||||||
--local ReportTypes = REPORT:New()
|
--local ReportTypes = REPORT:New()
|
||||||
--local ReportLaserCodes = REPORT:New()
|
--local ReportLaserCodes = REPORT:New()
|
||||||
|
|
||||||
TargetSetUnit:Flush( self )
|
--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
|
||||||
@@ -1229,10 +1229,12 @@ do -- DESIGNATE
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if TargetSetUnit == nil then return end
|
||||||
|
|
||||||
if self.AutoLase or ( not self.AutoLase and ( self.LaseStart + Duration >= timer.getTime() ) ) then
|
if self.AutoLase or ( not self.AutoLase and ( self.LaseStart + Duration >= timer.getTime() ) ) then
|
||||||
|
|
||||||
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
||||||
--- @param Wrapper.Unit#UNIT SmokeUnit
|
-- @param Wrapper.Unit#UNIT SmokeUnit
|
||||||
function( TargetUnit )
|
function( TargetUnit )
|
||||||
|
|
||||||
self:F( { TargetUnit = TargetUnit:GetName() } )
|
self:F( { TargetUnit = TargetUnit:GetName() } )
|
||||||
@@ -1253,7 +1255,7 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
local RecceUnit = UnitData -- Wrapper.Unit#UNIT
|
local RecceUnit = UnitData -- Wrapper.Unit#UNIT
|
||||||
local RecceUnitDesc = RecceUnit:GetDesc()
|
local RecceUnitDesc = RecceUnit:GetDesc()
|
||||||
--self:F( { RecceUnit = RecceUnit:GetName(), RecceDescription = RecceUnitDesc } )
|
--self:F( { RecceUnit = RecceUnit:GetName(), RecceDescription = RecceUnitDesc } )x
|
||||||
|
|
||||||
if RecceUnit:IsLasing() == false then
|
if RecceUnit:IsLasing() == false then
|
||||||
--self:F( { IsDetected = RecceUnit:IsDetected( TargetUnit ), IsLOS = RecceUnit:IsLOS( TargetUnit ) } )
|
--self:F( { IsDetected = RecceUnit:IsDetected( TargetUnit ), IsLOS = RecceUnit:IsLOS( TargetUnit ) } )
|
||||||
@@ -1275,9 +1277,10 @@ do -- DESIGNATE
|
|||||||
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
|
local DesignateName = self.DesignateName
|
||||||
|
local typename = TargetUnit:GetTypeName()
|
||||||
|
|
||||||
function Spot:OnAfterDestroyed( From, Event, To )
|
function Spot:OnAfterDestroyed( From, Event, To )
|
||||||
self.Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() .. " destroyed. " .. TargetSetUnit:Count() .. " targets left.",
|
self.Recce:MessageToSetGroup( "Target " ..typename .. " destroyed. " .. TargetSetUnit:CountAlive() .. " targets left.",
|
||||||
5, AttackSet, self.DesignateName )
|
5, AttackSet, self.DesignateName )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1285,7 +1288,7 @@ do -- DESIGNATE
|
|||||||
-- 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.",
|
RecceUnit:MessageToSetGroup( "Marking " .. TargetUnitType .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.",
|
||||||
10, self.AttackSet, DesignateName )
|
10, self.AttackSet, DesignateName )
|
||||||
if not MarkedTypes[TargetUnitType] then
|
if not MarkedTypes[TargetUnitType] then
|
||||||
MarkedTypes[TargetUnitType] = true
|
MarkedTypes[TargetUnitType] = true
|
||||||
@@ -1392,7 +1395,7 @@ do -- DESIGNATE
|
|||||||
local MarkedCount = 0
|
local MarkedCount = 0
|
||||||
|
|
||||||
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
||||||
--- @param Wrapper.Unit#UNIT SmokeUnit
|
-- @param Wrapper.Unit#UNIT SmokeUnit
|
||||||
function( SmokeUnit )
|
function( SmokeUnit )
|
||||||
|
|
||||||
if MarkedCount < self.MaximumMarkings then
|
if MarkedCount < self.MaximumMarkings then
|
||||||
@@ -1457,9 +1460,10 @@ do -- DESIGNATE
|
|||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
function DESIGNATE:onafterDoneSmoking( From, Event, To, Index )
|
function DESIGNATE:onafterDoneSmoking( From, Event, To, Index )
|
||||||
|
if self.Designating[Index] ~= nil then
|
||||||
self.Designating[Index] = string.gsub( self.Designating[Index], "S", "" )
|
self.Designating[Index] = string.gsub( self.Designating[Index], "S", "" )
|
||||||
self:SetDesignateMenu()
|
self:SetDesignateMenu()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- DoneIlluminating
|
--- DoneIlluminating
|
||||||
@@ -1472,5 +1476,3 @@ do -- DESIGNATE
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -545,7 +545,7 @@ do -- DETECTION_BASE
|
|||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
function DETECTION_BASE:onafterDetect( From, Event, To )
|
function DETECTION_BASE:onafterDetect( From, Event, To )
|
||||||
|
|
||||||
local DetectDelay = 0.1
|
local DetectDelay = 0.15
|
||||||
self.DetectionCount = 0
|
self.DetectionCount = 0
|
||||||
self.DetectionRun = 0
|
self.DetectionRun = 0
|
||||||
self:UnIdentifyAllDetectedObjects() -- Resets the DetectedObjectsIdentified table
|
self:UnIdentifyAllDetectedObjects() -- Resets the DetectedObjectsIdentified table
|
||||||
@@ -604,7 +604,7 @@ do -- DETECTION_BASE
|
|||||||
-- @param #number DetectionTimeStamp Time stamp of detection event.
|
-- @param #number DetectionTimeStamp Time stamp of detection event.
|
||||||
function DETECTION_BASE:onafterDetection( From, Event, To, Detection, DetectionTimeStamp )
|
function DETECTION_BASE:onafterDetection( From, Event, To, Detection, DetectionTimeStamp )
|
||||||
|
|
||||||
-- self:F( { DetectedObjects = self.DetectedObjects } )
|
self:I( { DetectedObjects = self.DetectedObjects } )
|
||||||
|
|
||||||
self.DetectionRun = self.DetectionRun + 1
|
self.DetectionRun = self.DetectionRun + 1
|
||||||
|
|
||||||
@@ -612,14 +612,14 @@ do -- DETECTION_BASE
|
|||||||
|
|
||||||
if Detection and Detection:IsAlive() then
|
if Detection and Detection:IsAlive() then
|
||||||
|
|
||||||
-- self:T( { "DetectionGroup is Alive", DetectionGroup:GetName() } )
|
self:I( { "DetectionGroup is Alive", Detection:GetName() } )
|
||||||
|
|
||||||
local DetectionGroupName = Detection:GetName()
|
local DetectionGroupName = Detection:GetName()
|
||||||
local DetectionUnit = Detection:GetUnit( 1 )
|
local DetectionUnit = Detection:GetUnit( 1 )
|
||||||
|
|
||||||
local DetectedUnits = {}
|
local DetectedUnits = {}
|
||||||
|
|
||||||
local DetectedTargets = Detection:GetDetectedTargets(
|
local DetectedTargets = DetectionUnit:GetDetectedTargets(
|
||||||
self.DetectVisual,
|
self.DetectVisual,
|
||||||
self.DetectOptical,
|
self.DetectOptical,
|
||||||
self.DetectRadar,
|
self.DetectRadar,
|
||||||
@@ -628,7 +628,9 @@ do -- DETECTION_BASE
|
|||||||
self.DetectDLINK
|
self.DetectDLINK
|
||||||
)
|
)
|
||||||
|
|
||||||
self:F( { DetectedTargets = DetectedTargets } )
|
--self:I( { DetectedTargets = DetectedTargets } )
|
||||||
|
--self:I(UTILS.PrintTableToLog(DetectedTargets))
|
||||||
|
|
||||||
|
|
||||||
for DetectionObjectID, Detection in pairs( DetectedTargets ) do
|
for DetectionObjectID, Detection in pairs( DetectedTargets ) do
|
||||||
local DetectedObject = Detection.object -- DCS#Object
|
local DetectedObject = Detection.object -- DCS#Object
|
||||||
|
|||||||
@@ -19,6 +19,10 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Functional/FOX)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- ### Author: **funkyfranky**
|
-- ### Author: **funkyfranky**
|
||||||
-- @module Functional.Fox
|
-- @module Functional.Fox
|
||||||
-- @image Functional_FOX.png
|
-- @image Functional_FOX.png
|
||||||
@@ -437,7 +441,7 @@ function FOX:SetProtectedGroupSet(groupset)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a group to the protected set.
|
--- Add a group to the protected set. Works only with AI!
|
||||||
-- @param #FOX self
|
-- @param #FOX self
|
||||||
-- @param Wrapper.Group#GROUP group Protected group.
|
-- @param Wrapper.Group#GROUP group Protected group.
|
||||||
-- @return #FOX self
|
-- @return #FOX self
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
-- @module Functional.Mantis
|
-- @module Functional.Mantis
|
||||||
-- @image Functional.Mantis.jpg
|
-- @image Functional.Mantis.jpg
|
||||||
--
|
--
|
||||||
-- Last Update: Dec 2023
|
-- Last Update: May 2024
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **MANTIS** class, extends Core.Base#BASE
|
--- **MANTIS** class, extends Core.Base#BASE
|
||||||
@@ -58,6 +58,7 @@
|
|||||||
-- @field #boolean ShoradLink If true, #MANTIS has #SHORAD enabled
|
-- @field #boolean ShoradLink If true, #MANTIS has #SHORAD enabled
|
||||||
-- @field #number ShoradTime Timer in seconds, how long #SHORAD will be active after a detection inside of the defense range
|
-- @field #number ShoradTime Timer in seconds, how long #SHORAD will be active after a detection inside of the defense range
|
||||||
-- @field #number ShoradActDistance Distance of an attacker in meters from a Mantis SAM site, on which Shorad will be switched on. Useful to not give away Shorad sites too early. Default 15km. Should be smaller than checkradius.
|
-- @field #number ShoradActDistance Distance of an attacker in meters from a Mantis SAM site, on which Shorad will be switched on. Useful to not give away Shorad sites too early. Default 15km. Should be smaller than checkradius.
|
||||||
|
-- @field #boolean checkforfriendlies If true, do not activate a SAM installation if a friendly aircraft is in firing range.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -187,29 +188,34 @@
|
|||||||
-- -- This is effectively a 3-stage filter allowing for zone overlap. A coordinate is accepted first when
|
-- -- This is effectively a 3-stage filter allowing for zone overlap. A coordinate is accepted first when
|
||||||
-- -- it is inside any AcceptZone. Then RejectZones are checked, which enforces both borders, but also overlaps of
|
-- -- it is inside any AcceptZone. Then RejectZones are checked, which enforces both borders, but also overlaps of
|
||||||
-- -- Accept- and RejectZones. Last, if it is inside a conflict zone, it is accepted.
|
-- -- Accept- and RejectZones. Last, if it is inside a conflict zone, it is accepted.
|
||||||
-- `mybluemantis:AddZones(AcceptZones,RejectZones,ConflictZones)`
|
-- mybluemantis:AddZones(AcceptZones,RejectZones,ConflictZones)
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ### 2.1.2 Change the number of long-, mid- and short-range systems going live on a detected target:
|
-- ### 2.1.2 Change the number of long-, mid- and short-range systems going live on a detected target:
|
||||||
--
|
--
|
||||||
-- -- parameters are numbers. Defaults are 1,2,2,6 respectively
|
-- -- parameters are numbers. Defaults are 1,2,2,6 respectively
|
||||||
-- `mybluemantis:SetMaxActiveSAMs(Short,Mid,Long,Classic)`
|
-- mybluemantis:SetMaxActiveSAMs(Short,Mid,Long,Classic)
|
||||||
--
|
--
|
||||||
-- ### 2.1.3 SHORAD will automatically be added from SAM sites of type "short-range"
|
-- ### 2.1.3 SHORAD will automatically be added from SAM sites of type "short-range"
|
||||||
--
|
--
|
||||||
-- ### 2.1.4 Advanced features
|
-- ### 2.1.4 Advanced features
|
||||||
--
|
--
|
||||||
-- -- switch off auto mode **before** you start MANTIS.
|
-- -- switch off auto mode **before** you start MANTIS.
|
||||||
-- `mybluemantis.automode = false`
|
-- mybluemantis.automode = false
|
||||||
--
|
--
|
||||||
-- -- switch off auto shorad **before** you start MANTIS.
|
-- -- switch off auto shorad **before** you start MANTIS.
|
||||||
-- `mybluemantis.autoshorad = false`
|
-- mybluemantis.autoshorad = false
|
||||||
--
|
--
|
||||||
-- -- scale of the activation range, i.e. don't activate at the fringes of max range, defaults below.
|
-- -- scale of the activation range, i.e. don't activate at the fringes of max range, defaults below.
|
||||||
-- -- also see engagerange below.
|
-- -- also see engagerange below.
|
||||||
-- ` self.radiusscale[MANTIS.SamType.LONG] = 1.1`
|
-- self.radiusscale[MANTIS.SamType.LONG] = 1.1
|
||||||
-- ` self.radiusscale[MANTIS.SamType.MEDIUM] = 1.2`
|
-- self.radiusscale[MANTIS.SamType.MEDIUM] = 1.2
|
||||||
-- ` self.radiusscale[MANTIS.SamType.SHORT] = 1.3`
|
-- self.radiusscale[MANTIS.SamType.SHORT] = 1.3
|
||||||
|
--
|
||||||
|
-- ### 2.1.5 Friendlies check in firing range
|
||||||
|
--
|
||||||
|
-- -- For some scenarios, like Cold War, it might be useful not to activate SAMs if friendly aircraft are around to avoid death by friendly fire.
|
||||||
|
-- mybluemantis.checkforfriendlies = true
|
||||||
--
|
--
|
||||||
-- # 3. Default settings [both modes unless stated otherwise]
|
-- # 3. Default settings [both modes unless stated otherwise]
|
||||||
--
|
--
|
||||||
@@ -321,6 +327,7 @@ MANTIS = {
|
|||||||
automode = true,
|
automode = true,
|
||||||
autoshorad = true,
|
autoshorad = true,
|
||||||
ShoradGroupSet = nil,
|
ShoradGroupSet = nil,
|
||||||
|
checkforfriendlies = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Advanced state enumerator
|
--- Advanced state enumerator
|
||||||
@@ -347,17 +354,17 @@ MANTIS.SamType = {
|
|||||||
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
||||||
-- @field #string Radar Radar typename on unit level (used as key)
|
-- @field #string Radar Radar typename on unit level (used as key)
|
||||||
MANTIS.SamData = {
|
MANTIS.SamData = {
|
||||||
["Hawk"] = { Range=44, Blindspot=0, Height=9, Type="Medium", Radar="Hawk" }, -- measures in km
|
["Hawk"] = { Range=35, Blindspot=0, Height=12, Type="Medium", Radar="Hawk" }, -- measures in km
|
||||||
["NASAMS"] = { Range=14, Blindspot=0, Height=3, Type="Short", Radar="NSAMS" },
|
["NASAMS"] = { Range=14, Blindspot=0, Height=7, Type="Short", Radar="NSAMS" }, -- AIM 120B
|
||||||
["Patriot"] = { Range=99, Blindspot=0, Height=9, Type="Long", Radar="Patriot" },
|
["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot" },
|
||||||
["Rapier"] = { Range=6, Blindspot=0, Height=3, Type="Short", Radar="rapier" },
|
["Rapier"] = { Range=10, Blindspot=0, Height=3, Type="Short", Radar="rapier" },
|
||||||
["SA-2"] = { Range=40, Blindspot=7, Height=25, Type="Medium", Radar="S_75M_Volhov" },
|
["SA-2"] = { Range=40, Blindspot=7, Height=25, Type="Medium", Radar="S_75M_Volhov" },
|
||||||
["SA-3"] = { Range=18, Blindspot=6, Height=18, Type="Short", Radar="5p73 s-125 ln" },
|
["SA-3"] = { Range=18, Blindspot=6, Height=18, Type="Short", Radar="5p73 s-125 ln" },
|
||||||
["SA-5"] = { Range=250, Blindspot=7, Height=40, Type="Long", Radar="5N62V" },
|
["SA-5"] = { Range=250, Blindspot=7, Height=40, Type="Long", Radar="5N62V" },
|
||||||
["SA-6"] = { Range=25, Blindspot=0, Height=8, Type="Medium", Radar="1S91" },
|
["SA-6"] = { Range=25, Blindspot=0, Height=8, Type="Medium", Radar="1S91" },
|
||||||
["SA-10"] = { Range=119, Blindspot=0, Height=18, Type="Long" , Radar="S-300PS 4"},
|
["SA-10"] = { Range=119, Blindspot=0, Height=18, Type="Long" , Radar="S-300PS 4"},
|
||||||
["SA-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" },
|
["SA-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" },
|
||||||
["Roland"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Roland" },
|
["Roland"] = { Range=5, Blindspot=0, Height=5, Type="Short", Radar="Roland" },
|
||||||
["HQ-7"] = { Range=12, Blindspot=0, Height=3, Type="Short", Radar="HQ-7" },
|
["HQ-7"] = { Range=12, Blindspot=0, Height=3, Type="Short", Radar="HQ-7" },
|
||||||
["SA-9"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Strela" },
|
["SA-9"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Strela" },
|
||||||
["SA-8"] = { Range=10, Blindspot=0, Height=5, Type="Short", Radar="Osa 9A33" },
|
["SA-8"] = { Range=10, Blindspot=0, Height=5, Type="Short", Radar="Osa 9A33" },
|
||||||
@@ -503,6 +510,7 @@ do
|
|||||||
-- DONE: Allow tables of prefixes for the setup
|
-- DONE: Allow tables of prefixes for the setup
|
||||||
-- DONE: Auto-Mode with range setups for various known SAM types.
|
-- DONE: Auto-Mode with range setups for various known SAM types.
|
||||||
|
|
||||||
|
self.name = name or "mymantis"
|
||||||
self.SAM_Templates_Prefix = samprefix or "Red SAM"
|
self.SAM_Templates_Prefix = samprefix or "Red SAM"
|
||||||
self.EWR_Templates_Prefix = ewrprefix or "Red EWR"
|
self.EWR_Templates_Prefix = ewrprefix or "Red EWR"
|
||||||
self.HQ_Template_CC = hq or nil
|
self.HQ_Template_CC = hq or nil
|
||||||
@@ -631,7 +639,7 @@ do
|
|||||||
|
|
||||||
-- TODO Version
|
-- TODO Version
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
self.version="0.8.16"
|
self.version="0.8.18"
|
||||||
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||||
|
|
||||||
--- FSM Functions ---
|
--- FSM Functions ---
|
||||||
@@ -1222,10 +1230,10 @@ do
|
|||||||
function MANTIS:_PreFilterHeight(height)
|
function MANTIS:_PreFilterHeight(height)
|
||||||
self:T(self.lid.."_PreFilterHeight")
|
self:T(self.lid.."_PreFilterHeight")
|
||||||
local set = {}
|
local set = {}
|
||||||
local dlink = self.Detection -- Ops.Intelligence#INTEL_DLINK
|
local dlink = self.Detection -- Ops.Intel#INTEL_DLINK
|
||||||
local detectedgroups = dlink:GetContactTable()
|
local detectedgroups = dlink:GetContactTable()
|
||||||
for _,_contact in pairs(detectedgroups) do
|
for _,_contact in pairs(detectedgroups) do
|
||||||
local contact = _contact -- Ops.Intelligence#INTEL.Contact
|
local contact = _contact -- Ops.Intel#INTEL.Contact
|
||||||
local grp = contact.group -- Wrapper.Group#GROUP
|
local grp = contact.group -- Wrapper.Group#GROUP
|
||||||
if grp:IsAlive() then
|
if grp:IsAlive() then
|
||||||
if grp:GetHeight(true) < height then
|
if grp:GetHeight(true) < height then
|
||||||
@@ -1255,6 +1263,10 @@ do
|
|||||||
-- DEBUG
|
-- DEBUG
|
||||||
set = self:_PreFilterHeight(height)
|
set = self:_PreFilterHeight(height)
|
||||||
end
|
end
|
||||||
|
local friendlyset -- Core.Set#SET_GROUP
|
||||||
|
if self.checkforfriendlies == true then
|
||||||
|
friendlyset = SET_GROUP:New():FilterCoalitions(self.Coalition):FilterCategories({"plane","helicopter"}):FilterFunction(function(grp) if grp and grp:InAir() then return true else return false end end):FilterOnce()
|
||||||
|
end
|
||||||
for _,_coord in pairs (set) do
|
for _,_coord in pairs (set) do
|
||||||
local coord = _coord -- get current coord to check
|
local coord = _coord -- get current coord to check
|
||||||
-- output for cross-check
|
-- output for cross-check
|
||||||
@@ -1279,8 +1291,16 @@ do
|
|||||||
local m = MESSAGE:New(text,10,"Check"):ToAllIf(self.debug)
|
local m = MESSAGE:New(text,10,"Check"):ToAllIf(self.debug)
|
||||||
self:T(self.lid..text)
|
self:T(self.lid..text)
|
||||||
end
|
end
|
||||||
|
-- friendlies around?
|
||||||
|
local nofriendlies = true
|
||||||
|
if self.checkforfriendlies == true then
|
||||||
|
local closestfriend, distance = friendlyset:GetClosestGroup(samcoordinate)
|
||||||
|
if closestfriend and distance and distance < rad then
|
||||||
|
nofriendlies = false
|
||||||
|
end
|
||||||
|
end
|
||||||
-- end output to cross-check
|
-- end output to cross-check
|
||||||
if targetdistance <= rad and zonecheck then
|
if targetdistance <= rad and zonecheck == true and nofriendlies == true then
|
||||||
return true, targetdistance
|
return true, targetdistance
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1777,7 +1797,7 @@ do
|
|||||||
-- @return #MANTIS self
|
-- @return #MANTIS self
|
||||||
function MANTIS:_CheckDLinkState()
|
function MANTIS:_CheckDLinkState()
|
||||||
self:T(self.lid .. "_CheckDLinkState")
|
self:T(self.lid .. "_CheckDLinkState")
|
||||||
local dlink = self.Detection -- Ops.Intelligence#INTEL_DLINK
|
local dlink = self.Detection -- Ops.Intel#INTEL_DLINK
|
||||||
local TS = timer.getAbsTime()
|
local TS = timer.getAbsTime()
|
||||||
if not dlink:Is("Running") and (TS - self.DLTimeStamp > 29) then
|
if not dlink:Is("Running") and (TS - self.DLTimeStamp > 29) then
|
||||||
self.DLink = false
|
self.DLink = false
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
|||||||
-- Implementation is based on the [Simple Range Script](https://forums.eagle.ru/showthread.php?t=157991) by Ciribob, which itself was motivated
|
-- Implementation is based on the [Simple Range Script](https://forums.eagle.ru/showthread.php?t=157991) by Ciribob, which itself was motivated
|
||||||
-- by a script by SNAFU [see here](https://forums.eagle.ru/showthread.php?t=109174).
|
-- by a script by SNAFU [see here](https://forums.eagle.ru/showthread.php?t=109174).
|
||||||
--
|
--
|
||||||
-- [476th - Air Weapons Range Objects mod](http://www.476vfightergroup.com/downloads.php?do=file&id=287) is highly recommended for this class.
|
-- [476th - Air Weapons Range Objects mod](https://www.476vfightergroup.com/downloads.php?do=download&downloadid=482) is highly recommended for this class.
|
||||||
--
|
--
|
||||||
-- **Main Features:**
|
-- **Main Features:**
|
||||||
--
|
--
|
||||||
@@ -1226,10 +1226,8 @@ function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume,
|
|||||||
self.instructsrsQ = MSRSQUEUE:New("INSTRUCT")
|
self.instructsrsQ = MSRSQUEUE:New("INSTRUCT")
|
||||||
|
|
||||||
if PathToGoogleKey then
|
if PathToGoogleKey then
|
||||||
self.controlmsrs:SetProviderOptionsGoogle(PathToGoogleKey,PathToGoogleKey)
|
self.controlmsrs:SetGoogle(PathToGoogleKey)
|
||||||
self.controlmsrs:SetProvider(MSRS.Provider.GOOGLE)
|
self.instructmsrs:SetGoogle(PathToGoogleKey)
|
||||||
self.instructmsrs:SetProviderOptionsGoogle(PathToGoogleKey,PathToGoogleKey)
|
|
||||||
self.instructmsrs:SetProvider(MSRS.Provider.GOOGLE)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
--
|
--
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
|
-- * **Applevangelist**: Additional functionality, fixes.
|
||||||
-- * **Wingthor (TAW)**: Testing & Advice.
|
-- * **Wingthor (TAW)**: Testing & Advice.
|
||||||
-- * **Dutch-Baron (TAW)**: Testing & Advice.
|
-- * **Dutch-Baron (TAW)**: Testing & Advice.
|
||||||
-- * **Whisper**: Testing and Advice.
|
-- * **Whisper**: Testing and Advice.
|
||||||
@@ -116,11 +117,13 @@
|
|||||||
-- 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 @{Wrapper.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 @{Wrapper.Static}s.
|
-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Wrapper.Static}s.
|
||||||
-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Wrapper.Group}s.
|
-- Use the method @{#SCORING.AddScoreSetGroup}() to specify a special additional score for a specific @{Wrapper.Group}s gathered in a @{Core.Set#SET_GROUP}.
|
||||||
--
|
--
|
||||||
-- local Scoring = SCORING:New( "Scoring File" )
|
-- local Scoring = SCORING:New( "Scoring File" )
|
||||||
-- Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 )
|
-- Scoring:AddUnitScore( UNIT:FindByName( "Unit #001" ), 200 )
|
||||||
-- Scoring:AddStaticScore( STATIC:FindByName( "Static #1" ), 100 )
|
-- Scoring:AddStaticScore( STATIC:FindByName( "Static #1" ), 100 )
|
||||||
|
-- local GroupSet = SET_GROUP:New():FilterPrefixes("RAT"):FilterStart()
|
||||||
|
-- Scoring:AddScoreSetGroup( GroupSet, 100)
|
||||||
--
|
--
|
||||||
-- The above grants an additional score of 200 points for Unit #001 and an additional 100 points of Static #1 if these are destroyed.
|
-- The above grants an additional score of 200 points for Unit #001 and an additional 100 points of Static #1 if these are destroyed.
|
||||||
-- Note that later in the mission, one can remove these scores set, for example, when the a goal achievement time limit is over.
|
-- Note that later in the mission, one can remove these scores set, for example, when the a goal achievement time limit is over.
|
||||||
@@ -226,7 +229,7 @@ SCORING = {
|
|||||||
ClassID = 0,
|
ClassID = 0,
|
||||||
Players = {},
|
Players = {},
|
||||||
AutoSave = true,
|
AutoSave = true,
|
||||||
version = "1.17.1"
|
version = "1.18.4"
|
||||||
}
|
}
|
||||||
|
|
||||||
local _SCORINGCoalition = {
|
local _SCORINGCoalition = {
|
||||||
@@ -245,13 +248,15 @@ local _SCORINGCategory = {
|
|||||||
--- Creates a new SCORING object to administer the scoring achieved by players.
|
--- Creates a new SCORING object to administer the scoring achieved by players.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param #string GameName The name of the game. This name is also logged in the CSV score file.
|
-- @param #string GameName The name of the game. This name is also logged in the CSV score file.
|
||||||
|
-- @param #string SavePath (Optional) Path where to save the CSV file, defaults to your **<User>\\Saved Games\\DCS\\Logs** folder.
|
||||||
|
-- @param #boolean AutoSave (Optional) If passed as `false`, then swith autosave off.
|
||||||
-- @return #SCORING self
|
-- @return #SCORING self
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Define a new scoring object for the mission Gori Valley.
|
-- -- Define a new scoring object for the mission Gori Valley.
|
||||||
-- ScoringObject = SCORING:New( "Gori Valley" )
|
-- ScoringObject = SCORING:New( "Gori Valley" )
|
||||||
--
|
--
|
||||||
function SCORING:New( GameName )
|
function SCORING:New( GameName, SavePath, AutoSave )
|
||||||
|
|
||||||
-- Inherits from BASE
|
-- Inherits from BASE
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #SCORING
|
local self = BASE:Inherit( self, BASE:New() ) -- #SCORING
|
||||||
@@ -314,7 +319,8 @@ function SCORING:New( GameName )
|
|||||||
end )
|
end )
|
||||||
|
|
||||||
-- Create the CSV file.
|
-- Create the CSV file.
|
||||||
self.AutoSave = true
|
self.AutoSavePath = SavePath
|
||||||
|
self.AutoSave = AutoSave or true
|
||||||
self:OpenCSV( GameName )
|
self:OpenCSV( GameName )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -428,6 +434,31 @@ function SCORING:AddScoreGroup( ScoreGroup, Score )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Specify a special additional score for a @{Core.Set#SET_GROUP}.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param Core.Set#SET_GROUP Set The @{Core.Set#SET_GROUP} for which each @{Wrapper.Unit} in each Group a Score is given.
|
||||||
|
-- @param #number Score The Score value.
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:AddScoreSetGroup(Set, Score)
|
||||||
|
local set = Set:GetSetObjects()
|
||||||
|
|
||||||
|
for _,_group in pairs (set) do
|
||||||
|
if _group and _group:IsAlive() then
|
||||||
|
self:AddScoreGroup(_group,Score)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function AddScore(group)
|
||||||
|
self:AddScoreGroup(group,Score)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Set:OnAfterAdded(From,Event,To,ObjectName,Object)
|
||||||
|
AddScore(Object)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Add a @{Core.Zone} to define additional scoring when any object is destroyed in that zone.
|
--- Add a @{Core.Zone} to define additional scoring when any object is destroyed in that zone.
|
||||||
-- Note that if a @{Core.Zone} with the same name is already within the scoring added, the @{Core.Zone} (type) and Score will be replaced!
|
-- Note that if a @{Core.Zone} with the same name is already within the scoring added, the @{Core.Zone} (type) and Score will be replaced!
|
||||||
-- This allows for a dynamic destruction zone evolution within your mission.
|
-- This allows for a dynamic destruction zone evolution within your mission.
|
||||||
@@ -1030,11 +1061,11 @@ function SCORING:_EventOnHit( Event )
|
|||||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
||||||
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
||||||
PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
|
PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
|
||||||
-- After an instant kill we can't compute the thread level anymore. To fix this we compute at OnEventBirth
|
-- After an instant kill we can't compute the threat level anymore. To fix this we compute at OnEventBirth
|
||||||
if PlayerHit.UNIT.ThreatType == nil then
|
if PlayerHit.UNIT.ThreatType == nil then
|
||||||
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
||||||
-- if this fails for some reason, set a good default value
|
-- if this fails for some reason, set a good default value
|
||||||
if PlayerHit.ThreatType == nil then
|
if PlayerHit.ThreatType == nil or PlayerHit.ThreatType == "" then
|
||||||
PlayerHit.ThreatLevel = 1
|
PlayerHit.ThreatLevel = 1
|
||||||
PlayerHit.ThreatType = "Unknown"
|
PlayerHit.ThreatType = "Unknown"
|
||||||
end
|
end
|
||||||
@@ -1141,7 +1172,7 @@ function SCORING:_EventOnHit( Event )
|
|||||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
|
||||||
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
|
||||||
PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
|
PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
|
||||||
-- After an instant kill we can't compute the thread level anymore. To fix this we compute at OnEventBirth
|
-- After an instant kill we can't compute the threat level anymore. To fix this we compute at OnEventBirth
|
||||||
if PlayerHit.UNIT.ThreatType == nil then
|
if PlayerHit.UNIT.ThreatType == nil then
|
||||||
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()
|
||||||
-- if this fails for some reason, set a good default value
|
-- if this fails for some reason, set a good default value
|
||||||
@@ -1288,17 +1319,17 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1
|
TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1
|
||||||
|
|
||||||
|
|
||||||
self:OnKillPvP(Player, TargetPlayerName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty)
|
--self:OnKillPvP(PlayerName, TargetPlayerName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty)
|
||||||
|
|
||||||
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
||||||
self:OnKillPvP(Player, TargetPlayerName, true)
|
self:OnKillPvP(PlayerName, TargetPlayerName, true)
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
"Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty,
|
"Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information )
|
||||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||||
else
|
else
|
||||||
self:OnKillPvE(Player, TargetUnitName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty)
|
self:OnKillPvE(PlayerName, TargetUnitName, true, TargetThreatLevel, Player.ThreatLevel, ThreatPenalty)
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
"Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty,
|
"Penalty: -" .. ThreatPenalty .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information )
|
||||||
@@ -1326,14 +1357,14 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
else
|
else
|
||||||
Player.PlayerKills = 1
|
Player.PlayerKills = 1
|
||||||
end
|
end
|
||||||
self:OnKillPvP(Player, TargetPlayerName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore)
|
self:OnKillPvP(PlayerName, TargetPlayerName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore)
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
"Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty,
|
"Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information )
|
||||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||||
else
|
else
|
||||||
self:OnKillPvE(Player, TargetUnitName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore)
|
self:OnKillPvE(PlayerName, TargetUnitName, false, TargetThreatLevel, Player.ThreatLevel, ThreatScore)
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
"Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty,
|
"Score: +" .. ThreatScore .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information )
|
||||||
@@ -1811,10 +1842,11 @@ end
|
|||||||
function SCORING:OpenCSV( ScoringCSV )
|
function SCORING:OpenCSV( ScoringCSV )
|
||||||
self:F( ScoringCSV )
|
self:F( ScoringCSV )
|
||||||
|
|
||||||
if lfs and io and os and self.AutoSave then
|
if lfs and io and os and self.AutoSave == true then
|
||||||
if ScoringCSV then
|
if ScoringCSV then
|
||||||
self.ScoringCSV = ScoringCSV
|
self.ScoringCSV = ScoringCSV
|
||||||
local fdir = lfs.writedir() .. [[Logs\]] .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv"
|
local path = self.AutoSavePath or lfs.writedir() .. [[Logs\]]
|
||||||
|
local fdir = path .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv"
|
||||||
|
|
||||||
self.CSVFile, self.err = io.open( fdir, "w+" )
|
self.CSVFile, self.err = io.open( fdir, "w+" )
|
||||||
if not self.CSVFile then
|
if not self.CSVFile then
|
||||||
@@ -1935,23 +1967,23 @@ end
|
|||||||
|
|
||||||
--- Handles the event when one player kill another player
|
--- Handles the event when one player kill another player
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param #PLAYER Player the ataching player
|
-- @param #string PlayerName The attacking player
|
||||||
-- @param #string TargetPlayerName the name of the killed player
|
-- @param #string TargetPlayerName The name of the killed player
|
||||||
-- @param #bool IsTeamKill true if this kill was a team kill
|
-- @param #boolean IsTeamKill true if this kill was a team kill
|
||||||
-- @param #number TargetThreatLevel Thread level of the target
|
-- @param #number TargetThreatLevel Threat level of the target
|
||||||
-- @param #number PlayerThreatLevelThread level of the player
|
-- @param #number PlayerThreatLevel Threat level of the player
|
||||||
-- @param #number Score The score based on both threat levels
|
-- @param #number Score The score based on both threat levels
|
||||||
function SCORING:OnKillPvP(Player, TargetPlayerName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score)
|
function SCORING:OnKillPvP(PlayerName, TargetPlayerName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score)
|
||||||
|
|
||||||
end
|
end
|
||||||
--- Handles the event when one player kill another player
|
--- Handles the event when one player kill another player
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param #PLAYER Player the ataching player
|
-- @param #string PlayerName The attacking player
|
||||||
-- @param #string TargetUnitName the name of the killed unit
|
-- @param #string TargetUnitName the name of the killed unit
|
||||||
-- @param #bool IsTeamKill true if this kill was a team kill
|
-- @param #boolean IsTeamKill true if this kill was a team kill
|
||||||
-- @param #number TargetThreatLevel Thread level of the target
|
-- @param #number TargetThreatLevel Threat level of the target
|
||||||
-- @param #number PlayerThreatLevelThread level of the player
|
-- @param #number PlayerThreatLevel Threat level of the player
|
||||||
-- @param #number Score The score based on both threat levels
|
-- @param #number Score The score based on both threat levels
|
||||||
function SCORING:OnKillPvE(Player, TargetUnitName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score)
|
function SCORING:OnKillPvE(PlayerName, TargetUnitName, IsTeamKill, TargetThreatLevel, PlayerThreatLevel, Score)
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -320,9 +320,6 @@ function SEAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADG
|
|||||||
end
|
end
|
||||||
|
|
||||||
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterZones({targetzone}):FilterOnce()
|
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterZones({targetzone}):FilterOnce()
|
||||||
local tgtcoord = targetzone:GetRandomPointVec2()
|
|
||||||
--if tgtcoord and tgtcoord.ClassName == "COORDINATE" then
|
|
||||||
--local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
|
||||||
local tgtgrp = seadset:GetRandom()
|
local tgtgrp = seadset:GetRandom()
|
||||||
local _targetgroup = nil
|
local _targetgroup = nil
|
||||||
local _targetgroupname = "none"
|
local _targetgroupname = "none"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1629,7 +1629,7 @@ WAREHOUSE = {
|
|||||||
-- @field #boolean arrived If true, asset arrived at its destination.
|
-- @field #boolean arrived If true, asset arrived at its destination.
|
||||||
--
|
--
|
||||||
-- @field #number damage Damage of asset group in percent.
|
-- @field #number damage Damage of asset group in percent.
|
||||||
-- @field Ops.AirWing#AIRWING.Payload payload The payload of the asset.
|
-- @field Ops.Airwing#AIRWING.Payload payload The payload of the asset.
|
||||||
-- @field Ops.OpsGroup#OPSGROUP flightgroup The flightgroup object.
|
-- @field Ops.OpsGroup#OPSGROUP flightgroup The flightgroup object.
|
||||||
-- @field Ops.Cohort#COHORT cohort The cohort this asset belongs to.
|
-- @field Ops.Cohort#COHORT cohort The cohort this asset belongs to.
|
||||||
-- @field Ops.Legion#LEGION legion The legion this asset belonts to.
|
-- @field Ops.Legion#LEGION legion The legion this asset belonts to.
|
||||||
|
|||||||
@@ -154,6 +154,14 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Actions/Act_Route.lua' )
|
|||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Actions/Act_Account.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Actions/Act_Account.lua' )
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Actions/Act_Assist.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Actions/Act_Assist.lua' )
|
||||||
|
|
||||||
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Shapes/ShapeBase.lua' )
|
||||||
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Shapes/Circle.lua' )
|
||||||
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Shapes/Cube.lua' )
|
||||||
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Shapes/Line.lua' )
|
||||||
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Shapes/Oval.lua' )
|
||||||
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Shapes/Polygon.lua' )
|
||||||
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Shapes/Triangle.lua' )
|
||||||
|
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Sound/UserSound.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Sound/UserSound.lua' )
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Sound/SoundOutput.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Sound/SoundOutput.lua' )
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Sound/Radio.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Sound/Radio.lua' )
|
||||||
|
|||||||
@@ -255,6 +255,7 @@
|
|||||||
-- @field #boolean skipperUturn U-turn on/off via menu.
|
-- @field #boolean skipperUturn U-turn on/off via menu.
|
||||||
-- @field #number skipperOffset Holding offset angle in degrees for Case II/III manual recoveries.
|
-- @field #number skipperOffset Holding offset angle in degrees for Case II/III manual recoveries.
|
||||||
-- @field #number skipperTime Recovery time in min for manual recovery.
|
-- @field #number skipperTime Recovery time in min for manual recovery.
|
||||||
|
-- @field #boolean intowindold If true, use old into wind calculation.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- Be the boss!
|
--- Be the boss!
|
||||||
@@ -2724,6 +2725,18 @@ function AIRBOSS:SetLSOCallInterval( TimeInterval )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set if old into wind calculation is used when carrier turns into the wind for a recovery.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #boolean SwitchOn If `true` or `nil`, use old into wind calculation.
|
||||||
|
-- @return #AIRBOSS self
|
||||||
|
function AIRBOSS:SetIntoWindLegacy( SwitchOn )
|
||||||
|
if SwitchOn==nil then
|
||||||
|
SwitchOn=true
|
||||||
|
end
|
||||||
|
self.intowindold=SwitchOn
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Airboss is a rather nice guy and not strictly following the rules. Fore example, he does allow you into the landing pattern if you are not coming from the Marshal stack.
|
--- Airboss is a rather nice guy and not strictly following the rules. Fore example, he does allow you into the landing pattern if you are not coming from the Marshal stack.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #boolean Switch If true or nil, Airboss bends the rules a bit.
|
-- @param #boolean Switch If true or nil, Airboss bends the rules a bit.
|
||||||
@@ -3642,6 +3655,12 @@ function AIRBOSS:onafterStatus( From, Event, To )
|
|||||||
local pos = self:GetCoordinate()
|
local pos = self:GetCoordinate()
|
||||||
local speed = self.carrier:GetVelocityKNOTS()
|
local speed = self.carrier:GetVelocityKNOTS()
|
||||||
|
|
||||||
|
-- Update magnetic variation if we can get it from DCS.
|
||||||
|
if require then
|
||||||
|
self.magvar=pos:GetMagneticDeclination()
|
||||||
|
--env.info(string.format("FF magvar=%.1f", self.magvar))
|
||||||
|
end
|
||||||
|
|
||||||
-- Check water is ahead.
|
-- Check water is ahead.
|
||||||
local collision = false -- self:_CheckCollisionCoord(pos:Translate(self.collisiondist, hdg))
|
local collision = false -- self:_CheckCollisionCoord(pos:Translate(self.collisiondist, hdg))
|
||||||
|
|
||||||
@@ -5201,6 +5220,7 @@ function AIRBOSS:_InitVoiceOvers()
|
|||||||
TOMCAT = { file = "PILOT-Tomcat", suffix = "ogg", loud = false, subtitle = "", duration = 0.66, subduration = 5 },
|
TOMCAT = { file = "PILOT-Tomcat", suffix = "ogg", loud = false, subtitle = "", duration = 0.66, subduration = 5 },
|
||||||
HORNET = { file = "PILOT-Hornet", suffix = "ogg", loud = false, subtitle = "", duration = 0.56, subduration = 5 },
|
HORNET = { file = "PILOT-Hornet", suffix = "ogg", loud = false, subtitle = "", duration = 0.56, subduration = 5 },
|
||||||
VIKING = { file = "PILOT-Viking", suffix = "ogg", loud = false, subtitle = "", duration = 0.61, subduration = 5 },
|
VIKING = { file = "PILOT-Viking", suffix = "ogg", loud = false, subtitle = "", duration = 0.61, subduration = 5 },
|
||||||
|
GREYHOUND = { file = "PILOT-Greyhound", suffix = "ogg", loud = false, subtitle = "", duration = 0.61, subduration = 5 },
|
||||||
BALL = { file = "PILOT-Ball", suffix = "ogg", loud = false, subtitle = "", duration = 0.50, subduration = 5 },
|
BALL = { file = "PILOT-Ball", suffix = "ogg", loud = false, subtitle = "", duration = 0.50, subduration = 5 },
|
||||||
BINGOFUEL = { file = "PILOT-BingoFuel", suffix = "ogg", loud = false, subtitle = "", duration = 0.80 },
|
BINGOFUEL = { file = "PILOT-BingoFuel", suffix = "ogg", loud = false, subtitle = "", duration = 0.80 },
|
||||||
GASATDIVERT = { file = "PILOT-GasAtDivert", suffix = "ogg", loud = false, subtitle = "", duration = 1.80 },
|
GASATDIVERT = { file = "PILOT-GasAtDivert", suffix = "ogg", loud = false, subtitle = "", duration = 1.80 },
|
||||||
@@ -6475,7 +6495,7 @@ function AIRBOSS:_LandAI( flight )
|
|||||||
or flight.actype == AIRBOSS.AircraftCarrier.RHINOF
|
or flight.actype == AIRBOSS.AircraftCarrier.RHINOF
|
||||||
or flight.actype == AIRBOSS.AircraftCarrier.GROWLER then
|
or flight.actype == AIRBOSS.AircraftCarrier.GROWLER then
|
||||||
Speed = UTILS.KnotsToKmph( 200 )
|
Speed = UTILS.KnotsToKmph( 200 )
|
||||||
elseif flight.actype == AIRBOSS.AircraftCarrier.E2D then
|
elseif flight.actype == AIRBOSS.AircraftCarrier.E2D or flight.actype == AIRBOSS.AircraftCarrier.C2A then
|
||||||
Speed = UTILS.KnotsToKmph( 150 )
|
Speed = UTILS.KnotsToKmph( 150 )
|
||||||
elseif flight.actype == AIRBOSS.AircraftCarrier.F14A_AI or flight.actype == AIRBOSS.AircraftCarrier.F14A or flight.actype == AIRBOSS.AircraftCarrier.F14B then
|
elseif flight.actype == AIRBOSS.AircraftCarrier.F14A_AI or flight.actype == AIRBOSS.AircraftCarrier.F14A or flight.actype == AIRBOSS.AircraftCarrier.F14B then
|
||||||
Speed = UTILS.KnotsToKmph( 175 )
|
Speed = UTILS.KnotsToKmph( 175 )
|
||||||
@@ -9755,7 +9775,7 @@ function AIRBOSS:_Groove( playerData )
|
|||||||
local glideslopeError = groovedata.GSE
|
local glideslopeError = groovedata.GSE
|
||||||
local AoA = groovedata.AoA
|
local AoA = groovedata.AoA
|
||||||
|
|
||||||
if rho <= RXX and playerData.step == AIRBOSS.PatternStep.GROOVE_XX and (math.abs( groovedata.Roll ) <= 4.0 or playerData.unit:IsInZone( self:_GetZoneLineup() )) then
|
if rho <= RXX and playerData.step == AIRBOSS.PatternStep.GROOVE_XX and (math.abs( groovedata.Roll ) <= 4.0 and playerData.unit:IsInZone( self:_GetZoneLineup() )) then
|
||||||
|
|
||||||
-- Start time in groove
|
-- Start time in groove
|
||||||
playerData.TIG0 = timer.getTime()
|
playerData.TIG0 = timer.getTime()
|
||||||
@@ -11476,7 +11496,7 @@ end
|
|||||||
|
|
||||||
--- Get wind direction and speed at carrier position.
|
--- Get wind direction and speed at carrier position.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #number alt Altitude ASL in meters. Default 15 m.
|
-- @param #number alt Altitude ASL in meters. Default 18 m.
|
||||||
-- @param #boolean magnetic Direction including magnetic declination.
|
-- @param #boolean magnetic Direction including magnetic declination.
|
||||||
-- @param Core.Point#COORDINATE coord (Optional) Coordinate at which to get the wind. Default is current carrier position.
|
-- @param Core.Point#COORDINATE coord (Optional) Coordinate at which to get the wind. Default is current carrier position.
|
||||||
-- @return #number Direction the wind is blowing **from** in degrees.
|
-- @return #number Direction the wind is blowing **from** in degrees.
|
||||||
@@ -11548,10 +11568,31 @@ end
|
|||||||
|
|
||||||
--- Get true (or magnetic) heading of carrier into the wind. This accounts for the angled runway.
|
--- Get true (or magnetic) heading of carrier into the wind. This accounts for the angled runway.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #number vdeck Desired wind velocity over deck in knots.
|
||||||
-- @param #boolean magnetic If true, calculate magnetic heading. By default true heading is returned.
|
-- @param #boolean magnetic If true, calculate magnetic heading. By default true heading is returned.
|
||||||
-- @param Core.Point#COORDINATE coord (Optional) Coordinate from which heading is calculated. Default is current carrier position.
|
-- @param Core.Point#COORDINATE coord (Optional) Coordinate from which heading is calculated. Default is current carrier position.
|
||||||
-- @return #number Carrier heading in degrees.
|
-- @return #number Carrier heading in degrees.
|
||||||
function AIRBOSS:GetHeadingIntoWind_old( magnetic, coord )
|
-- @return #number Carrier speed in knots to reach desired wind speed on deck.
|
||||||
|
function AIRBOSS:GetHeadingIntoWind(vdeck, magnetic, coord )
|
||||||
|
|
||||||
|
if self.intowindold then
|
||||||
|
--env.info("FF use OLD into wind")
|
||||||
|
return self:GetHeadingIntoWind_old(vdeck, magnetic, coord)
|
||||||
|
else
|
||||||
|
--env.info("FF use NEW into wind")
|
||||||
|
return self:GetHeadingIntoWind_new(vdeck, magnetic, coord)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get true (or magnetic) heading of carrier into the wind. This accounts for the angled runway.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #number vdeck Desired wind velocity over deck in knots.
|
||||||
|
-- @param #boolean magnetic If true, calculate magnetic heading. By default true heading is returned.
|
||||||
|
-- @param Core.Point#COORDINATE coord (Optional) Coordinate from which heading is calculated. Default is current carrier position.
|
||||||
|
-- @return #number Carrier heading in degrees.
|
||||||
|
function AIRBOSS:GetHeadingIntoWind_old( vdeck, magnetic, coord )
|
||||||
|
|
||||||
local function adjustDegreesForWindSpeed(windSpeed)
|
local function adjustDegreesForWindSpeed(windSpeed)
|
||||||
local degreesAdjustment = 0
|
local degreesAdjustment = 0
|
||||||
@@ -11608,7 +11649,13 @@ function AIRBOSS:GetHeadingIntoWind_old( magnetic, coord )
|
|||||||
intowind = intowind + 360
|
intowind = intowind + 360
|
||||||
end
|
end
|
||||||
|
|
||||||
return intowind
|
-- Wind speed.
|
||||||
|
--local _, vwind = self:GetWind()
|
||||||
|
|
||||||
|
-- Speed of carrier in m/s but at least 4 knots.
|
||||||
|
local vtot = math.max(vdeck-UTILS.MpsToKnots(vwind), 4)
|
||||||
|
|
||||||
|
return intowind, vtot
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get true (or magnetic) heading of carrier into the wind. This accounts for the angled runway.
|
--- Get true (or magnetic) heading of carrier into the wind. This accounts for the angled runway.
|
||||||
@@ -11619,7 +11666,7 @@ end
|
|||||||
-- @param Core.Point#COORDINATE coord (Optional) Coordinate from which heading is calculated. Default is current carrier position.
|
-- @param Core.Point#COORDINATE coord (Optional) Coordinate from which heading is calculated. Default is current carrier position.
|
||||||
-- @return #number Carrier heading in degrees.
|
-- @return #number Carrier heading in degrees.
|
||||||
-- @return #number Carrier speed in knots to reach desired wind speed on deck.
|
-- @return #number Carrier speed in knots to reach desired wind speed on deck.
|
||||||
function AIRBOSS:GetHeadingIntoWind( vdeck, magnetic, coord )
|
function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord )
|
||||||
|
|
||||||
-- Default offset angle.
|
-- Default offset angle.
|
||||||
local Offset=self.carrierparam.rwyangle or 0
|
local Offset=self.carrierparam.rwyangle or 0
|
||||||
@@ -14280,6 +14327,8 @@ function AIRBOSS:_GetACNickname( actype )
|
|||||||
nickname = "Harrier"
|
nickname = "Harrier"
|
||||||
elseif actype == AIRBOSS.AircraftCarrier.E2D then
|
elseif actype == AIRBOSS.AircraftCarrier.E2D then
|
||||||
nickname = "Hawkeye"
|
nickname = "Hawkeye"
|
||||||
|
elseif actype == AIRBOSS.AircraftCarrier.C2A then
|
||||||
|
nickname = "Greyhound"
|
||||||
elseif actype == AIRBOSS.AircraftCarrier.F14A_AI or actype == AIRBOSS.AircraftCarrier.F14A or actype == AIRBOSS.AircraftCarrier.F14B then
|
elseif actype == AIRBOSS.AircraftCarrier.F14A_AI or actype == AIRBOSS.AircraftCarrier.F14A or actype == AIRBOSS.AircraftCarrier.F14B then
|
||||||
nickname = "Tomcat"
|
nickname = "Tomcat"
|
||||||
elseif actype == AIRBOSS.AircraftCarrier.FA18C or actype == AIRBOSS.AircraftCarrier.HORNET then
|
elseif actype == AIRBOSS.AircraftCarrier.FA18C or actype == AIRBOSS.AircraftCarrier.HORNET then
|
||||||
@@ -14317,32 +14366,55 @@ function AIRBOSS:_GetOnboardNumbers( group, playeronly )
|
|||||||
-- Debug text.
|
-- Debug text.
|
||||||
local text = string.format( "Onboard numbers of group %s:", groupname )
|
local text = string.format( "Onboard numbers of group %s:", groupname )
|
||||||
|
|
||||||
-- Units of template group.
|
local template=group:GetTemplate()
|
||||||
local units = group:GetTemplate().units
|
|
||||||
|
|
||||||
-- Get numbers.
|
|
||||||
local numbers = {}
|
local numbers = {}
|
||||||
for _, unit in pairs( units ) do
|
if template then
|
||||||
|
|
||||||
-- Onboard number and unit name.
|
-- Units of template group.
|
||||||
local n = tostring( unit.onboard_num )
|
local units = template.units
|
||||||
local name = unit.name
|
|
||||||
local skill = unit.skill or "Unknown"
|
|
||||||
|
|
||||||
-- Debug text.
|
-- Get numbers.
|
||||||
text = text .. string.format( "\n- unit %s: onboard #=%s skill=%s", name, n, tostring( skill ) )
|
for _, unit in pairs( units ) do
|
||||||
|
|
||||||
if playeronly and skill == "Client" or skill == "Player" then
|
-- Onboard number and unit name.
|
||||||
-- There can be only one player in the group, so we skip everything else.
|
local n = tostring( unit.onboard_num )
|
||||||
return n
|
local name = unit.name
|
||||||
|
local skill = unit.skill or "Unknown"
|
||||||
|
|
||||||
|
-- Debug text.
|
||||||
|
text = text .. string.format( "\n- unit %s: onboard #=%s skill=%s", name, n, tostring( skill ) )
|
||||||
|
|
||||||
|
if playeronly and skill == "Client" or skill == "Player" then
|
||||||
|
-- There can be only one player in the group, so we skip everything else.
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Table entry.
|
||||||
|
numbers[name] = n
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Table entry.
|
-- Debug info.
|
||||||
numbers[name] = n
|
self:T2( self.lid .. text )
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug info.
|
else
|
||||||
self:T2( self.lid .. text )
|
|
||||||
|
if playeronly then
|
||||||
|
return 101
|
||||||
|
else
|
||||||
|
|
||||||
|
local units=group:GetUnits()
|
||||||
|
|
||||||
|
for i,_unit in pairs(units) do
|
||||||
|
local name=_unit:GetName()
|
||||||
|
|
||||||
|
numbers[name]=100+i
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
return numbers
|
return numbers
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -976,7 +976,10 @@ function ARMYGROUP:onafterSpawned(From, Event, To)
|
|||||||
-- Update route.
|
-- Update route.
|
||||||
if Nwp>1 and self.isMobile then
|
if Nwp>1 and self.isMobile then
|
||||||
self:T(self.lid..string.format("Got %d waypoints on spawn ==> Cruise in -1.0 sec!", Nwp))
|
self:T(self.lid..string.format("Got %d waypoints on spawn ==> Cruise in -1.0 sec!", Nwp))
|
||||||
self:__Cruise(-1, nil, self.option.Formation)
|
local wp=self:GetWaypointNext()
|
||||||
|
self.option.Formation=wp.action
|
||||||
|
--self:__Cruise(-1, nil, self.option.Formation)
|
||||||
|
self:__Cruise(-1)
|
||||||
else
|
else
|
||||||
self:T(self.lid.."No waypoints on spawn ==> Full Stop!")
|
self:T(self.lid.."No waypoints on spawn ==> Full Stop!")
|
||||||
self:FullStop()
|
self:FullStop()
|
||||||
@@ -1287,6 +1290,7 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation)
|
|||||||
|
|
||||||
-- Current set speed in m/s.
|
-- Current set speed in m/s.
|
||||||
self.speedWp=wp.speed
|
self.speedWp=wp.speed
|
||||||
|
self:T(self.lid..string.format("Expected/waypoint speed=%.1f m/s", self.speedWp))
|
||||||
|
|
||||||
-- Debug output.
|
-- Debug output.
|
||||||
if self.verbose>=10 then --or self.attribute==GROUP.Attribute.GROUND_APC then
|
if self.verbose>=10 then --or self.attribute==GROUP.Attribute.GROUND_APC then
|
||||||
@@ -1950,7 +1954,7 @@ function ARMYGROUP:onafterCruise(From, Event, To, Speed, Formation)
|
|||||||
self.dTwait=nil
|
self.dTwait=nil
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid.."Cruise ==> Update route in 0.01 sec")
|
self:T(self.lid..string.format("Cruise ==> Update route in 0.01 sec (speed=%s, formation=%s)", tostring(Speed), tostring(Formation)))
|
||||||
|
|
||||||
-- Update route.
|
-- Update route.
|
||||||
self:__UpdateRoute(-0.01, nil, nil, Speed, Formation)
|
self:__UpdateRoute(-0.01, nil, nil, Speed, Formation)
|
||||||
@@ -2045,8 +2049,11 @@ end
|
|||||||
-- @param #ARMYGROUP self
|
-- @param #ARMYGROUP self
|
||||||
-- @param #table Template Template used to init the group. Default is `self.template`.
|
-- @param #table Template Template used to init the group. Default is `self.template`.
|
||||||
-- @return #ARMYGROUP self
|
-- @return #ARMYGROUP self
|
||||||
function ARMYGROUP:_InitGroup(Template)
|
function ARMYGROUP:_InitGroup(Template, Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, ARMYGROUP._InitGroup, self, Template, 0)
|
||||||
|
else
|
||||||
-- First check if group was already initialized.
|
-- First check if group was already initialized.
|
||||||
if self.groupinitialized then
|
if self.groupinitialized then
|
||||||
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
||||||
@@ -2069,10 +2076,11 @@ function ARMYGROUP:_InitGroup(Template)
|
|||||||
self.speedMax=self.group:GetSpeedMax()
|
self.speedMax=self.group:GetSpeedMax()
|
||||||
|
|
||||||
-- Is group mobile?
|
-- Is group mobile?
|
||||||
if self.speedMax>3.6 then
|
if self.speedMax and self.speedMax>3.6 then
|
||||||
self.isMobile=true
|
self.isMobile=true
|
||||||
else
|
else
|
||||||
self.isMobile=false
|
self.isMobile=false
|
||||||
|
self.speedMax = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Cruise speed in km/h
|
-- Cruise speed in km/h
|
||||||
@@ -2095,32 +2103,84 @@ function ARMYGROUP:_InitGroup(Template)
|
|||||||
-- Set default formation to "on road".
|
-- Set default formation to "on road".
|
||||||
self.optionDefault.Formation=ENUMS.Formation.Vehicle.OnRoad
|
self.optionDefault.Formation=ENUMS.Formation.Vehicle.OnRoad
|
||||||
|
|
||||||
-- Default TACAN off.
|
-- First check if group was already initialized.
|
||||||
self:SetDefaultTACAN(nil, nil, nil, nil, true)
|
if self.groupinitialized then
|
||||||
self.tacan=UTILS.DeepCopy(self.tacanDefault)
|
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Units of the group.
|
self:T(self.lid.."FF Initializing Group")
|
||||||
local units=self.group:GetUnits()
|
|
||||||
|
|
||||||
-- DCS group.
|
-- Get template of group.
|
||||||
local dcsgroup=Group.getByName(self.groupname)
|
local template=Template or self:_GetTemplate()
|
||||||
local size0=dcsgroup:getInitialSize()
|
|
||||||
|
|
||||||
-- Quick check.
|
-- Ground are always AI.
|
||||||
if #units~=size0 then
|
self.isAI=true
|
||||||
self:T(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units!", #units, size0))
|
|
||||||
|
-- Is (template) group late activated.
|
||||||
|
self.isLateActivated=template.lateActivation
|
||||||
|
|
||||||
|
-- Ground groups cannot be uncontrolled.
|
||||||
|
self.isUncontrolled=false
|
||||||
|
|
||||||
|
-- Max speed in km/h.
|
||||||
|
self.speedMax=self.group:GetSpeedMax()
|
||||||
|
|
||||||
|
-- Is group mobile?
|
||||||
|
if self.speedMax>3.6 then
|
||||||
|
self.isMobile=true
|
||||||
|
else
|
||||||
|
self.isMobile=false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Cruise speed in km/h
|
||||||
|
self.speedCruise=self.speedMax*0.7
|
||||||
|
|
||||||
|
-- Group ammo.
|
||||||
|
self.ammo=self:GetAmmoTot()
|
||||||
|
|
||||||
|
-- Radio parameters from template.
|
||||||
|
self.radio.On=false -- Radio is always OFF for ground.
|
||||||
|
self.radio.Freq=133
|
||||||
|
self.radio.Modu=radio.modulation.AM
|
||||||
|
|
||||||
|
-- Set default radio.
|
||||||
|
self:SetDefaultRadio(self.radio.Freq, self.radio.Modu, self.radio.On)
|
||||||
|
|
||||||
|
-- Get current formation from first waypoint.
|
||||||
|
self.option.Formation=template.route.points[1].action
|
||||||
|
|
||||||
|
-- Set default formation to "on road".
|
||||||
|
self.optionDefault.Formation=ENUMS.Formation.Vehicle.OnRoad
|
||||||
|
|
||||||
|
-- Default TACAN off.
|
||||||
|
self:SetDefaultTACAN(nil, nil, nil, nil, true)
|
||||||
|
self.tacan=UTILS.DeepCopy(self.tacanDefault)
|
||||||
|
|
||||||
|
-- Units of the group.
|
||||||
|
local units=self.group:GetUnits()
|
||||||
|
|
||||||
|
-- DCS group.
|
||||||
|
local dcsgroup=Group.getByName(self.groupname)
|
||||||
|
local size0=dcsgroup:getInitialSize()
|
||||||
|
local u=dcsgroup:getUnits()
|
||||||
|
|
||||||
|
-- Quick check.
|
||||||
|
if #units~=size0 then
|
||||||
|
self:T(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units! u=%d", #units, size0, #u))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add elemets.
|
||||||
|
for _,unit in pairs(units) do
|
||||||
|
local unitname=unit:GetName()
|
||||||
|
self:_AddElementByName(unitname)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Init done.
|
||||||
|
self.groupinitialized=true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add elemets.
|
|
||||||
for _,unit in pairs(units) do
|
|
||||||
local unitname=unit:GetName()
|
|
||||||
self:_AddElementByName(unitname)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Init done.
|
|
||||||
self.groupinitialized=true
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -145,7 +145,7 @@
|
|||||||
-- @field #table NassetsLegMax Number of required warehouse assets for each assigned legion.
|
-- @field #table NassetsLegMax Number of required warehouse assets for each assigned legion.
|
||||||
-- @field #table requestID The ID of the queued warehouse request. Necessary to cancel the request if the mission was cancelled before the request is processed.
|
-- @field #table requestID The ID of the queued warehouse request. Necessary to cancel the request if the mission was cancelled before the request is processed.
|
||||||
-- @field #table payloads User specified airwing payloads for this mission. Only these will be considered for the job!
|
-- @field #table payloads User specified airwing payloads for this mission. Only these will be considered for the job!
|
||||||
-- @field Ops.AirWing#AIRWING.PatrolData patroldata Patrol data.
|
-- @field Ops.Airwing#AIRWING.PatrolData patroldata Patrol data.
|
||||||
--
|
--
|
||||||
-- @field #table specialLegions User specified legions assigned for this mission. Only these will be considered for the job!
|
-- @field #table specialLegions User specified legions assigned for this mission. Only these will be considered for the job!
|
||||||
-- @field #table specialCohorts User specified cohorts assigned for this mission. Only these will be considered for the job!
|
-- @field #table specialCohorts User specified cohorts assigned for this mission. Only these will be considered for the job!
|
||||||
@@ -338,7 +338,7 @@
|
|||||||
--
|
--
|
||||||
-- ## Legion Level
|
-- ## Legion Level
|
||||||
--
|
--
|
||||||
-- Adding an AUFTRAG to an airwing is done via the @{Ops.AirWing#AIRWING.AddMission} function. See AIRWING docs for further details.
|
-- Adding an AUFTRAG to an airwing is done via the @{Ops.Airwing#AIRWING.AddMission} function. See AIRWING docs for further details.
|
||||||
-- Similarly, an AUFTRAG can be added to a brigade via the @{Ops.Brigade#BRIGADE.AddMission} function.
|
-- Similarly, an AUFTRAG can be added to a brigade via the @{Ops.Brigade#BRIGADE.AddMission} function.
|
||||||
--
|
--
|
||||||
-- ## Commander Level
|
-- ## Commander Level
|
||||||
@@ -3734,7 +3734,7 @@ end
|
|||||||
|
|
||||||
--- Add a required payload for this mission. Only these payloads will be used for this mission. If they are not available, the mission cannot start. Only available for use with an AIRWING.
|
--- Add a required payload for this mission. Only these payloads will be used for this mission. If they are not available, the mission cannot start. Only available for use with an AIRWING.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param Ops.AirWing#AIRWING.Payload Payload Required payload.
|
-- @param Ops.Airwing#AIRWING.Payload Payload Required payload.
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
function AUFTRAG:AddRequiredPayload(Payload)
|
function AUFTRAG:AddRequiredPayload(Payload)
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ do
|
|||||||
-- @field #number Frequency
|
-- @field #number Frequency
|
||||||
-- @field #number Modulation
|
-- @field #number Modulation
|
||||||
-- @field Wrapper.Airbase#AIRBASE Airbase
|
-- @field Wrapper.Airbase#AIRBASE Airbase
|
||||||
-- @field Ops.AirWing#AIRWING AirWing
|
-- @field Ops.Airwing#AIRWING AirWing
|
||||||
-- @field #number AwacsAngels
|
-- @field #number AwacsAngels
|
||||||
-- @field Core.Zone#ZONE OrbitZone
|
-- @field Core.Zone#ZONE OrbitZone
|
||||||
-- @field #number CallSign
|
-- @field #number CallSign
|
||||||
@@ -159,10 +159,10 @@ do
|
|||||||
--
|
--
|
||||||
-- ## 3 Airwing(s)
|
-- ## 3 Airwing(s)
|
||||||
--
|
--
|
||||||
-- The AWACS plane, the optional escort planes, and the AI CAP planes work based on the @{Ops.AirWing} class. Read and understand the manual for this class in
|
-- The AWACS plane, the optional escort planes, and the AI CAP planes work based on the @{Ops.Airwing} class. Read and understand the manual for this class in
|
||||||
-- order to set everything up correctly. You will at least need one Squadron containing the AWACS plane itself.
|
-- order to set everything up correctly. You will at least need one Squadron containing the AWACS plane itself.
|
||||||
--
|
--
|
||||||
-- Set up the AirWing
|
-- Set up the Airwing
|
||||||
--
|
--
|
||||||
-- local AwacsAW = AIRWING:New("AirForce WH-1","AirForce One")
|
-- local AwacsAW = AIRWING:New("AirForce WH-1","AirForce One")
|
||||||
-- AwacsAW:SetMarker(false)
|
-- AwacsAW:SetMarker(false)
|
||||||
@@ -226,7 +226,7 @@ do
|
|||||||
--
|
--
|
||||||
-- ## 5 Set up AWACS
|
-- ## 5 Set up AWACS
|
||||||
--
|
--
|
||||||
-- -- Set up AWACS called "AWACS North". It will use the AwacsAW AirWing set up above and be of the "blue" coalition. Homebase is Kutaisi.
|
-- -- Set up AWACS called "AWACS North". It will use the AwacsAW Airwing set up above and be of the "blue" coalition. Homebase is Kutaisi.
|
||||||
-- -- The AWACS Orbit Zone is a round zone set in the mission editor named "Awacs Orbit", the FEZ is a Polygon-Zone called "Rock" we have also
|
-- -- The AWACS Orbit Zone is a round zone set in the mission editor named "Awacs Orbit", the FEZ is a Polygon-Zone called "Rock" we have also
|
||||||
-- -- set up in the mission editor with a late activated helo named "Rock#ZONE_POLYGON". Note this also sets the BullsEye to be referenced as "Rock".
|
-- -- set up in the mission editor with a late activated helo named "Rock#ZONE_POLYGON". Note this also sets the BullsEye to be referenced as "Rock".
|
||||||
-- -- The CAP station zone is called "Fremont". We will be on 255 AM.
|
-- -- The CAP station zone is called "Fremont". We will be on 255 AM.
|
||||||
@@ -248,7 +248,7 @@ do
|
|||||||
--
|
--
|
||||||
-- ### 5.1 Alternative - Set up as GCI (no AWACS plane needed) Theater Air Control System (TACS)
|
-- ### 5.1 Alternative - Set up as GCI (no AWACS plane needed) Theater Air Control System (TACS)
|
||||||
--
|
--
|
||||||
-- -- Set up as TACS called "GCI Senaki". It will use the AwacsAW AirWing set up above and be of the "blue" coalition. Homebase is Senaki.
|
-- -- Set up as TACS called "GCI Senaki". It will use the AwacsAW Airwing set up above and be of the "blue" coalition. Homebase is Senaki.
|
||||||
-- -- No need to set the AWACS Orbit Zone; the FEZ is still a Polygon-Zone called "Rock" we have also
|
-- -- No need to set the AWACS Orbit Zone; the FEZ is still a Polygon-Zone called "Rock" we have also
|
||||||
-- -- set up in the mission editor with a late activated helo named "Rock#ZONE_POLYGON". Note this also sets the BullsEye to be referenced as "Rock".
|
-- -- set up in the mission editor with a late activated helo named "Rock#ZONE_POLYGON". Note this also sets the BullsEye to be referenced as "Rock".
|
||||||
-- -- The CAP station zone is called "Fremont". We will be on 255 AM. Note the Orbit Zone is given as *nil* in the `New()`-Statement
|
-- -- The CAP station zone is called "Fremont". We will be on 255 AM. Note the Orbit Zone is given as *nil* in the `New()`-Statement
|
||||||
@@ -508,7 +508,7 @@ do
|
|||||||
-- @field #AWACS
|
-- @field #AWACS
|
||||||
AWACS = {
|
AWACS = {
|
||||||
ClassName = "AWACS", -- #string
|
ClassName = "AWACS", -- #string
|
||||||
version = "0.2.61", -- #string
|
version = "0.2.64", -- #string
|
||||||
lid = "", -- #string
|
lid = "", -- #string
|
||||||
coalition = coalition.side.BLUE, -- #number
|
coalition = coalition.side.BLUE, -- #number
|
||||||
coalitiontxt = "blue", -- #string
|
coalitiontxt = "blue", -- #string
|
||||||
@@ -852,8 +852,8 @@ AWACS.Messages = {
|
|||||||
--- Contact Data
|
--- Contact Data
|
||||||
-- @type AWACS.ManagedContact
|
-- @type AWACS.ManagedContact
|
||||||
-- @field #number CID
|
-- @field #number CID
|
||||||
-- @field Ops.Intelligence#INTEL.Contact Contact
|
-- @field Ops.Intel#INTEL.Contact Contact
|
||||||
-- @field Ops.Intelligence#INTEL.Cluster Cluster
|
-- @field Ops.Intel#INTEL.Cluster Cluster
|
||||||
-- @field #string IFF -- ID'ed or not (yet)
|
-- @field #string IFF -- ID'ed or not (yet)
|
||||||
-- @field Ops.Target#TARGET Target
|
-- @field Ops.Target#TARGET Target
|
||||||
-- @field #number LinkedTask --> TID
|
-- @field #number LinkedTask --> TID
|
||||||
@@ -902,8 +902,8 @@ AWACS.TaskStatus = {
|
|||||||
-- @field #AWACS.TaskStatus Status
|
-- @field #AWACS.TaskStatus Status
|
||||||
-- @field #AWACS.TaskDescription ToDo
|
-- @field #AWACS.TaskDescription ToDo
|
||||||
-- @field #string ScreenText Long descrition
|
-- @field #string ScreenText Long descrition
|
||||||
-- @field Ops.Intelligence#INTEL.Contact Contact
|
-- @field Ops.Intel#INTEL.Contact Contact
|
||||||
-- @field Ops.Intelligence#INTEL.Cluster Cluster
|
-- @field Ops.Intel#INTEL.Cluster Cluster
|
||||||
-- @field #number CurrentAuftrag
|
-- @field #number CurrentAuftrag
|
||||||
-- @field #number RequestedTimestamp
|
-- @field #number RequestedTimestamp
|
||||||
|
|
||||||
@@ -956,7 +956,7 @@ AWACS.TaskStatus = {
|
|||||||
-- DONE - Shift Change, Change on asset RTB or dead or mission done (done for AWACS and Escorts)
|
-- DONE - Shift Change, Change on asset RTB or dead or mission done (done for AWACS and Escorts)
|
||||||
-- DONE - TripWire - WIP - Threat (35nm), Meld (45nm, on mission), Merged (<3nm)
|
-- DONE - TripWire - WIP - Threat (35nm), Meld (45nm, on mission), Merged (<3nm)
|
||||||
--
|
--
|
||||||
-- DONE - Escorts via AirWing not staying on
|
-- DONE - Escorts via Airwing not staying on
|
||||||
-- DONE - Borders for INTEL. Optional, i.e. land based defense within borders
|
-- DONE - Borders for INTEL. Optional, i.e. land based defense within borders
|
||||||
-- DONE - Use AO as Anchor of Bulls, AO as default
|
-- DONE - Use AO as Anchor of Bulls, AO as default
|
||||||
-- DONE - SRS TTS output
|
-- DONE - SRS TTS output
|
||||||
@@ -984,7 +984,7 @@ AWACS.TaskStatus = {
|
|||||||
--- Set up a new AI AWACS.
|
--- Set up a new AI AWACS.
|
||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param #string Name Name of this AWACS for the radio menu.
|
-- @param #string Name Name of this AWACS for the radio menu.
|
||||||
-- @param #string AirWing The core Ops.AirWing#AIRWING managing the AWACS, Escort and (optionally) AI CAP planes for us.
|
-- @param #string AirWing The core Ops.Airwing#AIRWING managing the AWACS, Escort and (optionally) AI CAP planes for us.
|
||||||
-- @param #number Coalition Coalition, e.g. coalition.side.BLUE. Can also be passed as "blue", "red" or "neutral".
|
-- @param #number Coalition Coalition, e.g. coalition.side.BLUE. Can also be passed as "blue", "red" or "neutral".
|
||||||
-- @param #string AirbaseName Name of the home airbase.
|
-- @param #string AirbaseName Name of the home airbase.
|
||||||
-- @param #string AwacsOrbit Name of the round, mission editor created zone where this AWACS orbits.
|
-- @param #string AwacsOrbit Name of the round, mission editor created zone where this AWACS orbits.
|
||||||
@@ -1024,7 +1024,7 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
|||||||
|
|
||||||
-- base setup
|
-- base setup
|
||||||
self.Name = Name -- #string
|
self.Name = Name -- #string
|
||||||
self.AirWing = AirWing -- Ops.AirWing#AIRWING object
|
self.AirWing = AirWing -- Ops.Airwing#AIRWING object
|
||||||
|
|
||||||
AirWing:SetUsingOpsAwacs(self)
|
AirWing:SetUsingOpsAwacs(self)
|
||||||
|
|
||||||
@@ -1032,7 +1032,7 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
|||||||
self.CAPAirwings:Push(AirWing,1)
|
self.CAPAirwings:Push(AirWing,1)
|
||||||
|
|
||||||
self.AwacsFG = nil
|
self.AwacsFG = nil
|
||||||
--self.AwacsPayload = PayLoad -- Ops.AirWing#AIRWING.Payload
|
--self.AwacsPayload = PayLoad -- Ops.Airwing#AIRWING.Payload
|
||||||
--self.ModernEra = true -- use of EPLRS
|
--self.ModernEra = true -- use of EPLRS
|
||||||
self.RadarBlur = 15 -- +/-15% detection precision i.e. 85-115 reported group size
|
self.RadarBlur = 15 -- +/-15% detection precision i.e. 85-115 reported group size
|
||||||
if type(OpsZone) == "string" then
|
if type(OpsZone) == "string" then
|
||||||
@@ -1384,7 +1384,7 @@ end
|
|||||||
-- Functions
|
-- Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- [User] Set the tactical information option, create 10 radio channels groups can subscribe and get Bogey Dope on a specific frequency automatically.
|
--- [User] Set the tactical information option, create 10 radio channels groups can subscribe and get Bogey Dope on a specific frequency automatically. You **need** to set up SRS first before using this!
|
||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param #number BaseFreq Base Frequency to use, defaults to 130.
|
-- @param #number BaseFreq Base Frequency to use, defaults to 130.
|
||||||
-- @param #number Increase Increase to use, defaults to 0.5, thus channels created are 130, 130.5, 131 .. etc.
|
-- @param #number Increase Increase to use, defaults to 0.5, thus channels created are 130, 130.5, 131 .. etc.
|
||||||
@@ -1394,6 +1394,10 @@ end
|
|||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:SetTacticalRadios(BaseFreq,Increase,Modulation,Interval,Number)
|
function AWACS:SetTacticalRadios(BaseFreq,Increase,Modulation,Interval,Number)
|
||||||
self:T(self.lid.."SetTacticalRadios")
|
self:T(self.lid.."SetTacticalRadios")
|
||||||
|
if not self.AwacsSRS then
|
||||||
|
MESSAGE:New("AWACS: Setup SRS in your code BEFORE trying to add tac radios please!",30,"ERROR",true):ToLog():ToAll()
|
||||||
|
return self
|
||||||
|
end
|
||||||
self.TacticalMenu = true
|
self.TacticalMenu = true
|
||||||
self.TacticalBaseFreq = BaseFreq or 130
|
self.TacticalBaseFreq = BaseFreq or 130
|
||||||
self.TacticalIncrFreq = Increase or 0.5
|
self.TacticalIncrFreq = Increase or 0.5
|
||||||
@@ -1407,7 +1411,7 @@ function AWACS:SetTacticalRadios(BaseFreq,Increase,Modulation,Interval,Number)
|
|||||||
self.TacticalFrequencies[freq] = freq
|
self.TacticalFrequencies[freq] = freq
|
||||||
end
|
end
|
||||||
if self.AwacsSRS then
|
if self.AwacsSRS then
|
||||||
self.TacticalSRS = MSRS:New(self.PathToSRS,self.TacticalBaseFreq,self.TacticalModulation)
|
self.TacticalSRS = MSRS:New(self.PathToSRS,self.TacticalBaseFreq,self.TacticalModulation,self.Backend)
|
||||||
self.TacticalSRS:SetCoalition(self.coalition)
|
self.TacticalSRS:SetCoalition(self.coalition)
|
||||||
self.TacticalSRS:SetGender(self.Gender)
|
self.TacticalSRS:SetGender(self.Gender)
|
||||||
self.TacticalSRS:SetCulture(self.Culture)
|
self.TacticalSRS:SetCulture(self.Culture)
|
||||||
@@ -2085,8 +2089,9 @@ end
|
|||||||
-- @param #number Volume Volume - between 0.0 (silent) and 1.0 (loudest)
|
-- @param #number Volume Volume - between 0.0 (silent) and 1.0 (loudest)
|
||||||
-- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS; if you use a config file for MSRS, hand in nil here.
|
-- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS; if you use a config file for MSRS, hand in nil here.
|
||||||
-- @param #string AccessKey (Optional) Your Google API access key. This is necessary if DCS-gRPC is used as backend; if you use a config file for MSRS, hand in nil here.
|
-- @param #string AccessKey (Optional) Your Google API access key. This is necessary if DCS-gRPC is used as backend; if you use a config file for MSRS, hand in nil here.
|
||||||
|
-- @param #string Backend (Optional) Your MSRS Backend if different from your config file settings, e.g. MSRS.Backend.SRSEXE or MSRS.Backend.GRPC
|
||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey)
|
function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Backend)
|
||||||
self:T(self.lid.."SetSRS")
|
self:T(self.lid.."SetSRS")
|
||||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||||
self.Gender = Gender or MSRS.gender or "male"
|
self.Gender = Gender or MSRS.gender or "male"
|
||||||
@@ -2096,8 +2101,9 @@ function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey
|
|||||||
self.PathToGoogleKey = PathToGoogleKey
|
self.PathToGoogleKey = PathToGoogleKey
|
||||||
self.AccessKey = AccessKey
|
self.AccessKey = AccessKey
|
||||||
self.Volume = Volume or 1.0
|
self.Volume = Volume or 1.0
|
||||||
|
self.Backend = Backend or MSRS.backend
|
||||||
self.AwacsSRS = MSRS:New(self.PathToSRS,self.MultiFrequency,self.MultiModulation)
|
BASE:I({backend = self.Backend})
|
||||||
|
self.AwacsSRS = MSRS:New(self.PathToSRS,self.MultiFrequency,self.MultiModulation,self.Backend)
|
||||||
self.AwacsSRS:SetCoalition(self.coalition)
|
self.AwacsSRS:SetCoalition(self.coalition)
|
||||||
self.AwacsSRS:SetGender(self.Gender)
|
self.AwacsSRS:SetGender(self.Gender)
|
||||||
self.AwacsSRS:SetCulture(self.Culture)
|
self.AwacsSRS:SetCulture(self.Culture)
|
||||||
@@ -2463,7 +2469,7 @@ function AWACS:_UpdateContactFromCluster(CID)
|
|||||||
|
|
||||||
local function GetFirstAliveContact(table)
|
local function GetFirstAliveContact(table)
|
||||||
for _,_contact in pairs (table) do
|
for _,_contact in pairs (table) do
|
||||||
local contact = _contact -- Ops.Intelligence#INTEL.Contact
|
local contact = _contact -- Ops.Intel#INTEL.Contact
|
||||||
if contact and contact.group and contact.group:IsAlive() then
|
if contact and contact.group and contact.group:IsAlive() then
|
||||||
return contact
|
return contact
|
||||||
end
|
end
|
||||||
@@ -2499,13 +2505,22 @@ function AWACS:_CheckMerges()
|
|||||||
local cpos = contact.Cluster.coordinate or contact.Contact.position or contact.Contact.group:GetCoordinate()
|
local cpos = contact.Cluster.coordinate or contact.Contact.position or contact.Contact.group:GetCoordinate()
|
||||||
local dist = ppos:Get2DDistance(cpos)
|
local dist = ppos:Get2DDistance(cpos)
|
||||||
local distnm = UTILS.Round(UTILS.MetersToNM(dist),0)
|
local distnm = UTILS.Round(UTILS.MetersToNM(dist),0)
|
||||||
if (pilot.IsPlayer or self.debug) and distnm <= 5 and not contact.MergeCallDone then
|
if (pilot.IsPlayer or self.debug) and distnm <= 5 then --and ((not contact.MergeCallDone) or (timer.getTime() - contact.MergeCallDone > 30)) then
|
||||||
local label = contact.EngagementTag or ""
|
--local label = contact.EngagementTag or ""
|
||||||
if not contact.MergeCallDone or not string.find(label,pcallsign) then
|
--if not contact.MergeCallDone or not string.find(label,pcallsign) then
|
||||||
self:T(self.lid.."Merged")
|
self:T(self.lid.."Merged")
|
||||||
self:_MergedCall(_id)
|
self:_MergedCall(_id)
|
||||||
contact.MergeCallDone = true
|
--contact.MergeCallDone = true
|
||||||
end
|
--end
|
||||||
|
end
|
||||||
|
if (pilot.IsPlayer or self.debug) and distnm >5 and distnm <= self.ThreatDistance then
|
||||||
|
self:_ThreatRangeCall(_id,Contact)
|
||||||
|
end
|
||||||
|
if (pilot.IsPlayer or self.debug) and distnm > self.ThreatDistance and distnm <= self.MeldDistance then
|
||||||
|
self:_MeldRangeCall(_id,Contact)
|
||||||
|
end
|
||||||
|
if (pilot.IsPlayer or self.debug) and distnm > self.MeldDistance and distnm <= self.TacDistance then
|
||||||
|
self:_TACRangeCall(_id,Contact)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
@@ -3099,7 +3114,7 @@ function AWACS:_BogeyDope(Group,Tactical)
|
|||||||
local clean = self.gettext:GetEntry("CLEAN",self.locale)
|
local clean = self.gettext:GetEntry("CLEAN",self.locale)
|
||||||
text = string.format(clean,self:_GetCallSign(Group,GID) or "Ghost 1", self.callsigntxt)
|
text = string.format(clean,self:_GetCallSign(Group,GID) or "Ghost 1", self.callsigntxt)
|
||||||
|
|
||||||
self:_NewRadioEntry(text,textScreen,GID,Outcome,Outcome,true,false,true,Tactical)
|
self:_NewRadioEntry(text,text,GID,Outcome,Outcome,true,false,true,Tactical)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@@ -3141,9 +3156,13 @@ end
|
|||||||
function AWACS:_ShowAwacsInfo(Group)
|
function AWACS:_ShowAwacsInfo(Group)
|
||||||
self:T(self.lid.."_ShowAwacsInfo")
|
self:T(self.lid.."_ShowAwacsInfo")
|
||||||
local report = REPORT:New("Info")
|
local report = REPORT:New("Info")
|
||||||
|
local STN = self.STN
|
||||||
report:Add("====================")
|
report:Add("====================")
|
||||||
report:Add(string.format("AWACS %s",self.callsigntxt))
|
report:Add(string.format("AWACS %s",self.callsigntxt))
|
||||||
report:Add(string.format("Radio: %.3f %s",self.Frequency,UTILS.GetModulationName(self.Modulation)))
|
report:Add(string.format("Radio: %.3f %s",self.Frequency,UTILS.GetModulationName(self.Modulation)))
|
||||||
|
if STN then
|
||||||
|
report:Add(string.format("Link-16 STN: %s",STN))
|
||||||
|
end
|
||||||
report:Add(string.format("Bulls Alias: %s",self.AOName))
|
report:Add(string.format("Bulls Alias: %s",self.AOName))
|
||||||
report:Add(string.format("Coordinate: %s",self.AOCoordinate:ToStringLLDDM()))
|
report:Add(string.format("Coordinate: %s",self.AOCoordinate:ToStringLLDDM()))
|
||||||
report:Add("====================")
|
report:Add("====================")
|
||||||
@@ -4260,7 +4279,7 @@ function AWACS:_StartIntel(awacs)
|
|||||||
|
|
||||||
intel:__Start(5)
|
intel:__Start(5)
|
||||||
|
|
||||||
self.intel = intel -- Ops.Intelligence#INTEL
|
self.intel = intel -- Ops.Intel#INTEL
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4420,8 +4439,8 @@ end
|
|||||||
-- @param #table Object Object for Ops.Target#TARGET assignment
|
-- @param #table Object Object for Ops.Target#TARGET assignment
|
||||||
-- @param #AWACS.TaskStatus TaskStatus Status of this task
|
-- @param #AWACS.TaskStatus TaskStatus Status of this task
|
||||||
-- @param Ops.Auftrag#AUFTRAG Auftrag The Auftrag for this task if any
|
-- @param Ops.Auftrag#AUFTRAG Auftrag The Auftrag for this task if any
|
||||||
-- @param Ops.Intelligence#INTEL.Cluster Cluster Intel Cluster for this task
|
-- @param Ops.Intel#INTEL.Cluster Cluster Intel Cluster for this task
|
||||||
-- @param Ops.Intelligence#INTEL.Contact Contact Intel Contact for this task
|
-- @param Ops.Intel#INTEL.Contact Contact Intel Contact for this task
|
||||||
-- @return #number TID Task ID created
|
-- @return #number TID Task ID created
|
||||||
function AWACS:_CreateTaskForGroup(GroupID,Description,ScreenText,Object,TaskStatus,Auftrag,Cluster,Contact)
|
function AWACS:_CreateTaskForGroup(GroupID,Description,ScreenText,Object,TaskStatus,Auftrag,Cluster,Contact)
|
||||||
self:T(self.lid.."_CreateTaskForGroup "..GroupID .." Description: "..Description)
|
self:T(self.lid.."_CreateTaskForGroup "..GroupID .." Description: "..Description)
|
||||||
@@ -4620,7 +4639,7 @@ function AWACS:_CheckTaskQueue()
|
|||||||
|
|
||||||
-- Check ranges for TAC and MELD
|
-- Check ranges for TAC and MELD
|
||||||
-- postions relative to CAP position
|
-- postions relative to CAP position
|
||||||
|
--[[
|
||||||
local targetgrp = entry.Contact.group
|
local targetgrp = entry.Contact.group
|
||||||
local position = entry.Contact.position or entry.Cluster.coordinate
|
local position = entry.Contact.position or entry.Cluster.coordinate
|
||||||
if targetgrp and targetgrp:IsAlive() and managedgroup then
|
if targetgrp and targetgrp:IsAlive() and managedgroup then
|
||||||
@@ -4645,6 +4664,7 @@ function AWACS:_CheckTaskQueue()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
--]]
|
||||||
|
|
||||||
local auftrag = entry.Auftrag -- Ops.Auftrag#AUFTRAG
|
local auftrag = entry.Auftrag -- Ops.Auftrag#AUFTRAG
|
||||||
local auftragstatus = "Not Known"
|
local auftragstatus = "Not Known"
|
||||||
@@ -4843,6 +4863,7 @@ function AWACS:_CheckTaskQueue()
|
|||||||
elseif entry.Status == AWACS.TaskStatus.ASSIGNED then
|
elseif entry.Status == AWACS.TaskStatus.ASSIGNED then
|
||||||
self:T("Open Tasks VID ASSIGNED for GroupID "..entry.AssignedGroupID)
|
self:T("Open Tasks VID ASSIGNED for GroupID "..entry.AssignedGroupID)
|
||||||
-- check TAC/MELD ranges
|
-- check TAC/MELD ranges
|
||||||
|
--[[
|
||||||
local targetgrp = entry.Contact.group
|
local targetgrp = entry.Contact.group
|
||||||
local position = entry.Contact.position or entry.Cluster.coordinate
|
local position = entry.Contact.position or entry.Cluster.coordinate
|
||||||
if targetgrp and targetgrp:IsAlive() and managedgroup then
|
if targetgrp and targetgrp:IsAlive() and managedgroup then
|
||||||
@@ -4867,6 +4888,7 @@ function AWACS:_CheckTaskQueue()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
--]]
|
||||||
elseif entry.Status == AWACS.TaskStatus.SUCCESS then
|
elseif entry.Status == AWACS.TaskStatus.SUCCESS then
|
||||||
self:T("Open Tasks VID success for GroupID "..entry.AssignedGroupID)
|
self:T("Open Tasks VID success for GroupID "..entry.AssignedGroupID)
|
||||||
-- outcomes - player ID'd
|
-- outcomes - player ID'd
|
||||||
@@ -4978,7 +5000,7 @@ end
|
|||||||
|
|
||||||
--- [User] Add another AirWing for AI CAP Flights under management
|
--- [User] Add another AirWing for AI CAP Flights under management
|
||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param Ops.AirWing#AIRWING AirWing The AirWing to (also) obtain CAP flights from
|
-- @param Ops.Airwing#AIRWING AirWing The AirWing to (also) obtain CAP flights from
|
||||||
-- @param Core.Zone#ZONE_RADIUS Zone (optional) This AirWing has it's own station zone, AI CAP will be send there
|
-- @param Core.Zone#ZONE_RADIUS Zone (optional) This AirWing has it's own station zone, AI CAP will be send there
|
||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:AddCAPAirWing(AirWing,Zone)
|
function AWACS:AddCAPAirWing(AirWing,Zone)
|
||||||
@@ -5063,7 +5085,7 @@ function AWACS:_AnnounceContact(Contact,IsNew,Group,IsBogeyDope,Tag,IsPopup,Repo
|
|||||||
end
|
end
|
||||||
|
|
||||||
local cluster = Contact.Cluster
|
local cluster = Contact.Cluster
|
||||||
local intel = self.intel -- Ops.Intelligence#INTEL
|
local intel = self.intel -- Ops.Intel#INTEL
|
||||||
|
|
||||||
local size = self.intel:ClusterCountUnits(cluster)
|
local size = self.intel:ClusterCountUnits(cluster)
|
||||||
local threatsize, threatsizetext = self:_GetBlurredSize(size)
|
local threatsize, threatsizetext = self:_GetBlurredSize(size)
|
||||||
@@ -5465,9 +5487,10 @@ function AWACS:_TACRangeCall(GID,Contact)
|
|||||||
if not Contact then return self end
|
if not Contact then return self end
|
||||||
local pilotcallsign = self:_GetCallSign(nil,GID)
|
local pilotcallsign = self:_GetCallSign(nil,GID)
|
||||||
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
local contact = Contact.Contact -- Ops.Intelligence#INTEL.Contact
|
local contact = Contact.Contact -- Ops.Intel#INTEL.Contact
|
||||||
local contacttag = Contact.TargetGroupNaming
|
local contacttag = Contact.TargetGroupNaming
|
||||||
if contact and not Contact.TACCallDone then
|
local name = managedgroup.GroupName
|
||||||
|
if contact then --and not Contact.TACCallDone then
|
||||||
local position = contact.position -- Core.Point#COORDINATE
|
local position = contact.position -- Core.Point#COORDINATE
|
||||||
if position then
|
if position then
|
||||||
local distance = position:Get2DDistance(managedgroup.Group:GetCoordinate())
|
local distance = position:Get2DDistance(managedgroup.Group:GetCoordinate())
|
||||||
@@ -5475,8 +5498,18 @@ function AWACS:_TACRangeCall(GID,Contact)
|
|||||||
local grptxt = self.gettext:GetEntry("GROUP",self.locale)
|
local grptxt = self.gettext:GetEntry("GROUP",self.locale)
|
||||||
local miles = self.gettext:GetEntry("MILES",self.locale)
|
local miles = self.gettext:GetEntry("MILES",self.locale)
|
||||||
local text = string.format("%s. %s. %s %s, %d %s.",self.callsigntxt,pilotcallsign,contacttag,grptxt,distance,miles)
|
local text = string.format("%s. %s. %s %s, %d %s.",self.callsigntxt,pilotcallsign,contacttag,grptxt,distance,miles)
|
||||||
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
if not self.TacticalSubscribers[name] then
|
||||||
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
||||||
|
end
|
||||||
self:_UpdateContactEngagementTag(Contact.CID,Contact.EngagementTag,true,false,AWACS.TaskStatus.EXECUTING)
|
self:_UpdateContactEngagementTag(Contact.CID,Contact.EngagementTag,true,false,AWACS.TaskStatus.EXECUTING)
|
||||||
|
if GID and GID ~= 0 then
|
||||||
|
--local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
|
if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then
|
||||||
|
if self.TacticalSubscribers[name] then
|
||||||
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -5494,9 +5527,10 @@ function AWACS:_MeldRangeCall(GID,Contact)
|
|||||||
local pilotcallsign = self:_GetCallSign(nil,GID)
|
local pilotcallsign = self:_GetCallSign(nil,GID)
|
||||||
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
local flightpos = managedgroup.Group:GetCoordinate()
|
local flightpos = managedgroup.Group:GetCoordinate()
|
||||||
local contact = Contact.Contact -- Ops.Intelligence#INTEL.Contact
|
local contact = Contact.Contact -- Ops.Intel#INTEL.Contact
|
||||||
local contacttag = Contact.TargetGroupNaming
|
local contacttag = Contact.TargetGroupNaming or "Bogey"
|
||||||
if contact and not Contact.MeldCallDone then
|
local name = managedgroup.GroupName
|
||||||
|
if contact then --and not Contact.MeldCallDone then
|
||||||
local position = contact.position -- Core.Point#COORDINATE
|
local position = contact.position -- Core.Point#COORDINATE
|
||||||
if position then
|
if position then
|
||||||
local BRATExt = ""
|
local BRATExt = ""
|
||||||
@@ -5507,8 +5541,19 @@ function AWACS:_MeldRangeCall(GID,Contact)
|
|||||||
end
|
end
|
||||||
local grptxt = self.gettext:GetEntry("GROUP",self.locale)
|
local grptxt = self.gettext:GetEntry("GROUP",self.locale)
|
||||||
local text = string.format("%s. %s. %s %s, %s",self.callsigntxt,pilotcallsign,contacttag,grptxt,BRATExt)
|
local text = string.format("%s. %s. %s %s, %s",self.callsigntxt,pilotcallsign,contacttag,grptxt,BRATExt)
|
||||||
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
if not self.TacticalSubscribers[name] then
|
||||||
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
||||||
|
end
|
||||||
self:_UpdateContactEngagementTag(Contact.CID,Contact.EngagementTag,true,true,AWACS.TaskStatus.EXECUTING)
|
self:_UpdateContactEngagementTag(Contact.CID,Contact.EngagementTag,true,true,AWACS.TaskStatus.EXECUTING)
|
||||||
|
if GID and GID ~= 0 then
|
||||||
|
--local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
|
if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then
|
||||||
|
local name = managedgroup.GroupName
|
||||||
|
if self.TacticalSubscribers[name] then
|
||||||
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -5524,8 +5569,10 @@ function AWACS:_ThreatRangeCall(GID,Contact)
|
|||||||
local pilotcallsign = self:_GetCallSign(nil,GID)
|
local pilotcallsign = self:_GetCallSign(nil,GID)
|
||||||
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
local flightpos = managedgroup.Group:GetCoordinate() or managedgroup.LastKnownPosition
|
local flightpos = managedgroup.Group:GetCoordinate() or managedgroup.LastKnownPosition
|
||||||
local contact = Contact.Contact -- Ops.Intelligence#INTEL.Contact
|
local contact = Contact.Contact -- Ops.Intel#INTEL.Contact
|
||||||
local contacttag = Contact.TargetGroupNaming
|
local contacttag = Contact.TargetGroupNaming or "Bogey"
|
||||||
|
local name = managedgroup.GroupName
|
||||||
|
local IsSub = self.TacticalSubscribers[name] and true or false
|
||||||
if contact then
|
if contact then
|
||||||
local position = contact.position or contact.group:GetCoordinate() -- Core.Point#COORDINATE
|
local position = contact.position or contact.group:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
if position then
|
if position then
|
||||||
@@ -5538,7 +5585,18 @@ function AWACS:_ThreatRangeCall(GID,Contact)
|
|||||||
local grptxt = self.gettext:GetEntry("GROUP",self.locale)
|
local grptxt = self.gettext:GetEntry("GROUP",self.locale)
|
||||||
local thrt = self.gettext:GetEntry("THREAT",self.locale)
|
local thrt = self.gettext:GetEntry("THREAT",self.locale)
|
||||||
local text = string.format("%s. %s. %s %s, %s. %s",self.callsigntxt,pilotcallsign,contacttag,grptxt, thrt, BRATExt)
|
local text = string.format("%s. %s. %s %s, %s. %s",self.callsigntxt,pilotcallsign,contacttag,grptxt, thrt, BRATExt)
|
||||||
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
if IsSub == false then
|
||||||
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
||||||
|
end
|
||||||
|
if GID and GID ~= 0 then
|
||||||
|
--local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
|
if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then
|
||||||
|
local name = managedgroup.GroupName
|
||||||
|
if self.TacticalSubscribers[name] then
|
||||||
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -5554,11 +5612,17 @@ function AWACS:_MergedCall(GID)
|
|||||||
local pilotcallsign = self:_GetCallSign(nil,GID)
|
local pilotcallsign = self:_GetCallSign(nil,GID)
|
||||||
local merge = self.gettext:GetEntry("MERGED",self.locale)
|
local merge = self.gettext:GetEntry("MERGED",self.locale)
|
||||||
local text = string.format("%s. %s. %s.",self.callsigntxt,pilotcallsign,merge)
|
local text = string.format("%s. %s. %s.",self.callsigntxt,pilotcallsign,merge)
|
||||||
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
|
local name
|
||||||
|
if managedgroup then
|
||||||
|
name = managedgroup.GroupName or "none"
|
||||||
|
end
|
||||||
|
if not self.TacticalSubscribers[name] then
|
||||||
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true)
|
||||||
|
end
|
||||||
if GID and GID ~= 0 then
|
if GID and GID ~= 0 then
|
||||||
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
local managedgroup = self.ManagedGrps[GID] -- #AWACS.ManagedGroup
|
||||||
if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then
|
if managedgroup and managedgroup.Group and managedgroup.Group:IsAlive() then
|
||||||
local name = managedgroup.GroupName
|
|
||||||
if self.TacticalSubscribers[name] then
|
if self.TacticalSubscribers[name] then
|
||||||
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true,true)
|
self:_NewRadioEntry(text,text,GID,true,self.debug,true,false,true,true)
|
||||||
end
|
end
|
||||||
@@ -5832,7 +5896,7 @@ function AWACS:onafterStart(From, Event, To)
|
|||||||
|
|
||||||
if not self.GCI then
|
if not self.GCI then
|
||||||
-- set up the AWACS and let it orbit
|
-- set up the AWACS and let it orbit
|
||||||
local AwacsAW = self.AirWing -- Ops.AirWing#AIRWING
|
local AwacsAW = self.AirWing -- Ops.Airwing#AIRWING
|
||||||
local mission = AUFTRAG:NewORBIT_RACETRACK(self.OrbitZone:GetCoordinate(),self.AwacsAngels*1000,self.Speed,self.Heading,self.Leg)
|
local mission = AUFTRAG:NewORBIT_RACETRACK(self.OrbitZone:GetCoordinate(),self.AwacsAngels*1000,self.Speed,self.Heading,self.Leg)
|
||||||
local timeonstation = (self.AwacsTimeOnStation + self.ShiftChangeTime) * 3600
|
local timeonstation = (self.AwacsTimeOnStation + self.ShiftChangeTime) * 3600
|
||||||
mission:SetTime(nil,timeonstation)
|
mission:SetTime(nil,timeonstation)
|
||||||
@@ -5953,6 +6017,10 @@ function AWACS:_CheckAwacsStatus()
|
|||||||
local awacs = nil -- Wrapper.Group#GROUP
|
local awacs = nil -- Wrapper.Group#GROUP
|
||||||
if self.AwacsFG then
|
if self.AwacsFG then
|
||||||
awacs = self.AwacsFG:GetGroup() -- Wrapper.Group#GROUP
|
awacs = self.AwacsFG:GetGroup() -- Wrapper.Group#GROUP
|
||||||
|
local unit = awacs:GetUnit(1)
|
||||||
|
if unit then
|
||||||
|
self.STN = tostring(unit:GetSTN())
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local monitoringdata = self.MonitoringData -- #AWACS.MonitoringData
|
local monitoringdata = self.MonitoringData -- #AWACS.MonitoringData
|
||||||
@@ -6426,7 +6494,7 @@ end
|
|||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Ops.Intelligence#INTEL.Cluster Cluster
|
-- @param Ops.Intel#INTEL.Cluster Cluster
|
||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:onafterNewCluster(From,Event,To,Cluster)
|
function AWACS:onafterNewCluster(From,Event,To,Cluster)
|
||||||
self:T({From, Event, To, Cluster.index})
|
self:T({From, Event, To, Cluster.index})
|
||||||
@@ -6438,7 +6506,7 @@ function AWACS:onafterNewCluster(From,Event,To,Cluster)
|
|||||||
|
|
||||||
local function GetFirstAliveContact(table)
|
local function GetFirstAliveContact(table)
|
||||||
for _,_contact in pairs (table) do
|
for _,_contact in pairs (table) do
|
||||||
local contact = _contact -- Ops.Intelligence#INTEL.Contact
|
local contact = _contact -- Ops.Intel#INTEL.Contact
|
||||||
if contact and contact.group and contact.group:IsAlive() then
|
if contact and contact.group and contact.group:IsAlive() then
|
||||||
return contact, contact.group
|
return contact, contact.group
|
||||||
end
|
end
|
||||||
@@ -6446,7 +6514,7 @@ function AWACS:onafterNewCluster(From,Event,To,Cluster)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local Contact, Group = GetFirstAliveContact(ContactTable) -- Ops.Intelligence#INTEL.Contact
|
local Contact, Group = GetFirstAliveContact(ContactTable) -- Ops.Intel#INTEL.Contact
|
||||||
|
|
||||||
if not Contact then return self end
|
if not Contact then return self end
|
||||||
|
|
||||||
@@ -6457,7 +6525,7 @@ function AWACS:onafterNewCluster(From,Event,To,Cluster)
|
|||||||
local targetset = SET_GROUP:New()
|
local targetset = SET_GROUP:New()
|
||||||
-- SET for TARGET
|
-- SET for TARGET
|
||||||
for _,_grp in pairs(ContactTable) do
|
for _,_grp in pairs(ContactTable) do
|
||||||
local grp = _grp -- Ops.Intelligence#INTEL.Contact
|
local grp = _grp -- Ops.Intel#INTEL.Contact
|
||||||
targetset:AddGroup(grp.group, true)
|
targetset:AddGroup(grp.group, true)
|
||||||
end
|
end
|
||||||
local managedcontact = {} -- #AWACS.ManagedContact
|
local managedcontact = {} -- #AWACS.ManagedContact
|
||||||
@@ -6519,7 +6587,7 @@ end
|
|||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Ops.Intelligence#INTEL.Contact Contact
|
-- @param Ops.Intel#INTEL.Contact Contact
|
||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:onafterNewContact(From,Event,To,Contact)
|
function AWACS:onafterNewContact(From,Event,To,Contact)
|
||||||
self:T({From, Event, To, Contact})
|
self:T({From, Event, To, Contact})
|
||||||
@@ -6548,7 +6616,7 @@ end
|
|||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Ops.Intelligence#INTEL.Contact Contact
|
-- @param Ops.Intel#INTEL.Contact Contact
|
||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:onafterLostContact(From,Event,To,Contact)
|
function AWACS:onafterLostContact(From,Event,To,Contact)
|
||||||
self:T({From, Event, To, Contact})
|
self:T({From, Event, To, Contact})
|
||||||
@@ -6560,7 +6628,7 @@ end
|
|||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Ops.Intelligence#INTEL.Cluster Cluster
|
-- @param Ops.Intel#INTEL.Cluster Cluster
|
||||||
-- @param Ops.Auftrag#AUFTRAG Mission
|
-- @param Ops.Auftrag#AUFTRAG Mission
|
||||||
-- @return #AWACS self
|
-- @return #AWACS self
|
||||||
function AWACS:onafterLostCluster(From,Event,To,Cluster,Mission)
|
function AWACS:onafterLostCluster(From,Event,To,Cluster,Mission)
|
||||||
@@ -6632,7 +6700,7 @@ function AWACS:onafterCheckTacticalQueue(From,Event,To)
|
|||||||
|
|
||||||
end -- end while
|
end -- end while
|
||||||
|
|
||||||
if self:Is("Running") then
|
if not self:Is("Stopped") then
|
||||||
self:__CheckTacticalQueue(-self.TacticalInterval)
|
self:__CheckTacticalQueue(-self.TacticalInterval)
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -6761,7 +6829,7 @@ function AWACS:onafterAwacsShiftChange(From,Event,To)
|
|||||||
self.AwacsTimeStamp = timer.getTime()
|
self.AwacsTimeStamp = timer.getTime()
|
||||||
|
|
||||||
-- set up the AWACS and let it orbit
|
-- set up the AWACS and let it orbit
|
||||||
local AwacsAW = self.AirWing -- Ops.AirWing#AIRWING
|
local AwacsAW = self.AirWing -- Ops.Airwing#AIRWING
|
||||||
local mission = AUFTRAG:NewORBIT_RACETRACK(self.OrbitZone:GetCoordinate(),self.AwacsAngels*1000,self.Speed,self.Heading,self.Leg)
|
local mission = AUFTRAG:NewORBIT_RACETRACK(self.OrbitZone:GetCoordinate(),self.AwacsAngels*1000,self.Speed,self.Heading,self.Leg)
|
||||||
self.CatchAllMissions[#self.CatchAllMissions+1] = mission
|
self.CatchAllMissions[#self.CatchAllMissions+1] = mission
|
||||||
local timeonstation = (self.AwacsTimeOnStation + self.ShiftChangeTime) * 3600
|
local timeonstation = (self.AwacsTimeOnStation + self.ShiftChangeTime) * 3600
|
||||||
|
|||||||
@@ -313,8 +313,8 @@ end
|
|||||||
--
|
--
|
||||||
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
|
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
|
||||||
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
|
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
|
||||||
-- local BlueSaveOps = SET_GROUP:New():FilterCoalitions("blue"):FilterPrefixes("AID"):FilterCategoryGround():FilterOnce()
|
-- local BlueSaveOps = SET_OPSGROUP:New():FilterCoalitions("blue"):FilterCategoryGround():FilterOnce()
|
||||||
-- UTILS.SaveSetOfGroups(BlueSaveOps,Path,BlueOpsFilename)
|
-- UTILS.SaveSetOfOpsGroups(BlueSaveOps,Path,BlueOpsFilename)
|
||||||
--
|
--
|
||||||
-- where Path and Filename are strings, as chosen by you.
|
-- where Path and Filename are strings, as chosen by you.
|
||||||
-- You can then load back the assets at the start of your next mission run. Be aware that it takes a couple of seconds for the
|
-- You can then load back the assets at the start of your next mission run. Be aware that it takes a couple of seconds for the
|
||||||
@@ -324,7 +324,7 @@ end
|
|||||||
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
|
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
|
||||||
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
|
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
|
||||||
-- if UTILS.CheckFileExists(Path,BlueOpsFilename) then
|
-- if UTILS.CheckFileExists(Path,BlueOpsFilename) then
|
||||||
-- local loadback = UTILS.LoadSetOfGroups(Path,BlueOpsFilename,false)
|
-- local loadback = UTILS.LoadSetOfOpsGroups(Path,BlueOpsFilename,false)
|
||||||
-- for _,_platoondata in pairs (loadback) do
|
-- for _,_platoondata in pairs (loadback) do
|
||||||
-- local groupname = _platoondata.groupname -- #string
|
-- local groupname = _platoondata.groupname -- #string
|
||||||
-- local coordinate = _platoondata.coordinate -- Core.Point#COORDINATE
|
-- local coordinate = _platoondata.coordinate -- Core.Point#COORDINATE
|
||||||
|
|||||||
@@ -30,8 +30,8 @@
|
|||||||
-- @module Ops.CSAR
|
-- @module Ops.CSAR
|
||||||
-- @image OPS_CSAR.jpg
|
-- @image OPS_CSAR.jpg
|
||||||
|
|
||||||
-- Date: May 2023
|
---
|
||||||
-- Last: Update Dec 2024
|
-- Last Update April 2024
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
||||||
@@ -290,10 +290,13 @@ CSAR.AircraftType["Bell-47"] = 2
|
|||||||
CSAR.AircraftType["UH-60L"] = 10
|
CSAR.AircraftType["UH-60L"] = 10
|
||||||
CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
||||||
CSAR.AircraftType["Bronco-OV-10A"] = 2
|
CSAR.AircraftType["Bronco-OV-10A"] = 2
|
||||||
|
CSAR.AircraftType["MH-60R"] = 10
|
||||||
|
CSAR.AircraftType["OH-6A"] = 2
|
||||||
|
CSAR.AircraftType["OH58D"] = 2
|
||||||
|
|
||||||
--- CSAR class version.
|
--- CSAR class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CSAR.version="1.0.19"
|
CSAR.version="1.0.24"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -462,7 +465,7 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
self.SRSModulation = radio.modulation.AM -- modulation
|
self.SRSModulation = radio.modulation.AM -- modulation
|
||||||
self.SRSport = 5002 -- port
|
self.SRSport = 5002 -- port
|
||||||
self.SRSCulture = "en-GB"
|
self.SRSCulture = "en-GB"
|
||||||
self.SRSVoice = nil
|
self.SRSVoice = MSRS.Voices.Google.Standard.en_GB_Standard_B
|
||||||
self.SRSGPathToCredentials = nil
|
self.SRSGPathToCredentials = nil
|
||||||
self.SRSVolume = 1.0 -- volume 0.0 to 1.0
|
self.SRSVolume = 1.0 -- volume 0.0 to 1.0
|
||||||
self.SRSGender = "male" -- male or female
|
self.SRSGender = "male" -- male or female
|
||||||
@@ -733,7 +736,7 @@ function CSAR:_SpawnPilotInField(country,point,frequency,wetfeet)
|
|||||||
:NewWithAlias(template,alias)
|
:NewWithAlias(template,alias)
|
||||||
:InitCoalition(coalition)
|
:InitCoalition(coalition)
|
||||||
:InitCountry(country)
|
:InitCountry(country)
|
||||||
:InitAIOnOff(pilotcacontrol)
|
--:InitAIOnOff(pilotcacontrol)
|
||||||
:InitDelayOff()
|
:InitDelayOff()
|
||||||
:SpawnFromCoordinate(point)
|
:SpawnFromCoordinate(point)
|
||||||
|
|
||||||
@@ -1189,7 +1192,7 @@ function CSAR:_EventHandler(EventData)
|
|||||||
|
|
||||||
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
|
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
|
||||||
self:__Landed(2,_event.IniUnitName, _place)
|
self:__Landed(2,_event.IniUnitName, _place)
|
||||||
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true)
|
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true)
|
||||||
else
|
else
|
||||||
self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition()))
|
self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition()))
|
||||||
end
|
end
|
||||||
@@ -1237,10 +1240,24 @@ function CSAR:_InitSARForPilot(_downedGroup, _GroupName, _freq, _nomessage, _pla
|
|||||||
if not _nomessage then
|
if not _nomessage then
|
||||||
if _freq ~= 0 then --shagrat
|
if _freq ~= 0 then --shagrat
|
||||||
local _text = string.format("%s requests SAR at %s, beacon at %.2f KHz", _groupName, _coordinatesText, _freqk)--shagrat _groupName to prevent 'f15_Pilot_Parachute'
|
local _text = string.format("%s requests SAR at %s, beacon at %.2f KHz", _groupName, _coordinatesText, _freqk)--shagrat _groupName to prevent 'f15_Pilot_Parachute'
|
||||||
self:_DisplayToAllSAR(_text,self.coalition,self.messageTime)
|
if self.coordtype ~= 2 then --not MGRS
|
||||||
|
self:_DisplayToAllSAR(_text,self.coalition,self.messageTime)
|
||||||
|
else
|
||||||
|
self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,false,true)
|
||||||
|
local coordtext = UTILS.MGRSStringToSRSFriendly(_coordinatesText,true)
|
||||||
|
local _text = string.format("%s requests SAR at %s, beacon at %.2f kilo hertz", _groupName, coordtext, _freqk)
|
||||||
|
self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,true,false)
|
||||||
|
end
|
||||||
else --shagrat CASEVAC msg
|
else --shagrat CASEVAC msg
|
||||||
local _text = string.format("Pickup Zone at %s.", _coordinatesText )
|
local _text = string.format("Pickup Zone at %s.", _coordinatesText )
|
||||||
self:_DisplayToAllSAR(_text,self.coalition,self.messageTime)
|
if self.coordtype ~= 2 then --not MGRS
|
||||||
|
self:_DisplayToAllSAR(_text,self.coalition,self.messageTime)
|
||||||
|
else
|
||||||
|
self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,false,true)
|
||||||
|
local coordtext = UTILS.MGRSStringToSRSFriendly(_coordinatesText,true)
|
||||||
|
local _text = string.format("Pickup Zone at %s.", coordtext )
|
||||||
|
self:_DisplayToAllSAR(_text,self.coalition,self.messageTime,true,false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1528,7 +1545,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
local _reset = true
|
local _reset = true
|
||||||
|
|
||||||
if (_distance < 500) then
|
if (_distance < 500) then
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Helo closer than 500m: ".._lookupKeyHeli)
|
||||||
if self.heliCloseMessage[_lookupKeyHeli] == nil then
|
if self.heliCloseMessage[_lookupKeyHeli] == nil then
|
||||||
if self.autosmoke == true then
|
if self.autosmoke == true then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
|
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
|
||||||
@@ -1537,14 +1554,16 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
end
|
end
|
||||||
self.heliCloseMessage[_lookupKeyHeli] = true
|
self.heliCloseMessage[_lookupKeyHeli] = true
|
||||||
end
|
end
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Checking landed vs Hover for ".._lookupKeyHeli)
|
||||||
-- have we landed close enough?
|
-- have we landed close enough?
|
||||||
if not _heliUnit:InAir() then
|
if not _heliUnit:InAir() then
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Helo landed: ".._lookupKeyHeli)
|
||||||
if self.pilotRuntoExtractPoint == true then
|
if self.pilotRuntoExtractPoint == true then
|
||||||
if (_distance < self.extractDistance) then
|
if (_distance < self.extractDistance) then
|
||||||
local _time = self.landedStatus[_lookupKeyHeli]
|
local _time = self.landedStatus[_lookupKeyHeli]
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Check pilot running or arrived ".._lookupKeyHeli)
|
||||||
if _time == nil then
|
if _time == nil then
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Pilot running not arrived yet ".._lookupKeyHeli)
|
||||||
self.landedStatus[_lookupKeyHeli] = math.floor( (_distance - self.loadDistance) / 3.6 )
|
self.landedStatus[_lookupKeyHeli] = math.floor( (_distance - self.loadDistance) / 3.6 )
|
||||||
_time = self.landedStatus[_lookupKeyHeli]
|
_time = self.landedStatus[_lookupKeyHeli]
|
||||||
_woundedGroup:OptionAlarmStateGreen()
|
_woundedGroup:OptionAlarmStateGreen()
|
||||||
@@ -1555,11 +1574,15 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
self.landedStatus[_lookupKeyHeli] = _time
|
self.landedStatus[_lookupKeyHeli] = _time
|
||||||
end
|
end
|
||||||
--if _time <= 0 or _distance < self.loadDistance then
|
--if _time <= 0 or _distance < self.loadDistance then
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Pilot close enough? ".._lookupKeyHeli)
|
||||||
if _distance < self.loadDistance + 5 or _distance <= 13 then
|
if _distance < self.loadDistance + 5 or _distance <= 13 then
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Pilot close enough - YES ".._lookupKeyHeli)
|
||||||
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
|
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Pick up Pilot ".._lookupKeyHeli)
|
||||||
self.landedStatus[_lookupKeyHeli] = nil
|
self.landedStatus[_lookupKeyHeli] = nil
|
||||||
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
||||||
return true
|
return true
|
||||||
@@ -1567,28 +1590,32 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Helo landed, pilot NOT set to run to helo ".._lookupKeyHeli)
|
||||||
if (_distance < self.loadDistance) then
|
if (_distance < self.loadDistance) then
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Helo close enough, door check ".._lookupKeyHeli)
|
||||||
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
|
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Pick up Pilot ".._lookupKeyHeli)
|
||||||
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Helo hovering".._lookupKeyHeli)
|
||||||
local _unitsInHelicopter = self:_PilotsOnboard(_heliName)
|
local _unitsInHelicopter = self:_PilotsOnboard(_heliName)
|
||||||
local _maxUnits = self.AircraftType[_heliUnit:GetTypeName()]
|
local _maxUnits = self.AircraftType[_heliUnit:GetTypeName()]
|
||||||
if _maxUnits == nil then
|
if _maxUnits == nil then
|
||||||
_maxUnits = self.max_units
|
_maxUnits = self.max_units
|
||||||
end
|
end
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Check capacity and close enough for winching ".._lookupKeyHeli)
|
||||||
if _heliUnit:InAir() and _unitsInHelicopter + 1 <= _maxUnits then
|
if _heliUnit:InAir() and _unitsInHelicopter + 1 <= _maxUnits then
|
||||||
-- DONE - make variable
|
-- DONE - make variable
|
||||||
if _distance < self.rescuehoverdistance then
|
if _distance < self.rescuehoverdistance then
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Helo hovering close enough ".._lookupKeyHeli)
|
||||||
--check height!
|
--check height!
|
||||||
local leaderheight = _woundedLeader:GetHeight()
|
local leaderheight = _woundedLeader:GetHeight()
|
||||||
if leaderheight < 0 then leaderheight = 0 end
|
if leaderheight < 0 then leaderheight = 0 end
|
||||||
@@ -1596,7 +1623,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
|
|
||||||
-- DONE - make variable
|
-- DONE - make variable
|
||||||
if _height <= self.rescuehoverheight then
|
if _height <= self.rescuehoverheight then
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Helo hovering low enough ".._lookupKeyHeli)
|
||||||
local _time = self.hoverStatus[_lookupKeyHeli]
|
local _time = self.hoverStatus[_lookupKeyHeli]
|
||||||
|
|
||||||
if _time == nil then
|
if _time == nil then
|
||||||
@@ -1606,22 +1633,28 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
_time = self.hoverStatus[_lookupKeyHeli] - 10
|
_time = self.hoverStatus[_lookupKeyHeli] - 10
|
||||||
self.hoverStatus[_lookupKeyHeli] = _time
|
self.hoverStatus[_lookupKeyHeli] = _time
|
||||||
end
|
end
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Check hover timer ".._lookupKeyHeli)
|
||||||
if _time > 0 then
|
if _time > 0 then
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Helo hovering not long enough ".._lookupKeyHeli)
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Hovering above " .. _pilotName .. ". \n\nHold hover for " .. _time .. " seconds to winch them up. \n\nIf the countdown stops you\'re too far away!", self.messageTime, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Hovering above " .. _pilotName .. ". \n\nHold hover for " .. _time .. " seconds to winch them up. \n\nIf the countdown stops you\'re too far away!", self.messageTime, true)
|
||||||
else
|
else
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Helo hovering long enough - door check ".._lookupKeyHeli)
|
||||||
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
|
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
self.hoverStatus[_lookupKeyHeli] = nil
|
self.hoverStatus[_lookupKeyHeli] = nil
|
||||||
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Pilot picked up ".._lookupKeyHeli)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
_reset = false
|
_reset = false
|
||||||
else
|
else
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Helo hovering too high ".._lookupKeyHeli)
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Too high to winch " .. _pilotName .. " \nReduce height and hover for 10 seconds!", self.messageTime, true,true)
|
self:_DisplayMessageToSAR(_heliUnit, "Too high to winch " .. _pilotName .. " \nReduce height and hover for 10 seconds!", self.messageTime, true,true)
|
||||||
|
self:T(self.lid .. "[Pickup Debug] Hovering too high, try again next loop ".._lookupKeyHeli)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1646,7 +1679,8 @@ end
|
|||||||
-- @param #string heliname Heli name
|
-- @param #string heliname Heli name
|
||||||
-- @param #string groupname Group name
|
-- @param #string groupname Group name
|
||||||
-- @param #boolean isairport If true, EVENT.Landing took place at an airport or FARP
|
-- @param #boolean isairport If true, EVENT.Landing took place at an airport or FARP
|
||||||
function CSAR:_ScheduledSARFlight(heliname,groupname, isairport)
|
-- @param #boolean noreschedule If true, do not try to reschedule this is distances are not ok (coming from landing event)
|
||||||
|
function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule)
|
||||||
self:T(self.lid .. " _ScheduledSARFlight")
|
self:T(self.lid .. " _ScheduledSARFlight")
|
||||||
self:T({heliname,groupname})
|
self:T({heliname,groupname})
|
||||||
local _heliUnit = self:_GetSARHeli(heliname)
|
local _heliUnit = self:_GetSARHeli(heliname)
|
||||||
@@ -1666,20 +1700,29 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport)
|
|||||||
local _dist = self:_GetClosestMASH(_heliUnit)
|
local _dist = self:_GetClosestMASH(_heliUnit)
|
||||||
|
|
||||||
if _dist == -1 then
|
if _dist == -1 then
|
||||||
return
|
self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance can not be determined!")
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance km: "..math.floor(_dist/1000))
|
||||||
|
|
||||||
if ( _dist < self.FARPRescueDistance or isairport ) and _heliUnit:InAir() == false then
|
if ( _dist < self.FARPRescueDistance or isairport ) and _heliUnit:InAir() == false then
|
||||||
|
self:T(self.lid.."[Drop off debug] Distance ok, door check")
|
||||||
if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then
|
if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true, true)
|
||||||
|
self:T(self.lid.."[Drop off debug] Door closed, try again next loop")
|
||||||
else
|
else
|
||||||
|
self:T(self.lid.."[Drop off debug] Rescued!")
|
||||||
self:_RescuePilots(_heliUnit)
|
self:_RescuePilots(_heliUnit)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--queue up
|
--queue up
|
||||||
self:__Returning(-5,heliname,_woundedGroupName, isairport)
|
if not noreschedule then
|
||||||
|
self:__Returning(5,heliname,_woundedGroupName, isairport)
|
||||||
|
self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname, isairport, noreschedule)
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1751,7 +1794,7 @@ function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _overrid
|
|||||||
_text = string.gsub(_text,"nm"," nautical miles")
|
_text = string.gsub(_text,"nm"," nautical miles")
|
||||||
--self.msrs:SetVoice(self.SRSVoice)
|
--self.msrs:SetVoice(self.SRSVoice)
|
||||||
--self.SRSQueue:NewTransmission(_text,nil,self.msrs,nil,1)
|
--self.SRSQueue:NewTransmission(_text,nil,self.msrs,nil,1)
|
||||||
self:I("Voice = "..self.SRSVoice)
|
--self:I("Voice = "..self.SRSVoice)
|
||||||
self.SRSQueue:NewTransmission(_text,duration,self.msrs,tstart,2,subgroups,subtitle,subduration,self.SRSchannel,self.SRSModulation,gender,culture,self.SRSVoice,volume,label,coord)
|
self.SRSQueue:NewTransmission(_text,duration,self.msrs,tstart,2,subgroups,subtitle,subduration,self.SRSchannel,self.SRSModulation,gender,culture,self.SRSVoice,volume,label,coord)
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -1920,21 +1963,26 @@ end
|
|||||||
-- @param #string _message Message to display.
|
-- @param #string _message Message to display.
|
||||||
-- @param #number _side Coalition of message.
|
-- @param #number _side Coalition of message.
|
||||||
-- @param #number _messagetime How long to show.
|
-- @param #number _messagetime How long to show.
|
||||||
function CSAR:_DisplayToAllSAR(_message, _side, _messagetime)
|
-- @param #boolean ToSRS If true or nil, send to SRS TTS
|
||||||
|
-- @param #boolean ToScreen If true or nil, send to Screen
|
||||||
|
function CSAR:_DisplayToAllSAR(_message, _side, _messagetime,ToSRS,ToScreen)
|
||||||
self:T(self.lid .. " _DisplayToAllSAR")
|
self:T(self.lid .. " _DisplayToAllSAR")
|
||||||
local messagetime = _messagetime or self.messageTime
|
local messagetime = _messagetime or self.messageTime
|
||||||
if self.msrs then
|
self:T({_message,ToSRS=ToSRS,ToScreen=ToScreen})
|
||||||
|
if self.msrs and (ToSRS == true or ToSRS == nil) then
|
||||||
local voice = self.CSARVoice or MSRS.Voices.Google.Standard.en_GB_Standard_F
|
local voice = self.CSARVoice or MSRS.Voices.Google.Standard.en_GB_Standard_F
|
||||||
if self.msrs:GetProvider() == MSRS.Provider.WINDOWS then
|
if self.msrs:GetProvider() == MSRS.Provider.WINDOWS then
|
||||||
voice = self.CSARVoiceMS or MSRS.Voices.Microsoft.Hedda
|
voice = self.CSARVoiceMS or MSRS.Voices.Microsoft.Hedda
|
||||||
end
|
end
|
||||||
self:I("Voice = "..voice)
|
self:F("Voice = "..voice)
|
||||||
self.SRSQueue:NewTransmission(_message,duration,self.msrs,tstart,2,subgroups,subtitle,subduration,self.SRSchannel,self.SRSModulation,gender,culture,voice,volume,label,self.coordinate)
|
self.SRSQueue:NewTransmission(_message,duration,self.msrs,tstart,2,subgroups,subtitle,subduration,self.SRSchannel,self.SRSModulation,gender,culture,voice,volume,label,self.coordinate)
|
||||||
end
|
end
|
||||||
for _, _unitName in pairs(self.csarUnits) do
|
if ToScreen == true or ToScreen == nil then
|
||||||
local _unit = self:_GetSARHeli(_unitName)
|
for _, _unitName in pairs(self.csarUnits) do
|
||||||
if _unit and not self.suppressmessages then
|
local _unit = self:_GetSARHeli(_unitName)
|
||||||
self:_DisplayMessageToSAR(_unit, _message, _messagetime)
|
if _unit and not self.suppressmessages then
|
||||||
|
self:_DisplayMessageToSAR(_unit, _message, _messagetime)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -1980,7 +2028,7 @@ end
|
|||||||
--- (Internal) Determine distance to closest MASH.
|
--- (Internal) Determine distance to closest MASH.
|
||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
-- @param Wrapper.Unit#UNIT _heli Helicopter #UNIT
|
-- @param Wrapper.Unit#UNIT _heli Helicopter #UNIT
|
||||||
-- @retunr
|
-- @return #CSAR self
|
||||||
function CSAR:_GetClosestMASH(_heli)
|
function CSAR:_GetClosestMASH(_heli)
|
||||||
self:T(self.lid .. " _GetClosestMASH")
|
self:T(self.lid .. " _GetClosestMASH")
|
||||||
local _mashset = self.mash -- Core.Set#SET_GROUP
|
local _mashset = self.mash -- Core.Set#SET_GROUP
|
||||||
@@ -2218,7 +2266,7 @@ function CSAR:_RefreshRadioBeacons()
|
|||||||
if self:_CountActiveDownedPilots() > 0 then
|
if self:_CountActiveDownedPilots() > 0 then
|
||||||
local PilotTable = self.downedPilots
|
local PilotTable = self.downedPilots
|
||||||
for _,_pilot in pairs (PilotTable) do
|
for _,_pilot in pairs (PilotTable) do
|
||||||
self:T({_pilot})
|
self:T({_pilot.name})
|
||||||
local pilot = _pilot -- #CSAR.DownedPilot
|
local pilot = _pilot -- #CSAR.DownedPilot
|
||||||
local group = pilot.group
|
local group = pilot.group
|
||||||
local frequency = pilot.frequency or 0 -- thanks to @Thrud
|
local frequency = pilot.frequency or 0 -- thanks to @Thrud
|
||||||
@@ -2500,7 +2548,7 @@ end
|
|||||||
-- @param #boolean IsAirport True if heli has landed on an AFB (from event land).
|
-- @param #boolean IsAirport True if heli has landed on an AFB (from event land).
|
||||||
function CSAR:onbeforeReturning(From, Event, To, Heliname, Woundedgroupname, IsAirPort)
|
function CSAR:onbeforeReturning(From, Event, To, Heliname, Woundedgroupname, IsAirPort)
|
||||||
self:T({From, Event, To, Heliname, Woundedgroupname})
|
self:T({From, Event, To, Heliname, Woundedgroupname})
|
||||||
self:_ScheduledSARFlight(Heliname,Woundedgroupname, IsAirPort)
|
--self:_ScheduledSARFlight(Heliname,Woundedgroupname, IsAirPort)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
-- @module Ops.CTLD
|
-- @module Ops.CTLD
|
||||||
-- @image OPS_CTLD.jpg
|
-- @image OPS_CTLD.jpg
|
||||||
|
|
||||||
-- Last Update December 2023
|
-- Last Update April 2024
|
||||||
|
|
||||||
do
|
do
|
||||||
|
|
||||||
@@ -44,6 +44,8 @@ do
|
|||||||
-- @field #number PerCrateMass Mass in kg.
|
-- @field #number PerCrateMass Mass in kg.
|
||||||
-- @field #number Stock Number of builds available, -1 for unlimited.
|
-- @field #number Stock Number of builds available, -1 for unlimited.
|
||||||
-- @field #string Subcategory Sub-category name.
|
-- @field #string Subcategory Sub-category name.
|
||||||
|
-- @field #boolean DontShowInMenu Show this item in menu or not.
|
||||||
|
-- @field Core.Zone#ZONE Location Location (if set) where to get this cargo item.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -62,6 +64,8 @@ CTLD_CARGO = {
|
|||||||
PerCrateMass = 0,
|
PerCrateMass = 0,
|
||||||
Stock = nil,
|
Stock = nil,
|
||||||
Mark = nil,
|
Mark = nil,
|
||||||
|
DontShowInMenu = false,
|
||||||
|
Location = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Define cargo types.
|
--- Define cargo types.
|
||||||
@@ -97,8 +101,10 @@ CTLD_CARGO = {
|
|||||||
-- @param #number PerCrateMass Mass in kg
|
-- @param #number PerCrateMass Mass in kg
|
||||||
-- @param #number Stock Number of builds available, nil for unlimited
|
-- @param #number Stock Number of builds available, nil for unlimited
|
||||||
-- @param #string Subcategory Name of subcategory, handy if using > 10 types to load.
|
-- @param #string Subcategory Name of subcategory, handy if using > 10 types to load.
|
||||||
|
-- @param #boolean DontShowInMenu Show this item in menu or not (default: false == show it).
|
||||||
|
-- @param Core.Zone#ZONE Location (optional) Where the cargo is available (one location only).
|
||||||
-- @return #CTLD_CARGO self
|
-- @return #CTLD_CARGO self
|
||||||
function CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory)
|
function CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory, DontShowInMenu, Location)
|
||||||
-- Inherit everything from BASE class.
|
-- Inherit everything from BASE class.
|
||||||
local self=BASE:Inherit(self, BASE:New()) -- #CTLD_CARGO
|
local self=BASE:Inherit(self, BASE:New()) -- #CTLD_CARGO
|
||||||
self:T({ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped})
|
self:T({ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped})
|
||||||
@@ -115,9 +121,21 @@ CTLD_CARGO = {
|
|||||||
self.Stock = Stock or nil --#number
|
self.Stock = Stock or nil --#number
|
||||||
self.Mark = nil
|
self.Mark = nil
|
||||||
self.Subcategory = Subcategory or "Other"
|
self.Subcategory = Subcategory or "Other"
|
||||||
|
self.DontShowInMenu = DontShowInMenu or false
|
||||||
|
if type(Location) == "string" then
|
||||||
|
Location = ZONE:New(Location)
|
||||||
|
end
|
||||||
|
self.Location = Location
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Query Location.
|
||||||
|
-- @param #CTLD_CARGO self
|
||||||
|
-- @return Core.Zone#ZONE location or `nil` if not set
|
||||||
|
function CTLD_CARGO:GetLocation()
|
||||||
|
return self.Location
|
||||||
|
end
|
||||||
|
|
||||||
--- Query ID.
|
--- Query ID.
|
||||||
-- @param #CTLD_CARGO self
|
-- @param #CTLD_CARGO self
|
||||||
-- @return #number ID
|
-- @return #number ID
|
||||||
@@ -656,6 +674,8 @@ do
|
|||||||
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775)
|
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775)
|
||||||
-- -- if you want to limit your stock, add a number (here: 10) as parameter after weight. No parameter / nil means unlimited stock.
|
-- -- if you want to limit your stock, add a number (here: 10) as parameter after weight. No parameter / nil means unlimited stock.
|
||||||
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10)
|
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10)
|
||||||
|
-- -- additionally, you can limit **where** the stock is available (one location only!) - this one is available in a zone called "Vehicle Store".
|
||||||
|
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10,nil,nil,"Vehicle Store")
|
||||||
--
|
--
|
||||||
-- -- add infantry unit called "Forward Ops Base" using template "FOB", of type FOB, size 4, i.e. needs four crates to be build:
|
-- -- add infantry unit called "Forward Ops Base" using template "FOB", of type FOB, size 4, i.e. needs four crates to be build:
|
||||||
-- my_ctld:AddCratesCargo("Forward Ops Base",{"FOB"},CTLD_CARGO.Enum.FOB,4)
|
-- my_ctld:AddCratesCargo("Forward Ops Base",{"FOB"},CTLD_CARGO.Enum.FOB,4)
|
||||||
@@ -757,6 +777,9 @@ do
|
|||||||
-- ["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000},
|
-- ["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000},
|
||||||
-- ["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500},
|
-- ["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500},
|
||||||
-- ["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200},
|
-- ["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200},
|
||||||
|
-- ["MH-60R"] = {type="MH-60R", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
|
-- ["SH-60B"] = {type="SH-60B", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
|
-- ["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
|
||||||
--
|
--
|
||||||
-- ### 2.1.2 Activate and deactivate zones
|
-- ### 2.1.2 Activate and deactivate zones
|
||||||
--
|
--
|
||||||
@@ -1222,13 +1245,17 @@ CTLD.UnitTypeCapabilities = {
|
|||||||
["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000}, -- 19t cargo, 64 paratroopers.
|
["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000}, -- 19t cargo, 64 paratroopers.
|
||||||
--Actually it's longer, but the center coord is off-center of the model.
|
--Actually it's longer, but the center coord is off-center of the model.
|
||||||
["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
|
["MH-60R"] = {type="MH-60R", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
|
["SH-60B"] = {type="SH-60B", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
|
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
|
||||||
["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
|
["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
|
||||||
|
["OH-6A"] = {type="OH-6A", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 7, cargoweightlimit = 550},
|
||||||
|
["OH58D"] = {type="OH58D", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 14, cargoweightlimit = 400},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- CTLD class version.
|
--- CTLD class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CTLD.version="1.0.45"
|
CTLD.version="1.0.54"
|
||||||
|
|
||||||
--- Instantiate a new CTLD.
|
--- Instantiate a new CTLD.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
@@ -1433,7 +1460,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
|||||||
--- Pseudo Functions ---
|
--- Pseudo Functions ---
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
--- Triggers the FSM event "Start". Starts the CTLD. Initializes parameters and starts event handlers.
|
--- Triggers the FSM event "Start". Starts the CTLD. Initializes parameters and starts event handlers.
|
||||||
-- @function [parent=#CTLD] Start
|
-- @function [parent=#CTLD] Start
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
|
|
||||||
@@ -2215,7 +2242,9 @@ end
|
|||||||
local extractdistance = self.CrateDistance * self.ExtractFactor
|
local extractdistance = self.CrateDistance * self.ExtractFactor
|
||||||
for k,v in pairs(self.DroppedTroops) do
|
for k,v in pairs(self.DroppedTroops) do
|
||||||
local distance = self:_GetDistance(v:GetCoordinate(),unitcoord)
|
local distance = self:_GetDistance(v:GetCoordinate(),unitcoord)
|
||||||
if distance <= extractdistance and distance ~= -1 then
|
local TNow = timer.getTime()
|
||||||
|
local vtime = v.ExtractTime or TNow-310
|
||||||
|
if distance <= extractdistance and distance ~= -1 and (TNow - vtime > 300) then
|
||||||
nearestGroup = v
|
nearestGroup = v
|
||||||
nearestGroupIndex = k
|
nearestGroupIndex = k
|
||||||
nearestDistance = distance
|
nearestDistance = distance
|
||||||
@@ -2235,7 +2264,7 @@ end
|
|||||||
local secondarygroups = {}
|
local secondarygroups = {}
|
||||||
|
|
||||||
for i=1,#distancekeys do
|
for i=1,#distancekeys do
|
||||||
local nearestGroup = nearestList[distancekeys[i]]
|
local nearestGroup = nearestList[distancekeys[i]] -- Wrapper.Group#GROUP
|
||||||
-- find matching cargo type
|
-- find matching cargo type
|
||||||
local groupType = string.match(nearestGroup:GetName(), "(.+)-(.+)$")
|
local groupType = string.match(nearestGroup:GetName(), "(.+)-(.+)$")
|
||||||
local Cargotype = nil
|
local Cargotype = nil
|
||||||
@@ -2266,25 +2295,38 @@ end
|
|||||||
end
|
end
|
||||||
if troopsize + numberonboard > trooplimit then
|
if troopsize + numberonboard > trooplimit then
|
||||||
self:_SendMessage("Sorry, we\'re crammed already!", 10, false, Group)
|
self:_SendMessage("Sorry, we\'re crammed already!", 10, false, Group)
|
||||||
|
nearestGroup.ExtractTime = 0
|
||||||
--return self
|
--return self
|
||||||
else
|
else
|
||||||
self.CargoCounter = self.CargoCounter + 1
|
self.CargoCounter = self.CargoCounter + 1
|
||||||
|
nearestGroup.ExtractTime = timer.getTime()
|
||||||
local loadcargotype = CTLD_CARGO:New(self.CargoCounter, Cargotype.Name, Cargotype.Templates, Cargotype.CargoType, true, true, Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass)
|
local loadcargotype = CTLD_CARGO:New(self.CargoCounter, Cargotype.Name, Cargotype.Templates, Cargotype.CargoType, true, true, Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass)
|
||||||
self:T({cargotype=loadcargotype})
|
self:T({cargotype=loadcargotype})
|
||||||
|
local running = math.floor(nearestDistance / 4)+10 -- time run to helo plus boarding
|
||||||
loaded.Troopsloaded = loaded.Troopsloaded + troopsize
|
loaded.Troopsloaded = loaded.Troopsloaded + troopsize
|
||||||
table.insert(loaded.Cargo,loadcargotype)
|
table.insert(loaded.Cargo,loadcargotype)
|
||||||
self.Loaded_Cargo[unitname] = loaded
|
self.Loaded_Cargo[unitname] = loaded
|
||||||
self:_SendMessage("Troops boarded!", 10, false, Group)
|
self:ScheduleOnce(running,self._SendMessage,self,"Troops boarded!", 10, false, Group)
|
||||||
|
self:_SendMessage("Troops boarding!", 10, false, Group)
|
||||||
self:_UpdateUnitCargoMass(Unit)
|
self:_UpdateUnitCargoMass(Unit)
|
||||||
self:__TroopsExtracted(1,Group, Unit, nearestGroup)
|
self:__TroopsExtracted(running,Group, Unit, nearestGroup)
|
||||||
|
local coord = Unit:GetCoordinate() or Group:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
local Point
|
||||||
|
if coord then
|
||||||
|
local heading = unit:GetHeading() or 0
|
||||||
|
local Angle = math.floor((heading+160)%360)
|
||||||
|
Point = coord:Translate(8,Angle):GetVec2()
|
||||||
|
if Point then
|
||||||
|
nearestGroup:RouteToVec2(Point,4)
|
||||||
|
end
|
||||||
|
end
|
||||||
-- clean up:
|
-- clean up:
|
||||||
if type(Cargotype.Templates) == "table" and Cargotype.Templates[2] then
|
if type(Cargotype.Templates) == "table" and Cargotype.Templates[2] then
|
||||||
for _,_key in pairs (Cargotype.Templates) do
|
for _,_key in pairs (Cargotype.Templates) do
|
||||||
table.insert(secondarygroups,_key)
|
table.insert(secondarygroups,_key)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
nearestGroup:Destroy(false)
|
nearestGroup:Destroy(false,running)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2294,7 +2336,7 @@ end
|
|||||||
if _group and _group:IsAlive() then
|
if _group and _group:IsAlive() then
|
||||||
local groupname = string.match(_group:GetName(), "(.+)-(.+)$")
|
local groupname = string.match(_group:GetName(), "(.+)-(.+)$")
|
||||||
if _name == groupname then
|
if _name == groupname then
|
||||||
_group:Destroy(false)
|
_group:Destroy(false,15)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2351,6 +2393,20 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack)
|
|||||||
if not self.debug then return self end
|
if not self.debug then return self end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Check cargo location if available
|
||||||
|
local location = Cargo:GetLocation()
|
||||||
|
|
||||||
|
if location then
|
||||||
|
local unitcoord = Unit:GetCoordinate() or Group:GetCoordinate()
|
||||||
|
if unitcoord then
|
||||||
|
if not location:IsCoordinateInZone(unitcoord) then
|
||||||
|
-- no we're not at the right spot
|
||||||
|
self:_SendMessage("The requested cargo is not available in this zone!", 10, false, Group)
|
||||||
|
if not self.debug then return self end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- avoid crate spam
|
-- avoid crate spam
|
||||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
|
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
|
||||||
local canloadcratesno = capabilities.cratelimit
|
local canloadcratesno = capabilities.cratelimit
|
||||||
@@ -3024,9 +3080,10 @@ end
|
|||||||
function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
|
function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
|
||||||
local Positions = {}
|
local Positions = {}
|
||||||
local template = _DATABASE:GetGroupTemplate(Template)
|
local template = _DATABASE:GetGroupTemplate(Template)
|
||||||
UTILS.PrintTableToLog(template)
|
--UTILS.PrintTableToLog(template)
|
||||||
local numbertroops = #template.units
|
local numbertroops = #template.units
|
||||||
local newcenter = Coordinate:Translate(Radius,((Heading+270)%360))
|
local slightshift = math.abs(math.random(0,200)/100)
|
||||||
|
local newcenter = Coordinate:Translate(Radius+slightshift,((Heading+270)%360))
|
||||||
for i=1,360,math.floor(360/numbertroops) do
|
for i=1,360,math.floor(360/numbertroops) do
|
||||||
local phead = ((Heading+270+i)%360)
|
local phead = ((Heading+270+i)%360)
|
||||||
local post = newcenter:Translate(Radius,phead)
|
local post = newcenter:Translate(Radius,phead)
|
||||||
@@ -3038,7 +3095,7 @@ function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
|
|||||||
}
|
}
|
||||||
table.insert(Positions,p1t)
|
table.insert(Positions,p1t)
|
||||||
end
|
end
|
||||||
UTILS.PrintTableToLog(Positions)
|
--UTILS.PrintTableToLog(Positions)
|
||||||
return Positions
|
return Positions
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3552,7 +3609,7 @@ function CTLD:_MoveGroupToZone(Group)
|
|||||||
local groupcoord = Group:GetCoordinate()
|
local groupcoord = Group:GetCoordinate()
|
||||||
-- Get closest zone of type
|
-- Get closest zone of type
|
||||||
local outcome, name, zone, distance = self:IsUnitInZone(Group,CTLD.CargoZoneType.MOVE)
|
local outcome, name, zone, distance = self:IsUnitInZone(Group,CTLD.CargoZoneType.MOVE)
|
||||||
if (distance <= self.movetroopsdistance) and zone then
|
if (distance <= self.movetroopsdistance) and outcome == true and zone~= nil then
|
||||||
-- yes, we can ;)
|
-- yes, we can ;)
|
||||||
local groupname = Group:GetName()
|
local groupname = Group:GetName()
|
||||||
local zonecoord = zone:GetRandomCoordinate(20,125) -- Core.Point#COORDINATE
|
local zonecoord = zone:GetRandomCoordinate(20,125) -- Core.Point#COORDINATE
|
||||||
@@ -3700,14 +3757,20 @@ function CTLD:_RefreshF10Menus()
|
|||||||
for _,_entry in pairs(self.Cargo_Troops) do
|
for _,_entry in pairs(self.Cargo_Troops) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
local subcat = entry.Subcategory
|
local subcat = entry.Subcategory
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,entry.Name,subcatmenus[subcat],self._LoadTroops, self, _group, _unit, entry)
|
if not noshow then
|
||||||
|
menucount = menucount + 1
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,entry.Name,subcatmenus[subcat],self._LoadTroops, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for _,_entry in pairs(self.Cargo_Troops) do
|
for _,_entry in pairs(self.Cargo_Troops) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,entry.Name,troopsmenu,self._LoadTroops, self, _group, _unit, entry)
|
if not noshow then
|
||||||
|
menucount = menucount + 1
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,entry.Name,troopsmenu,self._LoadTroops, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local unloadmenu1 = MENU_GROUP_COMMAND:New(_group,"Drop troops",toptroops, self._UnloadTroops, self, _group, _unit):Refresh()
|
local unloadmenu1 = MENU_GROUP_COMMAND:New(_group,"Drop troops",toptroops, self._UnloadTroops, self, _group, _unit):Refresh()
|
||||||
@@ -3728,33 +3791,61 @@ function CTLD:_RefreshF10Menus()
|
|||||||
for _,_entry in pairs(self.Cargo_Crates) do
|
for _,_entry in pairs(self.Cargo_Crates) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
local subcat = entry.Subcategory
|
local subcat = entry.Subcategory
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
local zone = entry.Location
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry)
|
if not noshow then
|
||||||
|
menucount = menucount + 1
|
||||||
|
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
if zone then
|
||||||
|
menutext = string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
end
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
for _,_entry in pairs(self.Cargo_Statics) do
|
for _,_entry in pairs(self.Cargo_Statics) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
local subcat = entry.Subcategory
|
local subcat = entry.Subcategory
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
local zone = entry.Location
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry)
|
if not noshow then
|
||||||
|
menucount = menucount + 1
|
||||||
|
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
if zone then
|
||||||
|
menutext = string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
end
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for _,_entry in pairs(self.Cargo_Crates) do
|
for _,_entry in pairs(self.Cargo_Crates) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
local zone = entry.Location
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry)
|
if not noshow then
|
||||||
|
menucount = menucount + 1
|
||||||
|
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
if zone then
|
||||||
|
menutext = string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
end
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
for _,_entry in pairs(self.Cargo_Statics) do
|
for _,_entry in pairs(self.Cargo_Statics) do
|
||||||
local entry = _entry -- #CTLD_CARGO
|
local entry = _entry -- #CTLD_CARGO
|
||||||
menucount = menucount + 1
|
local noshow = entry.DontShowInMenu
|
||||||
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
local zone = entry.Location
|
||||||
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry)
|
if not noshow then
|
||||||
|
menucount = menucount + 1
|
||||||
|
local menutext = string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
if zone then
|
||||||
|
menutext = string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
|
||||||
|
end
|
||||||
|
menus[menucount] = MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates, self, _group, _unit, entry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
listmenu = MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates, self._ListCratesNearby, self, _group, _unit)
|
listmenu = MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates, self._ListCratesNearby, self, _group, _unit)
|
||||||
removecrates = MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",removecratesmenu, self._RemoveCratesNearby, self, _group, _unit)
|
local removecrates = MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",removecratesmenu, self._RemoveCratesNearby, self, _group, _unit)
|
||||||
local unloadmenu = MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates, self._UnloadCrates, self, _group, _unit)
|
local unloadmenu = MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates, self._UnloadCrates, self, _group, _unit)
|
||||||
if not self.nobuildmenu then
|
if not self.nobuildmenu then
|
||||||
local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit)
|
local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit)
|
||||||
@@ -3829,7 +3920,9 @@ end
|
|||||||
-- @param #number PerCrateMass Mass in kg of each crate
|
-- @param #number PerCrateMass Mass in kg of each crate
|
||||||
-- @param #number Stock Number of buildable groups in stock. Nil for unlimited.
|
-- @param #number Stock Number of buildable groups in stock. Nil for unlimited.
|
||||||
-- @param #string SubCategory Name of sub-category (optional).
|
-- @param #string SubCategory Name of sub-category (optional).
|
||||||
function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory)
|
-- @param #boolean DontShowInMenu (optional) If set to "true" this won't show up in the menu.
|
||||||
|
-- @param Core.Zone#ZONE Location (optional) If set, the cargo item is **only** available here. Can be a #ZONE object or the name of a zone as #string.
|
||||||
|
function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
|
||||||
self:T(self.lid .. " AddCratesCargo")
|
self:T(self.lid .. " AddCratesCargo")
|
||||||
if not self:_CheckTemplates(Templates) then
|
if not self:_CheckTemplates(Templates) then
|
||||||
self:E(self.lid .. "Crates Cargo for " .. Name .. " has missing template(s)!" )
|
self:E(self.lid .. "Crates Cargo for " .. Name .. " has missing template(s)!" )
|
||||||
@@ -3837,7 +3930,7 @@ function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,Sub
|
|||||||
end
|
end
|
||||||
self.CargoCounter = self.CargoCounter + 1
|
self.CargoCounter = self.CargoCounter + 1
|
||||||
-- Crates are not directly loadable
|
-- Crates are not directly loadable
|
||||||
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory)
|
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
|
||||||
table.insert(self.Cargo_Crates,cargo)
|
table.insert(self.Cargo_Crates,cargo)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -3848,13 +3941,15 @@ end
|
|||||||
-- @param #number Mass Mass in kg of each static in kg, e.g. 100.
|
-- @param #number Mass Mass in kg of each static in kg, e.g. 100.
|
||||||
-- @param #number Stock Number of groups in stock. Nil for unlimited.
|
-- @param #number Stock Number of groups in stock. Nil for unlimited.
|
||||||
-- @param #string SubCategory Name of sub-category (optional).
|
-- @param #string SubCategory Name of sub-category (optional).
|
||||||
function CTLD:AddStaticsCargo(Name,Mass,Stock,SubCategory)
|
-- @param #boolean DontShowInMenu (optional) If set to "true" this won't show up in the menu.
|
||||||
|
-- @param Core.Zone#ZONE Location (optional) If set, the cargo item is **only** available here. Can be a #ZONE object or the name of a zone as #string.
|
||||||
|
function CTLD:AddStaticsCargo(Name,Mass,Stock,SubCategory,DontShowInMenu,Location)
|
||||||
self:T(self.lid .. " AddStaticsCargo")
|
self:T(self.lid .. " AddStaticsCargo")
|
||||||
self.CargoCounter = self.CargoCounter + 1
|
self.CargoCounter = self.CargoCounter + 1
|
||||||
local type = CTLD_CARGO.Enum.STATIC
|
local type = CTLD_CARGO.Enum.STATIC
|
||||||
local template = STATIC:FindByName(Name,true):GetTypeName()
|
local template = STATIC:FindByName(Name,true):GetTypeName()
|
||||||
-- Crates are not directly loadable
|
-- Crates are not directly loadable
|
||||||
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,Stock,SubCategory)
|
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,Stock,SubCategory,DontShowInMenu,Location)
|
||||||
table.insert(self.Cargo_Statics,cargo)
|
table.insert(self.Cargo_Statics,cargo)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -3884,7 +3979,9 @@ end
|
|||||||
-- @param #number PerCrateMass Mass in kg of each crate
|
-- @param #number PerCrateMass Mass in kg of each crate
|
||||||
-- @param #number Stock Number of groups in stock. Nil for unlimited.
|
-- @param #number Stock Number of groups in stock. Nil for unlimited.
|
||||||
-- @param #string SubCategory Name of the sub-category (optional).
|
-- @param #string SubCategory Name of the sub-category (optional).
|
||||||
function CTLD:AddCratesRepair(Name,Template,Type,NoCrates, PerCrateMass,Stock,SubCategory)
|
-- @param #boolean DontShowInMenu (optional) If set to "true" this won't show up in the menu.
|
||||||
|
-- @param Core.Zone#ZONE Location (optional) If set, the cargo item is **only** available here. Can be a #ZONE object or the name of a zone as #string.
|
||||||
|
function CTLD:AddCratesRepair(Name,Template,Type,NoCrates, PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
|
||||||
self:T(self.lid .. " AddCratesRepair")
|
self:T(self.lid .. " AddCratesRepair")
|
||||||
if not self:_CheckTemplates(Template) then
|
if not self:_CheckTemplates(Template) then
|
||||||
self:E(self.lid .. "Repair Cargo for " .. Name .. " has a missing template!" )
|
self:E(self.lid .. "Repair Cargo for " .. Name .. " has a missing template!" )
|
||||||
@@ -3892,7 +3989,7 @@ function CTLD:AddCratesRepair(Name,Template,Type,NoCrates, PerCrateMass,Stock,Su
|
|||||||
end
|
end
|
||||||
self.CargoCounter = self.CargoCounter + 1
|
self.CargoCounter = self.CargoCounter + 1
|
||||||
-- Crates are not directly loadable
|
-- Crates are not directly loadable
|
||||||
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,Template,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory)
|
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,Template,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
|
||||||
table.insert(self.Cargo_Crates,cargo)
|
table.insert(self.Cargo_Crates,cargo)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -4369,10 +4466,9 @@ function CTLD:IsUnitInZone(Unit,Zonetype)
|
|||||||
zonewidth = zoneradius
|
zonewidth = zoneradius
|
||||||
end
|
end
|
||||||
local distance = self:_GetDistance(zonecoord,unitcoord)
|
local distance = self:_GetDistance(zonecoord,unitcoord)
|
||||||
if zone:IsVec2InZone(unitVec2) and active then
|
self:T("Distance Zone: "..distance)
|
||||||
|
if (zone:IsVec2InZone(unitVec2) or Zonetype == CTLD.CargoZoneType.MOVE) and active == true and maxdist > distance then
|
||||||
outcome = true
|
outcome = true
|
||||||
end
|
|
||||||
if maxdist > distance then
|
|
||||||
maxdist = distance
|
maxdist = distance
|
||||||
zoneret = zone
|
zoneret = zone
|
||||||
zonenameret = zonename
|
zonenameret = zonename
|
||||||
@@ -5357,19 +5453,19 @@ end
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) FSM Function onbeforeTroopsExtracted.
|
--- (Internal) FSM Function onbeforeTroopsExtracted.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @param #string From State.
|
-- @param #string From State.
|
||||||
-- @param #string Event Trigger.
|
-- @param #string Event Trigger.
|
||||||
-- @param #string To State.
|
-- @param #string To State.
|
||||||
-- @param Wrapper.Group#GROUP Group Group Object.
|
-- @param Wrapper.Group#GROUP Group Group Object.
|
||||||
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
||||||
-- @param Wrapper.Group#GROUP Troops Troops #GROUP Object.
|
-- @param Wrapper.Group#GROUP Troops Troops #GROUP Object.
|
||||||
-- @return #CTLD self
|
-- @return #CTLD self
|
||||||
function CTLD:onbeforeTroopsExtracted(From, Event, To, Group, Unit, Troops)
|
function CTLD:onbeforeTroopsExtracted(From, Event, To, Group, Unit, Troops)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (Internal) FSM Function onbeforeTroopsDeployed.
|
--- (Internal) FSM Function onbeforeTroopsDeployed.
|
||||||
|
|||||||
@@ -1078,6 +1078,13 @@ function CHIEF:SetStrategy(Strategy)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get current strategy.
|
||||||
|
-- @param #CHIEF self
|
||||||
|
-- @return #string Strategy.
|
||||||
|
function CHIEF:GetStrategy()
|
||||||
|
return self.strategy
|
||||||
|
end
|
||||||
|
|
||||||
--- Get defence condition.
|
--- Get defence condition.
|
||||||
-- @param #CHIEF self
|
-- @param #CHIEF self
|
||||||
-- @param #string Current Defence condition. See @{#CHIEF.DEFCON}, e.g. `CHIEF.DEFCON.RED`.
|
-- @param #string Current Defence condition. See @{#CHIEF.DEFCON}, e.g. `CHIEF.DEFCON.RED`.
|
||||||
@@ -1456,7 +1463,7 @@ end
|
|||||||
--- Add a CAP zone. Flights will engage detected targets inside this zone.
|
--- Add a CAP zone. Flights will engage detected targets inside this zone.
|
||||||
-- @param #CHIEF self
|
-- @param #CHIEF self
|
||||||
-- @param Core.Zone#ZONE Zone CAP Zone. Has to be a circular zone.
|
-- @param Core.Zone#ZONE Zone CAP Zone. Has to be a circular zone.
|
||||||
-- @param #number Altitude Orbit altitude in feet. Default is 12,0000 feet.
|
-- @param #number Altitude Orbit altitude in feet. Default is 12,000 feet.
|
||||||
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
||||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||||
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
||||||
@@ -1472,7 +1479,7 @@ end
|
|||||||
--- Add a GCI CAP.
|
--- Add a GCI CAP.
|
||||||
-- @param #CHIEF self
|
-- @param #CHIEF self
|
||||||
-- @param Core.Zone#ZONE Zone Zone, where the flight orbits.
|
-- @param Core.Zone#ZONE Zone Zone, where the flight orbits.
|
||||||
-- @param #number Altitude Orbit altitude in feet. Default is 12,0000 feet.
|
-- @param #number Altitude Orbit altitude in feet. Default is 12,000 feet.
|
||||||
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
||||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||||
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
||||||
@@ -1499,7 +1506,7 @@ end
|
|||||||
--- Add an AWACS zone.
|
--- Add an AWACS zone.
|
||||||
-- @param #CHIEF self
|
-- @param #CHIEF self
|
||||||
-- @param Core.Zone#ZONE Zone Zone.
|
-- @param Core.Zone#ZONE Zone Zone.
|
||||||
-- @param #number Altitude Orbit altitude in feet. Default is 12,0000 feet.
|
-- @param #number Altitude Orbit altitude in feet. Default is 12,000 feet.
|
||||||
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
||||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||||
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
||||||
@@ -1526,7 +1533,7 @@ end
|
|||||||
--- Add a refuelling tanker zone.
|
--- Add a refuelling tanker zone.
|
||||||
-- @param #CHIEF self
|
-- @param #CHIEF self
|
||||||
-- @param Core.Zone#ZONE Zone Zone.
|
-- @param Core.Zone#ZONE Zone Zone.
|
||||||
-- @param #number Altitude Orbit altitude in feet. Default is 12,0000 feet.
|
-- @param #number Altitude Orbit altitude in feet. Default is 12,000 feet.
|
||||||
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
||||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||||
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
||||||
|
|||||||
@@ -505,6 +505,9 @@ end
|
|||||||
function COHORT:SetCallsign(Callsign, Index)
|
function COHORT:SetCallsign(Callsign, Index)
|
||||||
self.callsignName=Callsign
|
self.callsignName=Callsign
|
||||||
self.callsignIndex=Index
|
self.callsignIndex=Index
|
||||||
|
self.callsign={}
|
||||||
|
self.callsign.NumberSquad=Callsign
|
||||||
|
self.callsign.NumberGroup=Index
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ COMMANDER = {
|
|||||||
|
|
||||||
--- COMMANDER class version.
|
--- COMMANDER class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
COMMANDER.version="0.1.3"
|
COMMANDER.version="0.1.4"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -663,7 +663,7 @@ end
|
|||||||
--- Add a CAP zone.
|
--- Add a CAP zone.
|
||||||
-- @param #COMMANDER self
|
-- @param #COMMANDER self
|
||||||
-- @param Core.Zone#ZONE Zone CapZone Zone.
|
-- @param Core.Zone#ZONE Zone CapZone Zone.
|
||||||
-- @param #number Altitude Orbit altitude in feet. Default is 12,0000 feet.
|
-- @param #number Altitude Orbit altitude in feet. Default is 12,000 feet.
|
||||||
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
||||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||||
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
||||||
@@ -675,7 +675,8 @@ function COMMANDER:AddCapZone(Zone, Altitude, Speed, Heading, Leg)
|
|||||||
patrolzone.zone=Zone
|
patrolzone.zone=Zone
|
||||||
patrolzone.altitude=Altitude or 12000
|
patrolzone.altitude=Altitude or 12000
|
||||||
patrolzone.heading=Heading or 270
|
patrolzone.heading=Heading or 270
|
||||||
patrolzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, patrolzone.altitude)
|
--patrolzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, patrolzone.altitude)
|
||||||
|
patrolzone.speed=Speed or 350
|
||||||
patrolzone.leg=Leg or 30
|
patrolzone.leg=Leg or 30
|
||||||
patrolzone.mission=nil
|
patrolzone.mission=nil
|
||||||
--patrolzone.marker=MARKER:New(patrolzone.zone:GetCoordinate(), "CAP Zone"):ToCoalition(self:GetCoalition())
|
--patrolzone.marker=MARKER:New(patrolzone.zone:GetCoordinate(), "CAP Zone"):ToCoalition(self:GetCoalition())
|
||||||
@@ -688,7 +689,7 @@ end
|
|||||||
--- Add a GCICAP zone.
|
--- Add a GCICAP zone.
|
||||||
-- @param #COMMANDER self
|
-- @param #COMMANDER self
|
||||||
-- @param Core.Zone#ZONE Zone CapZone Zone.
|
-- @param Core.Zone#ZONE Zone CapZone Zone.
|
||||||
-- @param #number Altitude Orbit altitude in feet. Default is 12,0000 feet.
|
-- @param #number Altitude Orbit altitude in feet. Default is 12,000 feet.
|
||||||
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
||||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||||
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
||||||
@@ -700,7 +701,8 @@ function COMMANDER:AddGciCapZone(Zone, Altitude, Speed, Heading, Leg)
|
|||||||
patrolzone.zone=Zone
|
patrolzone.zone=Zone
|
||||||
patrolzone.altitude=Altitude or 12000
|
patrolzone.altitude=Altitude or 12000
|
||||||
patrolzone.heading=Heading or 270
|
patrolzone.heading=Heading or 270
|
||||||
patrolzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, patrolzone.altitude)
|
--patrolzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, patrolzone.altitude)
|
||||||
|
patrolzone.speed=Speed or 350
|
||||||
patrolzone.leg=Leg or 30
|
patrolzone.leg=Leg or 30
|
||||||
patrolzone.mission=nil
|
patrolzone.mission=nil
|
||||||
--patrolzone.marker=MARKER:New(patrolzone.zone:GetCoordinate(), "GCICAP Zone"):ToCoalition(self:GetCoalition())
|
--patrolzone.marker=MARKER:New(patrolzone.zone:GetCoordinate(), "GCICAP Zone"):ToCoalition(self:GetCoalition())
|
||||||
@@ -733,7 +735,7 @@ end
|
|||||||
--- Add an AWACS zone.
|
--- Add an AWACS zone.
|
||||||
-- @param #COMMANDER self
|
-- @param #COMMANDER self
|
||||||
-- @param Core.Zone#ZONE Zone Zone.
|
-- @param Core.Zone#ZONE Zone Zone.
|
||||||
-- @param #number Altitude Orbit altitude in feet. Default is 12,0000 feet.
|
-- @param #number Altitude Orbit altitude in feet. Default is 12,000 feet.
|
||||||
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
||||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||||
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
||||||
@@ -745,7 +747,9 @@ function COMMANDER:AddAwacsZone(Zone, Altitude, Speed, Heading, Leg)
|
|||||||
awacszone.zone=Zone
|
awacszone.zone=Zone
|
||||||
awacszone.altitude=Altitude or 12000
|
awacszone.altitude=Altitude or 12000
|
||||||
awacszone.heading=Heading or 270
|
awacszone.heading=Heading or 270
|
||||||
awacszone.speed=UTILS.KnotsToAltKIAS(Speed or 350, awacszone.altitude)
|
--awacszone.speed=UTILS.KnotsToAltKIAS(Speed or 350, awacszone.altitude)
|
||||||
|
awacszone.speed=Speed or 350
|
||||||
|
awacszone.speed=Speed or 350
|
||||||
awacszone.leg=Leg or 30
|
awacszone.leg=Leg or 30
|
||||||
awacszone.mission=nil
|
awacszone.mission=nil
|
||||||
--awacszone.marker=MARKER:New(awacszone.zone:GetCoordinate(), "AWACS Zone"):ToCoalition(self:GetCoalition())
|
--awacszone.marker=MARKER:New(awacszone.zone:GetCoordinate(), "AWACS Zone"):ToCoalition(self:GetCoalition())
|
||||||
@@ -778,7 +782,7 @@ end
|
|||||||
--- Add a refuelling tanker zone.
|
--- Add a refuelling tanker zone.
|
||||||
-- @param #COMMANDER self
|
-- @param #COMMANDER self
|
||||||
-- @param Core.Zone#ZONE Zone Zone.
|
-- @param Core.Zone#ZONE Zone Zone.
|
||||||
-- @param #number Altitude Orbit altitude in feet. Default is 12,0000 feet.
|
-- @param #number Altitude Orbit altitude in feet. Default is 12,000 feet.
|
||||||
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
-- @param #number Speed Orbit speed in KIAS. Default 350 kts.
|
||||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||||
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
-- @param #number Leg Length of race-track in NM. Default 30 NM.
|
||||||
@@ -791,7 +795,8 @@ function COMMANDER:AddTankerZone(Zone, Altitude, Speed, Heading, Leg, RefuelSyst
|
|||||||
tankerzone.zone=Zone
|
tankerzone.zone=Zone
|
||||||
tankerzone.altitude=Altitude or 12000
|
tankerzone.altitude=Altitude or 12000
|
||||||
tankerzone.heading=Heading or 270
|
tankerzone.heading=Heading or 270
|
||||||
tankerzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, tankerzone.altitude)
|
--tankerzone.speed=UTILS.KnotsToAltKIAS(Speed or 350, tankerzone.altitude) -- speed translation to alt will be done by AUFTRAG anyhow
|
||||||
|
tankerzone.speed = Speed or 350
|
||||||
tankerzone.leg=Leg or 30
|
tankerzone.leg=Leg or 30
|
||||||
tankerzone.refuelsystem=RefuelSystem
|
tankerzone.refuelsystem=RefuelSystem
|
||||||
tankerzone.mission=nil
|
tankerzone.mission=nil
|
||||||
|
|||||||
@@ -702,7 +702,7 @@ function EASYGCICAP:_SetTankerPatrolPoints()
|
|||||||
self:T(self.lid.."_SetTankerPatrolPoints")
|
self:T(self.lid.."_SetTankerPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedTK) do
|
for _,_data in pairs(self.ManagedTK) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.AirWing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
local Speed = data.Speed
|
local Speed = data.Speed
|
||||||
@@ -721,7 +721,7 @@ function EASYGCICAP:_SetAwacsPatrolPoints()
|
|||||||
self:T(self.lid.."_SetAwacsPatrolPoints")
|
self:T(self.lid.."_SetAwacsPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedEWR) do
|
for _,_data in pairs(self.ManagedEWR) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.AirWing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
local Speed = data.Speed
|
local Speed = data.Speed
|
||||||
@@ -740,7 +740,7 @@ function EASYGCICAP:_SetCAPPatrolPoints()
|
|||||||
self:T(self.lid.."_SetCAPPatrolPoints")
|
self:T(self.lid.."_SetCAPPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedCP) do
|
for _,_data in pairs(self.ManagedCP) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.AirWing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
local Speed = data.Speed
|
local Speed = data.Speed
|
||||||
@@ -759,7 +759,7 @@ function EASYGCICAP:_SetReconPatrolPoints()
|
|||||||
self:T(self.lid.."_SetReconPatrolPoints")
|
self:T(self.lid.."_SetReconPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedREC) do
|
for _,_data in pairs(self.ManagedREC) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.AirWing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
local Speed = data.Speed
|
local Speed = data.Speed
|
||||||
@@ -947,7 +947,7 @@ function EASYGCICAP:_AddSquadron(TemplateName, SquadName, AirbaseName, AirFrames
|
|||||||
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
||||||
Squadron_One:SetMissionRange(self.missionrange)
|
Squadron_One:SetMissionRange(self.missionrange)
|
||||||
|
|
||||||
local wing = self.wings[AirbaseName][1] -- Ops.AirWing#AIRWING
|
local wing = self.wings[AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
|
|
||||||
wing:AddSquadron(Squadron_One)
|
wing:AddSquadron(Squadron_One)
|
||||||
wing:NewPayload(TemplateName,-1,{AUFTRAG.Type.CAP, AUFTRAG.Type.GCICAP, AUFTRAG.Type.INTERCEPT, AUFTRAG.Type.PATROLRACETRACK, AUFTRAG.Type.ALERT5},75)
|
wing:NewPayload(TemplateName,-1,{AUFTRAG.Type.CAP, AUFTRAG.Type.GCICAP, AUFTRAG.Type.INTERCEPT, AUFTRAG.Type.PATROLRACETRACK, AUFTRAG.Type.ALERT5},75)
|
||||||
@@ -978,7 +978,7 @@ function EASYGCICAP:_AddReconSquadron(TemplateName, SquadName, AirbaseName, AirF
|
|||||||
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
||||||
Squadron_One:SetMissionRange(self.missionrange)
|
Squadron_One:SetMissionRange(self.missionrange)
|
||||||
|
|
||||||
local wing = self.wings[AirbaseName][1] -- Ops.AirWing#AIRWING
|
local wing = self.wings[AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
|
|
||||||
wing:AddSquadron(Squadron_One)
|
wing:AddSquadron(Squadron_One)
|
||||||
wing:NewPayload(TemplateName,-1,{AUFTRAG.Type.RECON},75)
|
wing:NewPayload(TemplateName,-1,{AUFTRAG.Type.RECON},75)
|
||||||
@@ -1014,7 +1014,7 @@ function EASYGCICAP:_AddTankerSquadron(TemplateName, SquadName, AirbaseName, Air
|
|||||||
Squadron_One:SetRadio(Frequency,Modulation)
|
Squadron_One:SetRadio(Frequency,Modulation)
|
||||||
Squadron_One:AddTacanChannel(TACAN,TACAN)
|
Squadron_One:AddTacanChannel(TACAN,TACAN)
|
||||||
|
|
||||||
local wing = self.wings[AirbaseName][1] -- Ops.AirWing#AIRWING
|
local wing = self.wings[AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
|
|
||||||
wing:AddSquadron(Squadron_One)
|
wing:AddSquadron(Squadron_One)
|
||||||
wing:NewPayload(TemplateName,-1,{AUFTRAG.Type.TANKER},75)
|
wing:NewPayload(TemplateName,-1,{AUFTRAG.Type.TANKER},75)
|
||||||
@@ -1047,7 +1047,7 @@ function EASYGCICAP:_AddAWACSSquadron(TemplateName, SquadName, AirbaseName, AirF
|
|||||||
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
||||||
Squadron_One:SetMissionRange(self.missionrange)
|
Squadron_One:SetMissionRange(self.missionrange)
|
||||||
Squadron_One:SetRadio(Frequency,Modulation)
|
Squadron_One:SetRadio(Frequency,Modulation)
|
||||||
local wing = self.wings[AirbaseName][1] -- Ops.AirWing#AIRWING
|
local wing = self.wings[AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
|
|
||||||
wing:AddSquadron(Squadron_One)
|
wing:AddSquadron(Squadron_One)
|
||||||
wing:NewPayload(TemplateName,-1,{AUFTRAG.Type.AWACS},75)
|
wing:NewPayload(TemplateName,-1,{AUFTRAG.Type.AWACS},75)
|
||||||
@@ -1126,7 +1126,7 @@ end
|
|||||||
|
|
||||||
--- Add a zone to the rejected zones set.
|
--- Add a zone to the rejected zones set.
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param Ops.Intelligence#INTEL.Cluster Cluster
|
-- @param Ops.Intel#INTEL.Cluster Cluster
|
||||||
-- @return #EASYGCICAP self
|
-- @return #EASYGCICAP self
|
||||||
function EASYGCICAP:_AssignIntercept(Cluster)
|
function EASYGCICAP:_AssignIntercept(Cluster)
|
||||||
-- Here, we'll decide if we need to launch an intercepting flight, and from where
|
-- Here, we'll decide if we need to launch an intercepting flight, and from where
|
||||||
@@ -1151,7 +1151,7 @@ function EASYGCICAP:_AssignIntercept(Cluster)
|
|||||||
local position = self.Intel:CalcClusterFuturePosition(Cluster,300)
|
local position = self.Intel:CalcClusterFuturePosition(Cluster,300)
|
||||||
-- calculate closest zone
|
-- calculate closest zone
|
||||||
local bestdistance = 2000*1000 -- 2000km
|
local bestdistance = 2000*1000 -- 2000km
|
||||||
local targetairwing = nil -- Ops.AirWing#AIRWING
|
local targetairwing = nil -- Ops.Airwing#AIRWING
|
||||||
local targetawname = "" -- #string
|
local targetawname = "" -- #string
|
||||||
local clustersize = self.Intel:ClusterCountUnits(Cluster) or 1
|
local clustersize = self.Intel:ClusterCountUnits(Cluster) or 1
|
||||||
local wingsize = math.abs(overhead * (clustersize+1))
|
local wingsize = math.abs(overhead * (clustersize+1))
|
||||||
@@ -1164,7 +1164,7 @@ function EASYGCICAP:_AssignIntercept(Cluster)
|
|||||||
if (retrymission) and (wingsize >= 1) then
|
if (retrymission) and (wingsize >= 1) then
|
||||||
MESSAGE:New(string.format("**** %s Interceptors need wingsize %d", UTILS.GetCoalitionName(self.coalition), wingsize),15,"CAPGCI"):ToAllIf(self.debug):ToLog()
|
MESSAGE:New(string.format("**** %s Interceptors need wingsize %d", UTILS.GetCoalitionName(self.coalition), wingsize),15,"CAPGCI"):ToAllIf(self.debug):ToLog()
|
||||||
for _,_data in pairs (wings) do
|
for _,_data in pairs (wings) do
|
||||||
local airwing = _data[1] -- Ops.AirWing#AIRWING
|
local airwing = _data[1] -- Ops.Airwing#AIRWING
|
||||||
local zone = _data[2] -- Core.Zone#ZONE
|
local zone = _data[2] -- Core.Zone#ZONE
|
||||||
local zonecoord = zone:GetCoordinate()
|
local zonecoord = zone:GetCoordinate()
|
||||||
local name = _data[3] -- #string
|
local name = _data[3] -- #string
|
||||||
@@ -1177,7 +1177,7 @@ function EASYGCICAP:_AssignIntercept(Cluster)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
for _,_data in pairs (ctlpts) do
|
for _,_data in pairs (ctlpts) do
|
||||||
--local airwing = _data[1] -- Ops.AirWing#AIRWING
|
--local airwing = _data[1] -- Ops.Airwing#AIRWING
|
||||||
--local zone = _data[2] -- Core.Zone#ZONE
|
--local zone = _data[2] -- Core.Zone#ZONE
|
||||||
--local zonecoord = zone:GetCoordinate()
|
--local zonecoord = zone:GetCoordinate()
|
||||||
--local name = _data[3] -- #string
|
--local name = _data[3] -- #string
|
||||||
@@ -1191,7 +1191,7 @@ function EASYGCICAP:_AssignIntercept(Cluster)
|
|||||||
local airframes = airwing:CountAssets(true)
|
local airframes = airwing:CountAssets(true)
|
||||||
if distance < bestdistance and airframes >= wingsize then
|
if distance < bestdistance and airframes >= wingsize then
|
||||||
bestdistance = distance
|
bestdistance = distance
|
||||||
targetairwing = airwing -- Ops.AirWing#AIRWING
|
targetairwing = airwing -- Ops.Airwing#AIRWING
|
||||||
targetawname = name
|
targetawname = name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -62,6 +62,8 @@
|
|||||||
-- @field #number runwayrepairtime Time in seconds until runway will be repaired after it was destroyed. Default is 3600 sec (one hour).
|
-- @field #number runwayrepairtime Time in seconds until runway will be repaired after it was destroyed. Default is 3600 sec (one hour).
|
||||||
-- @field #boolean markerParking If `true`, occupied parking spots are marked.
|
-- @field #boolean markerParking If `true`, occupied parking spots are marked.
|
||||||
-- @field #boolean nosubs If `true`, SRS TTS is without subtitles.
|
-- @field #boolean nosubs If `true`, SRS TTS is without subtitles.
|
||||||
|
-- @field #number Nplayers Number of human players. Updated at each StatusUpdate call.
|
||||||
|
-- @field #boolean radioOnlyIfPlayers Activate to limit transmissions only if players are active at the airbase.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- **Ground Control**: Airliner X, Good news, you are clear to taxi to the active.
|
--- **Ground Control**: Airliner X, Good news, you are clear to taxi to the active.
|
||||||
@@ -272,6 +274,7 @@ FLIGHTCONTROL = {
|
|||||||
holdingpatterns = {},
|
holdingpatterns = {},
|
||||||
hpcounter = 0,
|
hpcounter = 0,
|
||||||
nosubs = false,
|
nosubs = false,
|
||||||
|
Nplayers = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Holding point. Contains holding stacks.
|
--- Holding point. Contains holding stacks.
|
||||||
@@ -329,7 +332,7 @@ FLIGHTCONTROL.FlightStatus={
|
|||||||
|
|
||||||
--- FlightControl class version.
|
--- FlightControl class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
FLIGHTCONTROL.version="0.7.5"
|
FLIGHTCONTROL.version="0.7.7"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -417,6 +420,9 @@ function FLIGHTCONTROL:New(AirbaseName, Frequency, Modulation, PathToSRS, Port,
|
|||||||
-- Init msrs queue.
|
-- Init msrs queue.
|
||||||
self.msrsqueue=MSRSQUEUE:New(self.alias)
|
self.msrsqueue=MSRSQUEUE:New(self.alias)
|
||||||
|
|
||||||
|
-- Set that transmission is only if alive players on the server.
|
||||||
|
self:SetTransmitOnlyWithPlayers(true)
|
||||||
|
|
||||||
-- Init msrs bases
|
-- Init msrs bases
|
||||||
local path = PathToSRS or MSRS.path
|
local path = PathToSRS or MSRS.path
|
||||||
local port = Port or MSRS.port or 5002
|
local port = Port or MSRS.port or 5002
|
||||||
@@ -571,6 +577,31 @@ function FLIGHTCONTROL:SetVerbosity(VerbosityLevel)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Limit radio transmissions only if human players are registered at the airbase.
|
||||||
|
-- This can be used to reduce TTS messages on heavy missions.
|
||||||
|
-- @param #FLIGHTCONTROL self
|
||||||
|
-- @param #boolean Switch If `true` or `nil` no transmission if there are no players. Use `false` enable TTS with no players.
|
||||||
|
-- @return #FLIGHTCONTROL self
|
||||||
|
function FLIGHTCONTROL:SetRadioOnlyIfPlayers(Switch)
|
||||||
|
if Switch==nil or Switch==true then
|
||||||
|
self.radioOnlyIfPlayers=true
|
||||||
|
else
|
||||||
|
self.radioOnlyIfPlayers=false
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set whether to only transmit TTS messages if there are players on the server.
|
||||||
|
-- @param #FLIGHTCONTROL self
|
||||||
|
-- @param #boolean Switch If `true`, only send TTS messages if there are alive Players. If `false` or `nil`, transmission are done also if no players are on the server.
|
||||||
|
-- @return #FLIGHTCONTROL self
|
||||||
|
function FLIGHTCONTROL:SetTransmitOnlyWithPlayers(Switch)
|
||||||
|
self.msrsqueue:SetTransmitOnlyWithPlayers(Switch)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set subtitles to appear on SRS TTS messages.
|
--- Set subtitles to appear on SRS TTS messages.
|
||||||
-- @param #FLIGHTCONTROL self
|
-- @param #FLIGHTCONTROL self
|
||||||
-- @return #FLIGHTCONTROL self
|
-- @return #FLIGHTCONTROL self
|
||||||
@@ -1063,9 +1094,10 @@ function FLIGHTCONTROL:onafterStatusUpdate()
|
|||||||
-- Check if runway was repaired.
|
-- Check if runway was repaired.
|
||||||
if self:IsRunwayOperational()==false then
|
if self:IsRunwayOperational()==false then
|
||||||
local Trepair=self:GetRunwayRepairtime()
|
local Trepair=self:GetRunwayRepairtime()
|
||||||
self:I(self.lid..string.format("Runway still destroyed! Will be repaired in %d sec", Trepair))
|
|
||||||
if Trepair==0 then
|
if Trepair==0 then
|
||||||
self:RunwayRepaired()
|
self:RunwayRepaired()
|
||||||
|
else
|
||||||
|
self:I(self.lid..string.format("Runway still destroyed! Will be repaired in %d sec", Trepair))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1835,7 +1867,7 @@ function FLIGHTCONTROL:_GetNextFightParking()
|
|||||||
local text="Parking flights:"
|
local text="Parking flights:"
|
||||||
for i,_flight in pairs(Qparking) do
|
for i,_flight in pairs(Qparking) do
|
||||||
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
|
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
|
||||||
text=text..string.format("\n[%d] %s [%s], state=%s [%s]: Tparking=%.1f sec", i, flight.groupname, flight.actype, flight:GetState(), self:GetFlightStatus(flight), flight:GetParkingTime())
|
text=text..string.format("\n[%d] %s [%s], state=%s [%s]: Tparking=%.1f sec", i, flight.groupname, tostring(flight.actype), flight:GetState(), self:GetFlightStatus(flight), flight:GetParkingTime())
|
||||||
end
|
end
|
||||||
self:I(self.lid..text)
|
self:I(self.lid..text)
|
||||||
end
|
end
|
||||||
@@ -2131,7 +2163,7 @@ function FLIGHTCONTROL:_InitParkingSpots()
|
|||||||
|
|
||||||
local isalive=unit:IsAlive()
|
local isalive=unit:IsAlive()
|
||||||
|
|
||||||
--env.info(string.format("FF parking spot %d is occupied by unit %s alive=%s", spot.TerminalID, unitname, tostring(isalive)))
|
self:T2(self.lid..string.format("FF parking spot %d is occupied by unit %s alive=%s", spot.TerminalID, unitname, tostring(isalive)))
|
||||||
|
|
||||||
if isalive then
|
if isalive then
|
||||||
|
|
||||||
@@ -4081,6 +4113,15 @@ function FLIGHTCONTROL:_CheckFlights()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Count number of players
|
||||||
|
self.Nplayers=0
|
||||||
|
for _,_flight in pairs(self.flights) do
|
||||||
|
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
|
||||||
|
if not flight.isAI then
|
||||||
|
self.Nplayers=self.Nplayers+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Check speeding.
|
-- Check speeding.
|
||||||
if self.speedLimitTaxi then
|
if self.speedLimitTaxi then
|
||||||
|
|
||||||
@@ -4313,6 +4354,11 @@ end
|
|||||||
-- @param #number Delay Delay in seconds before the text is transmitted. Default 0 sec.
|
-- @param #number Delay Delay in seconds before the text is transmitted. Default 0 sec.
|
||||||
function FLIGHTCONTROL:TransmissionTower(Text, Flight, Delay)
|
function FLIGHTCONTROL:TransmissionTower(Text, Flight, Delay)
|
||||||
|
|
||||||
|
if self.radioOnlyIfPlayers==true and self.Nplayers==0 then
|
||||||
|
self:T(self.lid.."No players ==> skipping TOWER radio transmission")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Spoken text.
|
-- Spoken text.
|
||||||
local text=self:_GetTextForSpeech(Text)
|
local text=self:_GetTextForSpeech(Text)
|
||||||
|
|
||||||
@@ -4344,6 +4390,12 @@ end
|
|||||||
-- @param #number Delay Delay in seconds before the text is transmitted. Default 0 sec.
|
-- @param #number Delay Delay in seconds before the text is transmitted. Default 0 sec.
|
||||||
function FLIGHTCONTROL:TransmissionPilot(Text, Flight, Delay)
|
function FLIGHTCONTROL:TransmissionPilot(Text, Flight, Delay)
|
||||||
|
|
||||||
|
if self.radioOnlyIfPlayers==true and self.Nplayers==0 then
|
||||||
|
self:T(self.lid.."No players ==> skipping PILOT radio transmission")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Get player data.
|
-- Get player data.
|
||||||
local playerData=Flight:_GetPlayerData()
|
local playerData=Flight:_GetPlayerData()
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
-- @field #boolean fuelcritical Fuel critical switch.
|
-- @field #boolean fuelcritical Fuel critical switch.
|
||||||
-- @field #number fuelcriticalthresh Critical fuel threshold in percent.
|
-- @field #number fuelcriticalthresh Critical fuel threshold in percent.
|
||||||
-- @field #boolean fuelcriticalrtb RTB on critical fuel switch.
|
-- @field #boolean fuelcriticalrtb RTB on critical fuel switch.
|
||||||
-- @field Ops.FlightControl#FLIGHTCONTROL flightcontrol The flightcontrol handling this group.
|
-- @field OPS.FlightControl#FLIGHTCONTROL flightcontrol The flightcontrol handling this group.
|
||||||
-- @field Ops.Airboss#AIRBOSS airboss The airboss handling this group.
|
-- @field Ops.Airboss#AIRBOSS airboss The airboss handling this group.
|
||||||
-- @field Core.UserFlag#USERFLAG flaghold Flag for holding.
|
-- @field Core.UserFlag#USERFLAG flaghold Flag for holding.
|
||||||
-- @field #number Tholding Abs. mission time stamp when the group reached the holding point.
|
-- @field #number Tholding Abs. mission time stamp when the group reached the holding point.
|
||||||
@@ -54,11 +54,12 @@
|
|||||||
-- @field #boolean despawnAfterLanding If `true`, group is despawned after landed at an airbase.
|
-- @field #boolean despawnAfterLanding If `true`, group is despawned after landed at an airbase.
|
||||||
-- @field #boolean despawnAfterHolding If `true`, group is despawned after reaching the holding point.
|
-- @field #boolean despawnAfterHolding If `true`, group is despawned after reaching the holding point.
|
||||||
-- @field #number RTBRecallCount Number that counts RTB calls.
|
-- @field #number RTBRecallCount Number that counts RTB calls.
|
||||||
-- @field Ops.FlightControl#FLIGHTCONTROL.HoldingStack stack Holding stack.
|
-- @field OPS.FlightControl#FLIGHTCONTROL.HoldingStack stack Holding stack.
|
||||||
-- @field #boolean isReadyTO Flight is ready for takeoff. This is for FLIGHTCONTROL.
|
-- @field #boolean isReadyTO Flight is ready for takeoff. This is for FLIGHTCONTROL.
|
||||||
-- @field #boolean prohibitAB Disallow (true) or allow (false) AI to use the afterburner.
|
-- @field #boolean prohibitAB Disallow (true) or allow (false) AI to use the afterburner.
|
||||||
-- @field #boolean jettisonEmptyTanks Allow (true) or disallow (false) AI to jettison empty fuel tanks.
|
-- @field #boolean jettisonEmptyTanks Allow (true) or disallow (false) AI to jettison empty fuel tanks.
|
||||||
-- @field #boolean jettisonWeapons Allow (true) or disallow (false) AI to jettison weapons if in danger.
|
-- @field #boolean jettisonWeapons Allow (true) or disallow (false) AI to jettison weapons if in danger.
|
||||||
|
-- @field #number holdtime Time [s] flight is holding before going on final. Set to nil for indefinitely.
|
||||||
--
|
--
|
||||||
-- @extends Ops.OpsGroup#OPSGROUP
|
-- @extends Ops.OpsGroup#OPSGROUP
|
||||||
|
|
||||||
@@ -273,6 +274,7 @@ function FLIGHTGROUP:New(group)
|
|||||||
-- Holding flag.
|
-- Holding flag.
|
||||||
self.flaghold=USERFLAG:New(string.format("%s_FlagHold", self.groupname))
|
self.flaghold=USERFLAG:New(string.format("%s_FlagHold", self.groupname))
|
||||||
self.flaghold:Set(0)
|
self.flaghold:Set(0)
|
||||||
|
self.holdtime=2*60
|
||||||
|
|
||||||
-- Add FSM transitions.
|
-- Add FSM transitions.
|
||||||
-- From State --> Event --> To State
|
-- From State --> Event --> To State
|
||||||
@@ -695,7 +697,7 @@ end
|
|||||||
|
|
||||||
--- Get airwing the flight group belongs to.
|
--- Get airwing the flight group belongs to.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
-- @return Ops.AirWing#AIRWING The AIRWING object (if any).
|
-- @return Ops.Airwing#AIRWING The AIRWING object (if any).
|
||||||
function FLIGHTGROUP:GetAirwing()
|
function FLIGHTGROUP:GetAirwing()
|
||||||
return self.legion
|
return self.legion
|
||||||
end
|
end
|
||||||
@@ -786,6 +788,7 @@ function FLIGHTGROUP:SetReadyForTakeoff(ReadyTO, Delay)
|
|||||||
if Delay and Delay>0 then
|
if Delay and Delay>0 then
|
||||||
self:ScheduleOnce(Delay, FLIGHTGROUP.SetReadyForTakeoff, self, ReadyTO, 0)
|
self:ScheduleOnce(Delay, FLIGHTGROUP.SetReadyForTakeoff, self, ReadyTO, 0)
|
||||||
else
|
else
|
||||||
|
self:T(self.lid.."Set Ready for Takeoff switch for flightcontrol")
|
||||||
self.isReadyTO=ReadyTO
|
self.isReadyTO=ReadyTO
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -793,7 +796,7 @@ end
|
|||||||
|
|
||||||
--- Set the FLIGHTCONTROL controlling this flight group.
|
--- Set the FLIGHTCONTROL controlling this flight group.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
-- @param Ops.FlightControl#FLIGHTCONTROL flightcontrol The FLIGHTCONTROL object.
|
-- @param OPS.FlightControl#FLIGHTCONTROL flightcontrol The FLIGHTCONTROL object.
|
||||||
-- @return #FLIGHTGROUP self
|
-- @return #FLIGHTGROUP self
|
||||||
function FLIGHTGROUP:SetFlightControl(flightcontrol)
|
function FLIGHTGROUP:SetFlightControl(flightcontrol)
|
||||||
|
|
||||||
@@ -822,7 +825,7 @@ end
|
|||||||
|
|
||||||
--- Get the FLIGHTCONTROL controlling this flight group.
|
--- Get the FLIGHTCONTROL controlling this flight group.
|
||||||
-- @param #FLIGHTGROUP self
|
-- @param #FLIGHTGROUP self
|
||||||
-- @return Ops.FlightControl#FLIGHTCONTROL The FLIGHTCONTROL object.
|
-- @return OPS.FlightControl#FLIGHTCONTROL The FLIGHTCONTROL object.
|
||||||
function FLIGHTGROUP:GetFlightControl()
|
function FLIGHTGROUP:GetFlightControl()
|
||||||
return self.flightcontrol
|
return self.flightcontrol
|
||||||
end
|
end
|
||||||
@@ -1254,9 +1257,12 @@ function FLIGHTGROUP:Status()
|
|||||||
-- Check ammo status.
|
-- Check ammo status.
|
||||||
self:_CheckAmmoStatus()
|
self:_CheckAmmoStatus()
|
||||||
|
|
||||||
-- Check damage.
|
-- Check damage.
|
||||||
self:_CheckDamage()
|
self:_CheckDamage()
|
||||||
|
|
||||||
|
-- Check if stuck while taxiing.
|
||||||
|
self:_CheckStuck()
|
||||||
|
|
||||||
-- Get current mission (if any).
|
-- Get current mission (if any).
|
||||||
local mission=self:GetMissionCurrent()
|
local mission=self:GetMissionCurrent()
|
||||||
|
|
||||||
@@ -1624,6 +1630,9 @@ function FLIGHTGROUP:Status()
|
|||||||
if not mission then
|
if not mission then
|
||||||
self.Twaiting=nil
|
self.Twaiting=nil
|
||||||
self.dTwait=nil
|
self.dTwait=nil
|
||||||
|
|
||||||
|
-- Check if group is done.
|
||||||
|
-- TODO: Not sure why I introduced this here.
|
||||||
self:_CheckGroupDone()
|
self:_CheckGroupDone()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2097,7 +2106,7 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To)
|
|||||||
-- Debug info.
|
-- Debug info.
|
||||||
if self.verbose>=1 then
|
if self.verbose>=1 then
|
||||||
local text=string.format("Initialized Flight Group %s:\n", self.groupname)
|
local text=string.format("Initialized Flight Group %s:\n", self.groupname)
|
||||||
text=text..string.format("Unit type = %s\n", self.actype)
|
text=text..string.format("Unit type = %s\n", tostring(self.actype))
|
||||||
text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedMax))
|
text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedMax))
|
||||||
text=text..string.format("Range max = %.1f km\n", self.rangemax/1000)
|
text=text..string.format("Range max = %.1f km\n", self.rangemax/1000)
|
||||||
text=text..string.format("Ceiling = %.1f feet\n", UTILS.MetersToFeet(self.ceiling))
|
text=text..string.format("Ceiling = %.1f feet\n", UTILS.MetersToFeet(self.ceiling))
|
||||||
@@ -2137,6 +2146,10 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To)
|
|||||||
|
|
||||||
if self.isAI then
|
if self.isAI then
|
||||||
|
|
||||||
|
-- TODO: Could be that element is spawned UNCONTROLLED.
|
||||||
|
-- In that case, the commands are not yet used.
|
||||||
|
-- This should be shifted to something like after ACTIVATED
|
||||||
|
|
||||||
-- Set ROE.
|
-- Set ROE.
|
||||||
self:SwitchROE(self.option.ROE)
|
self:SwitchROE(self.option.ROE)
|
||||||
|
|
||||||
@@ -2737,6 +2750,7 @@ function FLIGHTGROUP:onafterOutOfMissilesAA(From, Event, To)
|
|||||||
if self.outofAAMrtb then
|
if self.outofAAMrtb then
|
||||||
-- Back to destination or home.
|
-- Back to destination or home.
|
||||||
local airbase=self.destbase or self.homebase
|
local airbase=self.destbase or self.homebase
|
||||||
|
self:T(self.lid.."Calling RTB in onafterOutOfMissilesAA")
|
||||||
self:__RTB(-5, airbase)
|
self:__RTB(-5, airbase)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2751,6 +2765,7 @@ function FLIGHTGROUP:onafterOutOfMissilesAG(From, Event, To)
|
|||||||
if self.outofAGMrtb then
|
if self.outofAGMrtb then
|
||||||
-- Back to destination or home.
|
-- Back to destination or home.
|
||||||
local airbase=self.destbase or self.homebase
|
local airbase=self.destbase or self.homebase
|
||||||
|
self:T(self.lid.."Calling RTB in onafterOutOfMissilesAG")
|
||||||
self:__RTB(-5, airbase)
|
self:__RTB(-5, airbase)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2789,6 +2804,11 @@ function FLIGHTGROUP:_CheckGroupDone(delay, waittime)
|
|||||||
self:T(self.lid.."Engaging! Group NOT done...")
|
self:T(self.lid.."Engaging! Group NOT done...")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
-- Check if group is going for fuel.
|
||||||
|
if self:IsGoing4Fuel() then
|
||||||
|
self:T(self.lid.."Going for FUEL! Group NOT done...")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Number of tasks remaining.
|
-- Number of tasks remaining.
|
||||||
local nTasks=self:CountRemainingTasks()
|
local nTasks=self:CountRemainingTasks()
|
||||||
@@ -2840,8 +2860,8 @@ function FLIGHTGROUP:_CheckGroupDone(delay, waittime)
|
|||||||
-- Number of remaining tasks/missions?
|
-- Number of remaining tasks/missions?
|
||||||
if nTasks==0 and nMissions==0 and nTransports==0 then
|
if nTasks==0 and nMissions==0 and nTransports==0 then
|
||||||
|
|
||||||
local destbase=self.destbase or self.homebase
|
local destbase=self.destbase or self.homebase --Wrapper.Airbase#AIRBASE
|
||||||
local destzone=self.destzone or self.homezone
|
local destzone=self.destzone or self.homezone --Wrapper.Airbase#AIRBASE
|
||||||
|
|
||||||
-- Send flight to destination.
|
-- Send flight to destination.
|
||||||
if waittime then
|
if waittime then
|
||||||
@@ -2852,8 +2872,11 @@ function FLIGHTGROUP:_CheckGroupDone(delay, waittime)
|
|||||||
self:T(self.lid.."Passed Final WP and No current and/or future missions/tasks/transports AND parking at destination airbase ==> Arrived!")
|
self:T(self.lid.."Passed Final WP and No current and/or future missions/tasks/transports AND parking at destination airbase ==> Arrived!")
|
||||||
self:Arrived()
|
self:Arrived()
|
||||||
else
|
else
|
||||||
self:T(self.lid.."Passed Final WP and No current and/or future missions/tasks/transports ==> RTB!")
|
-- Only send RTB if current base is not yet the destination
|
||||||
self:__RTB(-0.1, destbase)
|
if self.currbase==nil or self.currbase.AirbaseName~=destbase.AirbaseName then
|
||||||
|
self:T(self.lid.."Passed Final WP and No current and/or future missions/tasks/transports ==> RTB!")
|
||||||
|
self:__RTB(-0.1, destbase)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
elseif destzone then
|
elseif destzone then
|
||||||
self:T(self.lid.."Passed Final WP and No current and/or future missions/tasks/transports ==> RTZ!")
|
self:T(self.lid.."Passed Final WP and No current and/or future missions/tasks/transports ==> RTZ!")
|
||||||
@@ -2981,6 +3004,7 @@ function FLIGHTGROUP:onbeforeRTB(From, Event, To, airbase, SpeedTo, SpeedHold)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if Tsuspend and not allowed then
|
if Tsuspend and not allowed then
|
||||||
|
self:T(self.lid.."Calling RTB in onbeforeRTB")
|
||||||
self:__RTB(Tsuspend, airbase, SpeedTo, SpeedHold)
|
self:__RTB(Tsuspend, airbase, SpeedTo, SpeedHold)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3198,7 +3222,7 @@ function FLIGHTGROUP:_LandAtAirbase(airbase, SpeedTo, SpeedHold, SpeedLand)
|
|||||||
self.flaghold:Set(0)
|
self.flaghold:Set(0)
|
||||||
|
|
||||||
-- Set holding time.
|
-- Set holding time.
|
||||||
local holdtime=2*60
|
local holdtime=self.holdtime
|
||||||
if fc or self.airboss then
|
if fc or self.airboss then
|
||||||
holdtime=nil
|
holdtime=nil
|
||||||
end
|
end
|
||||||
@@ -3361,7 +3385,7 @@ function FLIGHTGROUP:onafterWait(From, Event, To, Duration, Altitude, Speed)
|
|||||||
-- Set time stamp.
|
-- Set time stamp.
|
||||||
self.Twaiting=timer.getAbsTime()
|
self.Twaiting=timer.getAbsTime()
|
||||||
|
|
||||||
-- Max waiting
|
-- Max waiting time in seconds.
|
||||||
self.dTwait=Duration
|
self.dTwait=Duration
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -3401,6 +3425,9 @@ function FLIGHTGROUP:onafterRefuel(From, Event, To, Coordinate)
|
|||||||
|
|
||||||
self:Route({wp0, wp9}, 1)
|
self:Route({wp0, wp9}, 1)
|
||||||
|
|
||||||
|
-- Set RTB on Bingo option. Currently DCS does not execute the refueling task if RTB_ON_BINGO is set to "NO RTB ON BINGO"
|
||||||
|
self.group:SetOption(AI.Option.Air.id.RTB_ON_BINGO, true)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "Refueled" event.
|
--- On after "Refueled" event.
|
||||||
@@ -3414,6 +3441,9 @@ function FLIGHTGROUP:onafterRefueled(From, Event, To)
|
|||||||
local text=string.format("Flight group finished refuelling")
|
local text=string.format("Flight group finished refuelling")
|
||||||
self:T(self.lid..text)
|
self:T(self.lid..text)
|
||||||
|
|
||||||
|
-- Set RTB on Bingo option to "NO RTB ON BINGO"
|
||||||
|
self.group:SetOption(AI.Option.Air.id.RTB_ON_BINGO, false)
|
||||||
|
|
||||||
-- Check if flight is done.
|
-- Check if flight is done.
|
||||||
self:_CheckGroupDone(1)
|
self:_CheckGroupDone(1)
|
||||||
|
|
||||||
@@ -3661,6 +3691,7 @@ function FLIGHTGROUP:onafterFuelLow(From, Event, To)
|
|||||||
|
|
||||||
-- Send back to airbase.
|
-- Send back to airbase.
|
||||||
if airbase and self.fuellowrtb then
|
if airbase and self.fuellowrtb then
|
||||||
|
self:T(self.lid.."Calling RTB in onafterFuelLow")
|
||||||
self:RTB(airbase)
|
self:RTB(airbase)
|
||||||
--TODO: RTZ
|
--TODO: RTZ
|
||||||
end
|
end
|
||||||
@@ -3685,6 +3716,7 @@ function FLIGHTGROUP:onafterFuelCritical(From, Event, To)
|
|||||||
local airbase=self.destbase or self.homebase
|
local airbase=self.destbase or self.homebase
|
||||||
|
|
||||||
if airbase and self.fuelcriticalrtb and not self:IsGoing4Fuel() then
|
if airbase and self.fuelcriticalrtb and not self:IsGoing4Fuel() then
|
||||||
|
self:T(self.lid.."Calling RTB in onafterFuelCritical")
|
||||||
self:RTB(airbase)
|
self:RTB(airbase)
|
||||||
--TODO: RTZ
|
--TODO: RTZ
|
||||||
end
|
end
|
||||||
@@ -3799,10 +3831,11 @@ function FLIGHTGROUP:_InitGroup(Template)
|
|||||||
self.speedMax=group:GetSpeedMax()
|
self.speedMax=group:GetSpeedMax()
|
||||||
|
|
||||||
-- Is group mobile?
|
-- Is group mobile?
|
||||||
if self.speedMax>3.6 then
|
if self.speedMax and self.speedMax>3.6 then
|
||||||
self.isMobile=true
|
self.isMobile=true
|
||||||
else
|
else
|
||||||
self.isMobile=false
|
self.isMobile=false
|
||||||
|
self.speedMax = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Cruise speed limit 380 kts for fixed and 110 knots for rotary wings.
|
-- Cruise speed limit 380 kts for fixed and 110 knots for rotary wings.
|
||||||
@@ -4831,6 +4864,87 @@ function FLIGHTGROUP:_GetTerminal(_attribute, _category)
|
|||||||
return _terminal
|
return _terminal
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if group got stuck. This overwrites the OPSGROUP function.
|
||||||
|
-- Here we only check if stuck whilst taxiing.
|
||||||
|
-- @param #FLIGHTGROUP self
|
||||||
|
-- @param #boolean Despawn If `true`, despawn group if stuck.
|
||||||
|
-- @return #number Time in seconds the group got stuck or nil if not stuck.
|
||||||
|
function FLIGHTGROUP:_CheckStuck(Despawn)
|
||||||
|
|
||||||
|
-- Cases we are not stuck.
|
||||||
|
if not self:IsTaxiing() then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Current time.
|
||||||
|
local Tnow=timer.getTime()
|
||||||
|
|
||||||
|
-- Expected speed in m/s.
|
||||||
|
local ExpectedSpeed=5
|
||||||
|
|
||||||
|
-- Current speed in m/s.
|
||||||
|
local speed=self:GetVelocity()
|
||||||
|
|
||||||
|
-- Check speed.
|
||||||
|
if speed<0.1 then
|
||||||
|
|
||||||
|
if ExpectedSpeed>0 and not self.stuckTimestamp then
|
||||||
|
self:T2(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected", speed, ExpectedSpeed))
|
||||||
|
self.stuckTimestamp=Tnow
|
||||||
|
self.stuckVec3=self:GetVec3()
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
-- Moving (again).
|
||||||
|
self.stuckTimestamp=nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local holdtime=nil
|
||||||
|
|
||||||
|
-- Somehow we are not moving...
|
||||||
|
if self.stuckTimestamp then
|
||||||
|
|
||||||
|
-- Time we are holding.
|
||||||
|
holdtime=Tnow-self.stuckTimestamp
|
||||||
|
|
||||||
|
-- Trigger stuck event.
|
||||||
|
self:Stuck(holdtime)
|
||||||
|
|
||||||
|
if holdtime>=5*60 and holdtime<15*60 then
|
||||||
|
|
||||||
|
-- Debug warning.
|
||||||
|
self:T(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected for %d sec", speed, ExpectedSpeed, holdtime))
|
||||||
|
|
||||||
|
elseif holdtime>=15*60 then
|
||||||
|
|
||||||
|
-- Debug warning.
|
||||||
|
self:T(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected for %d sec", speed, ExpectedSpeed, holdtime))
|
||||||
|
|
||||||
|
-- Look for a current mission and cancel it as we do not seem to be able to perform it.
|
||||||
|
local mission=self:GetMissionCurrent()
|
||||||
|
|
||||||
|
if mission then
|
||||||
|
self:T(self.lid..string.format("WARNING: Cancelling mission %s [%s] due to being stuck", mission:GetName(), mission:GetType()))
|
||||||
|
self:MissionCancel(mission)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.stuckDespawn then
|
||||||
|
if self.legion then
|
||||||
|
self:T(self.lid..string.format("Asset is returned to its legion after being stuck!"))
|
||||||
|
self:ReturnToLegion()
|
||||||
|
else
|
||||||
|
self:T(self.lid..string.format("Despawning group after being stuck!"))
|
||||||
|
self:Despawn()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return holdtime
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- OPTION FUNCTIONS
|
-- OPTION FUNCTIONS
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -4871,7 +4985,7 @@ function FLIGHTGROUP:_UpdateMenu(delay)
|
|||||||
-- Get all FLIGHTCONTROLS
|
-- Get all FLIGHTCONTROLS
|
||||||
local fc={}
|
local fc={}
|
||||||
for airbasename,_flightcontrol in pairs(_DATABASE.FLIGHTCONTROLS) do
|
for airbasename,_flightcontrol in pairs(_DATABASE.FLIGHTCONTROLS) do
|
||||||
local flightcontrol=_flightcontrol --Ops.FlightControl#FLIGHTCONTROL
|
local flightcontrol=_flightcontrol --OPS.FlightControl#FLIGHTCONTROL
|
||||||
|
|
||||||
-- Get coord of airbase.
|
-- Get coord of airbase.
|
||||||
local coord=flightcontrol:GetCoordinate()
|
local coord=flightcontrol:GetCoordinate()
|
||||||
|
|||||||
@@ -2272,7 +2272,7 @@ function INTEL:GetHighestThreatContact(Cluster)
|
|||||||
|
|
||||||
for _,_contact in pairs(Cluster.Contacts) do
|
for _,_contact in pairs(Cluster.Contacts) do
|
||||||
|
|
||||||
local contact=_contact --Ops.Intelligence#INTEL.Contact
|
local contact=_contact --Ops.Intel#INTEL.Contact
|
||||||
|
|
||||||
if contact.threatlevel>threatlevel then
|
if contact.threatlevel>threatlevel then
|
||||||
threatlevel=contact.threatlevel
|
threatlevel=contact.threatlevel
|
||||||
@@ -2312,8 +2312,8 @@ end
|
|||||||
-- @field #string alias Alias name for logging.
|
-- @field #string alias Alias name for logging.
|
||||||
-- @field #number cachetime Number of seconds to keep an object.
|
-- @field #number cachetime Number of seconds to keep an object.
|
||||||
-- @field #number interval Number of seconds between collection runs.
|
-- @field #number interval Number of seconds between collection runs.
|
||||||
-- @field #table contacts Table of Ops.Intelligence#INTEL.Contact contacts.
|
-- @field #table contacts Table of Ops.Intel#INTEL.Contact contacts.
|
||||||
-- @field #table clusters Table of Ops.Intelligence#INTEL.Cluster clusters.
|
-- @field #table clusters Table of Ops.Intel#INTEL.Cluster clusters.
|
||||||
-- @field #table contactcoords Table of contacts' Core.Point#COORDINATE objects.
|
-- @field #table contactcoords Table of contacts' Core.Point#COORDINATE objects.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
@@ -2337,7 +2337,7 @@ INTEL_DLINK.version = "0.0.1"
|
|||||||
|
|
||||||
--- Function to instantiate a new object
|
--- Function to instantiate a new object
|
||||||
-- @param #INTEL_DLINK self
|
-- @param #INTEL_DLINK self
|
||||||
-- @param #table Intels Table of Ops.Intelligence#INTEL objects.
|
-- @param #table Intels Table of Ops.Intel#INTEL objects.
|
||||||
-- @param #string Alias (optional) Name of this instance. Default "SPECTRE"
|
-- @param #string Alias (optional) Name of this instance. Default "SPECTRE"
|
||||||
-- @param #number Interval (optional) When to query #INTEL objects for detected items (default 20 seconds).
|
-- @param #number Interval (optional) When to query #INTEL objects for detected items (default 20 seconds).
|
||||||
-- @param #number Cachetime (optional) How long to cache detected items (default 300 seconds).
|
-- @param #number Cachetime (optional) How long to cache detected items (default 300 seconds).
|
||||||
@@ -2449,7 +2449,7 @@ end
|
|||||||
|
|
||||||
--- Function to add an #INTEL object to the aggregator
|
--- Function to add an #INTEL object to the aggregator
|
||||||
-- @param #INTEL_DLINK self
|
-- @param #INTEL_DLINK self
|
||||||
-- @param Ops.Intelligence#INTEL Intel the #INTEL object to add
|
-- @param Ops.Intel#INTEL Intel the #INTEL object to add
|
||||||
-- @return #INTEL_DLINK self
|
-- @return #INTEL_DLINK self
|
||||||
function INTEL_DLINK:AddIntel(Intel)
|
function INTEL_DLINK:AddIntel(Intel)
|
||||||
self:T(self.lid .. "AddIntel")
|
self:T(self.lid .. "AddIntel")
|
||||||
|
|||||||
@@ -3190,14 +3190,14 @@ function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, Inclu
|
|||||||
elseif (currmission.type==AUFTRAG.Type.ONGUARD or currmission.type==AUFTRAG.Type.PATROLZONE) and (MissionType==AUFTRAG.Type.ARTY or MissionType==AUFTRAG.Type.GROUNDATTACK) then
|
elseif (currmission.type==AUFTRAG.Type.ONGUARD or currmission.type==AUFTRAG.Type.PATROLZONE) and (MissionType==AUFTRAG.Type.ARTY or MissionType==AUFTRAG.Type.GROUNDATTACK) then
|
||||||
score=score+25
|
score=score+25
|
||||||
elseif currmission.type==AUFTRAG.Type.NOTHING then
|
elseif currmission.type==AUFTRAG.Type.NOTHING then
|
||||||
score=score+25
|
score=score+30
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if MissionType==AUFTRAG.Type.OPSTRANSPORT or MissionType==AUFTRAG.Type.AMMOSUPPLY or MissionType==AUFTRAG.Type.AWACS or MissionType==AUFTRAG.Type.FUELSUPPLY or MissionType==AUFTRAG.Type.TANKER then
|
if MissionType==AUFTRAG.Type.OPSTRANSPORT or MissionType==AUFTRAG.Type.AMMOSUPPLY or MissionType==AUFTRAG.Type.AWACS or MissionType==AUFTRAG.Type.FUELSUPPLY or MissionType==AUFTRAG.Type.TANKER then
|
||||||
-- TODO: need to check for missions that do not require ammo like transport, recon, awacs, tanker etc.
|
-- TODO: need to check for missions that do not require ammo like transport, recon, awacs, tanker etc.
|
||||||
-- We better take a fresh asset. Sometimes spawned assets to something else, which is difficult to check.
|
-- We better take a fresh asset. Sometimes spawned assets do something else, which is difficult to check.
|
||||||
score=score-10
|
score=score-10
|
||||||
else
|
else
|
||||||
-- Combat mission.
|
-- Combat mission.
|
||||||
|
|||||||
@@ -1800,10 +1800,11 @@ function NAVYGROUP:_InitGroup(Template)
|
|||||||
self.speedMax=self.group:GetSpeedMax()
|
self.speedMax=self.group:GetSpeedMax()
|
||||||
|
|
||||||
-- Is group mobile?
|
-- Is group mobile?
|
||||||
if self.speedMax>3.6 then
|
if self.speedMax and self.speedMax>3.6 then
|
||||||
self.isMobile=true
|
self.isMobile=true
|
||||||
else
|
else
|
||||||
self.isMobile=false
|
self.isMobile=false
|
||||||
|
self.speedMax = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Cruise speed: 70% of max speed.
|
-- Cruise speed: 70% of max speed.
|
||||||
|
|||||||
@@ -118,6 +118,10 @@
|
|||||||
--
|
--
|
||||||
-- @field #OPSGROUP.Spot spot Laser and IR spot.
|
-- @field #OPSGROUP.Spot spot Laser and IR spot.
|
||||||
--
|
--
|
||||||
|
-- @field DCS#Vec3 stuckVec3 Position where the group got stuck.
|
||||||
|
-- @field #number stuckTimestamp Time stamp [sec], when the group got stuck.
|
||||||
|
-- @field #boolean stuckDespawn If `true`, group gets despawned after beeing stuck for a certain time.
|
||||||
|
--
|
||||||
-- @field #OPSGROUP.Ammo ammo Initial ammount of ammo.
|
-- @field #OPSGROUP.Ammo ammo Initial ammount of ammo.
|
||||||
-- @field #OPSGROUP.WeaponData weaponData Weapon data table with key=BitType.
|
-- @field #OPSGROUP.WeaponData weaponData Weapon data table with key=BitType.
|
||||||
--
|
--
|
||||||
@@ -508,7 +512,7 @@ OPSGROUP.CargoStatus={
|
|||||||
|
|
||||||
--- OpsGroup version.
|
--- OpsGroup version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
OPSGROUP.version="1.0.0"
|
OPSGROUP.version="1.0.1"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -554,11 +558,16 @@ function OPSGROUP:New(group)
|
|||||||
-- Check if group exists.
|
-- Check if group exists.
|
||||||
if self.group then
|
if self.group then
|
||||||
if not self:IsExist() then
|
if not self:IsExist() then
|
||||||
self:T(self.lid.."ERROR: GROUP does not exist! Returning nil")
|
self:E(self.lid.."ERROR: GROUP does not exist! Returning nil")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if UTILS.IsInstanceOf(group,"OPSGROUP") then
|
||||||
|
self:E(self.lid.."ERROR: GROUP is already an OPSGROUP: "..tostring(self.groupname).."!")
|
||||||
|
return group
|
||||||
|
end
|
||||||
|
|
||||||
-- Set the template.
|
-- Set the template.
|
||||||
self:_SetTemplate()
|
self:_SetTemplate()
|
||||||
|
|
||||||
@@ -592,32 +601,33 @@ function OPSGROUP:New(group)
|
|||||||
if units then
|
if units then
|
||||||
local masterunit=units[1] --Wrapper.Unit#UNIT
|
local masterunit=units[1] --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
-- Get Descriptors.
|
if masterunit then
|
||||||
self.descriptors=masterunit:GetDesc()
|
-- Get Descriptors.
|
||||||
|
self.descriptors=masterunit:GetDesc()
|
||||||
|
|
||||||
-- Set type name.
|
-- Set type name.
|
||||||
self.actype=masterunit:GetTypeName()
|
self.actype=masterunit:GetTypeName()
|
||||||
|
|
||||||
-- Is this a submarine.
|
-- Is this a submarine.
|
||||||
self.isSubmarine=masterunit:HasAttribute("Submarines")
|
self.isSubmarine=masterunit:HasAttribute("Submarines")
|
||||||
|
|
||||||
-- Has this a datalink?
|
-- Has this a datalink?
|
||||||
self.isEPLRS=masterunit:HasAttribute("Datalink")
|
self.isEPLRS=masterunit:HasAttribute("Datalink")
|
||||||
|
|
||||||
if self:IsFlightgroup() then
|
if self:IsFlightgroup() then
|
||||||
|
|
||||||
self.rangemax=self.descriptors.range and self.descriptors.range*1000 or 500*1000
|
self.rangemax=self.descriptors.range and self.descriptors.range*1000 or 500*1000
|
||||||
|
|
||||||
self.ceiling=self.descriptors.Hmax
|
self.ceiling=self.descriptors.Hmax
|
||||||
|
|
||||||
self.tankertype=select(2, masterunit:IsTanker())
|
self.tankertype=select(2, masterunit:IsTanker())
|
||||||
self.refueltype=select(2, masterunit:IsRefuelable())
|
self.refueltype=select(2, masterunit:IsRefuelable())
|
||||||
|
|
||||||
--env.info("DCS Unit BOOM_AND_RECEPTACLE="..tostring(Unit.RefuelingSystem.BOOM_AND_RECEPTACLE))
|
--env.info("DCS Unit BOOM_AND_RECEPTACLE="..tostring(Unit.RefuelingSystem.BOOM_AND_RECEPTACLE))
|
||||||
--env.info("DCS Unit PROBE_AND_DROGUE="..tostring(Unit.RefuelingSystem.PROBE_AND_DROGUE))
|
--env.info("DCS Unit PROBE_AND_DROGUE="..tostring(Unit.RefuelingSystem.PROBE_AND_DROGUE))
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Init set of detected units.
|
-- Init set of detected units.
|
||||||
@@ -670,10 +680,11 @@ function OPSGROUP:New(group)
|
|||||||
self:AddTransition("*", "UpdateRoute", "*") -- Update route of group.
|
self:AddTransition("*", "UpdateRoute", "*") -- Update route of group.
|
||||||
|
|
||||||
self:AddTransition("*", "PassingWaypoint", "*") -- Group passed a waypoint.
|
self:AddTransition("*", "PassingWaypoint", "*") -- Group passed a waypoint.
|
||||||
self:AddTransition("*", "PassedFinalWaypoint", "*") -- Group passed the waypoint.
|
self:AddTransition("*", "PassedFinalWaypoint", "*") -- Group passed the waypoint.
|
||||||
self:AddTransition("*", "GotoWaypoint", "*") -- Group switches to a specific waypoint.
|
self:AddTransition("*", "GotoWaypoint", "*") -- Group switches to a specific waypoint.
|
||||||
|
|
||||||
self:AddTransition("*", "Wait", "*") -- Group will wait for further orders.
|
self:AddTransition("*", "Wait", "*") -- Group will wait for further orders.
|
||||||
|
self:AddTransition("*", "Stuck", "*") -- Group got stuck.
|
||||||
|
|
||||||
self:AddTransition("*", "DetectedUnit", "*") -- Unit was detected (again) in this detection cycle.
|
self:AddTransition("*", "DetectedUnit", "*") -- Unit was detected (again) in this detection cycle.
|
||||||
self:AddTransition("*", "DetectedUnitNew", "*") -- Add a newly detected unit to the detected units set.
|
self:AddTransition("*", "DetectedUnitNew", "*") -- Add a newly detected unit to the detected units set.
|
||||||
@@ -1768,6 +1779,8 @@ function OPSGROUP:GetDCSUnit(UnitNumber)
|
|||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
local unit=DCSGroup:getUnit(UnitNumber or 1)
|
local unit=DCSGroup:getUnit(UnitNumber or 1)
|
||||||
return unit
|
return unit
|
||||||
|
else
|
||||||
|
self:E(self.lid..string.format("ERROR: DCS group does not exist! Cannot get unit"))
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -1881,7 +1894,7 @@ end
|
|||||||
|
|
||||||
--- Get current velocity of the group.
|
--- Get current velocity of the group.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param #string UnitName (Optional) Get heading of a specific unit of the group. Default is from the first existing unit in the group.
|
-- @param #string UnitName (Optional) Get velocity of a specific unit of the group. Default is from the first existing unit in the group.
|
||||||
-- @return #number Velocity in m/s.
|
-- @return #number Velocity in m/s.
|
||||||
function OPSGROUP:GetVelocity(UnitName)
|
function OPSGROUP:GetVelocity(UnitName)
|
||||||
|
|
||||||
@@ -2198,6 +2211,8 @@ function OPSGROUP:Destroy(Delay)
|
|||||||
self:ScheduleOnce(Delay, OPSGROUP.Destroy, self, 0)
|
self:ScheduleOnce(Delay, OPSGROUP.Destroy, self, 0)
|
||||||
else
|
else
|
||||||
|
|
||||||
|
self:T(self.lid.."Destroying group!")
|
||||||
|
|
||||||
-- Get all units.
|
-- Get all units.
|
||||||
local units=self:GetDCSUnits()
|
local units=self:GetDCSUnits()
|
||||||
|
|
||||||
@@ -3527,6 +3542,8 @@ function OPSGROUP:OnEventBirth(EventData)
|
|||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("EVENT: Element %s born ==> spawned", unitname))
|
self:T(self.lid..string.format("EVENT: Element %s born ==> spawned", unitname))
|
||||||
|
|
||||||
|
self:T2(self.lid..string.format("DCS unit=%s isExist=%s", tostring(EventData.IniDCSUnit:getName()), tostring(EventData.IniDCSUnit:isExist()) ))
|
||||||
|
|
||||||
-- Set element to spawned state.
|
-- Set element to spawned state.
|
||||||
self:ElementSpawned(element)
|
self:ElementSpawned(element)
|
||||||
|
|
||||||
@@ -6667,6 +6684,7 @@ function OPSGROUP:onafterPassingWaypoint(From, Event, To, Waypoint)
|
|||||||
local wpnext=self:GetWaypointNext()
|
local wpnext=self:GetWaypointNext()
|
||||||
if wpnext then
|
if wpnext then
|
||||||
self.speedWp=wpnext.speed
|
self.speedWp=wpnext.speed
|
||||||
|
self:T(self.lid..string.format("Expected/waypoint speed=%.1f m/s", self.speedWp))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -11382,6 +11400,7 @@ function OPSGROUP:_InitWaypoints(WpIndexMin, WpIndexMax)
|
|||||||
-- Expected speed to the first waypoint.
|
-- Expected speed to the first waypoint.
|
||||||
if i<=2 then
|
if i<=2 then
|
||||||
self.speedWp=wp.speed
|
self.speedWp=wp.speed
|
||||||
|
self:T(self.lid..string.format("Expected/waypoint speed=%.1f m/s", self.speedWp))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Speed in knots.
|
-- Speed in knots.
|
||||||
@@ -12014,7 +12033,7 @@ function OPSGROUP:GetEPLRS()
|
|||||||
return self.option.EPLRS or self.optionDefault.EPLRS
|
return self.option.EPLRS or self.optionDefault.EPLRS
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the default EPLRS for the group.
|
--- Set the default emission state for the group.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param #boolean OnOffSwitch If `true`, EPLRS is on by default. If `false` default EPLRS setting is off. If `nil`, default is on if group has EPLRS and off if it does not have a datalink.
|
-- @param #boolean OnOffSwitch If `true`, EPLRS is on by default. If `false` default EPLRS setting is off. If `nil`, default is on if group has EPLRS and off if it does not have a datalink.
|
||||||
-- @return #OPSGROUP self
|
-- @return #OPSGROUP self
|
||||||
@@ -12023,7 +12042,7 @@ function OPSGROUP:SetDefaultEmission(OnOffSwitch)
|
|||||||
if OnOffSwitch==nil then
|
if OnOffSwitch==nil then
|
||||||
self.optionDefault.Emission=true
|
self.optionDefault.Emission=true
|
||||||
else
|
else
|
||||||
self.optionDefault.EPLRS=OnOffSwitch
|
self.optionDefault.Emission=OnOffSwitch
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
-- @module Ops.PlayerTask
|
-- @module Ops.PlayerTask
|
||||||
-- @image OPS_PlayerTask.jpg
|
-- @image OPS_PlayerTask.jpg
|
||||||
-- @date Last Update Jan 2024
|
-- @date Last Update May 2024
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -411,6 +411,15 @@ function PLAYERTASK:IsDone()
|
|||||||
return IsDone
|
return IsDone
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Check if PLAYERTASK has clients assigned to it.
|
||||||
|
-- @param #PLAYERTASK self
|
||||||
|
-- @return #boolean hasclients
|
||||||
|
function PLAYERTASK:HasClients()
|
||||||
|
self:T(self.lid.."HasClients?")
|
||||||
|
local hasclients = self:CountClients() > 0 and true or false
|
||||||
|
return hasclients
|
||||||
|
end
|
||||||
|
|
||||||
--- [User] Get client names assigned as table of #strings
|
--- [User] Get client names assigned as table of #strings
|
||||||
-- @param #PLAYERTASK self
|
-- @param #PLAYERTASK self
|
||||||
-- @return #table clients
|
-- @return #table clients
|
||||||
@@ -1204,6 +1213,9 @@ do
|
|||||||
-- AIRDEFENSE = "Airdefense",
|
-- AIRDEFENSE = "Airdefense",
|
||||||
-- SAM = "SAM",
|
-- SAM = "SAM",
|
||||||
-- GROUP = "Group",
|
-- GROUP = "Group",
|
||||||
|
-- ELEVATION = "\nTarget Elevation: %s %s",
|
||||||
|
-- METER = "meter",
|
||||||
|
-- FEET = "feet",
|
||||||
-- },
|
-- },
|
||||||
--
|
--
|
||||||
-- e.g.
|
-- e.g.
|
||||||
@@ -1358,7 +1370,7 @@ PLAYERTASKCONTROLLER.Type = {
|
|||||||
AUFTRAG.Type.PRECISIONBOMBING = "Precision Bombing"
|
AUFTRAG.Type.PRECISIONBOMBING = "Precision Bombing"
|
||||||
AUFTRAG.Type.CTLD = "Combat Transport"
|
AUFTRAG.Type.CTLD = "Combat Transport"
|
||||||
AUFTRAG.Type.CSAR = "Combat Rescue"
|
AUFTRAG.Type.CSAR = "Combat Rescue"
|
||||||
|
AUFTRAG.Type.CONQUER = "Conquer"
|
||||||
---
|
---
|
||||||
-- @type Scores
|
-- @type Scores
|
||||||
PLAYERTASKCONTROLLER.Scores = {
|
PLAYERTASKCONTROLLER.Scores = {
|
||||||
@@ -1372,6 +1384,7 @@ PLAYERTASKCONTROLLER.Scores = {
|
|||||||
[AUFTRAG.Type.SEAD] = 100,
|
[AUFTRAG.Type.SEAD] = 100,
|
||||||
[AUFTRAG.Type.BOMBING] = 100,
|
[AUFTRAG.Type.BOMBING] = 100,
|
||||||
[AUFTRAG.Type.BOMBRUNWAY] = 100,
|
[AUFTRAG.Type.BOMBRUNWAY] = 100,
|
||||||
|
[AUFTRAG.Type.CONQUER] = 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -1410,6 +1423,9 @@ PLAYERTASKCONTROLLER.Messages = {
|
|||||||
THREATMEDIUM = "medium",
|
THREATMEDIUM = "medium",
|
||||||
THREATLOW = "low",
|
THREATLOW = "low",
|
||||||
THREATTEXT = "%s\nThreat: %s\nTargets left: %d\nCoord: %s",
|
THREATTEXT = "%s\nThreat: %s\nTargets left: %d\nCoord: %s",
|
||||||
|
ELEVATION = "\nTarget Elevation: %s %s",
|
||||||
|
METER = "meter",
|
||||||
|
FEET = "feet",
|
||||||
THREATTEXTTTS = "%s, %s. Target information for %s. Threat level %s. Targets left %d. Target location %s.",
|
THREATTEXTTTS = "%s, %s. Target information for %s. Threat level %s. Targets left %d. Target location %s.",
|
||||||
MARKTASK = "%s, %s, copy, task %03d location marked on map!",
|
MARKTASK = "%s, %s, copy, task %03d location marked on map!",
|
||||||
SMOKETASK = "%s, %s, copy, task %03d location smoked!",
|
SMOKETASK = "%s, %s, copy, task %03d location smoked!",
|
||||||
@@ -1490,6 +1506,9 @@ PLAYERTASKCONTROLLER.Messages = {
|
|||||||
THREATMEDIUM = "mittel",
|
THREATMEDIUM = "mittel",
|
||||||
THREATLOW = "niedrig",
|
THREATLOW = "niedrig",
|
||||||
THREATTEXT = "%s\nGefahrstufe: %s\nZiele: %d\nKoord: %s",
|
THREATTEXT = "%s\nGefahrstufe: %s\nZiele: %d\nKoord: %s",
|
||||||
|
ELEVATION = "\nZiel Höhe: %s %s",
|
||||||
|
METER = "Meter",
|
||||||
|
FEET = "Fuss",
|
||||||
THREATTEXTTTS = "%s, %s. Zielinformation zu %s. Gefahrstufe %s. Ziele %d. Zielposition %s.",
|
THREATTEXTTTS = "%s, %s. Zielinformation zu %s. Gefahrstufe %s. Ziele %d. Zielposition %s.",
|
||||||
MARKTASK = "%s, %s, verstanden, Zielposition %03d auf der Karte markiert!",
|
MARKTASK = "%s, %s, verstanden, Zielposition %03d auf der Karte markiert!",
|
||||||
SMOKETASK = "%s, %s, verstanden, Zielposition %03d mit Rauch markiert!",
|
SMOKETASK = "%s, %s, verstanden, Zielposition %03d mit Rauch markiert!",
|
||||||
@@ -1552,7 +1571,7 @@ PLAYERTASKCONTROLLER.Messages = {
|
|||||||
|
|
||||||
--- PLAYERTASK class version.
|
--- PLAYERTASK class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
PLAYERTASKCONTROLLER.version="0.1.64"
|
PLAYERTASKCONTROLLER.version="0.1.66"
|
||||||
|
|
||||||
--- Create and run a new TASKCONTROLLER instance.
|
--- Create and run a new TASKCONTROLLER instance.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
@@ -2104,10 +2123,12 @@ function PLAYERTASKCONTROLLER:_GetPlayerName(Client)
|
|||||||
local ttsplayername = nil
|
local ttsplayername = nil
|
||||||
if not self.customcallsigns[playername] then
|
if not self.customcallsigns[playername] then
|
||||||
local playergroup = Client:GetGroup()
|
local playergroup = Client:GetGroup()
|
||||||
ttsplayername = playergroup:GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
if playergroup ~= nil then
|
||||||
local newplayername = self:_GetTextForSpeech(ttsplayername)
|
ttsplayername = playergroup:GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
||||||
self.customcallsigns[playername] = newplayername
|
local newplayername = self:_GetTextForSpeech(ttsplayername)
|
||||||
ttsplayername = newplayername
|
self.customcallsigns[playername] = newplayername
|
||||||
|
ttsplayername = newplayername
|
||||||
|
end
|
||||||
else
|
else
|
||||||
ttsplayername = self.customcallsigns[playername]
|
ttsplayername = self.customcallsigns[playername]
|
||||||
end
|
end
|
||||||
@@ -3173,7 +3194,8 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
|||||||
local ttsname = self.gettext:GetEntry("TASKNAMETTS",self.locale)
|
local ttsname = self.gettext:GetEntry("TASKNAMETTS",self.locale)
|
||||||
local taskname = string.format(tname,task.Type,task.PlayerTaskNr)
|
local taskname = string.format(tname,task.Type,task.PlayerTaskNr)
|
||||||
local ttstaskname = string.format(ttsname,task.TTSType,task.PlayerTaskNr)
|
local ttstaskname = string.format(ttsname,task.TTSType,task.PlayerTaskNr)
|
||||||
local Coordinate = task.Target:GetCoordinate()
|
local Coordinate = task.Target:GetCoordinate() or COORDINATE:New(0,0,0) -- Core.Point#COORDINATE
|
||||||
|
local Elevation = Coordinate:GetLandHeight() or 0 -- meters
|
||||||
local CoordText = ""
|
local CoordText = ""
|
||||||
local CoordTextLLDM = nil
|
local CoordTextLLDM = nil
|
||||||
if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A then
|
if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A then
|
||||||
@@ -3198,6 +3220,17 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
|||||||
local ThreatGraph = "[" .. string.rep( "■", ThreatLevel ) .. string.rep( "□", 10 - ThreatLevel ) .. "]: "..ThreatLevel
|
local ThreatGraph = "[" .. string.rep( "■", ThreatLevel ) .. string.rep( "□", 10 - ThreatLevel ) .. "]: "..ThreatLevel
|
||||||
local ThreatLocaleText = self.gettext:GetEntry("THREATTEXT",self.locale)
|
local ThreatLocaleText = self.gettext:GetEntry("THREATTEXT",self.locale)
|
||||||
text = string.format(ThreatLocaleText, taskname, ThreatGraph, targets, CoordText)
|
text = string.format(ThreatLocaleText, taskname, ThreatGraph, targets, CoordText)
|
||||||
|
local settings = _DATABASE:GetPlayerSettings(playername) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
|
local elevationmeasure = self.gettext:GetEntry("FEET",self.locale)
|
||||||
|
if settings:IsMetric() then
|
||||||
|
elevationmeasure = self.gettext:GetEntry("METER",self.locale)
|
||||||
|
--Elevation = math.floor(UTILS.MetersToFeet(Elevation))
|
||||||
|
else
|
||||||
|
Elevation = math.floor(UTILS.MetersToFeet(Elevation))
|
||||||
|
end
|
||||||
|
-- ELEVATION = "\nTarget Elevation: %s %s",
|
||||||
|
local elev = self.gettext:GetEntry("ELEVATION",self.locale)
|
||||||
|
text = text .. string.format(elev,tostring(math.floor(Elevation)),elevationmeasure)
|
||||||
-- Prec bombing
|
-- Prec bombing
|
||||||
if task.Type == AUFTRAG.Type.PRECISIONBOMBING and self.precisionbombing then
|
if task.Type == AUFTRAG.Type.PRECISIONBOMBING and self.precisionbombing then
|
||||||
if self.LasingDrone and self.LasingDrone.playertask then
|
if self.LasingDrone and self.LasingDrone.playertask then
|
||||||
@@ -3946,7 +3979,7 @@ function PLAYERTASKCONTROLLER:SetupIntel(RecceName)
|
|||||||
|
|
||||||
local function NewCluster(Cluster)
|
local function NewCluster(Cluster)
|
||||||
if not self.usecluster then return self end
|
if not self.usecluster then return self end
|
||||||
local cluster = Cluster -- Ops.Intelligence#INTEL.Cluster
|
local cluster = Cluster -- Ops.Intel#INTEL.Cluster
|
||||||
local type = cluster.ctype
|
local type = cluster.ctype
|
||||||
self:T({type,self.Type})
|
self:T({type,self.Type})
|
||||||
if (type == INTEL.Ctype.AIRCRAFT and self.Type == PLAYERTASKCONTROLLER.Type.A2A) or (type == INTEL.Ctype.NAVAL and (self.Type == PLAYERTASKCONTROLLER.Type.A2S or self.Type == PLAYERTASKCONTROLLER.Type.A2GS)) then
|
if (type == INTEL.Ctype.AIRCRAFT and self.Type == PLAYERTASKCONTROLLER.Type.A2A) or (type == INTEL.Ctype.NAVAL and (self.Type == PLAYERTASKCONTROLLER.Type.A2S or self.Type == PLAYERTASKCONTROLLER.Type.A2GS)) then
|
||||||
@@ -3954,7 +3987,7 @@ function PLAYERTASKCONTROLLER:SetupIntel(RecceName)
|
|||||||
local contacts = cluster.Contacts -- #table of GROUP
|
local contacts = cluster.Contacts -- #table of GROUP
|
||||||
local targetset = SET_GROUP:New()
|
local targetset = SET_GROUP:New()
|
||||||
for _,_object in pairs(contacts) do
|
for _,_object in pairs(contacts) do
|
||||||
local contact = _object -- Ops.Intelligence#INTEL.Contact
|
local contact = _object -- Ops.Intel#INTEL.Contact
|
||||||
self:T("Adding group: "..contact.groupname)
|
self:T("Adding group: "..contact.groupname)
|
||||||
targetset:AddGroup(contact.group,true)
|
targetset:AddGroup(contact.group,true)
|
||||||
end
|
end
|
||||||
@@ -3966,14 +3999,14 @@ function PLAYERTASKCONTROLLER:SetupIntel(RecceName)
|
|||||||
if type == INTEL.Ctype.GROUND then
|
if type == INTEL.Ctype.GROUND then
|
||||||
targetset = SET_GROUP:New()
|
targetset = SET_GROUP:New()
|
||||||
for _,_object in pairs(contacts) do
|
for _,_object in pairs(contacts) do
|
||||||
local contact = _object -- Ops.Intelligence#INTEL.Contact
|
local contact = _object -- Ops.Intel#INTEL.Contact
|
||||||
self:T("Adding group: "..contact.groupname)
|
self:T("Adding group: "..contact.groupname)
|
||||||
targetset:AddGroup(contact.group,true)
|
targetset:AddGroup(contact.group,true)
|
||||||
end
|
end
|
||||||
elseif type == INTEL.Ctype.STRUCTURE then
|
elseif type == INTEL.Ctype.STRUCTURE then
|
||||||
targetset = SET_STATIC:New()
|
targetset = SET_STATIC:New()
|
||||||
for _,_object in pairs(contacts) do
|
for _,_object in pairs(contacts) do
|
||||||
local contact = _object -- Ops.Intelligence#INTEL.Contact
|
local contact = _object -- Ops.Intel#INTEL.Contact
|
||||||
self:T("Adding static: "..contact.groupname)
|
self:T("Adding static: "..contact.groupname)
|
||||||
targetset:AddStatic(contact.group)
|
targetset:AddStatic(contact.group)
|
||||||
end
|
end
|
||||||
@@ -3986,7 +4019,7 @@ function PLAYERTASKCONTROLLER:SetupIntel(RecceName)
|
|||||||
|
|
||||||
local function NewContact(Contact)
|
local function NewContact(Contact)
|
||||||
if self.usecluster then return self end
|
if self.usecluster then return self end
|
||||||
local contact = Contact -- Ops.Intelligence#INTEL.Contact
|
local contact = Contact -- Ops.Intel#INTEL.Contact
|
||||||
local type = contact.ctype
|
local type = contact.ctype
|
||||||
self:T({type,self.Type})
|
self:T({type,self.Type})
|
||||||
if (type == INTEL.Ctype.AIRCRAFT and self.Type == PLAYERTASKCONTROLLER.Type.A2A) or (type == INTEL.Ctype.NAVAL and (self.Type == PLAYERTASKCONTROLLER.Type.A2S or self.Type == PLAYERTASKCONTROLLER.Type.A2GS)) then
|
if (type == INTEL.Ctype.AIRCRAFT and self.Type == PLAYERTASKCONTROLLER.Type.A2A) or (type == INTEL.Ctype.NAVAL and (self.Type == PLAYERTASKCONTROLLER.Type.A2S or self.Type == PLAYERTASKCONTROLLER.Type.A2GS)) then
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ end
|
|||||||
|
|
||||||
--- Set airwing.
|
--- Set airwing.
|
||||||
-- @param #SQUADRON self
|
-- @param #SQUADRON self
|
||||||
-- @param Ops.AirWing#AIRWING Airwing The airwing.
|
-- @param Ops.Airwing#AIRWING Airwing The airwing.
|
||||||
-- @return #SQUADRON self
|
-- @return #SQUADRON self
|
||||||
function SQUADRON:SetAirwing(Airwing)
|
function SQUADRON:SetAirwing(Airwing)
|
||||||
self.legion=Airwing
|
self.legion=Airwing
|
||||||
@@ -252,7 +252,7 @@ end
|
|||||||
|
|
||||||
--- Get airwing.
|
--- Get airwing.
|
||||||
-- @param #SQUADRON self
|
-- @param #SQUADRON self
|
||||||
-- @return Ops.AirWing#AIRWING The airwing.
|
-- @return Ops.Airwing#AIRWING The airwing.
|
||||||
function SQUADRON:GetAirwing(Airwing)
|
function SQUADRON:GetAirwing(Airwing)
|
||||||
return self.legion
|
return self.legion
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
-- @field #number prio Priority.
|
-- @field #number prio Priority.
|
||||||
-- @field #number importance Importance.
|
-- @field #number importance Importance.
|
||||||
-- @field Ops.Auftrag#AUFTRAG mission Mission attached to this target.
|
-- @field Ops.Auftrag#AUFTRAG mission Mission attached to this target.
|
||||||
-- @field Ops.Intelligence#INTEL.Contact contact Contact attached to this target.
|
-- @field Ops.Intel#INTEL.Contact contact Contact attached to this target.
|
||||||
-- @field #boolean isDestroyed If true, target objects were destroyed.
|
-- @field #boolean isDestroyed If true, target objects were destroyed.
|
||||||
-- @field #table resources Resource list.
|
-- @field #table resources Resource list.
|
||||||
-- @field #table conditionStart Start condition functions.
|
-- @field #table conditionStart Start condition functions.
|
||||||
|
|||||||
260
Moose Development/Moose/Shapes/Circle.lua
Normal file
260
Moose Development/Moose/Shapes/Circle.lua
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
--
|
||||||
|
--
|
||||||
|
-- ### Author: **nielsvaes/coconutcockpit**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Shapes.CIRCLE
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
--- CIRCLE class.
|
||||||
|
-- @type CIRCLE
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #number Radius Radius of the circle
|
||||||
|
|
||||||
|
--- *It's NOT hip to be square* -- Someone, somewhere, probably
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # CIRCLE
|
||||||
|
-- CIRCLEs can be fetched from the drawings in the Mission Editor
|
||||||
|
|
||||||
|
---
|
||||||
|
-- This class has some of the standard CIRCLE functions you'd expect. One function of interest is CIRCLE:PointInSector() that you can use if a point is
|
||||||
|
-- within a certain sector (pizza slice) of a circle. This can be useful for many things, including rudimentary, "radar-like" searches from a unit.
|
||||||
|
--
|
||||||
|
-- CIRCLE class with properties and methods for handling circles.
|
||||||
|
-- @field #CIRCLE
|
||||||
|
CIRCLE = {
|
||||||
|
ClassName = "CIRCLE",
|
||||||
|
Radius = nil,
|
||||||
|
}
|
||||||
|
--- Finds a circle on the map by its name. The circle must have been added in the Mission Editor
|
||||||
|
-- @param #string shape_name Name of the circle to find
|
||||||
|
-- @return #CIRCLE The found circle, or nil if not found
|
||||||
|
function CIRCLE:FindOnMap(shape_name)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE:FindOnMap(shape_name))
|
||||||
|
for _, layer in pairs(env.mission.drawings.layers) do
|
||||||
|
for _, object in pairs(layer["objects"]) do
|
||||||
|
if string.find(object["name"], shape_name, 1, true) then
|
||||||
|
if object["polygonMode"] == "circle" then
|
||||||
|
self.Radius = object["radius"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds a circle by its name in the database.
|
||||||
|
-- @param #string shape_name Name of the circle to find
|
||||||
|
-- @return #CIRCLE The found circle, or nil if not found
|
||||||
|
function CIRCLE:Find(shape_name)
|
||||||
|
return _DATABASE:FindShape(shape_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Creates a new circle from a center point and a radius.
|
||||||
|
-- @param #table vec2 The center point of the circle
|
||||||
|
-- @param #number radius The radius of the circle
|
||||||
|
-- @return #CIRCLE The new circle
|
||||||
|
function CIRCLE:New(vec2, radius)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE:New())
|
||||||
|
self.CenterVec2 = vec2
|
||||||
|
self.Radius = radius
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the radius of the circle.
|
||||||
|
-- @return #number The radius of the circle
|
||||||
|
function CIRCLE:GetRadius()
|
||||||
|
return self.Radius
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if a point is contained within the circle.
|
||||||
|
-- @param #table point The point to check
|
||||||
|
-- @return #bool True if the point is contained, false otherwise
|
||||||
|
function CIRCLE:ContainsPoint(point)
|
||||||
|
if ((point.x - self.CenterVec2.x) ^ 2 + (point.y - self.CenterVec2.y) ^ 2) ^ 0.5 <= self.Radius then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if a point is contained within a sector of the circle. The start and end sector need to be clockwise
|
||||||
|
-- @param #table point The point to check
|
||||||
|
-- @param #table sector_start The start point of the sector
|
||||||
|
-- @param #table sector_end The end point of the sector
|
||||||
|
-- @param #table center The center point of the sector
|
||||||
|
-- @param #number radius The radius of the sector
|
||||||
|
-- @return #bool True if the point is contained, false otherwise
|
||||||
|
function CIRCLE:PointInSector(point, sector_start, sector_end, center, radius)
|
||||||
|
center = center or self.CenterVec2
|
||||||
|
radius = radius or self.Radius
|
||||||
|
|
||||||
|
local function are_clockwise(v1, v2)
|
||||||
|
return -v1.x * v2.y + v1.y * v2.x > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_in_radius(rp)
|
||||||
|
return rp.x * rp.x + rp.y * rp.y <= radius ^ 2
|
||||||
|
end
|
||||||
|
|
||||||
|
local rel_pt = {
|
||||||
|
x = point.x - center.x,
|
||||||
|
y = point.y - center.y
|
||||||
|
}
|
||||||
|
|
||||||
|
local rel_sector_start = {
|
||||||
|
x = sector_start.x - center.x,
|
||||||
|
y = sector_start.y - center.y,
|
||||||
|
}
|
||||||
|
|
||||||
|
local rel_sector_end = {
|
||||||
|
x = sector_end.x - center.x,
|
||||||
|
y = sector_end.y - center.y,
|
||||||
|
}
|
||||||
|
|
||||||
|
return not are_clockwise(rel_sector_start, rel_pt) and
|
||||||
|
are_clockwise(rel_sector_end, rel_pt) and
|
||||||
|
is_in_radius(rel_pt, radius)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if a unit is contained within a sector of the circle. The start and end sector need to be clockwise
|
||||||
|
-- @param #string unit_name The name of the unit to check
|
||||||
|
-- @param #table sector_start The start point of the sector
|
||||||
|
-- @param #table sector_end The end point of the sector
|
||||||
|
-- @param #table center The center point of the sector
|
||||||
|
-- @param #number radius The radius of the sector
|
||||||
|
-- @return #bool True if the unit is contained, false otherwise
|
||||||
|
function CIRCLE:UnitInSector(unit_name, sector_start, sector_end, center, radius)
|
||||||
|
center = center or self.CenterVec2
|
||||||
|
radius = radius or self.Radius
|
||||||
|
|
||||||
|
if self:PointInSector(UNIT:FindByName(unit_name):GetVec2(), sector_start, sector_end, center, radius) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if any unit of a group is contained within a sector of the circle. The start and end sector need to be clockwise
|
||||||
|
-- @param #string group_name The name of the group to check
|
||||||
|
-- @param #table sector_start The start point of the sector
|
||||||
|
-- @param #table sector_end The end point of the sector
|
||||||
|
-- @param #table center The center point of the sector
|
||||||
|
-- @param #number radius The radius of the sector
|
||||||
|
-- @return #bool True if any unit of the group is contained, false otherwise
|
||||||
|
function CIRCLE:AnyOfGroupInSector(group_name, sector_start, sector_end, center, radius)
|
||||||
|
center = center or self.CenterVec2
|
||||||
|
radius = radius or self.Radius
|
||||||
|
|
||||||
|
for _, unit in pairs(GROUP:FindByName(group_name):GetUnits()) do
|
||||||
|
if self:PointInSector(unit:GetVec2(), sector_start, sector_end, center, radius) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if all units of a group are contained within a sector of the circle. The start and end sector need to be clockwise
|
||||||
|
-- @param #string group_name The name of the group to check
|
||||||
|
-- @param #table sector_start The start point of the sector
|
||||||
|
-- @param #table sector_end The end point of the sector
|
||||||
|
-- @param #table center The center point of the sector
|
||||||
|
-- @param #number radius The radius of the sector
|
||||||
|
-- @return #bool True if all units of the group are contained, false otherwise
|
||||||
|
function CIRCLE:AllOfGroupInSector(group_name, sector_start, sector_end, center, radius)
|
||||||
|
center = center or self.CenterVec2
|
||||||
|
radius = radius or self.Radius
|
||||||
|
|
||||||
|
for _, unit in pairs(GROUP:FindByName(group_name):GetUnits()) do
|
||||||
|
if not self:PointInSector(unit:GetVec2(), sector_start, sector_end, center, radius) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if a unit is contained within a radius of the circle.
|
||||||
|
-- @param #string unit_name The name of the unit to check
|
||||||
|
-- @param #table center The center point of the radius
|
||||||
|
-- @param #number radius The radius to check
|
||||||
|
-- @return #bool True if the unit is contained, false otherwise
|
||||||
|
function CIRCLE:UnitInRadius(unit_name, center, radius)
|
||||||
|
center = center or self.CenterVec2
|
||||||
|
radius = radius or self.Radius
|
||||||
|
|
||||||
|
if UTILS.IsInRadius(center, UNIT:FindByName(unit_name):GetVec2(), radius) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if any unit of a group is contained within a radius of the circle.
|
||||||
|
-- @param #string group_name The name of the group to check
|
||||||
|
-- @param #table center The center point of the radius
|
||||||
|
-- @param #number radius The radius to check
|
||||||
|
-- @return #bool True if any unit of the group is contained, false otherwise
|
||||||
|
function CIRCLE:AnyOfGroupInRadius(group_name, center, radius)
|
||||||
|
center = center or self.CenterVec2
|
||||||
|
radius = radius or self.Radius
|
||||||
|
|
||||||
|
for _, unit in pairs(GROUP:FindByName(group_name):GetUnits()) do
|
||||||
|
if UTILS.IsInRadius(center, unit:GetVec2(), radius) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if all units of a group are contained within a radius of the circle.
|
||||||
|
-- @param #string group_name The name of the group to check
|
||||||
|
-- @param #table center The center point of the radius
|
||||||
|
-- @param #number radius The radius to check
|
||||||
|
-- @return #bool True if all units of the group are contained, false otherwise
|
||||||
|
function CIRCLE:AllOfGroupInRadius(group_name, center, radius)
|
||||||
|
center = center or self.CenterVec2
|
||||||
|
radius = radius or self.Radius
|
||||||
|
|
||||||
|
for _, unit in pairs(GROUP:FindByName(group_name):GetUnits()) do
|
||||||
|
if not UTILS.IsInRadius(center, unit:GetVec2(), radius) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a random Vec2 within the circle.
|
||||||
|
-- @return #table The random Vec2
|
||||||
|
function CIRCLE:GetRandomVec2()
|
||||||
|
local angle = math.random() * 2 * math.pi
|
||||||
|
|
||||||
|
local rx = math.random(0, self.Radius) * math.cos(angle) + self.CenterVec2.x
|
||||||
|
local ry = math.random(0, self.Radius) * math.sin(angle) + self.CenterVec2.y
|
||||||
|
|
||||||
|
return {x=rx, y=ry}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a random Vec2 on the border of the circle.
|
||||||
|
-- @return #table The random Vec2
|
||||||
|
function CIRCLE:GetRandomVec2OnBorder()
|
||||||
|
local angle = math.random() * 2 * math.pi
|
||||||
|
|
||||||
|
local rx = self.Radius * math.cos(angle) + self.CenterVec2.x
|
||||||
|
local ry = self.Radius * math.sin(angle) + self.CenterVec2.y
|
||||||
|
|
||||||
|
return {x=rx, y=ry}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculates the bounding box of the circle. The bounding box is the smallest rectangle that contains the circle.
|
||||||
|
-- @return #table The bounding box of the circle
|
||||||
|
function CIRCLE:GetBoundingBox()
|
||||||
|
local min_x = self.CenterVec2.x - self.Radius
|
||||||
|
local min_y = self.CenterVec2.y - self.Radius
|
||||||
|
local max_x = self.CenterVec2.x + self.Radius
|
||||||
|
local max_y = self.CenterVec2.y + self.Radius
|
||||||
|
|
||||||
|
return {
|
||||||
|
{x=min_x, y=min_x}, {x=max_x, y=min_y}, {x=max_x, y=max_y}, {x=min_x, y=max_y}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
85
Moose Development/Moose/Shapes/Cube.lua
Normal file
85
Moose Development/Moose/Shapes/Cube.lua
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
--
|
||||||
|
-- ### Author: **nielsvaes/coconutcockpit**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Shapes.CUBE
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
--- LINE class.
|
||||||
|
-- @type CUBE
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #number Points points of the line
|
||||||
|
-- @field #number Coords coordinates of the line
|
||||||
|
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @field #CUBE
|
||||||
|
CUBE = {
|
||||||
|
ClassName = "CUBE",
|
||||||
|
Points = {},
|
||||||
|
Coords = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Points need to be added in the following order:
|
||||||
|
--- p1 -> p4 make up the front face of the cube
|
||||||
|
--- p5 -> p8 make up the back face of the cube
|
||||||
|
--- p1 connects to p5
|
||||||
|
--- p2 connects to p6
|
||||||
|
--- p3 connects to p7
|
||||||
|
--- p4 connects to p8
|
||||||
|
---
|
||||||
|
--- 8-----------7
|
||||||
|
--- /| /|
|
||||||
|
--- / | / |
|
||||||
|
--- 4--+--------3 |
|
||||||
|
--- | | | |
|
||||||
|
--- | | | |
|
||||||
|
--- | | | |
|
||||||
|
--- | 5--------+--6
|
||||||
|
--- | / | /
|
||||||
|
--- |/ |/
|
||||||
|
--- 1-----------2
|
||||||
|
---
|
||||||
|
function CUBE:New(p1, p2, p3, p4, p5, p6, p7, p8)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE)
|
||||||
|
self.Points = {p1, p2, p3, p4, p5, p6, p7, p8}
|
||||||
|
for _, point in spairs(self.Points) do
|
||||||
|
table.insert(self.Coords, COORDINATE:NewFromVec3(point))
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function CUBE:GetCenter()
|
||||||
|
local center = { x=0, y=0, z=0 }
|
||||||
|
for _, point in pairs(self.Points) do
|
||||||
|
center.x = center.x + point.x
|
||||||
|
center.y = center.y + point.y
|
||||||
|
center.z = center.z + point.z
|
||||||
|
end
|
||||||
|
|
||||||
|
center.x = center.x / 8
|
||||||
|
center.y = center.y / 8
|
||||||
|
center.z = center.z / 8
|
||||||
|
return center
|
||||||
|
end
|
||||||
|
|
||||||
|
function CUBE:ContainsPoint(point, cube_points)
|
||||||
|
cube_points = cube_points or self.Points
|
||||||
|
local min_x, min_y, min_z = math.huge, math.huge, math.huge
|
||||||
|
local max_x, max_y, max_z = -math.huge, -math.huge, -math.huge
|
||||||
|
|
||||||
|
-- Find the minimum and maximum x, y, and z values of the cube points
|
||||||
|
for _, p in ipairs(cube_points) do
|
||||||
|
if p.x < min_x then min_x = p.x end
|
||||||
|
if p.y < min_y then min_y = p.y end
|
||||||
|
if p.z < min_z then min_z = p.z end
|
||||||
|
if p.x > max_x then max_x = p.x end
|
||||||
|
if p.y > max_y then max_y = p.y end
|
||||||
|
if p.z > max_z then max_z = p.z end
|
||||||
|
end
|
||||||
|
|
||||||
|
return point.x >= min_x and point.x <= max_x and point.y >= min_y and point.y <= max_y and point.z >= min_z and point.z <= max_z
|
||||||
|
end
|
||||||
333
Moose Development/Moose/Shapes/Line.lua
Normal file
333
Moose Development/Moose/Shapes/Line.lua
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
---
|
||||||
|
--
|
||||||
|
-- ### Author: **nielsvaes/coconutcockpit**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Shapes.LINE
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
--- LINE class.
|
||||||
|
-- @type LINE
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #number Points points of the line
|
||||||
|
-- @field #number Coords coordinates of the line
|
||||||
|
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @field #LINE
|
||||||
|
LINE = {
|
||||||
|
ClassName = "LINE",
|
||||||
|
Points = {},
|
||||||
|
Coords = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Finds a line on the map by its name. The line must be drawn in the Mission Editor
|
||||||
|
-- @param #string line_name Name of the line to find
|
||||||
|
-- @return #LINE The found line, or nil if not found
|
||||||
|
function LINE:FindOnMap(line_name)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE:FindOnMap(line_name))
|
||||||
|
|
||||||
|
for _, layer in pairs(env.mission.drawings.layers) do
|
||||||
|
for _, object in pairs(layer["objects"]) do
|
||||||
|
if object["name"] == line_name then
|
||||||
|
if object["primitiveType"] == "Line" then
|
||||||
|
for _, point in UTILS.spairs(object["points"]) do
|
||||||
|
local p = {x = object["mapX"] + point["x"],
|
||||||
|
y = object["mapY"] + point["y"] }
|
||||||
|
local coord = COORDINATE:NewFromVec2(p)
|
||||||
|
table.insert(self.Points, p)
|
||||||
|
table.insert(self.Coords, coord)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:I(#self.Points)
|
||||||
|
if #self.Points == 0 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
self.MarkIDs = {}
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds a line by its name in the database.
|
||||||
|
-- @param #string shape_name Name of the line to find
|
||||||
|
-- @return #LINE The found line, or nil if not found
|
||||||
|
function LINE:Find(shape_name)
|
||||||
|
return _DATABASE:FindShape(shape_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Creates a new line from two points.
|
||||||
|
-- @param #table vec2 The first point of the line
|
||||||
|
-- @param #number radius The second point of the line
|
||||||
|
-- @return #LINE The new line
|
||||||
|
function LINE:New(...)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE:New())
|
||||||
|
self.Points = {...}
|
||||||
|
self:I(self.Points)
|
||||||
|
for _, point in UTILS.spairs(self.Points) do
|
||||||
|
table.insert(self.Coords, COORDINATE:NewFromVec2(point))
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Creates a new line from a circle.
|
||||||
|
-- @param #table center_point center point of the circle
|
||||||
|
-- @param #number radius radius of the circle, half length of the line
|
||||||
|
-- @param #number angle_degrees degrees the line will form from center point
|
||||||
|
-- @return #LINE The new line
|
||||||
|
function LINE:NewFromCircle(center_point, radius, angle_degrees)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE:New())
|
||||||
|
self.CenterVec2 = center_point
|
||||||
|
local angleRadians = math.rad(angle_degrees)
|
||||||
|
|
||||||
|
local point1 = {
|
||||||
|
x = center_point.x + radius * math.cos(angleRadians),
|
||||||
|
y = center_point.y + radius * math.sin(angleRadians)
|
||||||
|
}
|
||||||
|
|
||||||
|
local point2 = {
|
||||||
|
x = center_point.x + radius * math.cos(angleRadians + math.pi),
|
||||||
|
y = center_point.y + radius * math.sin(angleRadians + math.pi)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, point in pairs{point1, point2} do
|
||||||
|
table.insert(self.Points, point)
|
||||||
|
table.insert(self.Coords, COORDINATE:NewFromVec2(point))
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the coordinates of the line.
|
||||||
|
-- @return #table The coordinates of the line
|
||||||
|
function LINE:Coordinates()
|
||||||
|
return self.Coords
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the start coordinate of the line. The start coordinate is the first point of the line.
|
||||||
|
-- @return #COORDINATE The start coordinate of the line
|
||||||
|
function LINE:GetStartCoordinate()
|
||||||
|
return self.Coords[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the end coordinate of the line. The end coordinate is the last point of the line.
|
||||||
|
-- @return #COORDINATE The end coordinate of the line
|
||||||
|
function LINE:GetEndCoordinate()
|
||||||
|
return self.Coords[#self.Coords]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the start point of the line. The start point is the first point of the line.
|
||||||
|
-- @return #table The start point of the line
|
||||||
|
function LINE:GetStartPoint()
|
||||||
|
return self.Points[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the end point of the line. The end point is the last point of the line.
|
||||||
|
-- @return #table The end point of the line
|
||||||
|
function LINE:GetEndPoint()
|
||||||
|
return self.Points[#self.Points]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the length of the line.
|
||||||
|
-- @return #number The length of the line
|
||||||
|
function LINE:GetLength()
|
||||||
|
local total_length = 0
|
||||||
|
for i=1, #self.Points - 1 do
|
||||||
|
local x1, y1 = self.Points[i]["x"], self.Points[i]["y"]
|
||||||
|
local x2, y2 = self.Points[i+1]["x"], self.Points[i+1]["y"]
|
||||||
|
local segment_length = math.sqrt((x2 - x1)^2 + (y2 - y1)^2)
|
||||||
|
total_length = total_length + segment_length
|
||||||
|
end
|
||||||
|
return total_length
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a random point on the line.
|
||||||
|
-- @param #table points (optional) The points of the line or 2 other points if you're just using the LINE class without an object of it
|
||||||
|
-- @return #table The random point
|
||||||
|
function LINE:GetRandomPoint(points)
|
||||||
|
points = points or self.Points
|
||||||
|
local rand = math.random() -- 0->1
|
||||||
|
|
||||||
|
local random_x = points[1].x + rand * (points[2].x - points[1].x)
|
||||||
|
local random_y = points[1].y + rand * (points[2].y - points[1].y)
|
||||||
|
|
||||||
|
return { x= random_x, y= random_y }
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the heading of the line.
|
||||||
|
-- @param #table points (optional) The points of the line or 2 other points if you're just using the LINE class without an object of it
|
||||||
|
-- @return #number The heading of the line
|
||||||
|
function LINE:GetHeading(points)
|
||||||
|
points = points or self.Points
|
||||||
|
|
||||||
|
local angle = math.atan2(points[2].y - points[1].y, points[2].x - points[1].x)
|
||||||
|
|
||||||
|
angle = math.deg(angle)
|
||||||
|
if angle < 0 then
|
||||||
|
angle = angle + 360
|
||||||
|
end
|
||||||
|
|
||||||
|
return angle
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Return each part of the line as a new line
|
||||||
|
-- @return #table The points
|
||||||
|
function LINE:GetIndividualParts()
|
||||||
|
local parts = {}
|
||||||
|
if #self.Points == 2 then
|
||||||
|
parts = {self}
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=1, #self.Points -1 do
|
||||||
|
local p1 = self.Points[i]
|
||||||
|
local p2 = self.Points[i % #self.Points + 1]
|
||||||
|
table.add(parts, LINE:New(p1, p2))
|
||||||
|
end
|
||||||
|
|
||||||
|
return parts
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets a number of points in between the start and end points of the line.
|
||||||
|
-- @param #number amount The number of points to get
|
||||||
|
-- @param #table start_point (Optional) The start point of the line, defaults to the object's start point
|
||||||
|
-- @param #table end_point (Optional) The end point of the line, defaults to the object's end point
|
||||||
|
-- @return #table The points
|
||||||
|
function LINE:GetPointsInbetween(amount, start_point, end_point)
|
||||||
|
start_point = start_point or self:GetStartPoint()
|
||||||
|
end_point = end_point or self:GetEndPoint()
|
||||||
|
if amount == 0 then return {start_point, end_point} end
|
||||||
|
|
||||||
|
amount = amount + 1
|
||||||
|
local points = {}
|
||||||
|
|
||||||
|
local difference = { x = end_point.x - start_point.x, y = end_point.y - start_point.y }
|
||||||
|
local divided = { x = difference.x / amount, y = difference.y / amount }
|
||||||
|
|
||||||
|
for j=0, amount do
|
||||||
|
local part_pos = {x = divided.x * j, y = divided.y * j}
|
||||||
|
-- add part_pos vector to the start point so the new point is placed along in the line
|
||||||
|
local point = {x = start_point.x + part_pos.x, y = start_point.y + part_pos.y}
|
||||||
|
table.insert(points, point)
|
||||||
|
end
|
||||||
|
return points
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets a number of points in between the start and end points of the line.
|
||||||
|
-- @param #number amount The number of points to get
|
||||||
|
-- @param #table start_point (Optional) The start point of the line, defaults to the object's start point
|
||||||
|
-- @param #table end_point (Optional) The end point of the line, defaults to the object's end point
|
||||||
|
-- @return #table The points
|
||||||
|
function LINE:GetCoordinatesInBetween(amount, start_point, end_point)
|
||||||
|
local coords = {}
|
||||||
|
for _, pt in pairs(self:GetPointsInbetween(amount, start_point, end_point)) do
|
||||||
|
table.add(coords, COORDINATE:NewFromVec2(pt))
|
||||||
|
end
|
||||||
|
return coords
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function LINE:GetRandomPoint(start_point, end_point)
|
||||||
|
start_point = start_point or self:GetStartPoint()
|
||||||
|
end_point = end_point or self:GetEndPoint()
|
||||||
|
|
||||||
|
local fraction = math.random()
|
||||||
|
|
||||||
|
local difference = { x = end_point.x - start_point.x, y = end_point.y - start_point.y }
|
||||||
|
local part_pos = {x = difference.x * fraction, y = difference.y * fraction}
|
||||||
|
local random_point = { x = start_point.x + part_pos.x, y = start_point.y + part_pos.y}
|
||||||
|
|
||||||
|
return random_point
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function LINE:GetRandomCoordinate(start_point, end_point)
|
||||||
|
start_point = start_point or self:GetStartPoint()
|
||||||
|
end_point = end_point or self:GetEndPoint()
|
||||||
|
|
||||||
|
return COORDINATE:NewFromVec2(self:GetRandomPoint(start_point, end_point))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Gets a number of points on a sine wave between the start and end points of the line.
|
||||||
|
-- @param #number amount The number of points to get
|
||||||
|
-- @param #table start_point (Optional) The start point of the line, defaults to the object's start point
|
||||||
|
-- @param #table end_point (Optional) The end point of the line, defaults to the object's end point
|
||||||
|
-- @param #number frequency (Optional) The frequency of the sine wave, default 1
|
||||||
|
-- @param #number phase (Optional) The phase of the sine wave, default 0
|
||||||
|
-- @param #number amplitude (Optional) The amplitude of the sine wave, default 100
|
||||||
|
-- @return #table The points
|
||||||
|
function LINE:GetPointsBetweenAsSineWave(amount, start_point, end_point, frequency, phase, amplitude)
|
||||||
|
amount = amount or 20
|
||||||
|
start_point = start_point or self:GetStartPoint()
|
||||||
|
end_point = end_point or self:GetEndPoint()
|
||||||
|
frequency = frequency or 1 -- number of cycles per unit of x
|
||||||
|
phase = phase or 0 -- offset in radians
|
||||||
|
amplitude = amplitude or 100 -- maximum height of the wave
|
||||||
|
|
||||||
|
local points = {}
|
||||||
|
|
||||||
|
-- Returns the y-coordinate of the sine wave at x
|
||||||
|
local function sine_wave(x)
|
||||||
|
return amplitude * math.sin(2 * math.pi * frequency * (x - start_point.x) + phase)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Plot x-amount of points on the sine wave between point_01 and point_02
|
||||||
|
local x = start_point.x
|
||||||
|
local step = (end_point.x - start_point.x) / 20
|
||||||
|
for _=1, amount do
|
||||||
|
local y = sine_wave(x)
|
||||||
|
x = x + step
|
||||||
|
table.add(points, {x=x, y=y})
|
||||||
|
end
|
||||||
|
return points
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculates the bounding box of the line. The bounding box is the smallest rectangle that contains the line.
|
||||||
|
-- @return #table The bounding box of the line
|
||||||
|
function LINE:GetBoundingBox()
|
||||||
|
local min_x, min_y, max_x, max_y = self.Points[1].x, self.Points[1].y, self.Points[2].x, self.Points[2].y
|
||||||
|
|
||||||
|
for i = 2, #self.Points do
|
||||||
|
local x, y = self.Points[i].x, self.Points[i].y
|
||||||
|
|
||||||
|
if x < min_x then
|
||||||
|
min_x = x
|
||||||
|
end
|
||||||
|
if y < min_y then
|
||||||
|
min_y = y
|
||||||
|
end
|
||||||
|
if x > max_x then
|
||||||
|
max_x = x
|
||||||
|
end
|
||||||
|
if y > max_y then
|
||||||
|
max_y = y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
{x=min_x, y=min_x}, {x=max_x, y=min_y}, {x=max_x, y=max_y}, {x=min_x, y=max_y}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Draws the line on the map.
|
||||||
|
-- @param #table points The points of the line
|
||||||
|
function LINE:Draw()
|
||||||
|
for i=1, #self.Coords -1 do
|
||||||
|
local c1 = self.Coords[i]
|
||||||
|
local c2 = self.Coords[i % #self.Coords + 1]
|
||||||
|
table.add(self.MarkIDs, c1:LineToAll(c2))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Removes the drawing of the line from the map.
|
||||||
|
function LINE:RemoveDraw()
|
||||||
|
for _, mark_id in pairs(self.MarkIDs) do
|
||||||
|
UTILS.RemoveMark(mark_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
213
Moose Development/Moose/Shapes/Oval.lua
Normal file
213
Moose Development/Moose/Shapes/Oval.lua
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
---
|
||||||
|
--
|
||||||
|
-- ### Author: **nielsvaes/coconutcockpit**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Shapes.OVAL
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
--- OVAL class.
|
||||||
|
-- @type OVAL
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #number MajorAxis The major axis (radius) of the oval
|
||||||
|
-- @field #number MinorAxis The minor axis (radius) of the oval
|
||||||
|
-- @field #number Angle The angle the oval is rotated on
|
||||||
|
|
||||||
|
--- *The little man removed his hat, what an egg shaped head he had* -- Agatha Christie
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # OVAL
|
||||||
|
-- OVALs can be fetched from the drawings in the Mission Editor
|
||||||
|
--
|
||||||
|
-- The major and minor axes define how elongated the shape of an oval is. This class has some basic functions that the other SHAPE classes have as well.
|
||||||
|
-- Since it's not possible to draw the shape of an oval while the mission is running, right now the draw function draws 2 cicles. One with the major axis and one with
|
||||||
|
-- the minor axis. It then draws a diamond shape on an angle where the corners touch the major and minor axes to give an indication of what the oval actually
|
||||||
|
-- looks like.
|
||||||
|
--
|
||||||
|
-- Using ovals can be handy to find an area on the ground that is actually an intersection of a cone and a plane. So imagine you're faking the view cone of
|
||||||
|
-- a targeting pod and
|
||||||
|
|
||||||
|
--- OVAL class with properties and methods for handling ovals.
|
||||||
|
-- @field #OVAL
|
||||||
|
OVAL = {
|
||||||
|
ClassName = "OVAL",
|
||||||
|
MajorAxis = nil,
|
||||||
|
MinorAxis = nil,
|
||||||
|
Angle = 0,
|
||||||
|
DrawPoly=nil
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Finds an oval on the map by its name. The oval must be drawn on the map.
|
||||||
|
-- @param #string shape_name Name of the oval to find
|
||||||
|
-- @return #OVAL The found oval, or nil if not found
|
||||||
|
function OVAL:FindOnMap(shape_name)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE:FindOnMap(shape_name))
|
||||||
|
for _, layer in pairs(env.mission.drawings.layers) do
|
||||||
|
for _, object in pairs(layer["objects"]) do
|
||||||
|
if string.find(object["name"], shape_name, 1, true) then
|
||||||
|
if object["polygonMode"] == "oval" then
|
||||||
|
self.CenterVec2 = { x = object["mapX"], y = object["mapY"] }
|
||||||
|
self.MajorAxis = object["r1"]
|
||||||
|
self.MinorAxis = object["r2"]
|
||||||
|
self.Angle = object["angle"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds an oval by its name in the database.
|
||||||
|
-- @param #string shape_name Name of the oval to find
|
||||||
|
-- @return #OVAL The found oval, or nil if not found
|
||||||
|
function OVAL:Find(shape_name)
|
||||||
|
return _DATABASE:FindShape(shape_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Creates a new oval from a center point, major axis, minor axis, and angle.
|
||||||
|
-- @param #table vec2 The center point of the oval
|
||||||
|
-- @param #number major_axis The major axis of the oval
|
||||||
|
-- @param #number minor_axis The minor axis of the oval
|
||||||
|
-- @param #number angle The angle of the oval
|
||||||
|
-- @return #OVAL The new oval
|
||||||
|
function OVAL:New(vec2, major_axis, minor_axis, angle)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE:New())
|
||||||
|
self.CenterVec2 = vec2
|
||||||
|
self.MajorAxis = major_axis
|
||||||
|
self.MinorAxis = minor_axis
|
||||||
|
self.Angle = angle or 0
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the major axis of the oval.
|
||||||
|
-- @return #number The major axis of the oval
|
||||||
|
function OVAL:GetMajorAxis()
|
||||||
|
return self.MajorAxis
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the minor axis of the oval.
|
||||||
|
-- @return #number The minor axis of the oval
|
||||||
|
function OVAL:GetMinorAxis()
|
||||||
|
return self.MinorAxis
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the angle of the oval.
|
||||||
|
-- @return #number The angle of the oval
|
||||||
|
function OVAL:GetAngle()
|
||||||
|
return self.Angle
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Sets the major axis of the oval.
|
||||||
|
-- @param #number value The new major axis
|
||||||
|
function OVAL:SetMajorAxis(value)
|
||||||
|
self.MajorAxis = value
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Sets the minor axis of the oval.
|
||||||
|
-- @param #number value The new minor axis
|
||||||
|
function OVAL:SetMinorAxis(value)
|
||||||
|
self.MinorAxis = value
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Sets the angle of the oval.
|
||||||
|
-- @param #number value The new angle
|
||||||
|
function OVAL:SetAngle(value)
|
||||||
|
self.Angle = value
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if a point is contained within the oval.
|
||||||
|
-- @param #table point The point to check
|
||||||
|
-- @return #bool True if the point is contained, false otherwise
|
||||||
|
function OVAL:ContainsPoint(point)
|
||||||
|
local cos, sin = math.cos, math.sin
|
||||||
|
local dx = point.x - self.CenterVec2.x
|
||||||
|
local dy = point.y - self.CenterVec2.y
|
||||||
|
local rx = dx * cos(self.Angle) + dy * sin(self.Angle)
|
||||||
|
local ry = -dx * sin(self.Angle) + dy * cos(self.Angle)
|
||||||
|
return rx * rx / (self.MajorAxis * self.MajorAxis) + ry * ry / (self.MinorAxis * self.MinorAxis) <= 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a random Vec2 within the oval.
|
||||||
|
-- @return #table The random Vec2
|
||||||
|
function OVAL:GetRandomVec2()
|
||||||
|
local theta = math.rad(self.Angle)
|
||||||
|
|
||||||
|
local random_point = math.sqrt(math.random()) --> uniformly
|
||||||
|
--local random_point = math.random() --> more clumped around center
|
||||||
|
local phi = math.random() * 2 * math.pi
|
||||||
|
local x_c = random_point * math.cos(phi)
|
||||||
|
local y_c = random_point * math.sin(phi)
|
||||||
|
local x_e = x_c * self.MajorAxis
|
||||||
|
local y_e = y_c * self.MinorAxis
|
||||||
|
local rx = (x_e * math.cos(theta) - y_e * math.sin(theta)) + self.CenterVec2.x
|
||||||
|
local ry = (x_e * math.sin(theta) + y_e * math.cos(theta)) + self.CenterVec2.y
|
||||||
|
|
||||||
|
return {x=rx, y=ry}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculates the bounding box of the oval. The bounding box is the smallest rectangle that contains the oval.
|
||||||
|
-- @return #table The bounding box of the oval
|
||||||
|
function OVAL:GetBoundingBox()
|
||||||
|
local min_x = self.CenterVec2.x - self.MajorAxis
|
||||||
|
local min_y = self.CenterVec2.y - self.MinorAxis
|
||||||
|
local max_x = self.CenterVec2.x + self.MajorAxis
|
||||||
|
local max_y = self.CenterVec2.y + self.MinorAxis
|
||||||
|
|
||||||
|
return {
|
||||||
|
{x=min_x, y=min_x}, {x=max_x, y=min_y}, {x=max_x, y=max_y}, {x=min_x, y=max_y}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Draws the oval on the map, for debugging
|
||||||
|
-- @param #number angle (Optional) The angle of the oval. If nil will use self.Angle
|
||||||
|
function OVAL:Draw()
|
||||||
|
--for pt in pairs(self:PointsOnEdge(20)) do
|
||||||
|
-- COORDINATE:NewFromVec2(pt)
|
||||||
|
--end
|
||||||
|
|
||||||
|
self.DrawPoly = POLYGON:NewFromPoints(self:PointsOnEdge(20))
|
||||||
|
self.DrawPoly:Draw(true)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---- TODO: draw a better shape using line segments
|
||||||
|
--angle = angle or self.Angle
|
||||||
|
--local coor = self:GetCenterCoordinate()
|
||||||
|
--
|
||||||
|
--table.add(self.MarkIDs, coor:CircleToAll(self.MajorAxis))
|
||||||
|
--table.add(self.MarkIDs, coor:CircleToAll(self.MinorAxis))
|
||||||
|
--table.add(self.MarkIDs, coor:LineToAll(coor:Translate(self.MajorAxis, self.Angle)))
|
||||||
|
--
|
||||||
|
--local pt_1 = coor:Translate(self.MajorAxis, self.Angle)
|
||||||
|
--local pt_2 = coor:Translate(self.MinorAxis, self.Angle - 90)
|
||||||
|
--local pt_3 = coor:Translate(self.MajorAxis, self.Angle - 180)
|
||||||
|
--local pt_4 = coor:Translate(self.MinorAxis, self.Angle - 270)
|
||||||
|
--table.add(self.MarkIDs, pt_1:QuadToAll(pt_2, pt_3, pt_4), -1, {0, 1, 0}, 1, {0, 1, 0})
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Removes the drawing of the oval from the map
|
||||||
|
function OVAL:RemoveDraw()
|
||||||
|
self.DrawPoly:RemoveDraw()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function OVAL:PointsOnEdge(num_points)
|
||||||
|
num_points = num_points or 20
|
||||||
|
local points = {}
|
||||||
|
local dtheta = 2 * math.pi / num_points
|
||||||
|
|
||||||
|
for i = 0, num_points - 1 do
|
||||||
|
local theta = i * dtheta
|
||||||
|
local x = self.CenterVec2.x + self.MajorAxis * math.cos(theta) * math.cos(self.Angle) - self.MinorAxis * math.sin(theta) * math.sin(self.Angle)
|
||||||
|
local y = self.CenterVec2.y + self.MajorAxis * math.cos(theta) * math.sin(self.Angle) + self.MinorAxis * math.sin(theta) * math.cos(self.Angle)
|
||||||
|
table.insert(points, {x = x, y = y})
|
||||||
|
end
|
||||||
|
|
||||||
|
return points
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
458
Moose Development/Moose/Shapes/Polygon.lua
Normal file
458
Moose Development/Moose/Shapes/Polygon.lua
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
---
|
||||||
|
--
|
||||||
|
-- ### Author: **nielsvaes/coconutcockpit**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Shapes.POLYGON
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
--- POLYGON class.
|
||||||
|
-- @type POLYGON
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #table Points List of 3D points defining the shape, this will be assigned automatically if you're passing in a drawing from the Mission Editor
|
||||||
|
-- @field #table Coords List of COORDINATE defining the path, this will be assigned automatically if you're passing in a drawing from the Mission Editor
|
||||||
|
-- @field #table MarkIDs List any MARKIDs this class use, this will be assigned automatically if you're passing in a drawing from the Mission Editor
|
||||||
|
-- @field #table Triangles List of TRIANGLEs that make up the shape of the POLYGON after being triangulated
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *Polygons are fashionable at the moment* -- Trip Hawkins
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # POLYGON
|
||||||
|
-- POLYGONs can be fetched from the drawings in the Mission Editor if the drawing is:
|
||||||
|
-- * A closed shape made with line segments
|
||||||
|
-- * A closed shape made with a freehand line
|
||||||
|
-- * A freehand drawn polygon
|
||||||
|
-- * A rect
|
||||||
|
-- Use the POLYGON:FindOnMap() of POLYGON:Find() functions for this. You can also create a non existing polygon in memory using the POLYGON:New() function. Pass in a
|
||||||
|
-- any number of Vec2s into this function to define the shape of the polygon you want.
|
||||||
|
--
|
||||||
|
-- You can draw very intricate and complex polygons in the Mission Editor to avoid (or include) map objects. You can then generate random points within this complex
|
||||||
|
-- shape for spawning groups or checking positions.
|
||||||
|
--
|
||||||
|
-- When a POLYGON is made, it's automatically triangulated. The resulting triangles are stored in POLYGON.Triangles. This also immeadiately saves the surface area
|
||||||
|
-- of the POLYGON. Because the POLYGON is triangulated, it's possible to generate random points within this POLYGON without having to use a trial and error method to see if
|
||||||
|
-- the point is contained within the shape.
|
||||||
|
-- Using POLYGON:GetRandomVec2() will result in a truly, non-biased, random Vec2 within the shape. You'll want to use this function most. There's also POLYGON:GetRandomNonWeightedVec2
|
||||||
|
-- which ignores the size of the triangles in the polygon to pick a random points. This will result in more points clumping together in parts of the polygon where the triangles are
|
||||||
|
-- the smallest.
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @field #POLYGON
|
||||||
|
POLYGON = {
|
||||||
|
ClassName = "POLYGON",
|
||||||
|
Points = {},
|
||||||
|
Coords = {},
|
||||||
|
Triangles = {},
|
||||||
|
SurfaceArea = 0,
|
||||||
|
TriangleMarkIDs = {},
|
||||||
|
OutlineMarkIDs = {},
|
||||||
|
Angle = nil, -- for arrows
|
||||||
|
Heading = nil -- for arrows
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Finds a polygon on the map by its name. The polygon must be added in the mission editor.
|
||||||
|
-- @param #string shape_name Name of the polygon to find
|
||||||
|
-- @return #POLYGON The found polygon, or nil if not found
|
||||||
|
function POLYGON:FindOnMap(shape_name)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE:FindOnMap(shape_name))
|
||||||
|
|
||||||
|
for _, layer in pairs(env.mission.drawings.layers) do
|
||||||
|
for _, object in pairs(layer["objects"]) do
|
||||||
|
if object["name"] == shape_name then
|
||||||
|
if (object["primitiveType"] == "Line" and object["closed"] == true) or (object["polygonMode"] == "free") then
|
||||||
|
for _, point in UTILS.spairs(object["points"]) do
|
||||||
|
local p = {x = object["mapX"] + point["x"],
|
||||||
|
y = object["mapY"] + point["y"] }
|
||||||
|
local coord = COORDINATE:NewFromVec2(p)
|
||||||
|
self.Points[#self.Points + 1] = p
|
||||||
|
self.Coords[#self.Coords + 1] = coord
|
||||||
|
end
|
||||||
|
elseif object["polygonMode"] == "rect" then
|
||||||
|
local angle = object["angle"]
|
||||||
|
local half_width = object["width"] / 2
|
||||||
|
local half_height = object["height"] / 2
|
||||||
|
|
||||||
|
local p1 = UTILS.RotatePointAroundPivot({ x = self.CenterVec2.x - half_height, y = self.CenterVec2.y + half_width }, self.CenterVec2, angle)
|
||||||
|
local p2 = UTILS.RotatePointAroundPivot({ x = self.CenterVec2.x + half_height, y = self.CenterVec2.y + half_width }, self.CenterVec2, angle)
|
||||||
|
local p3 = UTILS.RotatePointAroundPivot({ x = self.CenterVec2.x + half_height, y = self.CenterVec2.y - half_width }, self.CenterVec2, angle)
|
||||||
|
local p4 = UTILS.RotatePointAroundPivot({ x = self.CenterVec2.x - half_height, y = self.CenterVec2.y - half_width }, self.CenterVec2, angle)
|
||||||
|
|
||||||
|
self.Points = {p1, p2, p3, p4}
|
||||||
|
for _, point in pairs(self.Points) do
|
||||||
|
self.Coords[#self.Coords + 1] = COORDINATE:NewFromVec2(point)
|
||||||
|
end
|
||||||
|
elseif object["polygonMode"] == "arrow" then
|
||||||
|
for _, point in UTILS.spairs(object["points"]) do
|
||||||
|
local p = {x = object["mapX"] + point["x"],
|
||||||
|
y = object["mapY"] + point["y"] }
|
||||||
|
local coord = COORDINATE:NewFromVec2(p)
|
||||||
|
self.Points[#self.Points + 1] = p
|
||||||
|
self.Coords[#self.Coords + 1] = coord
|
||||||
|
end
|
||||||
|
self.Angle = object["angle"]
|
||||||
|
self.Heading = UTILS.ClampAngle(self.Angle + 90)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #self.Points == 0 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
self.CenterVec2 = self:GetCentroid()
|
||||||
|
self.Triangles = self:Triangulate()
|
||||||
|
self.SurfaceArea = self:__CalculateSurfaceArea()
|
||||||
|
|
||||||
|
self.TriangleMarkIDs = {}
|
||||||
|
self.OutlineMarkIDs = {}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Creates a polygon from a zone. The zone must be defined in the mission.
|
||||||
|
-- @param #string zone_name Name of the zone
|
||||||
|
-- @return #POLYGON The polygon created from the zone, or nil if the zone is not found
|
||||||
|
function POLYGON:FromZone(zone_name)
|
||||||
|
for _, zone in pairs(env.mission.triggers.zones) do
|
||||||
|
if zone["name"] == zone_name then
|
||||||
|
return POLYGON:New(unpack(zone["verticies"] or {}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds a polygon by its name in the database.
|
||||||
|
-- @param #string shape_name Name of the polygon to find
|
||||||
|
-- @return #POLYGON The found polygon, or nil if not found
|
||||||
|
function POLYGON:Find(shape_name)
|
||||||
|
return _DATABASE:FindShape(shape_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Creates a new polygon from a list of points. Each point is a table with 'x' and 'y' fields.
|
||||||
|
-- @param #table ... Points of the polygon
|
||||||
|
-- @return #POLYGON The new polygon
|
||||||
|
function POLYGON:New(...)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE:New())
|
||||||
|
|
||||||
|
self.Points = {...}
|
||||||
|
self.Coords = {}
|
||||||
|
for _, point in UTILS.spairs(self.Points) do
|
||||||
|
table.insert(self.Coords, COORDINATE:NewFromVec2(point))
|
||||||
|
end
|
||||||
|
self.Triangles = self:Triangulate()
|
||||||
|
self.SurfaceArea = self:__CalculateSurfaceArea()
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculates the centroid of the polygon. The centroid is the average of the 'x' and 'y' coordinates of the points.
|
||||||
|
-- @return #table The centroid of the polygon
|
||||||
|
function POLYGON:GetCentroid()
|
||||||
|
local function sum(t)
|
||||||
|
local total = 0
|
||||||
|
for _, value in pairs(t) do
|
||||||
|
total = total + value
|
||||||
|
end
|
||||||
|
return total
|
||||||
|
end
|
||||||
|
|
||||||
|
local x_values = {}
|
||||||
|
local y_values = {}
|
||||||
|
local length = table.length(self.Points)
|
||||||
|
|
||||||
|
for _, point in pairs(self.Points) do
|
||||||
|
table.insert(x_values, point.x)
|
||||||
|
table.insert(y_values, point.y)
|
||||||
|
end
|
||||||
|
|
||||||
|
local x = sum(x_values) / length
|
||||||
|
local y = sum(y_values) / length
|
||||||
|
|
||||||
|
return {
|
||||||
|
["x"] = x,
|
||||||
|
["y"] = y
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the coordinates of the polygon. Each coordinate is a COORDINATE object.
|
||||||
|
-- @return #table The coordinates of the polygon
|
||||||
|
function POLYGON:GetCoordinates()
|
||||||
|
return self.Coords
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the start coordinate of the polygon. The start coordinate is the first point of the polygon.
|
||||||
|
-- @return #COORDINATE The start coordinate of the polygon
|
||||||
|
function POLYGON:GetStartCoordinate()
|
||||||
|
return self.Coords[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the end coordinate of the polygon. The end coordinate is the last point of the polygon.
|
||||||
|
-- @return #COORDINATE The end coordinate of the polygon
|
||||||
|
function POLYGON:GetEndCoordinate()
|
||||||
|
return self.Coords[#self.Coords]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the start point of the polygon. The start point is the first point of the polygon.
|
||||||
|
-- @return #table The start point of the polygon
|
||||||
|
function POLYGON:GetStartPoint()
|
||||||
|
return self.Points[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the end point of the polygon. The end point is the last point of the polygon.
|
||||||
|
-- @return #table The end point of the polygon
|
||||||
|
function POLYGON:GetEndPoint()
|
||||||
|
return self.Points[#self.Points]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the points of the polygon. Each point is a table with 'x' and 'y' fields.
|
||||||
|
-- @return #table The points of the polygon
|
||||||
|
function POLYGON:GetPoints()
|
||||||
|
return self.Points
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculates the surface area of the polygon. The surface area is the sum of the areas of the triangles that make up the polygon.
|
||||||
|
-- @return #number The surface area of the polygon
|
||||||
|
function POLYGON:GetSurfaceArea()
|
||||||
|
return self.SurfaceArea
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculates the bounding box of the polygon. The bounding box is the smallest rectangle that contains the polygon.
|
||||||
|
-- @return #table The bounding box of the polygon
|
||||||
|
function POLYGON:GetBoundingBox()
|
||||||
|
local min_x, min_y, max_x, max_y = self.Points[1].x, self.Points[1].y, self.Points[1].x, self.Points[1].y
|
||||||
|
|
||||||
|
for i = 2, #self.Points do
|
||||||
|
local x, y = self.Points[i].x, self.Points[i].y
|
||||||
|
|
||||||
|
if x < min_x then
|
||||||
|
min_x = x
|
||||||
|
end
|
||||||
|
if y < min_y then
|
||||||
|
min_y = y
|
||||||
|
end
|
||||||
|
if x > max_x then
|
||||||
|
max_x = x
|
||||||
|
end
|
||||||
|
if y > max_y then
|
||||||
|
max_y = y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
{x=min_x, y=min_x}, {x=max_x, y=min_y}, {x=max_x, y=max_y}, {x=min_x, y=max_y}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Triangulates the polygon. The polygon is divided into triangles.
|
||||||
|
-- @param #table points (optional) Points of the polygon or other points if you're just using the POLYGON class without an object of it
|
||||||
|
-- @return #table The triangles of the polygon
|
||||||
|
function POLYGON:Triangulate(points)
|
||||||
|
points = points or self.Points
|
||||||
|
local triangles = {}
|
||||||
|
|
||||||
|
local function get_orientation(shape_points)
|
||||||
|
local sum = 0
|
||||||
|
for i = 1, #shape_points do
|
||||||
|
local j = i % #shape_points + 1
|
||||||
|
sum = sum + (shape_points[j].x - shape_points[i].x) * (shape_points[j].y + shape_points[i].y)
|
||||||
|
end
|
||||||
|
return sum >= 0 and "clockwise" or "counter-clockwise" -- sum >= 0, return "clockwise", else return "counter-clockwise"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ensure_clockwise(shape_points)
|
||||||
|
local orientation = get_orientation(shape_points)
|
||||||
|
if orientation == "counter-clockwise" then
|
||||||
|
-- Reverse the order of shape_points so they're clockwise
|
||||||
|
local reversed = {}
|
||||||
|
for i = #shape_points, 1, -1 do
|
||||||
|
table.insert(reversed, shape_points[i])
|
||||||
|
end
|
||||||
|
return reversed
|
||||||
|
end
|
||||||
|
return shape_points
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_clockwise(p1, p2, p3)
|
||||||
|
local cross_product = (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x)
|
||||||
|
return cross_product < 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local function divide_recursively(shape_points)
|
||||||
|
if #shape_points == 3 then
|
||||||
|
table.insert(triangles, TRIANGLE:New(shape_points[1], shape_points[2], shape_points[3]))
|
||||||
|
elseif #shape_points > 3 then -- find an ear -> a triangle with no other points inside it
|
||||||
|
for i, p1 in ipairs(shape_points) do
|
||||||
|
local p2 = shape_points[(i % #shape_points) + 1]
|
||||||
|
local p3 = shape_points[(i + 1) % #shape_points + 1]
|
||||||
|
local triangle = TRIANGLE:New(p1, p2, p3)
|
||||||
|
local is_ear = true
|
||||||
|
|
||||||
|
if not is_clockwise(p1, p2, p3) then
|
||||||
|
is_ear = false
|
||||||
|
else
|
||||||
|
for _, point in ipairs(shape_points) do
|
||||||
|
if point ~= p1 and point ~= p2 and point ~= p3 and triangle:ContainsPoint(point) then
|
||||||
|
is_ear = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_ear then
|
||||||
|
-- Check if any point in the original polygon is inside the ear triangle
|
||||||
|
local is_valid_triangle = true
|
||||||
|
for _, point in ipairs(points) do
|
||||||
|
if point ~= p1 and point ~= p2 and point ~= p3 and triangle:ContainsPoint(point) then
|
||||||
|
is_valid_triangle = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if is_valid_triangle then
|
||||||
|
table.insert(triangles, triangle)
|
||||||
|
local remaining_points = {}
|
||||||
|
for j, point in ipairs(shape_points) do
|
||||||
|
if point ~= p2 then
|
||||||
|
table.insert(remaining_points, point)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
divide_recursively(remaining_points)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
points = ensure_clockwise(points)
|
||||||
|
divide_recursively(points)
|
||||||
|
return triangles
|
||||||
|
end
|
||||||
|
|
||||||
|
function POLYGON:CovarianceMatrix()
|
||||||
|
local cx, cy = self:GetCentroid()
|
||||||
|
local covXX, covYY, covXY = 0, 0, 0
|
||||||
|
for _, p in ipairs(self.points) do
|
||||||
|
covXX = covXX + (p.x - cx)^2
|
||||||
|
covYY = covYY + (p.y - cy)^2
|
||||||
|
covXY = covXY + (p.x - cx) * (p.y - cy)
|
||||||
|
end
|
||||||
|
covXX = covXX / (#self.points - 1)
|
||||||
|
covYY = covYY / (#self.points - 1)
|
||||||
|
covXY = covXY / (#self.points - 1)
|
||||||
|
return covXX, covYY, covXY
|
||||||
|
end
|
||||||
|
|
||||||
|
function POLYGON:Direction()
|
||||||
|
local covXX, covYY, covXY = self:CovarianceMatrix()
|
||||||
|
-- Simplified calculation for the largest eigenvector's direction
|
||||||
|
local theta = 0.5 * math.atan2(2 * covXY, covXX - covYY)
|
||||||
|
return math.cos(theta), math.sin(theta)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a random Vec2 within the polygon. The Vec2 is weighted by the areas of the triangles that make up the polygon.
|
||||||
|
-- @return #table The random Vec2
|
||||||
|
function POLYGON:GetRandomVec2()
|
||||||
|
local weights = {}
|
||||||
|
for _, triangle in pairs(self.Triangles) do
|
||||||
|
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
||||||
|
end
|
||||||
|
|
||||||
|
local random_weight = math.random()
|
||||||
|
local accumulated_weight = 0
|
||||||
|
for triangle, weight in pairs(weights) do
|
||||||
|
accumulated_weight = accumulated_weight + weight
|
||||||
|
if accumulated_weight >= random_weight then
|
||||||
|
return triangle:GetRandomVec2()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a random non-weighted Vec2 within the polygon. The Vec2 is chosen from one of the triangles that make up the polygon.
|
||||||
|
-- @return #table The random non-weighted Vec2
|
||||||
|
function POLYGON:GetRandomNonWeightedVec2()
|
||||||
|
return self.Triangles[math.random(1, #self.Triangles)]:GetRandomVec2()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if a point is contained within the polygon. The point is a table with 'x' and 'y' fields.
|
||||||
|
-- @param #table point The point to check
|
||||||
|
-- @param #table points (optional) Points of the polygon or other points if you're just using the POLYGON class without an object of it
|
||||||
|
-- @return #bool True if the point is contained, false otherwise
|
||||||
|
function POLYGON:ContainsPoint(point, polygon_points)
|
||||||
|
local x = point.x
|
||||||
|
local y = point.y
|
||||||
|
|
||||||
|
polygon_points = polygon_points or self.Points
|
||||||
|
|
||||||
|
local counter = 0
|
||||||
|
local num_points = #polygon_points
|
||||||
|
for current_index = 1, num_points do
|
||||||
|
local next_index = (current_index % num_points) + 1
|
||||||
|
local current_x, current_y = polygon_points[current_index].x, polygon_points[current_index].y
|
||||||
|
local next_x, next_y = polygon_points[next_index].x, polygon_points[next_index].y
|
||||||
|
if ((current_y > y) ~= (next_y > y)) and (x < (next_x - current_x) * (y - current_y) / (next_y - current_y) + current_x) then
|
||||||
|
counter = counter + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return counter % 2 == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Draws the polygon on the map. The polygon can be drawn with or without inner triangles. This is just for debugging
|
||||||
|
-- @param #bool include_inner_triangles Whether to include inner triangles in the drawing
|
||||||
|
function POLYGON:Draw(include_inner_triangles)
|
||||||
|
include_inner_triangles = include_inner_triangles or false
|
||||||
|
for i=1, #self.Coords do
|
||||||
|
local c1 = self.Coords[i]
|
||||||
|
local c2 = self.Coords[i % #self.Coords + 1]
|
||||||
|
table.add(self.OutlineMarkIDs, c1:LineToAll(c2))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if include_inner_triangles then
|
||||||
|
for _, triangle in ipairs(self.Triangles) do
|
||||||
|
triangle:Draw()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Removes the drawing of the polygon from the map.
|
||||||
|
function POLYGON:RemoveDraw()
|
||||||
|
for _, triangle in pairs(self.Triangles) do
|
||||||
|
triangle:RemoveDraw()
|
||||||
|
end
|
||||||
|
for _, mark_id in pairs(self.OutlineMarkIDs) do
|
||||||
|
UTILS.RemoveMark(mark_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculates the surface area of the polygon. The surface area is the sum of the areas of the triangles that make up the polygon.
|
||||||
|
-- @return #number The surface area of the polygon
|
||||||
|
function POLYGON:__CalculateSurfaceArea()
|
||||||
|
local area = 0
|
||||||
|
for _, triangle in pairs(self.Triangles) do
|
||||||
|
area = area + triangle.SurfaceArea
|
||||||
|
end
|
||||||
|
return area
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
214
Moose Development/Moose/Shapes/ShapeBase.lua
Normal file
214
Moose Development/Moose/Shapes/ShapeBase.lua
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
--- **Shapes** - Class that serves as the base shapes drawn in the Mission Editor
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ### Author: **nielsvaes/coconutcockpit**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Shapes.SHAPE_BASE
|
||||||
|
-- @image CORE_Pathline.png
|
||||||
|
|
||||||
|
|
||||||
|
--- SHAPE_BASE class.
|
||||||
|
-- @type SHAPE_BASE
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #string Name Name of the shape
|
||||||
|
-- @field #table CenterVec2 Vec2 of the center of the shape, this will be assigned automatically
|
||||||
|
-- @field #table Points List of 3D points defining the shape, this will be assigned automatically
|
||||||
|
-- @field #table Coords List of COORDINATE defining the path, this will be assigned automatically
|
||||||
|
-- @field #table MarkIDs List any MARKIDs this class use, this will be assigned automatically
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *I'm in love with the shape of you -- Ed Sheeran
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # SHAPE_BASE
|
||||||
|
-- The class serves as the base class to deal with these shapes using MOOSE. You should never use this class on its own,
|
||||||
|
-- rather use:
|
||||||
|
-- CIRCLE
|
||||||
|
-- LINE
|
||||||
|
-- OVAL
|
||||||
|
-- POLYGON
|
||||||
|
-- TRIANGLE (although this one's a bit special as well)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- The idea is that anything you draw on the map in the Mission Editor can be turned in a shape to work with in MOOSE.
|
||||||
|
-- This is the base class that all other shape classes are built on. There are some shared functions, most of which are overridden in the derived classes
|
||||||
|
--
|
||||||
|
-- @field #SHAPE_BASE
|
||||||
|
SHAPE_BASE = {
|
||||||
|
ClassName = "SHAPE_BASE",
|
||||||
|
Name = "",
|
||||||
|
CenterVec2 = nil,
|
||||||
|
Points = {},
|
||||||
|
Coords = {},
|
||||||
|
MarkIDs = {},
|
||||||
|
ColorString = "",
|
||||||
|
ColorRGBA = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new instance of SHAPE_BASE.
|
||||||
|
-- @return #SHAPE_BASE The new instance
|
||||||
|
function SHAPE_BASE:New()
|
||||||
|
local self = BASE:Inherit(self, BASE:New())
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Finds a shape on the map by its name.
|
||||||
|
-- @param #string shape_name Name of the shape to find
|
||||||
|
-- @return #SHAPE_BASE The found shape
|
||||||
|
function SHAPE_BASE:FindOnMap(shape_name)
|
||||||
|
local self = BASE:Inherit(self, BASE:New())
|
||||||
|
|
||||||
|
local found = false
|
||||||
|
|
||||||
|
for _, layer in pairs(env.mission.drawings.layers) do
|
||||||
|
for _, object in pairs(layer["objects"]) do
|
||||||
|
if object["name"] == shape_name then
|
||||||
|
self.Name = object["name"]
|
||||||
|
self.CenterVec2 = { x = object["mapX"], y = object["mapY"] }
|
||||||
|
self.ColorString = object["colorString"]
|
||||||
|
self.ColorRGBA = UTILS.HexToRGBA(self.ColorString)
|
||||||
|
found = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not found then
|
||||||
|
self:E("Can't find a shape with name " .. shape_name)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function SHAPE_BASE:GetAllShapes(filter)
|
||||||
|
filter = filter or ""
|
||||||
|
local return_shapes = {}
|
||||||
|
for _, layer in pairs(env.mission.drawings.layers) do
|
||||||
|
for _, object in pairs(layer["objects"]) do
|
||||||
|
if string.contains(object["name"], filter) then
|
||||||
|
table.add(return_shapes, object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return return_shapes
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Offsets the shape to a new position.
|
||||||
|
-- @param #table new_vec2 The new position
|
||||||
|
function SHAPE_BASE:Offset(new_vec2)
|
||||||
|
local offset_vec2 = UTILS.Vec2Subtract(new_vec2, self.CenterVec2)
|
||||||
|
self.CenterVec2 = new_vec2
|
||||||
|
if self.ClassName == "POLYGON" then
|
||||||
|
for _, point in pairs(self.Points) do
|
||||||
|
point.x = point.x + offset_vec2.x
|
||||||
|
point.y = point.y + offset_vec2.y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the name of the shape.
|
||||||
|
-- @return #string The name of the shape
|
||||||
|
function SHAPE_BASE:GetName()
|
||||||
|
return self.Name
|
||||||
|
end
|
||||||
|
|
||||||
|
function SHAPE_BASE:GetColorString()
|
||||||
|
return self.ColorString
|
||||||
|
end
|
||||||
|
|
||||||
|
function SHAPE_BASE:GetColorRGBA()
|
||||||
|
return self.ColorRGBA
|
||||||
|
end
|
||||||
|
|
||||||
|
function SHAPE_BASE:GetColorRed()
|
||||||
|
return self.ColorRGBA.R
|
||||||
|
end
|
||||||
|
|
||||||
|
function SHAPE_BASE:GetColorGreen()
|
||||||
|
return self.ColorRGBA.G
|
||||||
|
end
|
||||||
|
|
||||||
|
function SHAPE_BASE:GetColorBlue()
|
||||||
|
return self.ColorRGBA.B
|
||||||
|
end
|
||||||
|
|
||||||
|
function SHAPE_BASE:GetColorAlpha()
|
||||||
|
return self.ColorRGBA.A
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the center position of the shape.
|
||||||
|
-- @return #table The center position
|
||||||
|
function SHAPE_BASE:GetCenterVec2()
|
||||||
|
return self.CenterVec2
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the center coordinate of the shape.
|
||||||
|
-- @return #COORDINATE The center coordinate
|
||||||
|
function SHAPE_BASE:GetCenterCoordinate()
|
||||||
|
return COORDINATE:NewFromVec2(self.CenterVec2)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the coordinate of the shape.
|
||||||
|
-- @return #COORDINATE The coordinate
|
||||||
|
function SHAPE_BASE:GetCoordinate()
|
||||||
|
return self:GetCenterCoordinate()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if a point is contained within the shape.
|
||||||
|
-- @param #table _ The point to check
|
||||||
|
-- @return #bool True if the point is contained, false otherwise
|
||||||
|
function SHAPE_BASE:ContainsPoint(_)
|
||||||
|
self:E("This needs to be set in the derived class")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if a unit is contained within the shape.
|
||||||
|
-- @param #string unit_name The name of the unit to check
|
||||||
|
-- @return #bool True if the unit is contained, false otherwise
|
||||||
|
function SHAPE_BASE:ContainsUnit(unit_name)
|
||||||
|
local unit = UNIT:FindByName(unit_name)
|
||||||
|
|
||||||
|
if unit == nil or not unit:IsAlive() then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if self:ContainsPoint(unit:GetVec2()) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if any unit of a group is contained within the shape.
|
||||||
|
-- @param #string group_name The name of the group to check
|
||||||
|
-- @return #bool True if any unit of the group is contained, false otherwise
|
||||||
|
function SHAPE_BASE:ContainsAnyOfGroup(group_name)
|
||||||
|
local group = GROUP:FindByName(group_name)
|
||||||
|
|
||||||
|
if group == nil or not group:IsAlive() then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, unit in pairs(group:GetUnits()) do
|
||||||
|
if self:ContainsPoint(unit:GetVec2()) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if all units of a group are contained within the shape.
|
||||||
|
-- @param #string group_name The name of the group to check
|
||||||
|
-- @return #bool True if all units of the group are contained, false otherwise
|
||||||
|
function SHAPE_BASE:ContainsAllOfGroup(group_name)
|
||||||
|
local group = GROUP:FindByName(group_name)
|
||||||
|
|
||||||
|
if group == nil or not group:IsAlive() then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, unit in pairs(group:GetUnits()) do
|
||||||
|
if not self:ContainsPoint(unit:GetVec2()) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
101
Moose Development/Moose/Shapes/Triangle.lua
Normal file
101
Moose Development/Moose/Shapes/Triangle.lua
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
--- TRIANGLE class with properties and methods for handling triangles. This class is mostly used by the POLYGON class, but you can use it on its own as well
|
||||||
|
--
|
||||||
|
-- ### Author: **nielsvaes/coconutcockpit**
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Shapes.TRIANGLE
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
--- LINE class.
|
||||||
|
-- @type CUBE
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #number Points points of the line
|
||||||
|
-- @field #number Coords coordinates of the line
|
||||||
|
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @field #TRIANGLE
|
||||||
|
TRIANGLE = {
|
||||||
|
ClassName = "TRIANGLE",
|
||||||
|
Points = {},
|
||||||
|
Coords = {},
|
||||||
|
SurfaceArea = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new triangle from three points. The points need to be given as Vec2s
|
||||||
|
-- @param #table p1 The first point of the triangle
|
||||||
|
-- @param #table p2 The second point of the triangle
|
||||||
|
-- @param #table p3 The third point of the triangle
|
||||||
|
-- @return #TRIANGLE The new triangle
|
||||||
|
function TRIANGLE:New(p1, p2, p3)
|
||||||
|
local self = BASE:Inherit(self, SHAPE_BASE:New())
|
||||||
|
self.Points = {p1, p2, p3}
|
||||||
|
|
||||||
|
local center_x = (p1.x + p2.x + p3.x) / 3
|
||||||
|
local center_y = (p1.y + p2.y + p3.y) / 3
|
||||||
|
self.CenterVec2 = {x=center_x, y=center_y}
|
||||||
|
|
||||||
|
for _, pt in pairs({p1, p2, p3}) do
|
||||||
|
table.add(self.Coords, COORDINATE:NewFromVec2(pt))
|
||||||
|
end
|
||||||
|
|
||||||
|
self.SurfaceArea = math.abs((p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y)) * 0.5
|
||||||
|
|
||||||
|
self.MarkIDs = {}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks if a point is contained within the triangle.
|
||||||
|
-- @param #table pt The point to check
|
||||||
|
-- @param #table points (optional) The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it
|
||||||
|
-- @return #bool True if the point is contained, false otherwise
|
||||||
|
function TRIANGLE:ContainsPoint(pt, points)
|
||||||
|
points = points or self.Points
|
||||||
|
|
||||||
|
local function sign(p1, p2, p3)
|
||||||
|
return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y)
|
||||||
|
end
|
||||||
|
|
||||||
|
local d1 = sign(pt, self.Points[1], self.Points[2])
|
||||||
|
local d2 = sign(pt, self.Points[2], self.Points[3])
|
||||||
|
local d3 = sign(pt, self.Points[3], self.Points[1])
|
||||||
|
|
||||||
|
local has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0)
|
||||||
|
local has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0)
|
||||||
|
|
||||||
|
return not (has_neg and has_pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a random Vec2 within the triangle.
|
||||||
|
-- @param #table points The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it
|
||||||
|
-- @return #table The random Vec2
|
||||||
|
function TRIANGLE:GetRandomVec2(points)
|
||||||
|
points = points or self.Points
|
||||||
|
local pt = {math.random(), math.random()}
|
||||||
|
table.sort(pt)
|
||||||
|
local s = pt[1]
|
||||||
|
local t = pt[2] - pt[1]
|
||||||
|
local u = 1 - pt[2]
|
||||||
|
|
||||||
|
return {x = s * points[1].x + t * points[2].x + u * points[3].x,
|
||||||
|
y = s * points[1].y + t * points[2].y + u * points[3].y}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Draws the triangle on the map, just for debugging
|
||||||
|
function TRIANGLE:Draw()
|
||||||
|
for i=1, #self.Coords do
|
||||||
|
local c1 = self.Coords[i]
|
||||||
|
local c2 = self.Coords[i % #self.Coords + 1]
|
||||||
|
table.add(self.MarkIDs, c1:LineToAll(c2))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Removes the drawing of the triangle from the map.
|
||||||
|
function TRIANGLE:RemoveDraw()
|
||||||
|
for _, mark_id in pairs(self.MarkIDs) do
|
||||||
|
UTILS.RemoveMark(mark_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -30,6 +30,10 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Sound/Radio)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- ### Authors: Hugues "Grey_Echo" Bousquet, funkyfranky
|
-- ### Authors: Hugues "Grey_Echo" Bousquet, funkyfranky
|
||||||
--
|
--
|
||||||
-- @module Sound.Radio
|
-- @module Sound.Radio
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ## Example Missions: [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Sound/MSRS).
|
-- ## Example Missions: [GitHub](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Sound/MSRS).
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -824,7 +824,7 @@ function MSRS:SetVoiceProvider(Voice, Provider)
|
|||||||
self:F( {Voice=Voice, Provider=Provider} )
|
self:F( {Voice=Voice, Provider=Provider} )
|
||||||
self.poptions=self.poptions or {}
|
self.poptions=self.poptions or {}
|
||||||
|
|
||||||
self.poptions[Provider or self:GetProvider()]=Voice
|
self.poptions[Provider or self:GetProvider()].voice=Voice
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -175,19 +175,19 @@ do -- TASK_A2G
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
-- @param Core.Set#SET_UNIT TargetSetUnit The set of targets.
|
-- @param Core.Set#SET_UNIT TargetSetUnit The set of targets.
|
||||||
function TASK_A2G:SetTargetSetUnit( TargetSetUnit )
|
function TASK_A2G:SetTargetSetUnit( TargetSetUnit )
|
||||||
|
|
||||||
self.TargetSetUnit = TargetSetUnit
|
self.TargetSetUnit = TargetSetUnit
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
function TASK_A2G:GetPlannedMenuText()
|
function TASK_A2G:GetPlannedMenuText()
|
||||||
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )"
|
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )"
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
-- @param Core.Point#COORDINATE RendezVousCoordinate The Coordinate object referencing to the 2D point where the RendezVous point is located on the map.
|
-- @param Core.Point#COORDINATE RendezVousCoordinate The Coordinate object referencing to the 2D point where the RendezVous point is located on the map.
|
||||||
-- @param #number RendezVousRange The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point.
|
-- @param #number RendezVousRange The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point.
|
||||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
@@ -200,7 +200,7 @@ do -- TASK_A2G
|
|||||||
ActRouteRendezVous:SetRange( RendezVousRange )
|
ActRouteRendezVous:SetRange( RendezVousRange )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
-- @return Core.Point#COORDINATE The Coordinate object referencing to the 2D point where the RendezVous point is located on the map.
|
-- @return Core.Point#COORDINATE The Coordinate object referencing to the 2D point where the RendezVous point is located on the map.
|
||||||
-- @return #number The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point.
|
-- @return #number The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point.
|
||||||
@@ -212,7 +212,7 @@ do -- TASK_A2G
|
|||||||
return ActRouteRendezVous:GetCoordinate(), ActRouteRendezVous:GetRange()
|
return ActRouteRendezVous:GetCoordinate(), ActRouteRendezVous:GetRange()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
-- @param Core.Zone#ZONE_BASE RendezVousZone The Zone object where the RendezVous is located on the map.
|
-- @param Core.Zone#ZONE_BASE RendezVousZone The Zone object where the RendezVous is located on the map.
|
||||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
function TASK_A2G:SetRendezVousZone( RendezVousZone, TaskUnit )
|
function TASK_A2G:SetRendezVousZone( RendezVousZone, TaskUnit )
|
||||||
@@ -223,7 +223,7 @@ do -- TASK_A2G
|
|||||||
ActRouteRendezVous:SetZone( RendezVousZone )
|
ActRouteRendezVous:SetZone( RendezVousZone )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
-- @return Core.Zone#ZONE_BASE The Zone object where the RendezVous is located on the map.
|
-- @return Core.Zone#ZONE_BASE The Zone object where the RendezVous is located on the map.
|
||||||
function TASK_A2G:GetRendezVousZone( TaskUnit )
|
function TASK_A2G:GetRendezVousZone( TaskUnit )
|
||||||
@@ -234,7 +234,7 @@ do -- TASK_A2G
|
|||||||
return ActRouteRendezVous:GetZone()
|
return ActRouteRendezVous:GetZone()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
-- @param Core.Point#COORDINATE TargetCoordinate The Coordinate object where the Target is located on the map.
|
-- @param Core.Point#COORDINATE TargetCoordinate The Coordinate object where the Target is located on the map.
|
||||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
function TASK_A2G:SetTargetCoordinate( TargetCoordinate, TaskUnit )
|
function TASK_A2G:SetTargetCoordinate( TargetCoordinate, TaskUnit )
|
||||||
@@ -245,7 +245,7 @@ do -- TASK_A2G
|
|||||||
ActRouteTarget:SetCoordinate( TargetCoordinate )
|
ActRouteTarget:SetCoordinate( TargetCoordinate )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
-- @return Core.Point#COORDINATE The Coordinate object where the Target is located on the map.
|
-- @return Core.Point#COORDINATE The Coordinate object where the Target is located on the map.
|
||||||
function TASK_A2G:GetTargetCoordinate( TaskUnit )
|
function TASK_A2G:GetTargetCoordinate( TaskUnit )
|
||||||
@@ -256,7 +256,7 @@ do -- TASK_A2G
|
|||||||
return ActRouteTarget:GetCoordinate()
|
return ActRouteTarget:GetCoordinate()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
-- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map.
|
-- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map.
|
||||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
function TASK_A2G:SetTargetZone( TargetZone, TaskUnit )
|
function TASK_A2G:SetTargetZone( TargetZone, TaskUnit )
|
||||||
@@ -267,7 +267,7 @@ do -- TASK_A2G
|
|||||||
ActRouteTarget:SetZone( TargetZone )
|
ActRouteTarget:SetZone( TargetZone )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
-- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map.
|
-- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map.
|
||||||
function TASK_A2G:GetTargetZone( TaskUnit )
|
function TASK_A2G:GetTargetZone( TaskUnit )
|
||||||
@@ -280,7 +280,7 @@ do -- TASK_A2G
|
|||||||
|
|
||||||
function TASK_A2G:SetGoalTotal()
|
function TASK_A2G:SetGoalTotal()
|
||||||
|
|
||||||
self.GoalTotal = self.TargetSetUnit:Count()
|
self.GoalTotal = self.TargetSetUnit:CountAlive()
|
||||||
end
|
end
|
||||||
|
|
||||||
function TASK_A2G:GetGoalTotal()
|
function TASK_A2G:GetGoalTotal()
|
||||||
@@ -304,14 +304,14 @@ do -- TASK_A2G
|
|||||||
function TASK_A2G:onafterGoal( TaskUnit, From, Event, To )
|
function TASK_A2G:onafterGoal( TaskUnit, From, Event, To )
|
||||||
local TargetSetUnit = self.TargetSetUnit -- Core.Set#SET_UNIT
|
local TargetSetUnit = self.TargetSetUnit -- Core.Set#SET_UNIT
|
||||||
|
|
||||||
if TargetSetUnit:Count() == 0 then
|
if TargetSetUnit:CountAlive() == 0 then
|
||||||
self:Success()
|
self:Success()
|
||||||
end
|
end
|
||||||
|
|
||||||
self:__Goal( -10 )
|
self:__Goal( -10 )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #TASK_A2G self
|
-- @param #TASK_A2G self
|
||||||
function TASK_A2G:UpdateTaskInfo( DetectedItem )
|
function TASK_A2G:UpdateTaskInfo( DetectedItem )
|
||||||
|
|
||||||
if self:IsStatePlanned() or self:IsStateAssigned() then
|
if self:IsStatePlanned() or self:IsStateAssigned() then
|
||||||
@@ -328,7 +328,7 @@ do -- TASK_A2G
|
|||||||
self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 10, "MOD", true )
|
self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 10, "MOD", true )
|
||||||
|
|
||||||
if self.Detection then
|
if self.Detection then
|
||||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
local DetectedItemsCount = self.TargetSetUnit:CountAlive()
|
||||||
local ReportTypes = REPORT:New()
|
local ReportTypes = REPORT:New()
|
||||||
local TargetTypes = {}
|
local TargetTypes = {}
|
||||||
for TargetUnitName, TargetUnit in pairs( self.TargetSetUnit:GetSet() ) do
|
for TargetUnitName, TargetUnit in pairs( self.TargetSetUnit:GetSet() ) do
|
||||||
@@ -341,7 +341,7 @@ do -- TASK_A2G
|
|||||||
self.TaskInfo:AddTargetCount( DetectedItemsCount, 11, "O", true )
|
self.TaskInfo:AddTargetCount( DetectedItemsCount, 11, "O", true )
|
||||||
self.TaskInfo:AddTargets( DetectedItemsCount, ReportTypes:Text( ", " ), 20, "D", true )
|
self.TaskInfo:AddTargets( DetectedItemsCount, ReportTypes:Text( ", " ), 20, "D", true )
|
||||||
else
|
else
|
||||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
local DetectedItemsCount = self.TargetSetUnit:CountAlive()
|
||||||
local DetectedItemsTypes = self.TargetSetUnit:GetTypeNames()
|
local DetectedItemsTypes = self.TargetSetUnit:GetTypeNames()
|
||||||
self.TaskInfo:AddTargetCount( DetectedItemsCount, 11, "O", true )
|
self.TaskInfo:AddTargetCount( DetectedItemsCount, 11, "O", true )
|
||||||
self.TaskInfo:AddTargets( DetectedItemsCount, DetectedItemsTypes, 20, "D", true )
|
self.TaskInfo:AddTargets( DetectedItemsCount, DetectedItemsTypes, 20, "D", true )
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ BIGSMOKEPRESET = {
|
|||||||
-- @field #string MarianaIslands Mariana Islands map.
|
-- @field #string MarianaIslands Mariana Islands map.
|
||||||
-- @field #string Falklands South Atlantic map.
|
-- @field #string Falklands South Atlantic map.
|
||||||
-- @field #string Sinai Sinai map.
|
-- @field #string Sinai Sinai map.
|
||||||
|
-- @field #string Kola Kola map.
|
||||||
DCSMAP = {
|
DCSMAP = {
|
||||||
Caucasus="Caucasus",
|
Caucasus="Caucasus",
|
||||||
NTTR="Nevada",
|
NTTR="Nevada",
|
||||||
@@ -64,7 +65,8 @@ DCSMAP = {
|
|||||||
Syria="Syria",
|
Syria="Syria",
|
||||||
MarianaIslands="MarianaIslands",
|
MarianaIslands="MarianaIslands",
|
||||||
Falklands="Falklands",
|
Falklands="Falklands",
|
||||||
Sinai="SinaiMap"
|
Sinai="SinaiMap",
|
||||||
|
Kola="Kola"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -444,10 +446,11 @@ end
|
|||||||
--- Print a table to log in a nice format
|
--- Print a table to log in a nice format
|
||||||
-- @param #table table The table to print
|
-- @param #table table The table to print
|
||||||
-- @param #number indent Number of indents
|
-- @param #number indent Number of indents
|
||||||
|
-- @param #boolean noprint Don't log but return text
|
||||||
-- @return #string text Text created on the fly of the log output
|
-- @return #string text Text created on the fly of the log output
|
||||||
function UTILS.PrintTableToLog(table, indent)
|
function UTILS.PrintTableToLog(table, indent, noprint)
|
||||||
local text = "\n"
|
local text = "\n"
|
||||||
if not table then
|
if not table or type(table) ~= "table" then
|
||||||
env.warning("No table passed!")
|
env.warning("No table passed!")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -455,11 +458,16 @@ function UTILS.PrintTableToLog(table, indent)
|
|||||||
for k, v in pairs(table) do
|
for k, v in pairs(table) do
|
||||||
if string.find(k," ") then k='"'..k..'"'end
|
if string.find(k," ") then k='"'..k..'"'end
|
||||||
if type(v) == "table" then
|
if type(v) == "table" then
|
||||||
env.info(string.rep(" ", indent) .. tostring(k) .. " = {")
|
if not noprint then
|
||||||
|
env.info(string.rep(" ", indent) .. tostring(k) .. " = {")
|
||||||
|
end
|
||||||
text = text ..string.rep(" ", indent) .. tostring(k) .. " = {\n"
|
text = text ..string.rep(" ", indent) .. tostring(k) .. " = {\n"
|
||||||
text = text .. tostring(UTILS.PrintTableToLog(v, indent + 1)).."\n"
|
text = text .. tostring(UTILS.PrintTableToLog(v, indent + 1)).."\n"
|
||||||
env.info(string.rep(" ", indent) .. "},")
|
if not noprint then
|
||||||
|
env.info(string.rep(" ", indent) .. "},")
|
||||||
|
end
|
||||||
text = text .. string.rep(" ", indent) .. "},\n"
|
text = text .. string.rep(" ", indent) .. "},\n"
|
||||||
|
elseif type(v) == "function" then
|
||||||
else
|
else
|
||||||
local value
|
local value
|
||||||
if tostring(v) == "true" or tostring(v) == "false" or tonumber(v) ~= nil then
|
if tostring(v) == "true" or tostring(v) == "false" or tonumber(v) ~= nil then
|
||||||
@@ -467,7 +475,9 @@ function UTILS.PrintTableToLog(table, indent)
|
|||||||
else
|
else
|
||||||
value = '"'..tostring(v)..'"'
|
value = '"'..tostring(v)..'"'
|
||||||
end
|
end
|
||||||
env.info(string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(value)..",\n")
|
if not noprint then
|
||||||
|
env.info(string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(value)..",\n")
|
||||||
|
end
|
||||||
text = text .. string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(value)..",\n"
|
text = text .. string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(value)..",\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1695,6 +1705,7 @@ end
|
|||||||
-- * Mariana Islands +2 (East)
|
-- * Mariana Islands +2 (East)
|
||||||
-- * Falklands +12 (East) - note there's a LOT of deviation across the map, as we're closer to the South Pole
|
-- * Falklands +12 (East) - note there's a LOT of deviation across the map, as we're closer to the South Pole
|
||||||
-- * Sinai +4.8 (East)
|
-- * Sinai +4.8 (East)
|
||||||
|
-- * Kola +15 (East) - not there is a lot of deviation across the map (-1° to +24°), as we are close to the North pole
|
||||||
-- @param #string map (Optional) Map for which the declination is returned. Default is from env.mission.theatre
|
-- @param #string map (Optional) Map for which the declination is returned. Default is from env.mission.theatre
|
||||||
-- @return #number Declination in degrees.
|
-- @return #number Declination in degrees.
|
||||||
function UTILS.GetMagneticDeclination(map)
|
function UTILS.GetMagneticDeclination(map)
|
||||||
@@ -1721,6 +1732,8 @@ function UTILS.GetMagneticDeclination(map)
|
|||||||
declination=12
|
declination=12
|
||||||
elseif map==DCSMAP.Sinai then
|
elseif map==DCSMAP.Sinai then
|
||||||
declination=4.8
|
declination=4.8
|
||||||
|
elseif map==DCSMAP.Kola then
|
||||||
|
declination=15
|
||||||
else
|
else
|
||||||
declination=0
|
declination=0
|
||||||
end
|
end
|
||||||
@@ -1938,6 +1951,8 @@ function UTILS.GMTToLocalTimeDifference()
|
|||||||
return -3 -- Fireland is UTC-3 hours.
|
return -3 -- Fireland is UTC-3 hours.
|
||||||
elseif theatre==DCSMAP.Sinai then
|
elseif theatre==DCSMAP.Sinai then
|
||||||
return 2 -- Currently map is +2 but should be +3 (DCS bug?)
|
return 2 -- Currently map is +2 but should be +3 (DCS bug?)
|
||||||
|
elseif theatre==DCSMAP.Kola then
|
||||||
|
return 3 -- Currently map is +2 but should be +3 (DCS bug?)
|
||||||
else
|
else
|
||||||
BASE:E(string.format("ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring(theatre)))
|
BASE:E(string.format("ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring(theatre)))
|
||||||
return 0
|
return 0
|
||||||
@@ -2229,6 +2244,16 @@ function UTILS.IsLoadingDoorOpen( unit_name )
|
|||||||
return true -- no doors on this one ;)
|
return true -- no doors on this one ;)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if type_name == "MH-60R" and (unit:getDrawArgumentValue(403) > 0 or unit:getDrawArgumentValue(403) == -1) then
|
||||||
|
BASE:T(unit_name .. " cargo door is open")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if type_name == " OH-58D" and (unit:getDrawArgumentValue(35) > 0 or unit:getDrawArgumentValue(421) == -1) then
|
||||||
|
BASE:T(unit_name .. " cargo door is open")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
end -- nil
|
end -- nil
|
||||||
@@ -2459,7 +2484,7 @@ function UTILS.SaveToFile(Path,Filename,Data)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Function to save an object to a file
|
--- Function to load an object from a file.
|
||||||
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
|
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
|
||||||
-- @param #string Filename The name of the file.
|
-- @param #string Filename The name of the file.
|
||||||
-- @return #boolean outcome True if reading is possible and successful, else false.
|
-- @return #boolean outcome True if reading is possible and successful, else false.
|
||||||
@@ -2636,6 +2661,9 @@ function UTILS.SaveSetOfGroups(Set,Path,Filename,Structured)
|
|||||||
if group and group:IsAlive() then
|
if group and group:IsAlive() then
|
||||||
local name = group:GetName()
|
local name = group:GetName()
|
||||||
local template = string.gsub(name,"-(.+)$","")
|
local template = string.gsub(name,"-(.+)$","")
|
||||||
|
if string.find(name,"AID") then
|
||||||
|
template = string.gsub(name,"(.AID.%d+$","")
|
||||||
|
end
|
||||||
if string.find(template,"#") then
|
if string.find(template,"#") then
|
||||||
template = string.gsub(name,"#(%d+)$","")
|
template = string.gsub(name,"#(%d+)$","")
|
||||||
end
|
end
|
||||||
@@ -3500,6 +3528,25 @@ function string.contains(str, value)
|
|||||||
return string.match(str, value)
|
return string.match(str, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Moves an object from one table to another
|
||||||
|
-- @param #obj object to move
|
||||||
|
-- @param #from_table table to move from
|
||||||
|
-- @param #to_table table to move to
|
||||||
|
function table.move_object(obj, from_table, to_table)
|
||||||
|
local index
|
||||||
|
for i, v in pairs(from_table) do
|
||||||
|
if v == obj then
|
||||||
|
index = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if index then
|
||||||
|
local moved = table.remove(from_table, index)
|
||||||
|
table.insert_unique(to_table, moved)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Given tbl is a indexed table ({"hello", "dcs", "world"}), checks if element exists in the table.
|
--- Given tbl is a indexed table ({"hello", "dcs", "world"}), checks if element exists in the table.
|
||||||
--- The table can be made up out of complex tables or values as well
|
--- The table can be made up out of complex tables or values as well
|
||||||
-- @param #table tbl
|
-- @param #table tbl
|
||||||
@@ -3717,3 +3764,178 @@ end
|
|||||||
function UTILS.OctalToDecimal(Number)
|
function UTILS.OctalToDecimal(Number)
|
||||||
return tonumber(Number,8)
|
return tonumber(Number,8)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- HexToRGBA
|
||||||
|
-- @param hex_string table
|
||||||
|
-- @return #table R, G, B, A
|
||||||
|
function UTILS.HexToRGBA(hex_string)
|
||||||
|
local hexNumber = tonumber(string.sub(hex_string, 3), 16) -- convert the string to a number
|
||||||
|
-- extract RGBA components
|
||||||
|
local alpha = hexNumber % 256
|
||||||
|
hexNumber = (hexNumber - alpha) / 256
|
||||||
|
local blue = hexNumber % 256
|
||||||
|
hexNumber = (hexNumber - blue) / 256
|
||||||
|
local green = hexNumber % 256
|
||||||
|
hexNumber = (hexNumber - green) / 256
|
||||||
|
local red = hexNumber % 256
|
||||||
|
|
||||||
|
return {R = red, G = green, B = blue, A = alpha}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Function to save the position of a set of #OPSGROUP (ARMYGROUP) objects.
|
||||||
|
-- @param Core.Set#SET_OPSGROUP Set of ops objects to save
|
||||||
|
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
|
||||||
|
-- @param #string Filename The name of the file.
|
||||||
|
-- @param #boolean Structured Append the data with a list of typenames in the group plus their count.
|
||||||
|
-- @return #boolean outcome True if saving is successful, else false.
|
||||||
|
function UTILS.SaveSetOfOpsGroups(Set,Path,Filename,Structured)
|
||||||
|
local filename = Filename or "SetOfGroups"
|
||||||
|
local data = "--Save SET of groups: (name,legion,template,alttemplate,units,position.x,position.y,position.z,strucdata) "..Filename .."\n"
|
||||||
|
local List = Set:GetSetObjects()
|
||||||
|
for _,_group in pairs (List) do
|
||||||
|
local group = _group:GetGroup() -- Wrapper.Group#GROUP
|
||||||
|
if group and group:IsAlive() then
|
||||||
|
local name = group:GetName()
|
||||||
|
local template = string.gsub(name,"(.AID.%d+$","")
|
||||||
|
if string.find(template,"#") then
|
||||||
|
template = string.gsub(name,"#(%d+)$","")
|
||||||
|
end
|
||||||
|
local alttemplate = _group.templatename or "none"
|
||||||
|
local legiono = _group.legion -- Ops.Legion#LEGION
|
||||||
|
local legion = "none"
|
||||||
|
if legiono and type(legiono) == "table" and legiono.ClassName then
|
||||||
|
legion = legiono:GetName()
|
||||||
|
local asset = legiono:GetAssetByName(name) -- Functional.Warehouse#WAREHOUSE.Assetitem
|
||||||
|
alttemplate=asset.templatename
|
||||||
|
end
|
||||||
|
local units = group:CountAliveUnits()
|
||||||
|
local position = group:GetVec3()
|
||||||
|
if Structured then
|
||||||
|
local structure = UTILS.GetCountPerTypeName(group)
|
||||||
|
local strucdata = ""
|
||||||
|
for typen,anzahl in pairs (structure) do
|
||||||
|
strucdata = strucdata .. typen .. "=="..anzahl..";"
|
||||||
|
end
|
||||||
|
data = string.format("%s%s,%s,%s,%s,%d,%d,%d,%d,%s\n",data,name,legion,template,alttemplate,units,position.x,position.y,position.z,strucdata)
|
||||||
|
else
|
||||||
|
data = string.format("%s%s,%s,%s,%s,%d,%d,%d,%d\n",data,name,legion,template,alttemplate,units,position.x,position.y,position.z)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- save the data
|
||||||
|
local outcome = UTILS.SaveToFile(Path,Filename,data)
|
||||||
|
return outcome
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Load back a #OPSGROUP (ARMYGROUP) data from file for use with @{Ops.Brigade#BRIGADE.LoadBackAssetInPosition}()
|
||||||
|
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
|
||||||
|
-- @param #string Filename The name of the file.
|
||||||
|
-- @return #table Returns a table of data entries: `{ groupname=groupname, size=size, coordinate=coordinate, template=template, structure=structure, legion=legion, alttemplate=alttemplate }`
|
||||||
|
-- Returns nil when the file cannot be read.
|
||||||
|
function UTILS.LoadSetOfOpsGroups(Path,Filename)
|
||||||
|
|
||||||
|
local filename = Filename or "SetOfGroups"
|
||||||
|
local datatable = {}
|
||||||
|
|
||||||
|
if UTILS.CheckFileExists(Path,filename) then
|
||||||
|
local outcome,loadeddata = UTILS.LoadFromFile(Path,Filename)
|
||||||
|
-- remove header
|
||||||
|
table.remove(loadeddata, 1)
|
||||||
|
for _id,_entry in pairs (loadeddata) do
|
||||||
|
local dataset = UTILS.Split(_entry,",")
|
||||||
|
-- 1name,2legion,3template,4alttemplate,5units,6position.x,7position.y,8position.z,9strucdata
|
||||||
|
local groupname = dataset[1]
|
||||||
|
local legion = dataset[2]
|
||||||
|
local template = dataset[3]
|
||||||
|
local alttemplate = dataset[4]
|
||||||
|
local size = tonumber(dataset[5])
|
||||||
|
local posx = tonumber(dataset[6])
|
||||||
|
local posy = tonumber(dataset[7])
|
||||||
|
local posz = tonumber(dataset[8])
|
||||||
|
local structure = dataset[9]
|
||||||
|
local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz})
|
||||||
|
if size > 0 then
|
||||||
|
local data = { groupname=groupname, size=size, coordinate=coordinate, template=template, structure=structure, legion=legion, alttemplate=alttemplate }
|
||||||
|
table.insert(datatable,data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return datatable
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the clock position from a relative heading
|
||||||
|
-- @param #number refHdg The heading of the reference object (such as a Wrapper.UNIT) in 0-360
|
||||||
|
-- @param #number tgtHdg The absolute heading from the reference object to the target object/point in 0-360
|
||||||
|
-- @return #string text Text in clock heading such as "4 O'CLOCK"
|
||||||
|
-- @usage Display the range and clock distance of a BTR in relation to REAPER 1-1's heading:
|
||||||
|
--
|
||||||
|
-- myUnit = UNIT:FindByName( "REAPER 1-1" )
|
||||||
|
-- myTarget = GROUP:FindByName( "BTR-1" )
|
||||||
|
--
|
||||||
|
-- coordUnit = myUnit:GetCoordinate()
|
||||||
|
-- coordTarget = myTarget:GetCoordinate()
|
||||||
|
--
|
||||||
|
-- hdgUnit = myUnit:GetHeading()
|
||||||
|
-- hdgTarget = coordUnit:HeadingTo( coordTarget )
|
||||||
|
-- distTarget = coordUnit:Get3DDistance( coordTarget )
|
||||||
|
--
|
||||||
|
-- clockString = UTILS.ClockHeadingString( hdgUnit, hdgTarget )
|
||||||
|
--
|
||||||
|
-- -- Will show this message to REAPER 1-1 in-game: Contact BTR at 3 o'clock for 1134m!
|
||||||
|
-- MESSAGE:New("Contact BTR at " .. clockString .. " for " .. distTarget .. "m!):ToUnit( myUnit )
|
||||||
|
function UTILS.ClockHeadingString(refHdg,tgtHdg)
|
||||||
|
local relativeAngle = tgtHdg - refHdg
|
||||||
|
if relativeAngle < 0 then
|
||||||
|
relativeAngle = relativeAngle + 360
|
||||||
|
end
|
||||||
|
local clockPos = math.ceil((relativeAngle % 360) / 30)
|
||||||
|
return clockPos.." o'clock"
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a NATO abbreviated MGRS text for SRS use, optionally with prosody slow tag
|
||||||
|
-- @param #string Text The input string, e.g. "MGRS 4Q FJ 12345 67890"
|
||||||
|
-- @param #boolean Slow Optional - add slow tags
|
||||||
|
-- @return #string Output for (Slow) spelling in SRS TTS e.g. "MGRS;<prosody rate="slow">4;Quebec;Foxtrot;Juliett;1;2;3;4;5;6;7;8;niner;zero;</prosody>"
|
||||||
|
function UTILS.MGRSStringToSRSFriendly(Text,Slow)
|
||||||
|
local Text = string.gsub(Text,"MGRS ","")
|
||||||
|
Text = string.gsub(Text,"%s+","")
|
||||||
|
Text = string.gsub(Text,"([%a%d])","%1;") -- "0;5;1;"
|
||||||
|
Text = string.gsub(Text,"A","Alpha")
|
||||||
|
Text = string.gsub(Text,"B","Bravo")
|
||||||
|
Text = string.gsub(Text,"C","Charlie")
|
||||||
|
Text = string.gsub(Text,"D","Delta")
|
||||||
|
Text = string.gsub(Text,"E","Echo")
|
||||||
|
Text = string.gsub(Text,"F","Foxtrot")
|
||||||
|
Text = string.gsub(Text,"G","Golf")
|
||||||
|
Text = string.gsub(Text,"H","Hotel")
|
||||||
|
Text = string.gsub(Text,"I","India")
|
||||||
|
Text = string.gsub(Text,"J","Juliett")
|
||||||
|
Text = string.gsub(Text,"K","Kilo")
|
||||||
|
Text = string.gsub(Text,"L","Lima")
|
||||||
|
Text = string.gsub(Text,"M","Mike")
|
||||||
|
Text = string.gsub(Text,"N","November")
|
||||||
|
Text = string.gsub(Text,"O","Oscar")
|
||||||
|
Text = string.gsub(Text,"P","Papa")
|
||||||
|
Text = string.gsub(Text,"Q","Quebec")
|
||||||
|
Text = string.gsub(Text,"R","Romeo")
|
||||||
|
Text = string.gsub(Text,"S","Sierra")
|
||||||
|
Text = string.gsub(Text,"T","Tango")
|
||||||
|
Text = string.gsub(Text,"U","Uniform")
|
||||||
|
Text = string.gsub(Text,"V","Victor")
|
||||||
|
Text = string.gsub(Text,"W","Whiskey")
|
||||||
|
Text = string.gsub(Text,"X","Xray")
|
||||||
|
Text = string.gsub(Text,"Y","Yankee")
|
||||||
|
Text = string.gsub(Text,"Z","Zulu")
|
||||||
|
Text = string.gsub(Text,"0","zero")
|
||||||
|
Text = string.gsub(Text,"9","niner")
|
||||||
|
if Slow then
|
||||||
|
Text = '<prosody rate="slow">'..Text..'</prosody>'
|
||||||
|
end
|
||||||
|
Text = "MGRS;"..Text
|
||||||
|
return Text
|
||||||
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -99,7 +99,7 @@
|
|||||||
-- This method can also be used to **embed a function call when a certain waypoint has been reached**.
|
-- This method can also be used to **embed a function call when a certain waypoint has been reached**.
|
||||||
-- See below the **Tasks at Waypoints** section.
|
-- See below the **Tasks at Waypoints** section.
|
||||||
--
|
--
|
||||||
-- Demonstration Mission: [GRP-502 - Route at waypoint to random point](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/Wrapper/Group/GRP-502%20-%20Route%20at%20waypoint%20to%20random%20point)
|
-- Demonstration Mission: [GRP-502 - Route at waypoint to random point](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Wrapper/Group/502-Route-at-waypoint-to-random-point)
|
||||||
--
|
--
|
||||||
-- ## 2.5) Tasks at Waypoints
|
-- ## 2.5) Tasks at Waypoints
|
||||||
--
|
--
|
||||||
@@ -2173,7 +2173,7 @@ do -- Patrol methods
|
|||||||
local Waypoint = Waypoints[#Waypoints]
|
local Waypoint = Waypoints[#Waypoints]
|
||||||
PatrolGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
PatrolGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||||
|
|
||||||
PatrolGroup:Route( Waypoints ) -- Move after a random seconds to the Route. See the Route method for details.
|
PatrolGroup:Route( Waypoints, 2 ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3871,6 +3871,10 @@ end
|
|||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #table WayPoints If WayPoints is given, then use the route.
|
-- @param #table WayPoints If WayPoints is given, then use the route.
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
|
-- @usage Intended Workflow is:
|
||||||
|
-- mygroup:WayPointInitialize()
|
||||||
|
-- mygroup:WayPointFunction( WayPoint, WayPointIndex, WayPointFunction, ... )
|
||||||
|
-- mygroup:WayPointExecute()
|
||||||
function CONTROLLABLE:WayPointInitialize( WayPoints )
|
function CONTROLLABLE:WayPointInitialize( WayPoints )
|
||||||
self:F( { WayPoints } )
|
self:F( { WayPoints } )
|
||||||
|
|
||||||
@@ -3902,9 +3906,15 @@ end
|
|||||||
-- @param #number WayPointIndex When defining multiple WayPoint functions for one WayPoint, use WayPointIndex to set the sequence of actions.
|
-- @param #number WayPointIndex When defining multiple WayPoint functions for one WayPoint, use WayPointIndex to set the sequence of actions.
|
||||||
-- @param #function WayPointFunction The waypoint function to be called when the controllable moves over the waypoint. The waypoint function takes variable parameters.
|
-- @param #function WayPointFunction The waypoint function to be called when the controllable moves over the waypoint. The waypoint function takes variable parameters.
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
|
-- @usage Intended Workflow is:
|
||||||
|
-- mygroup:WayPointInitialize()
|
||||||
|
-- mygroup:WayPointFunction( WayPoint, WayPointIndex, WayPointFunction, ... )
|
||||||
|
-- mygroup:WayPointExecute()
|
||||||
function CONTROLLABLE:WayPointFunction( WayPoint, WayPointIndex, WayPointFunction, ... )
|
function CONTROLLABLE:WayPointFunction( WayPoint, WayPointIndex, WayPointFunction, ... )
|
||||||
self:F2( { WayPoint, WayPointIndex, WayPointFunction } )
|
self:F2( { WayPoint, WayPointIndex, WayPointFunction } )
|
||||||
|
if not self.WayPoints then
|
||||||
|
self:WayPointInitialize()
|
||||||
|
end
|
||||||
table.insert( self.WayPoints[WayPoint].task.params.tasks, WayPointIndex )
|
table.insert( self.WayPoints[WayPoint].task.params.tasks, WayPointIndex )
|
||||||
self.WayPoints[WayPoint].task.params.tasks[WayPointIndex] = self:TaskFunction( WayPointFunction, arg )
|
self.WayPoints[WayPoint].task.params.tasks[WayPointIndex] = self:TaskFunction( WayPointFunction, arg )
|
||||||
return self
|
return self
|
||||||
@@ -3917,6 +3927,10 @@ end
|
|||||||
-- @param #number WayPoint The WayPoint from where to execute the mission.
|
-- @param #number WayPoint The WayPoint from where to execute the mission.
|
||||||
-- @param #number WaitTime The amount seconds to wait before initiating the mission.
|
-- @param #number WaitTime The amount seconds to wait before initiating the mission.
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
|
-- @usage Intended Workflow is:
|
||||||
|
-- mygroup:WayPointInitialize()
|
||||||
|
-- mygroup:WayPointFunction( WayPoint, WayPointIndex, WayPointFunction, ... )
|
||||||
|
-- mygroup:WayPointExecute()
|
||||||
function CONTROLLABLE:WayPointExecute( WayPoint, WaitTime )
|
function CONTROLLABLE:WayPointExecute( WayPoint, WaitTime )
|
||||||
self:F( { WayPoint, WaitTime } )
|
self:F( { WayPoint, WaitTime } )
|
||||||
|
|
||||||
@@ -4102,6 +4116,74 @@ function CONTROLLABLE:SetOptionRadarUsingForContinousSearch()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [AIR] Set if the AI is reporting passing of waypoints
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #boolean OnOff If true or nil, AI will report passing waypoints, if false, it will not.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:SetOptionWaypointPassReport(OnOff)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
local onoff = (OnOff == nil or OnOff == true) and false or true
|
||||||
|
if self:IsAir() then
|
||||||
|
self:SetOption(AI.Option.Air.id.PROHIBIT_WP_PASS_REPORT,onoff)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [AIR] Set the AI to not report anything over the radio - radio silence
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #boolean OnOff If true or nil, radio is set to silence, if false radio silence is lifted.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:SetOptionRadioSilence(OnOff)
|
||||||
|
local onoff = (OnOff == true or OnOff == nil) and true or false
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
if self:IsAir() then
|
||||||
|
self:SetOption(AI.Option.Air.id.SILENCE,onoff)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [AIR] Set the AI to report contact for certain types of objects.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #table Objects Table of attribute names for which AI reports contact. Defaults to {"Air"}. See [Hoggit Wiki](https://wiki.hoggitworld.com/view/DCS_enum_attributes)
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:SetOptionRadioContact(Objects)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
if not Objects then Objects = {"Air"} end
|
||||||
|
if type(Objects) ~= "table" then Objects = {Objects} end
|
||||||
|
if self:IsAir() then
|
||||||
|
self:SetOption(AI.Option.Air.id.OPTION_RADIO_USAGE_CONTACT,Objects)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [AIR] Set the AI to report engaging certain types of objects.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #table Objects Table of attribute names for which AI reports contact. Defaults to {"Air"}, see [Hoggit Wiki](https://wiki.hoggitworld.com/view/DCS_enum_attributes)
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:SetOptionRadioEngage(Objects)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
if not Objects then Objects = {"Air"} end
|
||||||
|
if type(Objects) ~= "table" then Objects = {Objects} end
|
||||||
|
if self:IsAir() then
|
||||||
|
self:SetOption(AI.Option.Air.id.OPTION_RADIO_USAGE_ENGAGE,Objects)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [AIR] Set the AI to report killing certain types of objects.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #table Objects Table of attribute names for which AI reports contact. Defaults to {"Air"}, see [Hoggit Wiki](https://wiki.hoggitworld.com/view/DCS_enum_attributes)
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:SetOptionRadioKill(Objects)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
if not Objects then Objects = {"Air"} end
|
||||||
|
if type(Objects) ~= "table" then Objects = {Objects} end
|
||||||
|
if self:IsAir() then
|
||||||
|
self:SetOption(AI.Option.Air.id.OPTION_RADIO_USAGE_KILL,Objects)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- (GROUND) Relocate controllable to a random point within a given radius; use e.g.for evasive actions; Note that not all ground controllables can actually drive, also the alarm state of the controllable might stop it from moving.
|
--- (GROUND) Relocate controllable to a random point within a given radius; use e.g.for evasive actions; Note that not all ground controllables can actually drive, also the alarm state of the controllable might stop it from moving.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number speed Speed of the controllable, default 20
|
-- @param #number speed Speed of the controllable, default 20
|
||||||
|
|||||||
@@ -26,6 +26,10 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Wrapper/Group)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
--
|
--
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
@@ -355,12 +359,15 @@ end
|
|||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @return DCS#Group The DCS Group.
|
-- @return DCS#Group The DCS Group.
|
||||||
function GROUP:GetDCSObject()
|
function GROUP:GetDCSObject()
|
||||||
|
|
||||||
|
-- Get DCS group.
|
||||||
local DCSGroup = Group.getByName( self.GroupName )
|
local DCSGroup = Group.getByName( self.GroupName )
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
return DCSGroup
|
return DCSGroup
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:T2(string.format("ERROR: Could not get DCS group object of group %s because DCS object could not be found!", tostring(self.GroupName)))
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -422,7 +429,7 @@ function GROUP:IsActive()
|
|||||||
|
|
||||||
local DCSGroup = self:GetDCSObject() -- DCS#Group
|
local DCSGroup = self:GetDCSObject() -- DCS#Group
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup and DCSGroup:isExist() then
|
||||||
local unit = DCSGroup:getUnit(1)
|
local unit = DCSGroup:getUnit(1)
|
||||||
if unit then
|
if unit then
|
||||||
local GroupIsActive = unit:isActive()
|
local GroupIsActive = unit:isActive()
|
||||||
@@ -1183,13 +1190,12 @@ end
|
|||||||
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
||||||
function GROUP:GetCoordinate()
|
function GROUP:GetCoordinate()
|
||||||
|
|
||||||
|
|
||||||
local Units = self:GetUnits() or {}
|
local Units = self:GetUnits() or {}
|
||||||
|
|
||||||
for _,_unit in pairs(Units) do
|
for _,_unit in pairs(Units) do
|
||||||
local FirstUnit = _unit -- Wrapper.Unit#UNIT
|
local FirstUnit = _unit -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
if FirstUnit then
|
if FirstUnit and FirstUnit:IsAlive() then
|
||||||
|
|
||||||
local FirstUnitCoordinate = FirstUnit:GetCoordinate()
|
local FirstUnitCoordinate = FirstUnit:GetCoordinate()
|
||||||
|
|
||||||
@@ -1201,6 +1207,24 @@ function GROUP:GetCoordinate()
|
|||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- no luck, try the API way
|
||||||
|
|
||||||
|
local DCSGroup = Group.getByName(self.GroupName)
|
||||||
|
if DCSGroup then
|
||||||
|
local DCSUnits = DCSGroup:getUnits() or {}
|
||||||
|
for _,_unit in pairs(DCSUnits) do
|
||||||
|
if Object.isExist(_unit) then
|
||||||
|
local position = _unit:getPosition()
|
||||||
|
local point = position.p ~= nil and position.p or _unit:GetPoint()
|
||||||
|
if point then
|
||||||
|
--self:I(point)
|
||||||
|
local coord = COORDINATE:NewFromVec3(point)
|
||||||
|
return coord
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
BASE:E( { "Cannot GetCoordinate", Group = self, Alive = self:IsAlive() } )
|
BASE:E( { "Cannot GetCoordinate", Group = self, Alive = self:IsAlive() } )
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1754,10 +1778,14 @@ end
|
|||||||
|
|
||||||
--- Returns the group template from the global _DATABASE object (an instance of @{Core.Database#DATABASE}).
|
--- Returns the group template from the global _DATABASE object (an instance of @{Core.Database#DATABASE}).
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @return #table
|
-- @return #table Template table.
|
||||||
function GROUP:GetTemplate()
|
function GROUP:GetTemplate()
|
||||||
local GroupName = self:GetName()
|
local GroupName = self:GetName()
|
||||||
return UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) )
|
local template=_DATABASE:GetGroupTemplate( GroupName )
|
||||||
|
if template then
|
||||||
|
return UTILS.DeepCopy( template )
|
||||||
|
end
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the group template route.points[] (the waypoints) from the global _DATABASE object (an instance of @{Core.Database#DATABASE}).
|
--- Returns the group template route.points[] (the waypoints) from the global _DATABASE object (an instance of @{Core.Database#DATABASE}).
|
||||||
@@ -1830,6 +1858,7 @@ end
|
|||||||
|
|
||||||
--- Randomize the positions of the units of the respawned group within the @{Core.Zone}.
|
--- Randomize the positions of the units of the respawned group within the @{Core.Zone}.
|
||||||
-- When a Respawn happens, the units of the group will be placed at random positions within the Zone (selected).
|
-- When a Respawn happens, the units of the group will be placed at random positions within the Zone (selected).
|
||||||
|
-- NOTE: InitRandomizePositionZone will not ensure, that every unit is placed within the zone!
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @param #boolean PositionZone true will randomize the positions within the Zone.
|
-- @param #boolean PositionZone true will randomize the positions within the Zone.
|
||||||
-- @return #GROUP self
|
-- @return #GROUP self
|
||||||
@@ -2780,6 +2809,14 @@ end
|
|||||||
-- @param #boolean switch If true, Invisible is enabled. If false, Invisible is disabled.
|
-- @param #boolean switch If true, Invisible is enabled. If false, Invisible is disabled.
|
||||||
-- @return #GROUP self
|
-- @return #GROUP self
|
||||||
function GROUP:SetCommandInvisible(switch)
|
function GROUP:SetCommandInvisible(switch)
|
||||||
|
return self:CommandSetInvisible(switch)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Switch on/off invisible flag for the group.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @param #boolean switch If true, Invisible is enabled. If false, Invisible is disabled.
|
||||||
|
-- @return #GROUP self
|
||||||
|
function GROUP:CommandSetInvisible(switch)
|
||||||
self:F2( self.GroupName )
|
self:F2( self.GroupName )
|
||||||
if switch==nil then
|
if switch==nil then
|
||||||
switch=false
|
switch=false
|
||||||
@@ -2794,6 +2831,14 @@ end
|
|||||||
-- @param #boolean switch If true, Immortal is enabled. If false, Immortal is disabled.
|
-- @param #boolean switch If true, Immortal is enabled. If false, Immortal is disabled.
|
||||||
-- @return #GROUP self
|
-- @return #GROUP self
|
||||||
function GROUP:SetCommandImmortal(switch)
|
function GROUP:SetCommandImmortal(switch)
|
||||||
|
return self:CommandSetImmortal(switch)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Switch on/off immortal flag for the group.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @param #boolean switch If true, Immortal is enabled. If false, Immortal is disabled.
|
||||||
|
-- @return #GROUP self
|
||||||
|
function GROUP:CommandSetImmortal(switch)
|
||||||
self:F2( self.GroupName )
|
self:F2( self.GroupName )
|
||||||
if switch==nil then
|
if switch==nil then
|
||||||
switch=false
|
switch=false
|
||||||
|
|||||||
@@ -723,7 +723,7 @@ end
|
|||||||
--- Converts a JSON string to a lua value.
|
--- Converts a JSON string to a lua value.
|
||||||
-- @param #string Json Anything JSON
|
-- @param #string Json Anything JSON
|
||||||
-- @return #table Lua
|
-- @return #table Lua
|
||||||
function NET.Lua2Json(Json)
|
function NET.Json2Lua(Json)
|
||||||
return net.json2lua(Json)
|
return net.json2lua(Json)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
-- @image Wrapper_Static.JPG
|
-- @image Wrapper_Static.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type STATIC
|
---
|
||||||
|
-- @type STATIC
|
||||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||||
|
|
||||||
--- Wrapper class to handle Static objects.
|
--- Wrapper class to handle Static objects.
|
||||||
@@ -236,7 +237,7 @@ function STATIC:SpawnAt(Coordinate, Heading, Delay)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Respawn the @{Wrapper.Unit} at the same location with the same properties.
|
--- Respawn the @{Wrapper.Static} at the same location with the same properties.
|
||||||
-- This is useful to respawn a cargo after it has been destroyed.
|
-- This is useful to respawn a cargo after it has been destroyed.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
-- @param DCS#country.id CountryID (Optional) The country ID used for spawning the new static. Default is same as currently.
|
-- @param DCS#country.id CountryID (Optional) The country ID used for spawning the new static. Default is same as currently.
|
||||||
@@ -280,3 +281,52 @@ function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Find the first(!) STATIC matching using patterns. Note that this is **a lot** slower than `:FindByName()`!
|
||||||
|
-- @param #STATIC self
|
||||||
|
-- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_\(Regular_Expressions\)) for regular expressions in LUA.
|
||||||
|
-- @return #STATIC The STATIC.
|
||||||
|
-- @usage
|
||||||
|
-- -- Find a static with a partial static name
|
||||||
|
-- local grp = STATIC:FindByMatching( "Apple" )
|
||||||
|
-- -- will return e.g. a static named "Apple-1-1"
|
||||||
|
--
|
||||||
|
-- -- using a pattern
|
||||||
|
-- local grp = STATIC:FindByMatching( ".%d.%d$" )
|
||||||
|
-- -- will return the first static found ending in "-1-1" to "-9-9", but not e.g. "-10-1"
|
||||||
|
function STATIC:FindByMatching( Pattern )
|
||||||
|
local GroupFound = nil
|
||||||
|
|
||||||
|
for name,static in pairs(_DATABASE.STATICS) do
|
||||||
|
if string.match(name, Pattern ) then
|
||||||
|
GroupFound = static
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return GroupFound
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Find all STATIC objects matching using patterns. Note that this is **a lot** slower than `:FindByName()`!
|
||||||
|
-- @param #STATIC self
|
||||||
|
-- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_\(Regular_Expressions\)) for regular expressions in LUA.
|
||||||
|
-- @return #table Groups Table of matching #STATIC objects found
|
||||||
|
-- @usage
|
||||||
|
-- -- Find all static with a partial static name
|
||||||
|
-- local grptable = STATIC:FindAllByMatching( "Apple" )
|
||||||
|
-- -- will return all statics with "Apple" in the name
|
||||||
|
--
|
||||||
|
-- -- using a pattern
|
||||||
|
-- local grp = STATIC:FindAllByMatching( ".%d.%d$" )
|
||||||
|
-- -- will return the all statics found ending in "-1-1" to "-9-9", but not e.g. "-10-1" or "-1-10"
|
||||||
|
function STATIC:FindAllByMatching( Pattern )
|
||||||
|
local GroupsFound = {}
|
||||||
|
|
||||||
|
for name,static in pairs(_DATABASE.STATICS) do
|
||||||
|
if string.match(name, Pattern ) then
|
||||||
|
GroupsFound[#GroupsFound+1] = static
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return GroupsFound
|
||||||
|
end
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
--
|
--
|
||||||
-- ## Example Missions:
|
-- ## Example Missions:
|
||||||
--
|
--
|
||||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Wrapper/Storage).
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Wrapper/Storage).
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1244,7 +1244,9 @@ function UNIT:GetThreatLevel()
|
|||||||
|
|
||||||
if Attributes["Fighters"] then ThreatLevel = 10
|
if Attributes["Fighters"] then ThreatLevel = 10
|
||||||
elseif Attributes["Multirole fighters"] then ThreatLevel = 9
|
elseif Attributes["Multirole fighters"] then ThreatLevel = 9
|
||||||
|
elseif Attributes["Interceptors"] then ThreatLevel = 9
|
||||||
elseif Attributes["Battleplanes"] then ThreatLevel = 8
|
elseif Attributes["Battleplanes"] then ThreatLevel = 8
|
||||||
|
elseif Attributes["Battle airplanes"] then ThreatLevel = 8
|
||||||
elseif Attributes["Attack helicopters"] then ThreatLevel = 7
|
elseif Attributes["Attack helicopters"] then ThreatLevel = 7
|
||||||
elseif Attributes["Strategic bombers"] then ThreatLevel = 6
|
elseif Attributes["Strategic bombers"] then ThreatLevel = 6
|
||||||
elseif Attributes["Bombers"] then ThreatLevel = 5
|
elseif Attributes["Bombers"] then ThreatLevel = 5
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
--
|
--
|
||||||
-- ## Additional Material:
|
-- ## Additional Material:
|
||||||
--
|
--
|
||||||
-- * **Demo Missions:** [GitHub](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Wrapper/Weapon)
|
-- * **Demo Missions:** [GitHub](https://github.com/FlightControl-Master/MOOSE_Demos/tree/master/Wrapper/Weapon)
|
||||||
-- * **YouTube videos:** None
|
-- * **YouTube videos:** None
|
||||||
-- * **Guides:** None
|
-- * **Guides:** None
|
||||||
--
|
--
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
-- @field #number coalition Coalition ID.
|
-- @field #number coalition Coalition ID.
|
||||||
-- @field #number country Country ID.
|
-- @field #number country Country ID.
|
||||||
-- @field DCS#Desc desc Descriptor table.
|
-- @field DCS#Desc desc Descriptor table.
|
||||||
|
-- @field DCS#Desc guidance Missile guidance descriptor.
|
||||||
-- @field DCS#Unit launcher Launcher DCS unit.
|
-- @field DCS#Unit launcher Launcher DCS unit.
|
||||||
-- @field Wrapper.Unit#UNIT launcherUnit Launcher Unit.
|
-- @field Wrapper.Unit#UNIT launcherUnit Launcher Unit.
|
||||||
-- @field #string launcherName Name of launcher unit.
|
-- @field #string launcherName Name of launcher unit.
|
||||||
@@ -196,6 +197,9 @@ function WEAPON:New(WeaponObject)
|
|||||||
|
|
||||||
if self:IsMissile() and self.desc.missileCategory then
|
if self:IsMissile() and self.desc.missileCategory then
|
||||||
self.categoryMissile=self.desc.missileCategory
|
self.categoryMissile=self.desc.missileCategory
|
||||||
|
if self.desc.guidance then
|
||||||
|
self.guidance = self.desc.guidance
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get type name.
|
-- Get type name.
|
||||||
@@ -667,6 +671,26 @@ function WEAPON:IsTorpedo()
|
|||||||
return self.category==Weapon.Category.TORPEDO
|
return self.category==Weapon.Category.TORPEDO
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if weapon is a Fox One missile (Radar Semi-Active).
|
||||||
|
-- @param #WEAPON self
|
||||||
|
-- @return #boolean If `true`, is a Fox One.
|
||||||
|
function WEAPON:IsFoxOne()
|
||||||
|
return self.guidance==Weapon.GuidanceType.RADAR_SEMI_ACTIVE
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if weapon is a Fox Two missile (IR guided).
|
||||||
|
-- @param #WEAPON self
|
||||||
|
-- @return #boolean If `true`, is a Fox Two.
|
||||||
|
function WEAPON:IsFoxTwo()
|
||||||
|
return self.guidance==Weapon.GuidanceType.IR
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if weapon is a Fox Three missile (Radar Active).
|
||||||
|
-- @param #WEAPON self
|
||||||
|
-- @return #boolean If `true`, is a Fox Three.
|
||||||
|
function WEAPON:IsFoxThree()
|
||||||
|
return self.guidance==Weapon.GuidanceType.RADAR_ACTIVE
|
||||||
|
end
|
||||||
|
|
||||||
--- Destroy the weapon object.
|
--- Destroy the weapon object.
|
||||||
-- @param #WEAPON self
|
-- @param #WEAPON self
|
||||||
|
|||||||
263
docs/advanced/concepts.md
Normal file
263
docs/advanced/concepts.md
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
---
|
||||||
|
title: Concepts
|
||||||
|
parent: Advanced
|
||||||
|
nav_order: 01
|
||||||
|
---
|
||||||
|
|
||||||
|
# Concepts
|
||||||
|
{: .no_toc }
|
||||||
|
|
||||||
|
1. Table of contents
|
||||||
|
{:toc}
|
||||||
|
|
||||||
|
If you want to get deeper into Moose, you will encounter a few terms and
|
||||||
|
concepts that we will explain here. You will need them for the later pages.
|
||||||
|
|
||||||
|
# Git and GitHub
|
||||||
|
|
||||||
|
Moose has about 260.000 lines of code and the amount is increasing each week.
|
||||||
|
To maintain such a big code base a vcs (version control system) is needed.
|
||||||
|
Moose uses [GitHub] as developer platform to create, store, and manage the code.
|
||||||
|
[GitHub] uses [Git] as version control system and provides additional
|
||||||
|
functionality like access control, bug tracking, feature requests and much more.
|
||||||
|
|
||||||
|
As a Moose user you don't need to learn how to use [Git]. You can download the
|
||||||
|
files on [GitHub] with a browser. But using [Git] will ease up the steps to keep
|
||||||
|
the Moose version on your hard disk up to date.
|
||||||
|
|
||||||
|
You will need to interact with [GitHub]. At least to download the Moose files.
|
||||||
|
For non-developers the page can be confusing. Take your time and read this
|
||||||
|
documentation. We are not able to explain every single detail on using [GitHub]
|
||||||
|
and [Git]. Especially because it is changing really quick and this documentation
|
||||||
|
will not. So try to use the help system of [GitHub] or find some videos on
|
||||||
|
[YouTube]. If you get stuck ask for help in the [Moose Discord].
|
||||||
|
|
||||||
|
Moose uses more than one repository on [GitHub] which doesn't exactly make it
|
||||||
|
any clearer. A list can be found on the [reposities] page.
|
||||||
|
|
||||||
|
# Branches: master & develop
|
||||||
|
|
||||||
|
As already explained in the [overview] two branches are used:
|
||||||
|
|
||||||
|
- Branch [master]: Stable release branch.
|
||||||
|
- Branch [develop]: Newest development with more OPS classes.
|
||||||
|
|
||||||
|
As a starter it is okay to begin your journey with the `master` branch.
|
||||||
|
If you are interested in some newer classes you need to use the `develop`
|
||||||
|
branch. The later one is also very stable, but it's missing more detailed
|
||||||
|
documentation and example missions for some of the new OPS classes.
|
||||||
|
|
||||||
|
You can switch between these branches with a drop down in the upper left corner
|
||||||
|
of the [GitHub] repository page. The list of branches is long. So it is a best
|
||||||
|
practice to save a bookmark in your browser with the links above.
|
||||||
|
Both branches are available on most of the different repositories. But because
|
||||||
|
of a limitation of [GitHub pages], we had to split the documentation in two
|
||||||
|
different repositories:
|
||||||
|
|
||||||
|
- Documentation of `master` branch: [MOOSE_DOCS]
|
||||||
|
- Documentation of `develop` branch: [MOOSE_DOCS_DEVELOP]
|
||||||
|
|
||||||
|
# Build result vs. source files
|
||||||
|
|
||||||
|
Moose consists of more than 140 individual files with the file extension `.lua`.
|
||||||
|
They are places in a [directory tree], which makes it more organized and its
|
||||||
|
semantic is pre-defined for [IntelliSense] to work.
|
||||||
|
|
||||||
|
On every change which is pushed to [GitHub] a build job will combine all of
|
||||||
|
these files to a single file called `Moose.lua`. In a second step all
|
||||||
|
comments will be removed to decrease the file size and the result will be saved
|
||||||
|
as `Moose_.lua`. These both files are created for users of Moose to include in
|
||||||
|
your missions.
|
||||||
|
|
||||||
|
The individual `.lua` files are used by the Moose developers and power users.
|
||||||
|
It is complicated to use them, but in combination with an IDE and a debugger it
|
||||||
|
is very useful to analyze even complex problems or write new additions to the
|
||||||
|
Moose framework.
|
||||||
|
|
||||||
|
# Static loading
|
||||||
|
|
||||||
|
If you add a script file with a `DO SCRIPT FILE` trigger, like we described in
|
||||||
|
[Create your own Hello world], the script file will be copied into the mission
|
||||||
|
file. This mission file (file extension .MIZ) is only a compressed ZIP archive
|
||||||
|
with another file ending.
|
||||||
|
|
||||||
|
If you change the script file after adding it to the mission, the changes are
|
||||||
|
not available on mission start. You have to re-add the script after each change.
|
||||||
|
This can be very annoying and often leads to forgetting to add the change again.
|
||||||
|
Then you wonder why the mission does not deliver the desired result.
|
||||||
|
|
||||||
|
But when the mission is finished you can upload it to your dedicated DCS server
|
||||||
|
or give it to a friend and it should run without problems. This way of embedding
|
||||||
|
the scripts do we call `static loading` and the resulting mission is very
|
||||||
|
portable.
|
||||||
|
|
||||||
|
# Dynamic loading of mission scripts
|
||||||
|
|
||||||
|
The other way of loading scripts is by using `DO SCRIPT`. This time the mission
|
||||||
|
editor don't show a file browse button. Instead you see a (very small) text
|
||||||
|
field to enter the code directly into it. It is only useful for very small
|
||||||
|
script snippets. But we can use it to load a file from your hard drive like
|
||||||
|
this:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
dofile('C:/MyScripts/hello-world.lua')
|
||||||
|
dofile('C:\\MyScripts\\hello-world.lua')
|
||||||
|
dofile([[C:\MyScripts\hello-world.lua]])
|
||||||
|
```
|
||||||
|
|
||||||
|
So all lines above do the same. In [Lua] you need to specify the path with
|
||||||
|
slashes, escape backslashes or use double square brackets around the string.
|
||||||
|
Double square brackets are usefull, because you can copy paste the path
|
||||||
|
without any modification.
|
||||||
|
|
||||||
|
If you upload a mission with this code, you need to create the folder
|
||||||
|
`C:\MyScripts\` on the server file system and upload the newest version of
|
||||||
|
`hello-world.lua`, too. The same applies, if you give the mission to a friend.
|
||||||
|
This makes the mission less portable, but on the other hand the mission uses the
|
||||||
|
file on the hard disk, without the need to add it to the mission again.
|
||||||
|
All you need to do is save the file and restart the mission.
|
||||||
|
|
||||||
|
The following can be used to increase portability:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
dofile(lfs.writedir() .. '/Missions/hello-world.lua')
|
||||||
|
```
|
||||||
|
|
||||||
|
The function `lfs.writedir()` will return your [Saved Games folder].
|
||||||
|
So you place the scripts in the subfolder Missions. This way the folder
|
||||||
|
structure is already available on all target systems. But you need to ensure
|
||||||
|
mission and script are both in sync to avoid problems. If you changed both and
|
||||||
|
upload only one of them to your server, you may get trouble.
|
||||||
|
|
||||||
|
There is another method you may find useful to dynamically load scripts:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
assert(loadfile('C:/MyScripts/hello-world.lua'))()
|
||||||
|
assert(loadfile('C:\\MyScripts\\hello-world.lua'))()
|
||||||
|
assert(loadfile([[C:\MyScripts\hello-world.lua]]))()
|
||||||
|
```
|
||||||
|
|
||||||
|
It is a little bit harder to read and write because of all these different
|
||||||
|
brackets. Especially the one on line 3. But it is a little safer than `dofile`.
|
||||||
|
Because of readability I prefer to use `dofile`.
|
||||||
|
|
||||||
|
# Dynamic loading of Moose
|
||||||
|
|
||||||
|
Of course you can use the same method to load Moose. This way you can place one
|
||||||
|
Moose file in your [Saved Games folder], which is used by multiple missions.
|
||||||
|
If you want to update Moose you just need to replace the file and all missions
|
||||||
|
will use the new version. But I prefer to add Moose by a `DO SCRIPT FILE`
|
||||||
|
trigger so I can add and test the new version for each mission step by step.
|
||||||
|
|
||||||
|
But we added two different ways to load the Moose source files automatically.
|
||||||
|
This is useful for Moose developers and it is a requirement to use a debugger.
|
||||||
|
This will be explained later in the [Debugger Guide].
|
||||||
|
|
||||||
|
# Automatic dynamic loading
|
||||||
|
|
||||||
|
With the code below you can have the advantages of both approaches.
|
||||||
|
- Copy the code into your mission script at the beginning.
|
||||||
|
- Save the mission script into the folder Missions in your [Saved Games folder].
|
||||||
|
- Change script filename in line 2 to match to your script.
|
||||||
|
- [De-Sanitize] your `MissionScripting.lua`.
|
||||||
|
|
||||||
|
Now the mission will use the script on your hard drive instead of the script
|
||||||
|
embedded in th MIZ file, as long as it is available. So you can chnge the
|
||||||
|
script, save it and restart the mission, without the need to readd it after each
|
||||||
|
change.
|
||||||
|
|
||||||
|
If you reach a stable state in your script development and want to upload the
|
||||||
|
mission to your server or give it to a friend, then just add the script again
|
||||||
|
like in the static method and save the mission.
|
||||||
|
|
||||||
|
{: .important }
|
||||||
|
> Do not forget to readd the script, prior uploading or sharing the mission,
|
||||||
|
> or it will run with an outdated version of your script and may fail if the
|
||||||
|
> objects in the mission don't match to this old version.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- Use script file from hard disk instead of the one included in the .miz file
|
||||||
|
if lfs and io then
|
||||||
|
MissionScript = lfs.writedir() .. '/Missions/hello-world-autodyn.lua'
|
||||||
|
-- Check if the running skript is from temp directory to avoid an endless loop
|
||||||
|
if string.find( debug.getinfo(1).source, lfs.tempdir() ) then
|
||||||
|
local f=io.open(MissionScript,"r")
|
||||||
|
if f~=nil then
|
||||||
|
io.close(f)
|
||||||
|
|
||||||
|
env.info( '*** LOAD MISSION SCRIPT FROM HARD DISK *** ' )
|
||||||
|
dofile(MissionScript)
|
||||||
|
do return end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
env.error( '*** LOAD MISSION SCRIPT FROM HARD DISK FAILED (Desanitize lfs and io)*** ' )
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Simple example mission to show the very basics of MOOSE
|
||||||
|
--
|
||||||
|
MESSAGE:New( "Hello World! This messages is printed by MOOSE!", 35, "INFO" ):ToAll():ToLog()
|
||||||
|
```
|
||||||
|
|
||||||
|
# IDE vs. Notepad++
|
||||||
|
|
||||||
|
As a beginner you should start with a good text editor, which supports syntax
|
||||||
|
highlighting of [Lua] code. This must not be [Notepad++]. It can be any other
|
||||||
|
powerful editor of your choice. Do yourself a favor and don't use the Windows
|
||||||
|
editor.
|
||||||
|
|
||||||
|
If you are a developer of [Lua] or another programming language, then your are
|
||||||
|
most likely familiar with an IDE (Integrated Develop Environment).
|
||||||
|
|
||||||
|
Otherwise you should know, that an IDE may help you with code completion,
|
||||||
|
Refactoring, Autocorrection, Formatting Source Code, showing documentation
|
||||||
|
as popup on mouse hover over keywords and Debugging.
|
||||||
|
|
||||||
|
There are different IDEs available. And not all IDEs support all features.
|
||||||
|
The three most important for Moose are:
|
||||||
|
|
||||||
|
- [Eclipse LDT]
|
||||||
|
- [Visual Studio Code]
|
||||||
|
- [PyCharm] (or [IntelliJ IDEA])
|
||||||
|
|
||||||
|
Eclipse has the best support for hover documentation and [IntelliSense] with
|
||||||
|
Moose. The Inventor of Moose (FlightControl) did an amazing job by adding an
|
||||||
|
integration to Eclipse LDT (a special version for Lua).
|
||||||
|
Unfortunately Eclipse LDT is not maintained any longer (last release 2018).
|
||||||
|
And the debugger doesn't work anymore, since an update of DCS.
|
||||||
|
|
||||||
|
In Visual Studio Code the support of Lua can be added by an addon.
|
||||||
|
The debugger works with Moose and DCS, but showing the LuaDoc and [IntelliSense]
|
||||||
|
is very limited.
|
||||||
|
|
||||||
|
PyCharm supports Lua also with an addon. The debugger works with Moose and DCS,
|
||||||
|
but showing the LuaDoc and [IntelliSense] is very limited.
|
||||||
|
|
||||||
|
It is up to you to choose the IDE according to your taste. Guides on how to
|
||||||
|
setup Moose with different IDEs and Debuggers are provided later in this
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
[Git]: https://en.wikipedia.org/wiki/Git
|
||||||
|
[GitHub]: https://github.com/
|
||||||
|
[YouTube]: https://www.youtube.com/
|
||||||
|
[Moose Discord]: https://discord.gg/gj68fm969S
|
||||||
|
[overview]: ../index.md
|
||||||
|
[reposities]: ../repositories.md
|
||||||
|
[master]: https://github.com/FlightControl-Master/MOOSE/tree/master
|
||||||
|
[develop]: https://github.com/FlightControl-Master/MOOSE/tree/develop
|
||||||
|
[GitHub pages]: https://pages.github.com/
|
||||||
|
[MOOSE_DOCS]: https://flightcontrol-master.github.io/MOOSE_DOCS/
|
||||||
|
[MOOSE_DOCS_DEVELOP]: https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/
|
||||||
|
[directory tree]: https://github.com/FlightControl-Master/MOOSE/tree/master/Moose%20Development/Moose
|
||||||
|
[Saved Games folder]: ../beginner/tipps-and-tricks.md#find-the-saved-games-folder
|
||||||
|
[Lua]: https://www.lua.org/
|
||||||
|
[Create your own Hello world]: ../beginner/hello-world-build.md
|
||||||
|
[Debugger Guide]: debugger.md
|
||||||
|
[IntelliSense]: https://en.wikipedia.org/wiki/IntelliSense
|
||||||
|
[De-Sanitize]: desanitize-dcs.md
|
||||||
|
[Notepad++]: https://notepad-plus-plus.org/downloads/
|
||||||
|
[Eclipse LDT]: https://projects.eclipse.org/projects/tools.ldt
|
||||||
|
[Visual Studio Code]: https://code.visualstudio.com/
|
||||||
|
[PyCharm]: https://www.jetbrains.com/pycharm/
|
||||||
|
[IntelliJ IDEA]: https://www.jetbrains.com/idea/
|
||||||
8
docs/advanced/debugger.md
Normal file
8
docs/advanced/debugger.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
title: Debugger
|
||||||
|
parent: Advanced
|
||||||
|
nav_order: 100
|
||||||
|
---
|
||||||
|
|
||||||
|
{: .warning }
|
||||||
|
> THIS DOCUMENT IS STILL WORK IN PROGRESS!
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: De-Sanitize DCS
|
title: De-Sanitize DCS
|
||||||
parent: Advanced
|
parent: Advanced
|
||||||
nav_order: 2
|
nav_order: 98
|
||||||
---
|
---
|
||||||
# De-Sanitize the DCS scripting environment
|
# De-Sanitize the DCS scripting environment
|
||||||
{: .no_toc }
|
{: .no_toc }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
parent: Advanced
|
parent: Advanced
|
||||||
nav_order: 1
|
nav_order: 97
|
||||||
---
|
---
|
||||||
# Eclipse Installation
|
# Eclipse Installation
|
||||||
{: .no_toc }
|
{: .no_toc }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
parent: Advanced
|
parent: Advanced
|
||||||
nav_order: 2
|
nav_order: 99
|
||||||
---
|
---
|
||||||
# Text to Speech
|
# Text to Speech
|
||||||
{: .no_toc }
|
{: .no_toc }
|
||||||
|
|||||||
@@ -35,16 +35,24 @@ Please remember when posting a question:
|
|||||||
- Before posting anything follow the [troubleshooting steps].
|
- Before posting anything follow the [troubleshooting steps].
|
||||||
- **Read your logs**.
|
- **Read your logs**.
|
||||||
|
|
||||||
|
### Formulate a good description
|
||||||
|
|
||||||
A post should contain the following:
|
A post should contain the following:
|
||||||
|
|
||||||
1. A describtion what you expected to happen and what actually happened.
|
- A description what you expected to happen and what actually happened.
|
||||||
- Do not use vague words this stuff is hard to help with! Be specific.
|
- Do not use vague words this stuff is hard to help with! Be specific.
|
||||||
|
|
||||||
2. Describe what happens instead.
|
- Describe what happens instead.
|
||||||
- The less detail you offer, the less chance you can be helped.
|
- The less detail you offer, the less chance you can be helped.
|
||||||
- Don’t say it doesn’t work. Or is it broken. Say what it actually does.
|
- Don't say it doesn't work. Or is it broken. Say what it actually does.
|
||||||
|
|
||||||
3. Post your code in Discord as formatted code:
|
### Format your code
|
||||||
|
|
||||||
|
The easier your code is to read, the more likely you are to get a helpful answer. If your code is hard to read, some
|
||||||
|
people who could help you may not even bother to read your code. Syntax Highlighting makes the code much clearer and
|
||||||
|
easier to understand. Therefore:
|
||||||
|
|
||||||
|
- Post your code in Discord as formatted code:
|
||||||
|
|
||||||
- Wrap a single line of code in backticks \` like this:
|
- Wrap a single line of code in backticks \` like this:
|
||||||
|
|
||||||
@@ -54,14 +62,31 @@ A post should contain the following:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Post your log lines with the error or warning messages. Format them like this:
|
### Do not post a screenshot of your code
|
||||||
|
|
||||||

|
Your code is easy to read on a screenshot if you are using a good text editor or IDE, but if someone discovers an error
|
||||||
|
in your code and wants to post a corrected version, they will have to type out the entire code. This could lead to them
|
||||||
|
not helping you because it's too much work for them.
|
||||||
|
|
||||||
|
### Post your log
|
||||||
|
|
||||||
|
If the error message in the `dcs.log` does not tell you anything, then post it in the Discord.
|
||||||
|
|
||||||
|
- Post the important log lines with the error or warning messages. Format them like this:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Send your mission when requested
|
||||||
|
|
||||||
|
Please don't just send your mission file. You have to manually extract the script from the file.
|
||||||
|
It is better to send your script code and log lines beforehand.
|
||||||
|
If this does not help, you may be asked to send your mission.
|
||||||
|
|
||||||
- Some complex problems need the mission (.miz file) also.
|
- Some complex problems need the mission (.miz file) also.
|
||||||
|
|
||||||
- But post your mission only when requested.
|
- But post your mission only when requested.
|
||||||
- Try to simplify your mission if it is complex!
|
- Try to simplify your mission if it is complex!
|
||||||
|
- Try to avoid or delete MODs, because could prevent people from helping you.
|
||||||
|
|
||||||
There are people in the Discord and in the forum, who spend their free time to
|
There are people in the Discord and in the forum, who spend their free time to
|
||||||
help you. <br />
|
help you. <br />
|
||||||
|
|||||||
@@ -11,10 +11,14 @@ nav_order: 05
|
|||||||
|
|
||||||
## Something went wrong
|
## Something went wrong
|
||||||
|
|
||||||
If the mission shows not the expected behaviour do the following steps:
|
If the mission shows not the expected behavior do the following steps:
|
||||||
|
|
||||||
1. Double check if you added the changed mission script to the mission again!
|
1. Double check if you added the changed mission script to the mission again!
|
||||||
1. Check if the triggers are configured as requested in the last sections.
|
1. Check if the triggers are configured as requested in the last sections:
|
||||||
|
- To load MOOSE: `4 MISSION START`, nothing on `CONDITIONS`, `DO SCRIPT FILE` to load `Moose_.lua`.
|
||||||
|
- To load mission script(s): `1 ONCE`, in `CONDITIONS` add `TIME MORE` = 1, `DO SCRIPT FILE` to load `yourscript.lua`.
|
||||||
|
1. Double check if you have the right version of MOOSE (some classes need the develop branch).
|
||||||
|
1. Try the newest version of MOOSE.
|
||||||
|
|
||||||
## Read the logs
|
## Read the logs
|
||||||
|
|
||||||
@@ -22,8 +26,7 @@ The DCS log is a super important and useful log for the entire of DCS World.
|
|||||||
All scripting and other errors are recorded here. It is the one stop shop for
|
All scripting and other errors are recorded here. It is the one stop shop for
|
||||||
things that occurred in your mission. It will tell you if there was a mistake.
|
things that occurred in your mission. It will tell you if there was a mistake.
|
||||||
|
|
||||||
1. Open the file `dcs.log` in the `Logs` subfolder in your DCS
|
1. Open the file `dcs.log` in the `Logs` subfolder in your DCS [Saved Games folder].
|
||||||
[Saved Games folder].
|
|
||||||
|
|
||||||
1. Search for the following line: `*** MOOSE INCLUDE END ***`
|
1. Search for the following line: `*** MOOSE INCLUDE END ***`
|
||||||
- If it is included in the log, Moose was loaded.
|
- If it is included in the log, Moose was loaded.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Reference in New Issue
Block a user