mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
238 Commits
2.9.1
...
FF/OpsStuf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffc72a53ff | ||
|
|
f789fbac70 | ||
|
|
375f12dc26 | ||
|
|
bc3a5271dc | ||
|
|
4d4b8862c2 | ||
|
|
31b75b7d17 | ||
|
|
fac7a5fdc6 | ||
|
|
cfca4fdc46 | ||
|
|
cca5a5d55d | ||
|
|
3243c92331 | ||
|
|
49191fb144 | ||
|
|
eab37d5e48 | ||
|
|
f739062463 | ||
|
|
e838431b28 | ||
|
|
c22304f2b0 | ||
|
|
1c10bfea92 | ||
|
|
c97d2ecaba | ||
|
|
2dc9f19d78 | ||
|
|
89a9d1d0a4 | ||
|
|
cf7d41cd7f | ||
|
|
fd191be274 | ||
|
|
31bdde130a | ||
|
|
afe542cc63 | ||
|
|
494550fe91 | ||
|
|
29c0d81c27 | ||
|
|
e79c2481da | ||
|
|
89a902fd57 | ||
|
|
460ad9db39 | ||
|
|
ae604fd847 | ||
|
|
099f059eec | ||
|
|
c3bba7d1fc | ||
|
|
db71610d72 | ||
|
|
4b8d120f20 | ||
|
|
1dc31cc852 | ||
|
|
68b97773fe | ||
|
|
3c0e977584 | ||
|
|
f03a48b118 | ||
|
|
c489a88106 | ||
|
|
a4704d0e2f | ||
|
|
4747dae51a | ||
|
|
b1e8ba74a8 | ||
|
|
641707f37b | ||
|
|
7538f63c00 | ||
|
|
52ed645f6c | ||
|
|
7c8f212b03 | ||
|
|
9f41cc51be | ||
|
|
85c73cb0a5 | ||
|
|
6390b223b0 | ||
|
|
b635490e47 | ||
|
|
62e8302753 | ||
|
|
cac7b39823 | ||
|
|
bfaf88f017 | ||
|
|
cc79dc74d4 | ||
|
|
427a11bd0f | ||
|
|
6f3133d48c | ||
|
|
4f4e8b17c1 | ||
|
|
aa7f26ac79 | ||
|
|
0850796368 | ||
|
|
343bf05c2c | ||
|
|
ff58649954 | ||
|
|
bbf793febe | ||
|
|
3e40d72e25 | ||
|
|
1c1daa4ebe | ||
|
|
fdcda6e5f3 | ||
|
|
a50dde7f2b | ||
|
|
1fb4cb1c4f | ||
|
|
cd0f854f41 | ||
|
|
f071c674d0 | ||
|
|
02a87d9fe0 | ||
|
|
3c53f627c2 | ||
|
|
12d68a41ca | ||
|
|
2dfde7d1fd | ||
|
|
c011d38313 | ||
|
|
6c4a64601f | ||
|
|
68350d6824 | ||
|
|
434f985e77 | ||
|
|
2e6cac7bee | ||
|
|
ba1dcfcdba | ||
|
|
b5965bbf81 | ||
|
|
b346dabdf8 | ||
|
|
a0429458d0 | ||
|
|
1376a16812 | ||
|
|
847dc1839f | ||
|
|
4267314260 | ||
|
|
b5110c8554 | ||
|
|
0dd4da1db4 | ||
|
|
1f1d1e4f2f | ||
|
|
4d4f8e9d61 | ||
|
|
522eb8b256 | ||
|
|
6fe883a17a | ||
|
|
b662ecc76b | ||
|
|
fbbdac9b7e | ||
|
|
6dd69eb6db | ||
|
|
1b6aeff005 | ||
|
|
de380614fb | ||
|
|
4287774d9f | ||
|
|
bcbda4eb64 | ||
|
|
f6fdff927b | ||
|
|
58ce4b001e | ||
|
|
6bba2fec0b | ||
|
|
5d2656d679 | ||
|
|
9a360a3bd5 | ||
|
|
217b8fe71e | ||
|
|
65a729a2d6 | ||
|
|
7868930fcb | ||
|
|
67248a290c | ||
|
|
32ae4986ca | ||
|
|
2a0086d3fe | ||
|
|
0bc52eb331 | ||
|
|
75a6a798ac | ||
|
|
067285f870 | ||
|
|
5353be482e | ||
|
|
8075be92a7 | ||
|
|
826ae86cb7 | ||
|
|
f453619c78 | ||
|
|
475153be4c | ||
|
|
ca20e059a6 | ||
|
|
2044068393 | ||
|
|
5f734a0d17 | ||
|
|
2c3e9e992d | ||
|
|
ef27daa282 | ||
|
|
1b8c9367a3 | ||
|
|
e36ade55d2 | ||
|
|
19047843cc | ||
|
|
2d631cba3f | ||
|
|
9ccfcb8fb1 | ||
|
|
a8e58b8121 | ||
|
|
dcc968c290 | ||
|
|
174454b8c5 | ||
|
|
36aa697936 | ||
|
|
d30a53333c | ||
|
|
8bace684c2 | ||
|
|
30b89328f1 | ||
|
|
aa5163fe3a | ||
|
|
b38dc62be7 | ||
|
|
097e0a3214 | ||
|
|
6d9333aa94 | ||
|
|
b5c9598cb0 | ||
|
|
6947bcfcf2 | ||
|
|
bc454fdec2 | ||
|
|
166a7ab7db | ||
|
|
db06154ad7 | ||
|
|
f459372720 | ||
|
|
f5d2439d69 | ||
|
|
fa43a6c40b | ||
|
|
04c092b9ef | ||
|
|
7af920891d | ||
|
|
5056187fb9 | ||
|
|
d9d333a7af | ||
|
|
72c5c2ee4d | ||
|
|
8f73a4c27c | ||
|
|
25936a526d | ||
|
|
f4b83a97a9 | ||
|
|
8bc735288f | ||
|
|
3360f511ee | ||
|
|
f64ec74d1c | ||
|
|
b885ef7767 | ||
|
|
f8afa1cb78 | ||
|
|
22f5104805 | ||
|
|
e95eb2768d | ||
|
|
266e34a92d | ||
|
|
f6091cd117 | ||
|
|
500a7f938f | ||
|
|
f408c11506 | ||
|
|
9fafdea0bb | ||
|
|
b4058ecab2 | ||
|
|
7306cc1102 | ||
|
|
21aadc14b1 | ||
|
|
fbf2c4c721 | ||
|
|
eed6119193 | ||
|
|
6db2e333ad | ||
|
|
9d3cb4cc1b | ||
|
|
0eb9dfc7de | ||
|
|
9d500186d1 | ||
|
|
f80265786d | ||
|
|
4eb0f8e9ca | ||
|
|
5a583671a7 | ||
|
|
7b9d8d375d | ||
|
|
6406ce696b | ||
|
|
e560c3ffdd | ||
|
|
7393cb2cbe | ||
|
|
74bd41743b | ||
|
|
56d4143a05 | ||
|
|
1093e55ea8 | ||
|
|
bcbe872c7d | ||
|
|
cc95c45fb0 | ||
|
|
bf60c535bc | ||
|
|
feb99e9405 | ||
|
|
6c36910ac7 | ||
|
|
d60f20a162 | ||
|
|
9fde88d61a | ||
|
|
430b4a274c | ||
|
|
dc26134845 | ||
|
|
5996426119 | ||
|
|
36d9460cdf | ||
|
|
0d9d0be0c3 | ||
|
|
adad7ef901 | ||
|
|
1561f49c9c | ||
|
|
bb6bb20179 | ||
|
|
e032781a92 | ||
|
|
07cac604cf | ||
|
|
aa7d0b1e25 | ||
|
|
28cb44874f | ||
|
|
13a8babe75 | ||
|
|
616f204f5b | ||
|
|
87dda49113 | ||
|
|
211e1b41b0 | ||
|
|
018830b539 | ||
|
|
d92d2d07c5 | ||
|
|
cd316e6719 | ||
|
|
046e49ac6b | ||
|
|
52e66ae969 | ||
|
|
0fb8fd8886 | ||
|
|
ca15d7cb00 | ||
|
|
1086c61ccf | ||
|
|
77f9721102 | ||
|
|
059d8ccfc0 | ||
|
|
bd9022c010 | ||
|
|
261a389ca5 | ||
|
|
b05683d384 | ||
|
|
708838c404 | ||
|
|
d7df08d754 | ||
|
|
974a56b135 | ||
|
|
92b21aa5c1 | ||
|
|
85c551cc59 | ||
|
|
0e2dff4e6b | ||
|
|
f33ccee7b1 | ||
|
|
5c9e3570e2 | ||
|
|
7277221905 | ||
|
|
497ac367ba | ||
|
|
51102e47ae | ||
|
|
92e2414612 | ||
|
|
3ca4898860 | ||
|
|
7643568706 | ||
|
|
e4d6e6d80e | ||
|
|
3684a023da | ||
|
|
99ebebe13c | ||
|
|
b0c8f05f38 |
@@ -1,87 +0,0 @@
|
||||
version: 2.4.a.{build}
|
||||
shallow_clone: true
|
||||
skip_branch_with_pr: false
|
||||
skip_commits:
|
||||
message: /!nobuild/
|
||||
skip_tags: false
|
||||
|
||||
environment:
|
||||
access_token_documentation:
|
||||
secure: JVBVVL8uJUcLXN+48eRdELEeCGOGCCaMzCqutsUqNuaZ/KblG5ZTt7+LV4UKv/0f
|
||||
LUAROCKS_VER: 2.4.1
|
||||
LUA_VER: 5.1.5
|
||||
LUA: lua5.3
|
||||
matrix:
|
||||
- LUA_VER: 5.1.5
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
|
||||
init:
|
||||
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
|
||||
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
|
||||
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
|
||||
throw "There are newer queued builds for this pull request, failing early." }
|
||||
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
|
||||
install:
|
||||
- cmd:
|
||||
# Outcomment if lua environment invalidates and needs to be reinstalled, otherwise all will run from the cache.
|
||||
call choco install 7zip.commandline
|
||||
call choco install lua51
|
||||
call choco install luarocks
|
||||
call refreshenv
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
|
||||
cmd: PATH = %PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\bin
|
||||
cmd: set LUA_PATH = %LUA_PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?.lua;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?\init.lua
|
||||
cmd: set LUA_CPATH = %LUA_CPATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\lib\lua\5.1\?.dll
|
||||
call luarocks install luasrcdiet
|
||||
call luarocks install checks
|
||||
call luarocks install luadocumentor
|
||||
call luarocks install luacheck
|
||||
|
||||
|
||||
cache:
|
||||
C:\ProgramData\chocolatey\lib
|
||||
C:\ProgramData\chocolatey\bin
|
||||
|
||||
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' )
|
||||
{
|
||||
echo "Hello World!"
|
||||
$apiUrl = 'https://ci.appveyor.com/api'
|
||||
$token = 'v2.6hcv3ige78kg3yvg4ge8'
|
||||
$headers = @{
|
||||
"Authorization" = "Bearer $token"
|
||||
"Content-type" = "application/json"
|
||||
}
|
||||
$RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-include'; branch = "$env:appveyor_repo_branch"; environmentVariables = @{} } | ConvertTo-Json
|
||||
# Generate the new version ...
|
||||
$project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody
|
||||
}
|
||||
- ps: |
|
||||
if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' )
|
||||
{
|
||||
$apiUrl = 'https://ci.appveyor.com/api'
|
||||
$token = 'v2.6hcv3ige78kg3yvg4ge8'
|
||||
$headers = @{
|
||||
"Authorization" = "Bearer $token"
|
||||
"Content-type" = "application/json"
|
||||
}
|
||||
$RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-docs'; branch = "$env:appveyor_repo_branch"; environmentVariables = @{} } | ConvertTo-Json
|
||||
# get project with last build details
|
||||
$project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody
|
||||
}
|
||||
|
||||
|
||||
test: off
|
||||
# test_script:
|
||||
# - cmd: luacheck "Moose Development\Moose\moose.lua" "Moose Mission Setup\moose.lua"
|
||||
|
||||
|
||||
on_finish:
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -15,3 +15,7 @@
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
|
||||
# Avoid Windows line endings on shell scripts
|
||||
# Needed for dockerfile builds
|
||||
*.sh text eol=lf
|
||||
|
||||
9
.github/workflows/build-docs.yml
vendored
9
.github/workflows/build-docs.yml
vendored
@@ -5,6 +5,15 @@ on:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
paths:
|
||||
- 'Moose Setup/**/*.lua'
|
||||
- 'Moose Development/**/*.lua'
|
||||
- 'Moose Development/**/*.py'
|
||||
- 'Moose Development/**/*.html'
|
||||
- '.github/workflows/build-docs.yml'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
|
||||
7
.github/workflows/build-includes.yml
vendored
7
.github/workflows/build-includes.yml
vendored
@@ -5,6 +5,13 @@ on:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
paths:
|
||||
- 'Moose Setup/**/*.lua'
|
||||
- 'Moose Development/**/*.lua'
|
||||
- '.github/workflows/build-includes.yml'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
|
||||
4
.github/workflows/gh-pages.yml
vendored
4
.github/workflows/gh-pages.yml
vendored
@@ -11,7 +11,7 @@ on:
|
||||
branches: ["master"]
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '.github/workflows/pages.yml'
|
||||
- '.github/workflows/gh-pages.yml'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
@@ -75,4 +75,4 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
- run: npm install linkinator
|
||||
- run: npx linkinator https://flightcontrol-master.github.io/MOOSE/ --recurse
|
||||
- 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
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -42,6 +42,8 @@ local.properties
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
.vscode
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
|
||||
@@ -91,12 +91,12 @@
|
||||
-- An optional @{Core.Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{#AI_A2A_CAP.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2A_CAP
|
||||
@@ -123,7 +123,7 @@ function AI_A2A_CAP:New2( AICap, EngageMinSpeed, EngageMaxSpeed, EngageFloorAlti
|
||||
|
||||
-- Multiple inheritance ... :-)
|
||||
local AI_Air = AI_AIR:New( AICap )
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AICap, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
|
||||
local self = BASE:Inherit( self, AI_Air_Engage ) --#AI_A2A_CAP
|
||||
|
||||
|
||||
@@ -176,12 +176,12 @@
|
||||
-- Per one, two, three, four?
|
||||
--
|
||||
-- **The default grouping is 1. That means, that each spawned defender will act individually.**
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: **FlightControl** rework of GCICAP + introduction of new concepts (squadrons).
|
||||
@@ -310,7 +310,7 @@ do -- AI_A2A_DISPATCHER
|
||||
-- Use the method @{#AI_A2A_DISPATCHER.SetEngageRadius}() to set a specific Engage Radius.
|
||||
-- **The Engage Radius is defined for ALL squadrons which are operational.**
|
||||
--
|
||||
-- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-019%20-%20AI_A2A%20-%20Engage%20Range%20Test)
|
||||
-- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching/AID-A2A-019%20-%20Engage%20Range%20Test)
|
||||
--
|
||||
-- In this example an Engage Radius is set to various values.
|
||||
--
|
||||
@@ -333,7 +333,7 @@ do -- AI_A2A_DISPATCHER
|
||||
-- Use the method @{#AI_A2A_DISPATCHER.SetGciRadius}() to set a specific controlled ground intercept radius.
|
||||
-- **The Ground Controlled Intercept radius is defined for ALL squadrons which are operational.**
|
||||
--
|
||||
-- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-013%20-%20AI_A2A%20-%20Intercept%20Test)
|
||||
-- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching/AID-A2A-013%20-%20Intercept%20Test)
|
||||
--
|
||||
-- In these examples, the Gci Radius is set to various values:
|
||||
--
|
||||
@@ -366,7 +366,7 @@ do -- AI_A2A_DISPATCHER
|
||||
-- it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are.
|
||||
-- In a hot war the borders are effectively defined by the ground based radar coverage of a coalition.
|
||||
--
|
||||
-- Demonstration Mission: [AID-009 - AI_A2A - Border Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-009 - AI_A2A - Border Test)
|
||||
-- Demonstration Mission: [AID-009 - AI_A2A - Border Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching/AID-A2A-009%20-%20Border%20Test)
|
||||
--
|
||||
-- In this example a border is set for the CCCP A2A dispatcher:
|
||||
--
|
||||
@@ -1233,7 +1233,7 @@ do -- AI_A2A_DISPATCHER
|
||||
--
|
||||
-- **Use the method @{#AI_A2A_DISPATCHER.SetEngageRadius}() to modify the default Engage Radius for ALL squadrons.**
|
||||
--
|
||||
-- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-019%20-%20AI_A2A%20-%20Engage%20Range%20Test)
|
||||
-- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching/AID-A2A-019%20-%20Engage%20Range%20Test)
|
||||
--
|
||||
-- @param #AI_A2A_DISPATCHER self
|
||||
-- @param #number EngageRadius (Optional, Default = 100000) The radius to report friendlies near the target.
|
||||
@@ -1283,7 +1283,7 @@ do -- AI_A2A_DISPATCHER
|
||||
-- Use the method @{#AI_A2A_DISPATCHER.SetGciRadius}() to set a specific controlled ground intercept radius.
|
||||
-- **The Ground Controlled Intercept radius is defined for ALL squadrons which are operational.**
|
||||
--
|
||||
-- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-013%20-%20AI_A2A%20-%20Intercept%20Test)
|
||||
-- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching/AID-A2A-013%20-%20Intercept%20Test)
|
||||
--
|
||||
-- @param #AI_A2A_DISPATCHER self
|
||||
-- @param #number GciRadius (Optional, Default = 200000) The radius to ground control intercept detected targets from the nearest airbase.
|
||||
|
||||
@@ -14,47 +14,31 @@
|
||||
|
||||
|
||||
--- @type AI_A2A_GCI
|
||||
-- @extends AI.AI_A2A#AI_A2A
|
||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_A2A_GCI is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- This cycle will continue.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- When enemies are detected, the AI will automatically engage the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## 1. AI_A2A_GCI constructor
|
||||
--
|
||||
-- * @{#AI_A2A_GCI.New}(): Creates a new AI_A2A_GCI object.
|
||||
--
|
||||
-- ## 2. AI_A2A_GCI is a FSM
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ### 2.1 AI_A2A_GCI States
|
||||
--
|
||||
-- * **None** ( Group ): The process is not started yet.
|
||||
@@ -75,29 +59,11 @@
|
||||
-- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
||||
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||
--
|
||||
-- ## 3. Set the Range of Engagement
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- An optional range can be set in meters,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_GCI#AI_A2A_GCI.SetEngageRange}() to define that range.
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Core.Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2A_GCI
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
|
||||
--- @type AI_A2A_PATROL
|
||||
-- @extends AI.AI_A2A#AI_A2A
|
||||
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
||||
|
||||
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
|
||||
--
|
||||
@@ -111,12 +111,12 @@
|
||||
-- When the AI is damaged, it is required that a new Patrol is started. However, damage cannon be foreseen early on.
|
||||
-- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
|
||||
-- Use the method @{#AI_A2A_PATROL.ManageDamage}() to have this proces in place.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2A_PATROL
|
||||
|
||||
@@ -12,15 +12,16 @@
|
||||
-- @image AI_Air_To_Ground_Engage.JPG
|
||||
|
||||
--- @type AI_A2G_BAI
|
||||
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage -- TODO: Documentation. This class does not exist, unable to determine what it extends.
|
||||
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2G_BAI
|
||||
@@ -46,7 +47,7 @@ AI_A2G_BAI = {
|
||||
function AI_A2G_BAI:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
|
||||
local AI_Air = AI_AIR:New( AIGroup )
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
|
||||
local self = BASE:Inherit( self, AI_Air_Engage )
|
||||
|
||||
|
||||
@@ -12,15 +12,16 @@
|
||||
-- @image AI_Air_To_Ground_Engage.JPG
|
||||
|
||||
--- @type AI_A2G_CAS
|
||||
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL TODO: Documentation. This class does not exist, unable to determine what it extends.
|
||||
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2G_CAS
|
||||
@@ -46,7 +47,7 @@ AI_A2G_CAS = {
|
||||
function AI_A2G_CAS:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
|
||||
local AI_Air = AI_AIR:New( AIGroup )
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
|
||||
local self = BASE:Inherit( self, AI_Air_Engage )
|
||||
|
||||
|
||||
@@ -253,12 +253,12 @@
|
||||
--
|
||||
-- **The default grouping is 1. That means, that each spawned defender will act individually.**
|
||||
-- But you can specify a number between 1 and 4, so that the defenders will act as a group.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl** rework of GCICAP + introduction of new concepts (squadrons).
|
||||
@@ -296,8 +296,6 @@ do -- AI_A2G_DISPATCHER
|
||||
--
|
||||
-- ## 1. AI\_A2G\_DISPATCHER constructor:
|
||||
--
|
||||
-- 
|
||||
--
|
||||
--
|
||||
-- The @{#AI_A2G_DISPATCHER.New}() method creates a new AI_A2G_DISPATCHER instance.
|
||||
--
|
||||
@@ -311,8 +309,6 @@ do -- AI_A2G_DISPATCHER
|
||||
-- A reconnaissance network, is used to detect enemy ground targets,
|
||||
-- potentially group them into areas, and to understand the position, level of threat of the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- As explained in the introduction, depending on the type of mission you want to achieve, different types of units can be applied to detect ground enemy targets.
|
||||
-- Ground based units are very useful to act as a reconnaissance, but they lack sometimes the visibility to detect targets at greater range.
|
||||
-- Recce are very useful to acquire the position of enemy ground targets when spread out over the battlefield at strategic positions.
|
||||
@@ -686,8 +682,6 @@ do -- AI_A2G_DISPATCHER
|
||||
--
|
||||
-- Use the method @{#AI_A2G_DISPATCHER.SetSquadronGrouping}() to set the grouping of aircraft when spawned in.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- In the case of **on call** engagement, the @{#AI_A2G_DISPATCHER.SetSquadronGrouping}() method has additional behaviour.
|
||||
-- When there aren't enough patrol flights airborne, a on call will be initiated for the remaining
|
||||
-- targets to be engaged. Depending on the grouping parameter, the spawned flights for on call aircraft are grouped into this setting.
|
||||
@@ -701,8 +695,6 @@ do -- AI_A2G_DISPATCHER
|
||||
-- The effectiveness can be set with the **overhead parameter**. This is a number that is used to calculate the amount of Units that dispatching command will allocate to GCI in surplus of detected amount of units.
|
||||
-- The **default value** of the overhead parameter is 1.0, which means **equal balance**.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- However, depending on the (type of) aircraft (strength and payload) in the squadron and the amount of resources available, this parameter can be changed.
|
||||
--
|
||||
-- The @{#AI_A2G_DISPATCHER.SetSquadronOverhead}() method can be used to tweak the defense strength,
|
||||
@@ -848,8 +840,6 @@ do -- AI_A2G_DISPATCHER
|
||||
--
|
||||
-- For example, the following setup will set the default refuel tanker to "Tanker":
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- -- Set the default tanker for refuelling to "Tanker", when the default fuel threshold has reached 90% fuel left.
|
||||
-- A2GDispatcher:SetDefaultFuelThreshold( 0.9 )
|
||||
-- A2GDispatcher:SetDefaultTanker( "Tanker" )
|
||||
|
||||
@@ -14,66 +14,43 @@
|
||||
|
||||
|
||||
--- @type AI_A2G_SEAD
|
||||
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL
|
||||
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||
|
||||
|
||||
--- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_A2G_SEAD is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_SEAD process can be started using the **Start** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- This cycle will continue.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- When enemies are detected, the AI will automatically engage the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## 1. AI_A2G_SEAD constructor
|
||||
--
|
||||
-- * @{#AI_A2G_SEAD.New}(): Creates a new AI_A2G_SEAD object.
|
||||
--
|
||||
-- ## 3. Set the Range of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional range can be set in meters,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_GCI#AI_A2G_SEAD.SetEngageRange}() to define that range.
|
||||
-- Use the method @{#AI_AIR_PATROL.SetEngageRange}() to define that range.
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Core.Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageZone}() to define that Zone. -- TODO: Documentation. Check that this is actually correct. The originally referenced class does not exist.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_A2G_SEAD
|
||||
@@ -99,7 +76,7 @@ AI_A2G_SEAD = {
|
||||
function AI_A2G_SEAD:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
|
||||
local AI_Air = AI_AIR:New( AIGroup )
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) -- #AI_AIR_PATROL
|
||||
local AI_Air_Patrol = AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
local AI_Air_Engage = AI_AIR_ENGAGE:New( AI_Air_Patrol, AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAltitude, EngageCeilingAltitude, EngageAltType )
|
||||
local self = BASE:Inherit( self, AI_Air_Engage )
|
||||
|
||||
|
||||
@@ -45,12 +45,12 @@
|
||||
-- * **Start**: Start the transport process.
|
||||
-- * **Stop**: Stop the transport process.
|
||||
-- * **Monitor**: Monitor and take action.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- @field #AI_AIR
|
||||
AI_AIR = {
|
||||
ClassName = "AI_AIR",
|
||||
|
||||
@@ -292,8 +292,6 @@ do -- AI_AIR_DISPATCHER
|
||||
--
|
||||
-- ## 1. AI\_AIR\_DISPATCHER constructor:
|
||||
--
|
||||
-- 
|
||||
--
|
||||
--
|
||||
-- The @{#AI_AIR_DISPATCHER.New}() method creates a new AI_AIR_DISPATCHER instance.
|
||||
--
|
||||
@@ -306,8 +304,6 @@ do -- AI_AIR_DISPATCHER
|
||||
-- A reconnaissance network, is used to detect enemy ground targets,
|
||||
-- potentially group them into areas, and to understand the position, level of threat of the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- As explained in the introduction, depending on the type of mission you want to achieve, different types of units can be applied to detect ground enemy targets.
|
||||
-- Ground based units are very useful to act as a reconnaissance, but they lack sometimes the visibility to detect targets at greater range.
|
||||
-- Recce are very useful to acquire the position of enemy ground targets when spread out over the battlefield at strategic positions.
|
||||
@@ -673,8 +669,6 @@ do -- AI_AIR_DISPATCHER
|
||||
--
|
||||
-- Use the method @{#AI_AIR_DISPATCHER.SetSquadronGrouping}() to set the grouping of aircraft when spawned in.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- In the case of **on call** engagement, the @{#AI_AIR_DISPATCHER.SetSquadronGrouping}() method has additional behaviour.
|
||||
-- When there aren't enough patrol flights airborne, a on call will be initiated for the remaining
|
||||
-- targets to be engaged. Depending on the grouping parameter, the spawned flights for on call aircraft are grouped into this setting.
|
||||
@@ -688,8 +682,6 @@ do -- AI_AIR_DISPATCHER
|
||||
-- The effectiveness can be set with the **overhead parameter**. This is a number that is used to calculate the amount of Units that dispatching command will allocate to GCI in surplus of detected amount of units.
|
||||
-- The **default value** of the overhead parameter is 1.0, which means **equal balance**.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- However, depending on the (type of) aircraft (strength and payload) in the squadron and the amount of resources available, this parameter can be changed.
|
||||
--
|
||||
-- The @{#AI_AIR_DISPATCHER.SetSquadronOverhead}() method can be used to tweak the defense strength,
|
||||
@@ -835,8 +827,6 @@ do -- AI_AIR_DISPATCHER
|
||||
--
|
||||
-- For example, the following setup will set the default refuel tanker to "Tanker":
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- -- Define the CAP
|
||||
-- A2ADispatcher:SetSquadron( "Sochi", AIRBASE.Caucasus.Sochi_Adler, { "SQ CCCP SU-34" }, 20 )
|
||||
-- A2ADispatcher:SetSquadronCap( "Sochi", ZONE:New( "PatrolZone" ), 4000, 8000, 600, 800, 1000, 1300 )
|
||||
|
||||
@@ -14,58 +14,32 @@
|
||||
|
||||
|
||||
--- @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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI_AIR_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_ENGAGE process can be started using the **Start** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- This cycle will continue.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- During the patrol, the AI will detect enemy targets, which are reported through the **Detected** event.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- When enemies are detected, the AI will automatically engage the enemy.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## 1. AI_AIR_ENGAGE constructor
|
||||
--
|
||||
-- * @{#AI_AIR_ENGAGE.New}(): Creates a new AI_AIR_ENGAGE object.
|
||||
--
|
||||
-- ## 3. Set the Range of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional range can be set in meters,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_GCI#AI_AIR_ENGAGE.SetEngageRange}() to define that range.
|
||||
-- ## 2. Set the Zone of Engagement
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Core.Zone} can be set,
|
||||
-- An optional @{Core.Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_CAP#AI_AIR_ENGAGE.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
@@ -74,6 +48,11 @@
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_AIR_ENGAGE
|
||||
@@ -456,12 +435,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!
|
||||
if TargetDistance <= EngageDistance * 9 then
|
||||
|
||||
self:I(string.format("AI_AIR_ENGAGE onafterEngageRoute ==> __Engage - target distance = %.1f km", TargetDistance/1000))
|
||||
--self:I(string.format("AI_AIR_ENGAGE onafterEngageRoute ==> __Engage - target distance = %.1f km", TargetDistance/1000))
|
||||
self:__Engage( 0.1, AttackSetUnit )
|
||||
|
||||
else
|
||||
|
||||
self:I(string.format("FF AI_AIR_ENGAGE onafterEngageRoute ==> Routing - target distance = %.1f km", TargetDistance/1000))
|
||||
--self:I(string.format("FF AI_AIR_ENGAGE onafterEngageRoute ==> Routing - target distance = %.1f km", TargetDistance/1000))
|
||||
|
||||
local EngageRoute = {}
|
||||
local AttackTasks = {}
|
||||
|
||||
@@ -79,21 +79,13 @@
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||
-- The range is applied at the position of the AI.
|
||||
-- Use the method @{AI.AI_CAP#AI_AIR_PATROL.SetEngageRange}() to define that range.
|
||||
-- Use the method @{#AI_AIR_PATROL.SetEngageRange}() to define that range.
|
||||
--
|
||||
-- ## 4. Set the Zone of Engagement
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- An optional @{Core.Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{AI.AI_CAP#AI_AIR_PATROL.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_AIR_PATROL
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
|
||||
--- Implements the core functions modeling squadrons for airplanes and helicopters.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_AIR_SQUADRON
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
||||
-- * **Gunterlund**: Test case revision.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -130,12 +130,12 @@
|
||||
-- AIBAIZone:SearchOff()
|
||||
--
|
||||
-- Searching can be switched back on with the method @{#AI_BAI_ZONE.SearchOn}(). Use the method @{#AI_BAI_ZONE.SearchOnOff}() to flexibily switch searching on or off.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_BAI_ZONE
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
|
||||
-- * **Dutch_Baron**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -40,7 +40,7 @@
|
||||
--
|
||||
-- The parent class @{Core.Fsm#FSM_SET} manages the functionality to control the Finite State Machine (FSM).
|
||||
-- The mission designer can tailor the behaviour of the AI_BALANCER, by defining event and state transition methods.
|
||||
-- An explanation about state and event transition methods can be found in the @{FSM} module documentation.
|
||||
-- An explanation about state and event transition methods can be found in the @{Core.Fsm} module documentation.
|
||||
--
|
||||
-- The mission designer can tailor the AI_BALANCER behaviour, by implementing a state or event handling method for the following:
|
||||
--
|
||||
@@ -52,7 +52,7 @@
|
||||
--
|
||||
-- ## 2. AI_BALANCER is a FSM
|
||||
--
|
||||
-- 
|
||||
-- 
|
||||
--
|
||||
-- ### 2.1. AI_BALANCER States
|
||||
--
|
||||
@@ -85,12 +85,12 @@
|
||||
--
|
||||
-- Note that when AI returns to an airbase, the AI_BALANCER will trigger the **Return** event and the AI will return,
|
||||
-- otherwise the AI_BALANCER will trigger a **Destroy** event, and the AI will be destroyed.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- @field #AI_BALANCER
|
||||
AI_BALANCER = {
|
||||
ClassName = "AI_BALANCER",
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
||||
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing.
|
||||
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
||||
-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing.
|
||||
-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing.
|
||||
-- * **Quax**: Concept, Advice & Testing.
|
||||
-- * **Pikey**: Concept, Advice & Testing.
|
||||
-- * **Gunterlund**: Test case revision.
|
||||
-- * **Whisper**: Testing.
|
||||
-- * **Delta99**: Testing.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -112,12 +112,12 @@
|
||||
-- An optional @{Core.Zone} can be set,
|
||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||
-- Use the method @{#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CAP_ZONE
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
||||
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing.
|
||||
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
||||
-- * **Quax**: Concept, Advice & Testing.
|
||||
-- * **Pikey**: Concept, Advice & Testing.
|
||||
-- * **Gunterlund**: Test case revision.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -118,12 +118,12 @@
|
||||
-- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
|
||||
-- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the CAS task.
|
||||
-- * **Status**: The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CAS_ZONE
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
-- * @{AI.AI_Cargo_APC} - Cargo transportation using APCs and other vehicles between zones.
|
||||
-- * @{AI.AI_Cargo_Helicopter} - Cargo transportation using helicopters between zones.
|
||||
-- * @{AI.AI_Cargo_Airplane} - Cargo transportation using airplanes to and from airbases.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- @field #AI_CARGO
|
||||
AI_CARGO = {
|
||||
ClassName = "AI_CARGO",
|
||||
|
||||
@@ -75,12 +75,12 @@
|
||||
-- Using the @{#AI_CARGO_APC.Pickup}() method, you are able to direct the APCs towards a point on the battlefield to board/load the cargo at the specific coordinate.
|
||||
-- The APCs will follow nearby roads as much as possible, to ensure fast and clean cargo transportation between the objects and villages in the simulation environment.
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- @field #AI_CARGO_APC
|
||||
AI_CARGO_APC = {
|
||||
|
||||
@@ -41,12 +41,12 @@
|
||||
-- marginal impact on the overall battlefield simulation. Fortunately, the firing strength of infantry is limited, and thus, respacing healthy infantry every
|
||||
-- time is not so much of an issue ...
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- @field #AI_CARGO_AIRPLANE
|
||||
AI_CARGO_AIRPLANE = {
|
||||
ClassName = "AI_CARGO_AIRPLANE",
|
||||
|
||||
@@ -100,12 +100,12 @@
|
||||
--
|
||||
-- Yes, please ensure that the zones are declared using the @{Core.Zone} classes.
|
||||
-- Possible zones that function at the moment are ZONE, ZONE_GROUP, ZONE_UNIT, ZONE_POLYGON.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
|
||||
@@ -137,12 +137,12 @@
|
||||
-- Use @{#AI_CARGO_DISPATCHER_APC.SetHomeZone}() to specify the home zone.
|
||||
--
|
||||
-- If no home zone is specified, the APCs will wait near the deploy zone for a new pickup command.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CARGO_DISPATCHER_APC
|
||||
|
||||
@@ -108,12 +108,12 @@
|
||||
--
|
||||
-- **There are a lot of templates available that allows you to quickly setup an event handler for a specific event type!**
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- @field #AI_CARGO_DISPATCHER_AIRPLANE
|
||||
AI_CARGO_DISPATCHER_AIRPLANE = {
|
||||
|
||||
@@ -140,12 +140,12 @@
|
||||
-- Use @{#AI_CARGO_DISPATCHER_HELICOPTER.SetHomeZone}() to specify the home zone.
|
||||
--
|
||||
-- If no home zone is specified, the helicopters will wait near the deploy zone for a new pickup command.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CARGO_DISPATCHER_HELICOPTER
|
||||
|
||||
@@ -130,12 +130,12 @@
|
||||
-- Use @{#AI_CARGO_DISPATCHER_SHIP.SetHomeZone}() to specify the home zone.
|
||||
--
|
||||
-- If no home zone is specified, the Ship will wait near the deploy zone for a new pickup command.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CARGO_DISPATCHER_SHIP
|
||||
|
||||
@@ -41,12 +41,12 @@
|
||||
-- marginal impact on the overall battlefield simulation. Fortunately, the firing strength of infantry is limited, and thus, respacing healthy infantry every
|
||||
-- time is not so much of an issue ...
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_CARGO_HELICOPTER
|
||||
|
||||
@@ -54,12 +54,12 @@
|
||||
-- Using the @{#AI_CARGO_SHIP.Pickup}() method, you are able to direct the Ship towards a Pickup zone to board/load the cargo at the specified
|
||||
-- coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- @field #AI_CARGO_SHIP
|
||||
AI_CARGO_SHIP = {
|
||||
ClassName = "AI_CARGO_SHIP",
|
||||
|
||||
@@ -174,12 +174,12 @@
|
||||
-- EscortPlanes = AI_ESCORT:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
|
||||
-- EscortPlanes:MenusAirplanes() -- create menus for airplanes
|
||||
-- EscortPlanes:__Start(2)
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- @field #AI_ESCORT
|
||||
AI_ESCORT = {
|
||||
ClassName = "AI_ESCORT",
|
||||
@@ -199,13 +199,6 @@ AI_ESCORT = {
|
||||
-- @field Functional.Detection#DETECTION_AREAS
|
||||
AI_ESCORT.Detection = nil
|
||||
|
||||
--- MENUPARAM type
|
||||
-- @type MENUPARAM
|
||||
-- @field #AI_ESCORT ParamSelf
|
||||
-- @field #Distance ParamDistance
|
||||
-- @field #function ParamFunction
|
||||
-- @field #string ParamMessage
|
||||
|
||||
--- AI_ESCORT class constructor for an AI group
|
||||
-- @param #AI_ESCORT self
|
||||
-- @param Wrapper.Client#CLIENT EscortUnit The client escorted by the EscortGroup.
|
||||
@@ -268,7 +261,7 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
|
||||
|
||||
|
||||
EscortGroupSet:ForEachGroup(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
-- Set EscortGroup known at EscortUnit.
|
||||
if not self.PlayerUnit._EscortGroups then
|
||||
@@ -350,7 +343,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
|
||||
self:F()
|
||||
|
||||
EscortGroupSet:ForEachGroup(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
EscortGroup:WayPointInitialize()
|
||||
|
||||
@@ -388,7 +381,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
|
||||
self:_InitFlightMenus()
|
||||
|
||||
self.EscortGroupSet:ForSomeGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
|
||||
self:_InitEscortMenus( EscortGroup )
|
||||
@@ -419,7 +412,7 @@ function AI_ESCORT:onafterStop( EscortGroupSet )
|
||||
self:F()
|
||||
|
||||
EscortGroupSet:ForEachGroup(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
EscortGroup:WayPointInitialize()
|
||||
|
||||
@@ -568,7 +561,7 @@ function AI_ESCORT:SetFlightMenuFormation( Formation )
|
||||
local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation,
|
||||
function ( self, Formation, ... )
|
||||
self.EscortGroupSet:ForSomeGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup, self, Formation, Arguments )
|
||||
if EscortGroup:IsAir() then
|
||||
self:E({FormationID=FormationID})
|
||||
@@ -1249,7 +1242,7 @@ function AI_ESCORT:MenuAssistedAttack()
|
||||
self:F()
|
||||
|
||||
self.EscortGroupSet:ForSomeGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if not EscortGroup:IsAir() then
|
||||
-- Request assistance from other escorts.
|
||||
@@ -1446,7 +1439,7 @@ function AI_ESCORT:_FlightHoldPosition( OrbitGroup, OrbitHeight, OrbitSeconds )
|
||||
local EscortUnit = self.PlayerUnit
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup, OrbitGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
if OrbitGroup == nil then
|
||||
@@ -1474,7 +1467,7 @@ end
|
||||
function AI_ESCORT:_FlightJoinUp()
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_JoinUp( EscortGroup )
|
||||
@@ -1501,7 +1494,7 @@ end
|
||||
function AI_ESCORT:_FlightFormationTrail( XStart, XSpace, YStart )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_EscortFormationTrail( EscortGroup, XStart, XSpace, YStart )
|
||||
@@ -1528,7 +1521,7 @@ end
|
||||
function AI_ESCORT:_FlightFormationStack( XStart, XSpace, YStart, YSpace )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_EscortFormationStack( EscortGroup, XStart, XSpace, YStart, YSpace )
|
||||
@@ -1551,7 +1544,7 @@ end
|
||||
function AI_ESCORT:_FlightFlare( Color, Message )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_Flare( EscortGroup, Color, Message )
|
||||
@@ -1574,7 +1567,7 @@ end
|
||||
function AI_ESCORT:_FlightSmoke( Color, Message )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_Smoke( EscortGroup, Color, Message )
|
||||
@@ -1605,7 +1598,7 @@ end
|
||||
function AI_ESCORT:_FlightSwitchReportNearbyTargets( ReportTargets )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_EscortSwitchReportNearbyTargets( EscortGroup, ReportTargets )
|
||||
@@ -1813,7 +1806,7 @@ end
|
||||
function AI_ESCORT:_FlightAttackTarget( DetectedItem )
|
||||
|
||||
self.EscortGroupSet:ForEachGroupAlive(
|
||||
-- @param Core.Group#GROUP EscortGroup
|
||||
-- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup, DetectedItem )
|
||||
if EscortGroup:IsAir() then
|
||||
self:_AttackTarget( EscortGroup, DetectedItem )
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
|
||||
|
||||
--- Models the automatic assignment of AI escorts to player flights.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_ESCORT_DISPATCHER
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
|
||||
|
||||
--- Models the assignment of AI escorts to player flights upon request using the radio menu.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_ESCORT_DISPATCHER_REQUEST
|
||||
|
||||
@@ -136,12 +136,12 @@
|
||||
--
|
||||
-- Escort groups can have their own mission. This menu item will allow the escort group to resume their Mission from a given waypoint.
|
||||
-- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors: **FlightControl**
|
||||
@@ -297,7 +297,7 @@ function AI_ESCORT_REQUEST:onafterStop( EscortGroupSet )
|
||||
self:F()
|
||||
|
||||
EscortGroupSet:ForEachGroup(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( EscortGroup )
|
||||
EscortGroup:WayPointInitialize()
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/FOR%20-%20Formation)
|
||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/FOR%20-%20AI%20Group%20Formation)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -31,11 +31,11 @@
|
||||
-- @field Core.Set#SET_GROUP FollowGroupSet
|
||||
-- @field #string FollowName
|
||||
-- @field #AI_FORMATION.MODE FollowMode The mode the escort is in.
|
||||
-- @field Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
|
||||
-- @field Core.Scheduler#SCHEDULER FollowScheduler The instance of the SCHEDULER class.
|
||||
-- @field #number FollowDistance The current follow distance.
|
||||
-- @field #boolean ReportTargets If true, nearby targets are reported.
|
||||
-- @Field DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the FollowGroup.
|
||||
-- @field DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup.
|
||||
-- @field DCS#AI.Option.Air.val.ROE OptionROE Which ROE is set to the FollowGroup.
|
||||
-- @field DCS#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the FollowGroup.
|
||||
-- @field #number dtFollow Time step between position updates.
|
||||
|
||||
|
||||
@@ -92,12 +92,12 @@
|
||||
-- local LargeFormation = AI_FORMATION:New( LeaderUnit, FollowGroupSet, "Center Wing Formation", "Briefing" )
|
||||
-- LargeFormation:FormationCenterWing( 500, 50, 0, 250, 250 )
|
||||
-- LargeFormation:__Start( 1 )
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- @field #AI_FORMATION
|
||||
AI_FORMATION = {
|
||||
ClassName = "AI_FORMATION",
|
||||
@@ -164,15 +164,6 @@ AI_FORMATION.__Enum.ReportType = {
|
||||
Ground = "G",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- MENUPARAM type
|
||||
-- @type MENUPARAM
|
||||
-- @field #AI_FORMATION ParamSelf
|
||||
-- @field #number ParamDistance
|
||||
-- @field #function ParamFunction
|
||||
-- @field #string ParamMessage
|
||||
|
||||
--- AI_FORMATION class constructor for an AI group
|
||||
-- @param #AI_FORMATION self
|
||||
-- @param Wrapper.Unit#UNIT FollowUnit The UNIT leading the FolllowGroupSet.
|
||||
@@ -1005,7 +996,7 @@ function AI_FORMATION:SetFlightModeMission( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
|
||||
else
|
||||
self.FollowGroupSet:ForSomeGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
|
||||
@@ -1029,7 +1020,7 @@ function AI_FORMATION:SetFlightModeAttack( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack )
|
||||
else
|
||||
self.FollowGroupSet:ForSomeGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack )
|
||||
@@ -1053,7 +1044,7 @@ function AI_FORMATION:SetFlightModeFormation( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
|
||||
else
|
||||
self.FollowGroupSet:ForSomeGroupAlive(
|
||||
--- @param Core.Group#GROUP EscortGroup
|
||||
--- @param Wrapper.Group#GROUP EscortGroup
|
||||
function( FollowGroup )
|
||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
|
||||
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Testing and API concept review.
|
||||
-- * **Dutch_Baron**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
|
||||
-- * **Pikey**: Testing and API concept review.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -144,12 +144,12 @@
|
||||
-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on.
|
||||
-- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
|
||||
-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this process in place.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #AI_PATROL_ZONE
|
||||
|
||||
@@ -142,7 +142,7 @@ end -- ACT_ACCOUNT
|
||||
|
||||
do -- ACT_ACCOUNT_DEADS
|
||||
|
||||
--- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Core.Fsm.Account#ACT_ACCOUNT}
|
||||
--- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{#ACT_ACCOUNT}
|
||||
--
|
||||
-- The ACT_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units.
|
||||
-- The process is given a @{Core.Set} of units that will be tracked upon successful destruction.
|
||||
|
||||
@@ -51,15 +51,15 @@
|
||||
-- * **After** the state transition.
|
||||
-- The state transition method needs to start with the name **OnAfter + the name of the state**.
|
||||
-- These state transition methods need to provide a return value, which is specified at the function description.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Core.Fsm.Assign#ACT_ASSIGN}
|
||||
-- # 1) @{#ACT_ASSIGN_ACCEPT} class, extends @{Core.Fsm#ACT_ASSIGN}
|
||||
--
|
||||
-- The ACT_ASSIGN_ACCEPT class accepts by default a task for a player. No player intervention is allowed to reject the task.
|
||||
--
|
||||
@@ -69,7 +69,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Core.Fsm.Assign#ACT_ASSIGN}
|
||||
-- # 2) @{#ACT_ASSIGN_MENU_ACCEPT} class, extends @{Core.Fsm#ACT_ASSIGN}
|
||||
--
|
||||
-- The ACT_ASSIGN_MENU_ACCEPT class accepts a task when the player accepts the task through an added menu option.
|
||||
-- This assignment type is useful to conditionally allow the player to choose whether or not he would accept the task.
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Core.Fsm.Route#ACT_ASSIST}
|
||||
-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{#ACT_ASSIST}
|
||||
--
|
||||
-- The ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Core.Zone}.
|
||||
-- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour.
|
||||
@@ -57,12 +57,12 @@
|
||||
-- # 1.1) ACT_ASSIST_SMOKE_TARGETS_ZONE constructor:
|
||||
--
|
||||
-- * @{#ACT_ASSIST_SMOKE_TARGETS_ZONE.New}(): Creates a new ACT_ASSIST_SMOKE_TARGETS_ZONE object.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module Actions.Act_Assist
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Core.Fsm.Route#ACT_ROUTE}
|
||||
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{#ACT_ROUTE}
|
||||
--
|
||||
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Core.Zone}.
|
||||
-- The player receives on perioding times messages with the coordinates of the route to follow.
|
||||
@@ -69,12 +69,12 @@
|
||||
-- # 1.1) ACT_ROUTE_ZONE constructor:
|
||||
--
|
||||
-- * @{#ACT_ROUTE_ZONE.New}(): Creates a new ACT_ROUTE_ZONE object.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module Actions.Act_Route
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
-- There are also dispatchers that make AI work together to transport cargo automatically!!!
|
||||
--
|
||||
-- - @{AI.AI_Cargo_Dispatcher_APC} derived classes will create for your dynamic cargo handlers controlled by AI ground vehicle groups (APCs) to transport cargo between sites.
|
||||
-- - @{AI.AI_Cargo_Dispatcher_Helicopters} derived classes will create for your dynamic cargo handlers controlled by AI helicopter groups to transport cargo between sites.
|
||||
-- - @{AI.AI_Cargo_Dispatcher_Helicopter} derived classes will create for your dynamic cargo handlers controlled by AI helicopter groups to transport cargo between sites.
|
||||
--
|
||||
-- ## 3.3) Cargo transportation tasking.
|
||||
--
|
||||
@@ -233,12 +233,12 @@
|
||||
-- Note that this option is optional, so can be omitted. The default value of the RR is 250 meters.
|
||||
-- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding.
|
||||
-- Note that this option is optional, so can be omitted. The default value of the RR is 10 meters.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
@@ -398,7 +398,7 @@ do -- CARGO
|
||||
--
|
||||
-- * AI Armoured Personnel Carriers to transport cargo and engage in battles, using the @{AI.AI_Cargo_APC#AI_CARGO_APC} class.
|
||||
-- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter#AI_CARGO_HELICOPTER} class.
|
||||
-- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Plane#AI_CARGO_PLANE} class.
|
||||
-- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Airplane#AI_CARGO_AIRPLANE} class.
|
||||
-- * AI Ships is planned.
|
||||
--
|
||||
-- The above cargo classes are also used by the TASK\_CARGO\_ classes to allow human players to transport cargo as part of a tasking:
|
||||
@@ -980,7 +980,7 @@ do -- CARGO
|
||||
|
||||
--- Report to a Carrier Group with a Flaring signal.
|
||||
-- @param #CARGO self
|
||||
-- @param Utils#UTILS.FlareColor FlareColor the color of the flare.
|
||||
-- @param Utilities.Utils#UTILS.FlareColor FlareColor the color of the flare.
|
||||
-- @return #CARGO
|
||||
function CARGO:ReportFlare( FlareColor )
|
||||
|
||||
@@ -989,7 +989,7 @@ do -- CARGO
|
||||
|
||||
--- Report to a Carrier Group with a Smoking signal.
|
||||
-- @param #CARGO self
|
||||
-- @param Utils#UTILS.SmokeColor SmokeColor the color of the smoke.
|
||||
-- @param Utilities.Utils#UTILS.SmokeColor SmokeColor the color of the smoke.
|
||||
-- @return #CARGO
|
||||
function CARGO:ReportSmoke( SmokeColor )
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
--
|
||||
-- # Calculate the Path
|
||||
--
|
||||
-- Finally, we have to calculate the path. This is done by the @{ASTAR.GetPath}(*ExcludeStart, ExcludeEnd*) function. This function returns a table of nodes, which
|
||||
-- Finally, we have to calculate the path. This is done by the @{#GetPath}(*ExcludeStart, ExcludeEnd*) function. This function returns a table of nodes, which
|
||||
-- describe the optimal path from the start node to the end node.
|
||||
--
|
||||
-- By default, the start and end node are include in the table that is returned.
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
--
|
||||
-- @module Core.ClientMenu
|
||||
-- @image Core_Menu.JPG
|
||||
-- last change: Sept 2023
|
||||
-- last change: Oct 2023
|
||||
|
||||
-- TODO
|
||||
----------------------------------------------------------------------------------------------------------------
|
||||
@@ -304,6 +304,8 @@ end
|
||||
-- @field #table menutree
|
||||
-- @field #number entrycount
|
||||
-- @field #boolean debug
|
||||
-- @field #table PlayerMenu
|
||||
-- @field #number Coalition
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- *As a child my family's menu consisted of two choices: take it, or leave it.*
|
||||
@@ -345,7 +347,7 @@ end
|
||||
-- local mymenu_lv3b = menumgr:NewEntry("Level 3 aab",mymenu_lv2a)
|
||||
-- local mymenu_lv3c = menumgr:NewEntry("Level 3 aac",mymenu_lv2a)
|
||||
--
|
||||
-- menumgr:Propagate()
|
||||
-- menumgr:Propagate() -- propagate **once** to all clients in the SET_CLIENT
|
||||
--
|
||||
-- ## Remove a single entry's subtree
|
||||
--
|
||||
@@ -384,13 +386,17 @@ end
|
||||
--
|
||||
-- ## Reset all and clear the reference tree
|
||||
--
|
||||
-- menumgr:ResetMenuComplete()
|
||||
-- menumgr:ResetMenuComplete()
|
||||
--
|
||||
-- ## Set to auto-propagate for CLIENTs joining the SET_CLIENT **after** the script is loaded - handy if you have a single menu tree.
|
||||
--
|
||||
-- menumgr:InitAutoPropagation()
|
||||
--
|
||||
-- @field #CLIENTMENUMANAGER
|
||||
CLIENTMENUMANAGER = {
|
||||
ClassName = "CLIENTMENUMANAGER",
|
||||
lid = "",
|
||||
version = "0.1.1",
|
||||
version = "0.1.4",
|
||||
name = nil,
|
||||
clientset = nil,
|
||||
menutree = {},
|
||||
@@ -399,26 +405,108 @@ CLIENTMENUMANAGER = {
|
||||
entrycount = 0,
|
||||
rootentries = {},
|
||||
debug = true,
|
||||
PlayerMenu = {},
|
||||
Coalition = nil,
|
||||
}
|
||||
|
||||
--- Create a new ClientManager instance.
|
||||
-- @param #CLIENTMENUMANAGER self
|
||||
-- @param Core.Set#SET_CLIENT ClientSet The set of clients to manage.
|
||||
-- @param #string Alias The name of this manager.
|
||||
-- @param #number Coalition (Optional) Coalition of this Manager, defaults to coalition.side.BLUE
|
||||
-- @return #CLIENTMENUMANAGER self
|
||||
function CLIENTMENUMANAGER:New(ClientSet, Alias)
|
||||
function CLIENTMENUMANAGER:New(ClientSet, Alias, Coalition)
|
||||
-- Inherit everything from FSM class.
|
||||
local self=BASE:Inherit(self, BASE:New()) -- #CLIENTMENUMANAGER
|
||||
self.clientset = ClientSet
|
||||
self.PlayerMenu = {}
|
||||
self.name = Alias or "Nightshift"
|
||||
self.Coalition = Coalition or coalition.side.BLUE
|
||||
-- Log id.
|
||||
self.lid=string.format("CLIENTMENUMANAGER %s | %s | ", self.version, self.name)
|
||||
if self.debug then
|
||||
self:T(self.lid.."Created")
|
||||
self:I(self.lid.."Created")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Internal] Event handling
|
||||
-- @param #CLIENTMENUMANAGER self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
-- @return #CLIENTMENUMANAGER self
|
||||
function CLIENTMENUMANAGER:_EventHandler(EventData)
|
||||
self:T(self.lid.."_EventHandler: "..EventData.id)
|
||||
--self:I(self.lid.."_EventHandler: "..tostring(EventData.IniPlayerName))
|
||||
if EventData.id == EVENTS.PlayerLeaveUnit or EventData.id == EVENTS.Ejection or EventData.id == EVENTS.Crash or EventData.id == EVENTS.PilotDead then
|
||||
self:T(self.lid.."Leave event for player: "..tostring(EventData.IniPlayerName))
|
||||
local Client = _DATABASE:FindClient( EventData.IniUnitName )
|
||||
if Client then
|
||||
self:ResetMenu(Client)
|
||||
end
|
||||
elseif (EventData.id == EVENTS.PlayerEnterAircraft) and EventData.IniCoalition == self.Coalition then
|
||||
if EventData.IniPlayerName and EventData.IniGroup then
|
||||
if (not self.clientset:IsIncludeObject(_DATABASE:FindClient( EventData.IniUnitName ))) then
|
||||
self:T(self.lid.."Client not in SET: "..EventData.IniPlayerName)
|
||||
return self
|
||||
end
|
||||
--self:I(self.lid.."Join event for player: "..EventData.IniPlayerName)
|
||||
local player = _DATABASE:FindClient( EventData.IniUnitName )
|
||||
self:Propagate(player)
|
||||
end
|
||||
elseif EventData.id == EVENTS.PlayerEnterUnit then
|
||||
-- special for CA slots
|
||||
local grp = GROUP:FindByName(EventData.IniGroupName)
|
||||
if grp:IsGround() then
|
||||
self:T(string.format("Player %s entered GROUND unit %s!",EventData.IniPlayerName,EventData.IniUnitName))
|
||||
local IsPlayer = EventData.IniDCSUnit:getPlayerName()
|
||||
if IsPlayer then
|
||||
|
||||
local client=_DATABASE.CLIENTS[EventData.IniDCSUnitName] --Wrapper.Client#CLIENT
|
||||
|
||||
-- Add client in case it does not exist already.
|
||||
if not client then
|
||||
|
||||
-- Debug info.
|
||||
self:I(string.format("Player '%s' joined ground unit '%s' of group '%s'", tostring(EventData.IniPlayerName), tostring(EventData.IniDCSUnitName), tostring(EventData.IniDCSGroupName)))
|
||||
|
||||
client=_DATABASE:AddClient(EventData.IniDCSUnitName)
|
||||
|
||||
-- Add player.
|
||||
client:AddPlayer(EventData.IniPlayerName)
|
||||
|
||||
-- Add player.
|
||||
if not _DATABASE.PLAYERS[EventData.IniPlayerName] then
|
||||
_DATABASE:AddPlayer( EventData.IniUnitName, EventData.IniPlayerName )
|
||||
end
|
||||
|
||||
-- Player settings.
|
||||
local Settings = SETTINGS:Set( EventData.IniPlayerName )
|
||||
Settings:SetPlayerMenu(EventData.IniUnit)
|
||||
end
|
||||
--local player = _DATABASE:FindClient( EventData.IniPlayerName )
|
||||
self:Propagate(client)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set this Client Manager to auto-propagate menus to newly joined players. Useful if you have **one** menu structure only.
|
||||
-- @param #CLIENTMENUMANAGER self
|
||||
-- @return #CLIENTMENUMANAGER self
|
||||
function CLIENTMENUMANAGER:InitAutoPropagation()
|
||||
-- Player Events
|
||||
self:HandleEvent(EVENTS.PlayerLeaveUnit, self._EventHandler)
|
||||
self:HandleEvent(EVENTS.Ejection, self._EventHandler)
|
||||
self:HandleEvent(EVENTS.Crash, self._EventHandler)
|
||||
self:HandleEvent(EVENTS.PilotDead, self._EventHandler)
|
||||
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
|
||||
self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler)
|
||||
self:SetEventPriority(5)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new entry in the generic structure.
|
||||
-- @param #CLIENTMENUMANAGER self
|
||||
-- @param #string Text Text of the F10 menu entry.
|
||||
@@ -571,7 +659,7 @@ end
|
||||
-- @return #CLIENTMENU Entry
|
||||
function CLIENTMENUMANAGER:Propagate(Client)
|
||||
self:T(self.lid.."Propagate")
|
||||
self:T(Client)
|
||||
--self:I(UTILS.PrintTableToLog(Client,1))
|
||||
local Set = self.clientset.Set
|
||||
if Client then
|
||||
Set = {Client}
|
||||
@@ -580,7 +668,7 @@ function CLIENTMENUMANAGER:Propagate(Client)
|
||||
for _,_client in pairs(Set) do
|
||||
local client = _client -- Wrapper.Client#CLIENT
|
||||
if client and client:IsAlive() then
|
||||
local playername = client:GetPlayerName()
|
||||
local playername = client:GetPlayerName() or "none"
|
||||
if not self.playertree[playername] then
|
||||
self.playertree[playername] = {}
|
||||
end
|
||||
@@ -792,4 +880,3 @@ end
|
||||
-- End ClientMenu
|
||||
--
|
||||
----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
--
|
||||
-- ## Example Missions:
|
||||
--
|
||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Operation).
|
||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Core/Condition).
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
|
||||
@@ -126,6 +126,8 @@ function DATABASE:New()
|
||||
self:SetEventPriority( 1 )
|
||||
|
||||
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
|
||||
-- DCS 2.9 fixed CA event for players -- TODO: reset unit when leaving
|
||||
self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit )
|
||||
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
|
||||
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
||||
self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash )
|
||||
@@ -680,7 +682,7 @@ do -- cargo
|
||||
--- Finds an CARGO based on the CargoName.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string CargoName
|
||||
-- @return Wrapper.Cargo#CARGO The found CARGO.
|
||||
-- @return Cargo.Cargo#CARGO The found CARGO.
|
||||
function DATABASE:FindCargo( CargoName )
|
||||
|
||||
local CargoFound = self.CARGOS[CargoName]
|
||||
@@ -810,6 +812,7 @@ function DATABASE:AddPlayer( UnitName, PlayerName )
|
||||
self.PLAYERUNITS[PlayerName] = self:FindUnit( UnitName )
|
||||
self.PLAYERSJOINED[PlayerName] = PlayerName
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Deletes a player from the DATABASE based on the Player Name.
|
||||
@@ -1470,39 +1473,43 @@ function DATABASE:_EventOnDeadOrCrash( Event )
|
||||
end
|
||||
|
||||
|
||||
--- Handles the OnPlayerEnterUnit event to fill the active players table (with the unit filter applied).
|
||||
--- Handles the OnPlayerEnterUnit event to fill the active players table for CA units (with the unit filter applied).
|
||||
-- @param #DATABASE self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function DATABASE:_EventOnPlayerEnterUnit( Event )
|
||||
self:F2( { Event } )
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
if Event.IniObjectCategory == 1 then
|
||||
-- Player entering a CA slot
|
||||
if Event.IniObjectCategory == 1 and Event.IniGroup and Event.IniGroup:IsGround() then
|
||||
|
||||
local IsPlayer = Event.IniDCSUnit:getPlayerName()
|
||||
if IsPlayer then
|
||||
|
||||
-- Add unit.
|
||||
self:AddUnit( Event.IniDCSUnitName )
|
||||
-- Debug info.
|
||||
self:I(string.format("Player '%s' joined GROUND unit '%s' of group '%s'", tostring(Event.IniPlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniDCSGroupName)))
|
||||
|
||||
local client= self.CLIENTS[Event.IniDCSUnitName] --Wrapper.Client#CLIENT
|
||||
|
||||
-- Add client in case it does not exist already.
|
||||
if not client then
|
||||
client=self:AddClient(Event.IniDCSUnitName)
|
||||
end
|
||||
|
||||
-- Add player.
|
||||
client:AddPlayer(Event.IniPlayerName)
|
||||
|
||||
-- Ini unit.
|
||||
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
|
||||
|
||||
-- Add group.
|
||||
self:AddGroup( Event.IniDCSGroupName )
|
||||
|
||||
-- Get player unit.
|
||||
local PlayerName = Event.IniDCSUnit:getPlayerName()
|
||||
|
||||
if PlayerName then
|
||||
|
||||
if not self.PLAYERS[PlayerName] then
|
||||
self:AddPlayer( Event.IniDCSUnitName, PlayerName )
|
||||
-- Add player.
|
||||
if not self.PLAYERS[Event.IniPlayerName] then
|
||||
self:AddPlayer( Event.IniUnitName, Event.IniPlayerName )
|
||||
end
|
||||
|
||||
local Settings = SETTINGS:Set( PlayerName )
|
||||
Settings:SetPlayerMenu( Event.IniUnit )
|
||||
-- Player settings.
|
||||
local Settings = SETTINGS:Set( Event.IniPlayerName )
|
||||
Settings:SetPlayerMenu(Event.IniUnit)
|
||||
|
||||
else
|
||||
self:E("ERROR: getPlayerName() returned nil for event PlayerEnterUnit")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1513,15 +1520,26 @@ end
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function DATABASE:_EventOnPlayerLeaveUnit( Event )
|
||||
self:F2( { Event } )
|
||||
|
||||
|
||||
local function FindPlayerName(UnitName)
|
||||
local playername = nil
|
||||
for _name,_unitname in pairs(self.PLAYERS) do
|
||||
if _unitname == UnitName then
|
||||
playername = _name
|
||||
break
|
||||
end
|
||||
end
|
||||
return playername
|
||||
end
|
||||
|
||||
if Event.IniUnit then
|
||||
|
||||
if Event.IniObjectCategory == 1 then
|
||||
|
||||
-- Try to get the player name. This can be buggy for multicrew aircraft!
|
||||
local PlayerName = Event.IniUnit:GetPlayerName()
|
||||
|
||||
if PlayerName then --and self.PLAYERS[PlayerName] then
|
||||
local PlayerName = Event.IniUnit:GetPlayerName() or FindPlayerName(Event.IniUnitName)
|
||||
|
||||
if PlayerName then
|
||||
|
||||
-- Debug info.
|
||||
self:I(string.format("Player '%s' left unit %s", tostring(PlayerName), tostring(Event.IniUnitName)))
|
||||
@@ -2005,8 +2023,6 @@ end
|
||||
TargetPlayerName = Event.IniPlayerName
|
||||
|
||||
TargetCoalition = Event.IniCoalition
|
||||
--TargetCategory = TargetUnit:getCategory()
|
||||
--TargetCategory = TargetUnit:getDesc().category -- Workaround
|
||||
TargetCategory = Event.IniCategory
|
||||
TargetType = Event.IniTypeName
|
||||
|
||||
|
||||
@@ -173,7 +173,8 @@
|
||||
-- @image Core_Event.JPG
|
||||
|
||||
|
||||
--- @type EVENT
|
||||
---
|
||||
-- @type EVENT
|
||||
-- @field #EVENT.Events Events
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
@@ -260,6 +261,15 @@ EVENTS = {
|
||||
SimulationStart = world.event.S_EVENT_SIMULATION_START or -1,
|
||||
WeaponRearm = world.event.S_EVENT_WEAPON_REARM or -1,
|
||||
WeaponDrop = world.event.S_EVENT_WEAPON_DROP or -1,
|
||||
-- Added with DCS 2.9.0
|
||||
UnitTaskTimeout = world.event.S_EVENT_UNIT_TASK_TIMEOUT or -1,
|
||||
UnitTaskStage = world.event.S_EVENT_UNIT_TASK_STAGE or -1,
|
||||
MacSubtaskScore = world.event.S_EVENT_MAC_SUBTASK_SCORE or -1,
|
||||
MacExtraScore = world.event.S_EVENT_MAC_EXTRA_SCORE or -1,
|
||||
MissionRestart = world.event.S_EVENT_MISSION_RESTART or -1,
|
||||
MissionWinner = world.event.S_EVENT_MISSION_WINNER or -1,
|
||||
PostponedTakeoff = world.event.S_EVENT_POSTPONED_TAKEOFF or -1,
|
||||
PostponedLand = world.event.S_EVENT_POSTPONED_LAND or -1,
|
||||
}
|
||||
|
||||
--- The Event structure
|
||||
@@ -282,6 +292,7 @@ EVENTS = {
|
||||
-- @field Wrapper.Group#GROUP IniGroup (UNIT) The initiating MOOSE wrapper @{Wrapper.Group#GROUP} of the initiator Group object.
|
||||
-- @field #string IniGroupName UNIT) The initiating GROUP name (same as IniDCSGroupName).
|
||||
-- @field #string IniPlayerName (UNIT) The name of the initiating player in case the Unit is a client or player slot.
|
||||
-- @field #string IniPlayerUCID (UNIT) The UCID of the initiating player in case the Unit is a client or player slot and on a multi-player server.
|
||||
-- @field DCS#coalition.side IniCoalition (UNIT) The coalition of the initiator.
|
||||
-- @field DCS#Unit.Category IniCategory (UNIT) The category of the initiator.
|
||||
-- @field #string IniTypeName (UNIT) The type name of the initiator.
|
||||
@@ -297,6 +308,7 @@ EVENTS = {
|
||||
-- @field Wrapper.Group#GROUP TgtGroup (UNIT) The target MOOSE wrapper @{Wrapper.Group#GROUP} of the target Group object.
|
||||
-- @field #string TgtGroupName (UNIT) The target GROUP name (same as TgtDCSGroupName).
|
||||
-- @field #string TgtPlayerName (UNIT) The name of the target player in case the Unit is a client or player slot.
|
||||
-- @field #string TgtPlayerUCID (UNIT) The UCID of the target player in case the Unit is a client or player slot and on a multi-player server.
|
||||
-- @field DCS#coalition.side TgtCoalition (UNIT) The coalition of the target.
|
||||
-- @field DCS#Unit.Category TgtCategory (UNIT) The category of the target.
|
||||
-- @field #string TgtTypeName (UNIT) The type name of the target.
|
||||
@@ -313,7 +325,7 @@ EVENTS = {
|
||||
-- @field Cargo.Cargo#CARGO Cargo The cargo object.
|
||||
-- @field #string CargoName The name of the cargo object.
|
||||
--
|
||||
-- @field Core.ZONE#ZONE Zone The zone object.
|
||||
-- @field Core.Zone#ZONE Zone The zone object.
|
||||
-- @field #string ZoneName The name of the zone.
|
||||
|
||||
|
||||
@@ -633,6 +645,55 @@ local _EVENTMETA = {
|
||||
Event = "OnEventWeaponDrop",
|
||||
Text = "S_EVENT_WEAPON_DROP"
|
||||
},
|
||||
-- DCS 2.9
|
||||
[EVENTS.UnitTaskTimeout] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventUnitTaskTimeout",
|
||||
Text = "S_EVENT_UNIT_TASK_TIMEOUT "
|
||||
},
|
||||
[EVENTS.UnitTaskStage] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventUnitTaskStage",
|
||||
Text = "S_EVENT_UNIT_TASK_STAGE "
|
||||
},
|
||||
[EVENTS.MacSubtaskScore] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventMacSubtaskScore",
|
||||
Text = "S_EVENT_MAC_SUBTASK_SCORE"
|
||||
},
|
||||
[EVENTS.MacExtraScore] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventMacExtraScore",
|
||||
Text = "S_EVENT_MAC_EXTRA_SCOREP"
|
||||
},
|
||||
[EVENTS.MissionRestart] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventMissionRestart",
|
||||
Text = "S_EVENT_MISSION_RESTART"
|
||||
},
|
||||
[EVENTS.MissionWinner] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventMissionWinner",
|
||||
Text = "S_EVENT_MISSION_WINNER"
|
||||
},
|
||||
[EVENTS.PostponedTakeoff] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventPostponedTakeoff",
|
||||
Text = "S_EVENT_POSTPONED_TAKEOFF"
|
||||
},
|
||||
[EVENTS.PostponedLand] = {
|
||||
Order = 1,
|
||||
Side = "I",
|
||||
Event = "OnEventPostponedLand",
|
||||
Text = "S_EVENT_POSTPONED_LAND"
|
||||
},
|
||||
}
|
||||
|
||||
--- The Events structure
|
||||
@@ -988,7 +1049,7 @@ do -- Event Creation
|
||||
|
||||
--- Creation of a New ZoneGoal Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Core.Functional#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
-- @param Functional.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
function EVENT:CreateEventNewZoneGoal( ZoneGoal )
|
||||
self:F( { ZoneGoal } )
|
||||
|
||||
@@ -1080,9 +1141,9 @@ function EVENT:onEvent( Event )
|
||||
|
||||
if Event.initiator then
|
||||
|
||||
Event.IniObjectCategory = Event.initiator:getCategory()
|
||||
Event.IniObjectCategory = Object.getCategory(Event.initiator)
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.STATIC then
|
||||
if Event.IniObjectCategory == Object.Category.STATIC then
|
||||
---
|
||||
-- Static
|
||||
---
|
||||
@@ -1118,10 +1179,9 @@ function EVENT:onEvent( Event )
|
||||
local Unit=UNIT:FindByName(Event.IniDCSUnitName)
|
||||
if Unit then
|
||||
Event.IniObjectCategory = Object.Category.UNIT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.UNIT then
|
||||
elseif Event.IniObjectCategory == Object.Category.UNIT then
|
||||
---
|
||||
-- Unit
|
||||
---
|
||||
@@ -1144,12 +1204,19 @@ function EVENT:onEvent( Event )
|
||||
end
|
||||
|
||||
Event.IniPlayerName = Event.IniDCSUnit:getPlayerName()
|
||||
if Event.IniPlayerName then
|
||||
-- get UUCID
|
||||
local PID = NET.GetPlayerIDByName(nil,Event.IniPlayerName)
|
||||
if PID then
|
||||
Event.IniPlayerUCID = net.get_player_info(tonumber(PID), 'ucid')
|
||||
--env.info("Event.IniPlayerUCID="..tostring(Event.IniPlayerUCID),false)
|
||||
end
|
||||
end
|
||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
end
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.CARGO then
|
||||
elseif Event.IniObjectCategory == Object.Category.CARGO then
|
||||
---
|
||||
-- Cargo
|
||||
---
|
||||
@@ -1160,9 +1227,8 @@ function EVENT:onEvent( Event )
|
||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||
end
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.SCENERY then
|
||||
elseif Event.IniObjectCategory == Object.Category.SCENERY then
|
||||
---
|
||||
-- Scenery
|
||||
---
|
||||
@@ -1172,9 +1238,8 @@ function EVENT:onEvent( Event )
|
||||
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY"
|
||||
end
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.BASE then
|
||||
elseif Event.IniObjectCategory == Object.Category.BASE then
|
||||
---
|
||||
-- Base Object
|
||||
---
|
||||
@@ -1201,9 +1266,12 @@ function EVENT:onEvent( Event )
|
||||
---
|
||||
|
||||
-- Target category.
|
||||
Event.TgtObjectCategory = Event.target:getCategory()
|
||||
Event.TgtObjectCategory = Object.getCategory(Event.target)
|
||||
|
||||
if Event.TgtObjectCategory == Object.Category.UNIT then
|
||||
---
|
||||
-- UNIT
|
||||
---
|
||||
Event.TgtDCSUnit = Event.target
|
||||
Event.TgtDCSGroup = Event.TgtDCSUnit:getGroup()
|
||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
||||
@@ -1216,21 +1284,33 @@ function EVENT:onEvent( Event )
|
||||
Event.TgtGroupName = Event.TgtDCSGroupName
|
||||
end
|
||||
Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName()
|
||||
if Event.TgtPlayerName then
|
||||
-- get UUCID
|
||||
local PID = NET.GetPlayerIDByName(nil,Event.TgtPlayerName)
|
||||
if PID then
|
||||
Event.TgtPlayerUCID = net.get_player_info(tonumber(PID), 'ucid')
|
||||
--env.info("Event.TgtPlayerUCID="..tostring(Event.TgtPlayerUCID),false)
|
||||
end
|
||||
end
|
||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
end
|
||||
|
||||
if Event.TgtObjectCategory == Object.Category.STATIC then
|
||||
-- get base data
|
||||
elseif Event.TgtObjectCategory == Object.Category.STATIC then
|
||||
---
|
||||
-- STATIC
|
||||
---
|
||||
Event.TgtDCSUnit = Event.target
|
||||
if Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object
|
||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
|
||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
-- Workaround for borked target info on cruise missiles
|
||||
if Event.TgtDCSUnitName and Event.TgtDCSUnitName ~= "" then
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
|
||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
end
|
||||
else
|
||||
Event.TgtDCSUnitName = string.format("No target object for Event ID %s", tostring(Event.id))
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
@@ -1249,9 +1329,11 @@ function EVENT:onEvent( Event )
|
||||
Event.TgtTypeName = "Static"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Event.TgtObjectCategory == Object.Category.SCENERY then
|
||||
elseif Event.TgtObjectCategory == Object.Category.SCENERY then
|
||||
---
|
||||
-- SCENERY
|
||||
---
|
||||
Event.TgtDCSUnit = Event.target
|
||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
@@ -1266,7 +1348,8 @@ function EVENT:onEvent( Event )
|
||||
Event.Weapon = Event.weapon
|
||||
Event.WeaponName = Event.Weapon:getTypeName()
|
||||
Event.WeaponUNIT = CLIENT:Find( Event.Weapon, '', true ) -- Sometimes, the weapon is a player unit!
|
||||
Event.WeaponPlayerName = Event.WeaponUNIT and Event.Weapon:getPlayerName()
|
||||
Event.WeaponPlayerName = Event.WeaponUNIT and Event.Weapon.getPlayerName and Event.Weapon:getPlayerName()
|
||||
--Event.WeaponPlayerName = Event.WeaponUNIT and Event.Weapon:getPlayerName()
|
||||
Event.WeaponCoalition = Event.WeaponUNIT and Event.Weapon:getCoalition()
|
||||
Event.WeaponCategory = Event.WeaponUNIT and Event.Weapon:getDesc().category
|
||||
Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon:getTypeName()
|
||||
@@ -1281,7 +1364,7 @@ function EVENT:onEvent( Event )
|
||||
-- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground.
|
||||
--Event.Place=UNIT:Find(Event.place)
|
||||
else
|
||||
if Event.place:isExist() and Event.place:getCategory() ~= Object.Category.SCENERY then
|
||||
if Event.place:isExist() and Object.getCategory(Event.place) ~= Object.Category.SCENERY then
|
||||
Event.Place=AIRBASE:Find(Event.place)
|
||||
Event.PlaceName=Event.Place:GetName()
|
||||
end
|
||||
|
||||
@@ -249,7 +249,7 @@ do -- FSM
|
||||
--
|
||||
-- ### Linear Transition Example
|
||||
--
|
||||
-- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua)
|
||||
-- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE_MISSIONS/blob/master/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua)
|
||||
--
|
||||
-- It models a unit standing still near Batumi, and flaring every 5 seconds while switching between a Green flare and a Red flare.
|
||||
-- The purpose of this example is not to show how exciting flaring is, but it demonstrates how a Linear Transition FSM can be build.
|
||||
@@ -1260,7 +1260,7 @@ do -- FSM_PROCESS
|
||||
|
||||
--- Assign the process to a @{Wrapper.Unit} and activate the process.
|
||||
-- @param #FSM_PROCESS self
|
||||
-- @param Task.Tasking#TASK Task
|
||||
-- @param Tasking.Task#TASK Task
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @return #FSM_PROCESS self
|
||||
function FSM_PROCESS:Assign( ProcessUnit, Task )
|
||||
|
||||
@@ -513,7 +513,7 @@ do -- MENU_COALITION
|
||||
--- @type MENU_COALITION
|
||||
-- @extends Core.Menu#MENU_BASE
|
||||
|
||||
--- Manages the main menus for @{DCS.coalition}s.
|
||||
--- Manages the main menus for DCS.coalition.
|
||||
--
|
||||
-- You can add menus with the @{#MENU_COALITION.New} method, which constructs a MENU_COALITION object and returns you the object reference.
|
||||
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION.Remove}.
|
||||
|
||||
@@ -73,7 +73,7 @@ MESSAGE.Type = {
|
||||
Detailed = "Detailed Report",
|
||||
}
|
||||
|
||||
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
|
||||
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{#MESSAGE.ToClient} or @{#MESSAGE.ToCoalition} or @{#MESSAGE.ToAll} to send these Messages to the respective recipients.
|
||||
-- @param self
|
||||
-- @param #string MessageText is the text of the Message.
|
||||
-- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel.
|
||||
@@ -127,7 +127,7 @@ end
|
||||
|
||||
--- Creates a new MESSAGE object of a certain type.
|
||||
-- Note that these MESSAGE objects are not yet displayed on the display panel.
|
||||
-- You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
|
||||
-- You must use the functions @{Core.Message#ToClient} or @{Core.Message#ToCoalition} or @{Core.Message#ToAll} to send these Messages to the respective recipients.
|
||||
-- The message display times are automatically defined based on the timing settings in the @{Core.Settings} menu.
|
||||
-- @param self
|
||||
-- @param #string MessageText is the text of the Message.
|
||||
@@ -343,7 +343,7 @@ end
|
||||
|
||||
--- Sends a MESSAGE to a Coalition.
|
||||
-- @param #MESSAGE self
|
||||
-- @param #DCS.coalition.side CoalitionSide @{#DCS.coalition.side} to which the message is displayed.
|
||||
-- @param DCS#coalition.side CoalitionSide @{#DCS.coalition.side} to which the message is displayed.
|
||||
-- @param Core.Settings#SETTINGS Settings (Optional) Settings for message display.
|
||||
-- @return #MESSAGE Message object.
|
||||
-- @usage
|
||||
@@ -379,7 +379,7 @@ end
|
||||
|
||||
--- Sends a MESSAGE to a Coalition if the given Condition is true.
|
||||
-- @param #MESSAGE self
|
||||
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}.
|
||||
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{#DCS.coalition.side}.
|
||||
-- @param #boolean Condition Sends the message only if the condition is true.
|
||||
-- @return #MESSAGE self
|
||||
function MESSAGE:ToCoalitionIf( CoalitionSide, Condition )
|
||||
@@ -465,7 +465,7 @@ _MESSAGESRS = {}
|
||||
-- @param #string PathToCredentials (optional) Path to credentials file for e.g. Google.
|
||||
-- @param #number Frequency Frequency in MHz. Can also be given as a #table of frequencies.
|
||||
-- @param #number Modulation Modulation, i.e. radio.modulation.AM or radio.modulation.FM. Can also be given as a #table of modulations.
|
||||
-- @param #string Gender (optional) Gender, i.e. "male" or "female", defaults to "male".
|
||||
-- @param #string Gender (optional) Gender, i.e. "male" or "female", defaults to "female".
|
||||
-- @param #string Culture (optional) Culture, e.g. "en-US", defaults to "en-GB"
|
||||
-- @param #string Voice (optional) Voice. Will override gender and culture settings, e.g. MSRS.Voices.Microsoft.Hazel or MSRS.Voices.Google.Standard.de_DE_Standard_D. Hint on Microsoft voices - working voices are limited to Hedda, Hazel, David, Zira and Hortense. **Must** be installed on your Desktop or Server!
|
||||
-- @param #number Coalition (optional) Coalition, can be coalition.side.RED, coalition.side.BLUE or coalition.side.NEUTRAL. Defaults to coalition.side.NEUTRAL.
|
||||
@@ -480,24 +480,42 @@ _MESSAGESRS = {}
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||
--
|
||||
function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,Gender,Culture,Voice,Coalition,Volume,Label,Coordinate)
|
||||
_MESSAGESRS.MSRS = MSRS:New(PathToSRS,Frequency,Modulation,Volume)
|
||||
_MESSAGESRS.MSRS:SetCoalition(Coalition)
|
||||
_MESSAGESRS.MSRS = MSRS:New(PathToSRS,Frequency or 243,Modulation or radio.modulation.AM,Volume)
|
||||
|
||||
_MESSAGESRS.frequency = Frequency
|
||||
_MESSAGESRS.modulation = Modulation or radio.modulation.AM
|
||||
|
||||
_MESSAGESRS.MSRS:SetCoalition(Coalition or coalition.side.NEUTRAL)
|
||||
_MESSAGESRS.coalition = Coalition or coalition.side.NEUTRAL
|
||||
|
||||
_MESSAGESRS.coordinate = Coordinate
|
||||
_MESSAGESRS.MSRS:SetCoordinate(Coordinate)
|
||||
|
||||
_MESSAGESRS.MSRS:SetCulture(Culture)
|
||||
_MESSAGESRS.Culture = Culture
|
||||
--_MESSAGESRS.MSRS:SetFrequencies(Frequency)
|
||||
_MESSAGESRS.Culture = Culture or "en-GB"
|
||||
|
||||
_MESSAGESRS.MSRS:SetGender(Gender)
|
||||
_MESSAGESRS.Gender = Gender
|
||||
_MESSAGESRS.Gender = Gender or "female"
|
||||
|
||||
_MESSAGESRS.MSRS:SetGoogle(PathToCredentials)
|
||||
_MESSAGESRS.google = PathToCredentials
|
||||
|
||||
_MESSAGESRS.MSRS:SetLabel(Label or "MESSAGE")
|
||||
--_MESSAGESRS.MSRS:SetModulations(Modulation)
|
||||
--_MESSAGESRS.MSRS:SetPath(PathToSRS)
|
||||
_MESSAGESRS.MSRS:SetPort(Port)
|
||||
-- _MESSAGESRS.MSRS:SetVolume(Volume)
|
||||
_MESSAGESRS.MSRS:SetVoice(Voice)
|
||||
_MESSAGESRS.Voice = Voice
|
||||
_MESSAGESRS.label = Label or "MESSAGE"
|
||||
|
||||
_MESSAGESRS.MSRS:SetPort(Port or 5002)
|
||||
_MESSAGESRS.port = Port or 5002
|
||||
|
||||
_MESSAGESRS.volume = Volume or 1
|
||||
_MESSAGESRS.MSRS:SetVolume(_MESSAGESRS.volume)
|
||||
|
||||
if Voice then _MESSAGESRS.MSRS:SetVoice(Voice) end
|
||||
|
||||
_MESSAGESRS.voice = Voice --or MSRS.Voices.Microsoft.Hedda
|
||||
--if _MESSAGESRS.google and not Voice then _MESSAGESRS.Voice = MSRS.Voices.Google.Standard.en_GB_Standard_A end
|
||||
--_MESSAGESRS.MSRS:SetVoice(Voice or _MESSAGESRS.voice)
|
||||
|
||||
_MESSAGESRS.SRSQ = MSRSQUEUE:New(Label or "MESSAGE")
|
||||
env.info(_MESSAGESRS.MSRS.provider,false)
|
||||
end
|
||||
|
||||
--- Sends a message via SRS.
|
||||
@@ -505,7 +523,7 @@ end
|
||||
-- @param #number frequency (optional) Frequency in MHz. Can also be given as a #table of frequencies. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting.
|
||||
-- @param #number modulation (optional) Modulation, i.e. radio.modulation.AM or radio.modulation.FM. Can also be given as a #table of modulations. Only needed if you want to override defaults set with `MESSAGE.SetMSRS()` for this one setting.
|
||||
-- @param #string gender (optional) Gender, i.e. "male" or "female". Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string culture (optional) Culture, e.g. "en-US. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string culture (optional) Culture, e.g. "en-US". Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #string voice (optional) Voice. Will override gender and culture settings. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #number coalition (optional) Coalition, can be coalition.side.RED, coalition.side.BLUE or coalition.side.NEUTRAL. Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
-- @param #number volume (optional) Volume, can be between 0.0 and 1.0 (loudest). Only needed if you want to change defaults set with `MESSAGE.SetMSRS()`.
|
||||
@@ -519,9 +537,16 @@ end
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||
--
|
||||
function MESSAGE:ToSRS(frequency,modulation,gender,culture,voice,coalition,volume,coordinate)
|
||||
local tgender = gender or _MESSAGESRS.Gender
|
||||
if _MESSAGESRS.SRSQ then
|
||||
_MESSAGESRS.MSRS:SetVoice(voice or _MESSAGESRS.Voice)
|
||||
_MESSAGESRS.SRSQ:NewTransmission(self.MessageText,nil,_MESSAGESRS.MSRS,nil,nil,nil,nil,nil,frequency,modulation,gender or _MESSAGESRS.Gender,culture or _MESSAGESRS.Culture,voice or _MESSAGESRS.Voice,volume,self.MessageCategory)
|
||||
if voice then
|
||||
_MESSAGESRS.MSRS:SetVoice(voice or _MESSAGESRS.voice)
|
||||
end
|
||||
if coordinate then
|
||||
_MESSAGESRS.MSRS:SetCoordinate(coordinate)
|
||||
end
|
||||
local category = string.gsub(self.MessageCategory,":","")
|
||||
_MESSAGESRS.SRSQ:NewTransmission(self.MessageText,nil,_MESSAGESRS.MSRS,nil,nil,nil,nil,nil,frequency or _MESSAGESRS.frequency,modulation or _MESSAGESRS.modulation, gender or _MESSAGESRS.Gender,culture or _MESSAGESRS.Culture,nil,volume or _MESSAGESRS.volume,category,coordinate or _MESSAGESRS.coordinate)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -199,7 +199,7 @@ end
|
||||
|
||||
--- Get points of pathline. Not that points are tables, that contain more information as just the 2D or 3D position but also the surface type etc.
|
||||
-- @param #PATHLINE self
|
||||
-- @return <#PATHLINE.Point> List of points.
|
||||
-- @return #list <#PATHLINE.Point> List of points.
|
||||
function PATHLINE:GetPoints()
|
||||
return self.points
|
||||
end
|
||||
|
||||
@@ -8,22 +8,6 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # Demo Missions
|
||||
--
|
||||
-- ### [POINT_VEC Demo Missions source code]()
|
||||
--
|
||||
-- ### [POINT_VEC Demo Missions, only for beta testers]()
|
||||
--
|
||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # YouTube Channel
|
||||
--
|
||||
-- ### [POINT_VEC YouTube Channel]()
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Authors:
|
||||
--
|
||||
-- * FlightControl (Design & Programming)
|
||||
@@ -544,7 +528,7 @@ do -- COORDINATE
|
||||
if ZoneObject then
|
||||
|
||||
-- Get category of scanned object.
|
||||
local ObjectCategory = ZoneObject:getCategory()
|
||||
local ObjectCategory = Object.getCategory(ZoneObject)
|
||||
|
||||
-- Check for unit or static objects
|
||||
if ObjectCategory==Object.Category.UNIT and ZoneObject:isExist() then
|
||||
@@ -920,7 +904,7 @@ do -- COORDINATE
|
||||
end
|
||||
|
||||
|
||||
--- Return an angle in radians from the COORDINATE using a direction vector in Vec3 format.
|
||||
--- Return an angle in radians from the COORDINATE using a **direction vector in Vec3 format**.
|
||||
-- @param #COORDINATE self
|
||||
-- @param DCS#Vec3 DirectionVec3 The direction vector in Vec3 format.
|
||||
-- @return #number DirectionRadians The angle in radians.
|
||||
@@ -933,10 +917,12 @@ do -- COORDINATE
|
||||
return DirectionRadians
|
||||
end
|
||||
|
||||
--- Return an angle in degrees from the COORDINATE using a direction vector in Vec3 format.
|
||||
--- Return an angle in degrees from the COORDINATE using a **direction vector in Vec3 format**.
|
||||
-- @param #COORDINATE self
|
||||
-- @param DCS#Vec3 DirectionVec3 The direction vector in Vec3 format.
|
||||
-- @return #number DirectionRadians The angle in degrees.
|
||||
-- @usage
|
||||
-- local directionAngle = currentCoordinate:GetAngleDegrees(currentCoordinate:GetDirectionVec3(sourceCoordinate:GetVec3()))
|
||||
function COORDINATE:GetAngleDegrees( DirectionVec3 )
|
||||
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
||||
local Angle = UTILS.ToDegree( AngleRadians )
|
||||
@@ -3021,6 +3007,16 @@ do -- COORDINATE
|
||||
return BRAANATO
|
||||
end
|
||||
|
||||
--- Return the BULLSEYE as COORDINATE Object
|
||||
-- @param #number Coalition Coalition of the bulls eye to return, e.g. coalition.side.BLUE
|
||||
-- @return #COORDINATE self
|
||||
-- @usage
|
||||
-- -- note the dot (.) here,not using the colon (:)
|
||||
-- local redbulls = COORDINATE.GetBullseyeCoordinate(coalition.side.RED)
|
||||
function COORDINATE.GetBullseyeCoordinate(Coalition)
|
||||
return COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) )
|
||||
end
|
||||
|
||||
--- Return a BULLS string out of the BULLS of the coalition to the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param DCS#coalition.side Coalition The coalition.
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
--
|
||||
-- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**.
|
||||
-- The ScheduleID is returned when the method @{#SCHEDULER.Schedule}() is called.
|
||||
-- It is recommended to store the ScheduleID in a variable, as it is used in the methods @{SCHEDULER.Start}() and @{SCHEDULER.Stop}(),
|
||||
-- It is recommended to store the ScheduleID in a variable, as it is used in the methods @{#SCHEDULER.Start}() and @{#SCHEDULER.Stop}(),
|
||||
-- which can start and stop specific repeating schedules respectively within a SCHEDULER object.
|
||||
--
|
||||
-- ## SCHEDULER constructor
|
||||
|
||||
@@ -1065,8 +1065,15 @@ do
|
||||
self:FilterActive( false )
|
||||
|
||||
return self
|
||||
|
||||
--- Filter the set once
|
||||
-- @function [parent=#SET_GROUP] FilterOnce
|
||||
-- @param #SET_GROUP self
|
||||
-- @return #SET_GROUP self
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Get a *new* set that only contains alive groups.
|
||||
-- @param #SET_GROUP self
|
||||
-- @return #SET_GROUP Set of alive groups.
|
||||
@@ -1976,6 +1983,7 @@ do
|
||||
--- Get the closest group of the set with respect to a given reference coordinate. Optionally, only groups of given coalitions are considered in the search.
|
||||
-- @param #SET_GROUP self
|
||||
-- @param Core.Point#COORDINATE Coordinate Reference Coordinate from which the closest group is determined.
|
||||
-- @param #table Coalitions (Optional) Table of coalition #number entries to filter for.
|
||||
-- @return Wrapper.Group#GROUP The closest group (if any).
|
||||
-- @return #number Distance in meters to the closest group.
|
||||
function SET_GROUP:GetClosestGroup(Coordinate, Coalitions)
|
||||
@@ -2425,6 +2433,26 @@ do -- SET_UNIT
|
||||
return CountU
|
||||
end
|
||||
|
||||
--- Gets the alive set.
|
||||
-- @param #SET_UNIT self
|
||||
-- @return #table Table of SET objects
|
||||
-- @return #SET_UNIT AliveSet
|
||||
function SET_UNIT:GetAliveSet()
|
||||
|
||||
local AliveSet = SET_UNIT:New()
|
||||
|
||||
-- Clean the Set before returning with only the alive Groups.
|
||||
for GroupName, GroupObject in pairs(self.Set) do
|
||||
local GroupObject=GroupObject --Wrapper.Client#CLIENT
|
||||
|
||||
if GroupObject and GroupObject:IsAlive() then
|
||||
AliveSet:Add(GroupName, GroupObject)
|
||||
end
|
||||
end
|
||||
|
||||
return AliveSet.Set or {}, AliveSet
|
||||
end
|
||||
|
||||
--- [Internal] Private function for use of continous zone filter
|
||||
-- @param #SET_UNIT self
|
||||
-- @return #SET_UNIT self
|
||||
@@ -2819,51 +2847,58 @@ do -- SET_UNIT
|
||||
-- @param #SET_UNIT self
|
||||
-- @return Core.Point#COORDINATE The center coordinate of all the units in the set, including heading in degrees and speed in mps in case of moving units.
|
||||
function SET_UNIT:GetCoordinate()
|
||||
|
||||
local Coordinate = self:GetRandom():GetCoordinate()
|
||||
--self:F({Coordinate:GetVec3()})
|
||||
|
||||
|
||||
local x1 = Coordinate.x
|
||||
local x2 = Coordinate.x
|
||||
local y1 = Coordinate.y
|
||||
local y2 = Coordinate.y
|
||||
local z1 = Coordinate.z
|
||||
local z2 = Coordinate.z
|
||||
local MaxVelocity = 0
|
||||
local AvgHeading = nil
|
||||
local MovingCount = 0
|
||||
|
||||
for UnitName, UnitData in pairs( self:GetSet() ) do
|
||||
|
||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||
local Coordinate = Unit:GetCoordinate()
|
||||
|
||||
x1 = (Coordinate.x < x1) and Coordinate.x or x1
|
||||
x2 = (Coordinate.x > x2) and Coordinate.x or x2
|
||||
y1 = (Coordinate.y < y1) and Coordinate.y or y1
|
||||
y2 = (Coordinate.y > y2) and Coordinate.y or y2
|
||||
z1 = (Coordinate.y < z1) and Coordinate.z or z1
|
||||
z2 = (Coordinate.y > z2) and Coordinate.z or z2
|
||||
|
||||
local Velocity = Coordinate:GetVelocity()
|
||||
if Velocity ~= 0 then
|
||||
MaxVelocity = (MaxVelocity < Velocity) and Velocity or MaxVelocity
|
||||
local Heading = Coordinate:GetHeading()
|
||||
AvgHeading = AvgHeading and (AvgHeading + Heading) or Heading
|
||||
MovingCount = MovingCount + 1
|
||||
end
|
||||
local Coordinate = nil
|
||||
local unit = self:GetRandom()
|
||||
if self:Count() == 1 and unit then
|
||||
return unit:GetCoordinate()
|
||||
end
|
||||
if unit then
|
||||
local Coordinate = unit:GetCoordinate()
|
||||
--self:F({Coordinate:GetVec3()})
|
||||
|
||||
|
||||
local x1 = Coordinate.x
|
||||
local x2 = Coordinate.x
|
||||
local y1 = Coordinate.y
|
||||
local y2 = Coordinate.y
|
||||
local z1 = Coordinate.z
|
||||
local z2 = Coordinate.z
|
||||
local MaxVelocity = 0
|
||||
local AvgHeading = nil
|
||||
local MovingCount = 0
|
||||
|
||||
for UnitName, UnitData in pairs( self:GetAliveSet() ) do
|
||||
|
||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||
local Coordinate = Unit:GetCoordinate()
|
||||
|
||||
x1 = (Coordinate.x < x1) and Coordinate.x or x1
|
||||
x2 = (Coordinate.x > x2) and Coordinate.x or x2
|
||||
y1 = (Coordinate.y < y1) and Coordinate.y or y1
|
||||
y2 = (Coordinate.y > y2) and Coordinate.y or y2
|
||||
z1 = (Coordinate.y < z1) and Coordinate.z or z1
|
||||
z2 = (Coordinate.y > z2) and Coordinate.z or z2
|
||||
|
||||
local Velocity = Coordinate:GetVelocity()
|
||||
if Velocity ~= 0 then
|
||||
MaxVelocity = (MaxVelocity < Velocity) and Velocity or MaxVelocity
|
||||
local Heading = Coordinate:GetHeading()
|
||||
AvgHeading = AvgHeading and (AvgHeading + Heading) or Heading
|
||||
MovingCount = MovingCount + 1
|
||||
end
|
||||
end
|
||||
|
||||
AvgHeading = AvgHeading and (AvgHeading / MovingCount)
|
||||
|
||||
Coordinate.x = (x2 - x1) / 2 + x1
|
||||
Coordinate.y = (y2 - y1) / 2 + y1
|
||||
Coordinate.z = (z2 - z1) / 2 + z1
|
||||
Coordinate:SetHeading( AvgHeading )
|
||||
Coordinate:SetVelocity( MaxVelocity )
|
||||
|
||||
self:F( { Coordinate = Coordinate } )
|
||||
end
|
||||
|
||||
AvgHeading = AvgHeading and (AvgHeading / MovingCount)
|
||||
|
||||
Coordinate.x = (x2 - x1) / 2 + x1
|
||||
Coordinate.y = (y2 - y1) / 2 + y1
|
||||
Coordinate.z = (z2 - z1) / 2 + z1
|
||||
Coordinate:SetHeading( AvgHeading )
|
||||
Coordinate:SetVelocity( MaxVelocity )
|
||||
|
||||
self:F( { Coordinate = Coordinate } )
|
||||
return Coordinate
|
||||
|
||||
end
|
||||
@@ -4317,6 +4352,8 @@ do -- SET_CLIENT
|
||||
self:UnHandleEvent(EVENTS.Birth)
|
||||
self:UnHandleEvent(EVENTS.Dead)
|
||||
self:UnHandleEvent(EVENTS.Crash)
|
||||
--self:UnHandleEvent(EVENTS.PlayerEnterUnit)
|
||||
--self:UnHandleEvent(EVENTS.PlayerLeaveUnit)
|
||||
|
||||
if self.Filter.Zones and self.ZoneTimer and self.ZoneTimer:IsRunning() then
|
||||
self.ZoneTimer:Stop()
|
||||
@@ -4335,6 +4372,9 @@ do -- SET_CLIENT
|
||||
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
|
||||
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
|
||||
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
||||
--self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventPlayerEnterUnit)
|
||||
--self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventPlayerLeaveUnit)
|
||||
--self:SetEventPriority(1)
|
||||
if self.Filter.Zones then
|
||||
self.ZoneTimer = TIMER:New(self._ContinousZoneFilter,self)
|
||||
local timing = self.ZoneTimerInterval or 30
|
||||
@@ -4345,6 +4385,43 @@ do -- SET_CLIENT
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Handle CA slots addition
|
||||
-- @param #SET_CLIENT self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
-- @return #SET_CLIENT self
|
||||
function SET_CLIENT:_EventPlayerEnterUnit(Event)
|
||||
self:I( "_EventPlayerEnterUnit" )
|
||||
if Event.IniDCSUnit then
|
||||
if Event.IniObjectCategory == 1 and Event.IniGroup and Event.IniGroup:IsGround() then
|
||||
-- CA Slot entered
|
||||
local ObjectName, Object = self:AddInDatabase( Event )
|
||||
self:I( ObjectName, UTILS.PrintTableToLog(Object) )
|
||||
if Object and self:IsIncludeObject( Object ) then
|
||||
self:Add( ObjectName, Object )
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Handle CA slots removal
|
||||
-- @param #SET_CLIENT self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
-- @return #SET_CLIENT self
|
||||
function SET_CLIENT:_EventPlayerLeaveUnit(Event)
|
||||
self:I( "_EventPlayerLeaveUnit" )
|
||||
if Event.IniDCSUnit then
|
||||
if Event.IniObjectCategory == 1 and Event.IniGroup and Event.IniGroup:IsGround() then
|
||||
-- CA Slot left
|
||||
local ObjectName, Object = self:FindInDatabase( Event )
|
||||
if ObjectName then
|
||||
self:Remove( ObjectName )
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
|
||||
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
||||
@@ -5471,7 +5548,7 @@ do -- SET_CARGO
|
||||
|
||||
--- (R2.1) Remove CARGOs from SET_CARGO.
|
||||
-- @param Core.Set#SET_CARGO self
|
||||
-- @param Wrapper.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names.
|
||||
-- @param Cargo.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names.
|
||||
-- @return Core.Set#SET_CARGO self
|
||||
function SET_CARGO:RemoveCargosByName( RemoveCargoNames ) -- R2.1
|
||||
|
||||
@@ -5487,7 +5564,7 @@ do -- SET_CARGO
|
||||
--- (R2.1) Finds a Cargo based on the Cargo Name.
|
||||
-- @param #SET_CARGO self
|
||||
-- @param #string CargoName
|
||||
-- @return Wrapper.Cargo#CARGO The found Cargo.
|
||||
-- @return Cargo.Cargo#CARGO The found Cargo.
|
||||
function SET_CARGO:FindCargo( CargoName ) -- R2.1
|
||||
|
||||
local CargoFound = self.Set[CargoName]
|
||||
@@ -5630,7 +5707,7 @@ do -- SET_CARGO
|
||||
--- (R2.1) Iterate the SET_CARGO while identifying the nearest @{Cargo.Cargo#CARGO} from a @{Core.Point#POINT_VEC2}.
|
||||
-- @param #SET_CARGO self
|
||||
-- @param Core.Point#POINT_VEC2 PointVec2 A @{Core.Point#POINT_VEC2} object from where to evaluate the closest @{Cargo.Cargo#CARGO}.
|
||||
-- @return Wrapper.Cargo#CARGO The closest @{Cargo.Cargo#CARGO}.
|
||||
-- @return Cargo.Cargo#CARGO The closest @{Cargo.Cargo#CARGO}.
|
||||
function SET_CARGO:FindNearestCargoFromPointVec2( PointVec2 ) -- R2.1
|
||||
self:F2( PointVec2 )
|
||||
|
||||
@@ -6195,7 +6272,7 @@ do -- SET_ZONE
|
||||
|
||||
--- Start watching if the Object or Objects move into or out of our set of zones.
|
||||
-- @param #SET_ZONE self
|
||||
-- @param Wrappe.Controllable#CONTROLLABLE Objects Object or Objects to watch, can be of type UNIT, GROUP, CLIENT, or SET\_UNIT, SET\_GROUP, SET\_CLIENT
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Objects Object or Objects to watch, can be of type UNIT, GROUP, CLIENT, or SET\_UNIT, SET\_GROUP, SET\_CLIENT
|
||||
-- @return #SET_ZONE self
|
||||
-- @usage
|
||||
-- -- Create a SET_GROUP and a SET_ZONE for this:
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
--
|
||||
-- Will customize which display format is used to indicate A2G coordinates in text as part of the Command Center communications.
|
||||
--
|
||||
-- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_(navigation)).
|
||||
-- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_\(navigation\)).
|
||||
-- - A2G MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
|
||||
-- - A2G LL DMS: Latitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
|
||||
-- - A2G LL DDM: Latitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
|
||||
@@ -105,9 +105,9 @@
|
||||
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
|
||||
--
|
||||
-- - @{#SETTINGS.SetA2G_BR}(): Enable the BR display formatting by default.
|
||||
-- - @{#SETTINGS.SetA2G_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2G_MGRS}(): Enable the MGRS display formatting by default. Use @{#SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
--
|
||||
-- ### 3.1.4) A2G coordinates setting - additional notes
|
||||
--
|
||||
@@ -120,7 +120,7 @@
|
||||
--
|
||||
-- Will customize which display format is used to indicate A2A coordinates in text as part of the Command Center communications.
|
||||
--
|
||||
-- - A2A BRAA: [Bearing Range Altitude Aspect](https://en.wikipedia.org/wiki/Bearing_(navigation)).
|
||||
-- - A2A BRAA: [Bearing Range Altitude Aspect](https://en.wikipedia.org/wiki/Bearing_\(navigation\)).
|
||||
-- - A2A MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
|
||||
-- - A2A LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
|
||||
-- - A2A LL DDM: Lattitude Longitude [Decimal Degrees and Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
|
||||
@@ -135,9 +135,9 @@
|
||||
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
|
||||
--
|
||||
-- - @{#SETTINGS.SetA2A_BRAA}(): Enable the BR display formatting by default.
|
||||
-- - @{#SETTINGS.SetA2A_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_MGRS}(): Enable the MGRS display formatting by default. Use @{#SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{#SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
|
||||
-- - @{#SETTINGS.SetA2A_BULLS}(): Enable the BULLSeye display formatting by default.
|
||||
--
|
||||
-- ### 3.2.4) A2A coordinates settings - additional notes
|
||||
@@ -190,8 +190,8 @@
|
||||
--
|
||||
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
|
||||
--
|
||||
-- - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
-- - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
-- - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Core.Message#MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
-- - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Core.Message#MESSAGE.MessageType} the duration to be displayed in seconds.
|
||||
--
|
||||
-- ## 3.5) **Era** of the battle
|
||||
--
|
||||
@@ -283,21 +283,21 @@ do -- SETTINGS
|
||||
function SETTINGS:SetMetric()
|
||||
self.Metric = true
|
||||
end
|
||||
|
||||
|
||||
--- Sets the SETTINGS default text locale.
|
||||
-- @param #SETTINGS self
|
||||
-- @param #string Locale
|
||||
function SETTINGS:SetLocale(Locale)
|
||||
self.Locale = Locale or "en"
|
||||
end
|
||||
|
||||
|
||||
--- Gets the SETTINGS text locale.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #string
|
||||
function SETTINGS:GetLocale()
|
||||
return self.Locale or _SETTINGS:GetLocale()
|
||||
end
|
||||
|
||||
|
||||
--- Gets if the SETTINGS is metric.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if metric.
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
-- @field #SPAWN.SpawnZoneTable SpawnZoneTable
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- Allows to spawn dynamically new @{Core.Group}s.
|
||||
--- Allows to spawn dynamically new @{Wrapper.Group}s.
|
||||
--
|
||||
-- Each SPAWN object needs to be have related **template groups** setup in the Mission Editor (ME),
|
||||
-- which is a normal group with the **Late Activation** flag set.
|
||||
@@ -320,7 +320,7 @@ function SPAWN:New( SpawnTemplatePrefix )
|
||||
self.AIOnOff = true -- The AI is on by default when spawning a group.
|
||||
self.SpawnUnControlled = false
|
||||
self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name.
|
||||
self.DelayOnOff = false -- No intial delay when spawning the first group.
|
||||
self.DelayOnOff = false -- No initial delay when spawning the first group.
|
||||
self.SpawnGrouping = nil -- No grouping.
|
||||
self.SpawnInitLivery = nil -- No special livery.
|
||||
self.SpawnInitSkill = nil -- No special skill.
|
||||
@@ -332,6 +332,7 @@ function SPAWN:New( SpawnTemplatePrefix )
|
||||
self.SpawnInitModexPostfix = nil
|
||||
self.SpawnInitAirbase = nil
|
||||
self.TweakedTemplate = false -- Check if the user is using self made template.
|
||||
self.SpawnRandomCallsign = false
|
||||
|
||||
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
|
||||
else
|
||||
@@ -1099,6 +1100,14 @@ function SPAWN:InitRandomizeZones( SpawnZoneTable )
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR/Fighter only!] This method randomizes the callsign for a new group.
|
||||
-- @param #SPAWN self
|
||||
-- @return #SPAWN self
|
||||
function SPAWN:InitRandomizeCallsign()
|
||||
self.SpawnRandomCallsign = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- This method sets a spawn position for the group that is different from the location of the template.
|
||||
-- @param #SPAWN self
|
||||
-- @param Core.Point#COORDINATE Coordinate The position to spawn from
|
||||
@@ -1331,7 +1340,7 @@ do -- Delay methods
|
||||
return self
|
||||
end
|
||||
|
||||
--- Turns the Delay On for the @{Wrapper.Group} when spawning with @{SpawnScheduled}(). In effect then the 1st group will only be spawned
|
||||
--- Turns the Delay On for the @{Wrapper.Group} when spawning with @{#SpawnScheduled}(). In effect then the 1st group will only be spawned
|
||||
-- after the number of seconds given in SpawnScheduled as arguments, and not immediately.
|
||||
-- @param #SPAWN self
|
||||
-- @return #SPAWN The SPAWN object
|
||||
@@ -1669,7 +1678,7 @@ end
|
||||
-- @param #number SpawnTimeVariation The variation to be applied on the defined time interval between each new spawn.
|
||||
-- The variation is a number between 0 and 1, representing the % of variation to be applied on the time interval.
|
||||
-- @param #boolean WithDelay Do not spawn the **first** group immediately, but delay the spawn as per the calculation below.
|
||||
-- Effectively the same as @{InitDelayOn}().
|
||||
-- Effectively the same as @{#InitDelayOn}().
|
||||
-- @return #SPAWN self
|
||||
-- @usage
|
||||
-- -- NATO helicopters engaging in the battle field.
|
||||
@@ -2783,7 +2792,7 @@ end
|
||||
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||
-- @usage
|
||||
--
|
||||
-- local SpawnPointVec2 = ZONE:New( ZoneName ):GetPointVec2()
|
||||
-- local SpawnPointVec2 = ZONE:New( ZoneName ):GetPointVec2()
|
||||
--
|
||||
-- -- Spawn at the zone center position at the height specified in the ME of the group template!
|
||||
-- SpawnAirplanes:SpawnFromPointVec2( SpawnPointVec2 )
|
||||
@@ -3275,22 +3284,143 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
||||
end
|
||||
|
||||
-- Callsign
|
||||
|
||||
if self.SpawnRandomCallsign and SpawnTemplate.units[1].callsign then
|
||||
if type( SpawnTemplate.units[1].callsign ) ~= "number" then
|
||||
-- change callsign
|
||||
local min = 1
|
||||
local max = 8
|
||||
local ctable = CALLSIGN.Aircraft
|
||||
if string.find(SpawnTemplate.units[1].type, "A-10",1,true) then
|
||||
max = 12
|
||||
end
|
||||
if string.find(SpawnTemplate.units[1].type, "18",1,true) then
|
||||
min = 9
|
||||
max = 20
|
||||
ctable = CALLSIGN.F18
|
||||
end
|
||||
if string.find(SpawnTemplate.units[1].type, "16",1,true) then
|
||||
min = 9
|
||||
max = 20
|
||||
ctable = CALLSIGN.F16
|
||||
end
|
||||
if SpawnTemplate.units[1].type == "F-15E" then
|
||||
min = 9
|
||||
max = 18
|
||||
ctable = CALLSIGN.F15E
|
||||
end
|
||||
local callsignnr = math.random(min,max)
|
||||
local callsignname = "Enfield"
|
||||
for name, value in pairs(ctable) do
|
||||
if value==callsignnr then
|
||||
callsignname = name
|
||||
end
|
||||
end
|
||||
for UnitID = 1, #SpawnTemplate.units do
|
||||
SpawnTemplate.units[UnitID].callsign[1] = callsignnr
|
||||
SpawnTemplate.units[UnitID].callsign[2] = UnitID
|
||||
SpawnTemplate.units[UnitID].callsign[3] = "1"
|
||||
SpawnTemplate.units[UnitID].callsign["name"] = tostring(callsignname)..tostring(UnitID).."1"
|
||||
-- UTILS.PrintTableToLog(SpawnTemplate.units[UnitID].callsign,1)
|
||||
end
|
||||
else
|
||||
-- Russkis
|
||||
for UnitID = 1, #SpawnTemplate.units do
|
||||
SpawnTemplate.units[UnitID].callsign = math.random(1,999)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for UnitID = 1, #SpawnTemplate.units do
|
||||
local Callsign = SpawnTemplate.units[UnitID].callsign
|
||||
if Callsign then
|
||||
if type( Callsign ) ~= "number" then -- blue callsign
|
||||
-- UTILS.PrintTableToLog(Callsign,1)
|
||||
Callsign[2] = ((SpawnIndex - 1) % 10) + 1
|
||||
local CallsignName = SpawnTemplate.units[UnitID].callsign["name"] -- #string
|
||||
CallsignName = string.match(CallsignName,"^(%a+)") -- 2.8 - only the part w/o numbers
|
||||
local CallsignLen = CallsignName:len()
|
||||
SpawnTemplate.units[UnitID].callsign[2] = UnitID
|
||||
SpawnTemplate.units[UnitID].callsign["name"] = CallsignName:sub( 1, CallsignLen ) .. SpawnTemplate.units[UnitID].callsign[2] .. SpawnTemplate.units[UnitID].callsign[3]
|
||||
else
|
||||
SpawnTemplate.units[UnitID].callsign = Callsign + SpawnIndex
|
||||
end
|
||||
end
|
||||
-- Link16
|
||||
local AddProps = SpawnTemplate.units[UnitID].AddPropAircraft
|
||||
if AddProps then
|
||||
if SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 then
|
||||
-- 4 digit octal with leading 0
|
||||
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16) ~= nil then
|
||||
local octal = SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16
|
||||
local decimal = UTILS.OctalToDecimal(octal)+UnitID-1
|
||||
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",UTILS.DecimalToOctal(decimal))
|
||||
else -- ED bug - chars in here
|
||||
local STN = math.floor(UTILS.RandomGaussian(4088/2,nil,1000,4088))
|
||||
STN = STN+UnitID-1
|
||||
local OSTN = UTILS.DecimalToOctal(STN)
|
||||
SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 = string.format("%05d",OSTN)
|
||||
end
|
||||
end
|
||||
-- A10CII
|
||||
if SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN then
|
||||
-- 3 digit octal with leading 0
|
||||
if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN) ~= nil then
|
||||
local octal = SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN
|
||||
local decimal = UTILS.OctalToDecimal(octal)+UnitID-1
|
||||
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",UTILS.DecimalToOctal(decimal))
|
||||
else -- ED bug - chars in here
|
||||
local STN = math.floor(UTILS.RandomGaussian(504/2,nil,100,504))
|
||||
STN = STN+UnitID-1
|
||||
local OSTN = UTILS.DecimalToOctal(STN)
|
||||
SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN = string.format("%04d",OSTN)
|
||||
end
|
||||
end
|
||||
-- VoiceCallsignNumber
|
||||
if SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber then
|
||||
SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber = SpawnTemplate.units[UnitID].callsign[2] .. SpawnTemplate.units[UnitID].callsign[3]
|
||||
end
|
||||
-- VoiceCallsignLabel
|
||||
if SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignLabel then
|
||||
local CallsignName = SpawnTemplate.units[UnitID].callsign["name"] -- #string
|
||||
CallsignName = string.match(CallsignName,"^(%a+)") -- 2.8 - only the part w/o numbers
|
||||
local label = "NY" -- Navy One exception
|
||||
if not string.find(CallsignName," ") then
|
||||
label = string.upper(string.match(CallsignName,"^%a")..string.match(CallsignName,"%a$"))
|
||||
end
|
||||
SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignLabel = label
|
||||
end
|
||||
-- UTILS.PrintTableToLog(SpawnTemplate.units[UnitID].AddPropAircraft,1)
|
||||
-- FlightLead
|
||||
if SpawnTemplate.units[UnitID].datalinks and SpawnTemplate.units[UnitID].datalinks.Link16 and SpawnTemplate.units[UnitID].datalinks.Link16.settings then
|
||||
SpawnTemplate.units[UnitID].datalinks.Link16.settings.flightLead = UnitID == 1 and true or false
|
||||
end
|
||||
-- A10CII
|
||||
if SpawnTemplate.units[UnitID].datalinks and SpawnTemplate.units[UnitID].datalinks.SADL and SpawnTemplate.units[UnitID].datalinks.SADL.settings then
|
||||
SpawnTemplate.units[UnitID].datalinks.SADL.settings.flightLead = UnitID == 1 and true or false
|
||||
end
|
||||
-- UTILS.PrintTableToLog(SpawnTemplate.units[UnitID].datalinks,1)
|
||||
end
|
||||
end
|
||||
-- Link16 team members
|
||||
for UnitID = 1, #SpawnTemplate.units do
|
||||
if SpawnTemplate.units[UnitID].datalinks and SpawnTemplate.units[UnitID].datalinks.Link16 and SpawnTemplate.units[UnitID].datalinks.Link16.network then
|
||||
local team = {}
|
||||
local isF16 = string.find(SpawnTemplate.units[UnitID].type,"F-16",1,true) and true or false
|
||||
for ID = 1, #SpawnTemplate.units do
|
||||
local member = {}
|
||||
member.missionUnitId = ID
|
||||
if isF16 then
|
||||
member.TDOA = true
|
||||
end
|
||||
table.insert(team,member)
|
||||
end
|
||||
SpawnTemplate.units[UnitID].datalinks.Link16.network.teamMembers = team
|
||||
end
|
||||
end
|
||||
|
||||
self:T3( { "Template:", SpawnTemplate } )
|
||||
--UTILS.PrintTableToLog(SpawnTemplate,1)
|
||||
return SpawnTemplate
|
||||
|
||||
end
|
||||
@@ -3622,7 +3752,7 @@ function SPAWN:_OnLand( EventData )
|
||||
end
|
||||
|
||||
--- Will detect AIR Units shutting down their engines ...
|
||||
-- When the event takes place, and the method @{RepeatOnEngineShutDown} was called, the spawned Group will Re-SPAWN.
|
||||
-- When the event takes place, and the method @{#InitRepeatOnEngineShutDown} was called, the spawned Group will Re-SPAWN.
|
||||
-- But only when the Unit was registered to have landed.
|
||||
-- @param #SPAWN self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * [**Ciribob**](https://forums.eagle.ru/member.php?u=112175): Showing the way how to lase targets + how laser codes work!!! Explained the autolase script.
|
||||
-- * [**EasyEB**](https://forums.eagle.ru/member.php?u=112055): Ideas and Beta Testing
|
||||
-- * [**Wingthor**](https://forums.eagle.ru/member.php?u=123698): Beta Testing
|
||||
-- * **Ciribob**: Showing the way how to lase targets + how laser codes work!!! Explained the autolase script.
|
||||
-- * **EasyEB**: Ideas and Beta Testing
|
||||
-- * **Wingthor**: Beta Testing
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -329,14 +329,14 @@ do
|
||||
if self.Lasing then
|
||||
if self.Target and self.Target:IsAlive() then
|
||||
|
||||
self.SpotIR:setPoint( self.Target:GetPointVec3():AddY(1):AddY(math.random(-100,100)/100):AddX(math.random(-100,100)/100):GetVec3() )
|
||||
self.SpotIR:setPoint( self.Target:GetPointVec3():AddY(1):AddY(math.random(-100,100)/200):AddX(math.random(-100,100)/200):GetVec3() )
|
||||
self.SpotLaser:setPoint( self.Target:GetPointVec3():AddY(1):GetVec3() )
|
||||
|
||||
self:__Lasing(0.2)
|
||||
elseif self.TargetCoord then
|
||||
|
||||
-- Wiggle the IR spot a bit.
|
||||
local irvec3={x=self.TargetCoord.x+math.random(-100,100)/100, y=self.TargetCoord.y+math.random(-100,100)/100, z=self.TargetCoord.z} --#DCS.Vec3
|
||||
local irvec3={x=self.TargetCoord.x+math.random(-100,100)/200, y=self.TargetCoord.y+math.random(-100,100)/200, z=self.TargetCoord.z} --#DCS.Vec3
|
||||
local lsvec3={x=self.TargetCoord.x, y=self.TargetCoord.y, z=self.TargetCoord.z} --#DCS.Vec3
|
||||
|
||||
self.SpotIR:setPoint(irvec3)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,13 +20,15 @@
|
||||
-- ### Author: FlightControl - Framework Design & Programming
|
||||
-- ### Refactoring to use the Runway auto-detection: Applevangelist
|
||||
-- @date August 2022
|
||||
-- Last Update Nov 2023
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @module Functional.ATC_Ground
|
||||
-- @image Air_Traffic_Control_Ground_Operations.JPG
|
||||
|
||||
--- @type ATC_GROUND
|
||||
---
|
||||
-- @type ATC_GROUND
|
||||
-- @field Core.Set#SET_CLIENT SetClient
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
@@ -39,7 +41,8 @@ ATC_GROUND = {
|
||||
AirbaseNames = nil,
|
||||
}
|
||||
|
||||
--- @type ATC_GROUND.AirbaseNames
|
||||
---
|
||||
-- @type ATC_GROUND.AirbaseNames
|
||||
-- @list <#string>
|
||||
|
||||
|
||||
@@ -51,7 +54,7 @@ function ATC_GROUND:New( Airbases, AirbaseList )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #ATC_GROUND
|
||||
self:E( { self.ClassName, Airbases } )
|
||||
self:T( { self.ClassName, Airbases } )
|
||||
|
||||
self.Airbases = Airbases
|
||||
self.AirbaseList = AirbaseList
|
||||
@@ -82,7 +85,7 @@ function ATC_GROUND:New( Airbases, AirbaseList )
|
||||
end
|
||||
|
||||
self.SetClient:ForEachClient(
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
function( Client )
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0)
|
||||
@@ -246,11 +249,11 @@ function ATC_GROUND:SetMaximumKickSpeedMiph( MaximumKickSpeedMiph, Airbase )
|
||||
return self
|
||||
end
|
||||
|
||||
--- @param #ATC_GROUND self
|
||||
-- @param #ATC_GROUND self
|
||||
function ATC_GROUND:_AirbaseMonitor()
|
||||
|
||||
self.SetClient:ForEachClient(
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
function( Client )
|
||||
|
||||
if Client:IsAlive() then
|
||||
@@ -258,7 +261,7 @@ function ATC_GROUND:_AirbaseMonitor()
|
||||
local IsOnGround = Client:InAir() == false
|
||||
|
||||
for AirbaseID, AirbaseMeta in pairs( self.Airbases ) do
|
||||
self:E( AirbaseID, AirbaseMeta.KickSpeed )
|
||||
self:T( AirbaseID, AirbaseMeta.KickSpeed )
|
||||
|
||||
if AirbaseMeta.Monitor == true and Client:IsInZone( AirbaseMeta.ZoneBoundary ) then
|
||||
|
||||
@@ -271,7 +274,7 @@ function ATC_GROUND:_AirbaseMonitor()
|
||||
|
||||
if IsOnGround then
|
||||
local Taxi = Client:GetState( self, "Taxi" )
|
||||
self:E( Taxi )
|
||||
self:T( Taxi )
|
||||
if Taxi == false then
|
||||
local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed )
|
||||
Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " ..
|
||||
@@ -331,7 +334,7 @@ function ATC_GROUND:_AirbaseMonitor()
|
||||
Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
|
||||
else
|
||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
Client:Destroy()
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0 )
|
||||
@@ -363,7 +366,7 @@ function ATC_GROUND:_AirbaseMonitor()
|
||||
Client:SetState( self, "OffRunwayWarnings", OffRunwayWarnings + 1 )
|
||||
else
|
||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
Client:Destroy()
|
||||
Client:SetState( self, "IsOffRunway", false )
|
||||
Client:SetState( self, "OffRunwayWarnings", 0 )
|
||||
@@ -424,13 +427,20 @@ ATC_GROUND_UNIVERSAL = {
|
||||
|
||||
--- Creates a new ATC\_GROUND\_UNIVERSAL object. This works on any map.
|
||||
-- @param #ATC_GROUND_UNIVERSAL self
|
||||
-- @param AirbaseList (Optional) A table of Airbase Names.
|
||||
-- @param AirbaseList A table of Airbase Names. Leave empty to cover **all** airbases of the map.
|
||||
-- @return #ATC_GROUND_UNIVERSAL self
|
||||
-- @usage
|
||||
-- -- define monitoring for one airbase
|
||||
-- local atc=ATC_GROUND_UNIVERSAL:New({AIRBASE.Syria.Gecitkale})
|
||||
-- -- set kick speed
|
||||
-- atc:SetKickSpeed(UTILS.KnotsToMps(20))
|
||||
-- -- start monitoring evey 10 secs
|
||||
-- atc:Start(10)
|
||||
function ATC_GROUND_UNIVERSAL:New(AirbaseList)
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #ATC_GROUND
|
||||
self:E( { self.ClassName } )
|
||||
self:T( { self.ClassName } )
|
||||
|
||||
self.Airbases = {}
|
||||
|
||||
@@ -440,6 +450,13 @@ function ATC_GROUND_UNIVERSAL:New(AirbaseList)
|
||||
|
||||
self.AirbaseList = AirbaseList
|
||||
|
||||
if not self.AirbaseList then
|
||||
self.AirbaseList = {}
|
||||
for _name,_ in pairs(_DATABASE.AIRBASES) do
|
||||
self.AirbaseList[_name]=_name
|
||||
end
|
||||
end
|
||||
|
||||
self.SetClient = SET_CLIENT:New():FilterCategories( "plane" ):FilterStart()
|
||||
|
||||
|
||||
@@ -460,8 +477,9 @@ function ATC_GROUND_UNIVERSAL:New(AirbaseList)
|
||||
self.Airbases[AirbaseName].Monitor = true
|
||||
end
|
||||
|
||||
|
||||
self.SetClient:ForEachClient(
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
function( Client )
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0)
|
||||
@@ -679,7 +697,7 @@ end
|
||||
-- @param #ATC_GROUND_UNIVERSAL self
|
||||
-- @return #ATC_GROUND_UNIVERSAL self
|
||||
function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
|
||||
self:I("_AirbaseMonitor")
|
||||
self.SetClient:ForEachClient(
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
function( Client )
|
||||
@@ -689,7 +707,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
local IsOnGround = Client:InAir() == false
|
||||
|
||||
for AirbaseID, AirbaseMeta in pairs( self.Airbases ) do
|
||||
self:E( AirbaseID, AirbaseMeta.KickSpeed )
|
||||
self:T( AirbaseID, AirbaseMeta.KickSpeed )
|
||||
|
||||
if AirbaseMeta.Monitor == true and Client:IsInZone( AirbaseMeta.ZoneBoundary ) then
|
||||
|
||||
@@ -706,7 +724,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
|
||||
if IsOnGround then
|
||||
local Taxi = Client:GetState( self, "Taxi" )
|
||||
self:E( Taxi )
|
||||
self:T( Taxi )
|
||||
if Taxi == false then
|
||||
local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed )
|
||||
Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " ..
|
||||
@@ -766,7 +784,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
|
||||
else
|
||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
Client:Destroy()
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0 )
|
||||
@@ -798,7 +816,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
Client:SetState( self, "OffRunwayWarnings", OffRunwayWarnings + 1 )
|
||||
else
|
||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
--- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
Client:Destroy()
|
||||
Client:SetState( self, "IsOffRunway", false )
|
||||
Client:SetState( self, "OffRunwayWarnings", 0 )
|
||||
@@ -838,15 +856,16 @@ end
|
||||
|
||||
--- Start SCHEDULER for ATC_GROUND_UNIVERSAL object.
|
||||
-- @param #ATC_GROUND_UNIVERSAL self
|
||||
-- @param RepeatScanSeconds Time in second for defining occurency of alerts.
|
||||
-- @param RepeatScanSeconds Time in second for defining schedule of alerts.
|
||||
-- @return #ATC_GROUND_UNIVERSAL self
|
||||
function ATC_GROUND_UNIVERSAL:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
return self
|
||||
end
|
||||
|
||||
--- @type ATC_GROUND_CAUCASUS
|
||||
---
|
||||
-- @type ATC_GROUND_CAUCASUS
|
||||
-- @extends #ATC_GROUND
|
||||
|
||||
--- # ATC\_GROUND\_CAUCASUS, extends @{#ATC_GROUND_UNIVERSAL}
|
||||
@@ -981,12 +1000,12 @@ end
|
||||
-- @return nothing
|
||||
function ATC_GROUND_CAUCASUS:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @type ATC_GROUND_NEVADA
|
||||
---
|
||||
-- @type ATC_GROUND_NEVADA
|
||||
-- @extends #ATC_GROUND
|
||||
|
||||
|
||||
@@ -1120,11 +1139,11 @@ end
|
||||
-- @return nothing
|
||||
function ATC_GROUND_NEVADA:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
end
|
||||
|
||||
|
||||
--- @type ATC_GROUND_NORMANDY
|
||||
---
|
||||
-- @type ATC_GROUND_NORMANDY
|
||||
-- @extends #ATC_GROUND
|
||||
|
||||
|
||||
@@ -1277,10 +1296,11 @@ end
|
||||
-- @return nothing
|
||||
function ATC_GROUND_NORMANDY:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
end
|
||||
|
||||
--- @type ATC_GROUND_PERSIANGULF
|
||||
---
|
||||
-- @type ATC_GROUND_PERSIANGULF
|
||||
-- @extends #ATC_GROUND
|
||||
|
||||
|
||||
@@ -1419,11 +1439,11 @@ end
|
||||
-- @return nothing
|
||||
function ATC_GROUND_PERSIANGULF:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
end
|
||||
|
||||
|
||||
--- @type ATC_GROUND_MARIANAISLANDS
|
||||
-- @type ATC_GROUND_MARIANAISLANDS
|
||||
-- @extends #ATC_GROUND
|
||||
|
||||
|
||||
@@ -1517,7 +1537,7 @@ end
|
||||
-- * @{#ATC_GROUND.SetMaximumKickSpeedKmph}(): Set the maximum speed allowed at an airbase in kilometers per hour.
|
||||
-- * @{#ATC_GROUND.SetMaximumKickSpeedMiph}(): Set the maximum speed allowed at an airbase in miles per hour.
|
||||
--
|
||||
---- @field #ATC_GROUND_MARIANAISLANDS
|
||||
-- @field #ATC_GROUND_MARIANAISLANDS
|
||||
ATC_GROUND_MARIANAISLANDS = {
|
||||
ClassName = "ATC_GROUND_MARIANAISLANDS",
|
||||
}
|
||||
@@ -1529,7 +1549,7 @@ ATC_GROUND_MARIANAISLANDS = {
|
||||
function ATC_GROUND_MARIANAISLANDS:New( AirbaseNames )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, ATC_GROUND_UNIVERSAL:New( self.Airbases, AirbaseNames ) )
|
||||
local self = BASE:Inherit( self, ATC_GROUND_UNIVERSAL:New( AirbaseNames ) )
|
||||
|
||||
self:SetKickSpeedKmph( 50 )
|
||||
self:SetMaximumKickSpeedKmph( 150 )
|
||||
@@ -1543,5 +1563,5 @@ end
|
||||
-- @return nothing
|
||||
function ATC_GROUND_MARIANAISLANDS:Start( RepeatScanSeconds )
|
||||
RepeatScanSeconds = RepeatScanSeconds or 0.05
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, 2, RepeatScanSeconds )
|
||||
self.AirbaseMonitor = SCHEDULER:New( self, self._AirbaseMonitor, { self }, 0, RepeatScanSeconds )
|
||||
end
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
|
||||
-- ### Contributions: FlightControl
|
||||
--
|
||||
-- ====
|
||||
-- @module Functional.Artillery
|
||||
@@ -291,14 +291,14 @@
|
||||
-- ### Illumination Shells
|
||||
--
|
||||
-- ARTY groups that possess shells can fire shells with illumination bombs. First, the group needs to be equipped with this weapon. This is done by the
|
||||
-- function @{ARTY.SetIlluminationShells}(*n*, *power*), where *n* is the number of shells the group has available and *power* the illumination power in mega candela (mcd).
|
||||
-- function @{#ARTY.SetIlluminationShells}(*n*, *power*), where *n* is the number of shells the group has available and *power* the illumination power in mega candela (mcd).
|
||||
--
|
||||
-- In order to execute an engagement with illumination shells one has to use the weapon type *ARTY.WeaponType.IlluminationShells* in the
|
||||
-- @{#ARTY.AssignTargetCoord}() function.
|
||||
--
|
||||
-- In the simulation, the explosive shell that is fired is destroyed once it gets close to the target point but before it can actually impact.
|
||||
-- At this position an illumination bomb is triggered at a random altitude between 500 and 1000 meters. This interval can be set by the function
|
||||
-- @{ARTY.SetIlluminationMinMaxAlt}(*minalt*, *maxalt*).
|
||||
-- @{#ARTY.SetIlluminationMinMaxAlt}(*minalt*, *maxalt*).
|
||||
--
|
||||
-- ### Smoke Shells
|
||||
--
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
-- @image Designation.JPG
|
||||
--
|
||||
-- Date: 24 Oct 2021
|
||||
-- Last Update: Aug 2022
|
||||
-- Last Update: Oct 2023
|
||||
--
|
||||
--- Class AUTOLASE
|
||||
-- @type AUTOLASE
|
||||
@@ -84,6 +84,9 @@
|
||||
-- @field #string alias
|
||||
-- @field #boolean debug
|
||||
-- @field #string version
|
||||
-- @field Core.Set#SET_GROUP RecceSet
|
||||
-- @field #table LaserCodes
|
||||
-- @field #table playermenus
|
||||
-- @extends Ops.Intel#INTEL
|
||||
|
||||
---
|
||||
@@ -109,9 +112,10 @@ AUTOLASE = {
|
||||
-- @field #string unittype
|
||||
-- @field Core.Point#COORDINATE coordinate
|
||||
|
||||
|
||||
--- AUTOLASE class version.
|
||||
-- @field #string version
|
||||
AUTOLASE.version = "0.1.21"
|
||||
AUTOLASE.version = "0.1.22"
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Begin Functional.Autolase.lua
|
||||
@@ -196,6 +200,8 @@ function AUTOLASE:New(RecceSet, Coalition, Alias, PilotSet)
|
||||
self.NoMenus = false
|
||||
self.minthreatlevel = 0
|
||||
self.blacklistattributes = {}
|
||||
self:SetLaserCodes( { 1688, 1130, 4785, 6547, 1465, 4578 } ) -- set self.LaserCodes
|
||||
self.playermenus = {}
|
||||
|
||||
-- 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")
|
||||
@@ -214,7 +220,7 @@ function AUTOLASE:New(RecceSet, Coalition, Alias, PilotSet)
|
||||
if PilotSet then
|
||||
self.usepilotset = true
|
||||
self.pilotset = PilotSet
|
||||
self:HandleEvent(EVENTS.PlayerEnterAircraft)
|
||||
self:HandleEvent(EVENTS.PlayerEnterAircraft,self._EventHandler)
|
||||
--self:SetPilotMenu()
|
||||
end
|
||||
--self.SetPilotMenu()
|
||||
@@ -298,6 +304,16 @@ end
|
||||
-- Helper Functions
|
||||
-------------------------------------------------------------------
|
||||
|
||||
--- [User] Set a table of possible laser codes.
|
||||
-- Each new RECCE can select a code from this table, default is { 1688, 1130, 4785, 6547, 1465, 4578 } .
|
||||
-- @param #AUTOLASE self
|
||||
-- @param #list<#number> LaserCodes
|
||||
-- @return #AUTOLASE
|
||||
function AUTOLASE:SetLaserCodes( LaserCodes )
|
||||
self.LaserCodes = ( type( LaserCodes ) == "table" ) and LaserCodes or { LaserCodes }
|
||||
return self
|
||||
end
|
||||
|
||||
--- (Internal) Function to set pilot menu.
|
||||
-- @param #AUTOLASE self
|
||||
-- @return #AUTOLASE self
|
||||
@@ -308,8 +324,31 @@ function AUTOLASE:SetPilotMenu()
|
||||
local Unit = _unit -- Wrapper.Unit#UNIT
|
||||
if Unit and Unit:IsAlive() then
|
||||
local Group = Unit:GetGroup()
|
||||
local lasemenu = MENU_GROUP_COMMAND:New(Group,"Autolase Status",nil,self.ShowStatus,self,Group,Unit)
|
||||
lasemenu:Refresh()
|
||||
local unitname = Unit:GetName()
|
||||
if self.playermenus[unitname] then self.playermenus[unitname]:Remove() end
|
||||
local lasetopm = MENU_GROUP:New(Group,"Autolase",nil)
|
||||
self.playermenus[unitname] = lasetopm
|
||||
local lasemenu = MENU_GROUP_COMMAND:New(Group,"Status",lasetopm,self.ShowStatus,self,Group,Unit)
|
||||
local smoke = (self.smoketargets == true) and "off" or "on"
|
||||
local smoketext = string.format("Switch smoke targets to %s",smoke)
|
||||
local smokemenu = MENU_GROUP_COMMAND:New(Group,smoketext,lasetopm,self.SetSmokeTargets,self,(not self.smoketargets))
|
||||
for _,_grp in pairs(self.RecceSet.Set) do
|
||||
local grp = _grp -- Wrapper.Group#GROUP
|
||||
local unit = grp:GetUnit(1)
|
||||
--local name = grp:GetName()
|
||||
if unit and unit:IsAlive() then
|
||||
local name = unit:GetName()
|
||||
local mname = string.gsub(name,".%d+.%d+$","")
|
||||
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
|
||||
end
|
||||
end
|
||||
--lasemenu:Refresh()
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -324,7 +363,7 @@ end
|
||||
-- @param #AUTOLASE self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
-- @return #AUTOLASE self
|
||||
function AUTOLASE:OnEventPlayerEnterAircraft(EventData)
|
||||
function AUTOLASE:_EventHandler(EventData)
|
||||
self:SetPilotMenu()
|
||||
return self
|
||||
end
|
||||
@@ -397,7 +436,7 @@ end
|
||||
--- (User) Function enable sending messages via SRS.
|
||||
-- @param #AUTOLASE self
|
||||
-- @param #boolean OnOff Switch usage on and off
|
||||
-- @param #string Path Path to SRS directory, e.g. C:\\Program Files\\DCS-SimpleRadio-Standalon
|
||||
-- @param #string Path Path to SRS directory, e.g. C:\\Program Files\\DCS-SimpleRadio-Standalone
|
||||
-- @param #number Frequency Frequency to send, e.g. 243
|
||||
-- @param #number Modulation Modulation i.e. radio.modulation.AM or radio.modulation.FM
|
||||
-- @param #string Label (Optional) Short label to be used on the SRS Client Overlay
|
||||
@@ -465,10 +504,20 @@ end
|
||||
-- @param #AUTOLASE self
|
||||
-- @param #string RecceName (Unit!) Name of the Recce
|
||||
-- @param #number Code The lase code
|
||||
-- @param #boolean Refresh If true, refresh menu entries
|
||||
-- @return #AUTOLASE self
|
||||
function AUTOLASE:SetRecceLaserCode(RecceName, Code)
|
||||
function AUTOLASE:SetRecceLaserCode(RecceName, Code, Refresh)
|
||||
local code = Code or 1688
|
||||
self.RecceLaserCode[RecceName] = code
|
||||
if Refresh then
|
||||
self:SetPilotMenu()
|
||||
if self.notifypilots then
|
||||
if string.find(RecceName,"#") then
|
||||
RecceName = string.match(RecceName,"^(.*)#")
|
||||
end
|
||||
self:NotifyPilots(string.format("Code for %s set to: %d",RecceName,Code),15)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -524,6 +573,9 @@ end
|
||||
function AUTOLASE:SetSmokeTargets(OnOff,Color)
|
||||
self.smoketargets = OnOff
|
||||
self.smokecolor = Color or SMOKECOLOR.Red
|
||||
local smktxt = OnOff == true and "on" or "off"
|
||||
local Message = "Smoking targets is now "..smktxt.."!"
|
||||
self:NotifyPilots(Message,10)
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -673,7 +725,7 @@ function AUTOLASE:ShowStatus(Group,Unit)
|
||||
if playername then
|
||||
local settings = _DATABASE:GetPlayerSettings(playername)
|
||||
if settings then
|
||||
--self:I("Get Settings ok!")
|
||||
self:I("Get Settings ok!")
|
||||
if settings:IsA2G_MGRS() then
|
||||
locationstring = entry.coordinate:ToStringMGRS(settings)
|
||||
elseif settings:IsA2G_LL_DMS() then
|
||||
@@ -995,6 +1047,9 @@ end
|
||||
function AUTOLASE:onbeforeRecceKIA(From,Event,To,RecceName)
|
||||
self:T({From, Event, To, RecceName})
|
||||
if self.notifypilots or self.debug then
|
||||
if string.find(RecceName,"#") then
|
||||
RecceName = string.match(RecceName,"^(.*)#")
|
||||
end
|
||||
local text = string.format("Recce %s KIA!",RecceName)
|
||||
self:NotifyPilots(text,self.reporttimeshort)
|
||||
end
|
||||
@@ -1029,6 +1084,9 @@ end
|
||||
function AUTOLASE:onbeforeTargetLost(From,Event,To,UnitName,RecceName)
|
||||
self:T({From, Event, To, UnitName,RecceName})
|
||||
if self.notifypilots or self.debug then
|
||||
if string.find(RecceName,"#") then
|
||||
RecceName = string.match(RecceName,"^(.*)#")
|
||||
end
|
||||
local text = string.format("%s lost sight of unit %s.",RecceName,UnitName)
|
||||
self:NotifyPilots(text,self.reporttimeshort)
|
||||
end
|
||||
@@ -1046,6 +1104,9 @@ end
|
||||
function AUTOLASE:onbeforeLaserTimeout(From,Event,To,UnitName,RecceName)
|
||||
self:T({From, Event, To, UnitName,RecceName})
|
||||
if self.notifypilots or self.debug then
|
||||
if string.find(RecceName,"#") then
|
||||
RecceName = string.match(RecceName,"^(.*)#")
|
||||
end
|
||||
local text = string.format("%s laser timeout on unit %s.",RecceName,UnitName)
|
||||
self:NotifyPilots(text,self.reporttimeshort)
|
||||
end
|
||||
@@ -1063,10 +1124,9 @@ function AUTOLASE:onbeforeLasing(From,Event,To,LaserSpot)
|
||||
self:T({From, Event, To, LaserSpot.unittype})
|
||||
if self.notifypilots or self.debug then
|
||||
local laserspot = LaserSpot -- #AUTOLASE.LaserSpot
|
||||
local name = laserspot.reccename
|
||||
if string.find(name,"#") then
|
||||
local name = laserspot.reccename if string.find(name,"#") then
|
||||
name = string.match(name,"^(.*)#")
|
||||
end
|
||||
end
|
||||
local text = string.format("%s is lasing %s code %d\nat %s",name,laserspot.unittype,laserspot.lasercode,laserspot.location)
|
||||
self:NotifyPilots(text,self.reporttimeshort+5)
|
||||
end
|
||||
|
||||
@@ -167,9 +167,9 @@
|
||||
--
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- * [**Ciribob**](https://forums.eagle.ru/member.php?u=112175): Showing the way how to lase targets + how laser codes work!!! Explained the autolase script.
|
||||
-- * [**EasyEB**](https://forums.eagle.ru/member.php?u=112055): Ideas and Beta Testing
|
||||
-- * [**Wingthor**](https://forums.eagle.ru/member.php?u=123698): Beta Testing
|
||||
-- * **Ciribob**: Showing the way how to lase targets + how laser codes work!!! Explained the autolase script.
|
||||
-- * **EasyEB**: Ideas and Beta Testing
|
||||
-- * **Wingthor**: Beta Testing
|
||||
--
|
||||
-- ### Authors:
|
||||
--
|
||||
|
||||
@@ -2452,7 +2452,7 @@ do -- DETECTION_AREAS
|
||||
--
|
||||
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
|
||||
--
|
||||
-- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZones}().
|
||||
-- Retrieve the formed @{Core.Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZones}().
|
||||
-- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZoneCount}().
|
||||
-- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZoneByID}() with a given index.
|
||||
--
|
||||
|
||||
@@ -21,7 +21,7 @@ do -- DETECTION_ZONES
|
||||
--
|
||||
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
|
||||
--
|
||||
-- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZones}().
|
||||
-- Retrieve the formed @{Core.Zone#ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZones}().
|
||||
-- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZoneCount}().
|
||||
-- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZone}() with a given index.
|
||||
--
|
||||
|
||||
@@ -252,7 +252,7 @@ end
|
||||
--- Set a Detection method for the EscortClient to be reported upon.
|
||||
-- Detection methods are based on the derived classes from DETECTION_BASE.
|
||||
-- @param #ESCORT self
|
||||
-- @param Function.Detection#DETECTION_BASE Detection
|
||||
-- @param Functional.Detection#DETECTION_BASE Detection
|
||||
function ESCORT:SetDetection( Detection )
|
||||
|
||||
self.Detection = Detection
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
--
|
||||
-- # The FOX Concept
|
||||
--
|
||||
-- As you probably know [Fox](https://en.wikipedia.org/wiki/Fox_(code_word)) is a NATO brevity code for launching air-to-air munition. Therefore, the class name is not 100% accurate as this
|
||||
-- As you probably know [Fox](https://en.wikipedia.org/wiki/Fox_\(code_word\)) is a NATO brevity code for launching air-to-air munition. Therefore, the class name is not 100% accurate as this
|
||||
-- script handles air-to-air but also surface-to-air missiles.
|
||||
--
|
||||
-- # Basic Script
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
-- @module Functional.Mantis
|
||||
-- @image Functional.Mantis.jpg
|
||||
--
|
||||
-- Last Update: Sept 2023
|
||||
-- Last Update: Nov 2023
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **MANTIS** class, extends Core.Base#BASE
|
||||
@@ -103,6 +103,7 @@
|
||||
-- * Roland
|
||||
-- * Silkworm (though strictly speaking this is a surface to ship missile)
|
||||
-- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19
|
||||
-- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!)
|
||||
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2
|
||||
--
|
||||
-- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M
|
||||
@@ -373,7 +374,9 @@ MANTIS.SamData = {
|
||||
["SA-20A"] = { Range=150, Blindspot=5, Height=27, Type="Long" , Radar="S-300PMU1"},
|
||||
["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"},
|
||||
["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
||||
["SHORAD"] = { Range=3, Blindspot=0, Height=3, Type="Short", Radar="Igla" }
|
||||
["SHORAD"] = { Range=3, Blindspot=0, Height=3, Type="Short", Radar="Igla" },
|
||||
["TAMIR IDFA"] = { Range=20, Blindspot=0.6, Height=12.3, Type="Short", Radar="IRON_DOME_LN" },
|
||||
["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" },
|
||||
}
|
||||
|
||||
--- SAM data HDS
|
||||
@@ -487,7 +490,11 @@ do
|
||||
-- mybluemantis:Start()
|
||||
--
|
||||
function MANTIS:New(name,samprefix,ewrprefix,hq,coalition,dynamic,awacs, EmOnOff, Padding, Zones)
|
||||
|
||||
|
||||
|
||||
-- Inherit everything from BASE class.
|
||||
local self = BASE:Inherit(self, FSM:New()) -- #MANTIS
|
||||
|
||||
-- DONE: Create some user functions for these
|
||||
-- DONE: Make HQ useful
|
||||
-- DONE: Set SAMs to auto if EWR dies
|
||||
@@ -549,6 +556,10 @@ do
|
||||
self.ShoradGroupSet = SET_GROUP:New() -- Core.Set#SET_GROUP
|
||||
self.FilterZones = Zones
|
||||
|
||||
self.SkateZones = nil
|
||||
self.SkateNumber = 3
|
||||
self.shootandscoot = false
|
||||
|
||||
self.UseEmOnOff = true
|
||||
if EmOnOff == false then
|
||||
self.UseEmOnOff = false
|
||||
@@ -560,9 +571,6 @@ do
|
||||
self.advAwacs = false
|
||||
end
|
||||
|
||||
-- Inherit everything from BASE class.
|
||||
local self = BASE:Inherit(self, FSM:New()) -- #MANTIS
|
||||
|
||||
-- Set the string id for output to DCS.log file.
|
||||
self.lid=string.format("MANTIS %s | ", self.name)
|
||||
|
||||
@@ -623,7 +631,7 @@ do
|
||||
|
||||
-- TODO Version
|
||||
-- @field #string version
|
||||
self.version="0.8.14"
|
||||
self.version="0.8.15"
|
||||
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||
|
||||
--- FSM Functions ---
|
||||
@@ -787,6 +795,23 @@ do
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a SET_ZONE of zones for Shoot&Scoot - SHORAD units will move around
|
||||
-- @param #MANTIS self
|
||||
-- @param Core.Set#SET_ZONE ZoneSet Set of zones to be used. Units will move around to the next (random) zone between 100m and 3000m away.
|
||||
-- @param #number Number Number of closest zones to be considered, defaults to 3.
|
||||
-- @param #boolean Random If true, use a random coordinate inside the next zone to scoot to.
|
||||
-- @param #string Formation Formation to use, defaults to "Cone". See mission editor dropdown for options.
|
||||
-- @return #MANTIS self
|
||||
function MANTIS:AddScootZones(ZoneSet, Number, Random, Formation)
|
||||
self:T(self.lid .. " AddScootZones")
|
||||
self.SkateZones = ZoneSet
|
||||
self.SkateNumber = Number or 3
|
||||
self.shootandscoot = true
|
||||
self.ScootRandom = Random
|
||||
self.ScootFormation = Formation or "Cone"
|
||||
return self
|
||||
end
|
||||
|
||||
--- Function to set accept and reject zones.
|
||||
-- @param #MANTIS self
|
||||
-- @param #table AcceptZones Table of @{Core.Zone#ZONE} objects
|
||||
@@ -893,7 +918,7 @@ do
|
||||
|
||||
--- Function to get the HQ object for further use
|
||||
-- @param #MANTIS self
|
||||
-- @return Wrapper.GROUP#GROUP The HQ #GROUP object or *nil* if it doesn't exist
|
||||
-- @return Wrapper.Group#GROUP The HQ #GROUP object or *nil* if it doesn't exist
|
||||
function MANTIS:GetCommandCenter()
|
||||
self:T(self.lid .. "GetCommandCenter")
|
||||
if self.HQ_CC then
|
||||
@@ -929,7 +954,7 @@ do
|
||||
|
||||
--- Function to set the HQ object for further use
|
||||
-- @param #MANTIS self
|
||||
-- @param Wrapper.GROUP#GROUP group The #GROUP object to be set as HQ
|
||||
-- @param Wrapper.Group#GROUP group The #GROUP object to be set as HQ
|
||||
function MANTIS:SetCommandCenter(group)
|
||||
self:T(self.lid .. "SetCommandCenter")
|
||||
local group = group or nil
|
||||
@@ -991,7 +1016,7 @@ do
|
||||
|
||||
--- Set using your own #INTEL_DLINK object instead of #DETECTION
|
||||
-- @param #MANTIS self
|
||||
-- @param Ops.Intelligence#INTEL_DLINK DLink The data link object to be used.
|
||||
-- @param Ops.Intel#INTEL_DLINK DLink The data link object to be used.
|
||||
function MANTIS:SetUsingDLink(DLink)
|
||||
self:T(self.lid .. "SetUsingDLink")
|
||||
self.DLink = true
|
||||
@@ -1786,6 +1811,10 @@ do
|
||||
self.Shorad:SetDefenseLimits(80,95)
|
||||
self.ShoradLink = true
|
||||
self.Shorad.Groupset=self.ShoradGroupSet
|
||||
self.Shorad.debug = self.debug
|
||||
end
|
||||
if self.shootandscoot and self.SkateZones and self.Shorad then
|
||||
self.Shorad:AddScootZones(self.SkateZones,self.SkateNumber or 3,self.ScootRandom,self.ScootFormation)
|
||||
end
|
||||
self:__Status(-math.random(1,10))
|
||||
return self
|
||||
|
||||
@@ -46,9 +46,9 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
|
||||
-- ### Contributions: FlightControl
|
||||
--
|
||||
-- ===
|
||||
-- @module Functional.RAT
|
||||
@@ -225,7 +225,7 @@
|
||||
--
|
||||
-- * Landing: When an aircraft tries to land at an airport where it does not have a valid parking spot, it is immidiately despawned the moment its wheels touch the runway, i.e.
|
||||
-- when a landing event is triggered. This leads to the loss of the RAT aircraft. On possible way to circumvent the this problem is to let another RAT aircraft spawn at landing
|
||||
-- and not when it shuts down its engines. See the @{RAT.RespawnAfterLanding}() function.
|
||||
-- and not when it shuts down its engines. See the @{#RAT.RespawnAfterLanding}() function.
|
||||
-- * Spawning: When a big aircraft is dynamically spawned on a small airbase a few things can go wrong. For example, it could be spawned at a parking spot with a shelter.
|
||||
-- Or it could be damaged by a scenery object when it is taxiing out to the runway, or it could overlap with other aircraft on parking spots near by.
|
||||
--
|
||||
@@ -2474,11 +2474,11 @@ end
|
||||
-- @param #RAT self
|
||||
-- @param #number takeoff Takeoff type. Could also be air start.
|
||||
-- @param #number landing Landing type. Could also be a destination in air.
|
||||
-- @param Wrapper.Airport#AIRBASE _departure (Optional) Departure airbase.
|
||||
-- @param Wrapper.Airport#AIRBASE _destination (Optional) Destination airbase.
|
||||
-- @param Wrapper.Airbase#AIRBASE _departure (Optional) Departure airbase.
|
||||
-- @param Wrapper.Airbase#AIRBASE _destination (Optional) Destination airbase.
|
||||
-- @param #table _waypoint Initial waypoint.
|
||||
-- @return Wrapper.Airport#AIRBASE Departure airbase.
|
||||
-- @return Wrapper.Airport#AIRBASE Destination airbase.
|
||||
-- @return Wrapper.Airbase#AIRBASE Departure airbase.
|
||||
-- @return Wrapper.Airbase#AIRBASE Destination airbase.
|
||||
-- @return #table Table of flight plan waypoints.
|
||||
-- @return #nil If no valid departure or destination airport could be found.
|
||||
function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint)
|
||||
@@ -4605,7 +4605,7 @@ function RAT:_TaskHolding(P1, Altitude, Speed, Duration)
|
||||
end
|
||||
|
||||
--- Function which is called after passing every waypoint. Info on waypoint is given and special functions are executed.
|
||||
-- @param Core.Group#GROUP group Group of aircraft.
|
||||
-- @param Wrapper.Group#GROUP group Group of aircraft.
|
||||
-- @param #RAT rat RAT object.
|
||||
-- @param #number wp Waypoint index. Running number of the waypoints. Determines the actions to be executed.
|
||||
function RAT._WaypointFunction(group, rat, wp)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
--
|
||||
-- The RANGE class enables easy set up of bombing and strafing ranges within DCS World.
|
||||
--
|
||||
-- Implementation is based on the [Simple Range Script](https://forums.eagle.ru/showthread.php?t=157991) by [Ciribob](https://forums.eagle.ru/member.php?u=112175), 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).
|
||||
--
|
||||
-- [476th - Air Weapons Range Objects mod](http://www.476vfightergroup.com/downloads.php?do=file&id=287) is highly recommended for this class.
|
||||
@@ -42,9 +42,9 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536), [Ciribob](https://forums.eagle.ru/member.php?u=112175)
|
||||
-- ### Contributions: FlightControl, Ciribob
|
||||
-- ### SRS Additions: Applevangelist
|
||||
--
|
||||
-- ===
|
||||
@@ -105,6 +105,7 @@
|
||||
-- @field Sound.SRS#MSRSQUEUE controlsrsQ SRS queue for range controller.
|
||||
-- @field Sound.SRS#MSRS instructmsrs SRS wrapper for range instructor.
|
||||
-- @field Sound.SRS#MSRSQUEUE instructsrsQ SRS queue for range instructor.
|
||||
-- @field #number Coalition Coalition side for the menu, if any.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- *Don't only practice your art, but force your way into its secrets; art deserves that, for it and knowledge can raise man to the Divine.* - Ludwig van Beethoven
|
||||
@@ -355,7 +356,8 @@ RANGE = {
|
||||
targetsheet = nil,
|
||||
targetpath = nil,
|
||||
targetprefix = nil,
|
||||
}
|
||||
Coalition = nil,
|
||||
}
|
||||
|
||||
--- Default range parameters.
|
||||
-- @type RANGE.Defaults
|
||||
@@ -591,7 +593,7 @@ RANGE.MenuF10Root = nil
|
||||
|
||||
--- Range script version.
|
||||
-- @field #string version
|
||||
RANGE.version = "2.7.1"
|
||||
RANGE.version = "2.7.3"
|
||||
|
||||
-- TODO list:
|
||||
-- TODO: Verbosity level for messages.
|
||||
@@ -613,8 +615,9 @@ RANGE.version = "2.7.1"
|
||||
--- RANGE contructor. Creates a new RANGE object.
|
||||
-- @param #RANGE self
|
||||
-- @param #string RangeName Name of the range. Has to be unique. Will we used to create F10 menu items etc.
|
||||
-- @param #number Coalition (optional) Coalition of the range, if any, e.g. coalition.side.BLUE.
|
||||
-- @return #RANGE RANGE object.
|
||||
function RANGE:New( RangeName )
|
||||
function RANGE:New( RangeName, Coalition )
|
||||
|
||||
-- Inherit BASE.
|
||||
local self = BASE:Inherit( self, FSM:New() ) -- #RANGE
|
||||
@@ -622,7 +625,9 @@ function RANGE:New( RangeName )
|
||||
-- Get range name.
|
||||
-- TODO: make sure that the range name is not given twice. This would lead to problems in the F10 radio menu.
|
||||
self.rangename = RangeName or "Practice Range"
|
||||
|
||||
|
||||
self.Coalition = Coalition
|
||||
|
||||
-- Log id.
|
||||
self.lid = string.format( "RANGE %s | ", self.rangename )
|
||||
|
||||
@@ -1229,7 +1234,7 @@ function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume,
|
||||
return self
|
||||
end
|
||||
|
||||
--- (SRS) Set range control frequency and voice.
|
||||
--- (SRS) Set range control frequency and voice. Use `RANGE:SetSRS()` once first before using this function.
|
||||
-- @param #RANGE self
|
||||
-- @param #number frequency Frequency in MHz. Default 256 MHz.
|
||||
-- @param #number modulation Modulation, defaults to radio.modulation.AM.
|
||||
@@ -1239,6 +1244,10 @@ end
|
||||
-- @param #string relayunitname Name of the unit used for transmission location.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetSRSRangeControl( frequency, modulation, voice, culture, gender, relayunitname )
|
||||
if not self.instructmsrs then
|
||||
self:E(self.lid.."Use myrange:SetSRS() once first before using myrange:SetSRSRangeControl!")
|
||||
return self
|
||||
end
|
||||
self.rangecontrolfreq = frequency or 256
|
||||
self.controlmsrs:SetFrequencies(self.rangecontrolfreq)
|
||||
self.controlmsrs:SetModulations(modulation or radio.modulation.AM)
|
||||
@@ -1254,7 +1263,7 @@ function RANGE:SetSRSRangeControl( frequency, modulation, voice, culture, gender
|
||||
return self
|
||||
end
|
||||
|
||||
--- (SRS) Set range instructor frequency and voice.
|
||||
--- (SRS) Set range instructor frequency and voice. Use `RANGE:SetSRS()` once first before using this function.
|
||||
-- @param #RANGE self
|
||||
-- @param #number frequency Frequency in MHz. Default 305 MHz.
|
||||
-- @param #number modulation Modulation, defaults to radio.modulation.AM.
|
||||
@@ -1264,6 +1273,10 @@ end
|
||||
-- @param #string relayunitname Name of the unit used for transmission location.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetSRSRangeInstructor( frequency, modulation, voice, culture, gender, relayunitname )
|
||||
if not self.instructmsrs then
|
||||
self:E(self.lid.."Use myrange:SetSRS() once first before using myrange:SetSRSRangeInstructor!")
|
||||
return self
|
||||
end
|
||||
self.instructorfreq = frequency or 305
|
||||
self.instructmsrs:SetFrequencies(self.instructorfreq)
|
||||
self.instructmsrs:SetModulations(modulation or radio.modulation.AM)
|
||||
@@ -1745,10 +1758,16 @@ function RANGE:OnEventBirth( EventData )
|
||||
|
||||
-- Reset current strafe status.
|
||||
self.strafeStatus[_uid] = nil
|
||||
|
||||
-- Add Menu commands after a delay of 0.1 seconds.
|
||||
self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName )
|
||||
|
||||
|
||||
if self.Coalition then
|
||||
if EventData.IniCoalition == self.Coalition then
|
||||
self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName )
|
||||
end
|
||||
else
|
||||
-- Add Menu commands after a delay of 0.1 seconds.
|
||||
self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName )
|
||||
end
|
||||
|
||||
-- By default, some bomb impact points and do not flare each hit on target.
|
||||
self.PlayerSettings[_playername] = {} -- #RANGE.PlayerData
|
||||
self.PlayerSettings[_playername].smokebombimpact = self.defaultsmokebomb
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
-- and creates a CSV file logging the scoring events and results for use at team or squadron websites.
|
||||
--
|
||||
-- SCORING automatically calculates the threat level of the objects hit and destroyed by players,
|
||||
-- which can be @{Wrapper.Unit}, @{Static) and @{Scenery} objects.
|
||||
-- which can be @{Wrapper.Unit}, @{Wrapper.Static) and @{Scenery} objects.
|
||||
--
|
||||
-- Positive score points are granted when enemy or neutral targets are destroyed.
|
||||
-- Negative score points or penalties are given when a friendly target is hit or destroyed.
|
||||
@@ -81,7 +81,7 @@
|
||||
--
|
||||
-- * **Wingthor (TAW)**: Testing & Advice.
|
||||
-- * **Dutch-Baron (TAW)**: Testing & Advice.
|
||||
-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing and Advice.
|
||||
-- * **Whisper**: Testing and Advice.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
--
|
||||
-- ### Authors: **FlightControl**, **applevangelist**
|
||||
--
|
||||
-- Last Update: September 2023
|
||||
-- Last Update: Oct 2023
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -34,7 +34,7 @@
|
||||
--
|
||||
-- This class is very easy to use. Just setup a SEAD object by using @{#SEAD.New}() and SAMs will evade and take defensive action when being fired upon.
|
||||
-- Once a HARM attack is detected, SEAD will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
|
||||
-- vehicles around (*if* they are drivable, that is). There's a component of randomness in detection and evasion, which is based on the
|
||||
-- vehicles around (*if* they are driveable, that is). There's a component of randomness in detection and evasion, which is based on the
|
||||
-- skill set of the SAM set (the higher the skill, the more likely). When a missile is fired from far away, the SAM will stay active for a
|
||||
-- period of time to stay defensive, before it takes evasive actions.
|
||||
--
|
||||
@@ -66,7 +66,6 @@ SEAD = {
|
||||
-- @field Harms
|
||||
SEAD.Harms = {
|
||||
["AGM_88"] = "AGM_88",
|
||||
--["AGM_45"] = "AGM_45",
|
||||
["AGM_122"] = "AGM_122",
|
||||
["AGM_84"] = "AGM_84",
|
||||
["AGM_45"] = "AGM_45",
|
||||
@@ -80,6 +79,7 @@ SEAD = {
|
||||
["BGM_109"] = "BGM_109",
|
||||
["AGM_154"] = "AGM_154",
|
||||
["HY-2"] = "HY-2",
|
||||
["ADM_141A"] = "ADM_141A",
|
||||
}
|
||||
|
||||
--- Missile enumerators - from DCS ME and Wikipedia
|
||||
@@ -100,6 +100,7 @@ SEAD = {
|
||||
["BGM_109"] = {460, 0.705}, --in-game ~465kn
|
||||
["AGM_154"] = {130, 0.61},
|
||||
["HY-2"] = {90,1},
|
||||
["ADM_141A"] = {126,0.6},
|
||||
}
|
||||
|
||||
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
||||
@@ -143,7 +144,7 @@ function SEAD:New( SEADGroupPrefixes, Padding )
|
||||
self:AddTransition("*", "ManageEvasion", "*")
|
||||
self:AddTransition("*", "CalculateHitZone", "*")
|
||||
|
||||
self:I("*** SEAD - Started Version 0.4.4")
|
||||
self:I("*** SEAD - Started Version 0.4.5")
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -348,8 +349,9 @@ end
|
||||
-- @param #string SEADWeaponName
|
||||
-- @param Wrapper.Group#GROUP SEADGroup Attacker Group
|
||||
-- @param #number timeoffset Offset for tti calc
|
||||
-- @param Wrapper.Weapon#WEAPON Weapon
|
||||
-- @return #SEAD self
|
||||
function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,timeoffset)
|
||||
function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,timeoffset,Weapon)
|
||||
local timeoffset = timeoffset or 0
|
||||
if _targetskill == "Random" then -- when skill is random, choose a skill
|
||||
local Skills = { "Average", "Good", "High", "Excellent" }
|
||||
@@ -372,6 +374,10 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
|
||||
reach = wpndata[1] * 1.1
|
||||
local mach = wpndata[2]
|
||||
wpnspeed = math.floor(mach * 340.29)
|
||||
if Weapon then
|
||||
wpnspeed = Weapon:GetSpeed()
|
||||
self:T(string.format("*** SEAD - Weapon Speed from WEAPON: %f m/s",wpnspeed))
|
||||
end
|
||||
end
|
||||
-- time to impact
|
||||
local _tti = math.floor(_distance / wpnspeed) - timeoffset -- estimated impact time
|
||||
@@ -457,6 +463,9 @@ function SEAD:HandleEventShot( EventData )
|
||||
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
||||
local SEADWeaponName = EventData.WeaponName -- return weapon type
|
||||
|
||||
local WeaponWrapper = WEAPON:New(EventData.Weapon)
|
||||
--local SEADWeaponSpeed = WeaponWrapper:GetSpeed() -- mps
|
||||
|
||||
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
||||
--self:T({ SEADWeapon })
|
||||
|
||||
@@ -475,7 +484,7 @@ function SEAD:HandleEventShot( EventData )
|
||||
end
|
||||
return self
|
||||
end
|
||||
local targetcat = _target:getCategory() -- Identify category
|
||||
local targetcat = Object.getCategory(_target) -- Identify category
|
||||
local _targetUnit = nil -- Wrapper.Unit#UNIT
|
||||
local _targetgroup = nil -- Wrapper.Group#GROUP
|
||||
self:T(string.format("*** Targetcat = %d",targetcat))
|
||||
@@ -513,7 +522,11 @@ function SEAD:HandleEventShot( EventData )
|
||||
end
|
||||
end
|
||||
if SEADGroupFound == true then -- yes we are being attacked
|
||||
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup)
|
||||
if string.find(SEADWeaponName,"ADM_141",1,true) then
|
||||
self:__ManageEvasion(2,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
|
||||
else
|
||||
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
-- @image Functional.Shorad.jpg
|
||||
--
|
||||
-- Date: Nov 2021
|
||||
-- Last Update: Nov 2023
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **SHORAD** class, extends Core.Base#BASE
|
||||
@@ -39,8 +40,15 @@
|
||||
-- @field #boolean DefendHarms Default true, intercept incoming HARMS
|
||||
-- @field #boolean DefendMavs Default true, intercept incoming AG-Missiles
|
||||
-- @field #number DefenseLowProb Default 70, minimum detection limit
|
||||
-- @field #number DefenseHighProb Default 90, maximim detection limit
|
||||
-- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green.
|
||||
-- @field #number DefenseHighProb Default 90, maximum detection limit
|
||||
-- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green
|
||||
-- @field #boolean shootandscoot If true, shoot and scoot between zones
|
||||
-- @field #number SkateNumber Number of zones to consider
|
||||
-- @field Core.Set#SET_ZONE SkateZones Zones in this set are considered
|
||||
-- @field #number minscootdist Min distance of the next zone
|
||||
-- @field #number maxscootdist Max distance of the next zone
|
||||
-- @field #boolean scootrandomcoord If true, use a random coordinate in the zone and not the center
|
||||
-- @field #string scootformation Formation to take for scooting, e.g. "Vee" or "Cone"
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
@@ -73,14 +81,15 @@
|
||||
--
|
||||
-- `myshorad = SHORAD:New("RedShorad", "Red SHORAD", SamSet, 25000, 600, "red")`
|
||||
--
|
||||
-- ## Customize options
|
||||
-- ## Customization options
|
||||
--
|
||||
-- * SHORAD:SwitchDebug(debug)
|
||||
-- * SHORAD:SwitchHARMDefense(onoff)
|
||||
-- * SHORAD:SwitchAGMDefense(onoff)
|
||||
-- * SHORAD:SetDefenseLimits(low,high)
|
||||
-- * SHORAD:SetActiveTimer(seconds)
|
||||
-- * SHORAD:SetDefenseRadius(meters)
|
||||
-- * myshorad:SwitchDebug(debug)
|
||||
-- * myshorad:SwitchHARMDefense(onoff)
|
||||
-- * myshorad:SwitchAGMDefense(onoff)
|
||||
-- * myshorad:SetDefenseLimits(low,high)
|
||||
-- * myshorad:SetActiveTimer(seconds)
|
||||
-- * myshorad:SetDefenseRadius(meters)
|
||||
-- * myshorad:AddScootZones(ZoneSet,Number,Random,Formation)
|
||||
--
|
||||
-- @field #SHORAD
|
||||
SHORAD = {
|
||||
@@ -99,7 +108,13 @@ SHORAD = {
|
||||
DefendMavs = true,
|
||||
DefenseLowProb = 70,
|
||||
DefenseHighProb = 90,
|
||||
UseEmOnOff = false,
|
||||
UseEmOnOff = true,
|
||||
shootandscoot = false,
|
||||
SkateNumber = 3,
|
||||
SkateZones = nil,
|
||||
minscootdist = 100,
|
||||
minscootdist = 3000,
|
||||
scootrandomcoord = false,
|
||||
}
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
@@ -112,7 +127,6 @@ do
|
||||
-- @field Harms
|
||||
SHORAD.Harms = {
|
||||
["AGM_88"] = "AGM_88",
|
||||
["AGM_45"] = "AGM_45",
|
||||
["AGM_122"] = "AGM_122",
|
||||
["AGM_84"] = "AGM_84",
|
||||
["AGM_45"] = "AGM_45",
|
||||
@@ -123,6 +137,8 @@ do
|
||||
["X_25"] = "X_25",
|
||||
["X_31"] = "X_31",
|
||||
["Kh25"] = "Kh25",
|
||||
["HY-2"] = "HY-2",
|
||||
["ADM_141A"] = "ADM_141A",
|
||||
}
|
||||
|
||||
--- TODO complete list?
|
||||
@@ -134,7 +150,6 @@ do
|
||||
["Kh29"] = "Kh29",
|
||||
["Kh31"] = "Kh31",
|
||||
["Kh66"] = "Kh66",
|
||||
--["BGM_109"] = "BGM_109",
|
||||
}
|
||||
|
||||
--- Instantiates a new SHORAD object
|
||||
@@ -146,7 +161,7 @@ do
|
||||
-- @param #number ActiveTimer Determines how many seconds the systems stay on red alert after wake-up call
|
||||
-- @param #string Coalition Coalition, i.e. "blue", "red", or "neutral"
|
||||
-- @param #boolean UseEmOnOff Use Emissions On/Off rather than Alarm State Red/Green (default: use Emissions switch)
|
||||
-- @retunr #SHORAD self
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:New(Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition, UseEmOnOff)
|
||||
local self = BASE:Inherit( self, FSM:New() )
|
||||
self:T({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition})
|
||||
@@ -165,8 +180,9 @@ do
|
||||
self.DefendMavs = true
|
||||
self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin
|
||||
self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin
|
||||
self.UseEmOnOff = UseEmOnOff or false -- Decide if we are using Emission on/off (default) or AlarmState red/green
|
||||
self:I("*** SHORAD - Started Version 0.3.1")
|
||||
self.UseEmOnOff = true -- Decide if we are using Emission on/off (default) or AlarmState red/green
|
||||
if UseEmOnOff == false then self.UseEmOnOff = UseEmOnOff end
|
||||
self:I("*** SHORAD - Started Version 0.3.4")
|
||||
-- Set the string id for output to DCS.log file.
|
||||
self.lid=string.format("SHORAD %s | ", self.name)
|
||||
self:_InitState()
|
||||
@@ -176,12 +192,14 @@ do
|
||||
self:SetStartState("Running")
|
||||
self:AddTransition("*", "WakeUpShorad", "*")
|
||||
self:AddTransition("*", "CalculateHitZone", "*")
|
||||
self:AddTransition("*", "ShootAndScoot", "*")
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Initially set all groups to alarm state GREEN
|
||||
-- @param #SHORAD self
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:_InitState()
|
||||
self:T(self.lid .. " _InitState")
|
||||
local table = {}
|
||||
@@ -205,21 +223,40 @@ do
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a SET_ZONE of zones for Shoot&Scoot
|
||||
-- @param #SHORAD self
|
||||
-- @param Core.Set#SET_ZONE ZoneSet Set of zones to be used. Units will move around to the next (random) zone between 100m and 3000m away.
|
||||
-- @param #number Number Number of closest zones to be considered, defaults to 3.
|
||||
-- @param #boolean Random If true, use a random coordinate inside the next zone to scoot to.
|
||||
-- @param #string Formation Formation to use, defaults to "Cone". See mission editor dropdown for options.
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:AddScootZones(ZoneSet, Number, Random, Formation)
|
||||
self:T(self.lid .. " AddScootZones")
|
||||
self.SkateZones = ZoneSet
|
||||
self.SkateNumber = Number or 3
|
||||
self.shootandscoot = true
|
||||
self.scootrandomcoord = Random
|
||||
self.scootformation = Formation or "Cone"
|
||||
return self
|
||||
end
|
||||
|
||||
--- Switch debug state on
|
||||
-- @param #SHORAD self
|
||||
-- @param #boolean debug Switch debug on (true) or off (false)
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SwitchDebug(onoff)
|
||||
self:T( { onoff } )
|
||||
if onoff then
|
||||
self:SwitchDebugOn()
|
||||
else
|
||||
self.SwitchDebugOff()
|
||||
self:SwitchDebugOff()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Switch debug state on
|
||||
-- @param #SHORAD self
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SwitchDebugOn()
|
||||
self.debug = true
|
||||
--tracing
|
||||
@@ -230,6 +267,7 @@ do
|
||||
|
||||
--- Switch debug state off
|
||||
-- @param #SHORAD self
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SwitchDebugOff()
|
||||
self.debug = false
|
||||
BASE:TraceOff()
|
||||
@@ -239,6 +277,7 @@ do
|
||||
--- Switch defense for HARMs
|
||||
-- @param #SHORAD self
|
||||
-- @param #boolean onoff
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SwitchHARMDefense(onoff)
|
||||
self:T( { onoff } )
|
||||
local onoff = onoff or true
|
||||
@@ -249,6 +288,7 @@ do
|
||||
--- Switch defense for AGMs
|
||||
-- @param #SHORAD self
|
||||
-- @param #boolean onoff
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SwitchAGMDefense(onoff)
|
||||
self:T( { onoff } )
|
||||
local onoff = onoff or true
|
||||
@@ -260,6 +300,7 @@ do
|
||||
-- @param #SHORAD self
|
||||
-- @param #number low Minimum detection limit, integer 1-100
|
||||
-- @param #number high Maximum detection limit integer 1-100
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SetDefenseLimits(low,high)
|
||||
self:T( { low, high } )
|
||||
local low = low or 70
|
||||
@@ -278,6 +319,7 @@ do
|
||||
--- Set the number of seconds a SHORAD site will stay active
|
||||
-- @param #SHORAD self
|
||||
-- @param #number seconds Number of seconds systems stay active
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SetActiveTimer(seconds)
|
||||
self:T(self.lid .. " SetActiveTimer")
|
||||
local timer = seconds or 600
|
||||
@@ -291,6 +333,7 @@ do
|
||||
--- Set the number of meters for the SHORAD defense zone
|
||||
-- @param #SHORAD self
|
||||
-- @param #number meters Radius of the defense search zone in meters. #SHORADs in this range around a targeted group will go active
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SetDefenseRadius(meters)
|
||||
self:T(self.lid .. " SetDefenseRadius")
|
||||
local radius = meters or 20000
|
||||
@@ -304,6 +347,7 @@ do
|
||||
--- Set using Emission on/off instead of changing alarm state
|
||||
-- @param #SHORAD self
|
||||
-- @param #boolean switch Decide if we are changing alarm state or AI state
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:SetUsingEmOnOff(switch)
|
||||
self:T(self.lid .. " SetUsingEmOnOff")
|
||||
self.UseEmOnOff = switch or false
|
||||
@@ -375,11 +419,11 @@ do
|
||||
local shorad = self.Groupset
|
||||
local shoradset = shorad:GetAliveSet() --#table
|
||||
local returnname = false
|
||||
--local TDiff = 1
|
||||
for _,_groups in pairs (shoradset) do
|
||||
local groupname = _groups:GetName()
|
||||
if string.find(groupname, tgtgrp, 1, true) then
|
||||
returnname = true
|
||||
--_groups:RelocateGroundRandomInRadius(7,100,false,false) -- be a bit evasive
|
||||
end
|
||||
end
|
||||
return returnname
|
||||
@@ -426,6 +470,7 @@ do
|
||||
-- @param #number Radius Radius of the #ZONE
|
||||
-- @param #number ActiveTimer Number of seconds to stay active
|
||||
-- @param #number TargetCat (optional) Category, i.e. Object.Category.UNIT or Object.Category.STATIC
|
||||
-- @return #SHORAD self
|
||||
-- @usage Use this function to integrate with other systems, example
|
||||
--
|
||||
-- local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()
|
||||
@@ -452,28 +497,35 @@ do
|
||||
local targetzone = ZONE_RADIUS:New("Shorad",targetvec2,Radius) -- create a defense zone to check
|
||||
local groupset = self.Groupset --Core.Set#SET_GROUP
|
||||
local shoradset = groupset:GetAliveSet() --#table
|
||||
|
||||
-- local function to switch off shorad again
|
||||
local function SleepShorad(group)
|
||||
local groupname = group:GetName()
|
||||
self.ActiveGroups[groupname] = nil
|
||||
if self.UseEmOnOff then
|
||||
group:EnableEmission(false)
|
||||
--group:SetAIOff()
|
||||
else
|
||||
group:OptionAlarmStateGreen()
|
||||
if group and group:IsAlive() then
|
||||
local groupname = group:GetName()
|
||||
self.ActiveGroups[groupname] = nil
|
||||
if self.UseEmOnOff then
|
||||
group:EnableEmission(false)
|
||||
else
|
||||
group:OptionAlarmStateGreen()
|
||||
end
|
||||
local text = string.format("Sleeping SHORAD %s", group:GetName())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
--Shoot and Scoot
|
||||
if self.shootandscoot then
|
||||
self:__ShootAndScoot(1,group)
|
||||
end
|
||||
end
|
||||
local text = string.format("Sleeping SHORAD %s", group:GetName())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
end
|
||||
|
||||
-- go through set and find the one(s) to activate
|
||||
local TDiff = 4
|
||||
for _,_group in pairs (shoradset) do
|
||||
if _group:IsAnyInZone(targetzone) then
|
||||
local text = string.format("Waking up SHORAD %s", _group:GetName())
|
||||
self:T(text)
|
||||
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||
if self.UseEmOnOff then
|
||||
--_group:SetAIOn()
|
||||
_group:EnableEmission(true)
|
||||
end
|
||||
_group:OptionAlarmStateRed()
|
||||
@@ -481,91 +533,132 @@ do
|
||||
if self.ActiveGroups[groupname] == nil then -- no timer yet for this group
|
||||
self.ActiveGroups[groupname] = { Timing = ActiveTimer }
|
||||
local endtime = timer.getTime() + (ActiveTimer * math.random(75,100) / 100 ) -- randomize wakeup a bit
|
||||
timer.scheduleFunction(SleepShorad, _group, endtime)
|
||||
self.ActiveGroups[groupname].Timer = TIMER:New(SleepShorad,_group):Start(endtime)
|
||||
--Shoot and Scoot
|
||||
if self.shootandscoot then
|
||||
self:__ShootAndScoot(TDiff,_group)
|
||||
TDiff=TDiff+1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- (Internal) Calculate hit zone of an AGM-88
|
||||
-- @param #SHORAD self
|
||||
-- @param #table SEADWeapon DCS.Weapon object
|
||||
-- @param Core.Point#COORDINATE pos0 Position of the plane when it fired
|
||||
-- @param #number height Height when the missile was fired
|
||||
-- @param Wrapper.Group#GROUP SEADGroup Attacker group
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADGroup)
|
||||
self:T("**** Calculating hit zone")
|
||||
if SEADWeapon and SEADWeapon:isExist() then
|
||||
--local pos = SEADWeapon:getPoint()
|
||||
--- (Internal) Calculate hit zone of an AGM-88
|
||||
-- @param #SHORAD self
|
||||
-- @param #table SEADWeapon DCS.Weapon object
|
||||
-- @param Core.Point#COORDINATE pos0 Position of the plane when it fired
|
||||
-- @param #number height Height when the missile was fired
|
||||
-- @param Wrapper.Group#GROUP SEADGroup Attacker group
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADGroup)
|
||||
self:T("**** Calculating hit zone")
|
||||
if SEADWeapon and SEADWeapon:isExist() then
|
||||
--local pos = SEADWeapon:getPoint()
|
||||
|
||||
-- postion and height
|
||||
local position = SEADWeapon:getPosition()
|
||||
local mheight = height
|
||||
-- heading
|
||||
local wph = math.atan2(position.x.z, position.x.x)
|
||||
if wph < 0 then
|
||||
wph=wph+2*math.pi
|
||||
end
|
||||
wph=math.deg(wph)
|
||||
|
||||
-- velocity
|
||||
local wpndata = SEAD.HarmData["AGM_88"]
|
||||
local mveloc = math.floor(wpndata[2] * 340.29)
|
||||
local c1 = (2*mheight*9.81)/(mveloc^2)
|
||||
local c2 = (mveloc^2) / 9.81
|
||||
local Ropt = c2 * math.sqrt(c1+1)
|
||||
if height <= 5000 then
|
||||
Ropt = Ropt * 0.72
|
||||
elseif height <= 7500 then
|
||||
Ropt = Ropt * 0.82
|
||||
elseif height <= 10000 then
|
||||
Ropt = Ropt * 0.87
|
||||
elseif height <= 12500 then
|
||||
Ropt = Ropt * 0.98
|
||||
end
|
||||
|
||||
-- look at a couple of zones across the trajectory
|
||||
for n=1,3 do
|
||||
local dist = Ropt - ((n-1)*20000)
|
||||
local predpos= pos0:Translate(dist,wph)
|
||||
if predpos then
|
||||
|
||||
-- postion and height
|
||||
local position = SEADWeapon:getPosition()
|
||||
local mheight = height
|
||||
-- heading
|
||||
local wph = math.atan2(position.x.z, position.x.x)
|
||||
if wph < 0 then
|
||||
wph=wph+2*math.pi
|
||||
end
|
||||
wph=math.deg(wph)
|
||||
|
||||
-- velocity
|
||||
local wpndata = SEAD.HarmData["AGM_88"]
|
||||
local mveloc = math.floor(wpndata[2] * 340.29)
|
||||
local c1 = (2*mheight*9.81)/(mveloc^2)
|
||||
local c2 = (mveloc^2) / 9.81
|
||||
local Ropt = c2 * math.sqrt(c1+1)
|
||||
if height <= 5000 then
|
||||
Ropt = Ropt * 0.72
|
||||
elseif height <= 7500 then
|
||||
Ropt = Ropt * 0.82
|
||||
elseif height <= 10000 then
|
||||
Ropt = Ropt * 0.87
|
||||
elseif height <= 12500 then
|
||||
Ropt = Ropt * 0.98
|
||||
local targetzone = ZONE_RADIUS:New("Target Zone",predpos:GetVec2(),20000)
|
||||
|
||||
if self.debug then
|
||||
predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%ddeg | Ropt=%dm",mheight,wph,mveloc,Ropt),false)
|
||||
targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
|
||||
end
|
||||
|
||||
local seadset = self.Groupset
|
||||
local tgtcoord = targetzone:GetRandomPointVec2()
|
||||
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local _targetgroup = nil
|
||||
local _targetgroupname = "none"
|
||||
local _targetskill = "Random"
|
||||
if tgtgrp and tgtgrp:IsAlive() then
|
||||
_targetgroup = tgtgrp
|
||||
_targetgroupname = tgtgrp:GetName() -- group name
|
||||
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||
self:T("*** Found Target = ".. _targetgroupname)
|
||||
self:WakeUpShorad(_targetgroupname, self.Radius, self.ActiveTimer, Object.Category.UNIT)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- look at a couple of zones across the trajectory
|
||||
for n=1,3 do
|
||||
local dist = Ropt - ((n-1)*20000)
|
||||
local predpos= pos0:Translate(dist,wph)
|
||||
if predpos then
|
||||
return self
|
||||
end
|
||||
|
||||
local targetzone = ZONE_RADIUS:New("Target Zone",predpos:GetVec2(),20000)
|
||||
|
||||
if self.debug then
|
||||
predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%ddeg | Ropt=%dm",mheight,wph,mveloc,Ropt),false)
|
||||
targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
|
||||
end
|
||||
|
||||
local seadset = self.Groupset
|
||||
local tgtcoord = targetzone:GetRandomPointVec2()
|
||||
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local _targetgroup = nil
|
||||
local _targetgroupname = "none"
|
||||
local _targetskill = "Random"
|
||||
if tgtgrp and tgtgrp:IsAlive() then
|
||||
_targetgroup = tgtgrp
|
||||
_targetgroupname = tgtgrp:GetName() -- group name
|
||||
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||
self:T("*** Found Target = ".. _targetgroupname)
|
||||
self:WakeUpShorad(_targetgroupname, self.Radius, self.ActiveTimer, Object.Category.UNIT)
|
||||
--- (Internal) Shoot and Scoot
|
||||
-- @param #SHORAD self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Group#GROUP Shorad Shorad group
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:onafterShootAndScoot(From,Event,To,Shorad)
|
||||
self:T( { From,Event,To } )
|
||||
local possibleZones = {}
|
||||
local mindist = self.minscootdist or 100
|
||||
local maxdist = self.maxscootdist or 3000
|
||||
if Shorad and Shorad:IsAlive() then
|
||||
local NowCoord = Shorad:GetCoordinate()
|
||||
for _,_zone in pairs(self.SkateZones.Set) do
|
||||
local zone = _zone -- Core.Zone#ZONE_RADIUS
|
||||
local dist = NowCoord:Get2DDistance(zone:GetCoordinate())
|
||||
if dist >= mindist and dist <= maxdist then
|
||||
possibleZones[#possibleZones+1] = zone
|
||||
if #possibleZones == self.SkateNumber then break end
|
||||
end
|
||||
end
|
||||
end
|
||||
if #possibleZones > 0 and Shorad:GetVelocityKMH() < 2 then
|
||||
local rand = math.floor(math.random(1,#possibleZones*1000)/1000+0.5)
|
||||
if rand == 0 then rand = 1 end
|
||||
self:T(self.lid .. " ShootAndScoot to zone "..rand)
|
||||
local ToCoordinate = possibleZones[rand]:GetCoordinate()
|
||||
if self.scootrandomcoord then
|
||||
ToCoordinate = possibleZones[rand]:GetRandomCoordinate(nil,nil,{land.SurfaceType.LAND,land.SurfaceType.ROAD})
|
||||
end
|
||||
local formation = self.scootformation or "Cone"
|
||||
Shorad:RouteGroundTo(ToCoordinate,20,formation,1)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Main function - work on the EventData
|
||||
-- @param #SHORAD self
|
||||
-- @param Core.Event#EVENTDATA EventData The event details table data set
|
||||
-- @return #SHORAD self
|
||||
function SHORAD:HandleEventShot( EventData )
|
||||
self:T( { EventData } )
|
||||
self:T(self.lid .. " HandleEventShot")
|
||||
--local ShootingUnit = EventData.IniDCSUnit
|
||||
--local ShootingUnitName = EventData.IniDCSUnitName
|
||||
local ShootingWeapon = EventData.Weapon -- Identify the weapon fired
|
||||
local ShootingWeaponName = EventData.WeaponName -- return weapon type
|
||||
-- get firing coalition
|
||||
@@ -596,27 +689,18 @@ end
|
||||
return self
|
||||
end
|
||||
|
||||
local targetcat = targetdata:getCategory() -- Identify category
|
||||
local targetcat = Object.getCategory(targetdata) -- Identify category
|
||||
self:T(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat)))
|
||||
self:T({targetdata})
|
||||
local targetunit = nil
|
||||
if targetcat == Object.Category.UNIT then -- UNIT
|
||||
targetunit = UNIT:Find(targetdata)
|
||||
elseif targetcat == Object.Category.STATIC then -- STATIC
|
||||
--self:T("Static Target Data")
|
||||
--self:T({targetdata:isExist()})
|
||||
--self:T({targetdata:getPoint()})
|
||||
local tgtcoord = COORDINATE:NewFromVec3(targetdata:getPoint())
|
||||
--tgtcoord:MarkToAll("Missile Target",true)
|
||||
|
||||
local tgtgrp1 = self.Samset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local tgtgrp1 = self.Samset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local tgtcoord1 = tgtgrp1:GetCoordinate()
|
||||
--tgtcoord1:MarkToAll("Close target SAM",true)
|
||||
|
||||
local tgtgrp2 = self.Groupset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||
local tgtcoord2 = tgtgrp2:GetCoordinate()
|
||||
--tgtcoord2:MarkToAll("Close target SHORAD",true)
|
||||
|
||||
local dist1 = tgtcoord:Get2DDistance(tgtcoord1)
|
||||
local dist2 = tgtcoord:Get2DDistance(tgtcoord2)
|
||||
|
||||
@@ -628,10 +712,8 @@ end
|
||||
targetcat = Object.Category.UNIT
|
||||
end
|
||||
end
|
||||
--local targetunitname = Unit.getName(targetdata) -- Unit name
|
||||
if targetunit and targetunit:IsAlive() then
|
||||
local targetunitname = targetunit:GetName()
|
||||
--local targetgroup = Unit.getGroup(Weapon.getTarget(ShootingWeapon)) --targeted group
|
||||
local targetgroup = nil
|
||||
local targetgroupname = "none"
|
||||
if targetcat == Object.Category.UNIT then
|
||||
@@ -649,7 +731,6 @@ end
|
||||
self:T( text )
|
||||
local m = MESSAGE:New(text,10,"Info"):ToAllIf(self.debug)
|
||||
-- check if we or a SAM site are the target
|
||||
--local TargetGroup = EventData.TgtGroup -- Wrapper.Group#GROUP
|
||||
local shotatus = self:_CheckShotAtShorad(targetgroupname) --#boolean
|
||||
local shotatsams = self:_CheckShotAtSams(targetgroupname) --#boolean
|
||||
-- if being shot at, find closest SHORADs to activate
|
||||
@@ -666,4 +747,4 @@ end
|
||||
end
|
||||
-----------------------------------------------------------------------
|
||||
-- SHORAD end
|
||||
-----------------------------------------------------------------------
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
@@ -33,9 +33,9 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
|
||||
-- ### Contributions: FlightControl
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
|
||||
@@ -742,7 +742,7 @@
|
||||
--
|
||||
-- ## Save Assets
|
||||
--
|
||||
-- Saving asset data to file is achieved by the @{WAREHOUSE.Save}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
|
||||
-- Saving asset data to file is achieved by the @{#WAREHOUSE.Save}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
|
||||
-- warehouse data is saved. If you do not specify a path, the file is saved your the DCS installation root directory.
|
||||
-- The parameter *filename* is optional and defines the name of the saved file. By default this is automatically created from the warehouse id and name, for example
|
||||
-- "Warehouse-1234_Batumi.txt".
|
||||
@@ -753,13 +753,13 @@
|
||||
--
|
||||
-- ### Automatic Save at Mission End
|
||||
--
|
||||
-- The assets can be saved automatically when the mission is ended via the @{WAREHOUSE.SetSaveOnMissionEnd}(*path*, *filename*) function, i.e.
|
||||
-- The assets can be saved automatically when the mission is ended via the @{#WAREHOUSE.SetSaveOnMissionEnd}(*path*, *filename*) function, i.e.
|
||||
--
|
||||
-- warehouseBatumi:SetSaveOnMissionEnd("D:\\My Warehouse Data\\")
|
||||
--
|
||||
-- ## Load Assets
|
||||
--
|
||||
-- Loading assets data from file is achieved by the @{WAREHOUSE.Load}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
|
||||
-- Loading assets data from file is achieved by the @{#WAREHOUSE.Load}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
|
||||
-- warehouse data is loaded from. If you do not specify a path, the file is loaded from your the DCS installation root directory.
|
||||
-- The parameter *filename* is optional and defines the name of the file to load. By default this is automatically generated from the warehouse id and name, for example
|
||||
-- "Warehouse-1234_Batumi.txt".
|
||||
@@ -7404,6 +7404,8 @@ function WAREHOUSE:_CheckRequestNow(request)
|
||||
|
||||
-- Check if at least one (cargo) asset is available.
|
||||
if _nassets>0 then
|
||||
|
||||
local asset=_assets[1] --#WAREHOUSE.Assetitem
|
||||
|
||||
-- Get the attibute of the requested asset.
|
||||
_assetattribute=_assets[1].attribute
|
||||
@@ -7414,11 +7416,24 @@ function WAREHOUSE:_CheckRequestNow(request)
|
||||
if _assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER then
|
||||
|
||||
if self.airbase and self.airbase:GetCoalition()==self:GetCoalition() then
|
||||
|
||||
-- Check if DCS warehouse of airbase has enough assets
|
||||
if self.airbase.storage then
|
||||
local nS=self.airbase.storage:GetAmount(asset.unittype)
|
||||
local nA=asset.nunits*request.nasset -- Number of units requested
|
||||
if nS<nA then
|
||||
local text=string.format("Warehouse %s: Request denied! DCS Warehouse has only %d assets of type %s ==> NOT enough to spawn the requested %d asset units (%d groups)",
|
||||
self.alias, nS, asset.unittype, nA, request.nasset)
|
||||
self:_InfoMessage(text, 5)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if self:IsRunwayOperational() or _assetairstart then
|
||||
|
||||
if _assetairstart then
|
||||
-- Airstart no need to check parking
|
||||
-- Airstart no need to check parking
|
||||
else
|
||||
|
||||
-- Check parking.
|
||||
@@ -7530,6 +7545,9 @@ function WAREHOUSE:_CheckRequestNow(request)
|
||||
self:_InfoMessage(text, 5)
|
||||
return false
|
||||
end
|
||||
|
||||
elseif _assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER then
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -7870,7 +7888,7 @@ function WAREHOUSE:_GetTerminal(_attribute, _category)
|
||||
-- Default terminal is "large".
|
||||
local _terminal=AIRBASE.TerminalType.OpenBig
|
||||
|
||||
if _attribute==WAREHOUSE.Attribute.AIR_FIGHTER then
|
||||
if _attribute==WAREHOUSE.Attribute.AIR_FIGHTER or _attribute==WAREHOUSE.Attribute.AIR_UAV then
|
||||
-- Fighter ==> small.
|
||||
_terminal=AIRBASE.TerminalType.FighterAircraft
|
||||
elseif _attribute==WAREHOUSE.Attribute.AIR_BOMBER or _attribute==WAREHOUSE.Attribute.AIR_TRANSPORTPLANE or _attribute==WAREHOUSE.Attribute.AIR_TANKER or _attribute==WAREHOUSE.Attribute.AIR_AWACS then
|
||||
|
||||
@@ -363,8 +363,8 @@ do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
--- ZONE_CAPTURE_COALITION Constructor.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved. Alternatively, can be handed as the name of late activated group describing a @{ZONE_POLYGON} with its waypoints.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved. Alternatively, can be handed as the name of late activated group describing a @{Core.Zone#ZONE_POLYGON} with its waypoints.
|
||||
-- @param #number Coalition The initial coalition owning the zone.
|
||||
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
|
||||
-- @param #table ObjectCategories Table of unit categories. See [DCS Class Object](https://wiki.hoggitworld.com/view/DCS_Class_Object). Default {Object.Category.UNIT, Object.Category.STATIC}, i.e. all UNITS and STATICS.
|
||||
-- @return #ZONE_CAPTURE_COALITION
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
--
|
||||
-- ZONE_GOAL_CARGO models processes that have a Goal with a defined achievement involving a Zone and Cargo.
|
||||
-- Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
@@ -61,7 +61,7 @@ do -- ZoneGoal
|
||||
--- ZONE_GOAL_CARGO Constructor.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||
-- @param #number Coalition The initial coalition owning the zone.
|
||||
-- @return #ZONE_GOAL_CARGO
|
||||
function ZONE_GOAL_CARGO:New( Zone, Coalition )
|
||||
|
||||
@@ -259,7 +259,7 @@ do -- ZoneGoal
|
||||
|
||||
--- Set the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition
|
||||
-- @param #number Coalition
|
||||
function ZONE_GOAL_CARGO:SetCoalition( Coalition )
|
||||
self.Coalition = Coalition
|
||||
end
|
||||
@@ -267,7 +267,7 @@ do -- ZoneGoal
|
||||
|
||||
--- Get the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||
-- @return #number Coalition.
|
||||
function ZONE_GOAL_CARGO:GetCoalition()
|
||||
return self.Coalition
|
||||
end
|
||||
|
||||
@@ -54,7 +54,7 @@ do -- ZoneGoal
|
||||
--- ZONE_GOAL_COALITION Constructor.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone. Default coalition.side.NEUTRAL.
|
||||
-- @param #number Coalition The initial coalition owning the zone. Default coalition.side.NEUTRAL.
|
||||
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
|
||||
-- @return #ZONE_GOAL_COALITION
|
||||
function ZONE_GOAL_COALITION:New( Zone, Coalition, UnitCategories )
|
||||
@@ -80,7 +80,7 @@ do -- ZoneGoal
|
||||
|
||||
--- Set the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The coalition ID, e.g. *coalition.side.RED*.
|
||||
-- @param #number Coalition The coalition ID, e.g. *coalition.side.RED*.
|
||||
-- @return #ZONE_GOAL_COALITION
|
||||
function ZONE_GOAL_COALITION:SetCoalition( Coalition )
|
||||
self.PreviousCoalition = self.Coalition or Coalition
|
||||
@@ -120,14 +120,14 @@ do -- ZoneGoal
|
||||
|
||||
--- Get the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||
-- @return #number Coalition.
|
||||
function ZONE_GOAL_COALITION:GetCoalition()
|
||||
return self.Coalition
|
||||
end
|
||||
|
||||
--- Get the previous coalition, i.e. the one owning the zone before the current one.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||
-- @return #number Coalition.
|
||||
function ZONE_GOAL_COALITION:GetPreviousCoalition()
|
||||
return self.PreviousCoalition
|
||||
end
|
||||
|
||||
@@ -312,10 +312,16 @@
|
||||
--
|
||||
-- atis=ATIS:New("Batumi", 305, radio.modulation.AM)
|
||||
-- atis:SetSRS("D:\\DCS\\_SRS\\", "male", "en-US")
|
||||
-- atis:Start()
|
||||
-- atis:Start()
|
||||
--
|
||||
-- This uses a male voice with US accent. It requires SRS to be installed in the `D:\DCS\_SRS\` directory. Note that backslashes need to be escaped or simply use slashes (as in linux).
|
||||
--
|
||||
-- ### SRS can use multiple frequencies:
|
||||
--
|
||||
-- atis=ATIS:New("Batumi", {305,103.85}, {radio.modulation.AM,radio.modulation.FM})
|
||||
-- atis:SetSRS("D:\\DCS\\_SRS\\", "male", "en-US")
|
||||
-- atis:Start()
|
||||
--
|
||||
-- ### SRS Localization
|
||||
--
|
||||
-- You can localize the SRS output, all you need is to provide a table of translations and set the `locale` of your instance. You need to provide the translations in your script **before you instantiate your ATIS**.
|
||||
@@ -353,6 +359,7 @@
|
||||
-- DEWPOINT = "Taupunkt",
|
||||
-- ALTIMETER = "Hoehenmesser",
|
||||
-- ACTIVERUN = "Aktive Startbahn",
|
||||
-- ACTIVELANDING = "Aktive Landebahn",
|
||||
-- LEFT = "Links",
|
||||
-- RIGHT = "Rechts",
|
||||
-- RWYLENGTH = "Startbahn",
|
||||
@@ -721,7 +728,8 @@ ATIS.Messages = {
|
||||
TEMPERATURE = "Temperature",
|
||||
DEWPOINT = "Dew point",
|
||||
ALTIMETER = "Altimeter",
|
||||
ACTIVERUN = "Active runway",
|
||||
ACTIVERUN = "Active runway departure",
|
||||
ACTIVELANDING = "Active runway arrival",
|
||||
LEFT = "Left",
|
||||
RIGHT = "Right",
|
||||
RWYLENGTH = "Runway length",
|
||||
@@ -781,6 +789,7 @@ ATIS.Messages = {
|
||||
DEWPOINT = "Taupunkt",
|
||||
ALTIMETER = "Hoehenmesser",
|
||||
ACTIVERUN = "Aktive Startbahn",
|
||||
ACTIVELANDING = "Aktive Landebahn",
|
||||
LEFT = "Links",
|
||||
RIGHT = "Rechts",
|
||||
RWYLENGTH = "Startbahn",
|
||||
@@ -841,6 +850,7 @@ ATIS.Messages = {
|
||||
DEWPOINT = "Punto de rocio",
|
||||
ALTIMETER = "Altímetro",
|
||||
ACTIVERUN = "Pista activa",
|
||||
ACTIVELANDING = "Pista de aterrizaje activa",
|
||||
LEFT = "Izquierda",
|
||||
RIGHT = "Derecha",
|
||||
RWYLENGTH = "Longitud de pista",
|
||||
@@ -880,13 +890,14 @@ _ATIS = {}
|
||||
|
||||
--- ATIS class version.
|
||||
-- @field #string version
|
||||
ATIS.version = "0.10.2"
|
||||
ATIS.version = "0.10.4"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Correct fog for elevation.
|
||||
-- DONE: Option to add multiple frequencies for SRS
|
||||
-- DONE: Zulu time --> Zulu in output.
|
||||
-- DONE: Fix for AB not having a runway - Helopost like Naqoura
|
||||
-- DONE: Add new Normandy airfields.
|
||||
@@ -895,13 +906,14 @@ ATIS.version = "0.10.2"
|
||||
-- DONE: Visibility reported twice over SRS
|
||||
-- DONE: Add text report for output.
|
||||
-- DONE: Add stop FMS functions.
|
||||
-- NOGO: Use local time. Not realisitc!
|
||||
-- NOGO: Use local time. Not realistic!
|
||||
-- DONE: Dew point. Approx. done.
|
||||
-- DONE: Metric units.
|
||||
-- DONE: Set UTC correction.
|
||||
-- DONE: Set magnetic variation.
|
||||
-- DONE: New DCS 2.7 weather presets.
|
||||
-- DONE: Added TextAndSound localization
|
||||
-- DONE: Added SRS spelling out both take off and landing runway
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@@ -910,8 +922,8 @@ ATIS.version = "0.10.2"
|
||||
--- Create a new ATIS class object for a specific airbase.
|
||||
-- @param #ATIS self
|
||||
-- @param #string AirbaseName Name of the airbase.
|
||||
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz.
|
||||
-- @param #number Modulation Radio modulation: 0=AM, 1=FM. Default 0=AM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators.
|
||||
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. When using **SRS** this can be passed as a table of multiple frequencies.
|
||||
-- @param #number Modulation Radio modulation: 0=AM, 1=FM. Default 0=AM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators. When using **SRS** this can be passed as a table of multiple modulations.
|
||||
-- @return #ATIS self
|
||||
function ATIS:New(AirbaseName, Frequency, Modulation)
|
||||
|
||||
@@ -1534,6 +1546,7 @@ function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port, GoogleKey)
|
||||
self.msrs:SetCoalition(self:GetCoalition())
|
||||
self.msrs:SetLabel("ATIS")
|
||||
self.msrs:SetGoogle(GoogleKey)
|
||||
self.msrs:SetCoordinate(self.airbase:GetCoordinate())
|
||||
self.msrsQ = MSRSQUEUE:New("ATIS")
|
||||
self.msrsQ:SetTransmitOnlyWithPlayers(self.TransmitOnlyWithPlayers)
|
||||
if self.dTQueueCheck<=10 then
|
||||
@@ -1588,8 +1601,16 @@ function ATIS:onafterStart( From, Event, To )
|
||||
end
|
||||
|
||||
-- Info.
|
||||
self:I( self.lid .. string.format( "Starting ATIS v%s for airbase %s on %.3f MHz Modulation=%d", ATIS.version, self.airbasename, self.frequency, self.modulation ) )
|
||||
|
||||
if type(self.frequency) == "table" then
|
||||
local frequency = table.concat(self.frequency,"/")
|
||||
local modulation = self.modulation
|
||||
if type(self.modulation) == "table" then
|
||||
modulation = table.concat(self.modulation,"/")
|
||||
end
|
||||
self:I( self.lid .. string.format( "Starting ATIS v%s for airbase %s on %s MHz Modulation=%s", ATIS.version, self.airbasename, frequency, modulation ) )
|
||||
else
|
||||
self:I( self.lid .. string.format( "Starting ATIS v%s for airbase %s on %.3f MHz Modulation=%d", ATIS.version, self.airbasename, self.frequency, self.modulation ) )
|
||||
end
|
||||
-- Start radio queue.
|
||||
if not self.useSRS then
|
||||
self.radioqueue = RADIOQUEUE:New( self.frequency, self.modulation, string.format( "ATIS %s", self.airbasename ) )
|
||||
@@ -1647,7 +1668,17 @@ function ATIS:onafterStatus( From, Event, To )
|
||||
end
|
||||
|
||||
-- Info text.
|
||||
local text = string.format( "State %s: Freq=%.3f MHz %s", fsmstate, self.frequency, UTILS.GetModulationName( self.modulation ) )
|
||||
local text = ""
|
||||
if type(self.frequency) == "table" then
|
||||
local frequency = table.concat(self.frequency,"/")
|
||||
local modulation = self.modulation
|
||||
if type(self.modulation) == "table" then
|
||||
modulation = table.concat(self.modulation,"/")
|
||||
end
|
||||
text = string.format( "State %s: Freq=%s MHz %s", fsmstate, frequency, modulation )
|
||||
else
|
||||
text = string.format( "State %s: Freq=%.3f MHz %s", fsmstate, self.frequency, UTILS.GetModulationName( self.modulation ) )
|
||||
end
|
||||
if self.useSRS then
|
||||
text = text .. string.format( ", SRS path=%s (%s), gender=%s, culture=%s, voice=%s", tostring( self.msrs.path ), tostring( self.msrs.port ), tostring( self.msrs.gender ), tostring( self.msrs.culture ), tostring( self.msrs.voice ) )
|
||||
else
|
||||
@@ -2506,10 +2537,10 @@ function ATIS:onafterBroadcast( From, Event, To )
|
||||
|
||||
if not self.ATISforFARPs then
|
||||
-- Active runway.
|
||||
local subtitle
|
||||
local subtitle = ""
|
||||
if runwayLanding then
|
||||
local actrun = self.gettext:GetEntry("ACTIVERUN",self.locale)
|
||||
--subtitle=string.format("Active runway %s", runwayLanding)
|
||||
local actrun = self.gettext:GetEntry("ACTIVELANDING",self.locale)
|
||||
--subtitle=string.format("Active runway landing %s", runwayLanding)
|
||||
subtitle=string.format("%s %s", actrun, runwayLanding)
|
||||
if rwyLandingLeft==true then
|
||||
--subtitle=subtitle.." Left"
|
||||
@@ -2518,6 +2549,19 @@ function ATIS:onafterBroadcast( From, Event, To )
|
||||
--subtitle=subtitle.." Right"
|
||||
subtitle=subtitle.." "..self.gettext:GetEntry("RIGHT",self.locale)
|
||||
end
|
||||
alltext = alltext .. ";\n" .. subtitle
|
||||
end
|
||||
if runwayTakeoff then
|
||||
local actrun = self.gettext:GetEntry("ACTIVERUN",self.locale)
|
||||
--subtitle=string.format("Active runway %s", runwayLanding)
|
||||
subtitle=string.format("%s %s", actrun, runwayTakeoff)
|
||||
if rwyTakeoffLeft==true then
|
||||
--subtitle=subtitle.." Left"
|
||||
subtitle=subtitle.." "..self.gettext:GetEntry("LEFT",self.locale)
|
||||
elseif rwyTakeoffLeft==false then
|
||||
--subtitle=subtitle.." Right"
|
||||
subtitle=subtitle.." "..self.gettext:GetEntry("RIGHT",self.locale)
|
||||
end
|
||||
end
|
||||
_RUNACT = subtitle
|
||||
if not self.useSRS then
|
||||
@@ -2900,8 +2944,17 @@ function ATIS:UpdateMarker( information, runact, wind, altimeter, temperature )
|
||||
if self.markerid then
|
||||
self.airbase:GetCoordinate():RemoveMark( self.markerid )
|
||||
end
|
||||
|
||||
local text = string.format( "ATIS on %.3f %s, %s:\n", self.frequency, UTILS.GetModulationName( self.modulation ), tostring( information ) )
|
||||
local text = ""
|
||||
if type(self.frequency) == "table" then
|
||||
local frequency = table.concat(self.frequency,"/")
|
||||
local modulation = self.modulation
|
||||
if type(modulation) == "table" then
|
||||
modulation = table.concat(self.modulation,"/")
|
||||
end
|
||||
text = string.format( "ATIS on %s %s, %s:\n", tostring(frequency), tostring(modulation), tostring( information ) )
|
||||
else
|
||||
text = string.format( "ATIS on %.3f %s, %s:\n", self.frequency, UTILS.GetModulationName( self.modulation ), tostring( information ) )
|
||||
end
|
||||
text = text .. string.format( "%s\n", tostring( runact ) )
|
||||
text = text .. string.format( "%s\n", tostring( wind ) )
|
||||
text = text .. string.format( "%s\n", tostring( altimeter ) )
|
||||
|
||||
@@ -27,17 +27,17 @@
|
||||
-- **Supported Carriers:**
|
||||
--
|
||||
-- * [USS John C. Stennis](https://en.wikipedia.org/wiki/USS_John_C._Stennis) (CVN-74)
|
||||
-- * [USS Theodore Roosevelt](https://en.wikipedia.org/wiki/USS_Theodore_Roosevelt_(CVN-71\)) (CVN-71) [Super Carrier Module]
|
||||
-- * [USS Abraham Lincoln](https://en.wikipedia.org/wiki/USS_Abraham_Lincoln_(CVN-72\)) (CVN-72) [Super Carrier Module]
|
||||
-- * [USS George Washington](https://en.wikipedia.org/wiki/USS_George_Washington_(CVN-73\)) (CVN-73) [Super Carrier Module]
|
||||
-- * [USS Theodore Roosevelt](https://en.wikipedia.org/wiki/USS_Theodore_Roosevelt_\(CVN-71\)) (CVN-71) [Super Carrier Module]
|
||||
-- * [USS Abraham Lincoln](https://en.wikipedia.org/wiki/USS_Abraham_Lincoln_\(CVN-72\)) (CVN-72) [Super Carrier Module]
|
||||
-- * [USS George Washington](https://en.wikipedia.org/wiki/USS_George_Washington_\(CVN-73\)) (CVN-73) [Super Carrier Module]
|
||||
-- * [USS Harry S. Truman](https://en.wikipedia.org/wiki/USS_Harry_S._Truman) (CVN-75) [Super Carrier Module]
|
||||
-- * [USS Forrestal](https://en.wikipedia.org/wiki/USS_Forrestal_(CV-59\)) (CV-59) [Heatblur Carrier Module]
|
||||
-- * [HMS Hermes](https://en.wikipedia.org/wiki/HMS_Hermes_(R12\)) (R12)
|
||||
-- * [HMS Invincible](https://en.wikipedia.org/wiki/HMS_Invincible_(R05\)) (R05)
|
||||
-- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_(LHA-1\)) (LHA-1)
|
||||
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_(LHA-6\)) (LHA-6)
|
||||
-- * [USS Forrestal](https://en.wikipedia.org/wiki/USS_Forrestal_\(CV-59\)) (CV-59) [Heatblur Carrier Module]
|
||||
-- * [HMS Hermes](https://en.wikipedia.org/wiki/HMS_Hermes_\(R12\)) (R12)
|
||||
-- * [HMS Invincible](https://en.wikipedia.org/wiki/HMS_Invincible_\(R05\)) (R05)
|
||||
-- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_\(LHA-1\)) (LHA-1)
|
||||
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_\(LHA-6\)) (LHA-6)
|
||||
-- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61)
|
||||
-- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_(L02\)) (L02)
|
||||
-- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_\(L02\)) (L02)
|
||||
--
|
||||
-- **Supported Aircraft:**
|
||||
--
|
||||
@@ -45,7 +45,7 @@
|
||||
-- * [F-14A/B Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI)
|
||||
-- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI)
|
||||
-- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI)
|
||||
-- * [T-45C Goshawk](https://www.vnao-cvw-7.com/t-45-goshawk) (VNAO mod) (Player & AI)
|
||||
-- * [T-45C Goshawk](https://forum.dcs.world/topic/203816-vnao-t-45-goshawk/) (VNAO mod) (Player & AI)
|
||||
-- * [FE/A-18E/F/G Superhornet](https://forum.dcs.world/topic/316971-cjs-super-hornet-community-mod-v20-official-thread/) (CJS mod) (Player & AI)
|
||||
-- * F/A-18C Hornet (AI)
|
||||
-- * F-14A Tomcat (AI)
|
||||
@@ -61,7 +61,7 @@
|
||||
--
|
||||
-- Heatblur's mighty F-14B Tomcat has been added (March 13th 2019) as well. Same goes for the A version.
|
||||
--
|
||||
-- The [DCS Supercarriers](https://forums.eagle.ru/forum/151-dcs-supercarrier/) are also supported.
|
||||
-- The [DCS Supercarriers](https://www.digitalcombatsimulator.com/de/shop/modules/supercarrier/) are also supported.
|
||||
--
|
||||
-- ## Discussion
|
||||
--
|
||||
@@ -95,11 +95,6 @@
|
||||
-- * [[MOOSE] Airboss - CASE I, "Until We Go Down" featuring the F-14B by Pikes](https://www.youtube.com/watch?v=ojgHDSw3Doc)
|
||||
-- * [[MOOSE] Airboss - Skipper Menu](https://youtu.be/awnecCxRoNQ)
|
||||
--
|
||||
-- ### Lex explaining Boat Ops:
|
||||
--
|
||||
-- * [( DCS HORNET ) Some boat ops basics VID 1](https://www.youtube.com/watch?v=LvGQS-3AzMc)
|
||||
-- * [( DCS HORNET ) Some boat ops basics VID 2](https://www.youtube.com/watch?v=bN44wvtRsw0)
|
||||
--
|
||||
-- ### Jabbers Case I and III Recovery Tutorials:
|
||||
--
|
||||
-- * [DCS World - F/A-18 - Case I Carrier Recovery Tutorial](https://www.youtube.com/watch?v=lm-M3VUy-_I)
|
||||
@@ -1735,10 +1730,10 @@ AIRBOSS.Difficulty = {
|
||||
-- @field #table trapsheet Groove data table recorded every 0.5 seconds.
|
||||
-- @field #boolean trapon If true, save trap sheets.
|
||||
-- @field #string debriefschedulerID Debrief scheduler ID.
|
||||
--
|
||||
--
|
||||
-- @field Sound.SRS#MSRS SRS
|
||||
-- @field Sound.SRS#MSRSQUEUE SRSQ
|
||||
--
|
||||
--
|
||||
-- @extends #AIRBOSS.FlightGroup
|
||||
|
||||
--- Main group level radio menu: F10 Other/Airboss.
|
||||
@@ -1751,7 +1746,7 @@ AIRBOSS.MenuF10Root = nil
|
||||
|
||||
--- Airboss class version.
|
||||
-- @field #string version
|
||||
AIRBOSS.version = "1.3.2"
|
||||
AIRBOSS.version = "1.3.3"
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -3058,7 +3053,7 @@ end
|
||||
-- @param #number Port Port of the SRS server, defaults to 5002.
|
||||
-- @param #string Culture (Optional, Airboss Culture) Culture, defaults to "en-US".
|
||||
-- @param #string Gender (Optional, Airboss Gender) Gender, e.g. "male" or "female". Defaults to "male".
|
||||
-- @param #string Voice (Optional, Airboss Voice) Set to use a specific voice. Will **override gender and culture** settings.
|
||||
-- @param #string Voice (Optional, Airboss Voice) Set to use a specific voice. Will **override gender and culture** settings.
|
||||
-- @param #string GoogleCreds (Optional) Path to Google credentials, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourgooglekey.json".
|
||||
-- @param #number Volume (Optional) E.g. 0.75. Defaults to 1.0 (loudest).
|
||||
-- @param #table AltBackend (Optional) See MSRS for details.
|
||||
@@ -3076,6 +3071,7 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum
|
||||
self.SRS:SetPath(PathToSRS)
|
||||
self.SRS:SetPort(Port or 5002)
|
||||
self.SRS:SetLabel(self.AirbossRadio.alias or "AIRBOSS")
|
||||
self.SRS:SetCoordinate(self.carrier:GetCoordinate())
|
||||
--self.SRS:SetModulations(Modulations)
|
||||
if GoogleCreds then
|
||||
self.SRS:SetGoogle(GoogleCreds)
|
||||
@@ -3087,10 +3083,10 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum
|
||||
-- SRSQUEUE
|
||||
self.SRSQ = MSRSQUEUE:New("AIRBOSS")
|
||||
self.SRSQ:SetTransmitOnlyWithPlayers(true)
|
||||
if not self.PilotRadio then
|
||||
if not self.PilotRadio then
|
||||
self:SetSRSPilotVoice()
|
||||
end
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set LSO radio frequency and modulation. Default frequency is 264 MHz AM.
|
||||
@@ -10271,7 +10267,7 @@ function AIRBOSS:_GetSternCoord()
|
||||
elseif case==2 or case==1 then
|
||||
-- V/Stol: Translate 8 meters port.
|
||||
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8, FB-90, true, true)
|
||||
end
|
||||
end
|
||||
elseif self.carriertype==AIRBOSS.CarrierType.STENNIS then
|
||||
-- Stennis: translate 7 meters starboard wrt Final bearing.
|
||||
self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 7, FB + 90, true, true )
|
||||
@@ -11558,7 +11554,7 @@ function AIRBOSS:GetHeadingIntoWind_old( magnetic, coord )
|
||||
local function adjustDegreesForWindSpeed(windSpeed)
|
||||
local degreesAdjustment = 0
|
||||
-- the windspeeds are in m/s
|
||||
|
||||
|
||||
-- +0 degrees at 15m/s = 37kts
|
||||
-- +0 degrees at 14m/s = 35kts
|
||||
-- +0 degrees at 13m/s = 33kts
|
||||
@@ -11573,7 +11569,7 @@ function AIRBOSS:GetHeadingIntoWind_old( magnetic, coord )
|
||||
-- +20 degrees at 4m/s = 26kts
|
||||
-- +20 degrees at 3m/s = 26kts
|
||||
-- +30 degrees at 2m/s = 26kts 1s
|
||||
|
||||
|
||||
if windSpeed > 0 and windSpeed < 3 then
|
||||
degreesAdjustment = 30
|
||||
elseif windSpeed >= 3 and windSpeed < 5 then
|
||||
@@ -11585,7 +11581,7 @@ function AIRBOSS:GetHeadingIntoWind_old( magnetic, coord )
|
||||
elseif windSpeed >= 13 then
|
||||
degreesAdjustment = 0
|
||||
end
|
||||
|
||||
|
||||
return degreesAdjustment
|
||||
end
|
||||
|
||||
@@ -14829,12 +14825,12 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p
|
||||
if radio == nil or call == nil then
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if not self.SRS then
|
||||
|
||||
|
||||
-- Create a new radio transmission item.
|
||||
local transmission = {} -- #AIRBOSS.Radioitem
|
||||
|
||||
|
||||
transmission.radio = radio
|
||||
transmission.call = call
|
||||
transmission.Tplay = timer.getAbsTime() + (delay or 0)
|
||||
@@ -14842,12 +14838,12 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p
|
||||
transmission.isplaying = false
|
||||
transmission.Tstarted = nil
|
||||
transmission.loud = loud and call.loud
|
||||
|
||||
|
||||
-- Player onboard number if sender has one.
|
||||
if self:_IsOnboard( call.modexsender ) then
|
||||
self:_Number2Radio( radio, call.modexsender, delay, 0.3, pilotcall )
|
||||
end
|
||||
|
||||
|
||||
-- Play onboard number if receiver has one.
|
||||
if self:_IsOnboard( call.modexreceiver ) then
|
||||
self:_Number2Radio( radio, call.modexreceiver, delay, 0.3, pilotcall )
|
||||
@@ -14890,16 +14886,12 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p
|
||||
-- SRS transmission
|
||||
if call.subtitle ~= nil and string.len(call.subtitle) > 1 then
|
||||
|
||||
|
||||
else
|
||||
-- SRS transmission
|
||||
|
||||
local frequency = self.MarshalRadio.frequency
|
||||
local modulation = self.MarshalRadio.modulation
|
||||
local voice = nil
|
||||
local gender = nil
|
||||
local culture = nil
|
||||
|
||||
|
||||
if radio.alias == "AIRBOSS" then
|
||||
frequency = self.AirbossRadio.frequency
|
||||
modulation = self.AirbossRadio.modulation
|
||||
@@ -14907,13 +14899,13 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p
|
||||
gender = self.AirbossRadio.gender
|
||||
culture = self.AirbossRadio.culture
|
||||
end
|
||||
|
||||
|
||||
if radio.alias == "MARSHAL" then
|
||||
voice = self.MarshalRadio.voice
|
||||
gender = self.MarshalRadio.gender
|
||||
culture = self.MarshalRadio.culture
|
||||
end
|
||||
|
||||
|
||||
if radio.alias == "LSO" then
|
||||
frequency = self.LSORadio.frequency
|
||||
modulation = self.LSORadio.modulation
|
||||
@@ -14921,7 +14913,7 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p
|
||||
gender = self.LSORadio.gender
|
||||
culture = self.LSORadio.culture
|
||||
end
|
||||
|
||||
|
||||
if pilotcall then
|
||||
voice = self.PilotRadio.voice
|
||||
gender = self.PilotRadio.gender
|
||||
@@ -14935,18 +14927,18 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p
|
||||
modulation = self.AirbossRadio.modulation
|
||||
radio.alias = "AIRBOSS"
|
||||
end
|
||||
|
||||
|
||||
local volume = nil
|
||||
|
||||
|
||||
if loud then
|
||||
volume = 1.0
|
||||
end
|
||||
|
||||
|
||||
--local text = tostring(call.modexreceiver).."; "..radio.alias.."; "..call.subtitle
|
||||
local text = call.subtitle
|
||||
self:I(self.lid..text)
|
||||
self:T(self.lid..text)
|
||||
local srstext = self:_GetNiceSRSText(text)
|
||||
self.SRSQ:NewTransmission(srstext, call.duration, self.SRS, tstart, 0.1, subgroups, call.subtitle, call.subduration, frequency, modulation, gender, culture, voice, volume, radio.alias)
|
||||
self.SRSQ:NewTransmission(srstext, call.duration, self.SRS, nil, 0.1, nil, call.subtitle, call.subduration, frequency, modulation, gender, culture, voice, volume, radio.alias)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -15259,7 +15251,7 @@ end
|
||||
-- @param #boolean clear If true, clear screen from previous messages.
|
||||
-- @param #number delay Delay in seconds, before the message is displayed.
|
||||
function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duration, clear, delay )
|
||||
self:I({sender,receiver,message})
|
||||
self:T({sender,receiver,message})
|
||||
if playerData and message and message ~= "" then
|
||||
|
||||
-- Default duration.
|
||||
@@ -15282,44 +15274,44 @@ function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duratio
|
||||
-- SCHEDULER:New(nil, self.MessageToPlayer, {self, playerData, message, sender, receiver, duration, clear}, delay)
|
||||
self:ScheduleOnce( delay, self.MessageToPlayer, self, playerData, message, sender, receiver, duration, clear )
|
||||
else
|
||||
|
||||
|
||||
if not self.SRS then
|
||||
-- Wait until previous sound finished.
|
||||
local wait = 0
|
||||
|
||||
|
||||
-- Onboard number to get the attention.
|
||||
if receiver == playerData.onboard then
|
||||
|
||||
|
||||
-- Which voice over number to use.
|
||||
if sender and (sender == "LSO" or sender == "MARSHAL" or sender == "AIRBOSS") then
|
||||
|
||||
|
||||
-- User sound of board number.
|
||||
wait = wait + self:_Number2Sound( playerData, sender, receiver )
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Negative.
|
||||
if string.find( text:lower(), "negative" ) then
|
||||
local filename = self:_RadioFilename( self.MarshalCall.NEGATIVE, false, "MARSHAL" )
|
||||
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
|
||||
wait = wait + self.MarshalCall.NEGATIVE.duration
|
||||
end
|
||||
|
||||
|
||||
-- Affirm.
|
||||
if string.find( text:lower(), "affirm" ) then
|
||||
local filename = self:_RadioFilename( self.MarshalCall.AFFIRMATIVE, false, "MARSHAL" )
|
||||
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
|
||||
wait = wait + self.MarshalCall.AFFIRMATIVE.duration
|
||||
end
|
||||
|
||||
|
||||
-- Roger.
|
||||
if string.find( text:lower(), "roger" ) then
|
||||
local filename = self:_RadioFilename( self.MarshalCall.ROGER, false, "MARSHAL" )
|
||||
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
|
||||
wait = wait + self.MarshalCall.ROGER.duration
|
||||
end
|
||||
|
||||
|
||||
-- Play click sound to end message.
|
||||
if wait > 0 then
|
||||
local filename = self:_RadioFilename( self.MarshalCall.CLICK )
|
||||
@@ -15332,7 +15324,7 @@ function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duratio
|
||||
local voice = self.MarshalRadio.voice
|
||||
local gender = self.MarshalRadio.gender
|
||||
local culture = self.MarshalRadio.culture
|
||||
|
||||
|
||||
if not sender then sender = "AIRBOSS" end
|
||||
|
||||
if string.find(sender,"AIRBOSS" ) then
|
||||
@@ -15362,10 +15354,10 @@ function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duratio
|
||||
--sender = "AIRBOSS"
|
||||
end
|
||||
|
||||
self:I(self.lid..text)
|
||||
self:I({sender,frequency,modulation,voice})
|
||||
self:T(self.lid..text)
|
||||
self:T({sender,frequency,modulation,voice})
|
||||
local srstext = self:_GetNiceSRSText(text)
|
||||
self.SRSQ:NewTransmission(srstext,duration,self.SRS,tstart,0.1,subgroups,subtitle,subduration,frequency,modulation,gender,culture,voice,volume,sender)
|
||||
self.SRSQ:NewTransmission(srstext,duration,self.SRS,nil,0.1,nil,nil,nil,frequency,modulation,gender,culture,voice,nil,sender)
|
||||
end
|
||||
-- Text message to player client.
|
||||
if playerData.client then
|
||||
|
||||
@@ -976,7 +976,8 @@ function ARMYGROUP:onafterSpawned(From, Event, To)
|
||||
-- Update route.
|
||||
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:__Cruise(-1, nil, self.option.Formation)
|
||||
--self:__Cruise(-1, nil, self.option.Formation)
|
||||
self:__Cruise(-1)
|
||||
else
|
||||
self:T(self.lid.."No waypoints on spawn ==> Full Stop!")
|
||||
self:FullStop()
|
||||
@@ -1948,7 +1949,7 @@ function ARMYGROUP:onafterCruise(From, Event, To, Speed, Formation)
|
||||
self.dTwait=nil
|
||||
|
||||
-- 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.
|
||||
self:__UpdateRoute(-0.01, nil, nil, Speed, Formation)
|
||||
@@ -2003,7 +2004,7 @@ function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation
|
||||
elseif self.optionDefault.Formation then
|
||||
Formation = self.optionDefault.Formation
|
||||
elseif self.option.Formation then
|
||||
Formation = self.option.Formation
|
||||
Formation = self.option.Formation
|
||||
else
|
||||
-- Default formation is on road.
|
||||
Formation = ENUMS.Formation.Vehicle.OnRoad
|
||||
@@ -2043,82 +2044,90 @@ end
|
||||
-- @param #ARMYGROUP self
|
||||
-- @param #table Template Template used to init the group. Default is `self.template`.
|
||||
-- @return #ARMYGROUP self
|
||||
function ARMYGROUP:_InitGroup(Template)
|
||||
function ARMYGROUP:_InitGroup(Template, Delay)
|
||||
|
||||
-- First check if group was already initialized.
|
||||
if self.groupinitialized then
|
||||
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
||||
return
|
||||
end
|
||||
|
||||
-- Get template of group.
|
||||
local template=Template or self:_GetTemplate()
|
||||
|
||||
-- Ground are always AI.
|
||||
self.isAI=true
|
||||
|
||||
-- Is (template) group late activated.
|
||||
self.isLateActivated=template.lateActivation
|
||||
|
||||
-- Ground groups cannot be uncontrolled.
|
||||
self.isUncontrolled=false
|
||||
|
||||
-- Max speed in km/h.
|
||||
self.speedMax=self.group:GetSpeedMax()
|
||||
|
||||
-- Is group mobile?
|
||||
if self.speedMax>3.6 then
|
||||
self.isMobile=true
|
||||
if Delay and Delay>0 then
|
||||
self:ScheduleOnce(Delay, ARMYGROUP._InitGroup, self, Template, 0)
|
||||
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)
|
||||
-- First check if group was already initialized.
|
||||
if self.groupinitialized then
|
||||
self:T(self.lid.."WARNING: Group was already initialized! Will NOT do it again!")
|
||||
return
|
||||
end
|
||||
|
||||
self:I(self.lid.."FF Initializing Group")
|
||||
|
||||
-- Units of the group.
|
||||
local units=self.group:GetUnits()
|
||||
-- Get template of group.
|
||||
local template=Template or self:_GetTemplate()
|
||||
|
||||
-- Ground are always AI.
|
||||
self.isAI=true
|
||||
|
||||
-- Is (template) group late activated.
|
||||
self.isLateActivated=template.lateActivation
|
||||
|
||||
-- Ground groups cannot be uncontrolled.
|
||||
self.isUncontrolled=false
|
||||
|
||||
-- Max speed in km/h.
|
||||
self.speedMax=self.group:GetSpeedMax()
|
||||
|
||||
-- Is group mobile?
|
||||
if self.speedMax>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
|
||||
|
||||
-- DCS group.
|
||||
local dcsgroup=Group.getByName(self.groupname)
|
||||
local size0=dcsgroup:getInitialSize()
|
||||
-- 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
|
||||
|
||||
|
||||
-- Quick check.
|
||||
if #units~=size0 then
|
||||
self:T(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units!", #units, size0))
|
||||
-- Init done.
|
||||
self.groupinitialized=true
|
||||
end
|
||||
|
||||
-- Add elemets.
|
||||
for _,unit in pairs(units) do
|
||||
local unitname=unit:GetName()
|
||||
self:_AddElementByName(unitname)
|
||||
end
|
||||
|
||||
|
||||
-- Init done.
|
||||
self.groupinitialized=true
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **applevangelist**
|
||||
-- @date Last Update July 2023
|
||||
-- @date Last Update Nov 2023
|
||||
-- @module Ops.AWACS
|
||||
-- @image OPS_AWACS.jpg
|
||||
|
||||
@@ -507,7 +507,7 @@ do
|
||||
-- @field #AWACS
|
||||
AWACS = {
|
||||
ClassName = "AWACS", -- #string
|
||||
version = "0.2.57", -- #string
|
||||
version = "0.2.59", -- #string
|
||||
lid = "", -- #string
|
||||
coalition = coalition.side.BLUE, -- #number
|
||||
coalitiontxt = "blue", -- #string
|
||||
@@ -971,6 +971,7 @@ AWACS.TaskStatus = {
|
||||
-- DONE - (WIP) Reporting
|
||||
-- DONE - Do not report non-airborne groups
|
||||
-- DONE - Added option for helos
|
||||
-- DONE - Added setting a coordinate for SRS
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@@ -2987,7 +2988,7 @@ function AWACS:_Picture(Group,IsGeneral)
|
||||
|
||||
if clustersAO == 0 and clustersEWR == 0 then
|
||||
-- clean
|
||||
self:_NewRadioEntry(text,textScreen,GID,Outcome,true,true,false)
|
||||
self:_NewRadioEntry(text,text,GID,Outcome,true,true,false)
|
||||
else
|
||||
|
||||
if clustersAO > 0 then
|
||||
@@ -6191,6 +6192,16 @@ function AWACS:onafterStatus(From, Event, To)
|
||||
-- Check on AUFTRAG status for CAP AI
|
||||
if self:Is("Running") and (awacsalive or self.AwacsInZone) then
|
||||
|
||||
|
||||
-- update coord for SRS
|
||||
|
||||
if self.AwacsSRS then
|
||||
self.AwacsSRS:SetCoordinate(self.AwacsFG:GetCoordinate())
|
||||
if self.TacticalSRS then
|
||||
self.TacticalSRS:SetCoordinate(self.AwacsFG:GetCoordinate())
|
||||
end
|
||||
end
|
||||
|
||||
self:_CheckAICAPOnStation()
|
||||
|
||||
self:_CleanUpContacts()
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
-- @image OPS_CSAR.jpg
|
||||
|
||||
-- Date: May 2023
|
||||
-- Last: Update Oct 2024
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
||||
@@ -46,8 +47,6 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # CSAR Concept
|
||||
--
|
||||
-- * MOOSE-based Helicopter CSAR Operations for Players.
|
||||
@@ -118,21 +117,21 @@
|
||||
-- mycsar.ADFRadioPwr = 1000 -- ADF Beacons sending with 1KW as default
|
||||
-- mycsar.PilotWeight = 80 -- Loaded pilots weigh 80kgs each
|
||||
--
|
||||
-- ## 2.1 Experimental Features
|
||||
-- ## 2.1 SRS Features and Other Features
|
||||
--
|
||||
-- WARNING - Here\'ll be dragons!
|
||||
-- DANGER - For this to work you need to de-sanitize your mission environment (all three entries) in <DCS root>\Scripts\MissionScripting.lua
|
||||
-- Needs SRS => 1.9.6 to work (works on the **server** side of SRS)
|
||||
-- mycsar.useSRS = false -- Set true to use FF\'s SRS integration
|
||||
-- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!)
|
||||
-- mycsar.SRSchannel = 300 -- radio channel
|
||||
-- mycsar.SRSModulation = radio.modulation.AM -- modulation
|
||||
-- mycsar.SRSport = 5002 -- and SRS Server port
|
||||
-- mycsar.SRSCulture = "en-GB" -- SRS voice culture
|
||||
-- mycsar.SRSVoice = nil -- SRS voice, relevant for Google TTS
|
||||
-- mycsar.SRSVoice = nil -- SRS voice for downed pilot, relevant for Google TTS
|
||||
-- mycsar.SRSGPathToCredentials = nil -- Path to your Google credentials json file, set this if you want to use Google TTS
|
||||
-- mycsar.SRSVolume = 1 -- Volume, between 0 and 1
|
||||
-- mycsar.SRSGender = "male" -- male or female voice
|
||||
-- mycsar.CSARVoice = MSRS.Voices.Google.Standard.en_US_Standard_A -- SRS voice for CSAR Controller, relevant for Google TTS
|
||||
-- mycsar.CSARVoiceMS = MSRS.Voices.Microsoft.Hedda -- SRS voice for CSAR Controller, relevant for MS Desktop TTS
|
||||
-- mycsar.coordinate -- Coordinate from which CSAR TTS is sending. Defaults to a random MASH object position
|
||||
-- --
|
||||
-- mycsar.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection. Requires mycsar.enableForAI to be set to true. --shagrat
|
||||
-- mycsar.wetfeettemplate = "man in floating thingy" -- if you use a mod to have a pilot in a rescue float, put the template name in here for wet feet spawns. Note: in conjunction with csarUsePara this might create dual ejected pilots in edge cases.
|
||||
@@ -232,7 +231,7 @@ CSAR = {
|
||||
takenOff = {},
|
||||
csarUnits = {}, -- table of unit names
|
||||
downedPilots = {},
|
||||
woundedGroups = {},
|
||||
-- = {},
|
||||
landedStatus = {},
|
||||
addedTo = {},
|
||||
woundedGroups = {}, -- contains the new group of units
|
||||
@@ -467,7 +466,10 @@ function CSAR:New(Coalition, Template, Alias)
|
||||
self.SRSGPathToCredentials = nil
|
||||
self.SRSVolume = 1.0 -- volume 0.0 to 1.0
|
||||
self.SRSGender = "male" -- male or female
|
||||
|
||||
self.CSARVoice = MSRS.Voices.Google.Standard.en_US_Standard_A
|
||||
self.CSARVoiceMS = MSRS.Voices.Microsoft.Hedda
|
||||
self.coordinate = nil -- Core.Point#COORDINATE
|
||||
|
||||
local AliaS = string.gsub(self.alias," ","_")
|
||||
self.filename = string.format("CSAR_%s_Persist.csv",AliaS)
|
||||
|
||||
@@ -1308,7 +1310,7 @@ end
|
||||
-- @param #string UnitName
|
||||
-- @return #string CallSign
|
||||
function CSAR:_GetCustomCallSign(UnitName)
|
||||
local callsign = Unitname
|
||||
local callsign = UnitName
|
||||
local unit = UNIT:FindByName(UnitName)
|
||||
if unit and unit:IsAlive() then
|
||||
local group = unit:GetGroup()
|
||||
@@ -1739,7 +1741,16 @@ function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _overrid
|
||||
end
|
||||
-- integrate SRS
|
||||
if _speak and self.useSRS then
|
||||
self.SRSQueue:NewTransmission(_text,nil,self.msrs,nil,2)
|
||||
local coord = _unit:GetCoordinate()
|
||||
if coord then
|
||||
self.msrs:SetCoordinate(coord)
|
||||
end
|
||||
_text = string.gsub(_text,"km"," kilometer")
|
||||
_text = string.gsub(_text,"nm"," nautical miles")
|
||||
--self.msrs:SetVoice(self.SRSVoice)
|
||||
--self.SRSQueue:NewTransmission(_text,nil,self.msrs,nil,1)
|
||||
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)
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -1878,7 +1889,7 @@ function CSAR:_SignalFlare(_unitName)
|
||||
if _closest ~= nil and _closest.pilot ~= nil and _closest.distance > 0 and _closest.distance < smokedist then
|
||||
|
||||
local _clockDir = self:_GetClockDirection(_heli, _closest.pilot)
|
||||
local _distance = 0
|
||||
local _distance = ""
|
||||
if _SETTINGS:IsImperial() then
|
||||
_distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance))
|
||||
else
|
||||
@@ -1891,12 +1902,13 @@ function CSAR:_SignalFlare(_unitName)
|
||||
_coord:FlareRed(_clockDir)
|
||||
else
|
||||
local _distance = smokedist
|
||||
local dtext = ""
|
||||
if _SETTINGS:IsImperial() then
|
||||
_distance = string.format("%.1fnm",UTILS.MetersToNM(smokedist))
|
||||
dtext = string.format("%.1fnm",UTILS.MetersToNM(smokedist))
|
||||
else
|
||||
_distance = string.format("%.1fkm",smokedist/1000)
|
||||
dtext = string.format("%.1fkm",smokedist/1000)
|
||||
end
|
||||
self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true)
|
||||
self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",dtext), self.messageTime, false, false, true)
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -1909,6 +1921,14 @@ end
|
||||
function CSAR:_DisplayToAllSAR(_message, _side, _messagetime)
|
||||
self:T(self.lid .. " _DisplayToAllSAR")
|
||||
local messagetime = _messagetime or self.messageTime
|
||||
if self.msrs then
|
||||
local voice = self.CSARVoice or MSRS.Voices.Google.Standard.en_GB_Standard_F
|
||||
if self.msrs.google == nil then
|
||||
voice = self.CSARVoiceMS or MSRS.Voices.Microsoft.Hedda
|
||||
end
|
||||
self:I("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)
|
||||
end
|
||||
for _, _unitName in pairs(self.csarUnits) do
|
||||
local _unit = self:_GetSARHeli(_unitName)
|
||||
if _unit and not self.suppressmessages then
|
||||
@@ -1932,7 +1952,7 @@ function CSAR:_Reqsmoke( _unitName )
|
||||
local _closest = self:_GetClosestDownedPilot(_heli)
|
||||
if _closest ~= nil and _closest.pilot ~= nil and _closest.distance > 0 and _closest.distance < smokedist then
|
||||
local _clockDir = self:_GetClockDirection(_heli, _closest.pilot)
|
||||
local _distance = 0
|
||||
local _distance = string.format("%.1fkm",_closest.distance/1000)
|
||||
if _SETTINGS:IsImperial() then
|
||||
_distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance))
|
||||
else
|
||||
@@ -1944,7 +1964,7 @@ function CSAR:_Reqsmoke( _unitName )
|
||||
local color = self.smokecolor
|
||||
_coord:Smoke(color)
|
||||
else
|
||||
local _distance = 0
|
||||
local _distance = string.format("%.1fkm",smokedist/1000)
|
||||
if _SETTINGS:IsImperial() then
|
||||
_distance = string.format("%.1fnm",UTILS.MetersToNM(smokedist))
|
||||
else
|
||||
@@ -2269,6 +2289,12 @@ function CSAR:onafterStart(From, Event, To)
|
||||
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterCategoryHelicopter():FilterStart()
|
||||
end
|
||||
self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() -- currently only GROUP objects, maybe support STATICs also?
|
||||
if not self.coordinate then
|
||||
local csarhq = self.mash:GetRandom()
|
||||
if csarhq then
|
||||
self.coordinate = csarhq:GetCoordinate()
|
||||
end
|
||||
end
|
||||
if self.wetfeettemplate then
|
||||
self.usewetfeet = true
|
||||
end
|
||||
@@ -2276,7 +2302,7 @@ function CSAR:onafterStart(From, Event, To)
|
||||
local path = self.SRSPath
|
||||
local modulation = self.SRSModulation
|
||||
local channel = self.SRSchannel
|
||||
self.msrs = MSRS:New(path,channel,modulation)
|
||||
self.msrs = MSRS:New(path,channel,modulation) -- Sound.SRS#MSRS
|
||||
self.msrs:SetPort(self.SRSport)
|
||||
self.msrs:SetLabel("CSAR")
|
||||
self.msrs:SetCulture(self.SRSCulture)
|
||||
@@ -2288,7 +2314,7 @@ function CSAR:onafterStart(From, Event, To)
|
||||
end
|
||||
self.msrs:SetVolume(self.SRSVolume)
|
||||
self.msrs:SetLabel("CSAR")
|
||||
self.SRSQueue = MSRSQUEUE:New("CSAR")
|
||||
self.SRSQueue = MSRSQUEUE:New("CSAR") -- Sound.SRS#MSRSQUEUE
|
||||
end
|
||||
|
||||
self:__Status(-10)
|
||||
|
||||
@@ -19,10 +19,12 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Applevangelist** (Moose Version), ***Ciribob*** (original), Thanks to: Shadowze, Cammel (testing), bbirchnz (additional code!!)
|
||||
-- ### Repack addition for crates: **Raiden**
|
||||
--
|
||||
-- @module Ops.CTLD
|
||||
-- @image OPS_CTLD.jpg
|
||||
|
||||
-- Last Update June 2023
|
||||
-- Last Update November 2023
|
||||
|
||||
do
|
||||
|
||||
@@ -599,7 +601,7 @@ do
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
-- 
|
||||
--
|
||||
-- # CTLD Concept
|
||||
--
|
||||
@@ -700,6 +702,7 @@ do
|
||||
--
|
||||
-- my_ctld.useprefix = true -- (DO NOT SWITCH THIS OFF UNLESS YOU KNOW WHAT YOU ARE DOING!) Adjust **before** starting CTLD. If set to false, *all* choppers of the coalition side will be enabled for CTLD.
|
||||
-- my_ctld.CrateDistance = 35 -- List and Load crates in this radius only.
|
||||
-- my_ctld.PackDistance = 35 -- Pack crates in this radius only
|
||||
-- my_ctld.dropcratesanywhere = false -- Option to allow crates to be dropped anywhere.
|
||||
-- my_ctld.dropAsCargoCrate = false -- Parachuted herc cargo is not unpacked automatically but placed as crate to be unpacked. Needs a cargo with the same name defined like the cargo that was dropped.
|
||||
-- my_ctld.maximumHoverHeight = 15 -- Hover max this high to load.
|
||||
@@ -738,7 +741,7 @@ do
|
||||
--
|
||||
-- -- E.g. update unit capabilities for testing. Please stay realistic in your mission design.
|
||||
-- -- Make a Gazelle into a heavy truck, this type can load both crates and troops and eight of each type, up to 4000 kgs:
|
||||
-- my_ctld:UnitCapabilities("SA342L", true, true, 8, 8, 12, 4000)
|
||||
-- my_ctld:SetUnitCapabilities("SA342L", true, true, 8, 8, 12, 4000)
|
||||
--
|
||||
-- -- Default unit type capabilities are:
|
||||
-- ["SA342Mistral"] = {type="SA342Mistral", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 12, cargoweightlimit = 400},
|
||||
@@ -1121,6 +1124,7 @@ CTLD = {
|
||||
Spawned_Crates = {}, -- Holds objects for crates spawned generally
|
||||
Spawned_Cargo = {}, -- Binds together spawned_crates and their CTLD_CARGO objects
|
||||
CrateDistance = 35, -- list crates in this radius
|
||||
PackDistance = 35, -- pack crates in this radius
|
||||
debug = false,
|
||||
wpZones = {},
|
||||
dropOffZones = {},
|
||||
@@ -1144,6 +1148,7 @@ CTLD = {
|
||||
-- DONE: List cargo in stock
|
||||
-- DONE: Limit of troops, crates buildable?
|
||||
-- DONE: Allow saving of Troops & Vehicles
|
||||
-- DONE: Adding re-packing dropped units
|
||||
------------------------------
|
||||
|
||||
--- Radio Beacons
|
||||
@@ -1195,14 +1200,14 @@ CTLD.CargoZoneType = {
|
||||
-- @field #CTLD_CARGO.Enum Type Type enumerator (for moves).
|
||||
|
||||
--- Unit capabilities.
|
||||
-- @type CTLD.UnitCapabilities
|
||||
-- @type CTLD.UnitTypeCapabilities
|
||||
-- @field #string type Unit type.
|
||||
-- @field #boolean crates Can transport crate.
|
||||
-- @field #boolean troops Can transport troops.
|
||||
-- @field #number cratelimit Number of crates transportable.
|
||||
-- @field #number trooplimit Number of troop units transportable.
|
||||
-- @field #number cargoweightlimit Max loadable kgs of cargo.
|
||||
CTLD.UnitTypes = {
|
||||
CTLD.UnitTypeCapabilities = {
|
||||
["SA342Mistral"] = {type="SA342Mistral", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 12, cargoweightlimit = 400},
|
||||
["SA342L"] = {type="SA342L", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 12, cargoweightlimit = 400},
|
||||
["SA342M"] = {type="SA342M", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 12, cargoweightlimit = 400},
|
||||
@@ -1223,7 +1228,7 @@ CTLD.UnitTypes = {
|
||||
|
||||
--- CTLD class version.
|
||||
-- @field #string version
|
||||
CTLD.version="1.0.40"
|
||||
CTLD.version="1.0.43"
|
||||
|
||||
--- Instantiate a new CTLD.
|
||||
-- @param #CTLD self
|
||||
@@ -1288,6 +1293,8 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
||||
self:AddTransition("*", "CratesDropped", "*") -- CTLD deploy event.
|
||||
self:AddTransition("*", "CratesBuild", "*") -- CTLD build event.
|
||||
self:AddTransition("*", "CratesRepaired", "*") -- CTLD repair event.
|
||||
self:AddTransition("*", "CratesBuildStarted", "*") -- CTLD build event.
|
||||
self:AddTransition("*", "CratesRepairStarted", "*") -- CTLD repair event.
|
||||
self:AddTransition("*", "Load", "*") -- CTLD load event.
|
||||
self:AddTransition("*", "Save", "*") -- CTLD save event.
|
||||
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
||||
@@ -1341,6 +1348,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
||||
|
||||
-- setup
|
||||
self.CrateDistance = 35 -- list/load crates in this radius
|
||||
self.PackDistance = 35 -- pack objects in this radius
|
||||
self.ExtractFactor = 3.33 -- factor for troops extraction, i.e. CrateDistance * Extractfactor
|
||||
self.prefixes = Prefixes or {"Cargoheli"}
|
||||
self.useprefix = true
|
||||
@@ -1469,7 +1477,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
||||
-- @param #CTLD self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- FSM Function OnBeforeTroopsPickedUp.
|
||||
--- FSM Function OnBeforeTroopsPickedUp.
|
||||
-- @function [parent=#CTLD] OnBeforeTroopsPickedUp
|
||||
-- @param #CTLD self
|
||||
-- @param #string From State.
|
||||
@@ -1621,6 +1629,46 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
||||
-- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB build.
|
||||
-- @return #CTLD self
|
||||
|
||||
--- FSM Function OnAfterCratesBuildStarted. Info event that a build has been started.
|
||||
-- @function [parent=#CTLD] OnAfterCratesBuildStarted
|
||||
-- @param #CTLD self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Group#GROUP Group Group Object.
|
||||
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
||||
-- @return #CTLD self
|
||||
|
||||
--- FSM Function OnAfterCratesRepairStarted. Info event that a repair has been started.
|
||||
-- @function [parent=#CTLD] OnAfterCratesRepairStarted
|
||||
-- @param #CTLD self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Group#GROUP Group Group Object.
|
||||
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
||||
-- @return #CTLD self
|
||||
|
||||
--- FSM Function OnBeforeCratesBuildStarted. Info event that a build has been started.
|
||||
-- @function [parent=#CTLD] OnBeforeCratesBuildStarted
|
||||
-- @param #CTLD self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Group#GROUP Group Group Object.
|
||||
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
||||
-- @return #CTLD self
|
||||
|
||||
--- FSM Function OnBeforeCratesRepairStarted. Info event that a repair has been started.
|
||||
-- @function [parent=#CTLD] OnBeforeCratesRepairStarted
|
||||
-- @param #CTLD self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Group#GROUP Group Group Object.
|
||||
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
||||
-- @return #CTLD self
|
||||
|
||||
--- FSM Function OnAfterCratesRepaired.
|
||||
-- @function [parent=#CTLD] OnAfterCratesRepaired
|
||||
-- @param #CTLD self
|
||||
@@ -1674,7 +1722,7 @@ function CTLD:_GetUnitCapabilities(Unit)
|
||||
self:T(self.lid .. " _GetUnitCapabilities")
|
||||
local _unit = Unit -- Wrapper.Unit#UNIT
|
||||
local unittype = _unit:GetTypeName()
|
||||
local capabilities = self.UnitTypes[unittype] -- #CTLD.UnitCapabilities
|
||||
local capabilities = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities
|
||||
if not capabilities or capabilities == {} then
|
||||
-- e.g. ["Ka-50"] = {type="Ka-50", crates=false, troops=false, cratelimit = 0, trooplimit = 0},
|
||||
capabilities = {}
|
||||
@@ -1865,7 +1913,7 @@ function CTLD:_PreloadCrates(Group, Unit, Cargo, NumberOfCrates)
|
||||
local unitname = unit:GetName()
|
||||
-- see if this heli can load crates
|
||||
local unittype = unit:GetTypeName()
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
|
||||
local cancrates = capabilities.crates -- #boolean
|
||||
local cratelimit = capabilities.cratelimit -- #number
|
||||
if not cancrates then
|
||||
@@ -2118,6 +2166,7 @@ function CTLD:_RepairObjectFromCrates(Group,Unit,Crates,Build,Number,Engineering
|
||||
desttimer:Start(self.repairtime - 1)
|
||||
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,object,true,NearestGroup:GetCoordinate())
|
||||
buildtimer:Start(self.repairtime)
|
||||
self:__CratesRepairStarted(1,Group,Unit)
|
||||
else
|
||||
if not Engineering then
|
||||
self:_SendMessage("Can't repair this unit with " .. build.Name, 10, false, Group)
|
||||
@@ -2260,9 +2309,10 @@ end
|
||||
-- @param #CTLD_CARGO Cargo
|
||||
-- @param #number number Number of crates to generate (for dropping)
|
||||
-- @param #boolean drop If true we\'re dropping from heli rather than loading.
|
||||
function CTLD:_GetCrates(Group, Unit, Cargo, number, drop)
|
||||
-- @param #boolean pack If true we\'re packing crates from a template rather than loading or dropping
|
||||
function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack)
|
||||
self:T(self.lid .. " _GetCrates")
|
||||
if not drop then
|
||||
if not drop and not pack then
|
||||
local cgoname = Cargo:GetName()
|
||||
-- check if we have stock
|
||||
local instock = Cargo:GetStock()
|
||||
@@ -2279,18 +2329,20 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop)
|
||||
local width = 20
|
||||
local distance = nil
|
||||
local zone = nil
|
||||
if not drop then
|
||||
if not drop and not pack then
|
||||
inzone = self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD)
|
||||
if not inzone then
|
||||
---@diagnostic disable-next-line: cast-local-type
|
||||
inzone, ship, zone, distance, width = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP)
|
||||
end
|
||||
else
|
||||
elseif drop and not pack then
|
||||
if self.dropcratesanywhere then -- #1570
|
||||
inzone = true
|
||||
else
|
||||
inzone = self:IsUnitInZone(Unit,CTLD.CargoZoneType.DROP)
|
||||
end
|
||||
elseif pack and not drop then
|
||||
inzone = true
|
||||
end
|
||||
|
||||
if not inzone then
|
||||
@@ -2299,7 +2351,7 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop)
|
||||
end
|
||||
|
||||
-- avoid crate spam
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
|
||||
local canloadcratesno = capabilities.cratelimit
|
||||
local loaddist = self.CrateDistance or 35
|
||||
local nearcrates, numbernearby = self:_FindCratesNearby(Group,Unit,loaddist,true)
|
||||
@@ -2509,6 +2561,40 @@ function CTLD:_ListCratesNearby( _group, _unit)
|
||||
return self
|
||||
end
|
||||
|
||||
-- (Internal) Function to find and Remove nearby crates.
|
||||
-- @param #CTLD self
|
||||
-- @param Wrapper.Group#GROUP Group
|
||||
-- @param Wrapper.Unit#UNIT Unit
|
||||
-- @return #CTLD self
|
||||
function CTLD:_RemoveCratesNearby( _group, _unit)
|
||||
self:T(self.lid .. " _RemoveCratesNearby")
|
||||
local finddist = self.CrateDistance or 35
|
||||
local crates,number = self:_FindCratesNearby(_group,_unit, finddist,true) -- #table
|
||||
if number > 0 then
|
||||
local text = REPORT:New("Removing Crates Found Nearby:")
|
||||
text:Add("------------------------------------------------------------")
|
||||
for _,_entry in pairs (crates) do
|
||||
local entry = _entry -- #CTLD_CARGO
|
||||
local name = entry:GetName() --#string
|
||||
local dropped = entry:WasDropped()
|
||||
if dropped then
|
||||
text:Add(string.format("Crate for %s, %dkg removed",name, entry.PerCrateMass))
|
||||
else
|
||||
text:Add(string.format("Crate for %s, %dkg removed",name, entry.PerCrateMass))
|
||||
end
|
||||
entry:GetPositionable():Destroy(false)
|
||||
end
|
||||
if text:GetCount() == 1 then
|
||||
text:Add(" N O N E")
|
||||
end
|
||||
text:Add("------------------------------------------------------------")
|
||||
self:_SendMessage(text:Text(), 30, true, _group)
|
||||
else
|
||||
self:_SendMessage(string.format("No (loadable) crates within %d meters!",finddist), 10, false, _group)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- (Internal) Return distance in meters between two coordinates.
|
||||
-- @param #CTLD self
|
||||
-- @param Core.Point#COORDINATE _point1 Coordinate one
|
||||
@@ -2592,8 +2678,8 @@ function CTLD:_LoadCratesNearby(Group, Unit)
|
||||
local unitname = unit:GetName()
|
||||
-- see if this heli can load crates
|
||||
local unittype = unit:GetTypeName()
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities
|
||||
--local capabilities = self.UnitTypes[unittype] -- #CTLD.UnitCapabilities
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
|
||||
--local capabilities = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities
|
||||
local cancrates = capabilities.crates -- #boolean
|
||||
local cratelimit = capabilities.cratelimit -- #number
|
||||
local grounded = not self:IsUnitInAir(Unit)
|
||||
@@ -2744,7 +2830,7 @@ function CTLD:_GetMaxLoadableMass(Unit)
|
||||
if not Unit then return 0 end
|
||||
local loadable = 0
|
||||
local loadedmass = self:_GetUnitCargoMass(Unit)
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
|
||||
local maxmass = capabilities.cargoweightlimit or 2000 -- max 2 tons
|
||||
loadable = maxmass - loadedmass
|
||||
return loadable
|
||||
@@ -2769,7 +2855,7 @@ function CTLD:_ListCargo(Group, Unit)
|
||||
self:T(self.lid .. " _ListCargo")
|
||||
local unitname = Unit:GetName()
|
||||
local unittype = Unit:GetTypeName()
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
|
||||
local trooplimit = capabilities.trooplimit -- #boolean
|
||||
local cratelimit = capabilities.cratelimit -- #number
|
||||
local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo
|
||||
@@ -3217,6 +3303,7 @@ function CTLD:_BuildCrates(Group, Unit,Engineering)
|
||||
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate())
|
||||
buildtimer:Start(self.buildtime)
|
||||
self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group)
|
||||
self:__CratesBuildStarted(1,Group,Unit)
|
||||
else
|
||||
self:_BuildObjectFromCrates(Group,Unit,build)
|
||||
end
|
||||
@@ -3229,6 +3316,42 @@ function CTLD:_BuildCrates(Group, Unit,Engineering)
|
||||
return self
|
||||
end
|
||||
|
||||
--- (Internal) Function to repair nearby vehicles / FOBs
|
||||
-- @param #CTLD self
|
||||
-- @param Wrapper.Group#GROUP Group
|
||||
-- @param Wrapper.Unit#UNIT Unit
|
||||
|
||||
function CTLD:_PackCratesNearby(Group, Unit)
|
||||
self:T(self.lid .. " _PackCratesNearby")
|
||||
-----------------------------------------
|
||||
-- search for nearest group to player
|
||||
-- determine if group is packable
|
||||
-- generate crates and destroy group
|
||||
-----------------------------------------
|
||||
|
||||
-- get nearby vehicles
|
||||
local location = Group:GetCoordinate() -- get coordinate of group using function
|
||||
local nearestGroups = SET_GROUP:New():FilterCoalitions("blue"):FilterZones({ZONE_RADIUS:New("TempZone", location:GetVec2(), self.PackDistance, false)}):FilterOnce() -- get all groups withing PackDistance from group using function
|
||||
-- get template name of all vehicles in zone
|
||||
|
||||
-- determine if group is packable
|
||||
for _, _Group in pairs(nearestGroups.Set) do -- convert #SET_GROUP to a list of Wrapper.Group#GROUP
|
||||
for _, _Template in pairs(_DATABASE.Templates.Groups) do -- iterate through the database of templates
|
||||
if (string.match(_Group:GetName(), _Template.GroupName)) then -- check if the Wrapper.Group#GROUP near the player is in the list of templates by name
|
||||
-- generate crates and destroy group
|
||||
for _, _entry in pairs(self.Cargo_Crates) do -- iterate through #CTLD_CARGO
|
||||
if (_entry.Templates[1] == _Template.GroupName) then -- check if the #CTLD_CARGO matches the template name
|
||||
_Group:Destroy() -- if a match is found destroy the Wrapper.Group#GROUP near the player
|
||||
self:_GetCrates(Group, Unit, _entry, nil, false, true) -- spawn the appropriate crates near the player
|
||||
return self
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- (Internal) Function to repair nearby vehicles / FOBs
|
||||
-- @param #CTLD self
|
||||
-- @param Wrapper.Group#GROUP Group
|
||||
@@ -3491,13 +3614,19 @@ function CTLD:_RefreshF10Menus()
|
||||
if _group then
|
||||
-- get chopper capabilities
|
||||
local unittype = _unit:GetTypeName()
|
||||
local capabilities = self:_GetUnitCapabilities(_unit) -- #CTLD.UnitCapabilities
|
||||
local capabilities = self:_GetUnitCapabilities(_unit) -- #CTLD.UnitTypeCapabilities
|
||||
local cantroops = capabilities.troops
|
||||
local cancrates = capabilities.crates
|
||||
-- top menu
|
||||
local topmenu = MENU_GROUP:New(_group,"CTLD",nil)
|
||||
local toptroops = MENU_GROUP:New(_group,"Manage Troops",topmenu)
|
||||
local topcrates = MENU_GROUP:New(_group,"Manage Crates",topmenu)
|
||||
local toptroops = nil
|
||||
local topcrates = nil
|
||||
if cantroops then
|
||||
toptroops = MENU_GROUP:New(_group,"Manage Troops",topmenu)
|
||||
end
|
||||
if cancrates then
|
||||
topcrates = MENU_GROUP:New(_group,"Manage Crates",topmenu)
|
||||
end
|
||||
local listmenu = MENU_GROUP_COMMAND:New(_group,"List boarded cargo",topmenu, self._ListCargo, self, _group, _unit)
|
||||
local invtry = MENU_GROUP_COMMAND:New(_group,"Inventory",topmenu, self._ListInventory, self, _group, _unit)
|
||||
local rbcns = MENU_GROUP_COMMAND:New(_group,"List active zone beacons",topmenu, self._ListRadioBeacons, self, _group, _unit)
|
||||
@@ -3541,6 +3670,7 @@ function CTLD:_RefreshF10Menus()
|
||||
if cancrates then
|
||||
local loadmenu = MENU_GROUP_COMMAND:New(_group,"Load crates",topcrates, self._LoadCratesNearby, self, _group, _unit)
|
||||
local cratesmenu = MENU_GROUP:New(_group,"Get Crates",topcrates)
|
||||
local packmenu = MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit)
|
||||
|
||||
if self.usesubcats then
|
||||
local subcatmenus = {}
|
||||
@@ -3576,6 +3706,7 @@ function CTLD:_RefreshF10Menus()
|
||||
end
|
||||
end
|
||||
listmenu = MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates, self._ListCratesNearby, self, _group, _unit)
|
||||
listmenu = MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",topcrates, self._RemoveCratesNearby, self, _group, _unit)
|
||||
local unloadmenu = MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates, self._UnloadCrates, self, _group, _unit)
|
||||
if not self.nobuildmenu then
|
||||
local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit)
|
||||
@@ -4293,7 +4424,7 @@ end
|
||||
-- @param #number Trooplimit Unit can carry number of troops. Default 0.
|
||||
-- @param #number Length Unit lenght (in metres) for the load radius. Default 20.
|
||||
-- @param #number Maxcargoweight Maxmimum weight in kgs this helo can carry. Default 500.
|
||||
function CTLD:UnitCapabilities(Unittype, Cancrates, Cantroops, Cratelimit, Trooplimit, Length, Maxcargoweight)
|
||||
function CTLD:SetUnitCapabilities(Unittype, Cancrates, Cantroops, Cratelimit, Trooplimit, Length, Maxcargoweight)
|
||||
self:T(self.lid .. " UnitCapabilities")
|
||||
local unittype = nil
|
||||
local unit = nil
|
||||
@@ -4307,13 +4438,13 @@ end
|
||||
end
|
||||
local length = 20
|
||||
local maxcargo = 500
|
||||
local existingcaps = self.UnitTypes[unittype] -- #CTLD.UnitCapabilities
|
||||
local existingcaps = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities
|
||||
if existingcaps then
|
||||
length = existingcaps.length or 20
|
||||
maxcargo = existingcaps.cargoweightlimit or 500
|
||||
end
|
||||
-- set capabilities
|
||||
local capabilities = {} -- #CTLD.UnitCapabilities
|
||||
local capabilities = {} -- #CTLD.UnitTypeCapabilities
|
||||
capabilities.type = unittype
|
||||
capabilities.crates = Cancrates or false
|
||||
capabilities.troops = Cantroops or false
|
||||
@@ -4321,10 +4452,26 @@ end
|
||||
capabilities.trooplimit = Trooplimit or 0
|
||||
capabilities.length = Length or length
|
||||
capabilities.cargoweightlimit = Maxcargoweight or maxcargo
|
||||
self.UnitTypes[unittype] = capabilities
|
||||
self.UnitTypeCapabilities[unittype] = capabilities
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Deprecated] - Function to add/adjust unittype capabilities. Has been replaced with `SetUnitCapabilities()` - pls use the new one going forward!
|
||||
-- @param #CTLD self
|
||||
-- @param #string Unittype The unittype to adjust. If passed as Wrapper.Unit#UNIT, it will search for the unit in the mission.
|
||||
-- @param #boolean Cancrates Unit can load crates. Default false.
|
||||
-- @param #boolean Cantroops Unit can load troops. Default false.
|
||||
-- @param #number Cratelimit Unit can carry number of crates. Default 0.
|
||||
-- @param #number Trooplimit Unit can carry number of troops. Default 0.
|
||||
-- @param #number Length Unit lenght (in metres) for the load radius. Default 20.
|
||||
-- @param #number Maxcargoweight Maxmimum weight in kgs this helo can carry. Default 500.
|
||||
function CTLD:UnitCapabilities(Unittype, Cancrates, Cantroops, Cratelimit, Trooplimit, Length, Maxcargoweight)
|
||||
self:I(self.lid.."This function been replaced with `SetUnitCapabilities()` - pls use the new one going forward!")
|
||||
self:SetUnitCapabilities(Unittype, Cancrates, Cantroops, Cratelimit, Trooplimit, Length, Maxcargoweight)
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- (Internal) Check if a unit is hovering *in parameters*.
|
||||
-- @param #CTLD self
|
||||
-- @param Wrapper.Unit#UNIT Unit
|
||||
@@ -4477,7 +4624,7 @@ end
|
||||
local unittype = Unit:GetTypeName()
|
||||
local unitname = Unit:GetName()
|
||||
local Group = Unit:GetGroup()
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
|
||||
local cancrates = capabilities.crates -- #boolean
|
||||
local cratelimit = capabilities.cratelimit -- #number
|
||||
if cancrates then
|
||||
|
||||
@@ -329,7 +329,7 @@ FLIGHTCONTROL.FlightStatus={
|
||||
|
||||
--- FlightControl class version.
|
||||
-- @field #string version
|
||||
FLIGHTCONTROL.version="0.7.4"
|
||||
FLIGHTCONTROL.version="0.7.5"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -424,12 +424,14 @@ function FLIGHTCONTROL:New(AirbaseName, Frequency, Modulation, PathToSRS, Port,
|
||||
self.msrsTower=MSRS:New(PathToSRS, Frequency, Modulation)
|
||||
self.msrsTower:SetPort(self.Port)
|
||||
self.msrsTower:SetGoogle(GoogleKey)
|
||||
self.msrsTower:SetCoordinate(self:GetCoordinate())
|
||||
self:SetSRSTower()
|
||||
|
||||
-- SRS for Pilot.
|
||||
self.msrsPilot=MSRS:New(PathToSRS, Frequency, Modulation)
|
||||
self.msrsPilot:SetPort(self.Port)
|
||||
self.msrsPilot:SetGoogle(GoogleKey)
|
||||
self.msrsTower:SetCoordinate(self:GetCoordinate())
|
||||
self:SetSRSPilot()
|
||||
|
||||
-- Wait at least 10 seconds after last radio message before calling the next status update.
|
||||
@@ -2809,7 +2811,11 @@ function FLIGHTCONTROL:_PlayerInfoATIS(groupname)
|
||||
|
||||
-- Radio message.
|
||||
self:TransmissionPilot(rtext, flight)
|
||||
self:TransmissionTower(srstxt,flight,10)
|
||||
if self.atis then
|
||||
self:TransmissionTower(srstxt,flight,10)
|
||||
else
|
||||
self:TransmissionTower(text,flight,10)
|
||||
end
|
||||
|
||||
else
|
||||
self:E(self.lid..string.format("Cannot find flight group %s.", tostring(groupname)))
|
||||
@@ -4341,7 +4347,7 @@ function FLIGHTCONTROL:TransmissionPilot(Text, Flight, Delay)
|
||||
local text=self:_GetTextForSpeech(Text)
|
||||
|
||||
-- MSRS instance to use.
|
||||
local msrs=self.msrsPilot
|
||||
local msrs=self.msrsPilot -- Sound.SRS#MSRS
|
||||
|
||||
if Flight.useSRS and Flight.msrs then
|
||||
|
||||
@@ -4361,6 +4367,8 @@ function FLIGHTCONTROL:TransmissionPilot(Text, Flight, Delay)
|
||||
end
|
||||
|
||||
-- Add transmission to msrsqueue.
|
||||
local coordinate = Flight:GetCoordinate(true)
|
||||
msrs:SetCoordinate()
|
||||
self.msrsqueue:NewTransmission(text, nil, msrs, nil, 1, subgroups, Text, nil, self.frequency, self.modulation)
|
||||
|
||||
end
|
||||
@@ -4437,11 +4445,21 @@ function FLIGHTCONTROL:SpawnParkingGuard(unit)
|
||||
-- Length of the unit + 3 meters.
|
||||
local size, x, y, z=unit:GetObjectSize()
|
||||
|
||||
local xdiff = 3
|
||||
--Fix for hangars, puts the guy out front and not on top.
|
||||
if AIRBASE._CheckTerminalType(spot.TerminalType, AIRBASE.TerminalType.Shelter) then
|
||||
xdiff = 27-(x*0.5)
|
||||
end
|
||||
|
||||
if (AIRBASE._CheckTerminalType(spot.TerminalType, AIRBASE.TerminalType.OpenMed) or AIRBASE._CheckTerminalType(spot.TerminalType, AIRBASE.TerminalType.Shelter)) and self.airbasename == AIRBASE.Sinai.Ramon_Airbase then
|
||||
xdiff = 12
|
||||
end
|
||||
|
||||
-- Debug message.
|
||||
self:T2(self.lid..string.format("Parking guard for %s: heading=%d, distance x=%.1f m", unit:GetName(), heading, x))
|
||||
self:T2(self.lid..string.format("Parking guard for %s: heading=%d, length x=%.1f m, xdiff=%.1f m", unit:GetName(), heading, x, xdiff))
|
||||
|
||||
-- Coordinate for the guard.
|
||||
local Coordinate=coordinate:Translate(0.75*x+3, heading)
|
||||
local Coordinate=coordinate:Translate(x*0.5+xdiff, heading)
|
||||
|
||||
-- Let him face the aircraft.
|
||||
local lookat=heading-180
|
||||
|
||||
@@ -216,7 +216,7 @@ FLIGHTGROUP.Players={}
|
||||
|
||||
--- FLIGHTGROUP class version.
|
||||
-- @field #string version
|
||||
FLIGHTGROUP.version="1.0.1"
|
||||
FLIGHTGROUP.version="1.0.2"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -1256,21 +1256,21 @@ function FLIGHTGROUP:Status()
|
||||
|
||||
-- Check damage.
|
||||
self:_CheckDamage()
|
||||
|
||||
|
||||
-- Get current mission (if any).
|
||||
local mission=self:GetMissionCurrent()
|
||||
|
||||
-- TODO: Check if group is waiting?
|
||||
if self:IsWaiting() then
|
||||
if self.Twaiting and self.dTwait then
|
||||
if timer.getAbsTime()>self.Twaiting+self.dTwait then
|
||||
--self.Twaiting=nil
|
||||
--self.dTwait=nil
|
||||
--self:Cruise()
|
||||
--self:_CheckGroupDone()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Get current mission (if any).
|
||||
local mission=self:GetMissionCurrent()
|
||||
|
||||
-- If mission, check if DCS task needs to be updated.
|
||||
if mission and mission.updateDCSTask then
|
||||
|
||||
@@ -1363,7 +1363,7 @@ function FLIGHTGROUP:Status()
|
||||
|
||||
else
|
||||
-- Check damage.
|
||||
self:_CheckDamage()
|
||||
self:_CheckDamage()
|
||||
end
|
||||
|
||||
---
|
||||
@@ -1617,9 +1617,15 @@ function FLIGHTGROUP:Status()
|
||||
---
|
||||
|
||||
self:_PrintTaskAndMissionStatus()
|
||||
|
||||
-- Current mission.
|
||||
|
||||
-- All done?
|
||||
-- Get current mission (if any).
|
||||
local mission=self:GetMissionCurrent()
|
||||
if not mission then
|
||||
self.Twaiting=nil
|
||||
self.dTwait=nil
|
||||
self:_CheckGroupDone()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -2857,8 +2863,11 @@ function FLIGHTGROUP:_CheckGroupDone(delay, waittime)
|
||||
end
|
||||
|
||||
else
|
||||
-- Check if not parking (could be on ALERT5 and just spawned (current mission=nil)
|
||||
if not self:IsParking() then
|
||||
self:T(self.lid..string.format("Passed Final WP but Tasks=%d or Missions=%d left in the queue. Wait!", nTasks, nMissions))
|
||||
self:__Wait(-1)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:T(self.lid..string.format("Passed Final WP but still have current Task (#%s) or Mission (#%s) left to do", tostring(self.taskcurrent), tostring(self.currentmission)))
|
||||
@@ -4789,7 +4798,7 @@ function FLIGHTGROUP:_GetTerminal(_attribute, _category)
|
||||
-- Default terminal is "large".
|
||||
local _terminal=AIRBASE.TerminalType.OpenBig
|
||||
|
||||
if _attribute==FLIGHTGROUP.Attribute.AIR_FIGHTER then
|
||||
if _attribute==FLIGHTGROUP.Attribute.AIR_FIGHTER or _attribute==FLIGHTGROUP.Attribute.AIR_UAV then
|
||||
-- Fighter ==> small.
|
||||
_terminal=AIRBASE.TerminalType.FighterAircraft
|
||||
elseif _attribute==FLIGHTGROUP.Attribute.AIR_BOMBER or _attribute==FLIGHTGROUP.Attribute.AIR_TRANSPORTPLANE or _attribute==FLIGHTGROUP.Attribute.AIR_TANKER or _attribute==FLIGHTGROUP.Attribute.AIR_AWACS then
|
||||
|
||||
@@ -1768,6 +1768,8 @@ function OPSGROUP:GetDCSUnit(UnitNumber)
|
||||
if DCSGroup then
|
||||
local unit=DCSGroup:getUnit(UnitNumber or 1)
|
||||
return unit
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: DCS group does not exist! Cannot get unit"))
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -2345,6 +2347,10 @@ function OPSGROUP:RadioTransmission(Text, Delay, SayCallsign, Frequency)
|
||||
|
||||
local freq, modu, radioon=self:GetRadio()
|
||||
|
||||
local coord = self:GetCoordinate()
|
||||
|
||||
self.msrs:SetCoordinate(coord)
|
||||
|
||||
if Frequency then
|
||||
self.msrs:SetFrequencies(Frequency)
|
||||
else
|
||||
@@ -3468,10 +3474,9 @@ function OPSGROUP:RemoveWaypoint(wpindex)
|
||||
|
||||
-- Could be that the waypoint we are currently moving to was the LAST waypoint. Then we now passed the final waypoint.
|
||||
if (self.adinfinitum or istemp) then
|
||||
self:_PassedFinalWaypoint(false, "Removed PASSED temporary waypoint ")
|
||||
end
|
||||
|
||||
|
||||
self:_PassedFinalWaypoint(false, "Removed PASSED temporary waypoint")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -3517,9 +3522,11 @@ function OPSGROUP:OnEventBirth(EventData)
|
||||
local element=self:GetElementByName(unitname)
|
||||
|
||||
if element and element.status~=OPSGROUP.ElementStatus.SPAWNED then
|
||||
|
||||
|
||||
-- Debug info.
|
||||
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.
|
||||
self:ElementSpawned(element)
|
||||
@@ -5797,6 +5804,27 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission)
|
||||
end
|
||||
end
|
||||
|
||||
if self.legion and self.legionReturn==false and self.waypoints and #self.waypoints==1 then
|
||||
---
|
||||
-- This is the case where a group was send on a mission (which is over now), has no addional
|
||||
-- waypoints or tasks and should NOT return to its legion.
|
||||
-- We create a new waypoint at the current position and let it hold here.
|
||||
---
|
||||
|
||||
local Coordinate=self:GetCoordinate()
|
||||
|
||||
if self.isArmygroup then
|
||||
ARMYGROUP.AddWaypoint(self, Coordinate, 0, nil, nil, false)
|
||||
elseif self.isNavygroup then
|
||||
NAVYGROUP.AddWaypoint(self,Coordinate, 0, nil, nil, false)
|
||||
end
|
||||
|
||||
-- Remove original waypoint.
|
||||
self:RemoveWaypoint(1)
|
||||
|
||||
self:_PassedFinalWaypoint(true, "Passed final waypoint as group is done with mission but should NOT return to its legion")
|
||||
end
|
||||
|
||||
-- Check if group is done.
|
||||
self:_CheckGroupDone(delay)
|
||||
|
||||
|
||||
@@ -1025,7 +1025,7 @@ function OPSZONE:Scan()
|
||||
if ZoneObject then
|
||||
|
||||
-- Object category.
|
||||
local ObjectCategory=ZoneObject:getCategory()
|
||||
local ObjectCategory=Object.getCategory(ZoneObject)
|
||||
|
||||
if ObjectCategory==Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() then
|
||||
|
||||
@@ -1483,11 +1483,11 @@ function OPSZONE:_GetZoneColor()
|
||||
local color={0,0,0}
|
||||
|
||||
if self.ownerCurrent==coalition.side.NEUTRAL then
|
||||
color={1, 1, 1}
|
||||
color=self.ZoneOwnerNeutral or {1, 1, 1}
|
||||
elseif self.ownerCurrent==coalition.side.BLUE then
|
||||
color={0, 0, 1}
|
||||
color=self.ZoneOwnerBlue or {0, 0, 1}
|
||||
elseif self.ownerCurrent==coalition.side.RED then
|
||||
color={1, 0, 0}
|
||||
color=self.ZoneOwnerRed or {1, 0, 0}
|
||||
else
|
||||
|
||||
end
|
||||
@@ -1495,6 +1495,21 @@ function OPSZONE:_GetZoneColor()
|
||||
return color
|
||||
end
|
||||
|
||||
--- Set custom RGB color of zone depending on current owner.
|
||||
-- @param #OPSZONE self
|
||||
-- @param #table Neutral Color is a table of RGB values 0..1 for Red, Green, and Blue respectively, e.g. {1,0,0} for red.
|
||||
-- @param #table Blue Color is a table of RGB values 0..1 for Red, Green, and Blue respectively, e.g. {0,1,0} for green.
|
||||
-- @param #table Red Color is a table of RGB values 0..1 for Red, Green, and Blue respectively, e.g. {0,0,1} for blue.
|
||||
-- @return #OPSZONE self
|
||||
function OPSZONE:SetZoneColor(Neutral, Blue, Red)
|
||||
|
||||
self.ZoneOwnerNeutral = Neutral or {1, 1, 1}
|
||||
self.ZoneOwnerBlue = Blue or {0, 0, 1}
|
||||
self.ZoneOwnerRed = Red or {1, 0, 0}
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Update marker on the F10 map.
|
||||
-- @param #OPSZONE self
|
||||
function OPSZONE:_UpdateMarker()
|
||||
|
||||
@@ -104,7 +104,7 @@ PLAYERRECCE = {
|
||||
ClassName = "PLAYERRECCE",
|
||||
verbose = true,
|
||||
lid = nil,
|
||||
version = "0.0.18",
|
||||
version = "0.0.22",
|
||||
ViewZone = {},
|
||||
ViewZoneVisual = {},
|
||||
ViewZoneLaser = {},
|
||||
@@ -268,6 +268,146 @@ function PLAYERRECCE:New(Name, Coalition, PlayerSet)
|
||||
|
||||
self:I(self.lid.." Started.")
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
------------------------
|
||||
|
||||
--- Triggers the FSM event "Start". Starts the PLAYERRECCE. Note: Start() is called automatically after New().
|
||||
-- @function [parent=#PLAYERRECCE] Start
|
||||
-- @param #PLAYERRECCE self
|
||||
|
||||
--- Triggers the FSM event "Start" after a delay. Starts the PLAYERRECCE. Note: Start() is called automatically after New().
|
||||
-- @function [parent=#PLAYERRECCE] __Start
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- Triggers the FSM event "Stop". Stops the PLAYERRECCE and all its event handlers.
|
||||
-- @param #PLAYERRECCE self
|
||||
|
||||
--- Triggers the FSM event "Stop" after a delay. Stops the PLAYERRECCE and all its event handlers.
|
||||
-- @function [parent=#PLAYERRECCE] __Stop
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- FSM Function OnAfterRecceOnStation. Recce came on station.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterRecceOnStation
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param #string Playername
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
--- FSM Function OnAfterRecceOffStation. Recce went off duty.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterRecceOffStation
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param #string Playername
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
--- FSM Function OnAfterTargetDetected. Targets detected.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterTargetDetected
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param #table Targetsbyclock #table with index 1..12 containing a #table of Wrapper.Unit#UNIT objects each.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param #string Playername
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
--- FSM Function OnAfterTargetsSmoked. Smoke grenade shot.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterTargetsSmoked
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param #string Playername
|
||||
-- @param Core.Set#SET_UNIT TargetSet
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
--- FSM Function OnAfterTargetsFlared. Flares shot.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterTargetsFlared
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param #string Playername
|
||||
-- @param Core.Set#SET_UNIT TargetSet
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
--- FSM Function OnAfterIllumination. Illumination rocket shot.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterIllumination
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param #string Playername
|
||||
-- @param Core.Set#SET_UNIT TargetSet
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
--- FSM Function OnAfterTargetLasing. Lasing a new target.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterTargetLasing
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Unit#UNIT Target
|
||||
-- @param #number Lasercode
|
||||
-- @param #number Lasingtime
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
--- FSM Function OnAfterTargetLOSLost. Lost LOS on lased target.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterTargetLOSLost
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Unit#UNIT Target
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
--- FSM Function OnAfterTargetReport. Laser target report sent.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterTargetReport
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Core.Set#SET_UNIT TargetSet
|
||||
-- @param Wrapper.Unit#UNIT Target Target currently lased
|
||||
-- @param #string Text
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
--- FSM Function OnAfterTargetReportSent. All targets report sent.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterTargetReportSent
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Client#CLIENT Client Client sending the report
|
||||
-- @param #string Playername Player name
|
||||
-- @param Core.Set#SET_UNIT TargetSet Set of targets
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
--- FSM Function OnAfterShack. Lased target has been destroyed.
|
||||
-- @function [parent=#PLAYERRECCE] OnAfterShack
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Unit#UNIT Target The destroyed target (if obtainable)
|
||||
-- @return #PLAYERRECCE self
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -329,8 +469,10 @@ function PLAYERRECCE:_GetClockDirection(unit, target)
|
||||
local _playerPosition = unit:GetCoordinate() -- get position of helicopter
|
||||
local _targetpostions = target:GetCoordinate() -- get position of downed pilot
|
||||
local _heading = unit:GetHeading() -- heading
|
||||
--self:I("Heading = ".._heading)
|
||||
local DirectionVec3 = _playerPosition:GetDirectionVec3( _targetpostions )
|
||||
local Angle = _playerPosition:GetAngleDegrees( DirectionVec3 )
|
||||
--self:I("Angle = "..Angle)
|
||||
local clock = 12
|
||||
local hours = 0
|
||||
if _heading and Angle then
|
||||
@@ -338,15 +480,18 @@ function PLAYERRECCE:_GetClockDirection(unit, target)
|
||||
--if angle == 0 then angle = 360 end
|
||||
clock = _heading-Angle
|
||||
hours = (clock/30)*-1
|
||||
--self:I("hours = "..hours)
|
||||
clock = 12+hours
|
||||
clock = UTILS.Round(clock,0)
|
||||
if clock > 12 then clock = clock-12 end
|
||||
end
|
||||
if clock == 0 then clock = 12 end
|
||||
end
|
||||
--self:I("Clock ="..clock)
|
||||
return clock
|
||||
end
|
||||
|
||||
--- [User] Set a table of possible laser codes.
|
||||
-- Each new RECCE can select a code from this table, default is 1688.
|
||||
-- Each new RECCE can select a code from this table, default is { 1688, 1130, 4785, 6547, 1465, 4578 }.
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #list<#number> LaserCodes
|
||||
-- @return #PLAYERRECCE
|
||||
@@ -399,7 +544,7 @@ end
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param Wrapper.Client#CLIENT client
|
||||
-- @param #string playername
|
||||
-- @return #boolen OnOff
|
||||
-- @return #boolean OnOff
|
||||
function PLAYERRECCE:_CameraOn(client,playername)
|
||||
local camera = true
|
||||
local unit = client -- Wrapper.Unit#UNIT
|
||||
@@ -430,26 +575,31 @@ function PLAYERRECCE:_GetGazelleVivianneSight(Gazelle)
|
||||
local unit = Gazelle -- Wrapper.Unit#UNIT
|
||||
if unit and unit:IsAlive() then
|
||||
local dcsunit = Unit.getByName(Gazelle:GetName())
|
||||
local vivihorizontal = dcsunit:getDrawArgumentValue(215) or 0 -- (not in MiniGun) 1 to -1 -- zero is straight ahead, 1/-1 = 180 deg
|
||||
local vivihorizontal = dcsunit:getDrawArgumentValue(215) or 0 -- (not in MiniGun) 1 to -1 -- zero is straight ahead, 1/-1 = 180 deg,
|
||||
local vivivertical = dcsunit:getDrawArgumentValue(216) or 0 -- L/Mistral/Minigun model has no 216, ca 10deg up (=1) and down (=-1)
|
||||
-- vertical model limits 1.53846, -1.10731
|
||||
local vivioff = false
|
||||
-- -1 = -180, 1 = 180
|
||||
-- Actual view -0,66 to 0,66
|
||||
-- Nick view -0,98 to 0,98 for +/- 30°
|
||||
if vivihorizontal < -0.7 then
|
||||
vivihorizontal = -0.7
|
||||
vivioff = true
|
||||
return 0,0,0,false
|
||||
elseif vivihorizontal > 0.7 then
|
||||
vivihorizontal = 0.7
|
||||
-- Actual model view -0,66 to 0,66
|
||||
-- Nick view 1.53846, -1.10731 for - 30° to +45°
|
||||
if vivihorizontal < -0.67 then -- model end
|
||||
vivihorizontal = -0.67
|
||||
vivioff = false
|
||||
--return 0,0,0,false
|
||||
elseif vivihorizontal > 0.67 then -- vivi off
|
||||
vivihorizontal = 0.67
|
||||
vivioff = true
|
||||
return 0,0,0,false
|
||||
end
|
||||
vivivertical = vivivertical / 1.10731 -- normalize
|
||||
local horizontalview = vivihorizontal * -180
|
||||
local verticalview = vivivertical * -30 -- ca +/- 30°
|
||||
local verticalview = vivivertical * 30 -- ca +/- 30°
|
||||
--self:I(string.format("vivihorizontal=%.5f | vivivertical=%.5f",vivihorizontal,vivivertical))
|
||||
--self:I(string.format("horizontal=%.5f | vertical=%.5f",horizontalview,verticalview))
|
||||
local heading = unit:GetHeading()
|
||||
local viviheading = (heading+horizontalview)%360
|
||||
local maxview = self:_GetActualMaxLOSight(unit,viviheading, verticalview,vivioff)
|
||||
--self:I(string.format("maxview=%.5f",maxview))
|
||||
-- visual skew
|
||||
local factor = 3.15
|
||||
self.GazelleViewFactors = {
|
||||
@@ -469,16 +619,18 @@ function PLAYERRECCE:_GetGazelleVivianneSight(Gazelle)
|
||||
}
|
||||
local lfac = UTILS.Round(maxview,-2)
|
||||
if lfac <= 1300 then
|
||||
factor = self.GazelleViewFactors[lfac/100]
|
||||
--factor = self.GazelleViewFactors[lfac/100]
|
||||
factor = 3.15
|
||||
maxview = math.ceil((maxview*factor)/100)*100
|
||||
end
|
||||
if maxview > 8000 then maxview = 8000 end
|
||||
--self:I(string.format("corrected maxview=%.5f",maxview))
|
||||
return viviheading, verticalview,maxview, not vivioff
|
||||
end
|
||||
return 0,0,0,false
|
||||
end
|
||||
|
||||
--- [Internal] Get the max line of sight based on unit head and camera nod via trigonometrie. Returns 0 if camera is off.
|
||||
--- [Internal] Get the max line of sight based on unit head and camera nod via trigonometry. Returns 0 if camera is off.
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param Wrapper.Unit#UNIT unit The unit which LOS we want
|
||||
-- @param #number vheading Heading where the unit or camera is looking
|
||||
@@ -488,12 +640,13 @@ end
|
||||
function PLAYERRECCE:_GetActualMaxLOSight(unit,vheading, vnod, vivoff)
|
||||
self:T(self.lid.."_GetActualMaxLOSight")
|
||||
if vivoff then return 0 end
|
||||
--if vnod < -0.03 then vnod = -0.03 end
|
||||
local maxview = 0
|
||||
if unit and unit:IsAlive() then
|
||||
local typename = unit:GetTypeName()
|
||||
maxview = self.MaxViewDistance[typename] or 8000
|
||||
maxview = self.MaxViewDistance[typename] or 8000
|
||||
local CamHeight = self.Cameraheight[typename] or 0
|
||||
if vnod > 0 then
|
||||
if vnod < 0 then
|
||||
-- Looking down
|
||||
-- determine max distance we're looking at
|
||||
local beta = 90
|
||||
@@ -505,7 +658,7 @@ function PLAYERRECCE:_GetActualMaxLOSight(unit,vheading, vnod, vivoff)
|
||||
maxview = c*1.2 -- +20%
|
||||
end
|
||||
end
|
||||
return maxview
|
||||
return math.abs(maxview)
|
||||
end
|
||||
|
||||
--- [User] Set callsign options for TTS output. See @{Wrapper.Group#GROUP.GetCustomCallSign}() on how to set customized callsigns.
|
||||
@@ -561,8 +714,8 @@ function PLAYERRECCE:_GetViewZone(unit, vheading, minview, maxview, angle, camon
|
||||
local heading2 = (vheading-90)%360
|
||||
self:T({heading1,heading2})
|
||||
local startpos = startp:Translate(minview,vheading)
|
||||
local pos1 = startpos:Translate(10,heading1)
|
||||
local pos2 = startpos:Translate(10,heading2)
|
||||
local pos1 = startpos:Translate(12.5,heading1)
|
||||
local pos2 = startpos:Translate(12.5,heading2)
|
||||
local pos3 = pos1:Translate(maxview,vheading)
|
||||
local pos4 = pos2:Translate(maxview,vheading)
|
||||
local array = {}
|
||||
@@ -764,31 +917,49 @@ function PLAYERRECCE:_LaseTarget(client,targetset)
|
||||
else
|
||||
laser = self.LaserSpots[playername]
|
||||
end
|
||||
-- old target
|
||||
if self.LaserTarget[playername] then
|
||||
-- still looking at target?
|
||||
local target=self.LaserTarget[playername] -- Ops.Target#TARGET
|
||||
local oldtarget = target:GetObject() --or laser.Target
|
||||
self:T("Targetstate: "..target:GetState())
|
||||
if not oldtarget or targetset:IsNotInSet(oldtarget) or target:IsDead() or target:IsDestroyed() then
|
||||
self:T("Laser State: "..tostring(laser:IsLasing()))
|
||||
if (not oldtarget) or targetset:IsNotInSet(oldtarget) or target:IsDead() or target:IsDestroyed() then
|
||||
-- lost LOS or dead
|
||||
laser:LaseOff()
|
||||
if target:IsDead() or target:IsDestroyed() or target:GetLife() < 2 then
|
||||
self:__Shack(-1,client,oldtarget)
|
||||
self.LaserTarget[playername] = nil
|
||||
--self.LaserTarget[playername] = nil
|
||||
else
|
||||
self:__TargetLOSLost(-1,client,oldtarget)
|
||||
self.LaserTarget[playername] = nil
|
||||
--self.LaserTarget[playername] = nil
|
||||
end
|
||||
self.LaserTarget[playername] = nil
|
||||
oldtarget = nil
|
||||
self.LaserSpots[playername] = nil
|
||||
elseif oldtarget and laser and (not laser:IsLasing()) then
|
||||
--laser:LaseOff()
|
||||
self:T("Switching laser back on ..")
|
||||
local lasercode = self.UnitLaserCodes[playername] or laser.LaserCode or 1688
|
||||
local lasingtime = self.lasingtime or 60
|
||||
--local targettype = target:GetTypeName()
|
||||
laser:LaseOn(oldtarget,lasercode,lasingtime)
|
||||
--self:__TargetLasing(-1,client,oldtarget,lasercode,lasingtime)
|
||||
else
|
||||
-- we should not be here...
|
||||
self:T("Target alive and laser is on!")
|
||||
--self.LaserSpots[playername] = nil
|
||||
end
|
||||
elseif not laser:IsLasing() and target then
|
||||
-- new target
|
||||
elseif (not laser:IsLasing()) and target then
|
||||
local relativecam = self.LaserRelativePos[client:GetTypeName()]
|
||||
laser:SetRelativeStartPosition(relativecam)
|
||||
local lasercode = self.UnitLaserCodes[playername] or laser.LaserCode or 1688
|
||||
local lasingtime = self.lasingtime or 60
|
||||
local targettype = target:GetTypeName()
|
||||
--local targettype = target:GetTypeName()
|
||||
laser:LaseOn(target,lasercode,lasingtime)
|
||||
self.LaserTarget[playername] = TARGET:New(target)
|
||||
self.LaserTarget[playername].TStatus = 9
|
||||
--self.LaserTarget[playername].TStatus = 9
|
||||
self:__TargetLasing(-1,client,target,lasercode,lasingtime)
|
||||
end
|
||||
return self
|
||||
@@ -870,6 +1041,13 @@ function PLAYERRECCE:_SwitchLasing(client,group,playername)
|
||||
MESSAGE:New("Lasing is now ON",10,self.Name or "FACA"):ToClient(client)
|
||||
else
|
||||
self.AutoLase[playername] = false
|
||||
if self.LaserSpots[playername] then
|
||||
local laser = self.LaserSpots[playername] -- Core.Spot#SPOT
|
||||
if laser:IsLasing() then
|
||||
laser:LaseOff()
|
||||
end
|
||||
self.LaserSpots[playername] = nil
|
||||
end
|
||||
MESSAGE:New("Lasing is now OFF",10,self.Name or "FACA"):ToClient(client)
|
||||
end
|
||||
if self.ClientMenus[playername] then
|
||||
@@ -953,9 +1131,13 @@ function PLAYERRECCE:_SmokeTargets(client,group,playername)
|
||||
end
|
||||
end
|
||||
|
||||
local coordinate = nil
|
||||
local setthreat = 0
|
||||
-- smoke everything else
|
||||
local coordinate = cameraset:GetCoordinate()
|
||||
local setthreat = cameraset:CalculateThreatLevelA2G()
|
||||
if cameraset:CountAlive() > 1 then
|
||||
local coordinate = cameraset:GetCoordinate()
|
||||
local setthreat = cameraset:CalculateThreatLevelA2G()
|
||||
end
|
||||
|
||||
if coordinate then
|
||||
local color = lowsmoke
|
||||
@@ -1520,12 +1702,16 @@ function PLAYERRECCE:onafterRecceOnStation(From, Event, To, Client, Playername)
|
||||
local text2tts = string.format("All stations, FACA %s on station at %s!",callsign, coordtext)
|
||||
text2tts = self:_GetTextForSpeech(text2tts)
|
||||
if self.debug then
|
||||
self:I(text2.."\n"..text2tts)
|
||||
self:T(text2.."\n"..text2tts)
|
||||
end
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
local coord = grp:GetCoordinate()
|
||||
if coord then
|
||||
self.SRS:SetCoordinate(coord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(text1,nil,self.SRS,nil,2)
|
||||
self.SRSQueue:NewTransmission(text2tts,nil,self.SRS,nil,2)
|
||||
self.SRSQueue:NewTransmission(text2tts,nil,self.SRS,nil,3)
|
||||
MESSAGE:New(text2,10,self.Name or "FACA"):ToCoalition(self.Coalition)
|
||||
else
|
||||
MESSAGE:New(text1,10,self.Name or "FACA"):ToClient(Client)
|
||||
@@ -1555,13 +1741,17 @@ function PLAYERRECCE:onafterRecceOffStation(From, Event, To, Client, Playername)
|
||||
local texttts = string.format("All stations, FACA %s leaving station at %s, good bye!",callsign, coordtext)
|
||||
texttts = self:_GetTextForSpeech(texttts)
|
||||
if self.debug then
|
||||
self:I(text.."\n"..texttts)
|
||||
self:T(text.."\n"..texttts)
|
||||
end
|
||||
local text1 = "Going home!"
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
local coord = grp:GetCoordinate()
|
||||
if coord then
|
||||
self.SRS:SetCoordinate(coord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(text1,nil,self.SRS,nil,2)
|
||||
self.SRSQueue:NewTransmission(texttts,nil,self.SRS,nil,2)
|
||||
self.SRSQueue:NewTransmission(texttts,nil,self.SRS,nil,3)
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToCoalition(self.Coalition)
|
||||
else
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToCoalition(self.Coalition)
|
||||
@@ -1574,7 +1764,7 @@ end
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param #table Targetsbyclock
|
||||
-- @param #table Targetsbyclock. #table with index 1..12 containing a #table of Wrapper.Unit#UNIT objects each.
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param #string Playername
|
||||
-- @return #PLAYERRECCE self
|
||||
@@ -1617,6 +1807,9 @@ function PLAYERRECCE:onafterTargetDetected(From, Event, To, Targetsbyclock, Clie
|
||||
local ttstext = string.format("Target! %s! %s oh clock, %d %s!", ThreatTxt, i, targetdistance, dunits)
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
if clientcoord then
|
||||
self.SRS:SetCoordinate(clientcoord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10)
|
||||
else
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client)
|
||||
@@ -1653,6 +1846,10 @@ function PLAYERRECCE:onafterTargetDetected(From, Event, To, Targetsbyclock, Clie
|
||||
local ttstext = string.format("%d targets! %s oh clock, %d %s!", targetno, i, targetdistance, dunits)
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
local coord = grp:GetCoordinate()
|
||||
if coord then
|
||||
self.SRS:SetCoordinate(coord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10)
|
||||
else
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client)
|
||||
@@ -1694,6 +1891,10 @@ function PLAYERRECCE:onafterIllumination(From, Event, To, Client, Playername, Ta
|
||||
local ttstext = "Sunshine!"
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
local coord = grp:GetCoordinate()
|
||||
if coord then
|
||||
self.SRS:SetCoordinate(coord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10)
|
||||
else
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client)
|
||||
@@ -1733,6 +1934,10 @@ function PLAYERRECCE:onafterTargetsSmoked(From, Event, To, Client, Playername, T
|
||||
local ttstext = "Smoke and Mirrors!"
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
local coord = grp:GetCoordinate()
|
||||
if coord then
|
||||
self.SRS:SetCoordinate(coord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10)
|
||||
else
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client)
|
||||
@@ -1772,6 +1977,10 @@ function PLAYERRECCE:onafterTargetsFlared(From, Event, To, Client, Playername, T
|
||||
local ttstext = "Fire works!"
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
local coord = grp:GetCoordinate()
|
||||
if coord then
|
||||
self.SRS:SetCoordinate(coord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10)
|
||||
else
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client)
|
||||
@@ -1808,7 +2017,7 @@ function PLAYERRECCE:onafterTargetLasing(From, Event, To, Client, Target, Laserc
|
||||
coordtext = coord:ToStringFromRPShort(self.ReferencePoint,self.RPName,client,Settings)
|
||||
end
|
||||
local coordtext = coord:ToStringA2G(client,Settings)
|
||||
local text = string.format("All stations, %s lasing %s\nat %s!\nCode %d, Duration %d seconds!",callsign, targettype, coordtext, Lasercode, Lasingtime)
|
||||
local text = string.format("All stations, %s lasing %s\nat %s!\nCode %d, Duration %d plus seconds!",callsign, targettype, coordtext, Lasercode, Lasingtime)
|
||||
MESSAGE:New(text,15,self.Name or "FACA"):ToClient(client)
|
||||
end
|
||||
end
|
||||
@@ -1817,6 +2026,10 @@ function PLAYERRECCE:onafterTargetLasing(From, Event, To, Client, Target, Laserc
|
||||
local ttstext = "Laser on!"
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
local coord = grp:GetCoordinate()
|
||||
if coord then
|
||||
self.SRS:SetCoordinate(coord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10)
|
||||
else
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client)
|
||||
@@ -1831,9 +2044,8 @@ end
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Wrapper.Unit#UNIT Target
|
||||
-- @param #string Targettype
|
||||
-- @return #PLAYERRECCE self
|
||||
function PLAYERRECCE:onafterShack(From, Event, To, Client, Target, Targettype)
|
||||
function PLAYERRECCE:onafterShack(From, Event, To, Client, Target)
|
||||
self:T({From, Event, To})
|
||||
local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
||||
local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS
|
||||
@@ -1861,6 +2073,10 @@ function PLAYERRECCE:onafterShack(From, Event, To, Client, Target, Targettype)
|
||||
local ttstext = "Shack!"
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
local coord = grp:GetCoordinate()
|
||||
if coord then
|
||||
self.SRS:SetCoordinate(coord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1)
|
||||
else
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client)
|
||||
@@ -1904,6 +2120,10 @@ function PLAYERRECCE:onafterTargetLOSLost(From, Event, To, Client, Target)
|
||||
local ttstext = "Lost L O S!"
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
local coord = grp:GetCoordinate()
|
||||
if coord then
|
||||
self.SRS:SetCoordinate(coord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10)
|
||||
else
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client)
|
||||
@@ -1933,7 +2153,6 @@ function PLAYERRECCE:onafterTargetReport(From, Event, To, Client, TargetSet, Tar
|
||||
end
|
||||
end
|
||||
end
|
||||
--self:__TargetReportSent(-2,Client, TargetSet, Target, Text)
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1942,16 +2161,19 @@ end
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Client#CLIENT Client
|
||||
-- @param Core.Set#SET_UNIT TargetSet
|
||||
-- @param Wrapper.Unit#UNIT Target
|
||||
-- @param #string Text
|
||||
-- @param Wrapper.Client#CLIENT Client Client sending the report
|
||||
-- @param #string Playername Player name
|
||||
-- @param Core.Set#SET_UNIT TargetSet Set of targets
|
||||
-- @return #PLAYERRECCE self
|
||||
function PLAYERRECCE:onafterTargetReportSent(From, Event, To, Client, TargetSet)
|
||||
function PLAYERRECCE:onafterTargetReportSent(From, Event, To, Client, Playername, TargetSet)
|
||||
self:T({From, Event, To})
|
||||
local text = "Upload completed!"
|
||||
if self.UseSRS then
|
||||
local grp = Client:GetGroup()
|
||||
local coord = grp:GetCoordinate()
|
||||
if coord then
|
||||
self.SRS:SetCoordinate(coord)
|
||||
end
|
||||
self.SRSQueue:NewTransmission(text,nil,self.SRS,nil,1,{grp},text,10)
|
||||
else
|
||||
MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client)
|
||||
|
||||
@@ -98,7 +98,7 @@ PLAYERTASK = {
|
||||
|
||||
--- PLAYERTASK class version.
|
||||
-- @field #string version
|
||||
PLAYERTASK.version="0.1.21"
|
||||
PLAYERTASK.version="0.1.22"
|
||||
|
||||
--- Generic task condition.
|
||||
-- @type PLAYERTASK.Condition
|
||||
@@ -935,7 +935,7 @@ end
|
||||
do
|
||||
-------------------------------------------------------------------------------------------------------------------
|
||||
-- PLAYERTASKCONTROLLER
|
||||
-- TODO: PLAYERTASKCONTROLLER
|
||||
-- TODO: PLAYERTASKCONTROLLER
|
||||
-- DONE Playername customized
|
||||
-- DONE Coalition-level screen info to SET based
|
||||
-- DONE Flash directions
|
||||
@@ -1552,7 +1552,7 @@ PLAYERTASKCONTROLLER.Messages = {
|
||||
|
||||
--- PLAYERTASK class version.
|
||||
-- @field #string version
|
||||
PLAYERTASKCONTROLLER.version="0.1.62"
|
||||
PLAYERTASKCONTROLLER.version="0.1.63"
|
||||
|
||||
--- Create and run a new TASKCONTROLLER instance.
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
@@ -1579,13 +1579,13 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter)
|
||||
self.ClusterRadius = 0.5
|
||||
self.TargetRadius = 500
|
||||
|
||||
self.ClientFilter = ClientFilter or ""
|
||||
self.ClientFilter = ClientFilter --or ""
|
||||
|
||||
self.TargetQueue = FIFO:New() -- Utilities.FiFo#FIFO
|
||||
self.TaskQueue = FIFO:New() -- Utilities.FiFo#FIFO
|
||||
self.TasksPerPlayer = FIFO:New() -- Utilities.FiFo#FIFO
|
||||
self.PrecisionTasks = FIFO:New() -- Utilities.FiFo#FIFO
|
||||
self.PlayerMenu = {} -- #table
|
||||
--self.PlayerMenu = {} -- #table
|
||||
self.FlashPlayer = {} -- #table
|
||||
self.AllowFlash = false
|
||||
self.lasttaskcount = 0
|
||||
@@ -2175,10 +2175,10 @@ function PLAYERTASKCONTROLLER:_EventHandler(EventData)
|
||||
if EventData.id == EVENTS.PlayerLeaveUnit or EventData.id == EVENTS.Ejection or EventData.id == EVENTS.Crash or EventData.id == EVENTS.PilotDead then
|
||||
if EventData.IniPlayerName then
|
||||
self:T(self.lid.."Event for player: "..EventData.IniPlayerName)
|
||||
if self.PlayerMenu[EventData.IniPlayerName] then
|
||||
self.PlayerMenu[EventData.IniPlayerName]:Remove()
|
||||
self.PlayerMenu[EventData.IniPlayerName] = nil
|
||||
end
|
||||
--if self.PlayerMenu[EventData.IniPlayerName] then
|
||||
--self.PlayerMenu[EventData.IniPlayerName]:Remove()
|
||||
--self.PlayerMenu[EventData.IniPlayerName] = nil
|
||||
--end
|
||||
local text = ""
|
||||
if self.TasksPerPlayer:HasUniqueID(EventData.IniPlayerName) then
|
||||
local task = self.TasksPerPlayer:PullByID(EventData.IniPlayerName) -- Ops.PlayerTask#PLAYERTASK
|
||||
@@ -2187,6 +2187,8 @@ function PLAYERTASKCONTROLLER:_EventHandler(EventData)
|
||||
task:RemoveClient(Client)
|
||||
--text = "Task aborted!"
|
||||
text = self.gettext:GetEntry("TASKABORT",self.locale)
|
||||
self.ActiveTaskMenuTemplate:ResetMenu(Client)
|
||||
self.JoinTaskMenuTemplate:ResetMenu(Client)
|
||||
else
|
||||
task:RemoveClient(nil,EventData.IniPlayerName)
|
||||
--text = "Task aborted!"
|
||||
@@ -2236,8 +2238,8 @@ function PLAYERTASKCONTROLLER:_EventHandler(EventData)
|
||||
self.SRSQueue:NewTransmission(text,nil,self.SRS,timer.getAbsTime()+60,2,{EventData.IniGroup},text,30,self.BCFrequency,self.BCModulation)
|
||||
end
|
||||
if EventData.IniPlayerName then
|
||||
self.PlayerMenu[EventData.IniPlayerName] = nil
|
||||
local player = CLIENT:FindByName(EventData.IniUnitName)
|
||||
--self.PlayerMenu[EventData.IniPlayerName] = nil
|
||||
local player = _DATABASE:FindClient( EventData.IniUnitName )
|
||||
self:_SwitchMenuForClient(player,"Info")
|
||||
end
|
||||
end
|
||||
@@ -2949,7 +2951,7 @@ function PLAYERTASKCONTROLLER:_AddTask(Target)
|
||||
task:HandleEvent(EVENTS.Shot)
|
||||
function task:OnEventShot(EventData)
|
||||
local data = EventData -- Core.Event#EVENTDATA EventData
|
||||
local wcat = data.Weapon:getCategory() -- cat 2 or 3
|
||||
local wcat = Object.getCategory(data.Weapon) -- cat 2 or 3
|
||||
local coord = data.IniUnit:GetCoordinate() or data.IniGroup:GetCoordinate()
|
||||
local vec2 = coord:GetVec2() or {x=0, y=0}
|
||||
local coal = data.IniCoalition
|
||||
@@ -4003,8 +4005,9 @@ end
|
||||
-- Note that this must be installed on your windows system. Can also be Google voice types, if you are using Google TTS.
|
||||
-- @param #number Volume (Optional) Volume - between 0.0 (silent) and 1.0 (loudest)
|
||||
-- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS
|
||||
-- @param Core.Point#COORDINATE Coordinate Coordinate from which the controller radio is sending
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey)
|
||||
function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,Coordinate)
|
||||
self:T(self.lid.."SetSRS")
|
||||
self.PathToSRS = PathToSRS or "C:\\Program Files\\DCS-SimpleRadio-Standalone" --
|
||||
self.Gender = Gender or "male" --
|
||||
@@ -4029,6 +4032,9 @@ function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Cultu
|
||||
if self.PathToGoogleKey then
|
||||
self.SRS:SetGoogle(self.PathToGoogleKey)
|
||||
end
|
||||
if Coordinate then
|
||||
self.SRS:SetCoordinate(Coordinate)
|
||||
end
|
||||
self.SRSQueue = MSRSQUEUE:New(self.MenuName or self.Name)
|
||||
self.SRSQueue:SetTransmitOnlyWithPlayers(self.TransmitOnlyWithPlayers)
|
||||
return self
|
||||
|
||||
@@ -64,8 +64,6 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # Recue Helo
|
||||
--
|
||||
-- The rescue helo will fly in close formation with another unit, which is typically an aircraft carrier.
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
--
|
||||
-- * First, you need to **"add a @{#RADIO} object** to your @{Wrapper.Positionable#POSITIONABLE}. This is done using the @{Wrapper.Positionable#POSITIONABLE.GetRadio}() function,
|
||||
-- * Then, you will **set the relevant parameters** to the transmission (see below),
|
||||
-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function.
|
||||
-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{#RADIO.Broadcast}() function.
|
||||
--
|
||||
-- Methods to set relevant parameters for both a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or any other @{Wrapper.Positionable#POSITIONABLE}
|
||||
--
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
--- Makes the radio speak.
|
||||
--
|
||||
-- # RADIOSPEECH usage
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- @type RADIOSPEECH
|
||||
-- @extends Core.RadioQueue#RADIOQUEUE
|
||||
-- @extends Sound.RadioQueue#RADIOQUEUE
|
||||
RADIOSPEECH = {
|
||||
ClassName = "RADIOSPEECH",
|
||||
Vocabulary = {
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
-- @field #string ConfigFileName Name of the standard config file
|
||||
-- @field #string ConfigFilePath Path to the standard config file
|
||||
-- @field #boolean ConfigLoaded
|
||||
-- @field #string ttsprovider Default provider TTS backend, e.g. "Google" or "Microsoft", default is Microsoft
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
|
||||
@@ -127,6 +128,10 @@
|
||||
--
|
||||
-- Use @{#MSRS.SetVolume} to define the SRS volume. Defaults to 1.0. Allowed values are between 0.0 and 1.0, from silent to loudest.
|
||||
--
|
||||
-- ## Config file for many variables, auto-loaded by Moose
|
||||
--
|
||||
-- See @{#MSRS.LoadConfigFile} for details on how to set this up.
|
||||
--
|
||||
-- ## Set DCS-gRPC as an alternative to 'DCS-SR-ExternalAudio.exe' for TTS
|
||||
--
|
||||
-- Use @{#MSRS.SetDefaultBackendGRPC} to enable [DCS-gRPC](https://github.com/DCS-gRPC/rust-server) as an alternate backend for transmitting text-to-speech over SRS.
|
||||
@@ -191,11 +196,12 @@ MSRS = {
|
||||
ConfigFileName = "Moose_MSRS.lua",
|
||||
ConfigFilePath = "Config\\",
|
||||
ConfigLoaded = false,
|
||||
ttsprovider = "Microsoft",
|
||||
}
|
||||
|
||||
--- MSRS class version.
|
||||
-- @field #string version
|
||||
MSRS.version="0.1.2"
|
||||
MSRS.version="0.1.3"
|
||||
|
||||
--- Voices
|
||||
-- @type MSRS.Voices
|
||||
@@ -377,9 +383,7 @@ function MSRS:New(PathToSRS, Frequency, Modulation, Volume, AltBackend)
|
||||
return self:_NewAltBackend(Backend)
|
||||
end
|
||||
|
||||
local success = self:LoadConfigFile(nil,nil,self.ConfigLoaded)
|
||||
|
||||
if (not success) and (not self.ConfigLoaded) then
|
||||
if not self.ConfigLoaded then
|
||||
|
||||
-- If no AltBackend table, the proceed with default initialisation
|
||||
self:SetPath(PathToSRS)
|
||||
@@ -446,7 +450,7 @@ function MSRS:SetPath(Path)
|
||||
end
|
||||
|
||||
-- Debug output.
|
||||
self:I(string.format("SRS path=%s", self:GetPath()))
|
||||
self:T(string.format("SRS path=%s", self:GetPath()))
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -674,7 +678,7 @@ function MSRS:SetCoordinate(Coordinate)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Use google text-to-speech.
|
||||
--- Use google text-to-speech credentials. Also sets Google as default TTS provider.
|
||||
-- @param #MSRS self
|
||||
-- @param #string PathToCredentials Full path to the google credentials JSON file, e.g. "C:\Users\username\Downloads\service-account-file.json". Can also be the Google API key.
|
||||
-- @return #MSRS self
|
||||
@@ -688,13 +692,14 @@ function MSRS:SetGoogle(PathToCredentials)
|
||||
|
||||
self.GRPCOptions.DefaultProvider = "gcloud"
|
||||
self.GRPCOptions.gcloud.key = PathToCredentials
|
||||
self.ttsprovider = "Google"
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Use google text-to-speech.
|
||||
--- gRPC Backend: Use google text-to-speech set the API key.
|
||||
-- @param #MSRS self
|
||||
-- @param #string APIKey API Key, usually a string of length 40 with characters and numbers.
|
||||
-- @return #MSRS self
|
||||
@@ -708,6 +713,22 @@ function MSRS:SetGoogleAPIKey(APIKey)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Use Google text-to-speech as default.
|
||||
-- @param #MSRS self
|
||||
-- @return #MSRS self
|
||||
function MSRS:SetTTSProviderGoogle()
|
||||
self.ttsprovider = "Google"
|
||||
return self
|
||||
end
|
||||
|
||||
--- Use Microsoft text-to-speech as default.
|
||||
-- @param #MSRS self
|
||||
-- @return #MSRS self
|
||||
function MSRS:SetTTSProviderMicrosoft()
|
||||
self.ttsprovider = "Microsoft"
|
||||
return self
|
||||
end
|
||||
|
||||
--- Print SRS STTS help to DCS log file.
|
||||
-- @param #MSRS self
|
||||
-- @return #MSRS self
|
||||
@@ -769,7 +790,7 @@ end
|
||||
|
||||
--- Play sound file (ogg or mp3) via SRS.
|
||||
-- @param #MSRS self
|
||||
-- @param Sound.SoundFile#SOUNDFILE Soundfile Sound file to play.
|
||||
-- @param Sound.SoundOutput#SOUNDFILE Soundfile Sound file to play.
|
||||
-- @param #number Delay Delay in seconds, before the sound file is played.
|
||||
-- @return #MSRS self
|
||||
function MSRS:PlaySoundFile(Soundfile, Delay)
|
||||
@@ -797,7 +818,7 @@ end
|
||||
|
||||
--- Play a SOUNDTEXT text-to-speech object.
|
||||
-- @param #MSRS self
|
||||
-- @param Sound.SoundFile#SOUNDTEXT SoundText Sound text.
|
||||
-- @param Sound.SoundOutput#SOUNDTEXT SoundText Sound text.
|
||||
-- @param #number Delay Delay in seconds, before the sound file is played.
|
||||
-- @return #MSRS self
|
||||
function MSRS:PlaySoundText(SoundText, Delay)
|
||||
@@ -824,15 +845,16 @@ end
|
||||
-- @param #MSRS self
|
||||
-- @param #string Text Text message.
|
||||
-- @param #number Delay Delay in seconds, before the message is played.
|
||||
-- @param Core.Point#COORDINATE Coordinate Coordinate.
|
||||
-- @return #MSRS self
|
||||
function MSRS:PlayText(Text, Delay)
|
||||
function MSRS:PlayText(Text, Delay, Coordinate)
|
||||
|
||||
if Delay and Delay>0 then
|
||||
self:ScheduleOnce(Delay, MSRS.PlayText, self, Text, 0)
|
||||
self:ScheduleOnce(Delay, MSRS.PlayText, self, Text, nil, Coordinate)
|
||||
else
|
||||
|
||||
-- Get command line.
|
||||
local command=self:_GetCommand()
|
||||
local command=self:_GetCommand(nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,Coordinate)
|
||||
|
||||
-- Append text.
|
||||
command=command..string.format(" --text=\"%s\"", tostring(Text))
|
||||
@@ -856,11 +878,12 @@ end
|
||||
-- @param #string Voice Voice.
|
||||
-- @param #number Volume Volume.
|
||||
-- @param #string Label Label.
|
||||
-- @param Core.Point#COORDINATE Coordinate Coordinate.
|
||||
-- @return #MSRS self
|
||||
function MSRS:PlayTextExt(Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
|
||||
function MSRS:PlayTextExt(Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label, Coordinate)
|
||||
|
||||
if Delay and Delay>0 then
|
||||
self:ScheduleOnce(Delay, MSRS.PlayTextExt, self, Text, 0, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
|
||||
self:ScheduleOnce(Delay, MSRS.PlayTextExt, self, Text, 0, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label, Coordinate)
|
||||
else
|
||||
|
||||
-- Ensure table.
|
||||
@@ -874,7 +897,7 @@ function MSRS:PlayTextExt(Text, Delay, Frequencies, Modulations, Gender, Culture
|
||||
end
|
||||
|
||||
-- Get command line.
|
||||
local command=self:_GetCommand(Frequencies, Modulations, nil, Gender, Voice, Culture, Volume, nil, nil, Label)
|
||||
local command=self:_GetCommand(Frequencies, Modulations, nil, Gender, Voice, Culture, Volume, nil, nil, Label, Coordinate)
|
||||
|
||||
-- Append text.
|
||||
command=command..string.format(" --text=\"%s\"", tostring(Text))
|
||||
@@ -1065,8 +1088,9 @@ end
|
||||
-- @param #number speed Speed.
|
||||
-- @param #number port Port.
|
||||
-- @param #string label Label, defaults to "ROBOT" (displayed sender name in the radio overlay of SRS) - No spaces allowed!
|
||||
-- @param Core.Point#COORDINATE coordinate Coordinate.
|
||||
-- @return #string Command.
|
||||
function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, speed, port,label)
|
||||
function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, speed, port,label,coordinate)
|
||||
|
||||
local path=self:GetPath() or STTS.DIRECTORY
|
||||
local exe=STTS.EXECUTABLE or "DCS-SR-ExternalAudio.exe"
|
||||
@@ -1080,6 +1104,7 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
||||
speed=speed or self.speed
|
||||
port=port or self.port
|
||||
label=label or self.Label
|
||||
coordinate=coordinate or self.coordinate
|
||||
|
||||
-- Replace modulation
|
||||
modus=modus:gsub("0", "AM")
|
||||
@@ -1104,13 +1129,13 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
||||
end
|
||||
|
||||
-- Set coordinate.
|
||||
if self.coordinate then
|
||||
local lat,lon,alt=self:_GetLatLongAlt(self.coordinate)
|
||||
if coordinate then
|
||||
local lat,lon,alt=self:_GetLatLongAlt(coordinate)
|
||||
command=command..string.format(" -L %.4f -O %.4f -A %d", lat, lon, alt)
|
||||
end
|
||||
|
||||
-- Set google.
|
||||
if self.google then
|
||||
if self.google and self.ttsprovider == "Google" then
|
||||
command=command..string.format(' --ssml -G "%s"', self.google)
|
||||
end
|
||||
|
||||
@@ -1124,7 +1149,6 @@ end
|
||||
-- @param #MSRS self
|
||||
-- @param #string Path Path to config file, defaults to "C:\Users\<yourname>\Saved Games\DCS\Config"
|
||||
-- @param #string Filename File to load, defaults to "Moose_MSRS.lua"
|
||||
-- @param #boolean ConfigLoaded - if true, skip the loading
|
||||
-- @return #boolean success
|
||||
-- @usage
|
||||
-- 0) Benefits: Centralize configuration of SRS, keep paths and keys out of the mission source code, making it safer and easier to move missions to/between servers,
|
||||
@@ -1134,18 +1158,19 @@ end
|
||||
--
|
||||
-- -- Moose MSRS default Config
|
||||
-- MSRS_Config = {
|
||||
-- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone", -- adjust as needed
|
||||
-- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone", -- adjust as needed, note double \\
|
||||
-- Port = 5002, -- adjust as needed
|
||||
-- Frequency = {127,243}, -- must be a table, 1..n entries!
|
||||
-- Modulation = {0,0}, -- must be a table, 1..n entries, one for each frequency!
|
||||
-- Volume = 1.0,
|
||||
-- Volume = 1.0, -- 0.0 to 1.0
|
||||
-- Coalition = 0, -- 0 = Neutral, 1 = Red, 2 = Blue
|
||||
-- Coordinate = {0,0,0}, -- x,y,alt - optional
|
||||
-- Coordinate = {0,0,0}, -- x,y,altitude - optional, all in meters
|
||||
-- Culture = "en-GB",
|
||||
-- Gender = "male",
|
||||
-- Google = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourfilename.json", -- path to google json key file - optional
|
||||
-- Google = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourfilename.json", -- path to google json key file - optional.
|
||||
-- Label = "MSRS",
|
||||
-- Voice = "Microsoft Hazel Desktop",
|
||||
-- Provider = "Microsoft", -- this is the default TTS provider, e.g. "Google" or "Microsoft"
|
||||
-- -- gRPC (optional)
|
||||
-- GRPC = { -- see https://github.com/DCS-gRPC/rust-server
|
||||
-- coalition = "blue", -- blue, red, neutral
|
||||
@@ -1162,14 +1187,18 @@ end
|
||||
-- }
|
||||
-- }
|
||||
--
|
||||
-- 3) Load the config into the MSRS raw class before you do anything else:
|
||||
-- 3) The config file is automatically loaded when Moose starts. YOu can also load the config into the MSRS raw class manually before you do anything else:
|
||||
--
|
||||
-- MSRS.LoadConfigFile() -- Note the "." here
|
||||
--
|
||||
-- Optionally, your might want to provide a specific path and filename:
|
||||
--
|
||||
-- MSRS.LoadConfigFile(nil,MyPath,MyFilename) -- Note the "." here
|
||||
--
|
||||
-- This will populate variables for the MSRS raw class and all instances you create with e.g. `mysrs = MSRS:New()`
|
||||
-- Optionally you can also load this per **single instance** if so needed, i.e.
|
||||
--
|
||||
-- mysrs:LoadConfig(Path,Filename)
|
||||
-- mysrs:LoadConfigFile(Path,Filename)
|
||||
--
|
||||
-- 4) Use the config in your code like so, variable names are basically the same as in the config file, but all lower case, examples:
|
||||
--
|
||||
@@ -1186,46 +1215,21 @@ end
|
||||
-- atis:SetSRS(nil,nil,nil,MSRS.Voices.Google.Standard.en_US_Standard_H)
|
||||
-- --Start ATIS
|
||||
-- atis:Start()
|
||||
function MSRS:LoadConfigFile(Path,Filename,ConfigLoaded)
|
||||
|
||||
function MSRS:LoadConfigFile(Path,Filename)
|
||||
|
||||
if lfs == nil then
|
||||
env.info("*****Note - lfs and os need to be desanitized for MSRS to work!")
|
||||
return false
|
||||
end
|
||||
local path = Path or lfs.writedir()..MSRS.ConfigFilePath
|
||||
local file = Filename or MSRS.ConfigFileName or "Moose_MSRS.lua"
|
||||
local pathandfile = path..file
|
||||
local filexsists = UTILS.FileExists(pathandfile)
|
||||
|
||||
if UTILS.CheckFileExists(path,file) and not ConfigLoaded then
|
||||
if filexsists and not MSRS.ConfigLoaded then
|
||||
assert(loadfile(path..file))()
|
||||
-- now we should have a global var MSRS_Config
|
||||
if MSRS_Config then
|
||||
--[[
|
||||
-- Moose MSRS default Config
|
||||
MSRS_Config = {
|
||||
Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone", -- adjust as needed
|
||||
Port = 5002, -- adjust as needed
|
||||
Frequency = {127,243}, -- must be a table, 1..n entries!
|
||||
Modulation = {0,0}, -- must be a table, 1..n entries, one for each frequency!
|
||||
Volume = 1.0,
|
||||
Coalition = 0, -- 0 = Neutral, 1 = Red, 2 = Blue
|
||||
Coordinate = {0,0,0}, -- x,y,alt - optional
|
||||
Culture = "en-GB",
|
||||
Gender = "male",
|
||||
Google = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourfilename.json", -- path to google json key file - optional
|
||||
Label = "MSRS",
|
||||
Voice = "Microsoft Hazel Desktop",
|
||||
-- gRPC (optional)
|
||||
GRPC = { -- see https://github.com/DCS-gRPC/rust-server
|
||||
coalition = "blue", -- blue, red, neutral
|
||||
DefaultProvider = "gcloud", -- win, gcloud, aws, or azure, some of the values below depend on your cloud provider
|
||||
gcloud = {
|
||||
key = "<API Google Key>", -- for gRPC Google API key
|
||||
--secret = "", -- needed for aws
|
||||
--region = "",-- needed for aws
|
||||
defaultVoice = MSRS.Voices.Google.Standard.en_GB_Standard_F,
|
||||
},
|
||||
win = {
|
||||
defaultVoice = "Hazel",
|
||||
},
|
||||
}
|
||||
}
|
||||
--]]
|
||||
if self then
|
||||
self.path = MSRS_Config.Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.port = MSRS_Config.Port or 5002
|
||||
@@ -1238,8 +1242,11 @@ function MSRS:LoadConfigFile(Path,Filename,ConfigLoaded)
|
||||
self.culture = MSRS_Config.Culture or "en-GB"
|
||||
self.gender = MSRS_Config.Gender or "male"
|
||||
self.google = MSRS_Config.Google
|
||||
if MSRS_Config.Provider then
|
||||
self.ttsprovider = MSRS_Config.Provider
|
||||
end
|
||||
self.Label = MSRS_Config.Label or "MSRS"
|
||||
self.voice = MSRS_Config.Voice or MSRS.Voices.Microsoft.Hazel
|
||||
self.voice = MSRS_Config.Voice --or MSRS.Voices.Microsoft.Hazel
|
||||
if MSRS_Config.GRPC then
|
||||
self.provider = MSRS_Config.GRPC.DefaultProvider
|
||||
if MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider] then
|
||||
@@ -1262,8 +1269,11 @@ function MSRS:LoadConfigFile(Path,Filename,ConfigLoaded)
|
||||
MSRS.culture = MSRS_Config.Culture or "en-GB"
|
||||
MSRS.gender = MSRS_Config.Gender or "male"
|
||||
MSRS.google = MSRS_Config.Google
|
||||
if MSRS_Config.Provider then
|
||||
MSRS.ttsprovider = MSRS_Config.Provider
|
||||
end
|
||||
MSRS.Label = MSRS_Config.Label or "MSRS"
|
||||
MSRS.voice = MSRS_Config.Voice or MSRS.Voices.Microsoft.Hazel
|
||||
MSRS.voice = MSRS_Config.Voice --or MSRS.Voices.Microsoft.Hazel
|
||||
if MSRS_Config.GRPC then
|
||||
MSRS.provider = MSRS_Config.GRPC.DefaultProvider
|
||||
if MSRS_Config.GRPC[MSRS_Config.GRPC.DefaultProvider] then
|
||||
@@ -1276,9 +1286,10 @@ function MSRS:LoadConfigFile(Path,Filename,ConfigLoaded)
|
||||
MSRS.ConfigLoaded = true
|
||||
end
|
||||
end
|
||||
env.info("MSRS - Sucessfully loaded default configuration from disk!",false)
|
||||
else
|
||||
env.info("MSRS - Cannot load default configuration from disk!",false)
|
||||
env.info("MSRS - Successfully loaded default configuration from disk!",false)
|
||||
end
|
||||
if not filexsists then
|
||||
env.info("MSRS - Cannot find default configuration file!",false)
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -1417,7 +1428,7 @@ end
|
||||
|
||||
--- Replacement function for @{#MSRS.PlaySoundText}
|
||||
-- @param #MSRS self
|
||||
-- @param Sound.SoundFile#SOUNDTEXT SoundText Sound text.
|
||||
-- @param Sound.SoundOutput#SOUNDTEXT SoundText Sound text.
|
||||
-- @param #number Delay Delay in seconds, before the sound file is played.
|
||||
-- @return #MSRS self
|
||||
MSRS_BACKEND_DCSGRPC.Functions.PlaySoundText = function (self, SoundText, Delay)
|
||||
@@ -1649,6 +1660,7 @@ MSRSQUEUE = {
|
||||
-- @field #string voice Voice if any
|
||||
-- @field #number volume Volume
|
||||
-- @field #string label Label to be used
|
||||
-- @field Core.Point#COORDINATE coordinate Coordinate for this transmission
|
||||
|
||||
--- Create a new MSRSQUEUE object for a given radio frequency/modulation.
|
||||
-- @param #MSRSQUEUE self
|
||||
@@ -1672,7 +1684,7 @@ end
|
||||
-- @param #MSRSQUEUE self
|
||||
-- @return #MSRSQUEUE self The MSRSQUEUE object.
|
||||
function MSRSQUEUE:Clear()
|
||||
self:I(self.lid.."Clearning MSRSQUEUE")
|
||||
self:I(self.lid.."Clearing MSRSQUEUE")
|
||||
self.queue={}
|
||||
return self
|
||||
end
|
||||
@@ -1733,8 +1745,9 @@ end
|
||||
-- @param #string voice Specific voice
|
||||
-- @param #number volume Volume setting
|
||||
-- @param #string label Label to be used
|
||||
-- @param Core.Point#COORDINATE coordinate Coordinate to be used
|
||||
-- @return #MSRSQUEUE.Transmission Radio transmission table.
|
||||
function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgroups, subtitle, subduration, frequency, modulation, gender, culture, voice, volume, label)
|
||||
function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgroups, subtitle, subduration, frequency, modulation, gender, culture, voice, volume, label,coordinate)
|
||||
|
||||
if self.TransmitOnlyWithPlayers then
|
||||
if self.PlayerSet and self.PlayerSet:CountAlive() == 0 then
|
||||
@@ -1772,9 +1785,10 @@ function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgr
|
||||
transmission.gender = gender
|
||||
transmission.culture = culture
|
||||
transmission.voice = voice
|
||||
transmission.gender = volume
|
||||
transmission.volume = volume
|
||||
transmission.label = label
|
||||
|
||||
transmission.coordinate = coordinate
|
||||
|
||||
-- Add transmission to queue.
|
||||
self:AddTransmission(transmission)
|
||||
|
||||
@@ -1785,11 +1799,11 @@ end
|
||||
-- @param #MSRSQUEUE self
|
||||
-- @param #MSRSQUEUE.Transmission transmission The transmission.
|
||||
function MSRSQUEUE:Broadcast(transmission)
|
||||
|
||||
|
||||
if transmission.frequency then
|
||||
transmission.msrs:PlayTextExt(transmission.text, nil, transmission.frequency, transmission.modulation, transmission.gender, transmission.culture, transmission.voice, transmission.volume, transmission.label)
|
||||
transmission.msrs:PlayTextExt(transmission.text, nil, transmission.frequency, transmission.modulation, transmission.gender, transmission.culture, transmission.voice, transmission.volume, transmission.label, transmission.coordinate)
|
||||
else
|
||||
transmission.msrs:PlayText(transmission.text)
|
||||
transmission.msrs:PlayText(transmission.text,nil,transmission.coordinate)
|
||||
end
|
||||
|
||||
local function texttogroup(gid)
|
||||
@@ -1988,6 +2002,7 @@ function MSRSQUEUE:_CheckRadioQueue(delay)
|
||||
|
||||
end
|
||||
|
||||
MSRS.LoadConfigFile()
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -313,7 +313,7 @@ do -- Text-To-Speech
|
||||
--
|
||||
-- ## Specific Voice
|
||||
--
|
||||
-- You can use a specific voice for the transmission with the @{SOUNDTEXT.SetVoice}(*VoiceName*) function. Here are some examples
|
||||
-- You can use a specific voice for the transmission with the @{#SOUNDTEXT.SetVoice}(*VoiceName*) function. Here are some examples
|
||||
--
|
||||
-- * Name: Microsoft Hazel Desktop, Culture: en-GB, Gender: Female, Age: Adult, Desc: Microsoft Hazel Desktop - English (Great Britain)
|
||||
-- * Name: Microsoft David Desktop, Culture: en-US, Gender: Male, Age: Adult, Desc: Microsoft David Desktop - English (United States)
|
||||
|
||||
@@ -162,12 +162,12 @@
|
||||
-- choose from 2 added menu options either to accept or reject the assigned task within 30 seconds.
|
||||
-- If the task is not accepted within 30 seconds; the task will be cancelled and a new task will be assigned.
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- @field #COMMANDCENTER
|
||||
COMMANDCENTER = {
|
||||
ClassName = "COMMANDCENTER",
|
||||
@@ -339,7 +339,7 @@ end
|
||||
|
||||
--- Gets the coalition of the command center.
|
||||
-- @param #COMMANDCENTER self
|
||||
-- @return DCScoalition#coalition
|
||||
-- @return #number Coalition of the command center.
|
||||
function COMMANDCENTER:GetCoalition()
|
||||
|
||||
return self.CommandCenterCoalition
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
-- Derived classes need to implement the method @{#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report.
|
||||
--
|
||||
-- Reporting can be started and stopped using the methods @{#DETECTION_MANAGER.StartReporting}() and @{#DETECTION_MANAGER.StopReporting}() respectively.
|
||||
-- If an ad-hoc report is requested, use the method @{#DETECTION_MANAGER#ReportNow}().
|
||||
-- If an ad-hoc report is requested, use the method @{#DETECTION_MANAGER.ReportNow}().
|
||||
--
|
||||
-- The default reporting interval is every 60 seconds. The reporting messages are displayed 15 seconds.
|
||||
--
|
||||
@@ -32,12 +32,12 @@
|
||||
-- -------------------------------
|
||||
-- The @{#DETECTION_REPORTING.New}() method creates a new DETECTION_REPORTING instance.
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Contributions: Mechanist, Prof_Hilactic, FlightControl - Concept & Testing
|
||||
|
||||
@@ -117,12 +117,12 @@
|
||||
-- - @{#MISSION.ReportPlayersPerTask}(): Generates a report showing the active players per task.
|
||||
-- - @{#MISSION.ReportPlayersProgress}(): Generates a report showing the task progress per player.
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- @field #MISSION
|
||||
MISSION = {
|
||||
ClassName = "MISSION",
|
||||
|
||||
@@ -203,12 +203,12 @@
|
||||
--
|
||||
-- These different completion states are important for the mission designer to reflect scoring to a player.
|
||||
-- A success could mean a positive score to be given, while a failure could mean a negative score or penalties to be awarded.
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
-- Therefore, this class is considered to be deprecated
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author(s): **FlightControl**
|
||||
@@ -1773,7 +1773,7 @@ do -- Links
|
||||
|
||||
--- Set detection of a task
|
||||
-- @param #TASK self
|
||||
-- @param Function.Detection#DETECTION_BASE Detection
|
||||
-- @param Functional.Detection#DETECTION_BASE Detection
|
||||
-- @param DetectedItem
|
||||
-- @return #TASK
|
||||
function TASK:SetDetection( Detection, DetectedItem )
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user