Compare commits

..

29 Commits

Author SHA1 Message Date
FlightControl
bd9b844909 Static 2017-07-11 16:57:53 +02:00
FlightControl
3c4f0a4b97 Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-07-11 16:57:05 +02:00
FlightControl
9a40bceec5 Static 2017-07-08 14:19:43 +02:00
FlightControl
a402235da3 Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-07-08 14:19:14 +02:00
FlightControl
62b156c0e8 Static 2017-07-08 09:23:01 +02:00
FlightControl
752de77a82 Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-07-08 09:22:07 +02:00
FlightControl
e658a2a3bf Static 2017-07-07 08:26:33 +02:00
FlightControl
4b8b155fb8 Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-07-07 08:25:57 +02:00
FlightControl
ce2b982782 Static 2017-07-06 21:51:12 +02:00
FlightControl
af61fc6c74 Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-07-06 21:50:48 +02:00
FlightControl
93f7d1f013 Static 2017-07-02 23:17:59 +02:00
FlightControl
51f8c532ca Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-07-02 23:17:28 +02:00
FlightControl
f18a56ab1a Static 2017-07-02 12:59:40 +02:00
FlightControl
9dc9fcfeff Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre
# Conflicts:
#	Moose Mission Setup/Moose.lua
2017-07-02 12:58:26 +02:00
FlightControl
b217e855e9 Static 2017-06-30 10:38:30 +02:00
FlightControl
21c19bf97e Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre
# Conflicts:
#	Moose Mission Setup/Moose.lua
2017-06-30 10:38:11 +02:00
FlightControl
565237b29e Static 2017-06-29 15:00:12 +02:00
FlightControl
78085d3de2 Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-06-29 14:59:32 +02:00
FlightControl
b245292d11 Static version 2017-06-29 13:53:13 +02:00
FlightControl
dd7d5d9a56 Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-06-29 13:45:03 +02:00
FlightControl
ce688aabcb New static version 2017-06-29 10:40:56 +02:00
FlightControl
8e2e2e5a1e Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-06-29 10:38:52 +02:00
FlightControl
a1b31e0065 Updated message bug 2017-06-26 20:52:30 +02:00
FlightControl
8af5de6fb5 Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-06-26 20:52:06 +02:00
FlightControl
572d1f2902 Pre release 2017-06-26 20:35:28 +02:00
FlightControl
4a7f8b869d Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-06-26 20:35:05 +02:00
FlightControl
967c2a5633 New version 2017-06-26 10:39:32 +02:00
FlightControl
0203e73c71 Merge remote-tracking branch 'refs/remotes/origin/master' into release-2-2-pre 2017-06-25 07:41:47 +02:00
FlightControl
05e7eb3456 Static 2017-06-24 15:48:50 +02:00
864 changed files with 272337 additions and 30891 deletions

View File

@@ -1,85 +0,0 @@
version: 3.9.1.{build}
shallow_clone: true
skip_branch_with_pr: false
skip_commits:
message: /!nobuild/
skip_tags: false
environment:
access_token_documentation:
secure: JVBVVL8uJUcLXN+48eRdELEeCGOGCCaMzCqutsUqNuaZ/KblG5ZTt7+LV4UKv/0f
LUAROCKS_VER: 2.4.1
LUA_VER: 5.1.5
LUA: lua5.3
matrix:
- LUA_VER: 5.1.5
platform:
- x64
init:
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
throw "There are newer queued builds for this pull request, failing early." }
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
install:
# Outcomment if lua environment invalidates and needs to be reinstalled, otherwise all will run from the cache.
# - call choco install 7zip.commandline
# - call choco install lua51
# - call choco install luarocks
# - call refreshenv
# - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
# - cmd: PATH = %PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\bin
# - cmd: set LUA_PATH = %LUA_PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?.lua;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?\init.lua
# - cmd: set LUA_CPATH = %LUA_CPATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\lib\lua\5.1\?.dll
# - call luarocks install luasrcdiet
# - call luarocks install checks
# - call luarocks install luadocumentor
# - call luarocks install luacheck
#cache:
# - C:\ProgramData\chocolatey\lib
# - C:\ProgramData\chocolatey\bin
build_script:
- ps: |
if( $env:appveyor_repo_branch -eq 'master' )
{
$apiUrl = 'https://ci.appveyor.com/api'
$token = 'qts80b5kpq0ooj4x6vvw'
$headers = @{
"Authorization" = "Bearer $token"
"Content-type" = "application/json"
}
$RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-include'; branch = 'master'; environmentVariables = @{} } | ConvertTo-Json
# get project with last build details
$project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody
}
- ps: |
if( $env:appveyor_repo_branch -eq 'master' )
{
$apiUrl = 'https://ci.appveyor.com/api'
$token = 'qts80b5kpq0ooj4x6vvw'
$headers = @{
"Authorization" = "Bearer $token"
"Content-type" = "application/json"
}
$RequestBody = @{ accountName = 'FlightControl-Master'; projectSlug = 'moose-docs'; branch = 'master'; environmentVariables = @{} } | ConvertTo-Json
# get project with last build details
$project = Invoke-RestMethod -method Post -Uri "$apiUrl/builds" -Headers $headers -Body $RequestBody
}
test: off
# test_script:
# - cmd: luacheck "Moose Development\Moose\moose.lua" "Moose Mission Setup\moose.lua"
on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

4
.gitmodules vendored
View File

@@ -0,0 +1,4 @@
[submodule "Moose Development/Moose/Dcs"]
path = Moose Development/Moose/Dcs
url = https://github.com/FlightControl-Master/DCS-API.git
branch = master

4
DCS_Folder_Sync.bat Normal file
View File

@@ -0,0 +1,4 @@
rem This script will pull the latest changes from the remote repository, and update the submodules accordingly.
C:\Program Files (x86)\Git\bin\git pull
C:\Program Files (x86)\Git\bin\git submodule update --init

View File

@@ -1,37 +0,0 @@
--Initialization script for the Mission lua Environment (SSE)
dofile('Scripts/ScriptingSystem.lua')
-- Add LuaSocket to the LUAPATH, so that it can be found.
package.path = package.path..";.\\LuaSocket\\?.lua;"
-- Connect to the debugger, first require it.
local initconnection = require("debugger")
-- Now make the connection..
-- "127.0.0.1" is the localhost.
-- 10000 is the port. If you wanna use another port in LDT, change this number too!
-- "dcsserver" is the name of the server. If you wanna use another name, change the name here too!
-- nil (is for transport protocol, but not using this)
-- "win" don't touch. But is important to indicate that we are in a windows environment to the debugger script.
initconnection( "127.0.0.1", 10000, "dcsserver", nil, "win", "" )
--Sanitize Mission Scripting environment
--This makes unavailable some unsecure functions.
--Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions.
--You can remove the code below and make availble these functions at your own risk.
local function sanitizeModule(name)
_G[name] = nil
package.loaded[name] = nil
end
do
sanitizeModule('os')
--sanitizeModule('io')
sanitizeModule('lfs')
require = nil
loadlib = nil
end

View File

@@ -1,56 +0,0 @@
-- If you want to use the debugger, add 3 lines of extra code into MissionScripting.lua of DCS world.
-- De-sanitize the io module. The debugger needs it.
---------------------------------------------------------------------------------------------------------------------------
-- MissionScripting.lua modifications
---------------------------------------------------------------------------------------------------------------------------
-- --Initialization script for the Mission lua Environment (SSE)
--
-- dofile('Scripts/ScriptingSystem.lua')
--
-- package.path = package.path..";.\\LuaSocket\\?.lua;"
-- local initconnection = require("debugger")
-- initconnection( "127.0.0.1", 10000, "dcsserver", nil, "win", "" )
--
-- --Sanitize Mission Scripting environment
-- --This makes unavailable some unsecure functions.
-- --Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions.
-- --You can remove the code below and make availble these functions at your own risk.
--
-- local function sanitizeModule(name)
-- _G[name] = nil
-- package.loaded[name] = nil
-- end
--
-- do
-- sanitizeModule('os')
-- --sanitizeModule('io')
-- sanitizeModule('lfs')
-- require = nil
-- loadlib = nil
-- end
---------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------
-- So for clarity, these are the three lines of code that matter!
-- Add LuaSocket to the LUAPATH, so that it can be found.
package.path = package.path..";.\\LuaSocket\\?.lua;"
-- Connect to the debugger, first require it.
local initconnection = require("debugger")
-- Now make the connection..
-- "127.0.0.1" is the localhost.
-- 10000 is the port. If you wanna use another port in LDT, change this number too!
-- "dcsserver" is the name of the server. Ensure the same name is used at the Debug Configuration panel!
-- nil (is for transport protocol, but not using this)
-- "win" don't touch. But is important to indicate that we are in a windows environment to the debugger script.
initconnection( "127.0.0.1", 10000, "dcsserver", nil, "win", "" )

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Utils/GenerateDocumentations.bat}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="*.lua"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Utils}"/>
</launchConfiguration>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Utils/luarocks/lua5.1.exe}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="&quot;Moose_Create.lua&quot; &#13;&#10;&quot;D&quot;&#13;&#10;&quot;${current_date}&quot; &#13;&#10;&quot;${workspace_loc:/Moose_Framework//Moose Development/Moose}&quot; &#13;&#10;&quot;${workspace_loc:/Moose_Framework/Moose Mission Setup}&quot;"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Moose Mission Setup}"/>
</launchConfiguration>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Utils/luarocks/lua5.1.exe}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="&quot;Moose_Create.lua&quot; &#13;&#10;&quot;S&quot;&#13;&#10;&quot;${current_date}&quot; &#13;&#10;&quot;${workspace_loc:/Moose_Framework//Moose Development/Moose}&quot; &#13;&#10;&quot;${workspace_loc:/Moose_Framework/Moose Mission Setup}&quot;"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Moose Mission Setup}"/>
</launchConfiguration>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Missions}"/>
</launchConfiguration>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/Moose Mission Setup/Moose Mission Update/Moose_Update_Missions.bat}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="&quot;${selected_resource_loc}&quot;"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework/Moose Mission Setup/Moose Mission Update}"/>
</launchConfiguration>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,12 +1,14 @@
--- **AI** -- (R2.2) - Models the process of air operations for airplanes.
--- **AI** -- **AI A2A Air Patrolling or Staging.**
--
-- This is a class used in the @{AI_A2A_Dispatcher}.
-- ====
--
-- ===
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ### Author: **FlightControl**
-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Testing and API concept review.
--
-- ===
-- ====
--
-- @module AI_A2A
@@ -68,9 +70,8 @@ function AI_A2A:New( AIGroup )
self:SetControllable( AIGroup )
self:SetFuelThreshold( .2, 60 )
self:SetDamageThreshold( 0.4 )
self:SetDisengageRadius( 70000 )
self:ManageFuel( .2, 60 )
self:ManageDamage( 0.4 )
self:SetStartState( "Stopped" )
@@ -218,37 +219,8 @@ function AI_A2A:New( AIGroup )
-- @param #string Event The Event string.
-- @param #string To The To State string.
self:AddTransition( "Patrolling", "Refuel", "Refuelling" )
--- Refuel Handler OnBefore for AI_A2A
-- @function [parent=#AI_A2A] OnBeforeRefuel
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Refuel Handler OnAfter for AI_A2A
-- @function [parent=#AI_A2A] OnAfterRefuel
-- @param #AI_A2A self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From
-- @param #string Event
-- @param #string To
--- Refuel Trigger for AI_A2A
-- @function [parent=#AI_A2A] Refuel
-- @param #AI_A2A self
--- Refuel Asynchronous Trigger for AI_A2A
-- @function [parent=#AI_A2A] __Refuel
-- @param #AI_A2A self
-- @param #number Delay
self:AddTransition( "*", "Takeoff", "Airborne" )
self:AddTransition( "*", "Return", "Returning" )
self:AddTransition( "*", "Hold", "Holding" )
self:AddTransition( "*", "Home", "Home" )
self:AddTransition( "*", "LostControl", "LostControl" )
self:AddTransition( "*", "Fuel", "Fuel" )
@@ -262,13 +234,6 @@ function AI_A2A:New( AIGroup )
return self
end
--- @param Wrapper.Group#GROUP self
-- @param Core.Event#EVENTDATA EventData
function GROUP:OnEventTakeoff( EventData, Fsm )
Fsm:Takeoff()
self:UnHandleEvent( EVENTS.Takeoff )
end
function AI_A2A:SetDispatcher( Dispatcher )
self.Dispatcher = Dispatcher
end
@@ -329,27 +294,8 @@ function AI_A2A:SetHomeAirbase( HomeAirbase )
self.HomeAirbase = HomeAirbase
end
--- Sets to refuel at the given tanker.
-- @param #AI_A2A self
-- @param Wrapper.Group#GROUP TankerName The group name of the tanker as defined within the Mission Editor or spawned.
-- @return #AI_A2A self
function AI_A2A:SetTanker( TankerName )
self:F2( { TankerName } )
self.TankerName = TankerName
end
--- Sets the disengage range, that when engaging a target beyond the specified range, the engagement will be cancelled and the plane will RTB.
-- @param #AI_A2A self
-- @param #number DisengageRadius The disengage range.
-- @return #AI_A2A self
function AI_A2A:SetDisengageRadius( DisengageRadius )
self:F2( { DisengageRadius } )
self.DisengageRadius = DisengageRadius
end
--- Set the status checking off.
-- @param #AI_A2A self
-- @return #AI_A2A self
@@ -365,13 +311,13 @@ end
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_A2A.
-- Once the time is finished, the old AI will return to the base.
-- @param #AI_A2A self
-- @param #number PatrolFuelThresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
-- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
-- @return #AI_A2A self
function AI_A2A:SetFuelThreshold( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
function AI_A2A:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime )
self.PatrolManageFuel = true
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
self.PatrolFuelTresholdPercentage = PatrolFuelTresholdPercentage
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
self.Controllable:OptionRTBBingoFuel( false )
@@ -386,12 +332,12 @@ end
-- Note that for groups, the average damage of the complete group will be calculated.
-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25.
-- @param #AI_A2A self
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
-- @param #number PatrolDamageTreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
-- @return #AI_A2A self
function AI_A2A:SetDamageThreshold( PatrolDamageThreshold )
function AI_A2A:ManageDamage( PatrolDamageTreshold )
self.PatrolManageDamage = true
self.PatrolDamageThreshold = PatrolDamageThreshold
self.PatrolDamageTreshold = PatrolDamageTreshold
return self
end
@@ -426,79 +372,45 @@ end
--- @param #AI_A2A self
function AI_A2A:onafterStatus()
self:F( " Checking Status" )
self:F()
if self.Controllable and self.Controllable:IsAlive() then
local RTB = false
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
if not self:Is( "Holding" ) and not self:Is( "Returning" ) then
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
self:F({DistanceFromHomeBase=DistanceFromHomeBase})
local Fuel = self.Controllable:GetUnit(1):GetFuel()
self:F({Fuel=Fuel})
if Fuel < self.PatrolFuelTresholdPercentage then
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
local OldAIControllable = self.Controllable
local AIControllableTemplate = self.Controllable:GetTemplate()
if DistanceFromHomeBase > self.DisengageRadius then
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
self:Hold( 300 )
RTB = false
end
end
if self:Is( "Fuel" ) or self:Is( "Damaged" ) or self:Is( "LostControl" ) then
if DistanceFromHomeBase < 5000 then
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
self:Home( "Destroy" )
end
end
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
OldAIControllable:SetTask( TimedOrbitTask, 10 )
if not self:Is( "Fuel" ) and not self:Is( "Home" ) then
local Fuel = self.Controllable:GetFuel()
self:F({Fuel=Fuel})
if Fuel < self.PatrolFuelThresholdPercentage then
if self.TankerName then
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
self:Refuel()
else
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
local OldAIControllable = self.Controllable
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
OldAIControllable:SetTask( TimedOrbitTask, 10 )
self:Fuel()
RTB = true
end
else
end
self:Fuel()
RTB = true
else
end
-- TODO: Check GROUP damage function.
local Damage = self.Controllable:GetLife()
local InitialLife = self.Controllable:GetLife0()
self:F( { Damage = Damage, InitialLife = InitialLife, DamageThreshold = self.PatrolDamageThreshold } )
if ( Damage / InitialLife ) < self.PatrolDamageThreshold then
self:F( { Damage = Damage, InitialLife = InitialLife, DamageTreshold = self.PatrolDamageTreshold } )
if ( Damage / InitialLife ) < self.PatrolDamageTreshold then
self:E( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" )
self:Damaged()
RTB = true
self:SetStatusOff()
end
-- Check if planes went RTB and are out of control.
if self.Controllable:HasTask() == false then
if not self:Is( "Started" ) and
not self:Is( "Stopped" ) and
not self:Is( "Home" ) then
not self:Is( "Stopped" ) then
if self.IdleCount >= 2 then
if Damage ~= InitialLife then
self:Damaged()
else
self:E( self.Controllable:GetName() .. " control lost! " )
self:LostControl()
end
self:E( self.Controllable:GetName() .. " control lost! " )
self:LostControl()
else
self.IdleCount = self.IdleCount + 1
end
@@ -506,7 +418,7 @@ function AI_A2A:onafterStatus()
else
self.IdleCount = 0
end
if RTB == true then
self:__RTB( 0.5 )
end
@@ -517,28 +429,13 @@ end
--- @param Wrapper.Group#GROUP AIGroup
function AI_A2A.RTBRoute( AIGroup, Fsm )
function AI_A2A.RTBRoute( AIGroup )
AIGroup:F( { "AI_A2A.RTBRoute:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:__RTB( 0.5 )
end
AIGroup:E( { "RTBRoute:", AIGroup:GetName() } )
local _AI_A2A = AIGroup:GetState( AIGroup, "AI_A2A" ) -- #AI_A2A
_AI_A2A:__RTB( 0.5 )
end
--- @param Wrapper.Group#GROUP AIGroup
function AI_A2A.RTBHold( AIGroup, Fsm )
AIGroup:F( { "AI_A2A.RTBHold:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:__RTB( 0.5 )
Fsm:Return()
local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
AIGroup:SetTask( Task )
end
end
--- @param #AI_A2A self
@@ -551,6 +448,8 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
self:E( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
self.CheckStatus = false
self:ClearTargetDistance()
AIGroup:ClearTasks()
@@ -567,12 +466,11 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
local ToAirbaseCoord = CurrentCoord:Translate( 5000, ToAirbaseAngle )
if Distance < 5000 then
self:E( "RTB and near the airbase!" )
self:Home()
return
end
--- Create a route point of type air.
local ToRTBRoutePoint = ToAirbaseCoord:WaypointAir(
local ToPatrolRoutePoint = ToAirbaseCoord:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -583,8 +481,7 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
self:F( { Angle = ToAirbaseAngle, ToTargetSpeed = ToTargetSpeed } )
self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } )
EngageRoute[#EngageRoute+1] = ToRTBRoutePoint
EngageRoute[#EngageRoute+1] = ToRTBRoutePoint
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
AIGroup:OptionROEHoldFire()
AIGroup:OptionROTEvadeFire()
@@ -593,11 +490,13 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
AIGroup:WayPointInitialize( EngageRoute )
local Tasks = {}
Tasks[#Tasks+1] = AIGroup:TaskFunction( "AI_A2A.RTBRoute", self )
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( Tasks )
Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A.RTBRoute" )
EngageRoute[1].task = AIGroup:TaskCombo( Tasks )
AIGroup:SetState( AIGroup, "AI_A2A", self )
--- NOW ROUTE THE GROUP!
AIGroup:Route( EngageRoute, 0.5 )
AIGroup:WayPointExecute( 1, 0 )
end
@@ -614,89 +513,6 @@ function AI_A2A:onafterHome( AIGroup, From, Event, To )
end
end
--- @param #AI_A2A self
-- @param Wrapper.Group#GROUP AIGroup
function AI_A2A:onafterHold( AIGroup, From, Event, To, HoldTime )
self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then
local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = AIGroup:TaskControlled( OrbitTask, AIGroup:TaskCondition( nil, nil, nil, nil, HoldTime , nil ) )
local RTBTask = AIGroup:TaskFunction( "AI_A2A.RTBHold", self )
local OrbitHoldTask = AIGroup:TaskOrbitCircle( 4000, self.PatrolMinSpeed )
--AIGroup:SetState( AIGroup, "AI_A2A", self )
AIGroup:SetTask( AIGroup:TaskCombo( { TimedOrbitTask, RTBTask, OrbitHoldTask } ), 1 )
end
end
--- @param Wrapper.Group#GROUP AIGroup
function AI_A2A.Resume( AIGroup, Fsm )
AIGroup:F( { "AI_A2A.Resume:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
Fsm:__RTB( 0.5 )
end
end
--- @param #AI_A2A self
-- @param Wrapper.Group#GROUP AIGroup
function AI_A2A:onafterRefuel( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Refuelling! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then
local Tanker = GROUP:FindByName( self.TankerName )
if Tanker:IsAlive() and Tanker:IsAirPlane() then
local RefuelRoute = {}
--- Calculate the target route point.
local CurrentCoord = AIGroup:GetCoordinate()
local ToRefuelCoord = Tanker:GetCoordinate()
local ToRefuelSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
--- Create a route point of type air.
local ToRefuelRoutePoint = ToRefuelCoord:WaypointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToRefuelSpeed,
true
)
self:F( { ToRefuelSpeed = ToRefuelSpeed } )
RefuelRoute[#RefuelRoute+1] = ToRefuelRoutePoint
RefuelRoute[#RefuelRoute+1] = ToRefuelRoutePoint
AIGroup:OptionROEHoldFire()
AIGroup:OptionROTEvadeFire()
local Tasks = {}
Tasks[#Tasks+1] = AIGroup:TaskRefueling()
Tasks[#Tasks+1] = AIGroup:TaskFunction( self:GetClassName() .. ".Resume", self )
RefuelRoute[#RefuelRoute].task = AIGroup:TaskCombo( Tasks )
AIGroup:Route( RefuelRoute, 0.5 )
else
self:RTB()
end
end
end

View File

@@ -1,12 +1,28 @@
--- **AI** -- (R2.2) - Models the process of Combat Air Patrol (CAP) for airplanes.
--
-- This is a class used in the @{AI_A2A_Dispatcher}.
--- **AI** -- **Execute Combat Air Patrol (CAP).**
--
-- ![Banner Image](..\Presentations\AI_CAP\Dia1.JPG)
--
-- ===
--
-- ### Author: **FlightControl**
-- AI CAP classes makes AI Controllables execute a Combat Air Patrol.
--
-- ===
-- There are the following types of CAP classes defined:
--
-- * @{#AI_A2A_CAP}: Perform a CAP in a zone.
--
-- ====
--
-- ### Author: **Sven Van de Velde (FlightControl)**
--
-- ### Contributions:
--
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
-- * **[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.
--
-- ====
--
-- @module AI_A2A_Cap
@@ -18,7 +34,7 @@
--- # AI_A2A_CAP class, extends @{AI_CAP#AI_PATROL_ZONE}
--
-- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Group} or @{Group}
-- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
--
-- ![Process](..\Presentations\AI_CAP\Dia3.JPG)
@@ -104,20 +120,20 @@ AI_A2A_CAP = {
--- Creates a new AI_A2A_CAP object
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap
-- @param Wrapper.Group#GROUP AIGroup
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#Speed EngageMinSpeed The minimum speed of the @{Group} in km/h when engaging a target.
-- @param Dcs.DCSTypes#Speed EngageMaxSpeed The maximum speed of the @{Group} in km/h when engaging a target.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed EngageMinSpeed The minimum speed of the @{Controllable} in km/h when engaging a target.
-- @param Dcs.DCSTypes#Speed EngageMaxSpeed The maximum speed of the @{Controllable} in km/h when engaging a target.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_A2A_CAP
function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
-- Inherits from BASE
local self = BASE:Inherit( self, AI_A2A_PATROL:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2A_CAP
local self = BASE:Inherit( self, AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2A_CAP
self.Accomplished = false
self.Engaging = false
@@ -125,12 +141,12 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
self.EngageMinSpeed = EngageMinSpeed
self.EngageMaxSpeed = EngageMaxSpeed
self:AddTransition( { "Patrolling", "Engaging", "Returning", "Airborne" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP.
self:AddTransition( { "Patrolling", "Engaging", "Returning" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP.
--- OnBefore Transition Handler for Event Engage.
-- @function [parent=#AI_A2A_CAP] OnBeforeEngage
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -139,7 +155,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnAfter Transition Handler for Event Engage.
-- @function [parent=#AI_A2A_CAP] OnAfterEngage
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -156,7 +172,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnLeave Transition Handler for State Engaging.
-- @function [parent=#AI_A2A_CAP] OnLeaveEngaging
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -165,7 +181,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnEnter Transition Handler for State Engaging.
-- @function [parent=#AI_A2A_CAP] OnEnterEngaging
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -175,7 +191,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnBefore Transition Handler for Event Fired.
-- @function [parent=#AI_A2A_CAP] OnBeforeFired
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -184,7 +200,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnAfter Transition Handler for Event Fired.
-- @function [parent=#AI_A2A_CAP] OnAfterFired
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -203,7 +219,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnBefore Transition Handler for Event Destroy.
-- @function [parent=#AI_A2A_CAP] OnBeforeDestroy
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -212,7 +228,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnAfter Transition Handler for Event Destroy.
-- @function [parent=#AI_A2A_CAP] OnAfterDestroy
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -232,7 +248,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnBefore Transition Handler for Event Abort.
-- @function [parent=#AI_A2A_CAP] OnBeforeAbort
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -241,7 +257,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnAfter Transition Handler for Event Abort.
-- @function [parent=#AI_A2A_CAP] OnAfterAbort
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -260,7 +276,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnBefore Transition Handler for Event Accomplish.
-- @function [parent=#AI_A2A_CAP] OnBeforeAccomplish
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -269,7 +285,7 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
--- OnAfter Transition Handler for Event Accomplish.
-- @function [parent=#AI_A2A_CAP] OnAfterAccomplish
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -286,17 +302,6 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
return self
end
--- onafter State Transition for Event Patrol.
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AICap The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onafterStart( AICap, From, Event, To )
AICap:HandleEvent( EVENTS.Takeoff, nil, self )
end
--- Set the Engage Zone which defines where the AI will engage bogies.
-- @param #AI_A2A_CAP self
@@ -328,36 +333,33 @@ end
--- onafter State Transition for Event Patrol.
-- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The AI Group managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE AIGroup The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onafterPatrol( AICap, From, Event, To )
function AI_A2A_CAP:onafterPatrol( AIGroup, From, Event, To )
-- Call the parent Start event handler
self:GetParent(self).onafterPatrol( self, AICap, From, Event, To )
self:GetParent(self).onafterPatrol( self, AIGroup, From, Event, To )
self:HandleEvent( EVENTS.Dead )
end
-- todo: need to fix this global function
--- @param Wrapper.Group#GROUP AICap
function AI_A2A_CAP.AttackRoute( AICap, Fsm )
--- @param Wrapper.Group#GROUP AIGroup
function AI_A2A_CAP.AttackRoute( AIGroup )
AICap:F( { "AI_A2A_CAP.AttackRoute:", AICap:GetName() } )
if AICap:IsAlive() then
Fsm:__Engage( 0.5 )
end
local EngageZone = AIGroup:GetState( AIGroup, "AI_A2A_CAP" ) -- AI.AI_Cap#AI_A2A_CAP
EngageZone:__Engage( 0.5 )
end
--- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE AIGroup The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onbeforeEngage( AICap, From, Event, To )
function AI_A2A_CAP:onbeforeEngage( AIGroup, From, Event, To )
if self.Accomplished == true then
return false
@@ -365,43 +367,43 @@ function AI_A2A_CAP:onbeforeEngage( AICap, From, Event, To )
end
--- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The AI Group managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE AIGroup The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onafterAbort( AICap, From, Event, To )
AICap:ClearTasks()
function AI_A2A_CAP:onafterAbort( AIGroup, From, Event, To )
AIGroup:ClearTasks()
self:__Route( 0.5 )
end
--- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The AICap Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE AIGroup The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onafterEngage( AICap, From, Event, To, AttackSetUnit )
function AI_A2A_CAP:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
self:F( { AICap, From, Event, To, AttackSetUnit} )
self:F( { AIGroup, From, Event, To, AttackSetUnit} )
self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT
local FirstAttackUnit = self.AttackSetUnit:GetFirst() -- Wrapper.Unit#UNIT
local FirstAttackUnit = self.AttackSetUnit:GetFirst()
if FirstAttackUnit and FirstAttackUnit:IsAlive() then -- If there is no attacker anymore, stop the engagement.
if FirstAttackUnit then
if AICap:IsAlive() then
if AIGroup:IsAlive() then
local EngageRoute = {}
--- Calculate the target route point.
local CurrentCoord = AICap:GetCoordinate()
local CurrentCoord = AIGroup:GetCoordinate()
local ToTargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
local ToTargetSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
local ToInterceptAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) )
--- Create a route point of type air.
local ToPatrolRoutePoint = CurrentCoord:Translate( 5000, ToInterceptAngle ):WaypointAir(
local ToPatrolRoutePoint = CurrentCoord:Translate( 5000, ToInterceptAngle ):RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -412,31 +414,40 @@ function AI_A2A_CAP:onafterEngage( AICap, From, Event, To, AttackSetUnit )
self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } )
self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } )
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
AIGroup:OptionROEOpenFire()
AIGroup:OptionROTPassiveDefense()
local AttackTasks = {}
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
local AttackUnit = AttackUnit -- Wrapper.Unit#UNIT
self:T( { "Attacking Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } )
if AttackUnit:IsAlive() and AttackUnit:IsAir() then
AttackTasks[#AttackTasks+1] = AICap:TaskAttackUnit( AttackUnit )
AttackTasks[#AttackTasks+1] = AIGroup:TaskAttackUnit( AttackUnit )
end
end
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
self.Controllable:WayPointInitialize( EngageRoute )
if #AttackTasks == 0 then
self:E("No targets found -> Going back to Patrolling")
self:__Abort( 0.5 )
else
AICap:OptionROEOpenFire()
AICap:OptionROTEvadeFire()
AttackTasks[#AttackTasks+1] = AICap:TaskFunction( "AI_A2A_CAP.AttackRoute", self )
EngageRoute[#EngageRoute].task = AICap:TaskCombo( AttackTasks )
AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( 1, #AttackTasks, "AI_A2A_CAP.AttackRoute" )
AttackTasks[#AttackTasks+1] = AIGroup:TaskOrbitCircle( 4000, self.PatrolMinSpeed )
EngageRoute[1].task = AIGroup:TaskCombo( AttackTasks )
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
AIGroup:SetState( AIGroup, "AI_A2A_CAP", self )
end
AICap:Route( EngageRoute, 0.5 )
--- NOW ROUTE THE GROUP!
AIGroup:WayPointExecute( 1, 0 )
end
else
self:E("No targets found -> Going back to Patrolling")
@@ -445,22 +456,22 @@ function AI_A2A_CAP:onafterEngage( AICap, From, Event, To, AttackSetUnit )
end
--- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_CAP:onafterAccomplish( AICap, From, Event, To )
function AI_A2A_CAP:onafterAccomplish( Controllable, From, Event, To )
self.Accomplished = true
self:SetDetectionOff()
end
--- @param #AI_A2A_CAP self
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @param Core.Event#EVENTDATA EventData
function AI_A2A_CAP:onafterDestroy( AICap, From, Event, To, EventData )
function AI_A2A_CAP:onafterDestroy( Controllable, From, Event, To, EventData )
if EventData.IniUnit then
self.AttackUnits[EventData.IniUnit] = nil
@@ -478,15 +489,3 @@ function AI_A2A_CAP:OnEventDead( EventData )
end
end
end
--- @param Wrapper.Group#GROUP AICap
function AI_A2A_CAP.Resume( AICap )
AICap:F( { "AI_A2A_CAP.Resume:", AICap:GetName() } )
if AICap:IsAlive() then
local _AI_A2A = AICap:GetState( AICap, "AI_A2A" ) -- #AI_A2A
_AI_A2A:__Reset( 1 )
_AI_A2A:__Route( 5 )
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,28 @@
--- **AI** -- (R2.2) - Models the process of Ground Controlled Interception (GCI) for airplanes.
--- **AI** -- **Execute Ground Controlled Interception (GCI).**
--
-- This is a class used in the @{AI_A2A_Dispatcher}.
-- ![Banner Image](..\Presentations\AI_GCI\Dia1.JPG)
--
-- ===
--
-- ### Author: **FlightControl**
-- AI A2A_INTEREPT class makes AI Groups execute an Intercept.
--
-- ===
-- There are the following types of GCI classes defined:
--
-- * @{#AI_A2A_GCI}: Perform a GCI in a zone.
--
-- ====
--
-- ### Author: **Sven Van de Velde (FlightControl)**
--
-- ### Contributions:
--
-- ====
--
-- @module AI_A2A_GCI
--BASE:TraceClass("AI_A2A_GCI")
--- @type AI_A2A_GCI
-- @extends AI.AI_A2A#AI_A2A
@@ -105,12 +117,12 @@ AI_A2A_GCI = {
--- Creates a new AI_A2A_GCI object
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept
-- @param Wrapper.Group#GROUP AIGroup
-- @return #AI_A2A_GCI
function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
-- Inherits from BASE
local self = BASE:Inherit( self, AI_A2A:New( AIIntercept ) ) -- #AI_A2A_GCI
local self = BASE:Inherit( self, AI_A2A:New( AIGroup ) ) -- #AI_A2A_GCI
self.Accomplished = false
self.Engaging = false
@@ -122,12 +134,12 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
self.PatrolAltType = "RADIO"
self:AddTransition( { "Started", "Engaging", "Returning", "Airborne" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI.
self:AddTransition( { "Started", "Engaging", "Returning" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI.
--- OnBefore Transition Handler for Event Engage.
-- @function [parent=#AI_A2A_GCI] OnBeforeEngage
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -136,7 +148,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnAfter Transition Handler for Event Engage.
-- @function [parent=#AI_A2A_GCI] OnAfterEngage
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -153,7 +165,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnLeave Transition Handler for State Engaging.
-- @function [parent=#AI_A2A_GCI] OnLeaveEngaging
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -162,7 +174,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnEnter Transition Handler for State Engaging.
-- @function [parent=#AI_A2A_GCI] OnEnterEngaging
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -172,7 +184,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnBefore Transition Handler for Event Fired.
-- @function [parent=#AI_A2A_GCI] OnBeforeFired
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -181,7 +193,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnAfter Transition Handler for Event Fired.
-- @function [parent=#AI_A2A_GCI] OnAfterFired
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -200,7 +212,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnBefore Transition Handler for Event Destroy.
-- @function [parent=#AI_A2A_GCI] OnBeforeDestroy
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -209,7 +221,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnAfter Transition Handler for Event Destroy.
-- @function [parent=#AI_A2A_GCI] OnAfterDestroy
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -229,7 +241,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnBefore Transition Handler for Event Abort.
-- @function [parent=#AI_A2A_GCI] OnBeforeAbort
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -238,7 +250,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnAfter Transition Handler for Event Abort.
-- @function [parent=#AI_A2A_GCI] OnAfterAbort
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -257,7 +269,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnBefore Transition Handler for Event Accomplish.
-- @function [parent=#AI_A2A_GCI] OnBeforeAccomplish
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -266,7 +278,7 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
--- OnAfter Transition Handler for Event Accomplish.
-- @function [parent=#AI_A2A_GCI] OnAfterAccomplish
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -283,27 +295,14 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
return self
end
--- onafter State Transition for Event Patrol.
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onafterStart( AIIntercept, From, Event, To )
AIIntercept:HandleEvent( EVENTS.Takeoff, nil, self )
end
--- onafter State Transition for Event Patrol.
-- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The AI Group managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onafterEngage( AIIntercept, From, Event, To )
function AI_A2A_GCI:onafterEngage( AIGroup, From, Event, To )
self:HandleEvent( EVENTS.Dead )
@@ -312,24 +311,19 @@ end
-- todo: need to fix this global function
--- @param Wrapper.Group#GROUP AIControllable
function AI_A2A_GCI.InterceptRoute( AIIntercept, Fsm )
function AI_A2A_GCI.InterceptRoute( AIControllable )
AIIntercept:F( { "AI_A2A_GCI.InterceptRoute:", AIIntercept:GetName() } )
if AIIntercept:IsAlive() then
Fsm:__Engage( 0.5 )
--local Task = AIIntercept:TaskOrbitCircle( 4000, 400 )
--AIIntercept:SetTask( Task )
end
AIControllable:T( "NewEngageRoute" )
local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cap#AI_A2A_GCI
EngageZone:__Engage( 0.5 )
end
--- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onbeforeEngage( AIIntercept, From, Event, To )
function AI_A2A_GCI:onbeforeEngage( AIGroup, From, Event, To )
if self.Accomplished == true then
return false
@@ -337,41 +331,39 @@ function AI_A2A_GCI:onbeforeEngage( AIIntercept, From, Event, To )
end
--- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The AI Group managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AI Group managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onafterAbort( AIIntercept, From, Event, To )
AIIntercept:ClearTasks()
function AI_A2A_GCI:onafterAbort( AIGroup, From, Event, To )
AIGroup:ClearTasks()
self:Return()
self:__RTB( 0.5 )
end
--- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The GroupGroup managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onafterEngage( AIIntercept, From, Event, To, AttackSetUnit )
function AI_A2A_GCI:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
self:F( { AIIntercept, From, Event, To, AttackSetUnit} )
self:F( { AIGroup, From, Event, To, AttackSetUnit} )
self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT
local FirstAttackUnit = self.AttackSetUnit:GetFirst()
if FirstAttackUnit and FirstAttackUnit:IsAlive() then
if FirstAttackUnit then
if AIIntercept:IsAlive() then
if AIGroup:IsAlive() then
local EngageRoute = {}
local CurrentCoord = AIIntercept:GetCoordinate()
--- Calculate the target route point.
local CurrentCoord = AIIntercept:GetCoordinate()
local CurrentCoord = AIGroup:GetCoordinate()
local ToTargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
@@ -380,7 +372,7 @@ function AI_A2A_GCI:onafterEngage( AIIntercept, From, Event, To, AttackSetUnit )
local ToInterceptAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) )
--- Create a route point of type air.
local ToPatrolRoutePoint = CurrentCoord:Translate( 15000, ToInterceptAngle ):WaypointAir(
local ToPatrolRoutePoint = CurrentCoord:Translate( 5000, ToInterceptAngle ):RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -389,34 +381,42 @@ function AI_A2A_GCI:onafterEngage( AIIntercept, From, Event, To, AttackSetUnit )
)
self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } )
self:F( { self.EngageMinSpeed, self.EngageMaxSpeed, ToTargetSpeed } )
self:T2( { self.EngageMinSpeed, self.EngageMaxSpeed, ToTargetSpeed } )
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
AIGroup:OptionROEOpenFire()
AIGroup:OptionROTPassiveDefense()
local AttackTasks = {}
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
local AttackUnit = AttackUnit -- Wrapper.Unit#UNIT
self:T( { "Intercepting Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } )
if AttackUnit:IsAlive() and AttackUnit:IsAir() then
self:T( { "Intercepting Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } )
AttackTasks[#AttackTasks+1] = AIIntercept:TaskAttackUnit( AttackUnit )
AttackTasks[#AttackTasks+1] = AIGroup:TaskAttackUnit( AttackUnit )
end
end
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
AIGroup:WayPointInitialize( EngageRoute )
if #AttackTasks == 0 then
self:E("No targets found -> Going RTB")
self:Return()
self:__RTB( 0.5 )
else
AIIntercept:OptionROEOpenFire()
AIIntercept:OptionROTEvadeFire()
AttackTasks[#AttackTasks+1] = AIIntercept:TaskFunction( "AI_A2A_GCI.InterceptRoute", self )
EngageRoute[#EngageRoute].task = AIIntercept:TaskCombo( AttackTasks )
AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( 1, #AttackTasks, "AI_A2A_GCI.InterceptRoute" )
AttackTasks[#AttackTasks+1] = AIGroup:TaskOrbitCircle( 4000, self.EngageMinSpeed )
EngageRoute[1].task = AIGroup:TaskCombo( AttackTasks )
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
AIGroup:SetState( AIGroup, "EngageZone", self )
end
AIIntercept:Route( EngageRoute, 0.5 )
--- NOW ROUTE THE GROUP!
AIGroup:WayPointExecute( 1, 0 )
end
else
@@ -427,22 +427,22 @@ function AI_A2A_GCI:onafterEngage( AIIntercept, From, Event, To, AttackSetUnit )
end
--- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_GCI:onafterAccomplish( AIIntercept, From, Event, To )
function AI_A2A_GCI:onafterAccomplish( AIGroup, From, Event, To )
self.Accomplished = true
self:SetDetectionOff()
end
--- @param #AI_A2A_GCI self
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
-- @param Core.Event#EVENTDATA EventData
function AI_A2A_GCI:onafterDestroy( AIIntercept, From, Event, To, EventData )
function AI_A2A_GCI:onafterDestroy( AIGroup, From, Event, To, EventData )
if EventData.IniUnit then
self.AttackUnits[EventData.IniUnit] = nil

View File

@@ -1,12 +1,40 @@
--- **AI** -- (R2.2) - Models the process of air patrol of airplanes.
--- **AI** -- **Air Patrolling or Staging.**
--
-- This is a class used in the @{AI_A2A_Dispatcher}.
-- ![Banner Image](..\Presentations\AI_PATROL\Dia1.JPG)
--
-- ===
--
-- ### Author: **FlightControl**
-- AI PATROL classes makes AI Controllables execute an Patrol.
--
-- ===
-- There are the following types of PATROL classes defined:
--
-- * @{#AI_A2A_PATROL}: Perform a PATROL in a zone.
--
-- ====
--
-- # Demo Missions
--
-- ### [AI_PATROL Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
--
-- ### [AI_PATROL Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/PAT%20-%20Patrolling)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [AI_PATROL YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl35HvYZKA6G22WMt7iI3zky)
--
-- ====
--
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Testing and API concept review.
--
-- ====
--
-- @module AI_A2A_Patrol
@@ -16,7 +44,7 @@
--- # AI_A2A_PATROL class, extends @{Fsm#FSM_CONTROLLABLE}
--
-- The AI_A2A_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Group} or @{Group}.
-- The AI_A2A_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}.
--
-- ![Process](..\Presentations\AI_PATROL\Dia3.JPG)
--
@@ -92,7 +120,7 @@
-- * @{#AI_A2A_PATROL.SetDetectionOn}(): Set the detection on. The AI will detect for targets.
-- * @{#AI_A2A_PATROL.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased.
--
-- The detection frequency can be set with @{#AI_A2A_PATROL.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
-- The detection frequency can be set with @{#AI_A2A_PATROL.SetDetectionInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
-- Use the method @{#AI_A2A_PATROL.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI.
--
-- The detection can be filtered to potential targets in a specific zone.
@@ -111,7 +139,7 @@
--
-- ## 7. Manage "damage" behaviour of the AI in the AI_A2A_PATROL
--
-- When the AI is damaged, it is required that a new Patrol is started. However, damage cannon be foreseen early on.
-- 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 treshold 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.
--
@@ -124,23 +152,23 @@ AI_A2A_PATROL = {
--- Creates a new AI_A2A_PATROL object
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol
-- @param Wrapper.Group#GROUP AIGroup
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
-- @return #AI_A2A_PATROL self
-- @usage
-- -- Define a new AI_A2A_PATROL Object. This PatrolArea will patrol a Group within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
-- -- Define a new AI_A2A_PATROL Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
-- PatrolZone = ZONE:New( 'PatrolZone' )
-- PatrolSpawn = SPAWN:New( 'Patrol Group' )
-- PatrolArea = AI_A2A_PATROL:New( PatrolZone, 3000, 6000, 600, 900 )
function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
-- Inherits from BASE
local self = BASE:Inherit( self, AI_A2A:New( AIPatrol ) ) -- #AI_A2A_PATROL
local self = BASE:Inherit( self, AI_A2A:New( AIGroup ) ) -- #AI_A2A_PATROL
self.PatrolZone = PatrolZone
self.PatrolFloorAltitude = PatrolFloorAltitude
@@ -151,12 +179,12 @@ function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCei
-- defafult PatrolAltType to "RADIO" if not specified
self.PatrolAltType = PatrolAltType or "RADIO"
self:AddTransition( { "Started", "Airborne", "Refuelling" }, "Patrol", "Patrolling" )
self:AddTransition( "Started", "Patrol", "Patrolling" )
--- OnBefore Transition Handler for Event Patrol.
-- @function [parent=#AI_A2A_PATROL] OnBeforePatrol
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -165,7 +193,7 @@ function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCei
--- OnAfter Transition Handler for Event Patrol.
-- @function [parent=#AI_A2A_PATROL] OnAfterPatrol
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -182,7 +210,7 @@ function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCei
--- OnLeave Transition Handler for State Patrolling.
-- @function [parent=#AI_A2A_PATROL] OnLeavePatrolling
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -191,7 +219,7 @@ function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCei
--- OnEnter Transition Handler for State Patrolling.
-- @function [parent=#AI_A2A_PATROL] OnEnterPatrolling
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -201,7 +229,7 @@ function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCei
--- OnBefore Transition Handler for Event Route.
-- @function [parent=#AI_A2A_PATROL] OnBeforeRoute
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -210,7 +238,7 @@ function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCei
--- OnAfter Transition Handler for Event Route.
-- @function [parent=#AI_A2A_PATROL] OnAfterRoute
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
@@ -224,8 +252,6 @@ function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCei
-- @param #AI_A2A_PATROL self
-- @param #number Delay The delay in seconds.
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_PATROL.
return self
@@ -236,8 +262,8 @@ end
--- Sets (modifies) the minimum and maximum speed of the patrol.
-- @param #AI_A2A_PATROL self
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @return #AI_A2A_PATROL self
function AI_A2A_PATROL:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
@@ -264,19 +290,20 @@ end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
-- @param #AI_A2A_PATROL self
-- @return #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_PATROL:onafterPatrol( AIPatrol, From, Event, To )
function AI_A2A_PATROL:onafterPatrol( Controllable, From, Event, To )
self:F2()
self:ClearTargetDistance()
self:__Route( 1 )
AIPatrol:OnReSpawn(
self.Controllable:OnReSpawn(
function( PatrolGroup )
self:E( "ReSpawn" )
self:__Reset( 1 )
self:__Route( 5 )
end
@@ -285,27 +312,23 @@ end
--- @param Wrapper.Group#GROUP AIPatrol
-- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
function AI_A2A_PATROL.PatrolRoute( AIPatrol, Fsm )
--- @param Wrapper.Group#GROUP AIGroup
-- This statis method is called from the route path within the last task at the last waaypoint of the Controllable.
-- Note that this method is required, as triggers the next route when patrolling for the Controllable.
function AI_A2A_PATROL.PatrolRoute( AIGroup )
AIPatrol:F( { "AI_A2A_PATROL.PatrolRoute:", AIPatrol:GetName() } )
if AIPatrol:IsAlive() then
Fsm:Route()
end
local _AI_A2A_Patrol = AIGroup:GetState( AIGroup, "AI_A2A_PATROL" ) -- #AI_A2A_PATROL
_AI_A2A_Patrol:Route()
end
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
-- @param #AI_A2A_PATROL self
-- @param Wrapper.Group#GROUP AIPatrol The Group managed by the FSM.
-- @param Wrapper.Group#GROUP AIGroup The AIGroup managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To )
function AI_A2A_PATROL:onafterRoute( AIGroup, From, Event, To )
self:F2()
@@ -315,22 +338,22 @@ function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To )
end
if AIPatrol:IsAlive() then
if AIGroup:IsAlive() then
local PatrolRoute = {}
--- Calculate the target route point.
local CurrentCoord = AIPatrol:GetCoordinate()
local CurrentCoord = AIGroup:GetCoordinate()
local ToTargetCoord = self.PatrolZone:GetRandomPointVec2()
ToTargetCoord:SetAlt( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) )
ToTargetCoord:SetAlt(math.random( self.PatrolFloorAltitude,self.PatrolCeilingAltitude ) )
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
--- Create a route point of type air.
local ToPatrolRoutePoint = ToTargetCoord:WaypointAir(
local ToPatrolRoutePoint = ToTargetCoord:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -338,29 +361,22 @@ function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To )
true
)
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
AIGroup:WayPointInitialize( PatrolRoute )
local Tasks = {}
Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_A2A_PATROL.PatrolRoute", self )
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A_PATROL.PatrolRoute" )
AIPatrol:OptionROEReturnFire()
AIPatrol:OptionROTEvadeFire()
PatrolRoute[1].task = AIGroup:TaskCombo( Tasks )
--- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the AIControllable in a temporary variable ...
AIGroup:SetState( AIGroup, "AI_A2A_PATROL", self )
AIPatrol:Route( PatrolRoute, 0.5 )
--- NOW ROUTE THE GROUP!
AIGroup:WayPointExecute( 1, 2 )
end
end
--- @param Wrapper.Group#GROUP AIPatrol
function AI_A2A_PATROL.Resume( AIPatrol )
AIPatrol:F( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } )
if AIPatrol:IsAlive() then
local _AI_A2A = AIPatrol:GetState( AIPatrol, "AI_A2A" ) -- #AI_A2A
_AI_A2A:__Reset( 1 )
_AI_A2A:__Route( 5 )
end
end

View File

@@ -1,25 +1,40 @@
--- **AI** -- (R2.1) - Manages the independent process of Battlefield Air Interdiction (bombing) for airplanes.
--
-- ===
--- **AI** -- **Provide Battlefield Air Interdiction (bombing).**
--
-- ![Banner Image](..\Presentations\AI_BAI\Dia1.JPG)
--
-- ===
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BAI%20-%20Battlefield%20Air%20Interdiction)
-- AI_BAI classes makes AI Controllables execute bombing tasks.
--
-- ===
-- There are the following types of BAI classes defined:
--
-- ### [YouTube Playlist]()
-- * @{#AI_BAI_ZONE}: Perform a BAI in a zone.
--
-- ====
--
-- ===
-- # Demo Missions
--
-- ### [AI_BAI Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/BOMB%20-%20Close%20Air%20Support)
--
-- ### [AI_BAI Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/BOMB%20-%20Close%20Air%20Support)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [AI_BAI YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2)
--
-- ====
--
-- ### Author: **Sven Van de Velde (FlightControl)**
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
--
-- ===
-- ====
--
-- @module AI_Bai
@@ -516,7 +531,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToEngageZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -573,7 +588,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
--- Create a route point of type air.
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -597,7 +612,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
--- NOW ROUTE THE GROUP!
Controllable:WayPointExecute( 1 )
self:SetRefreshTimeInterval( 2 )
self:SetDetectionInterval( 2 )
self:SetDetectionActivated()
self:__Target( -2 ) -- Start Targetting
end

View File

@@ -1,31 +1,39 @@
--- **AI** -- (2.1) - Balance player slots with AI to create an engaging simulation environment, independent of the amount of players.
--
-- ===
--- **AI** -- **AI Balancing will replace in multi player missions
-- non-occupied human slots with AI groups, in order to provide an engaging simulation environment,
-- even when there are hardly any players in the mission.**
--
-- ![Banner Image](..\Presentations\AI_Balancer\Dia1.JPG)
--
-- ====
--
-- ===
-- # Demo Missions
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/AIB%20-%20AI%20Balancing)
-- ### [AI_BALANCER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/AIB%20-%20AI%20Balancing)
--
-- ===
-- ### [AI_BALANCER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AIB%20-%20AI%20Balancing)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl2CJVIrL1TdAumuVS8n64B7)
-- ====
--
-- ===
-- # YouTube Channel
--
-- ### Author: **FlightControl**
-- ### [AI_BALANCER YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl2CJVIrL1TdAumuVS8n64B7)
--
-- ====
--
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
--
-- ===
-- ====
--
-- @module AI_Balancer
--- @type AI_BALANCER
-- @field Core.Set#SET_CLIENT SetClient
-- @field Core.Spawn#SPAWN SpawnAI
-- @field Functional.Spawn#SPAWN SpawnAI
-- @field Wrapper.Group#GROUP Test
-- @extends Core.Fsm#FSM_SET
@@ -98,7 +106,7 @@ AI_BALANCER = {
--- Creates a new AI_BALANCER object
-- @param #AI_BALANCER self
-- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player).
-- @param Core.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed.
-- @param Functional.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed.
-- @return #AI_BALANCER
function AI_BALANCER:New( SetClient, SpawnAI )
@@ -143,22 +151,22 @@ end
--- Returns the AI to the nearest friendly @{Airbase#AIRBASE}.
-- @param #AI_BALANCER self
-- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
-- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
-- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to.
function AI_BALANCER:ReturnToNearestAirbases( ReturnThresholdRange, ReturnAirbaseSet )
function AI_BALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet )
self.ToNearestAirbase = true
self.ReturnThresholdRange = ReturnThresholdRange
self.ReturnTresholdRange = ReturnTresholdRange
self.ReturnAirbaseSet = ReturnAirbaseSet
end
--- Returns the AI to the home @{Airbase#AIRBASE}.
-- @param #AI_BALANCER self
-- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
function AI_BALANCER:ReturnToHomeAirbase( ReturnThresholdRange )
-- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
function AI_BALANCER:ReturnToHomeAirbase( ReturnTresholdRange )
self.ToHomeAirbase = true
self.ReturnThresholdRange = ReturnThresholdRange
self.ReturnTresholdRange = ReturnTresholdRange
end
--- @param #AI_BALANCER self
@@ -170,10 +178,9 @@ function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName )
-- OK, Spawn a new group from the default SpawnAI object provided.
local AIGroup = self.SpawnAI:Spawn() -- Wrapper.Group#GROUP
if AIGroup then
AIGroup:T( { "Spawning new AIGroup", ClientName = ClientName } )
AIGroup:E( "Spawning new AIGroup" )
--TODO: need to rework UnitName thing ...
SetGroup:Remove( ClientName ) -- Ensure that the previously allocated AIGroup to ClientName is removed in the Set.
SetGroup:Add( ClientName, AIGroup )
self.SpawnQueue[ClientName] = nil
@@ -189,9 +196,9 @@ end
function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup )
AIGroup:Destroy()
SetGroup:Flush( self )
SetGroup:Flush()
SetGroup:Remove( ClientName )
SetGroup:Flush( self )
SetGroup:Flush()
end
--- @param #AI_BALANCER self
@@ -232,24 +239,23 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
self:T3(Client.ClientName)
local AIGroup = self.Set:Get( Client.UnitName ) -- Wrapper.Group#GROUP
if AIGroup then self:T( { AIGroup = AIGroup:GetName(), IsAlive = AIGroup:IsAlive() } ) end
if Client:IsAlive() == true then
if Client:IsAlive() then
if AIGroup and AIGroup:IsAlive() == true then
if self.ToNearestAirbase == false and self.ToHomeAirbase == false then
self:Destroy( Client.UnitName, AIGroup )
else
-- We test if there is no other CLIENT within the self.ReturnThresholdRange of the first unit of the AI group.
-- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group.
-- If there is a CLIENT, the AI stays engaged and will not return.
-- If there is no CLIENT within the self.ReturnThresholdRange, then the unit will return to the Airbase return method selected.
-- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected.
local PlayerInRange = { Value = false }
local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnThresholdRange )
local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange )
self:T2( RangeZone )
_DATABASE:ForEachPlayerUnit(
_DATABASE:ForEachPlayer(
--- @param Wrapper.Unit#UNIT RangeTestUnit
function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange )
self:T2( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } )
@@ -278,12 +284,11 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
else
if not AIGroup or not AIGroup:IsAlive() == true then
self:T( "Client " .. Client.UnitName .. " not alive." )
self:T( { Queue = self.SpawnQueue[Client.UnitName] } )
if not self.SpawnQueue[Client.UnitName] then
-- Spawn a new AI taking into account the spawn interval Earliest, Latest
self:__Spawn( math.random( self.Earliest, self.Latest ), Client.UnitName )
self.SpawnQueue[Client.UnitName] = true
self:T( "New AI Spawned for Client " .. Client.UnitName )
self:E( "New AI Spawned for Client " .. Client.UnitName )
end
end
end

View File

@@ -1,20 +1,35 @@
--- **AI** -- (R2.1) - Manages the independent process of Combat Air Patrol (CAP) for airplanes.
--
-- ===
--- **AI** -- **Execute Combat Air Patrol (CAP).**
--
-- ![Banner Image](..\Presentations\AI_CAP\Dia1.JPG)
--
-- ===
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol)
-- AI CAP classes makes AI Controllables execute a Combat Air Patrol.
--
-- ===
-- There are the following types of CAP classes defined:
--
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1YCyPxJgoZn-CfhwyeW65L)
-- * @{#AI_CAP_ZONE}: Perform a CAP in a zone.
--
-- ====
--
-- ===
-- # Demo Missions
--
-- ### [AI_CAP Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol)
--
-- ### [AI_CAP Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAP%20-%20Combat%20Air%20Patrol)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [AI_CAP YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1YCyPxJgoZn-CfhwyeW65L)
--
-- ====
--
-- ### Author: **Sven Van de Velde (FlightControl)**
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
@@ -23,7 +38,7 @@
-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing.
-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing.
--
-- ===
-- ====
--
-- @module AI_Cap
@@ -343,20 +358,16 @@ function AI_CAP_ZONE:onafterStart( Controllable, From, Event, To )
end
-- todo: need to fix this global function
--- @param AI.AI_CAP#AI_CAP_ZONE
-- @param Wrapper.Group#GROUP EngageGroup
function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
function _NewEngageCapRoute( AIControllable )
EngageGroup:F( { "AI_CAP_ZONE.EngageRoute:", EngageGroup:GetName() } )
if EngageGroup:IsAlive() then
Fsm:__Engage( 1 )
end
AIControllable:T( "NewEngageRoute" )
local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cap#AI_CAP_ZONE
EngageZone:__Engage( 1 )
end
--- @param #AI_CAP_ZONE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
-- @param #string From The From State string.
@@ -429,7 +440,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToEngageZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -453,7 +464,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
--- Create a route point of type air.
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
local ToPatrolRoutePoint = ToTargetPointVec3:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -464,7 +475,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
Controllable:OptionROEOpenFire()
Controllable:OptionROTEvadeFire()
Controllable:OptionROTPassiveDefense()
local AttackTasks = {}
@@ -492,20 +503,28 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
end
end
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
self.Controllable:WayPointInitialize( EngageRoute )
if #AttackTasks == 0 then
self:F("No targets found -> Going back to Patrolling")
self:__Abort( 1 )
self:__Route( 1 )
self:SetDetectionActivated()
else
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAP_ZONE.EngageRoute", self )
EngageRoute[1].task = Controllable:TaskCombo( AttackTasks )
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
self.Controllable:SetState( self.Controllable, "EngageZone", self )
self.Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageCapRoute" )
self:SetDetectionDeactivated()
end
Controllable:Route( EngageRoute, 0.5 )
--- NOW ROUTE THE GROUP!
self.Controllable:WayPointExecute( 1, 2 )
end
end

View File

@@ -1,27 +1,43 @@
--- **AI** -- (R2.1) - Manages the independent process of Close Air Support for airplanes.
--
-- ===
--- **AI** -- **Provide Close Air Support to friendly ground troops.**
--
-- ![Banner Image](..\Presentations\AI_CAS\Dia1.JPG)
--
-- ===
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support)
-- AI CAS classes makes AI Controllables execute a Close Air Support.
--
-- ===
-- There are the following types of CAS classes defined:
--
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2)
-- * @{#AI_CAS_ZONE}: Perform a CAS in a zone.
--
-- ====
--
-- ===
-- # Demo Missions
--
-- ### [AI_CAS Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support)
--
-- ### [AI_CAS Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAS%20-%20Close%20Air%20Support)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [AI_CAS YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl3JBO1WDqqpyYRRmIkR2ir2)
--
-- ====
--
--
-- ### Author: **Sven Van de Velde (FlightControl)**
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- * **[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.
--
-- ===
-- ====
--
-- @module AI_Cas
@@ -357,15 +373,12 @@ function AI_CAS_ZONE:onafterStart( Controllable, From, Event, To )
self:SetDetectionDeactivated() -- When not engaging, set the detection off.
end
--- @param AI.AI_CAS#AI_CAS_ZONE
-- @param Wrapper.Group#GROUP EngageGroup
function AI_CAS_ZONE.EngageRoute( EngageGroup, Fsm )
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
function _NewEngageRoute( AIControllable )
EngageGroup:F( { "AI_CAS_ZONE.EngageRoute:", EngageGroup:GetName() } )
if EngageGroup:IsAlive() then
Fsm:__Engage( 1, Fsm.EngageSpeed, Fsm.EngageAltitude, Fsm.EngageWeaponExpend, Fsm.EngageAttackQty, Fsm.EngageDirection )
end
AIControllable:T( "NewEngageRoute" )
local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cas#AI_CAS_ZONE
EngageZone:__Engage( 1, EngageZone.EngageSpeed, EngageZone.EngageAltitude, EngageZone.EngageWeaponExpend, EngageZone.EngageAttackQty, EngageZone.EngageDirection )
end
@@ -387,6 +400,7 @@ end
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_CAS_ZONE:onafterTarget( Controllable, From, Event, To )
self:E("onafterTarget")
if Controllable:IsAlive() then
@@ -397,7 +411,7 @@ function AI_CAS_ZONE:onafterTarget( Controllable, From, Event, To )
if DetectedUnit:IsAlive() then
if DetectedUnit:IsInZone( self.EngageZone ) then
if Detected == true then
self:F( {"Target: ", DetectedUnit } )
self:E( {"Target: ", DetectedUnit } )
self.DetectedUnits[DetectedUnit] = false
local AttackTask = Controllable:TaskAttackUnit( DetectedUnit, false, self.EngageWeaponExpend, self.EngageAttackQty, self.EngageDirection, self.EngageAltitude, nil )
self.Controllable:PushTask( AttackTask, 1 )
@@ -450,9 +464,6 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
if Controllable:IsAlive() then
Controllable:OptionROEOpenFire()
Controllable:OptionROTVertical()
local EngageRoute = {}
--- Calculate the current route point.
@@ -462,7 +473,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToEngageZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -474,12 +485,12 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
local AttackTasks = {}
for DetectedUnit, Detected in pairs( self.DetectedUnits ) do
for DetectedUnitID, DetectedUnit in pairs( self.DetectedUnits ) do
local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT
self:T( DetectedUnit )
if DetectedUnit:IsAlive() then
if DetectedUnit:IsInZone( self.EngageZone ) then
self:F( {"Engaging ", DetectedUnit } )
self:E( {"Engaging ", DetectedUnit } )
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit,
true,
EngageWeaponExpend,
@@ -492,8 +503,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
end
end
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAS_ZONE.EngageRoute", self )
EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks )
EngageRoute[1].task = Controllable:TaskCombo( AttackTasks )
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
@@ -505,7 +515,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
--- Create a route point of type air.
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -514,10 +524,22 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
)
EngageRoute[#EngageRoute+1] = ToTargetRoutePoint
Controllable:Route( EngageRoute, 0.5 )
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
Controllable:WayPointInitialize( EngageRoute )
self:SetRefreshTimeInterval( 2 )
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
Controllable:SetState( Controllable, "EngageZone", self )
Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageRoute" )
--- NOW ROUTE THE GROUP!
Controllable:WayPointExecute( 1 )
Controllable:OptionROEOpenFire()
Controllable:OptionROTVertical()
self:SetDetectionInterval( 2 )
self:SetDetectionActivated()
self:__Target( -2 ) -- Start Targetting
end

View File

@@ -1,6 +1,4 @@
--- **AI** -- (R2.2) - Build large airborne formations of aircraft.
--
-- ===
--- **AI** -- Build large **formations** of AI @{Group}s flying together.
--
-- ![Banner Image](..\Presentations\AI_FORMATION\Dia1.JPG)
--
@@ -30,20 +28,29 @@
--
-- * @{#AI_FORMATION}: Create a formation from several @{GROUP}s.
--
-- ===
-- ====
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/FOR%20-%20Formation)
-- # Demo Missions
--
-- ### [AI_FORMATION Demo Missions source code]()
--
-- ### [AI_FORMATION Demo Missions, only for beta testers]()
--
-- ### [ALL Demo Missions pack of the last release]()
--
-- ====
--
-- # YouTube Channel
--
--- ### [AI_FORMATION YouTube Channel]()
--
-- ===
--
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0bFIJ9jIdYM22uaWmIN4oz)
-- ### Author: **Sven Van de Velde (FlightControl)**
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
-- ====
--
-- @module AI_Formation
@@ -59,6 +66,7 @@
-- @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 Menu#MENU_CLIENT FollowMenuResumeMission
--- # AI_FORMATION class, extends @{Fsm#FSM_SET}
@@ -671,7 +679,7 @@ end
function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) --R2.1
self:F( { FollowGroupSet, From , Event ,To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace } )
FollowGroupSet:Flush( self )
FollowGroupSet:Flush()
local FollowSet = FollowGroupSet:GetSet()
@@ -950,7 +958,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
-- @param Wrapper.Unit#UNIT ClientUnit
function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 )
FollowGroup:OptionROTEvadeFire()
FollowGroup:OptionROTPassiveDefense()
FollowGroup:OptionROEReturnFire()
local GroupUnit = FollowGroup:GetUnit( 1 )

View File

@@ -1,6 +1,4 @@
--- **AI** -- (R2.1) - Manages the independent process of Air Patrol for airplanes.
--
-- ===
--- **AI** -- **Air Patrolling or Staging.**
--
-- ![Banner Image](..\Presentations\AI_PATROL\Dia1.JPG)
--
@@ -12,23 +10,31 @@
--
-- * @{#AI_PATROL_ZONE}: Perform a PATROL in a zone.
--
-- ===
-- ====
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
-- # Demo Missions
--
-- ===
-- ### [AI_PATROL Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
--
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl35HvYZKA6G22WMt7iI3zky)
-- ### [AI_PATROL Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/PAT%20-%20Patrolling)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ===
-- ====
--
-- ### Author: **FlightControl**
-- # YouTube Channel
--
-- ### [AI_PATROL YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl35HvYZKA6G22WMt7iI3zky)
--
-- ====
--
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- * **[Dutch_Baron](https://forums.eagle.ru/member.php?u=112075)**: Working together with James has resulted in the creation of the AI_BALANCER class. James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-)
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Testing and API concept review.
--
-- ===
-- ====
--
-- @module AI_Patrol
@@ -41,7 +47,7 @@
-- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @field Core.Spawn#SPAWN CoordTest
-- @field Functional.Spawn#SPAWN CoordTest
-- @extends Core.Fsm#FSM_CONTROLLABLE
--- # AI_PATROL_ZONE class, extends @{Fsm#FSM_CONTROLLABLE}
@@ -122,7 +128,7 @@
-- * @{#AI_PATROL_ZONE.SetDetectionOn}(): Set the detection on. The AI will detect for targets.
-- * @{#AI_PATROL_ZONE.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased.
--
-- The detection frequency can be set with @{#AI_PATROL_ZONE.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
-- The detection frequency can be set with @{#AI_PATROL_ZONE.SetDetectionInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
-- Use the method @{#AI_PATROL_ZONE.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI.
--
-- The detection can be filtered to potential targets in a specific zone.
@@ -181,7 +187,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
-- defafult PatrolAltType to "RADIO" if not specified
self.PatrolAltType = PatrolAltType or "RADIO"
self:SetRefreshTimeInterval( 30 )
self:SetDetectionInterval( 30 )
self.CheckStatus = true
@@ -538,7 +544,7 @@ end
-- @param #AI_PATROL_ZONE self
-- @param #number Seconds The interval in seconds.
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:SetRefreshTimeInterval( Seconds )
function AI_PATROL_ZONE:SetDetectionInterval( Seconds )
self:F2()
if Seconds then
@@ -585,13 +591,13 @@ end
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROL_ZONE.
-- Once the time is finished, the old AI will return to the base.
-- @param #AI_PATROL_ZONE self
-- @param #number PatrolFuelThresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
-- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
function AI_PATROL_ZONE:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime )
self.PatrolManageFuel = true
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
self.PatrolFuelTresholdPercentage = PatrolFuelTresholdPercentage
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
return self
@@ -604,12 +610,12 @@ end
-- Note that for groups, the average damage of the complete group will be calculated.
-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25.
-- @param #AI_PATROL_ZONE self
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
-- @param #number PatrolDamageTreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
-- @return #AI_PATROL_ZONE self
function AI_PATROL_ZONE:ManageDamage( PatrolDamageThreshold )
function AI_PATROL_ZONE:ManageDamage( PatrolDamageTreshold )
self.PatrolManageDamage = true
self.PatrolDamageThreshold = PatrolDamageThreshold
self.PatrolDamageTreshold = PatrolDamageTreshold
return self
end
@@ -742,7 +748,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TakeOffParking,
POINT_VEC3.RoutePointAction.FromParkingArea,
@@ -757,7 +763,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -783,7 +789,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
--- Create a route point of type air.
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
@@ -825,9 +831,10 @@ function AI_PATROL_ZONE:onafterStatus()
local RTB = false
local Fuel = self.Controllable:GetUnit(1):GetFuel()
if Fuel < self.PatrolFuelThresholdPercentage then
if Fuel < self.PatrolFuelTresholdPercentage then
self:E( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
local OldAIControllable = self.Controllable
local AIControllableTemplate = self.Controllable:GetTemplate()
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
@@ -839,7 +846,7 @@ function AI_PATROL_ZONE:onafterStatus()
-- TODO: Check GROUP damage function.
local Damage = self.Controllable:GetLife()
if Damage <= self.PatrolDamageThreshold then
if Damage <= self.PatrolDamageTreshold then
self:E( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" )
RTB = true
end
@@ -870,7 +877,7 @@ function AI_PATROL_ZONE:onafterRTB()
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,

View File

@@ -91,7 +91,7 @@ do -- ACT_ACCOUNT
--- StateMachine callback function
-- @param #ACT_ACCOUNT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -107,7 +107,7 @@ do -- ACT_ACCOUNT
--- StateMachine callback function
-- @param #ACT_ACCOUNT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -125,7 +125,7 @@ do -- ACT_ACCOUNT
--- StateMachine callback function
-- @param #ACT_ACCOUNT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -155,6 +155,7 @@ do -- ACT_ACCOUNT_DEADS
-- @extends #ACT_ACCOUNT
ACT_ACCOUNT_DEADS = {
ClassName = "ACT_ACCOUNT_DEADS",
TargetSetUnit = nil,
}
@@ -162,10 +163,13 @@ do -- ACT_ACCOUNT_DEADS
-- @param #ACT_ACCOUNT_DEADS self
-- @param Set#SET_UNIT TargetSetUnit
-- @param #string TaskName
function ACT_ACCOUNT_DEADS:New()
function ACT_ACCOUNT_DEADS:New( TargetSetUnit, TaskName )
-- Inherits from BASE
local self = BASE:Inherit( self, ACT_ACCOUNT:New() ) -- #ACT_ACCOUNT_DEADS
self.TargetSetUnit = TargetSetUnit
self.TaskName = TaskName
self.DisplayInterval = 30
self.DisplayCount = 30
self.DisplayMessage = true
@@ -177,38 +181,38 @@ do -- ACT_ACCOUNT_DEADS
function ACT_ACCOUNT_DEADS:Init( FsmAccount )
self.Task = self:GetTask()
self.TaskName = self.Task:GetName()
self.TargetSetUnit = FsmAccount.TargetSetUnit
self.TaskName = FsmAccount.TaskName
end
--- Process Events
--- StateMachine callback function
-- @param #ACT_ACCOUNT_DEADS self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ACCOUNT_DEADS:onenterReport( ProcessUnit, Task, From, Event, To )
self:E( { ProcessUnit, From, Event, To } )
local MessageText = "Your group with assigned " .. self.TaskName .. " task has " .. Task.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed."
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
self:Message( "Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed." )
end
--- StateMachine callback function
-- @param #ACT_ACCOUNT_DEADS self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Client#CLIENT ProcessClient
-- @param Tasking.Task#TASK Task
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onafterEvent( ProcessUnit, Task, From, Event, To, EventData )
self:T( { ProcessUnit:GetName(), Task:GetName(), From, Event, To, EventData } )
function ACT_ACCOUNT_DEADS:onafterEvent( ProcessClient, Task, From, Event, To, EventData )
self:T( { ProcessClient:GetName(), Task:GetName(), From, Event, To, EventData } )
if Task.TargetSetUnit:FindUnit( EventData.IniUnitName ) then
local PlayerName = ProcessUnit:GetPlayerName()
if self.TargetSetUnit:FindUnit( EventData.IniUnitName ) then
local PlayerName = ProcessClient:GetPlayerName()
local PlayerHit = self.PlayerHits and self.PlayerHits[EventData.IniUnitName]
if PlayerHit == PlayerName then
self:Player( EventData )
@@ -220,26 +224,24 @@ do -- ACT_ACCOUNT_DEADS
--- StateMachine callback function
-- @param #ACT_ACCOUNT_DEADS self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Client#CLIENT ProcessClient
-- @param Tasking.Task#TASK Task
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onenterAccountForPlayer( ProcessUnit, Task, From, Event, To, EventData )
self:T( { ProcessUnit:GetName(), Task:GetName(), From, Event, To, EventData } )
function ACT_ACCOUNT_DEADS:onenterAccountForPlayer( ProcessClient, Task, From, Event, To, EventData )
self:T( { ProcessClient:GetName(), Task:GetName(), From, Event, To, EventData } )
local TaskGroup = ProcessUnit:GetGroup()
local TaskGroup = ProcessClient:GetGroup()
Task.TargetSetUnit:Remove( EventData.IniUnitName )
local MessageText = "You have destroyed a target.\nYour group assigned with task " .. self.TaskName .. " has\n" .. Task.TargetSetUnit:Count() .. " targets ( " .. Task.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed."
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
local PlayerName = ProcessUnit:GetPlayerName()
self.TargetSetUnit:Remove( EventData.IniUnitName )
self:Message( "You have destroyed a target. Your group assigned with task " .. self.TaskName .. " has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed." )
local PlayerName = ProcessClient:GetPlayerName()
Task:AddProgress( PlayerName, "Destroyed " .. EventData.IniTypeName, timer.getTime(), 1 )
if Task.TargetSetUnit:Count() > 0 then
if self.TargetSetUnit:Count() > 0 then
self:__More( 1 )
else
self:__NoMore( 1 )
@@ -248,22 +250,20 @@ do -- ACT_ACCOUNT_DEADS
--- StateMachine callback function
-- @param #ACT_ACCOUNT_DEADS self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Client#CLIENT ProcessClient
-- @param Tasking.Task#TASK Task
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Event#EVENTDATA EventData
function ACT_ACCOUNT_DEADS:onenterAccountForOther( ProcessUnit, Task, From, Event, To, EventData )
self:T( { ProcessUnit:GetName(), Task:GetName(), From, Event, To, EventData } )
function ACT_ACCOUNT_DEADS:onenterAccountForOther( ProcessClient, Task, From, Event, To, EventData )
self:T( { ProcessClient:GetName(), Task:GetName(), From, Event, To, EventData } )
local TaskGroup = ProcessUnit:GetGroup()
Task.TargetSetUnit:Remove( EventData.IniUnitName )
local MessageText = "One of the task targets has been destroyed.\nYour group assigned with task " .. self.TaskName .. " has\n" .. Task.TargetSetUnit:Count() .. " targets ( " .. Task.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed."
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
local TaskGroup = ProcessClient:GetGroup()
self.TargetSetUnit:Remove( EventData.IniUnitName )
self:Message( "One of the task targets has been destroyed. Your group assigned with task " .. self.TaskName .. " has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed." )
if Task.TargetSetUnit:Count() > 0 then
if self.TargetSetUnit:Count() > 0 then
self:__More( 1 )
else
self:__NoMore( 1 )

View File

@@ -156,7 +156,7 @@ do -- ACT_ASSIGN_ACCEPT
-- @param #string From
-- @param #string To
function ACT_ASSIGN_ACCEPT:onafterStart( ProcessUnit, From, Event, To )
self:F( { ProcessUnit, From, Event, To } )
self:E( { ProcessUnit, From, Event, To } )
self:__Assign( 1 )
end
@@ -168,7 +168,8 @@ do -- ACT_ASSIGN_ACCEPT
-- @param #string From
-- @param #string To
function ACT_ASSIGN_ACCEPT:onenterAssigned( ProcessUnit, From, Event, To )
self:F( { ProcessUnit, From, Event, To } )
env.info( "in here" )
self:E( { ProcessUnit, From, Event, To } )
local ProcessGroup = ProcessUnit:GetGroup()
@@ -228,14 +229,14 @@ do -- ACT_ASSIGN_MENU_ACCEPT
--- StateMachine callback function
-- @param #ACT_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, From, Event, To )
self:F( { ProcessUnit, From, Event, To } )
self:E( { ProcessUnit, From, Event, To } )
self:GetCommandCenter():MessageTypeToGroup( "Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled.", ProcessUnit:GetGroup(), MESSAGE.Type.Information )
self:Message( "Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled." )
local ProcessGroup = ProcessUnit:GetGroup()
@@ -247,6 +248,7 @@ do -- ACT_ASSIGN_MENU_ACCEPT
--- Menu function.
-- @param #ACT_ASSIGN_MENU_ACCEPT self
function ACT_ASSIGN_MENU_ACCEPT:MenuAssign()
self:E( )
self:__Assign( 1 )
end
@@ -254,30 +256,31 @@ do -- ACT_ASSIGN_MENU_ACCEPT
--- Menu function.
-- @param #ACT_ASSIGN_MENU_ACCEPT self
function ACT_ASSIGN_MENU_ACCEPT:MenuReject()
self:E( )
self:__Reject( 1 )
end
--- StateMachine callback function
-- @param #ACT_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ASSIGN_MENU_ACCEPT:onafterAssign( ProcessUnit, From, Event, To )
self:F( { ProcessUnit.UnitNameFrom, Event, To } )
self:E( { ProcessUnit.UnitNameFrom, Event, To } )
self.Menu:Remove()
end
--- StateMachine callback function
-- @param #ACT_ASSIGN_MENU_ACCEPT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ASSIGN_MENU_ACCEPT:onafterReject( ProcessUnit, From, Event, To )
self:F( { ProcessUnit.UnitName, From, Event, To } )
self:E( { ProcessUnit.UnitName, From, Event, To } )
self.Menu:Remove()
--TODO: need to resolve this problem ... it has to do with the events ...

View File

@@ -111,6 +111,7 @@ do -- ACT_ASSIST
local MissionMenu = self:GetMission():GetMenu( ProcessGroup )
local function MenuSmoke( MenuParam )
self:E( MenuParam )
local self = MenuParam.self
local SmokeColor = MenuParam.SmokeColor
self.SmokeColor = SmokeColor

View File

@@ -83,7 +83,7 @@ end
function PROCESS_JTAC:OnJTACMenuUpdate( Fsm, From, Event, To )
local function JTACMenuSpot( MenuParam )
self:F( MenuParam.TargetUnit.UnitName )
self:E( MenuParam.TargetUnit.UnitName )
local self = MenuParam.self
local TargetUnit = MenuParam.TargetUnit
@@ -91,7 +91,7 @@ function PROCESS_JTAC:OnJTACMenuUpdate( Fsm, From, Event, To )
end
local function JTACMenuCancel( MenuParam )
self:F( MenuParam )
self:E( MenuParam )
local self = MenuParam.self
local TargetUnit = MenuParam.TargetUnit
@@ -102,7 +102,7 @@ function PROCESS_JTAC:OnJTACMenuUpdate( Fsm, From, Event, To )
-- Loop each unit in the target set, and determine the threat levels map table.
local UnitThreatLevels = self.TargetSetUnit:GetUnitThreatLevels()
self:F( {"UnitThreadLevels", UnitThreatLevels } )
self:E( {"UnitThreadLevels", UnitThreatLevels } )
local JTACMenu = self.ProcessGroup:GetState( self.ProcessGroup, "JTACMenu" )

View File

@@ -97,7 +97,7 @@ end
function PROCESS_PICKUP:OnHitTarget( Fsm, From, Event, To, Event )
self.TargetSetUnit:Flush( self )
self.TargetSetUnit:Flush()
if self.TargetSetUnit:FindUnit( Event.IniUnitName ) then
self.TargetSetUnit:RemoveUnitsByName( Event.IniUnitName )

View File

@@ -154,10 +154,12 @@ do -- ACT_ROUTE
--- Get the routing text to be displayed.
-- The route mode determines the text displayed.
-- @param #ACT_ROUTE self
-- @param Wrapper.Unit#UNIT Controllable
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @return #string
function ACT_ROUTE:GetRouteText( Controllable )
self:E()
local RouteText = ""
local Coordinate = nil -- Core.Point#COORDINATE
@@ -172,7 +174,6 @@ do -- ACT_ROUTE
end
local Task = self:GetTask() -- This is to dermine that the coordinates are for a specific task mode (A2A or A2G).
local CC = self:GetTask():GetMission():GetCommandCenter()
if CC then
if CC:IsModeWWII() then
@@ -180,13 +181,13 @@ do -- ACT_ROUTE
local ShortestDistance = 0
local ShortestReferencePoint = nil
local ShortestReferenceName = ""
self:F( { CC.ReferencePoints } )
self:E( { CC.ReferencePoints } )
for ZoneName, Zone in pairs( CC.ReferencePoints ) do
self:F( { ZoneName = ZoneName } )
self:E( { ZoneName = ZoneName } )
local Zone = Zone -- Core.Zone#ZONE
local ZoneCoord = Zone:GetCoordinate()
local ZoneDistance = ZoneCoord:Get2DDistance( self.Coordinate )
self:F( { ShortestDistance, ShortestReferenceName } )
self:E( { ShortestDistance, ShortestReferenceName } )
if ShortestDistance == 0 or ZoneDistance < ShortestDistance then
ShortestDistance = ZoneDistance
ShortestReferencePoint = ZoneCoord
@@ -197,7 +198,7 @@ do -- ACT_ROUTE
RouteText = Coordinate:ToStringFromRP( ShortestReferencePoint, ShortestReferenceName, Controllable )
end
else
RouteText = Coordinate:ToString( Controllable, nil, Task )
RouteText = Coordinate:ToString( Controllable )
end
end
@@ -213,7 +214,7 @@ do -- ACT_ROUTE
--- StateMachine callback function
-- @param #ACT_ROUTE self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -225,7 +226,7 @@ do -- ACT_ROUTE
--- Check if the controllable has arrived.
-- @param #ACT_ROUTE self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @return #boolean
function ACT_ROUTE:onfuncHasArrived( ProcessUnit )
return false
@@ -233,7 +234,7 @@ do -- ACT_ROUTE
--- StateMachine callback function
-- @param #ACT_ROUTE self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
@@ -350,7 +351,7 @@ do -- ACT_ROUTE_POINT
--- Method override to check if the controllable has arrived.
-- @param #ACT_ROUTE_POINT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @return #boolean
function ACT_ROUTE_POINT:onfuncHasArrived( ProcessUnit )
@@ -359,7 +360,7 @@ do -- ACT_ROUTE_POINT
if Distance <= self.Range then
local RouteText = "You have arrived."
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
self:Message( RouteText )
return true
end
end
@@ -371,15 +372,14 @@ do -- ACT_ROUTE_POINT
--- StateMachine callback function
-- @param #ACT_ROUTE_POINT self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ROUTE_POINT:onafterReport( ProcessUnit, From, Event, To )
local RouteText = self:GetRouteText( ProcessUnit )
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
self:Message( RouteText )
end
end -- ACT_ROUTE_POINT
@@ -444,13 +444,13 @@ do -- ACT_ROUTE_ZONE
--- Method override to check if the controllable has arrived.
-- @param #ACT_ROUTE self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @return #boolean
function ACT_ROUTE_ZONE:onfuncHasArrived( ProcessUnit )
if ProcessUnit:IsInZone( self.Zone ) then
local RouteText = "You have arrived within the zone."
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
self:Message( RouteText )
end
return ProcessUnit:IsInZone( self.Zone )
@@ -460,15 +460,15 @@ do -- ACT_ROUTE_ZONE
--- StateMachine callback function
-- @param #ACT_ROUTE_ZONE self
-- @param Wrapper.Unit#UNIT ProcessUnit
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
-- @param #string Event
-- @param #string From
-- @param #string To
function ACT_ROUTE_ZONE:onafterReport( ProcessUnit, From, Event, To )
self:F( { ProcessUnit = ProcessUnit } )
self:E( { ProcessUnit = ProcessUnit } )
local RouteText = self:GetRouteText( ProcessUnit )
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
self:Message( RouteText )
end
end -- ACT_ROUTE_ZONE

View File

@@ -4,10 +4,10 @@
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ===
-- ====
--
-- @module Base
@@ -198,19 +198,13 @@ BASE = {
ClassID = 0,
Events = {},
States = {},
Debug = debug,
Scheduler = nil,
_ = {},
}
--- @field #BASE.__
BASE.__ = {}
--- @field #BASE._
BASE._ = {
Schedules = {} --- Contains the Schedulers Active
}
--- The Formation Class
-- @type FORMATION
-- @field Cone A cone formation.
@@ -271,23 +265,6 @@ function BASE:Inherit( Child, Parent )
return Child
end
local function getParent( Child )
local Parent = nil
if Child.ClassName == 'BASE' then
Parent = nil
else
if rawget( Child, "__" ) then
Parent = getmetatable( Child.__ ).__index
else
Parent = getmetatable( Child ).__index
end
end
return Parent
end
--- This is the worker method to retrieve the Parent class.
-- Note that the Parent class must be passed to call the parent class method.
--
@@ -297,91 +274,16 @@ end
-- @param #BASE self
-- @param #BASE Child is the Child class from which the Parent class needs to be retrieved.
-- @return #BASE
function BASE:GetParent( Child, FromClass )
function BASE:GetParent( Child )
local Parent
-- BASE class has no parent
if Child.ClassName == 'BASE' then
Parent = nil
else
--self:E({FromClass = FromClass})
--self:E({Child = Child.ClassName})
if FromClass then
while( Child.ClassName ~= "BASE" and Child.ClassName ~= FromClass.ClassName ) do
Child = getParent( Child )
--self:E({Child.ClassName})
end
end
if Child.ClassName == 'BASE' then
Parent = nil
else
Parent = getParent( Child )
end
end
--self:E({Parent.ClassName})
return Parent
if rawget( Child, "__" ) then
Parent = getmetatable( Child.__ ).__index
else
Parent = getmetatable( Child ).__index
end
return Parent
end
--- This is the worker method to check if an object is an (sub)instance of a class.
--
-- ### Examples:
--
-- * ZONE:New( 'some zone' ):IsInstanceOf( ZONE ) will return true
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'ZONE' ) will return true
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'zone' ) will return true
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'BASE' ) will return true
--
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'GROUP' ) will return false
--
-- @param #BASE self
-- @param ClassName is the name of the class or the class itself to run the check against
-- @return #boolean
function BASE:IsInstanceOf( ClassName )
-- Is className NOT a string ?
if type( ClassName ) ~= 'string' then
-- Is className a Moose class ?
if type( ClassName ) == 'table' and ClassName.ClassName ~= nil then
-- Get the name of the Moose class as a string
ClassName = ClassName.ClassName
-- className is neither a string nor a Moose class, throw an error
else
-- I'm not sure if this should take advantage of MOOSE logging function, or throw an error for pcall
local err_str = 'className parameter should be a string; parameter received: '..type( ClassName )
self:E( err_str )
-- error( err_str )
return false
end
end
ClassName = string.upper( ClassName )
if string.upper( self.ClassName ) == ClassName then
return true
end
local Parent = getParent(self)
while Parent do
if string.upper( Parent.ClassName ) == ClassName then
return true
end
Parent = getParent( Parent )
end
return false
end
--- Get the ClassName + ClassID of the class instance.
-- The ClassName + ClassID is formatted as '%s#%09d'.
-- @param #BASE self
@@ -645,22 +547,6 @@ function BASE:CreateEventCrash( EventTime, Initiator )
world.onEvent( Event )
end
--- Creation of a Takeoff Event.
-- @param #BASE self
-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event.
-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event.
function BASE:CreateEventTakeoff( EventTime, Initiator )
self:F( { EventTime, Initiator } )
local Event = {
id = world.event.S_EVENT_TAKEOFF,
time = EventTime,
initiator = Initiator,
}
world.onEvent( Event )
end
-- TODO: Complete Dcs.DCSTypes#Event structure.
--- The main event handling function... This function captures all events generated for the class.
-- @param #BASE self
@@ -691,96 +577,6 @@ function BASE:onEvent(event)
end
end
do -- Scheduling
--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also.
-- @param #BASE self
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
-- @return #number The ScheduleID of the planned schedule.
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
self:F2( { Start } )
self:T3( { ... } )
local ObjectName = "-"
ObjectName = self.ClassName .. self.ClassID
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
if not self.Scheduler then
self.Scheduler = SCHEDULER:New( self )
end
self.Scheduler.SchedulerObject = self.Scheduler
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
self,
SchedulerFunction,
{ ... },
Start,
nil,
nil,
nil
)
self._.Schedules[#self._.Schedules+1] = ScheduleID
return self._.Schedules[#self._.Schedules]
end
--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also.
-- @param #BASE self
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
-- @param #number Repeat Specifies the interval in seconds when the scheduler will call the event function.
-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat.
-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped.
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
-- @return #number The ScheduleID of the planned schedule.
function BASE:ScheduleRepeat( Start, Repeat, RandomizeFactor, Stop, SchedulerFunction, ... )
self:F2( { Start } )
self:T3( { ... } )
local ObjectName = "-"
ObjectName = self.ClassName .. self.ClassID
self:F3( { "ScheduleRepeat: ", ObjectName, Start, Repeat, RandomizeFactor, Stop } )
if not self.Scheduler then
self.Scheduler = SCHEDULER:New( self )
end
self.Scheduler.SchedulerObject = self.Scheduler
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
self,
SchedulerFunction,
{ ... },
Start,
Repeat,
RandomizeFactor,
Stop
)
self._.Schedules[#self._.Schedules+1] = ScheduleID
return self._.Schedules[#self._.Schedules]
end
--- Stops the Schedule.
-- @param #BASE self
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
function BASE:ScheduleStop( SchedulerFunction )
self:F3( { "ScheduleStop:" } )
_SCHEDULEDISPATCHER:Stop( self.Scheduler, self._.Schedules[SchedulerFunction] )
end
end
--- Set a state or property of the Object given a Key and a Value.
-- Note that if the Object is destroyed, nillified or garbage collected, then the Values and Keys will also be gone.
-- @param #BASE self
@@ -795,6 +591,7 @@ function BASE:SetState( Object, Key, Value )
self.States[ClassNameAndID] = self.States[ClassNameAndID] or {}
self.States[ClassNameAndID][Key] = Value
self:T2( { ClassNameAndID, Key, Value } )
return self.States[ClassNameAndID][Key]
end
@@ -812,6 +609,7 @@ function BASE:GetState( Object, Key )
if self.States[ClassNameAndID] then
local Value = self.States[ClassNameAndID][Key] or false
self:T2( { ClassNameAndID, Key, Value } )
return Value
end
@@ -832,7 +630,7 @@ end
-- TODO: Make trace function using variable parameters.
--- Set trace on or off
-- Note that when trace is off, no BASE.Debug statement is performed, increasing performance!
-- Note that when trace is off, no debug statement is performed, increasing performance!
-- When Moose is loaded statically, (as one file), tracing is switched off by default.
-- So tracing must be switched on manually in your mission if you are using Moose statically.
-- When moose is loading dynamically (for moose class development), tracing is switched on by default.
@@ -854,7 +652,7 @@ end
-- @return #boolean
function BASE:IsTrace()
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
return true
else
return false
@@ -910,10 +708,10 @@ end
-- @param Arguments A #table or any field.
function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" )
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo( 2, "nl" )
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" )
local Function = "function"
if DebugInfoCurrent.name then
@@ -939,9 +737,9 @@ end
-- @param Arguments A #table or any field.
function BASE:F( Arguments )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if _TraceLevel >= 1 then
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -955,9 +753,9 @@ end
-- @param Arguments A #table or any field.
function BASE:F2( Arguments )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if _TraceLevel >= 2 then
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -970,9 +768,9 @@ end
-- @param Arguments A #table or any field.
function BASE:F3( Arguments )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if _TraceLevel >= 3 then
self:_F( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -985,10 +783,10 @@ end
-- @param Arguments A #table or any field.
function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
if debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" )
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or debug.getinfo( 2, "nl" )
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or debug.getinfo( 3, "l" )
local Function = "function"
if DebugInfoCurrent.name then
@@ -1014,9 +812,9 @@ end
-- @param Arguments A #table or any field.
function BASE:T( Arguments )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if _TraceLevel >= 1 then
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -1030,9 +828,9 @@ end
-- @param Arguments A #table or any field.
function BASE:T2( Arguments )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if _TraceLevel >= 2 then
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -1045,9 +843,9 @@ end
-- @param Arguments A #table or any field.
function BASE:T3( Arguments )
if BASE.Debug and _TraceOnOff then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if debug and _TraceOnOff then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
if _TraceLevel >= 3 then
self:_T( Arguments, DebugInfoCurrent, DebugInfoFrom )
@@ -1060,9 +858,9 @@ end
-- @param Arguments A #table or any field.
function BASE:E( Arguments )
if BASE.Debug then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
if debug then
local DebugInfoCurrent = debug.getinfo( 2, "nl" )
local DebugInfoFrom = debug.getinfo( 3, "l" )
local Function = "function"
if DebugInfoCurrent.name then
@@ -1076,36 +874,6 @@ function BASE:E( Arguments )
end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
else
env.info( string.format( "%1s:%20s%05d(%s)" , "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end
end
--- Log an information which will be traced always. Can be anywhere within the function logic.
-- @param #BASE self
-- @param Arguments A #table or any field.
function BASE:I( Arguments )
if BASE.Debug then
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
local Function = "function"
if DebugInfoCurrent.name then
Function = DebugInfoCurrent.name
end
local LineCurrent = DebugInfoCurrent.currentline
local LineFrom = -1
if DebugInfoFrom then
LineFrom = DebugInfoFrom.currentline
end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
else
env.info( string.format( "%1s:%20s%05d(%s)" , "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end
end

View File

@@ -11,7 +11,7 @@
--
-- This module is still under construction, but is described above works already, and will keep working ...
--
-- ===
-- ====
--
-- # Demo Missions
--
@@ -21,18 +21,18 @@
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ===
-- ====
--
-- # YouTube Channel
--
-- ### [CARGO YouTube Channel](https://www.youtube.com/watch?v=tM00lTlkpYs&list=PL7ZUrU4zZUl2zUTuKrLW5RsO9zLMqUtbf)
--
-- ===
-- ====
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ===
-- ====
--
-- @module Cargo
@@ -338,13 +338,6 @@ function CARGO:IsUnLoaded()
return self:Is( "UnLoaded" )
end
--- Check if cargo is boarding.
-- @param #CARGO self
-- @return #boolean true if boarding
function CARGO:IsBoarding()
return self:Is( "Boarding" )
end
--- Check if cargo is alive.
-- @param #CARGO self
-- @return #boolean true if unloaded
@@ -493,8 +486,7 @@ end
function CARGO:IsNear( PointVec2, NearRadius )
self:F( { PointVec2, NearRadius } )
--local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() )
local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
self:T( Distance )
if Distance <= NearRadius then
@@ -536,7 +528,7 @@ do -- CARGO_REPRESENTABLE
-- @extends #CARGO
-- @field test
--- Models CARGO that is representable by a Unit.
---
-- @field #CARGO_REPRESENTABLE CARGO_REPRESENTABLE
CARGO_REPRESENTABLE = {
ClassName = "CARGO_REPRESENTABLE"
@@ -556,18 +548,6 @@ do -- CARGO_REPRESENTABLE
return self
end
--- CARGO_REPRESENTABLE Destructor.
-- @param #CARGO_REPRESENTABLE self
-- @return #CARGO_REPRESENTABLE
function CARGO_REPRESENTABLE:Destroy()
-- Cargo objects are deleted from the _DATABASE and SET_CARGO objects.
self:F( { CargoName = self:GetName() } )
_EVENTDISPATCHER:CreateEventDeleteCargo( self )
return self
end
--- Route a cargo unit to a PointVec2.
-- @param #CARGO_REPRESENTABLE self
@@ -581,8 +561,8 @@ do -- CARGO_REPRESENTABLE
local PointStartVec2 = self.CargoObject:GetPointVec2()
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
Points[#Points+1] = ToPointVec2:WaypointGround( Speed )
Points[#Points+1] = PointStartVec2:RoutePointGround( Speed )
Points[#Points+1] = ToPointVec2:RoutePointGround( Speed )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 2 )
@@ -697,7 +677,7 @@ end
do -- CARGO_UNIT
--- Models CARGO in the form of units, which can be boarded, unboarded, loaded, unloaded.
--- Hello
-- @type CARGO_UNIT
-- @extends #CARGO_REPRESENTABLE
@@ -714,425 +694,346 @@ do -- CARGO_UNIT
ClassName = "CARGO_UNIT"
}
--- CARGO_UNIT Constructor.
-- @param #CARGO_UNIT self
-- @param Wrapper.Unit#UNIT CargoUnit
-- @param #string Type
-- @param #string Name
-- @param #number Weight
-- @param #number ReportRadius (optional)
-- @param #number NearRadius (optional)
-- @return #CARGO_UNIT
function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT
self:F( { Type, Name, Weight, NearRadius } )
--- CARGO_UNIT Constructor.
-- @param #CARGO_UNIT self
-- @param Wrapper.Unit#UNIT CargoUnit
-- @param #string Type
-- @param #string Name
-- @param #number Weight
-- @param #number ReportRadius (optional)
-- @param #number NearRadius (optional)
-- @return #CARGO_UNIT
function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT
self:F( { Type, Name, Weight, NearRadius } )
self:T( CargoUnit )
self.CargoObject = CargoUnit
self:T( self.ClassName )
-- self:HandleEvent( EVENTS.Dead,
-- --- @param #CARGO Cargo
-- -- @param Core.Event#EVENTDATA EventData
-- function( Cargo, EventData )
-- if Cargo:GetObjectName() == EventData.IniUnit:GetName() then
-- self:E( { "Cargo destroyed", Cargo } )
-- Cargo:Destroyed()
-- end
-- end
-- )
self:SetEventPriority( 5 )
return self
end
--- CARGO_UNIT Destructor.
-- @param #CARGO_UNIT self
-- @return #CARGO_UNIT
function CARGO_UNIT:Destroy()
-- Cargo objects are deleted from the _DATABASE and SET_CARGO objects.
self:F( { CargoName = self:GetName() } )
_EVENTDISPATCHER:CreateEventDeleteCargo( self )
return self
end
--- Enter UnBoarding State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25
local Angle = 180
local Speed = 60
local DeployDistance = 9
local RouteDistance = 60
if From == "Loaded" then
local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading )
-- if there is no ToPointVec2 given, then use the CargoRoutePointVec2
ToPointVec2 = ToPointVec2 or CargoRoutePointVec2
local DirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3(ToPointVec2)
local Angle = CargoCarrierPointVec2:GetAngleDegrees(DirectionVec3)
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, Angle )
local FromPointVec2 = CargoCarrierPointVec2
-- Respawn the group...
if self.CargoObject then
self.CargoObject:ReSpawn( CargoDeployPointVec2:GetVec3(), CargoDeployHeading )
self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } )
self.CargoCarrier = nil
local Points = {}
Points[#Points+1] = CargoCarrierPointVec2:RoutePointGround( Speed )
Points[#Points+1] = ToPointVec2:RoutePointGround( Speed )
self:T( CargoUnit )
self.CargoObject = CargoUnit
self:T( self.ClassName )
self:SetEventPriority( 5 )
return self
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 1 )
self:__UnBoarding( 1, ToPointVec2, NearRadius )
end
end
end
--- Leave UnBoarding State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25
local Angle = 180
local Speed = 10
local Distance = 5
if From == "UnBoarding" then
if self:IsNear( ToPointVec2, NearRadius ) then
return true
else
self:__UnBoarding( 1, ToPointVec2, NearRadius )
end
return false
end
end
--- UnBoard Event.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25
self.CargoInAir = self.CargoObject:InAir()
self:T( self.CargoInAir )
-- Only unboard the cargo when the carrier is not in the air.
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then
end
self:__UnLoad( 1, ToPointVec2, NearRadius )
end
--- Enter UnLoaded State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2
function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
self:F( { ToPointVec2, From, Event, To } )
local Angle = 180
local Speed = 10
local Distance = 5
if From == "Loaded" then
local StartPointVec2 = self.CargoCarrier:GetPointVec2()
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading )
ToPointVec2 = ToPointVec2 or POINT_VEC2:New( CargoDeployPointVec2:GetX(), CargoDeployPointVec2:GetY() )
-- Respawn the group...
if self.CargoObject then
self.CargoObject:ReSpawn( ToPointVec2:GetVec3(), 0 )
self.CargoCarrier = nil
end
end
if self.OnUnLoadedCallBack then
self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) )
self.OnUnLoadedCallBack = nil
end
end
--- Board Event.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier, NearRadius } )
local NearRadius = NearRadius or 25
--- Enter UnBoarding State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25
local Angle = 180
local Speed = 60
local DeployDistance = 9
local RouteDistance = 60
if From == "Loaded" then
local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE
self.CargoInAir = self.CargoObject:InAir()
self:T( self.CargoInAir )
-- Only move the group to the carrier when the cargo is not in the air
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
self:Load( CargoCarrier, NearRadius, ... )
else
local Speed = 90
local Angle = 180
local Distance = 5
NearRadius = NearRadius or 25
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading )
-- if there is no ToPointVec2 given, then use the CargoRoutePointVec2
ToPointVec2 = ToPointVec2 or CargoRoutePointVec2
local DirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3(ToPointVec2)
local Angle = CargoCarrierPointVec2:GetAngleDegrees(DirectionVec3)
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, Angle )
local FromPointVec2 = CargoCarrierPointVec2
-- Respawn the group...
if self.CargoObject then
self.CargoObject:ReSpawn( CargoDeployPointVec2:GetVec3(), CargoDeployHeading )
self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } )
self.CargoCarrier = nil
local Points = {}
Points[#Points+1] = CargoCarrierPointVec2:WaypointGround( Speed )
Points[#Points+1] = ToPointVec2:WaypointGround( Speed )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 1 )
self:__UnBoarding( 1, ToPointVec2, NearRadius )
end
end
end
--- Leave UnBoarding State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25
local Angle = 180
local Speed = 10
local Distance = 5
if From == "UnBoarding" then
if self:IsNear( ToPointVec2, NearRadius ) then
return true
else
self:__UnBoarding( 1, ToPointVec2, NearRadius )
end
return false
end
end
--- UnBoard Event.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25
self.CargoInAir = self.CargoObject:InAir()
self:T( self.CargoInAir )
-- Only unboard the cargo when the carrier is not in the air.
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then
end
self:__UnLoad( 1, ToPointVec2, NearRadius )
end
--- Enter UnLoaded State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2
function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
self:F( { ToPointVec2, From, Event, To } )
local Angle = 180
local Speed = 10
local Distance = 5
if From == "Loaded" then
local StartPointVec2 = self.CargoCarrier:GetPointVec2()
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployCoord = StartPointVec2:Translate( Distance, CargoDeployHeading )
ToPointVec2 = ToPointVec2 or COORDINATE:New( CargoDeployCoord.x, CargoDeployCoord.z )
-- Respawn the group...
if self.CargoObject then
self.CargoObject:ReSpawn( ToPointVec2:GetVec3(), 0 )
self.CargoCarrier = nil
end
end
if self.OnUnLoadedCallBack then
self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) )
self.OnUnLoadedCallBack = nil
end
end
--- Board Event.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier, NearRadius } )
local NearRadius = NearRadius or 25
local Points = {}
self.CargoInAir = self.CargoObject:InAir()
local PointStartVec2 = self.CargoObject:GetPointVec2()
Points[#Points+1] = PointStartVec2:RoutePointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 2 )
self:__Boarding( -1, CargoCarrier, NearRadius )
self.RunCount = 0
end
end
self:T( self.CargoInAir )
end
--- Boarding Event.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
-- Only move the group to the carrier when the cargo is not in the air
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then
if CargoCarrier and CargoCarrier:IsAlive() then
if CargoCarrier:InAir() == false then
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
self:Load( CargoCarrier, NearRadius, ... )
self:__Load( 1, CargoCarrier, ... )
else
local Speed = 90
local Angle = 180
local Distance = 5
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
self.RunCount = self.RunCount + 1
if self.RunCount >= 20 then
self.RunCount = 0
local Speed = 90
local Angle = 180
local Distance = 5
NearRadius = NearRadius or 25
NearRadius = NearRadius or 25
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
local Points = {}
local PointStartVec2 = self.CargoObject:GetPointVec2()
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 2 )
self:__Boarding( -1, CargoCarrier, NearRadius )
self.RunCount = 0
end
end
end
--- Boarding Event.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
if CargoCarrier and CargoCarrier:IsAlive() then
if CargoCarrier:InAir() == false then
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
self:__Load( 1, CargoCarrier, ... )
else
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
self.RunCount = self.RunCount + 1
if self.RunCount >= 60 then
self.RunCount = 0
local Speed = 90
local Angle = 180
local Distance = 5
NearRadius = NearRadius or 25
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
local Points = {}
local PointStartVec2 = self.CargoObject:GetPointVec2()
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 0.2 )
end
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
local Points = {}
local PointStartVec2 = self.CargoObject:GetPointVec2()
Points[#Points+1] = PointStartVec2:RoutePointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 0.2 )
end
else
self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() )
self:CancelBoarding( CargoCarrier, NearRadius, ... )
self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) )
end
else
self:E("Something is wrong")
self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() )
self:CancelBoarding( CargoCarrier, NearRadius, ... )
self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) )
end
else
self:E("Something is wrong")
end
--- Enter Boarding State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
local Speed = 90
local Angle = 180
local Distance = 5
local NearRadius = NearRadius or 25
if From == "UnLoaded" or From == "Boarding" then
end
end
--- Loaded State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier )
self:F( { From, Event, To, CargoCarrier } )
self.CargoCarrier = CargoCarrier
-- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects).
if self.CargoObject then
self:T("Destroying")
self.CargoObject:Destroy()
end
end
end -- CARGO_UNIT
end
do -- CARGO_CRATE
--- Enter Boarding State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
local Speed = 90
local Angle = 180
local Distance = 5
local NearRadius = NearRadius or 25
--- Models the behaviour of cargo crates, which can be slingloaded and boarded on helicopters using the DCS menus.
-- @type CARGO_CRATE
-- @extends #CARGO_REPRESENTABLE
--- # CARGO\_CRATE class, extends @{#CARGO_REPRESENTABLE}
--
-- The CARGO\_CRATE class defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers.
--
-- ===
--
-- @field #CARGO_CRATE
CARGO_CRATE = {
ClassName = "CARGO_CRATE"
}
--- CARGO_CRATE Constructor.
-- @param #CARGO_CRATE self
-- @param #string CrateName
-- @param #string Type
-- @param #string Name
-- @param #number Weight
-- @param #number ReportRadius (optional)
-- @param #number NearRadius (optional)
-- @return #CARGO_CRATE
function CARGO_CRATE:New( CargoCrateName, Type, Name, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCrateName, Type, Name, nil, NearRadius ) ) -- #CARGO_CRATE
self:F( { Type, Name, NearRadius } )
self:T( CargoCrateName )
_DATABASE:AddStatic( CargoCrateName )
self.CargoObject = STATIC:FindByName( CargoCrateName )
self:T( self.ClassName )
self:SetEventPriority( 5 )
return self
end
--- Enter UnLoaded State.
-- @param #CARGO_CRATE self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2
function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 )
self:F( { ToPointVec2, From, Event, To } )
local Angle = 180
local Speed = 10
local Distance = 10
if From == "Loaded" then
local StartCoordinate = self.CargoCarrier:GetCoordinate()
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployCoord = StartCoordinate:Translate( Distance, CargoDeployHeading )
ToPointVec2 = ToPointVec2 or COORDINATE:NewFromVec2( { x= CargoDeployCoord.x, y = CargoDeployCoord.z } )
-- Respawn the group...
if self.CargoObject then
self.CargoObject:ReSpawn( ToPointVec2, 0 )
self.CargoCarrier = nil
end
end
if self.OnUnLoadedCallBack then
self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) )
self.OnUnLoadedCallBack = nil
end
if From == "UnLoaded" or From == "Boarding" then
end
end
--- Loaded State.
-- @param #CARGO_UNIT self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier )
self:F( { From, Event, To, CargoCarrier } )
self.CargoCarrier = CargoCarrier
--- Loaded State.
-- @param #CARGO_CRATE self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_CRATE:onenterLoaded( From, Event, To, CargoCarrier )
self:F( { From, Event, To, CargoCarrier } )
self.CargoCarrier = CargoCarrier
-- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects).
if self.CargoObject then
self:T("Destroying")
self.CargoObject:Destroy()
end
-- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects).
if self.CargoObject then
self:T("Destroying")
self.CargoObject:Destroy()
end
end
end
do -- CARGO_GROUP
--- @type CARGO_GROUP
@@ -1289,10 +1190,7 @@ function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius,
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
self:T( { Cargo:GetName(), Cargo.current } )
if not Cargo:is( "Loaded" )
and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function.
if not Cargo:is( "Loaded" ) then
Boarded = false
end
@@ -1432,9 +1330,7 @@ function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... )
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach(
function( Cargo )
--Cargo:UnLoad( ToPointVec2 )
local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(10)
Cargo:UnLoad( RandomVec2 )
Cargo:UnLoad( ToPointVec2 )
end
)
@@ -1515,8 +1411,8 @@ function CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, Boa
self:T( { CargoCarrierHeading, CargoDeployHeading } )
local CargoDeployPointVec2 = CargoCarrier:GetPointVec2():Translate( BoardDistance, CargoDeployHeading )
Points[#Points+1] = StartPointVec2:WaypointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
Points[#Points+1] = StartPointVec2:RoutePointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed )
local TaskRoute = self.CargoCarrier:TaskRoute( Points )
self.CargoCarrier:SetTask( TaskRoute, 1 )
@@ -1592,8 +1488,8 @@ function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnL
self:T( { CargoCarrierHeading, CargoDeployHeading } )
local CargoDeployPointVec2 = StartPointVec2:Translate( UnBoardDistance, CargoDeployHeading )
Points[#Points+1] = StartPointVec2:WaypointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
Points[#Points+1] = StartPointVec2:RoutePointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed )
local TaskRoute = CargoCarrier:TaskRoute( Points )
CargoCarrier:SetTask( TaskRoute, 1 )
@@ -1639,8 +1535,8 @@ function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDi
local CargoDeployPointVec2 = StartPointVec2:Translate( LoadDistance, CargoDeployHeading )
local Points = {}
Points[#Points+1] = StartPointVec2:WaypointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
Points[#Points+1] = StartPointVec2:RoutePointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed )
local TaskRoute = self.CargoCarrier:TaskRoute( Points )
self.CargoCarrier:SetTask( TaskRoute, 1 )
@@ -1665,8 +1561,8 @@ function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Dist
self.CargoCarrier = CargoCarrier
local Points = {}
Points[#Points+1] = StartPointVec2:WaypointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
Points[#Points+1] = StartPointVec2:RoutePointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:RoutePointGround( Speed )
local TaskRoute = self.CargoCarrier:TaskRoute( Points )
self.CargoCarrier:SetTask( TaskRoute, 1 )

View File

@@ -1,20 +1,9 @@
--- **Core** -- DATABASE manages the database of mission objects.
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module Database
--- @type DATABASE
-- @extends Core.Base#BASE
--- # DATABASE class, extends @{Base#BASE}
-- ====
--
-- 1) @{#DATABASE} class, extends @{Base#BASE}
-- ===================================================
-- Mission designers can use the DATABASE class to refer to:
--
-- * STATICS
@@ -28,10 +17,35 @@
--
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
--
-- The singleton object **_DATABASE** is automatically created by MOOSE, that administers all objects within the mission.
-- Moose refers to **_DATABASE** within the framework extensively, but you can also refer to the _DATABASE object within your missions if required.
-- Moose will automatically create one instance of the DATABASE class into the **global** object _DATABASE.
-- Moose refers to _DATABASE within the framework extensively, but you can also refer to the _DATABASE object within your missions if required.
--
-- @field #DATABASE
-- 1.1) DATABASE iterators
-- -----------------------
-- You can iterate the database with the available iterator methods.
-- The iterator methods will walk the DATABASE set, and call for each element within the set a function that you provide.
-- The following iterator methods are currently available within the DATABASE:
--
-- * @{#DATABASE.ForEachUnit}: Calls a function for each @{UNIT} it finds within the DATABASE.
-- * @{#DATABASE.ForEachGroup}: Calls a function for each @{GROUP} it finds within the DATABASE.
-- * @{#DATABASE.ForEachPlayer}: Calls a function for each alive player it finds within the DATABASE.
-- * @{#DATABASE.ForEachPlayerJoined}: Calls a function for each joined player it finds within the DATABASE.
-- * @{#DATABASE.ForEachClient}: Calls a function for each @{CLIENT} it finds within the DATABASE.
-- * @{#DATABASE.ForEachClientAlive}: Calls a function for each alive @{CLIENT} it finds within the DATABASE.
--
-- ===
--
--
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ====
-- @module Database
--- DATABASE class
-- @type DATABASE
-- @extends Core.Base#BASE
DATABASE = {
ClassName = "DATABASE",
Templates = {
@@ -56,8 +70,6 @@ DATABASE = {
NavPoints = {},
PLAYERSETTINGS = {},
ZONENAMES = {},
HITS = {},
DESTROYS = {},
}
local _DATABASECoalition =
@@ -92,12 +104,11 @@ function DATABASE:New()
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Hit, self.AccountHits )
self:HandleEvent( EVENTS.NewCargo )
self:HandleEvent( EVENTS.DeleteCargo )
-- Follow alive players and clients
--self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event.
self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit )
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit )
self:_RegisterTemplates()
@@ -137,8 +148,8 @@ function DATABASE:New()
end
end
--self:E( "Scheduling" )
--PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 1, 1 )
self:E( "Scheduling" )
PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 1, 1 )
return self
end
@@ -325,7 +336,7 @@ function DATABASE:AddPlayer( UnitName, PlayerName )
if PlayerName then
self:E( { "Add player for unit:", UnitName, PlayerName } )
self.PLAYERS[PlayerName] = UnitName
self.PLAYERUNITS[PlayerName] = self:FindUnit( UnitName )
self.PLAYERUNITS[UnitName] = PlayerName
self.PLAYERSJOINED[PlayerName] = PlayerName
end
end
@@ -337,48 +348,10 @@ function DATABASE:DeletePlayer( UnitName, PlayerName )
if PlayerName then
self:E( { "Clean player:", PlayerName } )
self.PLAYERS[PlayerName] = nil
self.PLAYERUNITS[PlayerName] = nil
self.PLAYERUNITS[UnitName] = PlayerName
end
end
--- Get the player table from the DATABASE.
-- The player table contains all unit names with the key the name of the player (PlayerName).
-- @param #DATABASE self
-- @usage
-- local Players = _DATABASE:GetPlayers()
-- for PlayerName, UnitName in pairs( Players ) do
-- ..
-- end
function DATABASE:GetPlayers()
return self.PLAYERS
end
--- Get the player table from the DATABASE, which contains all UNIT objects.
-- The player table contains all UNIT objects of the player with the key the name of the player (PlayerName).
-- @param #DATABASE self
-- @usage
-- local PlayerUnits = _DATABASE:GetPlayerUnits()
-- for PlayerName, PlayerUnit in pairs( PlayerUnits ) do
-- ..
-- end
function DATABASE:GetPlayerUnits()
return self.PLAYERUNITS
end
--- Get the player table from the DATABASE which have joined in the mission historically.
-- The player table contains all UNIT objects with the key the name of the player (PlayerName).
-- @param #DATABASE self
-- @usage
-- local PlayersJoined = _DATABASE:GetPlayersJoined()
-- for PlayerName, PlayerUnit in pairs( PlayersJoined ) do
-- ..
-- end
function DATABASE:GetPlayersJoined()
return self.PLAYERSJOINED
end
--- Instantiate new Groups within the DCSRTE.
-- This method expects EXACTLY the same structure as a structure within the ME, and needs 2 additional fields defined:
@@ -442,13 +415,10 @@ end
--- Private method that registers new Group Templates within the DATABASE Object.
-- @param #DATABASE self
-- @param #table GroupTemplate
-- @param Dcs.DCScoalition#coalition.side CoalitionSide The coalition.side of the object.
-- @param Dcs.DCSObject#Object.Category CategoryID The Object.category of the object.
-- @param Dcs.DCScountry#country.id CountryID the country.id of the object
-- @return #DATABASE self
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName )
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID )
local GroupTemplateName = GroupName or env.getValueDictByKey( GroupTemplate.name )
local GroupTemplateName = env.getValueDictByKey(GroupTemplate.name)
local TraceTable = {}
@@ -463,7 +433,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
end
GroupTemplate.CategoryID = CategoryID
GroupTemplate.CoalitionID = CoalitionSide
GroupTemplate.CoalitionID = CoalitionID
GroupTemplate.CountryID = CountryID
self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName
@@ -472,7 +442,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
self.Templates.Groups[GroupTemplateName].UnitCount = #GroupTemplate.units
self.Templates.Groups[GroupTemplateName].Units = GroupTemplate.units
self.Templates.Groups[GroupTemplateName].CategoryID = CategoryID
self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionSide
self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionID
self.Templates.Groups[GroupTemplateName].CountryID = CountryID
@@ -499,13 +469,13 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
self.Templates.Units[UnitTemplate.name].GroupTemplate = GroupTemplate
self.Templates.Units[UnitTemplate.name].GroupId = GroupTemplate.groupId
self.Templates.Units[UnitTemplate.name].CategoryID = CategoryID
self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionSide
self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionID
self.Templates.Units[UnitTemplate.name].CountryID = CountryID
if UnitTemplate.skill and (UnitTemplate.skill == "Client" or UnitTemplate.skill == "Player") then
self.Templates.ClientsByName[UnitTemplate.name] = UnitTemplate
self.Templates.ClientsByName[UnitTemplate.name].CategoryID = CategoryID
self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionSide
self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionID
self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
end
@@ -549,7 +519,7 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
TraceTable[#TraceTable+1] = "Static"
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].StaticName
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].GroupName
TraceTable[#TraceTable+1] = "Coalition"
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CoalitionID
@@ -676,7 +646,6 @@ end
function DATABASE:_RegisterStatics()
local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) }
self:E( { Statics = CoalitionsData } )
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
for DCSStaticId, DCSStatic in pairs( CoalitionData ) do
@@ -729,21 +698,7 @@ function DATABASE:_EventOnBirth( Event )
self:AddGroup( Event.IniDCSGroupName )
end
end
if Event.IniObjectCategory == 1 then
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
Event.IniGroup = self:FindGroup( Event.IniDCSGroupName )
local PlayerName = Event.IniUnit:GetPlayerName()
self:E( { "PlayerName:", PlayerName } )
if PlayerName ~= "" then
self:E( { "Player Joined:", PlayerName } )
if not self.PLAYERS[PlayerName] then
self:AddPlayer( Event.IniUnitName, PlayerName )
end
local Settings = SETTINGS:Set( PlayerName )
Settings:SetPlayerMenu( Event.IniUnit )
--MENU_INDEX:Refresh( Event.IniGroup )
end
end
--self:_EventOnPlayerEnterUnit( Event )
end
end
@@ -767,8 +722,6 @@ function DATABASE:_EventOnDeadOrCrash( Event )
end
end
end
self:AccountDestroys( Event )
end
@@ -778,14 +731,13 @@ end
function DATABASE:_EventOnPlayerEnterUnit( Event )
self:F2( { Event } )
if Event.IniDCSUnit then
if Event.IniUnit then
if Event.IniObjectCategory == 1 then
self:AddUnit( Event.IniDCSUnitName )
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
self:AddGroup( Event.IniDCSGroupName )
local PlayerName = Event.IniDCSUnit:getPlayerName()
local PlayerName = Event.IniUnit:GetPlayerName()
if not self.PLAYERS[PlayerName] then
self:AddPlayer( Event.IniDCSUnitName, PlayerName )
self:AddPlayer( Event.IniUnitName, PlayerName )
end
local Settings = SETTINGS:Set( PlayerName )
Settings:SetPlayerMenu( Event.IniUnit )
@@ -804,7 +756,6 @@ function DATABASE:_EventOnPlayerLeaveUnit( Event )
if Event.IniObjectCategory == 1 then
local PlayerName = Event.IniUnit:GetPlayerName()
if self.PLAYERS[PlayerName] then
self:E( { "Player Left:", PlayerName } )
local Settings = SETTINGS:Set( PlayerName )
Settings:RemovePlayerMenu( Event.IniUnit )
self:DeletePlayer( Event.IniUnit, PlayerName )
@@ -993,7 +944,7 @@ end
-- @param #string PlayerName
-- @return Core.Settings#SETTINGS
function DATABASE:GetPlayerSettings( PlayerName )
self:F2( { PlayerName } )
self:E({PlayerName})
return self.PLAYERSETTINGS[PlayerName]
end
@@ -1004,7 +955,7 @@ end
-- @param Core.Settings#SETTINGS Settings
-- @return Core.Settings#SETTINGS
function DATABASE:SetPlayerSettings( PlayerName, Settings )
self:F2( { PlayerName, Settings } )
self:E({PlayerName, Settings})
self.PLAYERSETTINGS[PlayerName] = Settings
end
@@ -1102,101 +1053,6 @@ function DATABASE:_RegisterTemplates()
return self
end
--- Account the Hits of the Players.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event
function DATABASE:AccountHits( Event )
self:F( { Event } )
if Event.IniPlayerName ~= nil then -- It is a player that is hitting something
self:T( "Hitting Something" )
-- What is he hitting?
if Event.TgtCategory then
-- A target got hit
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
local Hit = self.HITS[Event.TgtUnitName]
Hit.Players = Hit.Players or {}
Hit.Players[Event.IniPlayerName] = true
end
end
-- It is a weapon initiated by a player, that is hitting something
-- This seems to occur only with scenery and static objects.
if Event.WeaponPlayerName ~= nil then
self:T( "Hitting Scenery" )
-- What is he hitting?
if Event.TgtCategory then
if Event.IniCoalition then -- A coalition object was hit, probably a static.
-- A target got hit
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
local Hit = self.HITS[Event.TgtUnitName]
Hit.Players = Hit.Players or {}
Hit.Players[Event.WeaponPlayerName] = true
else -- A scenery object was hit.
end
end
end
end
--- Account the destroys.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event
function DATABASE:AccountDestroys( Event )
self:F( { Event } )
local TargetUnit = nil
local TargetGroup = nil
local TargetUnitName = ""
local TargetGroupName = ""
local TargetPlayerName = ""
local TargetCoalition = nil
local TargetCategory = nil
local TargetType = nil
local TargetUnitCoalition = nil
local TargetUnitCategory = nil
local TargetUnitType = nil
if Event.IniDCSUnit then
TargetUnit = Event.IniUnit
TargetUnitName = Event.IniDCSUnitName
TargetGroup = Event.IniDCSGroup
TargetGroupName = Event.IniDCSGroupName
TargetPlayerName = Event.IniPlayerName
TargetCoalition = Event.IniCoalition
--TargetCategory = TargetUnit:getCategory()
--TargetCategory = TargetUnit:getDesc().category -- Workaround
TargetCategory = Event.IniCategory
TargetType = Event.IniTypeName
TargetUnitType = TargetType
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
end
self:T( "Something got destroyed" )
local Destroyed = false
-- What is the player destroying?
if self.HITS[Event.IniUnitName] then -- Was there a hit for this unit for this player before registered???
self.DESTROYS[Event.IniUnitName] = self.DESTROYS[Event.IniUnitName] or {}
self.DESTROYS[Event.IniUnitName] = true
end
end

View File

@@ -159,10 +159,10 @@
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ===
-- ====
--
-- @module Event
@@ -206,10 +206,6 @@ EVENTS = {
PlayerComment = world.event.S_EVENT_PLAYER_COMMENT,
ShootingStart = world.event.S_EVENT_SHOOTING_START,
ShootingEnd = world.event.S_EVENT_SHOOTING_END,
MarkAdded = world.event.S_EVENT_MARK_ADDED,
MarkChange = world.event.S_EVENT_MARK_CHANGE,
MarkRemoved = world.event.S_EVENT_MARK_REMOVED,
ShootingEnd = world.event.S_EVENT_SHOOTING_END,
NewCargo = world.event.S_EVENT_NEW_CARGO,
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
}
@@ -399,24 +395,6 @@ local _EVENTMETA = {
Event = "OnEventShootingEnd",
Text = "S_EVENT_SHOOTING_END"
},
[world.event.S_EVENT_MARK_ADDED] = {
Order = 1,
Side = "I",
Event = "OnEventMarkAdded",
Text = "S_EVENT_MARK_ADDED"
},
[world.event.S_EVENT_MARK_CHANGE] = {
Order = 1,
Side = "I",
Event = "OnEventMarkChange",
Text = "S_EVENT_MARK_CHANGE"
},
[world.event.S_EVENT_MARK_REMOVED] = {
Order = 1,
Side = "I",
Event = "OnEventMarkRemoved",
Text = "S_EVENT_MARK_REMOVED"
},
[EVENTS.NewCargo] = {
Order = 1,
Event = "OnEventNewCargo",
@@ -494,7 +472,7 @@ end
-- @return #EVENT.Events
function EVENT:Reset( EventObject ) --R2.1
self:F( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
self:E( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
local EventPriority = EventObject:GetEventPriority()
for EventID, EventData in pairs( self.Events ) do
@@ -583,12 +561,12 @@ end
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
-- @param EventID
-- @return #EVENT
function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID, ... )
function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID )
self:F2( GroupName )
local Event = self:Init( EventID, EventClass )
Event.EventGroup = true
Event.EventFunction = EventFunction
Event.Params = arg
return self
end
@@ -755,7 +733,7 @@ function EVENT:onEvent( Event )
local ErrorHandler = function( errmsg )
env.info( "Error in SCHEDULER function:" .. errmsg )
if BASE.Debug ~= nil then
if debug ~= nil then
env.info( debug.traceback() )
end
@@ -765,15 +743,13 @@ function EVENT:onEvent( Event )
local EventMeta = _EVENTMETA[Event.id]
--self:E( { EventMeta.Text, Event } ) -- Activate the see all incoming events ...
if self and
self.Events and
self.Events[Event.id] and
( Event.initiator ~= nil or ( Event.initiator == nil and Event.id ~= EVENTS.PlayerLeaveUnit ) ) then
if Event.initiator then
Event.IniObjectCategory = Event.initiator:getCategory()
if Event.IniObjectCategory == Object.Category.UNIT then
@@ -848,7 +824,7 @@ function EVENT:onEvent( Event )
Event.TgtDCSUnit = Event.target
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName )
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
@@ -895,9 +871,9 @@ function EVENT:onEvent( Event )
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do
--if Event.IniObjectCategory ~= Object.Category.STATIC then
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
--end
if Event.IniObjectCategory ~= Object.Category.STATIC then
--self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
end
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
@@ -907,7 +883,6 @@ function EVENT:onEvent( Event )
-- So now the EventClass must be a UNIT class!!! We check if it is still "Alive".
if EventClass:IsAlive() or
Event.id == EVENTS.PlayerEnterUnit or
Event.id == EVENTS.Crash or
Event.id == EVENTS.Dead then
@@ -920,7 +895,7 @@ function EVENT:onEvent( Event )
if EventData.EventFunction then
if Event.IniObjectCategory ~= 3 then
self:F( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
end
local Result, Value = xpcall(
@@ -936,7 +911,7 @@ function EVENT:onEvent( Event )
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:F( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
self:E( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
end
local Result, Value = xpcall(
@@ -957,7 +932,6 @@ function EVENT:onEvent( Event )
-- So now the EventClass must be a GROUP class!!! We check if it is still "Alive".
if EventClass:IsAlive() or
Event.id == EVENTS.PlayerEnterUnit or
Event.id == EVENTS.Crash or
Event.id == EVENTS.Dead then
@@ -971,12 +945,12 @@ function EVENT:onEvent( Event )
if EventData.EventFunction then
if Event.IniObjectCategory ~= 3 then
self:F( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
end
local Result, Value = xpcall(
function()
return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) )
return EventData.EventFunction( EventClass, Event )
end, ErrorHandler )
else
@@ -987,19 +961,19 @@ function EVENT:onEvent( Event )
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:F( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
self:E( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
end
local Result, Value = xpcall(
function()
return EventFunction( EventClass, Event, unpack( EventData.Params ) )
return EventFunction( EventClass, Event )
end, ErrorHandler )
end
end
end
else
-- The EventClass is not alive anymore, we remove it from the EventHandlers...
--self:RemoveEvent( EventClass, Event.id )
self:RemoveEvent( EventClass, Event.id )
end
else
@@ -1044,7 +1018,7 @@ function EVENT:onEvent( Event )
end
end
else
self:T( { EventMeta.Text, Event } )
self:E( { EventMeta.Text, Event } )
end
Event = nil

View File

@@ -56,13 +56,13 @@
-- * @{#FSM_SET}: Models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here
-- for multiple objects or the position of the state machine in the process.
--
-- ===
-- ====
--
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ===
-- ====
--
-- @module Fsm
@@ -562,8 +562,8 @@ do -- FSM
local ErrorHandler = function( errmsg )
env.info( "Error in SCHEDULER function:" .. errmsg )
if BASE.Debug ~= nil then
env.info( BASE.Debug.traceback() )
if debug ~= nil then
env.info( debug.traceback() )
end
return errmsg
@@ -860,8 +860,8 @@ do -- FSM_CONTROLLABLE
local ErrorHandler = function( errmsg )
env.info( "Error in SCHEDULER function:" .. errmsg )
if BASE.Debug ~= nil then
env.info( BASE.Debug.traceback() )
if debug ~= nil then
env.info( debug.traceback() )
end
return errmsg
@@ -920,8 +920,8 @@ do -- FSM_PROCESS
local ErrorHandler = function( errmsg )
env.info( "Error in FSM_PROCESS call handler:" .. errmsg )
if BASE.Debug ~= nil then
env.info( BASE.Debug.traceback() )
if debug ~= nil then
env.info( debug.traceback() )
end
return errmsg

View File

@@ -1,146 +0,0 @@
--- **Core (WIP)** -- Base class to allow the modeling of processes to achieve Goals.
--
-- ===
--
-- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module Goal
do -- Goal
--- @type GOAL
-- @extends Core.Fsm#FSM
--- # GOAL class, extends @{Fsm#FSM}
--
-- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
--
-- ## 1. GOAL constructor
--
-- * @{#GOAL.New}(): Creates a new GOAL object.
--
-- ## 2. GOAL is a finite state machine (FSM).
--
-- ### 2.1 GOAL States
--
-- * **Pending**: The goal object is in progress.
-- * **Achieved**: The goal objective is Achieved.
--
-- ### 2.2 GOAL Events
--
-- * **Achieved**: Set the goal objective to Achieved.
--
-- @field #GOAL
GOAL = {
ClassName = "GOAL",
}
--- @field #table GOAL.Players
GOAL.Players = {}
--- @field #number GOAL.TotalContributions
GOAL.TotalContributions = 0
--- GOAL Constructor.
-- @param #GOAL self
-- @return #GOAL
function GOAL:New()
local self = BASE:Inherit( self, FSM:New() ) -- #GOAL
self:F( {} )
--- Achieved State for GOAL
-- @field GOAL.Achieved
--- Achieved State Handler OnLeave for GOAL
-- @function [parent=#GOAL] OnLeaveAchieved
-- @param #GOAL self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Achieved State Handler OnEnter for GOAL
-- @function [parent=#GOAL] OnEnterAchieved
-- @param #GOAL self
-- @param #string From
-- @param #string Event
-- @param #string To
self:SetStartState( "Pending" )
self:AddTransition( "*", "Achieved", "Achieved" )
--- Achieved Handler OnBefore for GOAL
-- @function [parent=#GOAL] OnBeforeAchieved
-- @param #GOAL self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Achieved Handler OnAfter for GOAL
-- @function [parent=#GOAL] OnAfterAchieved
-- @param #GOAL self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Achieved Trigger for GOAL
-- @function [parent=#GOAL] Achieved
-- @param #GOAL self
--- Achieved Asynchronous Trigger for GOAL
-- @function [parent=#GOAL] __Achieved
-- @param #GOAL self
-- @param #number Delay
self:SetEventPriority( 5 )
return self
end
--- @param #GOAL self
-- @param #string PlayerName
function GOAL:AddPlayerContribution( PlayerName )
self.Players[PlayerName] = self.Players[PlayerName] or 0
self.Players[PlayerName] = self.Players[PlayerName] + 1
self.TotalContributions = self.TotalContributions + 1
end
--- @param #GOAL self
-- @param #number Player contribution.
function GOAL:GetPlayerContribution( PlayerName )
return self.Players[PlayerName] or 0
end
--- @param #GOAL self
function GOAL:GetPlayerContributions()
return self.Players or {}
end
--- @param #GOAL self
function GOAL:GetTotalContributions()
return self.TotalContributions or 0
end
--- @param #GOAL self
-- @return #boolean true if the goal is Achieved
function GOAL:IsAchieved()
return self:Is( "Achieved" )
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -39,12 +39,12 @@
-- * To all players using @{Message#MESSAGE.ToAllIf}().
-- * To a coalition using @{Message#MESSAGE.ToCoalitionIf}().
--
-- ===
-- ====
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ===
-- ====
--
-- @field #MESSAGE
MESSAGE = {
@@ -53,16 +53,6 @@ MESSAGE = {
MessageID = 0,
}
--- Message Types
-- @type MESSAGE.Type
MESSAGE.Type = {
Update = "Update",
Information = "Information",
Briefing = "Briefing Report",
Overview = "Overview Report",
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.
-- @param self
@@ -84,9 +74,6 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText, MessageDuration, MessageCategory } )
self.MessageType = nil
-- When no MessageCategory is given, we don't show it as a title...
if MessageCategory and MessageCategory ~= "" then
if MessageCategory:sub(-1) ~= "\n" then
@@ -109,37 +96,6 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
return self
end
--- Creates a new MESSAGE object of a certain type.
-- Note that these MESSAGE objects are not yet displayed on the display panel.
-- You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
-- The message display times are automatically defined based on the timing settings in the @{Settings} menu.
-- @param self
-- @param #string MessageText is the text of the Message.
-- @param #MESSAGE.Type MessageType The type of the message.
-- @return #MESSAGE
-- @usage
-- MessageAll = MESSAGE:NewType( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", MESSAGE.Type.Information )
-- MessageRED = MESSAGE:NewType( "To the RED Players: You receive a penalty because you've killed one of your own units", MESSAGE.Type.Information )
-- MessageClient1 = MESSAGE:NewType( "Congratulations, you've just hit a target", MESSAGE.Type.Update )
-- MessageClient2 = MESSAGE:NewType( "Congratulations, you've just killed a target", MESSAGE.Type.Update )
function MESSAGE:NewType( MessageText, MessageType )
local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText } )
self.MessageType = MessageType
self.MessageTime = timer.getTime()
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
return self
end
--- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player".
-- @param #MESSAGE self
-- @param Wrapper.Client#CLIENT Client is the Group of the Client.
@@ -159,22 +115,14 @@ end
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
-- MessageClient1:ToClient( ClientGroup )
-- MessageClient2:ToClient( ClientGroup )
function MESSAGE:ToClient( Client, Settings )
function MESSAGE:ToClient( Client )
self:F( Client )
if Client and Client:GetClientGroupID() then
if self.MessageType then
local Settings = Settings or ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if self.MessageDuration ~= 0 then
local ClientGroupID = Client:GetClientGroupID()
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
end
local ClientGroupID = Client:GetClientGroupID()
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
end
return self
@@ -184,21 +132,13 @@ end
-- @param #MESSAGE self
-- @param Wrapper.Group#GROUP Group is the Group.
-- @return #MESSAGE
function MESSAGE:ToGroup( Group, Settings )
function MESSAGE:ToGroup( Group )
self:F( Group.GroupName )
if Group then
if self.MessageType then
local Settings = Settings or ( Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
end
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
end
return self
@@ -253,20 +193,12 @@ end
-- or
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageRED:ToCoalition( coalition.side.RED )
function MESSAGE:ToCoalition( CoalitionSide, Settings )
function MESSAGE:ToCoalition( CoalitionSide )
self:F( CoalitionSide )
if self.MessageType then
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if CoalitionSide then
if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
end
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForCoalition( CoalitionSide, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
end
return self
@@ -300,16 +232,8 @@ end
function MESSAGE:ToAll()
self:F()
if self.MessageType then
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
self.MessageCategory = "" -- self.MessageType .. ": "
end
if self.MessageDuration ~= 0 then
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
end
self:ToCoalition( coalition.side.RED )
self:ToCoalition( coalition.side.BLUE )
return self
end
@@ -321,7 +245,8 @@ end
function MESSAGE:ToAllIf( Condition )
if Condition and Condition == true then
self:ToAll()
self:ToCoalition( coalition.side.RED )
self:ToCoalition( coalition.side.BLUE )
end
return self

View File

@@ -2,7 +2,7 @@
--
-- ![Banner Image](..\Presentations\POINT\Dia1.JPG)
--
-- ===
-- ====
--
-- # Demo Missions
--
@@ -12,7 +12,7 @@
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ===
-- ====
--
-- # YouTube Channel
--
@@ -54,8 +54,8 @@ do -- COORDINATE
--
-- A COORDINATE can prepare waypoints for Ground and Air groups to be embedded into a Route.
--
-- * @{#COORDINATE.WaypointAir}(): Build an air route point.
-- * @{#COORDINATE.WaypointGround}(): Build a ground route point.
-- * @{#COORDINATE.RoutePointAir}(): Build an air route point.
-- * @{#COORDINATE.RoutePointGround}(): Build a ground route point.
--
-- Route points can be used in the Route methods of the @{Group#GROUP} class.
--
@@ -90,18 +90,6 @@ do -- COORDINATE
-- * @{#COORDINATE.IlluminationBomb}(): To illuminate the point.
--
--
-- ## Markings
--
-- Place markers (text boxes with clarifications for briefings, target locations or any other reference point) on the map for all players, coalitions or specific groups:
--
-- * @{#COORDINATE.MarkToAll}(): Place a mark to all players.
-- * @{#COORDINATE.MarkToCoalition}(): Place a mark to a coalition.
-- * @{#COORDINATE.MarkToCoalitionRed}(): Place a mark to the red coalition.
-- * @{#COORDINATE.MarkToCoalitionBlue}(): Place a mark to the blue coalition.
-- * @{#COORDINATE.MarkToGroup}(): Place a mark to a group (needs to have a client in it or a CA group (CA group is bugged)).
-- * @{#COORDINATE.RemoveMark}(): Removes a mark from the map.
--
--
-- ## 3D calculation methods
--
-- Various calculation methods exist to use or manipulate 3D space. Find below a short description of each method:
@@ -150,31 +138,6 @@ do -- COORDINATE
ClassName = "COORDINATE",
}
--- @field COORDINATE.WaypointAltType
COORDINATE.WaypointAltType = {
BARO = "BARO",
RADIO = "RADIO",
}
--- @field COORDINATE.WaypointAction
COORDINATE.WaypointAction = {
TurningPoint = "Turning Point",
FlyoverPoint = "Fly Over Point",
FromParkingArea = "From Parking Area",
FromParkingAreaHot = "From Parking Area Hot",
FromRunway = "From Runway",
Landing = "Landing",
}
--- @field COORDINATE.WaypointType
COORDINATE.WaypointType = {
TakeOffParking = "TakeOffParking",
TakeOffParkingHot = "TakeOffParkingHot",
TakeOff = "TakeOffParkingHot",
TurningPoint = "Turning Point",
Land = "Land",
}
--- COORDINATE constructor.
-- @param #COORDINATE self
@@ -326,45 +289,9 @@ do -- COORDINATE
end
--- Set the heading of the coordinate, if applicable.
-- @param #COORDINATE self
function COORDINATE:SetHeading( Heading )
self.Heading = Heading
end
--- Get the heading of the coordinate, if applicable.
-- @param #COORDINATE self
-- @return #number or nil
function COORDINATE:GetHeading()
return self.Heading
end
--- Set the velocity of the COORDINATE.
-- @param #COORDINATE self
-- @param #string Velocity Velocity in meters per second.
function COORDINATE:SetVelocity( Velocity )
self.Velocity = Velocity
end
--- Return the velocity of the COORDINATE.
-- @param #COORDINATE self
-- @return #number Velocity in meters per second.
function COORDINATE:GetVelocity()
local Velocity = self.Velocity
return Velocity or 0
end
--- Return velocity text of the COORDINATE.
-- @param #COORDINATE self
-- @return #string
function COORDINATE:GetMovingText( Settings )
return self:GetVelocityText( Settings ) .. ", " .. self:GetHeadingText( Settings )
end
--- Return a direction vector Vec3 from COORDINATE to the COORDINATE.
@@ -375,7 +302,6 @@ do -- COORDINATE
return { x = TargetCoordinate.x - self.x, y = TargetCoordinate.y - self.y, z = TargetCoordinate.z - self.z }
end
--- Get a correction in radians of the real magnetic north of the COORDINATE.
-- @param #COORDINATE self
-- @return #number CorrectionRadians The correction in radians.
@@ -420,160 +346,6 @@ do -- COORDINATE
local SourceVec3 = self:GetVec3()
return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5
end
--- Returns the temperature in Degrees Celsius.
-- @param #COORDINATE self
-- @param height (Optional) parameter specifying the height ASL.
-- @return Temperature in Degrees Celsius.
function COORDINATE:GetTemperature(height)
local y=height or self.y
env.info("FF height = "..y)
local point={x=self.x, y=height or self.y, z=self.z}
-- get temperature [K] and pressure [Pa] at point
local T,P=atmosphere.getTemperatureAndPressure(point)
-- Return Temperature in Deg C
return T-273.15
end
--- Returns a text of the temperature according the measurement system @{Settings}.
-- The text will reflect the temperature like this:
--
-- - For Russian and European aircraft using the metric system - Degrees Celcius (°C)
-- - For Americain aircraft we link to the imperial system - Degrees Farenheit (°F)
--
-- A text containing a pressure will look like this:
--
-- - `Temperature: %n.d °C`
-- - `Temperature: %n.d °F`
--
-- @param #COORDINATE self
-- @param height (Optional) parameter specifying the height ASL.
-- @return #string Temperature according the measurement system @{Settings}.
function COORDINATE:GetTemperatureText( height, Settings )
local DegreesCelcius = self:GetTemperature( height )
local Settings = Settings or _SETTINGS
if DegreesCelcius then
if Settings:IsMetric() then
return string.format( " %-2.2f °C", DegreesCelcius )
else
return string.format( " %-2.2f °F", UTILS.CelciusToFarenheit( DegreesCelcius ) )
end
else
return " no temperature"
end
return nil
end
--- Returns the pressure in hPa.
-- @param #COORDINATE self
-- @param height (Optional) parameter specifying the height ASL. E.g. set height=0 for QNH.
-- @return Pressure in hPa.
function COORDINATE:GetPressure(height)
local point={x=self.x, y=height or self.y, z=self.z}
-- get temperature [K] and pressure [Pa] at point
local T,P=atmosphere.getTemperatureAndPressure(point)
-- Return Pressure in hPa.
return P/100
end
--- Returns a text of the pressure according the measurement system @{Settings}.
-- The text will contain always the pressure in hPa and:
--
-- - For Russian and European aircraft using the metric system - hPa and mmHg
-- - For Americain and European aircraft we link to the imperial system - hPa and inHg
--
-- A text containing a pressure will look like this:
--
-- - `QFE: x hPa (y mmHg)`
-- - `QFE: x hPa (y inHg)`
--
-- @param #COORDINATE self
-- @param height (Optional) parameter specifying the height ASL. E.g. set height=0 for QNH.
-- @return #string Pressure in hPa and mmHg or inHg depending on the measurement system @{Settings}.
function COORDINATE:GetPressureText( height, Settings )
local Pressure_hPa = self:GetPressure( height )
local Pressure_mmHg = Pressure_hPa * 0.7500615613030
local Pressure_inHg = Pressure_hPa * 0.0295299830714
local Settings = Settings or _SETTINGS
if Pressure_hPa then
if Settings:IsMetric() then
return string.format( " %4.1f hPa (%3.1f mmHg)", Pressure_hPa, Pressure_mmHg )
else
return string.format( " %4.1f hPa (%3.2f inHg)", Pressure_hPa, Pressure_inHg )
end
else
return " no pressure"
end
return nil
end
--- Returns the wind direction (from) and strength.
-- @param #COORDINATE self
-- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground.
-- @return Direction the wind is blowing from in degrees.
-- @return Wind strength in m/s.
function COORDINATE:GetWind(height)
local landheight=self:GetLandHeight()+0.1 -- we at 0.1 meters to be sure to be above ground since wind is zero below ground level.
local point={x=self.x, y=math.max(height or self.y, landheight), z=self.z}
-- get wind velocity vector
local wind = atmosphere.getWind(point)
local direction = math.deg(math.atan2(wind.z, wind.x))
if direction < 0 then
direction = 360 + direction
end
-- Convert to direction to from direction
if direction > 180 then
direction = direction-180
else
direction = direction+180
end
local strength=math.sqrt((wind.x)^2+(wind.z)^2)
-- Return wind direction and strength km/h.
return direction, strength
end
--- Returns a text documenting the wind direction (from) and strength according the measurement system @{Settings}.
-- The text will reflect the wind like this:
--
-- - For Russian and European aircraft using the metric system - Wind direction in degrees (°) and wind speed in meters per second (mps).
-- - For Americain aircraft we link to the imperial system - Wind direction in degrees (°) and wind speed in knots per second (kps).
--
-- A text containing a pressure will look like this:
--
-- - `Wind: %n ° at n.d mps`
-- - `Wind: %n ° at n.d kps`
--
-- @param #COORDINATE self
-- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground.
-- @return #string Wind direction and strength according the measurement system @{Settings}.
function COORDINATE:GetWindText( height, Settings )
local Direction, Strength = self:GetWind( height )
local Settings = Settings or _SETTINGS
if Direction and Strength then
if Settings:IsMetric() then
return string.format( " %d ° at %3.2f mps", Direction, UTILS.MpsToKmph( Strength ) )
else
return string.format( " %d ° at %3.2f kps", Direction, UTILS.MpsToKnots( Strength ) )
end
else
return " no wind"
end
return nil
end
--- Return the 3D distance in meters between the target COORDINATE and the COORDINATE.
-- @param #COORDINATE self
@@ -641,38 +413,6 @@ do -- COORDINATE
end
--- Return the velocity text of the COORDINATE.
-- @param #COORDINATE self
-- @return #string Velocity text.
function COORDINATE:GetVelocityText( Settings )
local Velocity = self:GetVelocity()
local Settings = Settings or _SETTINGS
if Velocity then
if Settings:IsMetric() then
return string.format( " moving at %d km/h", UTILS.MpsToKmph( Velocity ) )
else
return string.format( " moving at %d mi/h", UTILS.MpsToKmph( Velocity ) / 1.852 )
end
else
return " stationary"
end
end
--- Return the heading text of the COORDINATE.
-- @param #COORDINATE self
-- @return #string Heading text.
function COORDINATE:GetHeadingText( Settings )
local Heading = self:GetHeading()
if Heading then
return string.format( " bearing %3d°", Heading )
else
return " bearing unknown"
end
end
--- Provides a Bearing / Range string
-- @param #COORDINATE self
-- @param #number AngleRadians The angle in randians
@@ -731,25 +471,25 @@ do -- COORDINATE
--- Build an air type route point.
-- @param #COORDINATE self
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
-- @param #COORDINATE.WaypointType Type The route point type.
-- @param #COORDINATE.WaypointAction Action The route point action.
-- @param #COORDINATE.RoutePointAltType AltType The altitude type.
-- @param #COORDINATE.RoutePointType Type The route point type.
-- @param #COORDINATE.RoutePointAction Action The route point action.
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
-- @param #boolean SpeedLocked true means the speed is locked.
-- @return #table The route point.
function COORDINATE:WaypointAir( AltType, Type, Action, Speed, SpeedLocked )
function COORDINATE:RoutePointAir( AltType, Type, Action, Speed, SpeedLocked )
self:F2( { AltType, Type, Action, Speed, SpeedLocked } )
local RoutePoint = {}
RoutePoint.x = self.x
RoutePoint.y = self.z
RoutePoint.alt = self.y
RoutePoint.alt_type = AltType or "RADIO"
RoutePoint.alt_type = AltType
RoutePoint.type = Type or nil
RoutePoint.action = Action or nil
RoutePoint.type = Type
RoutePoint.action = Action
RoutePoint.speed = ( Speed and Speed / 3.6 ) or ( 500 / 3.6 )
RoutePoint.speed = Speed / 3.6
RoutePoint.speed_locked = true
-- ["task"] =
@@ -773,81 +513,12 @@ do -- COORDINATE
return RoutePoint
end
--- Build a Waypoint Air "Turning Point".
-- @param #COORDINATE self
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
-- @return #table The route point.
function COORDINATE:WaypointAirTurningPoint( AltType, Speed )
return self:WaypointAir( AltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed )
end
--- Build a Waypoint Air "Fly Over Point".
-- @param #COORDINATE self
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
-- @return #table The route point.
function COORDINATE:WaypointAirFlyOverPoint( AltType, Speed )
return self:WaypointAir( AltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint, Speed )
end
--- Build a Waypoint Air "Take Off Parking Hot".
-- @param #COORDINATE self
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
-- @return #table The route point.
function COORDINATE:WaypointAirTakeOffParkingHot( AltType, Speed )
return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOffParkingHot, COORDINATE.WaypointAction.FromParkingAreaHot, Speed )
end
--- Build a Waypoint Air "Take Off Parking".
-- @param #COORDINATE self
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
-- @return #table The route point.
function COORDINATE:WaypointAirTakeOffParking( AltType, Speed )
return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOffParking, COORDINATE.WaypointAction.FromParkingArea, Speed )
end
--- Build a Waypoint Air "Take Off Runway".
-- @param #COORDINATE self
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
-- @return #table The route point.
function COORDINATE:WaypointAirTakeOffRunway( AltType, Speed )
return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOff, COORDINATE.WaypointAction.FromRunway, Speed )
end
--- Build a Waypoint Air "Landing".
-- @param #COORDINATE self
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
-- @return #table The route point.
-- @usage
--
-- LandingZone = ZONE:New( "LandingZone" )
-- LandingCoord = LandingZone:GetCoordinate()
-- LandingWaypoint = LandingCoord:WaypointAirLanding( 60 )
-- HeliGroup:Route( { LandWaypoint }, 1 ) -- Start landing the helicopter in one second.
--
function COORDINATE:WaypointAirLanding( Speed )
return self:WaypointAir( nil, COORDINATE.WaypointType.Land, COORDINATE.WaypointAction.Landing, Speed )
end
--- Build an ground type route point.
-- @param #COORDINATE self
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
-- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right".
-- @param Dcs.DCSTypes#Speed Speed Speed in km/h.
-- @param #COORDINATE.RoutePointAction Formation The route point Formation.
-- @return #table The route point.
function COORDINATE:WaypointGround( Speed, Formation )
function COORDINATE:RoutePointGround( Speed, Formation )
self:F2( { Formation, Speed } )
local RoutePoint = {}
@@ -857,7 +528,7 @@ do -- COORDINATE
RoutePoint.action = Formation or ""
RoutePoint.speed = ( Speed or 20 ) / 3.6
RoutePoint.speed = Speed / 3.6
RoutePoint.speed_locked = true
-- ["task"] =
@@ -880,30 +551,6 @@ do -- COORDINATE
return RoutePoint
end
--- Gets the nearest coordinate to a road.
-- @param #COORDINATE self
-- @return #COORDINATE Coordinate of the nearest road.
function COORDINATE:GetClosestPointToRoad()
local x,y = land.getClosestPointOnRoads("roads", self.x, self.z)
local vec2={ x = x, y = y }
return COORDINATE:NewFromVec2(vec2)
end
--- Returns a table of coordinates to a destination.
-- @param #COORDINATE self
-- @param #COORDINATE ToCoord Coordinate of destination.
-- @return #table Table of coordinates on road.
function COORDINATE:GetPathOnRoad(ToCoord)
local Path={}
local path = land.findPathOnRoads("roads", self.x, self.z, ToCoord.x, ToCoord.z)
for i, v in ipairs(path) do
--self:E(v)
local coord=COORDINATE:NewFromVec2(v)
Path[#Path+1]=COORDINATE:NewFromVec2(v)
end
return Path
end
--- Creates an explosion at the point of a certain intensity.
-- @param #COORDINATE self
@@ -1003,88 +650,6 @@ do -- COORDINATE
self:F2( Azimuth )
self:Flare( FLARECOLOR.Red, Azimuth )
end
do -- Markings
--- Mark to All
-- @param #COORDINATE self
-- @param #string MarkText Free format text that shows the marking clarification.
-- @return #number The resulting Mark ID which is a number.
-- @usage
-- local TargetCoord = TargetGroup:GetCoordinate()
-- local MarkID = TargetCoord:MarkToAll( "This is a target for all players" )
function COORDINATE:MarkToAll( MarkText )
local MarkID = UTILS.GetMarkID()
trigger.action.markToAll( MarkID, MarkText, self:GetVec3(), false, "" )
return MarkID
end
--- Mark to Coalition
-- @param #COORDINATE self
-- @param #string MarkText Free format text that shows the marking clarification.
-- @param Coalition
-- @return #number The resulting Mark ID which is a number.
-- @usage
-- local TargetCoord = TargetGroup:GetCoordinate()
-- local MarkID = TargetCoord:MarkToCoalition( "This is a target for the red coalition", coalition.side.RED )
function COORDINATE:MarkToCoalition( MarkText, Coalition )
local MarkID = UTILS.GetMarkID()
trigger.action.markToCoalition( MarkID, MarkText, self:GetVec3(), Coalition, false, "" )
return MarkID
end
--- Mark to Red Coalition
-- @param #COORDINATE self
-- @param #string MarkText Free format text that shows the marking clarification.
-- @return #number The resulting Mark ID which is a number.
-- @usage
-- local TargetCoord = TargetGroup:GetCoordinate()
-- local MarkID = TargetCoord:MarkToCoalitionRed( "This is a target for the red coalition" )
function COORDINATE:MarkToCoalitionRed( MarkText )
return self:MarkToCoalition( MarkText, coalition.side.RED )
end
--- Mark to Blue Coalition
-- @param #COORDINATE self
-- @param #string MarkText Free format text that shows the marking clarification.
-- @return #number The resulting Mark ID which is a number.
-- @usage
-- local TargetCoord = TargetGroup:GetCoordinate()
-- local MarkID = TargetCoord:MarkToCoalitionBlue( "This is a target for the blue coalition" )
function COORDINATE:MarkToCoalitionBlue( MarkText )
return self:MarkToCoalition( MarkText, coalition.side.BLUE )
end
--- Mark to Group
-- @param #COORDINATE self
-- @param #string MarkText Free format text that shows the marking clarification.
-- @param Wrapper.Group#GROUP MarkGroup The @{Group} that receives the mark.
-- @return #number The resulting Mark ID which is a number.
-- @usage
-- local TargetCoord = TargetGroup:GetCoordinate()
-- local MarkGroup = GROUP:FindByName( "AttackGroup" )
-- local MarkID = TargetCoord:MarkToGroup( "This is a target for the attack group", AttackGroup )
function COORDINATE:MarkToGroup( MarkText, MarkGroup )
local MarkID = UTILS.GetMarkID()
trigger.action.markToGroup( MarkID, MarkText, self:GetVec3(), MarkGroup:GetID(), false, "" )
return MarkID
end
--- Remove a mark
-- @param #COORDINATE self
-- @param #number MarkID The ID of the mark to be removed.
-- @usage
-- local TargetCoord = TargetGroup:GetCoordinate()
-- local MarkGroup = GROUP:FindByName( "AttackGroup" )
-- local MarkID = TargetCoord:MarkToGroup( "This is a target for the attack group", AttackGroup )
-- <<< logic >>>
-- RemoveMark( MarkID ) -- The mark is now removed
function COORDINATE:RemoveMark( MarkID )
trigger.action.removeMark( MarkID )
end
end -- Markings
--- Returns if a Coordinate has Line of Sight (LOS) with the ToCoordinate.
-- @param #COORDINATE self
@@ -1105,39 +670,6 @@ do -- COORDINATE
end
--- Returns if a Coordinate is in a certain Radius of this Coordinate in 2D plane using the X and Z axis.
-- @param #COORDINATE self
-- @param #COORDINATE ToCoordinate The coordinate that will be tested if it is in the radius of this coordinate.
-- @param #number Radius The radius of the circle on the 2D plane around this coordinate.
-- @return #boolean true if in the Radius.
function COORDINATE:IsInRadius( Coordinate, Radius )
local InVec2 = self:GetVec2()
local Vec2 = Coordinate:GetVec2()
local InRadius = UTILS.IsInRadius( InVec2, Vec2, Radius)
return InRadius
end
--- Returns if a Coordinate is in a certain radius of this Coordinate in 3D space using the X, Y and Z axis.
-- So Radius defines the radius of the a Sphere in 3D space around this coordinate.
-- @param #COORDINATE self
-- @param #COORDINATE ToCoordinate The coordinate that will be tested if it is in the radius of this coordinate.
-- @param #number Radius The radius of the sphere in the 3D space around this coordinate.
-- @return #boolean true if in the Sphere.
function COORDINATE:IsInSphere( Coordinate, Radius )
local InVec3 = self:GetVec3()
local Vec3 = Coordinate:GetVec3()
local InSphere = UTILS.IsInSphere( InVec3, Vec3, Radius)
return InSphere
end
--- Return a BR string from a COORDINATE to the COORDINATE.
-- @param #COORDINATE self
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
@@ -1161,15 +693,15 @@ do -- COORDINATE
return "BRA, " .. self:GetBRAText( AngleRadians, Distance, Settings )
end
--- Return a BULLS string out of the BULLS of the coalition to the COORDINATE.
--- Return a BULLS string from a COORDINATE to the BULLS of the coalition.
-- @param #COORDINATE self
-- @param Dcs.DCSCoalition#coalition.side Coalition The coalition.
-- @return #string The BR text.
function COORDINATE:ToStringBULLS( Coalition, Settings )
local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) )
local DirectionVec3 = BullsCoordinate:GetDirectionVec3( self )
local TargetCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) )
local DirectionVec3 = self:GetDirectionVec3( TargetCoordinate )
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
local Distance = self:Get2DDistance( BullsCoordinate )
local Distance = self:Get2DDistance( TargetCoordinate )
local Altitude = self:GetAltitudeText()
return "BULLS, " .. self:GetBRText( AngleRadians, Distance, Settings )
end
@@ -1201,26 +733,16 @@ do -- COORDINATE
return ""
end
--- Provides a Lat Lon string in Degree Minute Second format.
--- Provides a Lat Lon string
-- @param #COORDINATE self
-- @param Core.Settings#SETTINGS Settings (optional) Settings
-- @return #string The LL DMS Text
function COORDINATE:ToStringLLDMS( Settings )
-- @return #string The LL Text
function COORDINATE:ToStringLL( Settings ) --R2.1 Fixes issue #424.
local LL_Accuracy = Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy
local LL_DMS = Settings and Settings.LL_DMS or _SETTINGS.LL_DMS
local lat, lon = coord.LOtoLL( self:GetVec3() )
return "LL DMS, " .. UTILS.tostringLL( lat, lon, LL_Accuracy, true )
end
--- Provides a Lat Lon string in Degree Decimal Minute format.
-- @param #COORDINATE self
-- @param Core.Settings#SETTINGS Settings (optional) Settings
-- @return #string The LL DDM Text
function COORDINATE:ToStringLLDDM( Settings )
local LL_Accuracy = Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy
local lat, lon = coord.LOtoLL( self:GetVec3() )
return "LL DDM, " .. UTILS.tostringLL( lat, lon, LL_Accuracy, false )
return "LL, " .. UTILS.tostringLL( lat, lon, LL_Accuracy, LL_DMS )
end
--- Provides a MGRS string
@@ -1244,7 +766,7 @@ do -- COORDINATE
-- @return #string The coordinate Text in the configured coordinate system.
function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings ) -- R2.2
self:F( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } )
self:E( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } )
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
@@ -1266,176 +788,48 @@ do -- COORDINATE
end
--- Provides a coordinate string of the point, based on the A2G coordinate format system.
-- @param #COORDINATE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings
-- @return #string The coordinate Text in the configured coordinate system.
function COORDINATE:ToStringA2G( Controllable, Settings ) -- R2.2
self:F( { Controllable = Controllable and Controllable:GetName() } )
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
if Settings:IsA2G_BR() then
-- If no Controllable is given to calculate the BR from, then MGRS will be used!!!
if Controllable then
local Coordinate = Controllable:GetCoordinate()
return Controllable and self:ToStringBR( Coordinate, Settings ) or self:ToStringMGRS( Settings )
else
return self:ToStringMGRS( Settings )
end
end
if Settings:IsA2G_LL_DMS() then
return self:ToStringLLDMS( Settings )
end
if Settings:IsA2G_LL_DDM() then
return self:ToStringLLDDM( Settings )
end
if Settings:IsA2G_MGRS() then
return self:ToStringMGRS( Settings )
end
return nil
end
--- Provides a coordinate string of the point, based on the A2A coordinate format system.
-- @param #COORDINATE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings
-- @return #string The coordinate Text in the configured coordinate system.
function COORDINATE:ToStringA2A( Controllable, Settings ) -- R2.2
self:F( { Controllable = Controllable and Controllable:GetName() } )
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
if Settings:IsA2A_BRAA() then
if Controllable then
local Coordinate = Controllable:GetCoordinate()
return self:ToStringBRA( Coordinate, Settings )
else
return self:ToStringMGRS( Settings )
end
end
if Settings:IsA2A_BULLS() then
local Coalition = Controllable:GetCoalition()
return self:ToStringBULLS( Coalition, Settings )
end
if Settings:IsA2A_LL_DMS() then
return self:ToStringLLDMS( Settings )
end
if Settings:IsA2A_LL_DDM() then
return self:ToStringLLDDM( Settings )
end
if Settings:IsA2A_MGRS() then
return self:ToStringMGRS( Settings )
end
return nil
end
--- Provides a coordinate string of the point, based on a coordinate format system:
-- * Uses default settings in COORDINATE.
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
-- @param #COORDINATE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings
-- @param Tasking.Task#TASK Task The task for which coordinates need to be calculated.
-- @return #string The coordinate Text in the configured coordinate system.
function COORDINATE:ToString( Controllable, Settings, Task ) -- R2.2
function COORDINATE:ToString( Controllable, Settings ) -- R2.2
self:F( { Controllable = Controllable and Controllable:GetName() } )
self:E( { Controllable = Controllable } )
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
local ModeA2A = false
if Task then
if Task:IsInstanceOf( TASK_A2A ) then
ModeA2A = true
else
if Task:IsInstanceOf( TASK_A2G ) then
ModeA2A = false
else
if Task:IsInstanceOf( TASK_CARGO ) then
ModeA2A = false
else
ModeA2A = false
end
end
local IsAir = Controllable and Controllable:IsAirPlane() or false
if IsAir then
if Settings:IsA2A_BRAA() then
local Coordinate = Controllable:GetCoordinate()
return self:ToStringBRA( Coordinate, Settings )
end
if Settings:IsA2A_BULLS() then
local Coalition = Controllable:GetCoalition()
return self:ToStringBULLS( Coalition, Settings )
end
else
local IsAir = Controllable and Controllable:IsAirPlane() or false
if IsAir then
ModeA2A = true
else
ModeA2A = false
if Settings:IsA2G_BR() then
local Coordinate = Controllable:GetCoordinate()
return Controllable and self:ToStringBR( Coordinate, Settings ) or self:ToStringMGRS( Settings )
end
if Settings:IsA2G_LL() then
return self:ToStringLL( Settings )
end
if Settings:IsA2G_MGRS() then
return self:ToStringMGRS( Settings )
end
end
if ModeA2A == true then
return self:ToStringA2A( Controllable, Settings )
else
return self:ToStringA2G( Controllable, Settings )
end
return nil
end
--- Provides a pressure string of the point, based on a measurement system:
-- * Uses default settings in COORDINATE.
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
-- @param #COORDINATE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings
-- @return #string The pressure text in the configured measurement system.
function COORDINATE:ToStringPressure( Controllable, Settings ) -- R2.3
self:F( { Controllable = Controllable and Controllable:GetName() } )
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
return self:GetPressureText( nil, Settings )
end
--- Provides a wind string of the point, based on a measurement system:
-- * Uses default settings in COORDINATE.
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
-- @param #COORDINATE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings
-- @return #string The wind text in the configured measurement system.
function COORDINATE:ToStringWind( Controllable, Settings ) -- R2.3
self:F( { Controllable = Controllable and Controllable:GetName() } )
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
return self:GetWindText( nil, Settings )
end
--- Provides a temperature string of the point, based on a measurement system:
-- * Uses default settings in COORDINATE.
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
-- @param #COORDINATE self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings
-- @return #string The temperature text in the configured measurement system.
function COORDINATE:ToStringTemperature( Controllable, Settings ) -- R2.3
self:F( { Controllable = Controllable and Controllable:GetName() } )
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
return self:GetTemperatureText( nil, Settings )
end
end
do -- POINT_VEC3

View File

@@ -1,86 +0,0 @@
--- The REPORT class
-- @type REPORT
-- @extends Core.Base#BASE
REPORT = {
ClassName = "REPORT",
Title = "",
}
--- Create a new REPORT.
-- @param #REPORT self
-- @param #string Title
-- @return #REPORT
function REPORT:New( Title )
local self = BASE:Inherit( self, BASE:New() ) -- #REPORT
self.Report = {}
self:SetTitle( Title or "" )
self:SetIndent( 3 )
return self
end
--- Has the REPORT Text?
-- @param #REPORT self
-- @return #boolean
function REPORT:HasText() --R2.1
return #self.Report > 0
end
--- Set indent of a REPORT.
-- @param #REPORT self
-- @param #number Indent
-- @return #REPORT
function REPORT:SetIndent( Indent ) --R2.1
self.Indent = Indent
return self
end
--- Add a new line to a REPORT.
-- @param #REPORT self
-- @param #string Text
-- @return #REPORT
function REPORT:Add( Text )
self.Report[#self.Report+1] = Text
return self
end
--- Add a new line to a REPORT.
-- @param #REPORT self
-- @param #string Text
-- @return #REPORT
function REPORT:AddIndent( Text, Separator ) --R2.1
self.Report[#self.Report+1] = ( ( Separator and Separator .. string.rep( " ", self.Indent - 1 ) ) or string.rep(" ", self.Indent ) ) .. Text:gsub("\n","\n"..string.rep( " ", self.Indent ) )
return self
end
--- Produces the text of the report, taking into account an optional delimeter, which is \n by default.
-- @param #REPORT self
-- @param #string Delimiter (optional) A delimiter text.
-- @return #string The report text.
function REPORT:Text( Delimiter )
Delimiter = Delimiter or "\n"
local ReportText = ( self.Title ~= "" and self.Title .. Delimiter or self.Title ) .. table.concat( self.Report, Delimiter ) or ""
return ReportText
end
--- Sets the title of the report.
-- @param #REPORT self
-- @param #string Title The title of the report.
-- @return #REPORT
function REPORT:SetTitle( Title )
self.Title = Title
return self
end
--- Gets the amount of report items contained in the report.
-- @param #REPORT self
-- @return #number Returns the number of report items contained in the report. 0 is returned if no report items are contained in the report. The title is not counted for.
function REPORT:GetCount()
return #self.Report
end

View File

@@ -55,7 +55,6 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } )
self.CallID = self.CallID + 1
local CallID = self.CallID .. "#" .. ( Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "" ) or ""
-- Initialize the ObjectSchedulers array, which is a weakly coupled table.
-- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array.
@@ -66,33 +65,33 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } )
if Scheduler.MasterObject then
self.ObjectSchedulers[CallID] = Scheduler
self:F3( { CallID = CallID, ObjectScheduler = tostring(self.ObjectSchedulers[CallID]), MasterObject = tostring(Scheduler.MasterObject) } )
self.ObjectSchedulers[self.CallID] = Scheduler
self:F3( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), MasterObject = tostring(Scheduler.MasterObject) } )
else
self.PersistentSchedulers[CallID] = Scheduler
self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } )
self.PersistentSchedulers[self.CallID] = Scheduler
self:F3( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } )
end
self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } )
self.Schedule[Scheduler] = self.Schedule[Scheduler] or {}
self.Schedule[Scheduler][CallID] = {}
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + ( Start or 0 )
self.Schedule[Scheduler][CallID].Start = Start + .1
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
self.Schedule[Scheduler][CallID].Stop = Stop
self.Schedule[Scheduler][self.CallID] = {}
self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction
self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments
self.Schedule[Scheduler][self.CallID].StartTime = timer.getTime() + ( Start or 0 )
self.Schedule[Scheduler][self.CallID].Start = Start + .1
self.Schedule[Scheduler][self.CallID].Repeat = Repeat
self.Schedule[Scheduler][self.CallID].Randomize = Randomize
self.Schedule[Scheduler][self.CallID].Stop = Stop
self:T3( self.Schedule[Scheduler][CallID] )
self:T3( self.Schedule[Scheduler][self.CallID] )
self.Schedule[Scheduler][CallID].CallHandler = function( CallID )
--self:E( CallID )
self.Schedule[Scheduler][self.CallID].CallHandler = function( CallID )
self:F2( CallID )
local ErrorHandler = function( errmsg )
env.info( "Error in timer function: " .. errmsg )
if BASE.Debug ~= nil then
env.info( BASE.Debug.traceback() )
if debug ~= nil then
env.info( debug.traceback() )
end
return errmsg
end
@@ -101,17 +100,16 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
if not Scheduler then
Scheduler = self.PersistentSchedulers[CallID]
end
--self:T3( { Scheduler = Scheduler } )
if Scheduler then
local MasterObject = tostring(Scheduler.MasterObject)
local Schedule = self.Schedule[Scheduler][CallID]
--self:T3( { Schedule = Schedule } )
local SchedulerObject = Scheduler.SchedulerObject
local ScheduleObject = Scheduler.SchedulerObject
--local ScheduleObjectName = Scheduler.SchedulerObject:GetNameAndClassID()
local ScheduleFunction = Schedule.Function
local ScheduleArguments = Schedule.Arguments
@@ -122,10 +120,9 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
local ScheduleID = Schedule.ScheduleID
local Status, Result
--self:E( { SchedulerObject = SchedulerObject } )
if SchedulerObject then
if ScheduleObject then
local function Timer()
return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) )
return ScheduleFunction( ScheduleObject, unpack( ScheduleArguments ) )
end
Status, Result = xpcall( Timer, ErrorHandler )
else
@@ -136,13 +133,10 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
end
local CurrentTime = timer.getTime()
local StartTime = Schedule.StartTime
self:F3( { Master = MasterObject, CurrentTime = CurrentTime, StartTime = StartTime, Start = Start, Repeat = Repeat, Randomize = Randomize, Stop = Stop } )
local StartTime = CurrentTime + Start
if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then
if Repeat ~= 0 and ( ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) ) then
if Repeat ~= 0 and ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) then
local ScheduleTime =
CurrentTime +
Repeat +
@@ -166,9 +160,9 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
return nil
end
self:Start( Scheduler, CallID )
self:Start( Scheduler, self.CallID )
return CallID
return self.CallID
end
function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID )
@@ -188,11 +182,10 @@ function SCHEDULEDISPATCHER:Start( Scheduler, CallID )
-- Only start when there is no ScheduleID defined!
-- This prevents to "Start" the scheduler twice with the same CallID...
if not Schedule[CallID].ScheduleID then
Schedule[CallID].StartTime = timer.getTime() -- Set the StartTime field to indicate when the scheduler started.
Schedule[CallID].ScheduleID = timer.scheduleFunction(
Schedule[CallID].CallHandler,
CallID,
timer.getTime() + Schedule[CallID].Start
timer.getTime() + Schedule[CallID].Start
)
end
else

View File

@@ -21,13 +21,13 @@
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ===
-- ====
--
-- # YouTube Channel
--
-- ### [SCHEDULER YouTube Channel (none)]()
--
-- ===
-- ====
--
-- ### Contributions:
--
@@ -210,8 +210,7 @@ SCHEDULER = {
-- @return #SCHEDULER self.
-- @return #number The ScheduleID of the planned schedule.
function SCHEDULER:New( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
local self = BASE:Inherit( self, BASE:New() ) -- #SCHEDULER
local self = BASE:Inherit( self, BASE:New() )
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
local ScheduleID = nil

File diff suppressed because it is too large Load Diff

View File

@@ -1,199 +1,46 @@
--- **Core** -- Manages various settings for MOOSE classes.
--- **Core** -- **SETTINGS** classe defines the format settings management for measurement.
--
-- ![Banner Image](..\Presentations\SETTINGS\Dia1.JPG)
--
-- ====
--
-- # Demo Missions
--
-- ### [SETTINGS Demo Missions source code]()
--
-- ### [SETTINGS Demo Missions, only for beta testers]()
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [SETTINGS YouTube Channel]()
--
-- ===
--
-- The documentation of the SETTINGS class can be found further in this document.
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
-- ====
--
-- @module Settings
--- @type SETTINGS
-- @field #number LL_Accuracy
-- @field #boolean LL_DMS
-- @field #number MGRS_Accuracy
-- @field #string A2GSystem
-- @field #string A2ASystem
-- @extends Core.Base#BASE
--- # SETTINGS class, extends @{Base#BASE}
-- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
--
-- ===
--
-- ![Banner Image](..\Presentations\SETTINGS\Dia1.JPG)
--
-- ===
--
-- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
-- SETTINGS can work on 2 levels:
--
-- - **Default settings**: A running mission has **Default settings**.
-- - **Player settings**: For each player its own **Player settings** can be defined, overriding the **Default settings**.
--
-- So, when there isn't any **Player setting** defined for a player for a specific setting, or, the player cannot be identified, the **Default setting** will be used instead.
--
-- ## 1. \_SETTINGS object
--
-- MOOSE defines by default a singleton object called **\_SETTINGS**. Use this object to modify all the **Default settings** for a running mission.
-- For each player, MOOSE will automatically allocate also a **player settings** object, and will expose a radio menu to allow the player to adapt the settings to his own preferences.
--
-- ## 2. SETTINGS Menu
--
-- Settings can be adapted by the Players and by the Mission Administrator through **radio menus, which are automatically available in the mission**.
-- These menus can be found **on level F10 under "Settings"**. There are two kinds of menus generated by the system.
--
-- ### 2.1. Default settings menu
--
-- A menu is created automatically per Command Center that allows to modify the **Default** settings.
-- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**!
-- Note that the **Default settings** will only be used when a player has not choosen its own settings.
--
-- ### 2.2. Player settings menu
--
-- A menu is created automatically per Player Slot (group) that allows to modify the **Player** settings.
-- So, when joining a slot, a menu wil be available that allows to change the settings parameters **FOR THE PLAYER ONLY**!
-- Note that when a player has not chosen a specific setting, the **Default settings** will be used.
--
-- ### 2.3. Show or Hide the Player Setting menus
--
-- Of course, it may be requried not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**.
-- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus.
-- Note that when this method is used, any player already in a slot will not have its menus visibility changed.
-- The option will only have effect when a player enters a new slot or changes a slot.
--
-- Example:
--
-- _SETTINGS:SetPlayerMenuOff() -- will disable the player menus.
-- _SETTINGS:SetPlayerMenuOn() -- will enable the player menus.
-- -- But only when a player exits and reenters the slot these settings will have effect!
--
--
-- ## 3. Settings
--
-- There are different settings that are managed and applied within the MOOSE framework.
-- See below a comprehensive description of each.
--
-- ### 3.1. **A2G coordinates** display formatting
--
-- #### 3.1.1. A2G coordinates setting **types**
--
-- Will customize which display format is used to indicate A2G coordinates in text as part of the Command Center communications.
--
-- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_(navigation)).
-- - A2G MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
-- - A2G LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
-- - A2G LL DDM: Lattitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
--
-- #### 3.1.2. A2G coordinates setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- #### 3.1.3. A2G coordinates setting **methods**
--
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
--
-- - @{#SETTINGS.SetA2G_BR}(): Enable the BR display formatting by default.
-- - @{#SETTINGS.SetA2G_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
-- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
-- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
--
-- #### 3.1.4. A2G coordinates setting - additional notes
--
-- One additional note on BR. In a situation when a BR coordinate should be given,
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
--
-- ### 3.2. **A2A coordinates** formatting
--
-- #### 3.2.1. A2A coordinates setting **types**
--
-- Will customize which display format is used to indicate A2A coordinates in text as part of the Command Center communications.
--
-- - A2A BRAA: [Bearing Range Altitude Aspect](https://en.wikipedia.org/wiki/Bearing_(navigation)).
-- - A2A MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
-- - A2A LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
-- - A2A LL DDM: Lattitude Longitude [Decimal Degrees and Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
-- - A2A BULLS: [Bullseye](http://falcon4.wikidot.com/concepts:bullseye).
--
-- #### 3.2.2. A2A coordinates setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- #### 3.2.3. A2A coordinates setting **methods**
--
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
--
-- - @{#SETTINGS.SetA2A_BRAA}(): Enable the BR display formatting by default.
-- - @{#SETTINGS.SetA2A_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
-- - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
-- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
-- - @{#SETTINGS.SetA2A_BULLS}(): Enable the BULLSeye display formatting by default.
--
-- #### 3.2.4. A2A coordinates settings - additional notes
--
-- One additional note on BRAA. In a situation when a BRAA coordinate should be given,
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
--
-- ### 3.3. **Measurements** formatting
--
-- #### 3.3.1. Measurements setting **types**
--
-- Will customize the measurements system being used as part as part of the Command Center communications.
--
-- - **Metrics** system: Applies the [Metrics system](https://en.wikipedia.org/wiki/Metric_system) ...
-- - **Imperial** system: Applies the [Imperial system](https://en.wikipedia.org/wiki/Imperial_units) ...
--
-- #### 3.3.2. Measurements setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- #### 3.3.3. Measurements setting **methods**
--
-- There are different methods that can be used to change the **Default settings** using the \_SETTINGS object.
--
-- - @{#SETTINGS.SetMetric}(): Enable the Metric system.
-- - @{#SETTINGS.SetImperial}(): Enable the Imperial system.
--
-- ### 3.4. **Message** display times
--
-- #### 3.4.1. Message setting **types**
--
-- There are various **Message Types** that will influence the duration how long a message will appear as part of the Command Center communications.
--
-- - **Update** message: A short update message.
-- - **Information** message: Provides new information **while** executing a mission.
-- - **Briefing** message: Provides a complete briefing **before** executing a mission.
-- - **Overview report**: Provides a short report overview, the summary of the report.
-- - **Detailed report**: Provides a complete report.
--
-- #### 3.4.2. Message setting **menu**
--
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
--
-- Each Message Type has specific timings that will be applied when the message is displayed.
-- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be choosen.
-- So the player can choose its own amount of seconds how long a message should be displayed of a certain type.
-- Note that **Update** messages can be chosen not to be displayed at all!
--
-- #### 3.4.3. Message setting **methods**
--
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
--
-- - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
-- - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
--
-- ===
--
-- @field #SETTINGS
SETTINGS = {
ClassName = "SETTINGS",
ShowPlayerMenu = true,
}
@@ -210,13 +57,9 @@ do -- SETTINGS
self:SetMetric() -- Defaults
self:SetA2G_BR() -- Defaults
self:SetA2A_BRAA() -- Defaults
self:SetLL_Accuracy( 3 ) -- Defaults
self:SetLL_Accuracy( 2 ) -- Defaults
self:SetLL_DMS( true ) -- Defaults
self:SetMGRS_Accuracy( 5 ) -- Defaults
self:SetMessageTime( MESSAGE.Type.Briefing, 180 )
self:SetMessageTime( MESSAGE.Type.Detailed, 60 )
self:SetMessageTime( MESSAGE.Type.Information, 30 )
self:SetMessageTime( MESSAGE.Type.Overview, 60 )
self:SetMessageTime( MESSAGE.Type.Update, 15 )
return self
else
local Settings = _DATABASE:GetPlayerSettings( PlayerName )
@@ -239,6 +82,7 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if metric.
function SETTINGS:IsMetric()
self:E( {Metric = ( self.Metric ~= nil and self.Metric == true ) or ( self.Metric == nil and _SETTINGS:IsMetric() ) } )
return ( self.Metric ~= nil and self.Metric == true ) or ( self.Metric == nil and _SETTINGS:IsMetric() )
end
@@ -252,6 +96,7 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if imperial.
function SETTINGS:IsImperial()
self:E( {Metric = ( self.Metric ~= nil and self.Metric == false ) or ( self.Metric == nil and _SETTINGS:IsMetric() ) } )
return ( self.Metric ~= nil and self.Metric == false ) or ( self.Metric == nil and _SETTINGS:IsMetric() )
end
@@ -266,10 +111,25 @@ do -- SETTINGS
--- Gets the SETTINGS LL accuracy.
-- @param #SETTINGS self
-- @return #number
function SETTINGS:GetLL_DDM_Accuracy()
return self.LL_DDM_Accuracy or _SETTINGS:GetLL_DDM_Accuracy()
function SETTINGS:GetLL_Accuracy()
return self.LL_Accuracy or _SETTINGS:GetLL_Accuracy()
end
--- Sets the SETTINGS LL DMS.
-- @param #SETTINGS self
-- @param #number LL_DMS
-- @return #SETTINGS
function SETTINGS:SetLL_DMS( LL_DMS )
self.LL_DMS = LL_DMS
end
--- Gets the SETTINGS LL DMS.
-- @param #SETTINGS self
-- @return #number
function SETTINGS:GetLL_DMS()
return self.LL_DMS or _SETTINGS:GetLL_DMS()
end
--- Sets the SETTINGS MGRS accuracy.
-- @param #SETTINGS self
-- @param #number MGRS_Accuracy
@@ -285,50 +145,21 @@ do -- SETTINGS
return self.MGRS_Accuracy or _SETTINGS:GetMGRS_Accuracy()
end
--- Sets the SETTINGS Message Display Timing of a MessageType
-- @param #SETTINGS self
-- @param Core.Message#MESSAGE MessageType The type of the message.
-- @param #number MessageTime The display time duration in seconds of the MessageType.
function SETTINGS:SetMessageTime( MessageType, MessageTime )
self.MessageTypeTimings = self.MessageTypeTimings or {}
self.MessageTypeTimings[MessageType] = MessageTime
end
--- Gets the SETTINGS Message Display Timing of a MessageType
-- @param #SETTINGS self
-- @param Core.Message#MESSAGE MessageType The type of the message.
-- @return #number
function SETTINGS:GetMessageTime( MessageType )
return ( self.MessageTypeTimings and self.MessageTypeTimings[MessageType] ) or _SETTINGS:GetMessageTime( MessageType )
end
--- Sets A2G LL DMS
--- Sets A2G LL
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2G_LL_DMS()
self.A2GSystem = "LL DMS"
function SETTINGS:SetA2G_LL()
self.A2GSystem = "LL"
end
--- Sets A2G LL DDM
--- Is LL
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2G_LL_DDM()
self.A2GSystem = "LL DDM"
end
--- Is LL DMS
-- @param #SETTINGS self
-- @return #boolean true if LL DMS
function SETTINGS:IsA2G_LL_DMS()
return ( self.A2GSystem and self.A2GSystem == "LL DMS" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS() )
end
--- Is LL DDM
-- @param #SETTINGS self
-- @return #boolean true if LL DDM
function SETTINGS:IsA2G_LL_DDM()
return ( self.A2GSystem and self.A2GSystem == "LL DDM" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM() )
-- @return #boolean true if LL
function SETTINGS:IsA2G_LL()
return ( self.A2GSystem and self.A2GSystem == "LL" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL() )
end
--- Sets A2G MGRS
@@ -356,6 +187,7 @@ do -- SETTINGS
-- @param #SETTINGS self
-- @return #boolean true if BRA
function SETTINGS:IsA2G_BR()
self:E( { BRA = ( self.A2GSystem and self.A2GSystem == "BR" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BR() ) } )
return ( self.A2GSystem and self.A2GSystem == "BR" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BR() )
end
@@ -388,48 +220,6 @@ do -- SETTINGS
return ( self.A2ASystem and self.A2ASystem == "BULLS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BULLS() )
end
--- Sets A2A LL DMS
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2A_LL_DMS()
self.A2ASystem = "LL DMS"
end
--- Sets A2A LL DDM
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2A_LL_DDM()
self.A2ASystem = "LL DDM"
end
--- Is LL DMS
-- @param #SETTINGS self
-- @return #boolean true if LL DMS
function SETTINGS:IsA2A_LL_DMS()
return ( self.A2ASystem and self.A2ASystem == "LL DMS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS() )
end
--- Is LL DDM
-- @param #SETTINGS self
-- @return #boolean true if LL DDM
function SETTINGS:IsA2A_LL_DDM()
return ( self.A2ASystem and self.A2ASystem == "LL DDM" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM() )
end
--- Sets A2A MGRS
-- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetA2A_MGRS()
self.A2ASystem = "MGRS"
end
--- Is MGRS
-- @param #SETTINGS self
-- @return #boolean true if MGRS
function SETTINGS:IsA2A_MGRS()
return ( self.A2ASystem and self.A2ASystem == "MGRS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_MGRS() )
end
--- @param #SETTINGS self
-- @return #SETTINGS
function SETTINGS:SetSystemMenu( MenuGroup, RootMenu )
@@ -442,73 +232,41 @@ do -- SETTINGS
local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, "A2G Coordinate System", SettingsMenu ):SetTime( MenuTime )
if not self:IsA2G_LL_DMS() then
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
end
if not self:IsA2G_LL_DDM() then
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
end
if self:IsA2G_LL_DDM() then
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
end
if not self:IsA2G_BR() then
if self:IsA2G_LL() then
MENU_GROUP_COMMAND:New( MenuGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
end
if not self:IsA2G_MGRS() then
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL) Accuracy 1", A2GCoordinateMenu, self.MenuLL_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL) Accuracy 2", A2GCoordinateMenu, self.MenuLL_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL) Accuracy 3", A2GCoordinateMenu, self.MenuLL_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL) Decimal On", A2GCoordinateMenu, self.MenuLL_DMS, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL) Decimal Off", A2GCoordinateMenu, self.MenuLL_DMS, self, MenuGroup, RootMenu, false ):SetTime( MenuTime )
end
if self:IsA2G_MGRS() then
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 2", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL" ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS) Accuracy 1", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS) Accuracy 2", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS) Accuracy 3", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS) Accuracy 4", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS) Accuracy 5", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
end
if self:IsA2G_BR() then
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Lattitude Longitude (LL)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL" ):SetTime( MenuTime )
end
local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, "A2A Coordinate System", SettingsMenu ):SetTime( MenuTime )
if not self:IsA2A_LL_DMS() then
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
if self:IsA2A_BULLS() then
MENU_GROUP_COMMAND:New( MenuGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime )
end
if not self:IsA2A_LL_DDM() then
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
end
if self:IsA2A_LL_DDM() then
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 3", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
end
if not self:IsA2A_BULLS() then
if self:IsA2A_BRAA() then
MENU_GROUP_COMMAND:New( MenuGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime )
end
if not self:IsA2A_BRAA() then
MENU_GROUP_COMMAND:New( MenuGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime )
end
if not self:IsA2A_MGRS() then
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
end
if self:IsA2A_MGRS() then
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 1", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 2", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 3", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
end
local MetricsMenu = MENU_GROUP:New( MenuGroup, "Measures and Weights System", SettingsMenu ):SetTime( MenuTime )
if self:IsMetric() then
@@ -518,225 +276,85 @@ do -- SETTINGS
if self:IsImperial() then
MENU_GROUP_COMMAND:New( MenuGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
end
local MessagesMenu = MENU_GROUP:New( MenuGroup, "Messages and Reports", SettingsMenu ):SetTime( MenuTime )
local UpdateMessagesMenu = MENU_GROUP:New( MenuGroup, "Update Messages", MessagesMenu ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "Off", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 0 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "5 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 5 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "10 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 10 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 15 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 30 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 60 ):SetTime( MenuTime )
local InformationMessagesMenu = MENU_GROUP:New( MenuGroup, "Information Messages", MessagesMenu ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "5 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 5 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "10 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 10 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 15 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 30 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 60 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 120 ):SetTime( MenuTime )
local BriefingReportsMenu = MENU_GROUP:New( MenuGroup, "Briefing Reports", MessagesMenu ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 15 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 30 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 60 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 120 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 180 ):SetTime( MenuTime )
local OverviewReportsMenu = MENU_GROUP:New( MenuGroup, "Overview Reports", MessagesMenu ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 15 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 30 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 60 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 120 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 180 ):SetTime( MenuTime )
local DetailedReportsMenu = MENU_GROUP:New( MenuGroup, "Detailed Reports", MessagesMenu ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 15 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 30 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 60 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 120 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 180 ):SetTime( MenuTime )
SettingsMenu:Remove( MenuTime )
return self
end
--- Sets the player menus on, so that the **Player setting menus** show up for the players.
-- But only when a player exits and reenters the slot these settings will have effect!
-- It is advised to use this method at the start of the mission.
-- @param #SETTINGS self
-- @return #SETTINGS
-- @usage
-- _SETTINGS:SetPlayerMenuOn() -- will enable the player menus.
function SETTINGS:SetPlayerMenuOn()
self.ShowPlayerMenu = true
end
--- Sets the player menus off, so that the **Player setting menus** won't show up for the players.
-- But only when a player exits and reenters the slot these settings will have effect!
-- It is advised to use this method at the start of the mission.
-- @param #SETTINGS self
-- @return #SETTINGS self
-- @usage
-- _SETTINGS:SetPlayerMenuOff() -- will disable the player menus.
function SETTINGS:SetPlayerMenuOff()
self.ShowPlayerMenu = false
end
--- Updates the menu of the player seated in the PlayerUnit.
-- @param #SETTINGS self
--- @param #SETTINGS self
-- @param RootMenu
-- @param Wrapper.Client#CLIENT PlayerUnit
-- @return #SETTINGS self
-- @param #string MenuText
-- @return #SETTINGS
function SETTINGS:SetPlayerMenu( PlayerUnit )
if _SETTINGS.ShowPlayerMenu == true then
local PlayerGroup = PlayerUnit:GetGroup()
local PlayerName = PlayerUnit:GetPlayerName()
local PlayerNames = PlayerGroup:GetPlayerNames()
local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' )
local PlayerGroup = PlayerUnit:GetGroup()
local PlayerName = PlayerUnit:GetPlayerName()
local PlayerNames = PlayerGroup:GetPlayerNames()
self.PlayerMenu = PlayerMenu
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2G Coordinate System", PlayerMenu )
local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' )
self.PlayerMenu = PlayerMenu
if self:IsA2G_LL() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL) Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL) Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL) Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL) Decimal On", A2GCoordinateMenu, self.MenuGroupLL_DMSSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL) Decimal Off", A2GCoordinateMenu, self.MenuGroupLL_DMSSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
end
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2G Coordinate System", PlayerMenu )
if self:IsA2G_MGRS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing Range (BR)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL" )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 1", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 2", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 3", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 4", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 5", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
end
if self:IsA2G_BR() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
MENU_GROUP_COMMAND:New( PlayerGroup, "Lattitude Longitude (LL)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL" )
end
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2A Coordinate System", PlayerMenu )
if self:IsA2A_BULLS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
end
if self:IsA2A_BRAA() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
end
local MetricsMenu = MENU_GROUP:New( PlayerGroup, "Measures and Weights System", PlayerMenu )
if not self:IsA2G_LL_DMS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
end
if self:IsMetric() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Imperial (Miles,Feet)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
end
if not self:IsA2G_LL_DDM() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
end
if self:IsA2G_LL_DDM() then
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
end
if not self:IsA2G_BR() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
end
if not self:IsA2G_MGRS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
end
if self:IsA2G_MGRS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 2", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
end
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2A Coordinate System", PlayerMenu )
if not self:IsA2A_LL_DMS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
end
if not self:IsA2A_LL_DDM() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
end
if self:IsA2A_LL_DDM() then
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
end
if not self:IsA2A_BULLS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
end
if not self:IsA2A_BRAA() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
end
if not self:IsA2A_MGRS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
end
if self:IsA2A_MGRS() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 1", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 2", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 3", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 4", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 5", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
end
local MetricsMenu = MENU_GROUP:New( PlayerGroup, "Measures and Weights System", PlayerMenu )
if self:IsMetric() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Imperial (Miles,Feet)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
end
if self:IsImperial() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
end
local MessagesMenu = MENU_GROUP:New( PlayerGroup, "Messages and Reports", PlayerMenu )
local UpdateMessagesMenu = MENU_GROUP:New( PlayerGroup, "Update Messages", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "Off", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 0 )
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 5 )
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 10 )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 60 )
local InformationMessagesMenu = MENU_GROUP:New( PlayerGroup, "Information Messages", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 5 )
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 10 )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 120 )
local BriefingReportsMenu = MENU_GROUP:New( PlayerGroup, "Briefing Reports", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 120 )
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 180 )
local OverviewReportsMenu = MENU_GROUP:New( PlayerGroup, "Overview Reports", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 120 )
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 180 )
local DetailedReportsMenu = MENU_GROUP:New( PlayerGroup, "Detailed Reports", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 120 )
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 180 )
end
if self:IsImperial() then
MENU_GROUP_COMMAND:New( PlayerGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
end
return self
end
--- Removes the player menu from the PlayerUnit.
--- @param #SETTINGS self
-- @param RootMenu
-- @param Wrapper.Client#CLIENT PlayerUnit
-- @return #SETTINGS self
-- @return #SETTINGS
function SETTINGS:RemovePlayerMenu( PlayerUnit )
if self.PlayerMenu then
self.PlayerMenu:Remove()
self.PlayerMenu = nil
end
return self
@@ -746,50 +364,51 @@ do -- SETTINGS
--- @param #SETTINGS self
function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem )
self.A2GSystem = A2GSystem
MESSAGE:New( string.format("Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
MESSAGE:New( string.format("Settings: Default A2G coordinate system set to %s for all players!.", A2GSystem ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem )
self.A2ASystem = A2ASystem
MESSAGE:New( string.format("Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
MESSAGE:New( string.format("Settings: Default A2A coordinate system set to %s for all players!.", A2ASystem ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuLL_DDM_Accuracy( MenuGroup, RootMenu, LL_Accuracy )
function SETTINGS:MenuLL_Accuracy( MenuGroup, RootMenu, LL_Accuracy )
self.LL_Accuracy = LL_Accuracy
MESSAGE:New( string.format("Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll()
MESSAGE:New( string.format("Settings: Default LL accuracy set to %s for all players!.", LL_Accuracy ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuLL_DMS( MenuGroup, RootMenu, LL_DMS )
self.LL_DMS = LL_DMS
MESSAGE:New( string.format("Settings: Default LL format set to %s for all players!.", LL_DMS or "Decimal" or "HMS" ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy
MESSAGE:New( string.format("Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll()
MESSAGE:New( string.format("Settings: Default MGRS accuracy set to %s for all players!.", MGRS_Accuracy ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuMWSystem( MenuGroup, RootMenu, MW )
self.Metric = MW
MESSAGE:New( string.format("Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll()
MESSAGE:New( string.format("Settings: Default measurement format set to %s for all players!.", MW and "Metric" or "Imperial" ), 5 ):ToAll()
self:SetSystemMenu( MenuGroup, RootMenu )
end
--- @param #SETTINGS self
function SETTINGS:MenuMessageTimingsSystem( MenuGroup, RootMenu, MessageType, MessageTime )
self:SetMessageTime( MessageType, MessageTime )
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToAll()
end
do
--- @param #SETTINGS self
function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem )
BASE:E( {self, PlayerUnit:GetName(), A2GSystem} )
self.A2GSystem = A2GSystem
MESSAGE:New( string.format( "Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
MESSAGE:New( string.format("Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
@@ -797,23 +416,31 @@ do -- SETTINGS
--- @param #SETTINGS self
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
self.A2ASystem = A2ASystem
MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
MESSAGE:New( string.format("Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
--- @param #SETTINGS self
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
function SETTINGS:MenuGroupLL_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
self.LL_Accuracy = LL_Accuracy
MESSAGE:New( string.format( "Settings: A2G LL format accuracy set to %d for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
MESSAGE:New( string.format("Settings: A2G LL format accuracy set to %d for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
--- @param #SETTINGS self
function SETTINGS:MenuGroupLL_DMSSystem( PlayerUnit, PlayerGroup, PlayerName, LL_DMS )
self.LL_DMS = LL_DMS
MESSAGE:New( string.format("Settings: A2G LL format mode set to %s for player %s.", LL_DMS and "Decimal" or "HMS", PlayerName ), 5 ):ToGroup( PlayerGroup )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
--- @param #SETTINGS self
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy
MESSAGE:New( string.format( "Settings: A2G MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
MESSAGE:New( string.format("Settings: A2G MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
@@ -821,16 +448,10 @@ do -- SETTINGS
--- @param #SETTINGS self
function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, MW )
self.Metric = MW
MESSAGE:New( string.format( "Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
MESSAGE:New( string.format("Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
self:RemovePlayerMenu(PlayerUnit)
self:SetPlayerMenu(PlayerUnit)
end
--- @param #SETTINGS self
function SETTINGS:MenuGroupMessageTimingsSystem( PlayerUnit, PlayerGroup, PlayerName, MessageType, MessageTime )
self:SetMessageTime( MessageType, MessageTime )
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToGroup( PlayerGroup )
end
end

View File

@@ -2,11 +2,11 @@
--
-- ![Banner Image](..\Presentations\SPAWNSTATIC\Dia1.JPG)
--
-- ===
-- ====
--
-- SPAWNSTATIC spawns static structures in your missions dynamically. See below the SPAWNSTATIC class documentation.
--
-- ===
-- ====
--
-- # Demo Missions
--
@@ -16,18 +16,18 @@
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ===
-- ====
--
-- # YouTube Channel
--
-- ### [SPAWNSTATIC YouTube Channel]()
--
-- ===
-- ====
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ===
-- ====
--
-- @module SpawnStatic
@@ -116,33 +116,6 @@ function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory,
return self
end
--- Creates a new @{Static} at the original position.
-- @param #SPAWNSTATIC self
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
-- @param #string (optional) The name of the new static.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:Spawn( Heading, NewName ) --R2.3
self:F( { Heading, NewName } )
local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID]
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
StaticTemplate.heading = ( Heading / 180 ) * math.pi
StaticTemplate.CountryID = nil
StaticTemplate.CoalitionID = nil
StaticTemplate.CategoryID = nil
local Static = coalition.addStaticObject( self.CountryID, StaticTemplate )
self.SpawnIndex = self.SpawnIndex + 1
return Static
end
--- Creates a new @{Static} from a POINT_VEC2.
-- @param #SPAWNSTATIC self
@@ -157,13 +130,8 @@ function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) --R2.1
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
StaticTemplate.x = PointVec2.x
StaticTemplate.y = PointVec2.z
StaticTemplate.units = nil
StaticTemplate.route = nil
StaticTemplate.groupId = nil
StaticTemplate.x = PointVec2:GetLat()
StaticTemplate.y = PointVec2:GetLon()
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
StaticTemplate.heading = ( Heading / 180 ) * math.pi

View File

@@ -2,7 +2,7 @@
--
-- ![Banner Image](..\Presentations\SPOT\Dia1.JPG)
--
-- ===
-- ====
--
-- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to:
--
@@ -11,7 +11,7 @@
-- * Provide a @{Unit} as a target, instead of a point.
-- * Implement a status machine, LaseOn, LaseOff.
--
-- ===
-- ====
--
-- # Demo Missions
--
@@ -21,22 +21,22 @@
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ===
-- ====
--
-- # YouTube Channel
--
-- ### [SPOT YouTube Channel]()
--
-- ===
-- ====
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (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
--
-- ===
-- ====
--
-- @module Spot
@@ -200,7 +200,7 @@ do
-- @param #number LaserCode
-- @param #number Duration
function SPOT:onafterLaseOn( From, Event, To, Target, LaserCode, Duration )
self:F( { "LaseOn", Target, LaserCode, Duration } )
self:E( { "LaseOn", Target, LaserCode, Duration } )
local function StopLase( self )
self:LaseOff()
@@ -222,16 +222,16 @@ do
self:HandleEvent( EVENTS.Dead )
self:__Lasing( -1 )
self:__Lasing( -0.2 )
end
--- @param #SPOT self
-- @param Core.Event#EVENTDATA EventData
function SPOT:OnEventDead(EventData)
self:F( { Dead = EventData.IniDCSUnitName, Target = self.Target } )
self:E( { Dead = EventData.IniDCSUnitName, Target = self.Target } )
if self.Target then
if EventData.IniDCSUnitName == self.Target:GetName() then
self:F( {"Target dead ", self.Target:GetName() } )
self:E( {"Target dead ", self.Target:GetName() } )
self:Destroyed()
self:LaseOff()
end
@@ -249,7 +249,7 @@ do
self.SpotLaser:setPoint( self.Target:GetPointVec3():AddY(1):GetVec3() )
self:__Lasing( -0.2 )
else
self:F( { "Target is not alive", self.Target:IsAlive() } )
self:E( { "Target is not alive", self.Target:IsAlive() } )
end
end
@@ -261,7 +261,7 @@ do
-- @return #SPOT
function SPOT:onafterLaseOff( From, Event, To )
self:F( {"Stopped lasing for ", self.Target:GetName() , SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
self:E( {"Stopped lasing for ", self.Target:GetName() , SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
self.Lasing = false

View File

@@ -1,95 +0,0 @@
--- **Core (WIP)** -- Manage user flags.
--
-- ===
--
-- Management of DCS User Flags.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module UserFlag
do -- UserFlag
--- @type USERFLAG
-- @extends Core.Base#BASE
--- # USERFLAG class, extends @{Base#BASE}
--
-- Management of DCS User Flags.
--
-- ## 1. USERFLAG constructor
--
-- * @{#USERFLAG.New}(): Creates a new USERFLAG object.
--
-- @field #USERFLAG
USERFLAG = {
ClassName = "USERFLAG",
}
--- USERFLAG Constructor.
-- @param #USERFLAG self
-- @param #string UserFlagName The name of the userflag, which is a free text string.
-- @return #USERFLAG
function USERFLAG:New( UserFlagName ) --R2.3
local self = BASE:Inherit( self, BASE:New() ) -- #USERFLAG
self.UserFlagName = UserFlagName
return self
end
--- Set the userflag to a given Number.
-- @param #USERFLAG self
-- @param #number Number The number value to be checked if it is the same as the userflag.
-- @return #USERFLAG The userflag instance.
-- @usage
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
-- BlueVictory:Set( 100 ) -- Set the UserFlag VictoryBlue to 100.
--
function USERFLAG:Set( Number ) --R2.3
self:F( { Number = Number } )
trigger.action.setUserFlag( self.UserFlagName, Number )
return self
end
--- Get the userflag Number.
-- @param #USERFLAG self
-- @return #number Number The number value to be checked if it is the same as the userflag.
-- @usage
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
-- local BlueVictoryValue = BlueVictory:Get() -- Get the UserFlag VictoryBlue value.
--
function USERFLAG:Get( Number ) --R2.3
return trigger.misc.getUserFlag( self.UserFlagName )
end
--- Check if the userflag has a value of Number.
-- @param #USERFLAG self
-- @param #number Number The number value to be checked if it is the same as the userflag.
-- @return #boolean true if the Number is the value of the userflag.
-- @usage
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
-- if BlueVictory:Is( 1 ) then
-- return "Blue has won"
-- end
function USERFLAG:Is( Number ) --R2.3
return trigger.misc.getUserFlag( self.UserFlagName ) == Number
end
end

View File

@@ -1,129 +0,0 @@
--- **Core (WIP)** -- Manage user sound.
--
-- ===
--
-- Management of DCS User Sound.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module UserSound
do -- UserSound
--- @type USERSOUND
-- @extends Core.Base#BASE
--- # USERSOUND class, extends @{Base#BASE}
--
-- Management of DCS User Sound.
--
-- ## 1. USERSOUND constructor
--
-- * @{#USERSOUND.New}(): Creates a new USERSOUND object.
--
-- @field #USERSOUND
USERSOUND = {
ClassName = "USERSOUND",
}
--- USERSOUND Constructor.
-- @param #USERSOUND self
-- @param #string UserSoundFileName The filename of the usersound.
-- @return #USERSOUND
function USERSOUND:New( UserSoundFileName ) --R2.3
local self = BASE:Inherit( self, BASE:New() ) -- #USERSOUND
self.UserSoundFileName = UserSoundFileName
return self
end
--- Set usersound filename.
-- @param #USERSOUND self
-- @param #string UserSoundFileName The filename of the usersound.
-- @return #USERSOUND The usersound instance.
-- @usage
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
-- BlueVictory:SetFileName( "BlueVictoryLoud.ogg" ) -- Set the BlueVictory to change the file name to play a louder sound.
--
function USERSOUND:SetFileName( UserSoundFileName ) --R2.3
self.UserSoundFileName = UserSoundFileName
return self
end
--- Play the usersound to all players.
-- @param #USERSOUND self
-- @return #USERSOUND The usersound instance.
-- @usage
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
-- BlueVictory:ToAll() -- Play the sound that Blue has won.
--
function USERSOUND:ToAll() --R2.3
trigger.action.outSound( self.UserSoundFileName )
return self
end
--- Play the usersound to the given coalition.
-- @param #USERSOUND self
-- @param Dcs.DCScoalition#coalition Coalition The coalition to play the usersound to.
-- @return #USERSOUND The usersound instance.
-- @usage
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
-- BlueVictory:ToCoalition( coalition.side.BLUE ) -- Play the sound that Blue has won to the blue coalition.
--
function USERSOUND:ToCoalition( Coalition ) --R2.3
trigger.action.outSoundForCoalition(Coalition, self.UserSoundFileName )
return self
end
--- Play the usersound to the given country.
-- @param #USERSOUND self
-- @param Dcs.DCScountry#country Country The country to play the usersound to.
-- @return #USERSOUND The usersound instance.
-- @usage
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
-- BlueVictory:ToCountry( country.id.USA ) -- Play the sound that Blue has won to the USA country.
--
function USERSOUND:ToCountry( Country ) --R2.3
trigger.action.outSoundForCountry( Country, self.UserSoundFileName )
return self
end
--- Play the usersound to the given @{Group}.
-- @param #USERSOUND self
-- @param Wrapper.Group#GROUP Group The @{Group} to play the usersound to.
-- @return #USERSOUND The usersound instance.
-- @usage
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
-- local PlayerGroup = GROUP:FindByName( "PlayerGroup" ) -- Search for the active group named "PlayerGroup", that contains a human player.
-- BlueVictory:ToGroup( PlayerGroup ) -- Play the sound that Blue has won to the player group.
--
function USERSOUND:ToGroup( Group ) --R2.3
trigger.action.outSoundForGroup( Group:GetID(), self.UserSoundFileName )
return self
end
end

View File

@@ -1,184 +0,0 @@
--- **Core** -- VELOCITY models a speed, which can be expressed in various formats according the Settings.
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions:
--
-- ===
--
-- @module Velocity
do -- Velocity
--- @type VELOCITY
-- @extends Core.Base#BASE
--- # VELOCITY class, extends @{Base#BASE}
--
-- VELOCITY models a speed, which can be expressed in various formats according the Settings.
--
-- ## 1. VELOCITY constructor
--
-- * @{#VELOCITY.New}(): Creates a new VELOCITY object.
--
-- @field #VELOCITY
VELOCITY = {
ClassName = "VELOCITY",
}
--- VELOCITY Constructor.
-- @param #VELOCITY self
-- @param #number VelocityMps The velocity in meters per second.
-- @return #VELOCITY
function VELOCITY:New( VelocityMps )
local self = BASE:Inherit( self, BASE:New() ) -- #VELOCITY
self:F( {} )
self.Velocity = VelocityMps
return self
end
--- Set the velocity in Mps (meters per second).
-- @param #VELOCITY self
-- @param #number VelocityMps The velocity in meters per second.
-- @return #VELOCITY
function VELOCITY:Set( VelocityMps )
self.Velocity = VelocityMps
return self
end
--- Get the velocity in Mps (meters per second).
-- @param #VELOCITY self
-- @return #number The velocity in meters per second.
function VELOCITY:Get()
return self.Velocity
end
--- Set the velocity in Kmph (kilometers per hour).
-- @param #VELOCITY self
-- @param #number VelocityKmph The velocity in kilometers per hour.
-- @return #VELOCITY
function VELOCITY:SetKmph( VelocityKmph )
self.Velocity = UTILS.KmphToMps( VelocityKmph )
return self
end
--- Get the velocity in Kmph (kilometers per hour).
-- @param #VELOCITY self
-- @return #number The velocity in kilometers per hour.
function VELOCITY:GetKmph()
return UTILS.MpsToKmph( self.Velocity )
end
--- Set the velocity in Miph (miles per hour).
-- @param #VELOCITY self
-- @param #number VelocityMiph The velocity in miles per hour.
-- @return #VELOCITY
function VELOCITY:SetMiph( VelocityMiph )
self.Velocity = UTILS.MiphToMps( VelocityMiph )
return self
end
--- Get the velocity in Miph (miles per hour).
-- @param #VELOCITY self
-- @return #number The velocity in miles per hour.
function VELOCITY:GetMiph()
return UTILS.MpsToMiph( self.Velocity )
end
--- Get the velocity in text, according the player @{Settings}.
-- @param #VELOCITY self
-- @param Core.Settings#SETTINGS Settings
-- @return #string The velocity in text.
function VELOCITY:GetText( Settings )
local Settings = Settings or _SETTINGS
if self.Velocity ~= 0 then
if Settings:IsMetric() then
return string.format( "%d km/h", UTILS.MpsToKmph( self.Velocity ) )
else
return string.format( "%d mi/h", UTILS.MpsToMiph( self.Velocity ) )
end
else
return "stationary"
end
end
--- Get the velocity in text, according the player or default @{Settings}.
-- @param #VELOCITY self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param Core.Settings#SETTINGS Settings
-- @return #string The velocity in text according the player or default @{Settings}
function VELOCITY:ToString( VelocityGroup, Settings ) -- R2.3
self:F( { Group = VelocityGroup and VelocityGroup:GetName() } )
local Settings = Settings or ( VelocityGroup and _DATABASE:GetPlayerSettings( VelocityGroup:GetPlayerName() ) ) or _SETTINGS
return self:GetText( Settings )
end
end
do -- VELOCITY_POSITIONABLE
--- @type VELOCITY_POSITIONABLE
-- @extends Core.Base#BASE
--- # VELOCITY_POSITIONABLE class, extends @{Base#BASE}
--
-- VELOCITY_POSITIONABLE monitors the speed of an @{Positionable} in the simulation, which can be expressed in various formats according the Settings.
--
-- ## 1. VELOCITY_POSITIONABLE constructor
--
-- * @{#VELOCITY_POSITIONABLE.New}(): Creates a new VELOCITY_POSITIONABLE object.
--
-- @field #VELOCITY_POSITIONABLE
VELOCITY_POSITIONABLE = {
ClassName = "VELOCITY_POSITIONABLE",
}
--- VELOCITY_POSITIONABLE Constructor.
-- @param #VELOCITY_POSITIONABLE self
-- @param Wrapper.Positionable#POSITIONABLE Positionable The Positionable to monitor the speed.
-- @return #VELOCITY_POSITIONABLE
function VELOCITY_POSITIONABLE:New( Positionable )
local self = BASE:Inherit( self, VELOCITY:New() ) -- #VELOCITY_POSITIONABLE
self:F( {} )
self.Positionable = Positionable
return self
end
--- Get the velocity in Mps (meters per second).
-- @param #VELOCITY_POSITIONABLE self
-- @return #number The velocity in meters per second.
function VELOCITY_POSITIONABLE:Get()
return self.Positionable:GetVelocityMPS() or 0
end
--- Get the velocity in Kmph (kilometers per hour).
-- @param #VELOCITY_POSITIONABLE self
-- @return #number The velocity in kilometers per hour.
function VELOCITY_POSITIONABLE:GetKmph()
return UTILS.MpsToKmph( self.Positionable:GetVelocityMPS() or 0)
end
--- Get the velocity in Miph (miles per hour).
-- @param #VELOCITY_POSITIONABLE self
-- @return #number The velocity in miles per hour.
function VELOCITY_POSITIONABLE:GetMiph()
return UTILS.MpsToMiph( self.Positionable:GetVelocityMPS() or 0 )
end
--- Get the velocity in text, according the player or default @{Settings}.
-- @param #VELOCITY_POSITIONABLE self
-- @return #string The velocity in text according the player or default @{Settings}
function VELOCITY_POSITIONABLE:ToString() -- R2.3
self:F( { Group = self.Positionable and self.Positionable:GetName() } )
local Settings = Settings or ( self.Positionable and _DATABASE:GetPlayerSettings( self.Positionable:GetPlayerName() ) ) or _SETTINGS
self.Velocity = self.Positionable:GetVelocityMPS()
return self:GetText( Settings )
end
end

View File

@@ -2,7 +2,7 @@
--
-- ![Banner Image](..\Presentations\ZONE\Dia1.JPG)
--
-- ===
-- ====
--
-- There are essentially two core functions that zones accomodate:
--
@@ -27,12 +27,12 @@
-- * @{#ZONE_GROUP}: The ZONE_GROUP class defines by a zone around a @{Group#GROUP} with a radius.
-- * @{#ZONE_POLYGON}: The ZONE_POLYGON class defines by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon.
--
-- ===
-- ====
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ===
-- ====
--
-- @module Zone
@@ -50,8 +50,6 @@
-- ## Each zone has a name:
--
-- * @{#ZONE_BASE.GetName}(): Returns the name of the zone.
-- * @{#ZONE_BASE.SetName}(): Sets the name of the zone.
--
--
-- ## Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}:
--
@@ -123,17 +121,6 @@ function ZONE_BASE:GetName()
return self.ZoneName
end
--- Sets the name of the zone.
-- @param #ZONE_BASE self
-- @param #string ZoneName The name of the zone.
-- @return #ZONE_BASE
function ZONE_BASE:SetName( ZoneName )
self:F2()
self.ZoneName = ZoneName
end
--- Returns if a Vec2 is within the zone.
-- @param #ZONE_BASE self
-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 to test.
@@ -458,17 +445,12 @@ end
-- @param #ZONE_RADIUS self
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color.
-- @param #number Points (optional) The amount of points in the circle.
-- @param #number AddHeight (optional) The height to be added for the smoke.
-- @param #number AddOffSet (optional) The angle to be added for the smoking start position.
-- @return #ZONE_RADIUS self
function ZONE_RADIUS:SmokeZone( SmokeColor, Points, AddHeight, AngleOffset )
function ZONE_RADIUS:SmokeZone( SmokeColor, Points )
self:F2( SmokeColor )
local Point = {}
local Vec2 = self:GetVec2()
AddHeight = AddHeight or 0
AngleOffset = AngleOffset or 0
Points = Points and Points or 360
@@ -476,10 +458,10 @@ function ZONE_RADIUS:SmokeZone( SmokeColor, Points, AddHeight, AngleOffset )
local RadialBase = math.pi*2
for Angle = 0, 360, 360 / Points do
local Radial = ( Angle + AngleOffset ) * RadialBase / 360
local Radial = Angle * RadialBase / 360
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Smoke( SmokeColor )
POINT_VEC2:New( Point.x, Point.y ):Smoke( SmokeColor )
end
return self
@@ -491,16 +473,13 @@ end
-- @param Utilities.Utils#FLARECOLOR FlareColor The flare color.
-- @param #number Points (optional) The amount of points in the circle.
-- @param Dcs.DCSTypes#Azimuth Azimuth (optional) Azimuth The azimuth of the flare.
-- @param #number AddHeight (optional) The height to be added for the smoke.
-- @return #ZONE_RADIUS self
function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth, AddHeight )
function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth )
self:F2( { FlareColor, Azimuth } )
local Point = {}
local Vec2 = self:GetVec2()
AddHeight = AddHeight or 0
Points = Points and Points or 360
local Angle
@@ -510,7 +489,7 @@ function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth, AddHeight )
local Radial = Angle * RadialBase / 360
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Flare( FlareColor, Azimuth )
POINT_VEC2:New( Point.x, Point.y ):Flare( FlareColor, Azimuth )
end
return self
@@ -583,225 +562,6 @@ function ZONE_RADIUS:GetVec3( Height )
end
--- Scan the zone for the presence of units of the given ObjectCategories.
-- Note that after a zone has been scanned, the zone can be evaluated by:
--
-- * @{ZONE_RADIUS.IsAllInZoneOfCoalition}(): Scan the presence of units in the zone of a coalition.
-- * @{ZONE_RADIUS.IsAllInZoneOfOtherCoalition}(): Scan the presence of units in the zone of an other coalition.
-- * @{ZONE_RADIUS.IsSomeInZoneOfCoalition}(): Scan if there is some presence of units in the zone of the given coalition.
-- * @{ZONE_RADIUS.IsNoneInZoneOfCoalition}(): Scan if there isn't any presence of units in the zone of an other coalition than the given one.
-- * @{ZONE_RADIUS.IsNoneInZone}(): Scan if the zone is empty.
-- @{#ZONE_RADIUS.
-- @param #ZONE_RADIUS self
-- @param ObjectCategories
-- @param Coalition
-- @usage
-- self.Zone:Scan()
-- local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
function ZONE_RADIUS:Scan( ObjectCategories )
self.ScanData = {}
self.ScanData.Coalitions = {}
self.ScanData.Scenery = {}
local ZoneCoord = self:GetCoordinate()
local ZoneRadius = self:GetRadius()
self:F({ZoneCoord = ZoneCoord, ZoneRadius = ZoneRadius, ZoneCoordLL = ZoneCoord:ToStringLLDMS()})
local SphereSearch = {
id = world.VolumeType.SPHERE,
params = {
point = ZoneCoord:GetVec3(),
radius = ZoneRadius,
}
}
local function EvaluateZone( ZoneObject )
--if ZoneObject:isExist() then --FF: isExist always returns false for SCENERY objects since DCS 2.2 and still in DCS 2.5
if ZoneObject then
local ObjectCategory = ZoneObject:getCategory()
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or
(ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then
local CoalitionDCSUnit = ZoneObject:getCoalition()
self.ScanData.Coalitions[CoalitionDCSUnit] = true
self:F( { Name = ZoneObject:getName(), Coalition = CoalitionDCSUnit } )
end
if ObjectCategory == Object.Category.SCENERY then
local SceneryType = ZoneObject:getTypeName()
local SceneryName = ZoneObject:getName()
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
self.ScanData.Scenery[SceneryType][SceneryName] = SCENERY:Register( SceneryName, ZoneObject )
self:F( { SCENERY = self.ScanData.Scenery[SceneryType][SceneryName] } )
end
end
return true
end
world.searchObjects( ObjectCategories, SphereSearch, EvaluateZone )
end
function ZONE_RADIUS:CountScannedCoalitions()
local Count = 0
for CoalitionID, Coalition in pairs( self.ScanData.Coalitions ) do
Count = Count + 1
end
return Count
end
--- Get Coalitions of the units in the Zone, or Check if there are units of the given Coalition in the Zone.
-- Returns nil if there are none ot two Coalitions in the zone!
-- Returns one Coalition if there are only Units of one Coalition in the Zone.
-- Returns the Coalition for the given Coalition if there are units of the Coalition in the Zone
-- @param #ZONE_RADIUS self
-- @return #table
function ZONE_RADIUS:GetScannedCoalition( Coalition )
if Coalition then
return self.ScanData.Coalitions[Coalition]
else
local Count = 0
local ReturnCoalition = nil
for CoalitionID, Coalition in pairs( self.ScanData.Coalitions ) do
Count = Count + 1
ReturnCoalition = CoalitionID
end
if Count ~= 1 then
ReturnCoalition = nil
end
return ReturnCoalition
end
end
function ZONE_RADIUS:GetScannedSceneryType( SceneryType )
return self.ScanData.Scenery[SceneryType]
end
function ZONE_RADIUS:GetScannedScenery()
return self.ScanData.Scenery
end
--- Is All in Zone of Coalition?
-- @param #ZONE_RADIUS self
-- @param Coalition
-- @return #boolean
-- @usage
-- self.Zone:Scan()
-- local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition )
function ZONE_RADIUS:IsAllInZoneOfCoalition( Coalition )
--self:E( { Coalitions = self.Coalitions, Count = self:CountScannedCoalitions() } )
return self:CountScannedCoalitions() == 1 and self:GetScannedCoalition( Coalition ) == true
end
--- Is All in Zone of Other Coalition?
-- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated!
-- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set.
-- @param #ZONE_RADIUS self
-- @param Coalition
-- @return #boolean
-- @usage
-- self.Zone:Scan()
-- local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
function ZONE_RADIUS:IsAllInZoneOfOtherCoalition( Coalition )
--self:E( { Coalitions = self.Coalitions, Count = self:CountScannedCoalitions() } )
return self:CountScannedCoalitions() == 1 and self:GetScannedCoalition( Coalition ) == nil
end
--- Is Some in Zone of Coalition?
-- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated!
-- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set.
-- @param #ZONE_RADIUS self
-- @param Coalition
-- @return #boolean
-- @usage
-- self.Zone:Scan()
-- local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
function ZONE_RADIUS:IsSomeInZoneOfCoalition( Coalition )
return self:CountScannedCoalitions() > 1 and self:GetScannedCoalition( Coalition ) == true
end
--- Is None in Zone of Coalition?
-- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated!
-- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set.
-- @param #ZONE_RADIUS self
-- @param Coalition
-- @return #boolean
-- @usage
-- self.Zone:Scan()
-- local IsOccupied = self.Zone:IsNoneInZoneOfCoalition( self.Coalition )
function ZONE_RADIUS:IsNoneInZoneOfCoalition( Coalition )
return self:GetScannedCoalition( Coalition ) == nil
end
--- Is None in Zone?
-- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated!
-- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set.
-- @param #ZONE_RADIUS self
-- @return #boolean
-- @usage
-- self.Zone:Scan()
-- local IsEmpty = self.Zone:IsNoneInZone()
function ZONE_RADIUS:IsNoneInZone()
return self:CountScannedCoalitions() == 0
end
--- Searches the zone
-- @param #ZONE_RADIUS self
-- @param ObjectCategories A list of categories, which are members of Object.Category
-- @param EvaluateFunction
function ZONE_RADIUS:SearchZone( EvaluateFunction, ObjectCategories )
local SearchZoneResult = true
local ZoneCoord = self:GetCoordinate()
local ZoneRadius = self:GetRadius()
self:F({ZoneCoord = ZoneCoord, ZoneRadius = ZoneRadius, ZoneCoordLL = ZoneCoord:ToStringLLDMS()})
local SphereSearch = {
id = world.VolumeType.SPHERE,
params = {
point = ZoneCoord:GetVec3(),
radius = ZoneRadius / 2,
}
}
local function EvaluateZone( ZoneDCSUnit )
env.info( ZoneDCSUnit:getName() )
local ZoneUnit = UNIT:Find( ZoneDCSUnit )
return EvaluateFunction( ZoneUnit )
end
world.searchObjects( Object.Category.UNIT, SphereSearch, EvaluateZone )
end
--- Returns if a location is within the zone.
-- @param #ZONE_RADIUS self
-- @param Dcs.DCSTypes#Vec2 Vec2 The location to test.
@@ -862,29 +622,13 @@ end
function ZONE_RADIUS:GetRandomPointVec2( inner, outer )
self:F( self.ZoneName, inner, outer )
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2( inner, outer ) )
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
self:T3( { PointVec2 } )
return PointVec2
end
--- Returns Returns a random Vec3 location within the zone.
-- @param #ZONE_RADIUS self
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
-- @return Dcs.DCSTypes#Vec3 The random location within the zone.
function ZONE_RADIUS:GetRandomVec3( inner, outer )
self:F( self.ZoneName, inner, outer )
local Vec2 = self:GetRandomVec2( inner, outer )
self:T3( { x = Vec2.x, y = self.y, z = Vec2.y } )
return { x = Vec2.x, y = self.y, z = Vec2.y }
end
--- Returns a @{Point#POINT_VEC3} object reflecting a random 3D location within the zone.
-- @param #ZONE_RADIUS self
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
@@ -893,7 +637,7 @@ end
function ZONE_RADIUS:GetRandomPointVec3( inner, outer )
self:F( self.ZoneName, inner, outer )
local PointVec3 = POINT_VEC3:NewFromVec2( self:GetRandomVec2( inner, outer ) )
local PointVec3 = POINT_VEC3:NewFromVec2( self:GetRandomVec2() )
self:T3( { PointVec3 } )
@@ -901,22 +645,6 @@ function ZONE_RADIUS:GetRandomPointVec3( inner, outer )
end
--- Returns a @{Point#COORDINATE} object reflecting a random 3D location within the zone.
-- @param #ZONE_RADIUS self
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
-- @return Core.Point#COORDINATE
function ZONE_RADIUS:GetRandomCoordinate( inner, outer )
self:F( self.ZoneName, inner, outer )
local Coordinate = COORDINATE:NewFromVec2( self:GetRandomVec2() )
self:T3( { Coordinate = Coordinate } )
return Coordinate
end
--- @type ZONE
-- @extends #ZONE_RADIUS
@@ -1106,20 +834,6 @@ function ZONE_GROUP:GetRandomVec2()
return Point
end
--- Returns a @{Point#POINT_VEC2} object reflecting a random 2D location within the zone.
-- @param #ZONE_GROUP self
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
-- @return Core.Point#POINT_VEC2 The @{Point#POINT_VEC2} object reflecting the random 3D location within the zone.
function ZONE_GROUP:GetRandomPointVec2( inner, outer )
self:F( self.ZoneName, inner, outer )
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
self:T3( { PointVec2 } )
return PointVec2
end
--- @type ZONE_POLYGON_BASE
@@ -1363,20 +1077,6 @@ function ZONE_POLYGON_BASE:GetRandomPointVec3()
end
--- Return a @{Point#COORDINATE} object representing a random 3D point at landheight within the zone.
-- @param #ZONE_POLYGON_BASE self
-- @return Core.Point#COORDINATE
function ZONE_POLYGON_BASE:GetRandomCoordinate()
self:F2()
local Coordinate = COORDINATE:NewFromVec2( self:GetRandomVec2() )
self:T2( Coordinate )
return Coordinate
end
--- Get the bounding square the zone.
-- @param #ZONE_POLYGON_BASE self
-- @return #ZONE_POLYGON_BASE.BoundingSquare The bounding square.
@@ -1414,7 +1114,7 @@ ZONE_POLYGON = {
ClassName="ZONE_POLYGON",
}
--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the @{Group#GROUP} defined within the Mission Editor.
--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the name of the @{Group#GROUP} defined within the Mission Editor.
-- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON.
-- @param #ZONE_POLYGON self
-- @param #string ZoneName Name of the zone.
@@ -1430,22 +1130,3 @@ function ZONE_POLYGON:New( ZoneName, ZoneGroup )
return self
end
--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the **name** of the @{Group#GROUP} defined within the Mission Editor.
-- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON.
-- @param #ZONE_POLYGON self
-- @param #string ZoneName Name of the zone.
-- @param #string GroupName The group name of the GROUP defining the waypoints within the Mission Editor to define the polygon shape.
-- @return #ZONE_POLYGON self
function ZONE_POLYGON:NewFromGroupName( GroupName )
local ZoneGroup = GROUP:FindByName( GroupName )
local GroupPoints = ZoneGroup:GetTaskRoute()
local self = BASE:Inherit( self, ZONE_POLYGON_BASE:New( GroupName, GroupPoints ) )
self:F( { GroupName, ZoneGroup, self._.Polygon } )
return self
end

View File

@@ -1,54 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSAirbase
--- Represents airbases: airdromes, helipads and ships with flying decks or landing pads.
-- @type Airbase
-- @extends Dcs.DCSCoalitionWrapper.Object#CoalitionObject
-- @field #Airbase.ID ID Identifier of an airbase. It assigned to an airbase by the Mission Editor automatically. This identifier is used in AI tasks to refer an airbase that exists (spawned and not dead) or not.
-- @field #Airbase.Category Category enum contains identifiers of airbase categories.
-- @field #Airbase.Desc Desc Airbase descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type.
--- Enum contains identifiers of airbase categories.
-- @type Airbase.Category
-- @field AIRDROME
-- @field HELIPAD
-- @field SHIP
--- Airbase descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type.
-- @type Airbase.Desc
-- @extends #Desc
-- @field #Airbase.Category category Category of the airbase type.
--- Returns airbase by its name. If no airbase found the function will return nil.
-- @function [parent=#Airbase] getByName
-- @param #string name
-- @return #Airbase
--- Returns airbase descriptor by type name. If no descriptor is found the function will return nil.
-- @function [parent=#Airbase] getDescByName
-- @param #TypeName typeName Airbase type name.
-- @return #Airbase.Desc
--- Returns Unit that is corresponded to the airbase. Works only for ships.
-- @function [parent=#Airbase] getUnit
-- @param self
-- @return Wrapper.Unit#Unit
--- Returns identifier of the airbase.
-- @function [parent=#Airbase] getID
-- @param self
-- @return #Airbase.ID
--- Returns the airbase's callsign - the localized string.
-- @function [parent=#Airbase] getCallsign
-- @param self
-- @return #string
--- Returns descriptor of the airbase.
-- @function [parent=#Airbase] getDesc
-- @param self
-- @return #Airbase.Desc
Airbase = {} --#Airbase

View File

@@ -1,20 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSCoalitionObject
--- @type CoalitionObject
-- @extends Dcs.DCSWrapper.Object#Object
coalition = {} --#coalition
--- Returns coalition of the object.
-- @function [parent=#CoalitionObject] getCoalition
-- @param #CoalitionObject self
-- @return Dcs.DCSTypes#coalition.side
--- Returns object country.
-- @function [parent=#CoalitionObject] getCountry
-- @param #CoalitionObject self
-- @return #country.id
CoalitionObject = {} --#CoalitionObject

View File

@@ -1,10 +0,0 @@
--- @module DCSCommand
--- @type Command
-- @field #string id
-- @field #Command.params params
--- @type Command.params
env.info( "Command defined" )

View File

@@ -1,115 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSController
--- Controller is an object that performs A.I.-routines. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C.
--
-- This class has 2 types of functions:
--
-- * Tasks
-- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics.
-- @type Controller
-- @field #Controller.Detection Detection Enum contains identifiers of surface types.
--- Enables and disables the controller.
-- Note: Now it works only for ground / naval groups!
-- @function [parent=#Controller] setOnOff
-- @param self
-- @param #boolean value Enable / Disable.
-- Tasks
--- Resets current task and then sets the task to the controller. Task is a table that contains task identifier and task parameters.
-- @function [parent=#Controller] setTask
-- @param self
-- @param #Task task
--- Resets current task of the controller.
-- @function [parent=#Controller] resetTask
-- @param self
--- Pushes the task to the front of the queue and makes the task active. Further call of function Controller.setTask() function will stop current task, clear the queue and set the new task active. If the task queue is empty the function will work like function Controller.setTask() function.
-- @function [parent=#Controller] pushTask
-- @param self
-- @param #Task task
--- Pops current (front) task from the queue and makes active next task in the queue (if exists). If no more tasks in the queue the function works like function Controller.resetTask() function. Does nothing if the queue is empty.
-- @function [parent=#Controller] popTask
-- @param self
--- Returns true if the controller has a task.
-- @function [parent=#Controller] hasTask
-- @param self
-- @return #boolean
-- Commands
--TODO: describe #Command structure
--- Sets the command to perform by controller.
-- @function [parent=#Controller] setCommand
-- @param self
-- @param #Command command Table that contains command identifier and command parameters.
-- Behaviours
--- Sets the option to the controller.
-- Option is a pair of identifier and value. Behavior options are global parameters those affect controller behavior in all tasks it performs.
-- Option identifiers and values are stored in table AI.Option in subtables Air, Ground and Naval.
--
-- OptionId = @{#AI.Option.Air.id} or @{#AI.Option.Ground.id} or @{#AI.Option.Naval.id}
-- OptionValue = AI.Option.Air.val[optionName] or AI.Option.Ground.val[optionName] or AI.Option.Naval.val[optionName]
--
-- @function [parent=#Controller] setOption
-- @param self
-- @param #OptionId optionId Option identifier.
-- @param #OptionValue optionValue Value of the option.
-- Detection
--- Enum contains identifiers of surface types.
-- @type Controller.Detection
-- @field VISUAL
-- @field OPTIC
-- @field RADAR
-- @field IRST
-- @field RWR
-- @field DLINK
--- Detected target.
-- @type DetectedTarget
-- @field Wrapper.Object#Object object The target
-- @field #boolean visible The target is visible
-- @field #boolean type The target type is known
-- @field #boolean distance Distance to the target is known
--- Checks if the target is detected or not. If one or more detection method is specified the function will return true if the target is detected by at least one of these methods. If no detection methods are specified the function will return true if the target is detected by any method.
-- @function [parent=#Controller] isTargetDetected
-- @param self
-- @param Wrapper.Object#Object target Target to check
-- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
-- @return #boolean detected True if the target is detected.
-- @return #boolean visible Has effect only if detected is true. True if the target is visible now.
-- @return #ModelTime lastTime Has effect only if visible is false. Last time when target was seen.
-- @return #boolean type Has effect only if detected is true. True if the target type is known.
-- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known.
-- @return #Vec3 lastPos Has effect only if visible is false. Last position of the target when it was seen.
-- @return #Vec3 lastVel Has effect only if visible is false. Last velocity of the target when it was seen.
--- Returns list of detected targets. If one or more detection method is specified the function will return targets which were detected by at least one of these methods. If no detection methods are specified the function will return targets which were detected by any method.
-- @function [parent=#Controller] getDetectedTargets
-- @param self
-- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
-- @return #list<#DetectedTarget> array of DetectedTarget
--- Know a target.
-- @function [parent=#Controller] knowTarget
-- @param self
-- @param Wrapper.Object#Object object The target.
-- @param #boolean type Target type is known.
-- @param #boolean distance Distance to target is known.
Controller = {} --#Controller

View File

@@ -1,83 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSGroup
--- Represents group of Units.
-- @type Group
-- @field #ID ID Identifier of a group. It is assigned to a group by Mission Editor automatically.
-- @field #Group.Category Category Enum contains identifiers of group types.
--- Enum contains identifiers of group types.
-- @type Group.Category
-- @field AIRPLANE
-- @field HELICOPTER
-- @field GROUND
-- @field SHIP
-- Static Functions
--- Returns group by the name assigned to the group in Mission Editor.
-- @function [parent=#Group] getByName
-- @param #string name
-- @return #Group
-- Member Functions
--- returns true if the group exist or false otherwise.
-- @function [parent=#Group] isExist
-- @param #Group self
-- @return #boolean
--- Destroys the group and all of its units.
-- @function [parent=#Group] destroy
-- @param #Group self
--- Returns category of the group.
-- @function [parent=#Group] getCategory
-- @param #Group self
-- @return #Group.Category
--TODO check coalition.side
--- Returns the coalition of the group.
-- @function [parent=#Group] getCoalition
-- @param #Group self
-- @return Dcs.DCSCoalitionWrapper.Object#coalition.side
--- Returns the group's name. This is the same name assigned to the group in Mission Editor.
-- @function [parent=#Group] getName
-- @param #Group self
-- @return #string
--- Returns the group identifier.
-- @function [parent=#Group] getID
-- @param #Group self
-- @return #ID
--- Returns the unit with number unitNumber. If the unit is not exists the function will return nil.
-- @function [parent=#Group] getUnit
-- @param #Group self
-- @param #number unitNumber
-- @return Dcs.DCSWrapper.Unit#Unit
--- Returns current size of the group. If some of the units will be destroyed, As units are destroyed the size of the group will be changed.
-- @function [parent=#Group] getSize
-- @param #Group self
-- @return #number
--- Returns initial size of the group. If some of the units will be destroyed, initial size of the group will not be changed. Initial size limits the unitNumber parameter for Group.getUnit() function.
-- @function [parent=#Group] getInitialSize
-- @param #Group self
-- @return #number
--- Returns array of the units present in the group now. Destroyed units will not be enlisted at all.
-- @function [parent=#Group] getUnits
-- @param #Group self
-- @return #list<Dcs.DCSWrapper.Unit#Unit> array of Units
--- Returns controller of the group.
-- @function [parent=#Group] getController
-- @param #Group self
-- @return Controller#Controller
Group = {} --#Group

View File

@@ -1,73 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSObject
--- @type Object
-- @field #Object.Category Category
-- @field #Object.Desc Desc
--- @type Object.Category
-- @field UNIT
-- @field WEAPON
-- @field STATIC
-- @field SCENERY
-- @field BASE
--- @type Object.Desc
-- @extends #Desc
-- @field #number life initial life level
-- @field #Box3 box bounding box of collision geometry
--- @function [parent=#Object] isExist
-- @param #Object self
-- @return #boolean
--- @function [parent=#Object] destroy
-- @param #Object self
--- @function [parent=#Object] getCategory
-- @param #Object self
-- @return #Object.Category
--- Returns type name of the Object.
-- @function [parent=#Object] getTypeName
-- @param #Object self
-- @return #string
--- Returns object descriptor.
-- @function [parent=#Object] getDesc
-- @param #Object self
-- @return #Object.Desc
--- Returns true if the object belongs to the category.
-- @function [parent=#Object] hasAttribute
-- @param #Object self
-- @param #AttributeName attributeName Attribute name to check.
-- @return #boolean
--- Returns name of the object. This is the name that is assigned to the object in the Mission Editor.
-- @function [parent=#Object] getName
-- @param #Object self
-- @return #string
--- Returns object coordinates for current time.
-- @function [parent=#Object] getPoint
-- @param #Object self
-- @return #Vec3
--- Returns object position for current time.
-- @function [parent=#Object] getPosition
-- @param #Object self
-- @return #Position3
--- Returns the unit's velocity vector.
-- @function [parent=#Object] getVelocity
-- @param #Object self
-- @return #Vec3
--- Returns true if the unit is in air.
-- @function [parent=#Object] inAir
-- @param #Object self
-- @return #boolean
Object = {} --#Object

View File

@@ -1,34 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSStaticObject
-------------------------------------------------------------------------------
-- @module StaticObject
-- @extends CoalitionWrapper.Object#CoalitionObject
--- Represents static object added in the Mission Editor.
-- @type StaticObject
-- @field #StaticObject.ID ID Identifier of a StaticObject. It assigned to an StaticObject by the Mission Editor automatically.
-- @field #StaticObject.Desc Desc Descriptor of StaticObject and Unit are equal. StaticObject is just a passive variant of Unit.
--- StaticObject descriptor. Airdromes are unique and their types are unique, but helipads and ships are not always unique and may have the same type.
-- @type StaticObject.Desc
-- @extends Wrapper.Unit#Unit.Desc
--- Returns static object by its name. If no static object found nil will be returned.
-- @function [parent=#StaticObject] getByName
-- @param #string name Name of static object to find.
-- @return #StaticObject
--- returns identifier of the static object.
-- @function [parent=#StaticObject] getID
-- @param #StaticObject self
-- @return #StaticObject.ID
--- Returns descriptor of the StaticObject.
-- @function [parent=#StaticObject] getDesc
-- @param #StaticObject self
-- @return #StaticObject.Desc
StaticObject = {} --#StaticObject

View File

@@ -1,15 +0,0 @@
--- @module DCSTask
--- A task descriptor (internal structure for DCS World)
-- @type Task
-- @field #string id
-- @field #Task.param param
--- @type Task.param
--- List of @{#Task}
-- @type TaskArray
-- @list <#Task>
env.info( "Task defined" )

View File

@@ -1,8 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSTime
--- @type ModelTime
-- @extends #number
--- @type Time
-- @extends #number

View File

@@ -1,246 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSTypes
--- Time is given in seconds.
-- @type Time
-- @extends #number
--- Model time is the time that drives the simulation. Model time may be stopped, accelerated and decelerated relative real time.
-- @type ModelTime
-- @extends #number
--- Mission time is a model time plus time of the mission start.
-- @type MissionTime
-- @extends #number
--- Distance is given in meters.
-- @type Distance
-- @extends #number
--- Angle is given in radians.
-- @type Angle
-- @extends #number
--- Azimuth is an angle of rotation around world axis y counter-clockwise.
-- @type Azimuth
-- @extends #number
--- Mass is given in kilograms.
-- @type Mass
-- @extends #number
--- Vec3 type is a 3D-vector.
-- DCS world has 3-dimensional coordinate system. DCS ground is an infinite plain.
-- @type Vec3
-- @field #Distance x is directed to the north
-- @field #Distance z is directed to the east
-- @field #Distance y is directed up
--- Vec2 is a 2D-vector for the ground plane as a reference plane.
-- @type Vec2
-- @field #Distance x Vec2.x = Vec3.x
-- @field #Distance y Vec2.y = Vec3.z
--- Position is a composite structure. It consists of both coordinate vector and orientation matrix. Position3 (also known as "Pos3" for short) is a table that has following format:
-- @type Position3
-- @field #Vec3 p
-- @field #Vec3 x
-- @field #Vec3 y
-- @field #Vec3 z
--- 3-dimensional box.
-- @type Box3
-- @field #Vec3 min
-- @field #Vec3 max
--- Each object belongs to a type. Object type is a named couple of properties those independent of mission and common for all units of the same type. Name of unit type is a string. Samples of unit type: "Su-27", "KAMAZ" and "M2 Bradley".
-- @type TypeName
-- @extends #string
--- AttributeName = string
-- Each object type may have attributes.
-- Attributes are enlisted in ./Scripts/Database/db_attributes.Lua.
-- To know what attributes the object type has, look for the unit type script in sub-directories planes/, helicopter/s, vehicles, navy/ of ./Scripts/Database/ directory.
-- @type AttributeName
-- @extends #string
--- List of @{#AttributeName}
-- @type AttributeNameArray
-- @list <#AttributeName>
--- @type AI
-- @field #AI.Skill Skill
-- @field #AI.Task Task
-- @field #AI.Option Option
--- @type AI.Skill
-- @field AVERAGE
-- @field GOOD
-- @field HIGH
-- @field EXCELLENT
-- @field PLAYER
-- @field CLIENT
--- @type AI.Task
-- @field #AI.Task.WeaponExpend WeaponExpend
-- @field #AI.Task.OrbitPattern OrbitPattern
-- @field #AI.Task.Designation Designation
-- @field #AI.Task.WaypointType WaypointType
-- @field #AI.Task.TurnMethod TurnMethod
-- @field #AI.Task.AltitudeType AltitudeType
-- @field #AI.Task.VehicleFormation VehicleFormation
--- @type AI.Task.WeaponExpend
-- @field ONE
-- @field TWO
-- @field FOUR
-- @field QUARTER
-- @field HALF
-- @field ALL
--- @type AI.Task.OrbitPattern
-- @field CIRCLE
-- @field RACE_TRACK
--- @type AI.Task.Designation
-- @field NO
-- @field AUTO
-- @field WP
-- @field IR_POINTER
-- @field LASER
--- @type AI.Task.WaypointType
-- @field TAKEOFF
-- @field TAKEOFF_PARKING
-- @field TURNING_POINT
-- @field LAND
--- @type AI.Task.TurnMethod
-- @field FLY_OVER_POINT
-- @field FIN_POINT
--- @type AI.Task.AltitudeType
-- @field BARO
-- @field RADIO
--- @type AI.Task.VehicleFormation
-- @field OFF_ROAD
-- @field ON_ROAD
-- @field RANK
-- @field CONE
-- @field DIAMOND
-- @field VEE
-- @field ECHELON_LEFT
-- @field ECHELON_RIGHT
--- @type AI.Option
-- @field #AI.Option.Air Air
-- @field #AI.Option.Ground Ground
-- @field #AI.Option.Naval Naval
--- @type AI.Option.Air
-- @field #AI.Option.Air.id id
-- @field #AI.Option.Air.val val
--- @type AI.Option.Ground
-- @field #AI.Option.Ground.id id
-- @field #AI.Option.Ground.val val
--- @type AI.Option.Naval
-- @field #AI.Option.Naval.id id
-- @field #AI.Option.Naval.val val
--TODO: work on formation
--- @type AI.Option.Air.id
-- @field NO_OPTION
-- @field ROE
-- @field REACTION_ON_THREAT
-- @field RADAR_USING
-- @field FLARE_USING
-- @field FORMATION
-- @field RTB_ON_BINGO
-- @field SILENCE
--- @type AI.Option.Air.val
-- @field #AI.Option.Air.val.ROE ROE
-- @field #AI.Option.Air.val.REACTION_ON_THREAT REACTION_ON_THREAT
-- @field #AI.Option.Air.val.RADAR_USING RADAR_USING
-- @field #AI.Option.Air.val.FLARE_USING FLARE_USING
--- @type AI.Option.Air.val.ROE
-- @field WEAPON_FREE
-- @field OPEN_FIRE_WEAPON_FREE
-- @field OPEN_FIRE
-- @field RETURN_FIRE
-- @field WEAPON_HOLD
--- @type AI.Option.Air.val.REACTION_ON_THREAT
-- @field NO_REACTION
-- @field PASSIVE_DEFENCE
-- @field EVADE_FIRE
-- @field BYPASS_AND_ESCAPE
-- @field ALLOW_ABORT_MISSION
--- @type AI.Option.Air.val.RADAR_USING
-- @field NEVER
-- @field FOR_ATTACK_ONLY
-- @field FOR_SEARCH_IF_REQUIRED
-- @field FOR_CONTINUOUS_SEARCH
--- @type AI.Option.Air.val.FLARE_USING
-- @field NEVER
-- @field AGAINST_FIRED_MISSILE
-- @field WHEN_FLYING_IN_SAM_WEZ
-- @field WHEN_FLYING_NEAR_ENEMIES
--- @type AI.Option.Ground.id
-- @field NO_OPTION
-- @field ROE @{#AI.Option.Ground.val.ROE}
-- @field DISPERSE_ON_ATTACK true or false
-- @field ALARM_STATE @{#AI.Option.Ground.val.ALARM_STATE}
--- @type AI.Option.Ground.val
-- @field #AI.Option.Ground.val.ROE ROE
-- @field #AI.Option.Ground.val.ALARM_STATE ALARM_STATE
--- @type AI.Option.Ground.val.ROE
-- @field OPEN_FIRE
-- @field RETURN_FIRE
-- @field WEAPON_HOLD
--- @type AI.Option.Ground.val.ALARM_STATE
-- @field AUTO
-- @field GREEN
-- @field RED
--- @type AI.Option.Naval.id
-- @field NO_OPTION
-- @field ROE
--- @type AI.Option.Naval.val
-- @field #AI.Option.Naval.val.ROE ROE
--- @type AI.Option.Naval.val.ROE
-- @field OPEN_FIRE
-- @field RETURN_FIRE
-- @field WEAPON_HOLD
AI = {} --#AI
--- @type Desc
-- @field #TypeName typeName type name
-- @field #string displayName localized display name
-- @field #table attributes object type attributes
--- A distance type
-- @type Distance
--- An angle type
-- @type Angle
env.info( 'AI types created' )

View File

@@ -1,241 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSUnit
--- @type Unit
-- @extends Dcs.DCSCoalitionWrapper.Object#CoalitionObject
-- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically.
-- @field #Unit.Category Category
-- @field #Unit.RefuelingSystem RefuelingSystem
-- @field #Unit.SensorType SensorType
-- @field #Unit.OpticType OpticType
-- @field #Unit.RadarType RadarType
-- @field #Unit.Desc Desc
-- @field #Unit.DescAircraft DescAircraft
-- @field #Unit.DescAirplane DescAirplane
-- @field #Unit.DescHelicopter DescHelicopter
-- @field #Unit.DescVehicle DescVehicle
-- @field #Unit.DescShip DescShip
-- @field #Unit.AmmoItem AmmoItem
-- @field #list<#Unit.AmmoItem> Ammo
-- @field #Unit.Sensor Sensor
-- @field #Unit.Optic Optic
-- @field #Unit.Radar Radar
-- @field #Unit.IRST IRST
--- Enum that stores unit categories.
-- @type Unit.Category
-- @field AIRPLANE
-- @field HELICOPTER
-- @field GROUND_UNIT
-- @field SHIP
-- @field STRUCTURE
--- Enum that stores aircraft refueling system types.
-- @type Unit.RefuelingSystem
-- @field BOOM_AND_RECEPTACLE
-- @field PROBE_AND_DROGUE
--- Enum that stores sensor types.
-- @type Unit.SensorType
-- @field OPTIC
-- @field RADAR
-- @field IRST
-- @field RWR
--- Enum that stores types of optic sensors.
-- @type Unit.OpticType
-- @field TV TV-sensor
-- @field LLTV Low-level TV-sensor
-- @field IR Infra-Red optic sensor
--- Enum that stores radar types.
-- @type Unit.RadarType
-- @field AS air search radar
-- @field SS surface/land search radar
--- A unit descriptor.
-- @type Unit.Desc
-- @extends Wrapper.Object#Object.Desc
-- @field #Unit.Category category Unit Category
-- @field #Mass massEmpty mass of empty unit
-- @field #number speedMax istance / Time, --maximal velocity
--- An aircraft descriptor.
-- @type Unit.DescAircraft
-- @extends Wrapper.Unit#Unit.Desc
-- @field #Mass fuelMassMax maximal inner fuel mass
-- @field #Distance range Operational range
-- @field #Distance Hmax Ceiling
-- @field #number VyMax #Distance / #Time, --maximal climb rate
-- @field #number NyMin minimal safe acceleration
-- @field #number NyMax maximal safe acceleration
-- @field #Unit.RefuelingSystem tankerType refueling system type
--- An airplane descriptor.
-- @type Unit.DescAirplane
-- @extends Wrapper.Unit#Unit.DescAircraft
-- @field #number speedMax0 Distance / Time maximal TAS at ground level
-- @field #number speedMax10K Distance / Time maximal TAS at altitude of 10 km
--- A helicopter descriptor.
-- @type Unit.DescHelicopter
-- @extends Wrapper.Unit#Unit.DescAircraft
-- @field #Distance HmaxStat static ceiling
--- A vehicle descriptor.
-- @type Unit.DescVehicle
-- @extends Wrapper.Unit#Unit.Desc
-- @field #Angle maxSlopeAngle maximal slope angle
-- @field #boolean riverCrossing can the vehicle cross a rivers
--- A ship descriptor.
-- @type Unit.DescShip
-- @extends #Unit.Desc
--- ammunition item: "type-count" pair.
-- @type Unit.AmmoItem
-- @field #Weapon.Desc desc ammunition descriptor
-- @field #number count ammunition count
--- A unit sensor.
-- @type Unit.Sensor
-- @field #TypeName typeName
-- @field #Unit.SensorType type
--- An optic sensor.
-- @type Unit.Optic
-- @extends Wrapper.Unit#Unit.Sensor
-- @field #Unit.OpticType opticType
--- A radar.
-- @type Unit.Radar
-- @extends Wrapper.Unit#Unit.Sensor
-- @field #Distance detectionDistanceRBM detection distance for RCS=1m^2 in real-beam mapping mode, nil if radar doesn't support surface/land search
-- @field #Distance detectionDistanceHRM detection distance for RCS=1m^2 in high-resolution mapping mode, nil if radar has no HRM
-- @field #Unit.Radar.detectionDistanceAir detectionDistanceAir detection distance for RCS=1m^2 airborne target, nil if radar doesn't support air search
--- @type Unit.Radar.detectionDistanceAir
-- @field #Unit.Radar.detectionDistanceAir.upperHemisphere upperHemisphere
-- @field #Unit.Radar.detectionDistanceAir.lowerHemisphere lowerHemisphere
--- @type Unit.Radar.detectionDistanceAir.upperHemisphere
-- @field #Distance headOn
-- @field #Distance tailOn
--- @type Unit.Radar.detectionDistanceAir.lowerHemisphere
-- @field #Distance headOn
-- @field #Distance tailOn
--- An IRST.
-- @type Wrapper.Unit#Unit.IRST
-- @extends Unit.Sensor
-- @field #Distance detectionDistanceIdle detection of tail-on target with heat signature = 1 in upper hemisphere, engines are in idle
-- @field #Distance detectionDistanceMaximal ..., engines are in maximal mode
-- @field #Distance detectionDistanceAfterburner ..., engines are in afterburner mode
--- An RWR.
-- @type Unit.RWR
-- @extends Wrapper.Unit#Unit.Sensor
--- table that stores all unit sensors.
-- TODO @type Sensors
--
--- Returns unit object by the name assigned to the unit in Mission Editor. If there is unit with such name or the unit is destroyed the function will return nil. The function provides access to non-activated units too.
-- @function [parent=#Unit] getByName
-- @param #string name
-- @return #Unit
--- Returns if the unit is activated.
-- @function [parent=#Unit] isActive
-- @param #Unit self
-- @return #boolean
--- Returns name of the player that control the unit or nil if the unit is controlled by A.I.
-- @function [parent=#Unit] getPlayerName
-- @param #Unit self
-- @return #string
--- returns the unit's unique identifier.
-- @function [parent=#Unit] getID
-- @param #Unit self
-- @return #Unit.ID
--- Returns the unit's number in the group. The number is the same number the unit has in ME. It may not be changed during the mission. If any unit in the group is destroyed, the numbers of another units will not be changed.
-- @function [parent=#Unit] getNumber
-- @param #Unit self
-- @return #number
--- Returns controller of the unit if it exist and nil otherwise
-- @function [parent=#Unit] getController
-- @param #Unit self
-- @return #Controller
--- Returns the unit's group if it exist and nil otherwise
-- @function [parent=#Unit] getGroup
-- @param #Unit self
-- @return Dcs.DCSWrapper.Group#Group
--- Returns the unit's callsign - the localized string.
-- @function [parent=#Unit] getCallsign
-- @param #Unit self
-- @return #string
--- Returns the unit's health. Dead units has health <= 1.0
-- @function [parent=#Unit] getLife
-- @param #Unit self
-- @return #number
--- returns the unit's initial health.
-- @function [parent=#Unit] getLife0
-- @param #Unit self
-- @return #number
--- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks. If there are additional fuel tanks the value may be greater than 1.0.
-- @function [parent=#Unit] getFuel
-- @param #Unit self
-- @return #number
--- Returns the unit ammunition.
-- @function [parent=#Unit] getAmmo
-- @param #Unit self
-- @return #Unit.Ammo
--- Returns the unit sensors.
-- @function [parent=#Unit] getSensors
-- @param #Unit self
-- @return #Unit.Sensors
--- Returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors.
-- @function [parent=#Unit] hasSensors
-- @param #Unit self
-- @param #Unit.SensorType sensorType (= nil) Sensor type.
-- @param ... Additional parameters.
-- @return #boolean
-- @usage
-- If sensorType is Unit.SensorType.OPTIC, additional parameters are optic sensor types. Following example checks if the unit has LLTV or IR optics:
-- unit:hasSensors(Unit.SensorType.OPTIC, Unit.OpticType.LLTV, Unit.OpticType.IR)
-- If sensorType is Unit.SensorType.RADAR, additional parameters are radar types. Following example checks if the unit has air search radars:
-- unit:hasSensors(Unit.SensorType.RADAR, Unit.RadarType.AS)
-- If no additional parameters are specified the function returns true if the unit has at least one sensor of specified type.
-- If sensor type is not specified the function returns true if the unit has at least one sensor of any type.
--
--- returns two values:
-- First value indicates if at least one of the unit's radar(s) is on.
-- Second value is the object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target.
-- @function [parent=#Unit] getRadar
-- @param #Unit self
-- @return #boolean, Wrapper.Object#Object
--- Returns unit descriptor. Descriptor type depends on unit category.
-- @function [parent=#Unit] getDesc
-- @param #Unit self
-- @return #Unit.Desc
Unit = {} --#Unit

View File

@@ -1,11 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSVec3
---
-- @type Vec3
-- @field #number x
-- @field #number y
-- @field #number z
Vec3 = {}

View File

@@ -1,10 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSZone
---
-- @type Zone
-- @field DCSVec3#Vec3 point
-- @field #number radius
Zone = {}

View File

@@ -1,14 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCScoalition
--- @type coalition
-- @field #coalition.side side
--- @type coalition.side
-- @field NEUTRAL
-- @field RED
-- @field BLUE
--- @function [parent=#coalition] getCountryCoalition
-- @param #number countryId
-- @return #number coalitionId

View File

@@ -1,27 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCScountry
--- @type country
-- @field #country.id id
country = country -- #country
--- @type country.id
-- @field RUSSIA
-- @field UKRAINE
-- @field USA
-- @field TURKEY
-- @field UK
-- @field FRANCE
-- @field GERMANY
-- @field CANADA
-- @field SPAIN
-- @field THE_NETHERLANDS
-- @field BELGIUM
-- @field NORWAY
-- @field DENMARK
-- @field ISRAEL
-- @field GEORGIA
-- @field INSURGENTS
-- @field ABKHAZIA
-- @field SOUTH_OSETIA
-- @field ITALY

View File

@@ -1,27 +0,0 @@
-------------------------------------------------------------------------------
-- @module env
--- @type env
--- Add message to simulator log with caption "INFO". Message box is optional.
-- @function [parent=#env] info
-- @field #string message message string to add to log.
-- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional.
--- Add message to simulator log with caption "WARNING". Message box is optional.
-- @function [parent=#env] warning
-- @field #string message message string to add to log.
-- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional.
--- Add message to simulator log with caption "ERROR". Message box is optional.
-- @function [parent=#env] error
-- @field #string message message string to add to log.
-- @field #boolean showMessageBox If the parameter is true Message Box will appear. Optional.
--- Enables/disables appearance of message box each time lua error occurs.
-- @function [parent=#env] setErrorMessageBoxEnabled
-- @field #boolean on if true message box appearance is enabled.
env = {} --#env

View File

@@ -1,26 +0,0 @@
-------------------------------------------------------------------------------
-- @module land
--- @type land
-- @field #land.SurfaceType SurfaceType
--- @type land.SurfaceType
-- @field LAND
-- @field SHALLOW_WATER
-- @field WATER
-- @field ROAD
-- @field RUNWAY
--- Returns altitude MSL of the point.
-- @function [parent=#land] getHeight
-- @param #Vec2 point point on the ground.
-- @return Dcs.DCSTypes#Distance
--- returns surface type at the given point.
-- @function [parent=#land] getSurfaceType
-- @param #Vec2 point Point on the land.
-- @return #land.SurfaceType
land = {} --#land

View File

@@ -1,45 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCStimer
--- @type timer
--- Returns model time in seconds.
-- @function [parent=#timer] getTime
-- @return #Time
--- Returns mission time in seconds.
-- @function [parent=#timer] getAbsTime
-- @return #Time
--- Returns mission start time in seconds.
-- @function [parent=#timer] getTime0
-- @return #Time
--- Schedules function to call at desired model time.
-- Time function FunctionToCall(any argument, Time time)
--
-- ...
--
-- return ...
--
-- end
--
-- Must return model time of next call or nil. Note that the DCS scheduler calls the function in protected mode and any Lua errors in the called function will be trapped and not reported. If the function triggers a Lua error then it will be terminated and not scheduled to run again.
-- @function [parent=#timer] scheduleFunction
-- @param #FunctionToCall functionToCall Lua-function to call. Must have prototype of FunctionToCall.
-- @param functionArgument Function argument of any type to pass to functionToCall.
-- @param #Time time Model time of the function call.
-- @return functionId
--- Re-schedules function to call at another model time.
-- @function [parent=#timer] setFunctionTime
-- @param functionId Lua-function to call. Must have prototype of FunctionToCall.
-- @param #Time time Model time of the function call.
--- Removes the function from schedule.
-- @function [parent=#timer] removeFunction
-- @param functionId Function identifier to remove from schedule
timer = {} --#timer

View File

@@ -1,8 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCStrigger
trigger = {} --#timer

View File

@@ -1,35 +0,0 @@
-------------------------------------------------------------------------------
-- @module DCSWorld
--- @type world
-- @field #world.event event
--- @type world.event
-- @field S_EVENT_INVALID
-- @field S_EVENT_SHOT
-- @field S_EVENT_HIT
-- @field S_EVENT_TAKEOFF
-- @field S_EVENT_LAND
-- @field S_EVENT_CRASH
-- @field S_EVENT_EJECTION
-- @field S_EVENT_REFUELING
-- @field S_EVENT_DEAD
-- @field S_EVENT_PILOT_DEAD
-- @field S_EVENT_BASE_CAPTURED
-- @field S_EVENT_MISSION_START
-- @field S_EVENT_MISSION_END
-- @field S_EVENT_TOOK_CONTROL
-- @field S_EVENT_REFUELING_STOP
-- @field S_EVENT_BIRTH
-- @field S_EVENT_HUMAN_FAILURE
-- @field S_EVENT_ENGINE_STARTUP
-- @field S_EVENT_ENGINE_SHUTDOWN
-- @field S_EVENT_PLAYER_ENTER_UNIT
-- @field S_EVENT_PLAYER_LEAVE_UNIT
-- @field S_EVENT_PLAYER_COMMENT
-- @field S_EVENT_SHOOTING_START
-- @field S_EVENT_SHOOTING_END
-- @field S_EVENT_MAX
world = {} --#world

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,10 +2,10 @@
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
-- ### Contributions:
--
-- ===
-- ====
--
-- @module CleanUp

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
--- **Functional** -- Taking the lead of AI escorting your flight.
--
-- ===
-- ====
--
-- @{#ESCORT} class
-- ===
-- ================
-- The @{#ESCORT} class allows you to interact with escorting AI on your flight and take the lead.
-- Each escorting group can be commanded with a whole set of radio commands (radio menu in your flight, and then F10).
--
@@ -11,7 +11,7 @@
-- Ships and Ground troops will have a more limited set, but they can provide support through the bombing of targets designated by the other escorts.
--
-- RADIO MENUs that can be created:
-- ===
-- ================================
-- Find a summary below of the current available commands:
--
-- Navigation ...:
@@ -79,13 +79,13 @@
-- Note that this is really fantastic, as you now have the dynamic of taking control of the escort groups, and allowing them to resume their path or mission.
--
-- ESCORT construction methods.
-- ===
-- ============================
-- Create a new SPAWN object with the @{#ESCORT.New} method:
--
-- * @{#ESCORT.New}: Creates a new ESCORT object from a @{Group#GROUP} for a @{Client#CLIENT}, with an optional briefing text.
--
-- ESCORT initialization methods.
-- ===
-- ==============================
-- The following menus are created within the RADIO MENU (F10) of an active unit hosted by a player:
--
-- * @{#ESCORT.MenuFollowAt}: Creates a menu to make the escort follow the client.
@@ -129,7 +129,8 @@
-- @field #boolean ReportTargets If true, nearby targets are reported.
-- @Field Dcs.DCSTypes#AI.Option.Air.val.ROE OptionROE Which ROE is set to the EscortGroup.
-- @field Dcs.DCSTypes#AI.Option.Air.val.REACTION_ON_THREAT OptionReactionOnThreat Which REACTION_ON_THREAT is set to the EscortGroup.
-- @field FunctionalMENU_GROUPDETECTION_BASE Detection
-- @field Core.Menu#MENU_CLIENT EscortMenuResumeMission
-- @field Functional.Detection#DETECTION_BASE Detection
ESCORT = {
ClassName = "ESCORT",
EscortName = nil, -- The Escort Name
@@ -206,7 +207,7 @@ function ESCORT:New( EscortClient, EscortGroup, EscortName, EscortBriefing )
self.EscortClient._EscortGroups[EscortGroup:GetName()].Detection = self.EscortGroup.Detection
end
self.EscortMenu = MENU_GROUP:New( self.EscortClient:GetGroup(), self.EscortName )
self.EscortMenu = MENU_CLIENT:New( self.EscortClient, self.EscortName )
self.EscortGroup:WayPointInitialize(1)
@@ -302,14 +303,14 @@ function ESCORT:MenuFollowAt( Distance )
if self.EscortGroup:IsAir() then
if not self.EscortMenuReportNavigation then
self.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortClient:GetGroup(), "Navigation", self.EscortMenu )
self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu )
end
if not self.EscortMenuJoinUpAndFollow then
self.EscortMenuJoinUpAndFollow = {}
end
self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1] = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Join-Up and Follow at " .. Distance, self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, self, Distance )
self.EscortMenuJoinUpAndFollow[#self.EscortMenuJoinUpAndFollow+1] = MENU_CLIENT_COMMAND:New( self.EscortClient, "Join-Up and Follow at " .. Distance, self.EscortMenuReportNavigation, ESCORT._JoinUpAndFollow, self, Distance )
self.EscortMode = ESCORT.MODE.FOLLOW
end
@@ -331,7 +332,7 @@ function ESCORT:MenuHoldAtEscortPosition( Height, Seconds, MenuTextFormat )
if self.EscortGroup:IsAir() then
if not self.EscortMenuHold then
self.EscortMenuHold = MENU_GROUP:New( self.EscortClient:GetGroup(), "Hold position", self.EscortMenu )
self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu )
end
if not Height then
@@ -361,9 +362,9 @@ function ESCORT:MenuHoldAtEscortPosition( Height, Seconds, MenuTextFormat )
self.EscortMenuHoldPosition = {}
end
self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1] = MENU_GROUP_COMMAND
self.EscortMenuHoldPosition[#self.EscortMenuHoldPosition+1] = MENU_CLIENT_COMMAND
:New(
self.EscortClient:GetGroup(),
self.EscortClient,
MenuText,
self.EscortMenuHold,
ESCORT._HoldPosition,
@@ -392,7 +393,7 @@ function ESCORT:MenuHoldAtLeaderPosition( Height, Seconds, MenuTextFormat )
if self.EscortGroup:IsAir() then
if not self.EscortMenuHold then
self.EscortMenuHold = MENU_GROUP:New( self.EscortClient:GetGroup(), "Hold position", self.EscortMenu )
self.EscortMenuHold = MENU_CLIENT:New( self.EscortClient, "Hold position", self.EscortMenu )
end
if not Height then
@@ -422,9 +423,9 @@ function ESCORT:MenuHoldAtLeaderPosition( Height, Seconds, MenuTextFormat )
self.EscortMenuHoldAtLeaderPosition = {}
end
self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_GROUP_COMMAND
self.EscortMenuHoldAtLeaderPosition[#self.EscortMenuHoldAtLeaderPosition+1] = MENU_CLIENT_COMMAND
:New(
self.EscortClient:GetGroup(),
self.EscortClient,
MenuText,
self.EscortMenuHold,
ESCORT._HoldPosition,
@@ -451,7 +452,7 @@ function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat )
if self.EscortGroup:IsAir() then
if not self.EscortMenuScan then
self.EscortMenuScan = MENU_GROUP:New( self.EscortClient:GetGroup(), "Scan for targets", self.EscortMenu )
self.EscortMenuScan = MENU_CLIENT:New( self.EscortClient, "Scan for targets", self.EscortMenu )
end
if not Height then
@@ -481,9 +482,9 @@ function ESCORT:MenuScanForTargets( Height, Seconds, MenuTextFormat )
self.EscortMenuScanForTargets = {}
end
self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_GROUP_COMMAND
self.EscortMenuScanForTargets[#self.EscortMenuScanForTargets+1] = MENU_CLIENT_COMMAND
:New(
self.EscortClient:GetGroup(),
self.EscortClient,
MenuText,
self.EscortMenuScan,
ESCORT._ScanTargets,
@@ -507,7 +508,7 @@ function ESCORT:MenuFlare( MenuTextFormat )
self:F()
if not self.EscortMenuReportNavigation then
self.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortClient:GetGroup(), "Navigation", self.EscortMenu )
self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu )
end
local MenuText = ""
@@ -518,11 +519,11 @@ function ESCORT:MenuFlare( MenuTextFormat )
end
if not self.EscortMenuFlare then
self.EscortMenuFlare = MENU_GROUP:New( self.EscortClient:GetGroup(), MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, self )
self.EscortMenuFlareGreen = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release green flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Green, "Released a green flare!" )
self.EscortMenuFlareRed = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release red flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Red, "Released a red flare!" )
self.EscortMenuFlareWhite = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release white flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.White, "Released a white flare!" )
self.EscortMenuFlareYellow = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Yellow, "Released a yellow flare!" )
self.EscortMenuFlare = MENU_CLIENT:New( self.EscortClient, MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, self )
self.EscortMenuFlareGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Green, "Released a green flare!" )
self.EscortMenuFlareRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Red, "Released a red flare!" )
self.EscortMenuFlareWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.White, "Released a white flare!" )
self.EscortMenuFlareYellow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, self, FLARECOLOR.Yellow, "Released a yellow flare!" )
end
return self
@@ -540,7 +541,7 @@ function ESCORT:MenuSmoke( MenuTextFormat )
if not self.EscortGroup:IsAir() then
if not self.EscortMenuReportNavigation then
self.EscortMenuReportNavigation = MENU_GROUP:New( self.EscortClient:GetGroup(), "Navigation", self.EscortMenu )
self.EscortMenuReportNavigation = MENU_CLIENT:New( self.EscortClient, "Navigation", self.EscortMenu )
end
local MenuText = ""
@@ -551,12 +552,12 @@ function ESCORT:MenuSmoke( MenuTextFormat )
end
if not self.EscortMenuSmoke then
self.EscortMenuSmoke = MENU_GROUP:New( self.EscortClient:GetGroup(), "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, self )
self.EscortMenuSmokeGreen = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Green, "Releasing green smoke!" )
self.EscortMenuSmokeRed = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Red, "Releasing red smoke!" )
self.EscortMenuSmokeWhite = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.White, "Releasing white smoke!" )
self.EscortMenuSmokeOrange = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" )
self.EscortMenuSmokeBlue = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" )
self.EscortMenuSmoke = MENU_CLIENT:New( self.EscortClient, "Smoke", self.EscortMenuReportNavigation, ESCORT._Smoke, self )
self.EscortMenuSmokeGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Green, "Releasing green smoke!" )
self.EscortMenuSmokeRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Red, "Releasing red smoke!" )
self.EscortMenuSmokeWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.White, "Releasing white smoke!" )
self.EscortMenuSmokeOrange = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release orange smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Orange, "Releasing orange smoke!" )
self.EscortMenuSmokeBlue = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release blue smoke", self.EscortMenuSmoke, ESCORT._Smoke, self, SMOKECOLOR.Blue, "Releasing blue smoke!" )
end
end
@@ -573,7 +574,7 @@ function ESCORT:MenuReportTargets( Seconds )
self:F( { Seconds } )
if not self.EscortMenuReportNearbyTargets then
self.EscortMenuReportNearbyTargets = MENU_GROUP:New( self.EscortClient:GetGroup(), "Report targets", self.EscortMenu )
self.EscortMenuReportNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Report targets", self.EscortMenu )
end
if not Seconds then
@@ -581,12 +582,12 @@ function ESCORT:MenuReportTargets( Seconds )
end
-- Report Targets
self.EscortMenuReportNearbyTargetsNow = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, self )
self.EscortMenuReportNearbyTargetsOn = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, true )
self.EscortMenuReportNearbyTargetsOff = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, false )
self.EscortMenuReportNearbyTargetsNow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets now!", self.EscortMenuReportNearbyTargets, ESCORT._ReportNearbyTargetsNow, self )
self.EscortMenuReportNearbyTargetsOn = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets on", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, true )
self.EscortMenuReportNearbyTargetsOff = MENU_CLIENT_COMMAND:New( self.EscortClient, "Report targets off", self.EscortMenuReportNearbyTargets, ESCORT._SwitchReportNearbyTargets, self, false )
-- Attack Targets
self.EscortMenuAttackNearbyTargets = MENU_GROUP:New( self.EscortClient:GetGroup(), "Attack targets", self.EscortMenu )
self.EscortMenuAttackNearbyTargets = MENU_CLIENT:New( self.EscortClient, "Attack targets", self.EscortMenu )
self.ReportTargetsScheduler = SCHEDULER:New( self, self._ReportTargetsScheduler, {}, 1, Seconds )
@@ -604,7 +605,7 @@ function ESCORT:MenuAssistedAttack()
-- Request assistance from other escorts.
-- This is very useful to let f.e. an escorting ship attack a target detected by an escorting plane...
self.EscortMenuTargetAssistance = MENU_GROUP:New( self.EscortClient:GetGroup(), "Request assistance from", self.EscortMenu )
self.EscortMenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, "Request assistance from", self.EscortMenu )
return self
end
@@ -618,18 +619,18 @@ function ESCORT:MenuROE( MenuTextFormat )
if not self.EscortMenuROE then
-- Rules of Engagement
self.EscortMenuROE = MENU_GROUP:New( self.EscortClient:GetGroup(), "ROE", self.EscortMenu )
self.EscortMenuROE = MENU_CLIENT:New( self.EscortClient, "ROE", self.EscortMenu )
if self.EscortGroup:OptionROEHoldFirePossible() then
self.EscortMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Hold Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEHoldFire(), "Holding weapons!" )
self.EscortMenuROEHoldFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Hold Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEHoldFire(), "Holding weapons!" )
end
if self.EscortGroup:OptionROEReturnFirePossible() then
self.EscortMenuROEReturnFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Return Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEReturnFire(), "Returning fire!" )
self.EscortMenuROEReturnFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Return Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEReturnFire(), "Returning fire!" )
end
if self.EscortGroup:OptionROEOpenFirePossible() then
self.EscortMenuROEOpenFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Open Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEOpenFire(), "Opening fire on designated targets!!" )
self.EscortMenuROEOpenFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Open Fire", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEOpenFire(), "Opening fire on designated targets!!" )
end
if self.EscortGroup:OptionROEWeaponFreePossible() then
self.EscortMenuROEWeaponFree = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Weapon Free", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEWeaponFree(), "Opening fire on targets of opportunity!" )
self.EscortMenuROEWeaponFree = MENU_CLIENT_COMMAND:New( self.EscortClient, "Weapon Free", self.EscortMenuROE, ESCORT._ROE, self, self.EscortGroup:OptionROEWeaponFree(), "Opening fire on targets of opportunity!" )
end
end
@@ -647,18 +648,18 @@ function ESCORT:MenuEvasion( MenuTextFormat )
if self.EscortGroup:IsAir() then
if not self.EscortMenuEvasion then
-- Reaction to Threats
self.EscortMenuEvasion = MENU_GROUP:New( self.EscortClient:GetGroup(), "Evasion", self.EscortMenu )
self.EscortMenuEvasion = MENU_CLIENT:New( self.EscortClient, "Evasion", self.EscortMenu )
if self.EscortGroup:OptionROTNoReactionPossible() then
self.EscortMenuEvasionNoReaction = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTNoReaction(), "Fighting until death!" )
self.EscortMenuEvasionNoReaction = MENU_CLIENT_COMMAND:New( self.EscortClient, "Fight until death", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTNoReaction(), "Fighting until death!" )
end
if self.EscortGroup:OptionROTPassiveDefensePossible() then
self.EscortMenuEvasionPassiveDefense = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTPassiveDefense(), "Defending using jammers, chaff and flares!" )
self.EscortMenuEvasionPassiveDefense = MENU_CLIENT_COMMAND:New( self.EscortClient, "Use flares, chaff and jammers", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTPassiveDefense(), "Defending using jammers, chaff and flares!" )
end
if self.EscortGroup:OptionROTEvadeFirePossible() then
self.EscortMenuEvasionEvadeFire = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTEvadeFire(), "Evading on enemy fire!" )
self.EscortMenuEvasionEvadeFire = MENU_CLIENT_COMMAND:New( self.EscortClient, "Evade enemy fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTEvadeFire(), "Evading on enemy fire!" )
end
if self.EscortGroup:OptionROTVerticalPossible() then
self.EscortMenuOptionEvasionVertical = MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(), "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTVertical(), "Evading on enemy fire with vertical manoeuvres!" )
self.EscortMenuOptionEvasionVertical = MENU_CLIENT_COMMAND:New( self.EscortClient, "Go below radar and evade fire", self.EscortMenuEvasion, ESCORT._ROT, self, self.EscortGroup:OptionROTVertical(), "Evading on enemy fire with vertical manoeuvres!" )
end
end
end
@@ -675,7 +676,7 @@ function ESCORT:MenuResumeMission()
if not self.EscortMenuResumeMission then
-- Mission Resume Menu Root
self.EscortMenuResumeMission = MENU_GROUP:New( self.EscortClient:GetGroup(), "Resume mission from", self.EscortMenu )
self.EscortMenuResumeMission = MENU_CLIENT:New( self.EscortClient, "Resume mission from", self.EscortMenu )
end
return self
@@ -846,11 +847,11 @@ function _Resume( EscortGroup )
end
--- @param #ESCORT self
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
function ESCORT:_AttackTarget( DetectedItem )
-- @param #number DetectedItemID
function ESCORT:_AttackTarget( DetectedItemID )
local EscortGroup = self.EscortGroup -- Wrapper.Group#GROUP
self:F( EscortGroup )
self:E( EscortGroup )
local EscortClient = self.EscortClient
@@ -861,7 +862,7 @@ function ESCORT:_AttackTarget( DetectedItem )
EscortGroup:OptionROTPassiveDefense()
EscortGroup:SetState( EscortGroup, "Escort", self )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local Tasks = {}
@@ -874,7 +875,7 @@ function ESCORT:_AttackTarget( DetectedItem )
end, Tasks
)
Tasks[#Tasks+1] = EscortGroup:TaskFunction( "_Resume", { "''" } )
Tasks[#Tasks+1] = EscortGroup:TaskFunction( 1, 2, "_Resume", { "''" } )
EscortGroup:SetTask(
EscortGroup:TaskCombo(
@@ -884,7 +885,7 @@ function ESCORT:_AttackTarget( DetectedItem )
else
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local Tasks = {}
@@ -910,9 +911,8 @@ function ESCORT:_AttackTarget( DetectedItem )
end
---
--- @param #ESCORT self
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
-- @param #number DetectedItemID
function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItemID )
local EscortGroup = self.EscortGroup
local EscortClient = self.EscortClient
@@ -923,7 +923,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
EscortGroupAttack:OptionROEOpenFire()
EscortGroupAttack:OptionROTVertical()
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local Tasks = {}
@@ -945,7 +945,7 @@ function ESCORT:_AssistTarget( EscortGroupAttack, DetectedItem )
)
else
local DetectedSet = self.Detection:GetDetectedSet( DetectedItem )
local DetectedSet = self.Detection:GetDetectedSet( DetectedItemID )
local Tasks = {}
@@ -1152,7 +1152,7 @@ function ESCORT:_ReportTargetsScheduler()
end
local DetectedItems = self.Detection:GetDetectedItems()
self:F( DetectedItems )
self:E( DetectedItems )
local DetectedTargets = false
@@ -1161,42 +1161,36 @@ function ESCORT:_ReportTargetsScheduler()
for ClientEscortGroupName, EscortGroupData in pairs( self.EscortClient._EscortGroups ) do
local ClientEscortTargets = EscortGroupData.Detection
--local EscortUnit = EscortGroupData:GetUnit( 1 )
for DetectedItemIndex, DetectedItem in pairs( DetectedItems ) do
self:F( { DetectedItemIndex, DetectedItem } )
for DetectedItemID, DetectedItem in ipairs( DetectedItems ) do
self:E( { DetectedItemID, DetectedItem } )
-- Remove the sub menus of the Attack menu of the Escort for the EscortGroup.
local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItem, EscortGroupData.EscortGroup, _DATABASE:GetPlayerSettings( self.EscortClient:GetPlayerName() ) )
local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItemID, EscortGroupData )
if ClientEscortGroupName == EscortGroupName then
local DetectedMsg = DetectedItemReportSummary:Text("\n")
DetectedMsgs[#DetectedMsgs+1] = DetectedMsg
self:T( DetectedMsg )
DetectedMsgs[#DetectedMsgs+1] = DetectedItemReportSummary
MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(),
DetectedMsg,
MENU_CLIENT_COMMAND:New( self.EscortClient,
DetectedItemReportSummary,
self.EscortMenuAttackNearbyTargets,
ESCORT._AttackTarget,
self,
DetectedItem
DetectedItemID
)
else
if self.EscortMenuTargetAssistance then
local DetectedMsg = DetectedItemReportSummary:Text("\n")
self:T( DetectedMsg )
local MenuTargetAssistance = MENU_GROUP:New( self.EscortClient:GetGroup(), EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
MENU_GROUP_COMMAND:New( self.EscortClient:GetGroup(),
DetectedMsg,
self:T( DetectedItemReportSummary )
local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
MENU_CLIENT_COMMAND:New( self.EscortClient,
DetectedItemReportSummary,
MenuTargetAssistance,
ESCORT._AssistTarget,
self,
EscortGroupData.EscortGroup,
DetectedItem
DetectedItemID
)
end
end
@@ -1205,9 +1199,9 @@ function ESCORT:_ReportTargetsScheduler()
end
end
self:F( DetectedMsgs )
self:E( DetectedMsgs )
if DetectedTargets then
self.EscortGroup:MessageToClient( "Reporting detected targets:\n" .. table.concat( DetectedMsgs, "\n" ), 20, self.EscortClient )
self.EscortGroup:MessageToClient( "Detected targets:\n" .. table.concat( DetectedMsgs, "\n" ), 20, self.EscortClient )
else
self.EscortGroup:MessageToClient( "No targets detected.", 10, self.EscortClient )
end
@@ -1327,7 +1321,7 @@ function ESCORT:_ReportTargetsScheduler()
--
-- if ClientEscortGroupName == EscortGroupName then
--
-- MENU_GROUP_COMMAND:New( self.EscortClient,
-- MENU_CLIENT_COMMAND:New( self.EscortClient,
-- EscortTargetMessage,
-- self.EscortMenuAttackNearbyTargets,
-- ESCORT._AttackTarget,
@@ -1338,8 +1332,8 @@ function ESCORT:_ReportTargetsScheduler()
-- EscortTargetMessages = EscortTargetMessages .. "\n - " .. EscortTargetMessage
-- else
-- if self.EscortMenuTargetAssistance then
-- local MenuTargetAssistance = MENU_GROUP:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
-- MENU_GROUP_COMMAND:New( self.EscortClient,
-- local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
-- MENU_CLIENT_COMMAND:New( self.EscortClient,
-- EscortTargetMessage,
-- MenuTargetAssistance,
-- ESCORT._AssistTarget,
@@ -1378,7 +1372,7 @@ function ESCORT:_ReportTargetsScheduler()
-- local Distance = ( ( WayPoint.x - EscortVec3.x )^2 +
-- ( WayPoint.y - EscortVec3.z )^2
-- ) ^ 0.5 / 1000
-- MENU_GROUP_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
-- MENU_CLIENT_COMMAND:New( self.EscortClient, "Waypoint " .. WayPointID .. " at " .. string.format( "%.2f", Distance ).. "km", self.EscortMenuResumeMission, ESCORT._ResumeMission, { ParamSelf = self, ParamWayPoint = WayPointID } )
-- end
-- end
--

View File

@@ -3,7 +3,7 @@
-- ===
--
-- 1) @{MissileTrainer#MISSILETRAINER} class, extends @{Base#BASE}
-- ===
-- ===============================================================
-- The @{#MISSILETRAINER} class uses the DCS world messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft,
-- the class will destroy the missile within a certain range, to avoid damage to your aircraft.
-- It suports the following functionality:
@@ -71,7 +71,7 @@
-- ===
--
-- CREDITS
-- ===
-- =======
-- **Stuka (Danny)** Who you can search on the Eagle Dynamics Forums.
-- Working together with Danny has resulted in the MISSILETRAINER class.
-- Danny has shared his ideas and together we made a design.
@@ -99,39 +99,39 @@ function MISSILETRAINER._Alive( Client, self )
if self.MenusOnOff == true then
Client:Message( "Use the 'Radio Menu' -> 'Other (F10)' -> 'Missile Trainer' menu options to change the Missile Trainer settings (for all players).", 15, "Trainer" )
Client.MainMenu = MENU_GROUP:New( Client:GetGroup(), "Missile Trainer", nil ) -- Menu#MENU_GROUP
Client.MainMenu = MENU_CLIENT:New( Client, "Missile Trainer", nil ) -- Menu#MENU_CLIENT
Client.MenuMessages = MENU_GROUP:New( Client:GetGroup(), "Messages", Client.MainMenu )
Client.MenuOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } )
Client.MenuOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } )
Client.MenuMessages = MENU_CLIENT:New( Client, "Messages", Client.MainMenu )
Client.MenuOn = MENU_CLIENT_COMMAND:New( Client, "Messages On", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = true } )
Client.MenuOff = MENU_CLIENT_COMMAND:New( Client, "Messages Off", Client.MenuMessages, self._MenuMessages, { MenuSelf = self, MessagesOnOff = false } )
Client.MenuTracking = MENU_GROUP:New( Client:GetGroup(), "Tracking", Client.MainMenu )
Client.MenuTrackingToAll = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } )
Client.MenuTrackingToTarget = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } )
Client.MenuTrackOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = true } )
Client.MenuTrackOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = false } )
Client.MenuTrackIncrease = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Frequency Increase", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = -1 } )
Client.MenuTrackDecrease = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Frequency Decrease", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = 1 } )
Client.MenuTracking = MENU_CLIENT:New( Client, "Tracking", Client.MainMenu )
Client.MenuTrackingToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = true } )
Client.MenuTrackingToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingToAll = false } )
Client.MenuTrackOn = MENU_CLIENT_COMMAND:New( Client, "Tracking On", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = true } )
Client.MenuTrackOff = MENU_CLIENT_COMMAND:New( Client, "Tracking Off", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingOnOff = false } )
Client.MenuTrackIncrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Increase", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = -1 } )
Client.MenuTrackDecrease = MENU_CLIENT_COMMAND:New( Client, "Frequency Decrease", Client.MenuTracking, self._MenuMessages, { MenuSelf = self, TrackingFrequency = 1 } )
Client.MenuAlerts = MENU_GROUP:New( Client:GetGroup(), "Alerts", Client.MainMenu )
Client.MenuAlertsToAll = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } )
Client.MenuAlertsToTarget = MENU_GROUP_COMMAND:New( Client:GetGroup(), "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } )
Client.MenuHitsOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = true } )
Client.MenuHitsOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = false } )
Client.MenuLaunchesOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = true } )
Client.MenuLaunchesOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = false } )
Client.MenuAlerts = MENU_CLIENT:New( Client, "Alerts", Client.MainMenu )
Client.MenuAlertsToAll = MENU_CLIENT_COMMAND:New( Client, "To All", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = true } )
Client.MenuAlertsToTarget = MENU_CLIENT_COMMAND:New( Client, "To Target", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsToAll = false } )
Client.MenuHitsOn = MENU_CLIENT_COMMAND:New( Client, "Hits On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = true } )
Client.MenuHitsOff = MENU_CLIENT_COMMAND:New( Client, "Hits Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsHitsOnOff = false } )
Client.MenuLaunchesOn = MENU_CLIENT_COMMAND:New( Client, "Launches On", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = true } )
Client.MenuLaunchesOff = MENU_CLIENT_COMMAND:New( Client, "Launches Off", Client.MenuAlerts, self._MenuMessages, { MenuSelf = self, AlertsLaunchesOnOff = false } )
Client.MenuDetails = MENU_GROUP:New( Client:GetGroup(), "Details", Client.MainMenu )
Client.MenuDetailsDistanceOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = true } )
Client.MenuDetailsDistanceOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = false } )
Client.MenuDetailsBearingOn = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = true } )
Client.MenuDetailsBearingOff = MENU_GROUP_COMMAND:New( Client:GetGroup(), "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = false } )
Client.MenuDetails = MENU_CLIENT:New( Client, "Details", Client.MainMenu )
Client.MenuDetailsDistanceOn = MENU_CLIENT_COMMAND:New( Client, "Range On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = true } )
Client.MenuDetailsDistanceOff = MENU_CLIENT_COMMAND:New( Client, "Range Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsRangeOnOff = false } )
Client.MenuDetailsBearingOn = MENU_CLIENT_COMMAND:New( Client, "Bearing On", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = true } )
Client.MenuDetailsBearingOff = MENU_CLIENT_COMMAND:New( Client, "Bearing Off", Client.MenuDetails, self._MenuMessages, { MenuSelf = self, DetailsBearingOnOff = false } )
Client.MenuDistance = MENU_GROUP:New( Client:GetGroup(), "Set distance to plane", Client.MainMenu )
Client.MenuDistance50 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "50 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 50 / 1000 } )
Client.MenuDistance100 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "100 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 100 / 1000 } )
Client.MenuDistance150 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "150 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 150 / 1000 } )
Client.MenuDistance200 = MENU_GROUP_COMMAND:New( Client:GetGroup(), "200 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 200 / 1000 } )
Client.MenuDistance = MENU_CLIENT:New( Client, "Set distance to plane", Client.MainMenu )
Client.MenuDistance50 = MENU_CLIENT_COMMAND:New( Client, "50 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 50 / 1000 } )
Client.MenuDistance100 = MENU_CLIENT_COMMAND:New( Client, "100 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 100 / 1000 } )
Client.MenuDistance150 = MENU_CLIENT_COMMAND:New( Client, "150 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 150 / 1000 } )
Client.MenuDistance200 = MENU_CLIENT_COMMAND:New( Client, "200 meter", Client.MenuDistance, self._MenuMessages, { MenuSelf = self, Distance = 200 / 1000 } )
else
if Client.MainMenu then
Client.MainMenu:Remove()
@@ -177,13 +177,13 @@ function MISSILETRAINER:New( Distance, Briefing )
-- for ClientID, Client in pairs( self.DBClients.Database ) do
-- self:F( "ForEach:" .. Client.UnitName )
-- self:E( "ForEach:" .. Client.UnitName )
-- Client:Alive( self._Alive, self )
-- end
--
self.DBClients:ForEachClient(
function( Client )
self:F( "ForEach:" .. Client.UnitName )
self:E( "ForEach:" .. Client.UnitName )
Client:Alive( self._Alive, self )
end
)
@@ -442,7 +442,7 @@ function MISSILETRAINER._MenuMessages( MenuParameters )
if MenuParameters.Distance ~= nil then
self.Distance = MenuParameters.Distance
MESSAGE:New( "Hit detection distance set to " .. ( self.Distance * 1000 ) .. " meters", 15, "Menu" ):ToAll()
MESSAGE:New( "Hit detection distance set to " .. self.Distance * 1000 .. " meters", 15, "Menu" ):ToAll()
end
end

View File

@@ -1,6 +1,6 @@
--- **Functional** -- Limit the MOVEMENT of simulaneous moving ground vehicles.
--
-- ===
-- ====
--
-- Limit the simultaneous movement of Groups within a running Mission.
-- This module is defined to improve the performance in missions, and to bring additional realism for GROUND vehicles.

View File

@@ -1,305 +0,0 @@
--- **Functional** -- The PROTECT class handles the protection of objects, which can be zones, units, scenery.
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions: **MillerTime**
--
-- ===
--
-- @module Protect
--- @type PROTECT.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
-- @extends Core.Fsm#FSM
--- @type PROTECT
-- @extends #PROTECT.__
--- # PROTECT, extends @{Base#BASE}
--
-- @field #PROTECT
PROTECT = {
ClassName = "PROTECT",
}
--- Get the ProtectZone
-- @param #PROTECT self
-- @return Core.Zone#ZONE_BASE
function PROTECT:GetProtectZone()
return self.ProtectZone
end
--- Get the name of the ProtectZone
-- @param #PROTECT self
-- @return #string
function PROTECT:GetProtectZoneName()
return self.ProtectZone:GetName()
end
--- Set the owning coalition of the zone.
-- @param #PROTECT self
-- @param DCSCoalition.DCSCoalition#coalition Coalition
function PROTECT:SetCoalition( Coalition )
self.Coalition = Coalition
end
--- Get the owning coalition of the zone.
-- @param #PROTECT self
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
function PROTECT:GetCoalition()
return self.Coalition
end
--- Get the owning coalition name of the zone.
-- @param #PROTECT self
-- @return #string Coalition name.
function PROTECT:GetCoalitionName()
if self.Coalition == coalition.side.BLUE then
return "Blue"
end
if self.Coalition == coalition.side.RED then
return "Red"
end
if self.Coalition == coalition.side.NEUTRAL then
return "Neutral"
end
return ""
end
function PROTECT:IsGuarded()
local IsGuarded = self.ProtectZone:IsAllInZoneOfCoalition( self.Coalition )
self:F( { IsGuarded = IsGuarded } )
return IsGuarded
end
function PROTECT:IsCaptured()
local IsCaptured = self.ProtectZone:IsAllInZoneOfOtherCoalition( self.Coalition )
self:F( { IsCaptured = IsCaptured } )
return IsCaptured
end
function PROTECT:IsAttacked()
local IsAttacked = self.ProtectZone:IsSomeInZoneOfCoalition( self.Coalition )
self:F( { IsAttacked = IsAttacked } )
return IsAttacked
end
function PROTECT:IsEmpty()
local IsEmpty = self.ProtectZone:IsNoneInZone()
self:F( { IsEmpty = IsEmpty } )
return IsEmpty
end
--- Check if the units are still alive.
-- @param #PROTECT self
function PROTECT:AreProtectUnitsAlive()
local IsAlive = false
local UnitSet = self.ProtectUnitSet
UnitSet:Flush( self )
local UnitList = UnitSet:GetSet()
for UnitID, ProtectUnit in pairs( UnitList ) do
local IsUnitAlive = ProtectUnit:IsAlive()
if IsUnitAlive == true then
IsAlive = true
break
end
end
return IsAlive
end
--- Check if the statics are still alive.
-- @param #PROTECT self
function PROTECT:AreProtectStaticsAlive()
local IsAlive = false
local StaticSet = self.ProtectStaticSet
StaticSet:Flush( self )
local StaticList = StaticSet:GetSet()
for UnitID, ProtectStatic in pairs( StaticList ) do
local IsStaticAlive = ProtectStatic:IsAlive()
if IsStaticAlive == true then
IsAlive = true
break
end
end
return IsAlive
end
--- Check if there is a capture unit in the zone.
-- @param #PROTECT self
function PROTECT:IsCaptureUnitInZone()
local CaptureUnitSet = self.CaptureUnitSet
CaptureUnitSet:Flush( self )
local IsInZone = self.CaptureUnitSet:IsPartiallyInZone( self.ProtectZone )
self:F({IsInZone = IsInZone})
return IsInZone
end
--- Smoke.
-- @param #PROTECT self
-- @param #SMOKECOLOR.Color SmokeColor
function PROTECT:Smoke( SmokeColor )
self.SmokeColor = SmokeColor
end
--- Flare.
-- @param #PROTECT self
-- @param #SMOKECOLOR.Color FlareColor
function PROTECT:Flare( FlareColor )
self.ProtectZone:FlareZone( FlareColor, math.random( 1, 360 ) )
end
--- Mark.
-- @param #PROTECT self
function PROTECT:Mark()
local Coord = self.ProtectZone:GetCoordinate()
local ZoneName = self:GetProtectZoneName()
local State = self:GetState()
if self.MarkRed and self.MarkBlue then
self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } )
Coord:RemoveMark( self.MarkRed )
Coord:RemoveMark( self.MarkBlue )
end
if self.Coalition == coalition.side.BLUE then
self.MarkBlue = Coord:MarkToCoalitionBlue( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
self.MarkRed = Coord:MarkToCoalitionRed( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
else
self.MarkRed = Coord:MarkToCoalitionRed( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
self.MarkBlue = Coord:MarkToCoalitionBlue( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
end
end
--- Bound.
-- @param #PROTECT self
function PROTECT:onafterStart()
self:ScheduleRepeat( 5, 15, 0.1, nil, self.StatusCoalition, self )
self:ScheduleRepeat( 5, 15, 0.1, nil, self.StatusZone, self )
self:ScheduleRepeat( 10, 15, 0, nil, self.StatusSmoke, self )
end
--- Bound.
-- @param #PROTECT self
function PROTECT:onenterGuarded()
if self.Coalition == coalition.side.BLUE then
--elf.ProtectZone:BoundZone( 12, country.id.USA )
else
--self.ProtectZone:BoundZone( 12, country.id.RUSSIA )
end
self:Mark()
end
function PROTECT:onenterCaptured()
local NewCoalition = self.ProtectZone:GetCoalition()
self:F( { NewCoalition = NewCoalition } )
self:SetCoalition( NewCoalition )
self:Mark()
end
function PROTECT:onenterEmpty()
self:Mark()
end
function PROTECT:onenterAttacked()
self:Mark()
end
--- Check status Coalition ownership.
-- @param #PROTECT self
function PROTECT:StatusCoalition()
self:F( { State = self:GetState() } )
self.ProtectZone:Scan()
if self:IsGuarded() then
self:Guard()
else
if self:IsCaptured() then
self:Capture()
end
end
end
--- Check status Zone.
-- @param #PROTECT self
function PROTECT:StatusZone()
self:F( { State = self:GetState() } )
self.ProtectZone:Scan()
if self:IsAttacked() then
self:Attack()
else
if self:IsEmpty() then
self:Empty()
end
end
end
--- Check status Smoke.
-- @param #PROTECT self
function PROTECT:StatusSmoke()
local CurrentTime = timer.getTime()
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
if self.SmokeColor then
self.ProtectZone:GetCoordinate():Smoke( self.SmokeColor )
--self.SmokeColor = nil
self.SmokeTime = CurrentTime
end
end
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
--- **Functional** -- (R2.0) - Administer the scoring of player achievements, and create a CSV file logging the scoring events for use at team or squadron websites.
--
-- ===
--- **Functional** -- **Administer the SCORING of player achievements,
-- and create a CSV file logging the scoring events for use at team or squadron websites.**
--
-- ![Banner Image](..\Presentations\SCORING\Dia1.JPG)
--
@@ -103,9 +102,7 @@
-- A mission has goals and achievements. The scoring system provides an API to set additional scores when a goal or achievement event happens.
-- Use the method @{#SCORING.AddGoalScore}() to add a score for a Player at any time in your mission.
--
-- ## 1.5) (Decommissioned) Configure fratricide level.
--
-- **This functionality is decomissioned until the DCS bug concerning Unit:destroy() not being functional in multi player for player units has been fixed by ED**.
-- ## 1.5) Configure fratricide level.
--
-- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked.
@@ -179,7 +176,7 @@
-- * @{#SCORING.SetMessagesToCoalition}(): Configure to send messages to only those players within the same coalition as the player.
--
--
-- ===
-- ====
--
-- # **API CHANGE HISTORY**
--
@@ -261,7 +258,7 @@ function SCORING:New( GameName )
-- Configure Messages
self:SetMessagesToAll()
self:SetMessagesHit( false )
self:SetMessagesHit( true )
self:SetMessagesDestroy( true )
self:SetMessagesScore( true )
self:SetMessagesZone( true )
@@ -282,22 +279,8 @@ function SCORING:New( GameName )
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Hit, self._EventOnHit )
self:HandleEvent( EVENTS.Birth )
--self:HandleEvent( EVENTS.PlayerEnterUnit )
self:HandleEvent( EVENTS.PlayerEnterUnit )
self:HandleEvent( EVENTS.PlayerLeaveUnit )
-- During mission startup, especially for single player,
-- iterate the database for the player that has joined, and add him to the scoring, and set the menu.
-- But this can only be started one second after the mission has started, so i need to schedule this ...
self.ScoringPlayerScan = BASE:ScheduleOnce( 1,
function()
for PlayerName, PlayerUnit in pairs( _DATABASE:GetPlayerUnits() ) do
self:_AddPlayerFromUnit( PlayerUnit )
self:SetScoringMenu( PlayerUnit:GetGroup() )
end
end
)
-- Create the CSV file.
self:OpenCSV( GameName )
@@ -584,19 +567,6 @@ function SCORING:SetCoalitionChangePenalty( CoalitionChangePenalty )
end
--- Sets the scoring menu.
-- @param #SCORING self
-- @return #SCORING
function SCORING:SetScoringMenu( ScoringGroup )
local Menu = MENU_GROUP:New( ScoringGroup, 'Scoring and Statistics' )
local ReportGroupSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report players in group', Menu, SCORING.ReportScoreGroupSummary, self, ScoringGroup )
local ReportGroupDetailed = MENU_GROUP_COMMAND:New( ScoringGroup, 'Detailed report players in group', Menu, SCORING.ReportScoreGroupDetailed, self, ScoringGroup )
local ReportToAllSummary = MENU_GROUP_COMMAND:New( ScoringGroup, 'Summary report all players', Menu, SCORING.ReportScoreAllSummary, self, ScoringGroup )
self:SetState( ScoringGroup, "ScoringMenu", Menu )
return self
end
--- Add a new player entering a Unit.
-- @param #SCORING self
-- @param Wrapper.Unit#UNIT UnitData
@@ -638,15 +608,14 @@ function SCORING:_AddPlayerFromUnit( UnitData )
if self.Players[PlayerName].UnitCoalition ~= UnitCoalition then
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + 50
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] ..
MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] ..
"(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.",
MESSAGE.Type.Information
2
):ToAll()
self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -50, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType,
UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
end
end
self.Players[PlayerName].UnitName = UnitName
self.Players[PlayerName].UnitCoalition = UnitCoalition
self.Players[PlayerName].UnitCategory = UnitCategory
@@ -655,59 +624,26 @@ function SCORING:_AddPlayerFromUnit( UnitData )
self.Players[PlayerName].ThreatLevel = UnitThreatLevel
self.Players[PlayerName].ThreatType = UnitThreatType
-- TODO: DCS bug concerning Units with skill level client don't get destroyed in multi player. This logic is deactivated until this bug gets fixed.
--[[
if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 then
if self.Players[PlayerName].PenaltyWarning < 1 then
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty,
MESSAGE.Type.Information
MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty,
30
):ToAll()
self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1
end
end
if self.Players[PlayerName].Penalty > self.Fratricide then
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!",
MESSAGE.Type.Information
MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!",
10
):ToAll()
UnitData:GetGroup():Destroy()
end
--]]
end
end
--- Add a goal score for a player.
-- The method takes the Player name for which the Goal score needs to be set.
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
-- A free text can be given that is shown to the players.
-- The Score can be both positive and negative.
-- @param #SCORING self
-- @param #string PlayerName The name of the Player.
-- @param #string GoalTag The string or identifier that is used in the CSV file to identify the goal (sort or group later in Excel).
-- @param #string Text A free text that is shown to the players.
-- @param #number Score The score can be both positive or negative ( Penalty ).
function SCORING:AddGoalScorePlayer( PlayerName, GoalTag, Text, Score )
self:F( { PlayerName, PlayerName, GoalTag, Text, Score } )
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
if PlayerName then
local PlayerData = self.Players[PlayerName]
PlayerData.Goals[GoalTag] = PlayerData.Goals[GoalTag] or { Score = 0 }
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
PlayerData.Score = PlayerData.Score + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll()
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, nil )
end
end
--- Add a goal score for a player.
-- The method takes the PlayerUnit for which the Goal score needs to be set.
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
@@ -722,7 +658,7 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score )
local PlayerName = PlayerUnit:GetPlayerName()
self:F( { PlayerUnit.UnitName, PlayerName, GoalTag, Text, Score } )
self:E( { PlayerUnit.UnitName, PlayerName, GoalTag, Text, Score } )
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
if PlayerName then
@@ -732,7 +668,7 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score )
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
PlayerData.Score = PlayerData.Score + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll()
MESSAGE:New( self.DisplayMessagePrefix .. Text, 30 ):ToAll()
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() )
end
@@ -750,7 +686,7 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
local PlayerName = PlayerUnit:GetPlayerName()
local MissionName = Mission:GetName()
self:F( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } )
self:E( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } )
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
if PlayerName then
@@ -768,45 +704,12 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
PlayerData.Score = self.Players[PlayerName].Score + Score
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score, MESSAGE.Type.Information ):ToAll()
MESSAGE:New( self.DisplayMessagePrefix .. MissionName .. " : " .. Text .. " Score: " .. Score, 30 ):ToAll()
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
end
end
--- Registers Scores the players completing a Mission Task.
-- @param #SCORING self
-- @param Tasking.Mission#MISSION Mission
-- @param #string PlayerName
-- @param #string Text
-- @param #number Score
function SCORING:_AddMissionGoalScore( Mission, PlayerName, Text, Score )
local MissionName = Mission:GetName()
self:F( { Mission:GetName(), PlayerName, Text, Score } )
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
if PlayerName then
local PlayerData = self.Players[PlayerName]
if not PlayerData.Mission[MissionName] then
PlayerData.Mission[MissionName] = {}
PlayerData.Mission[MissionName].ScoreTask = 0
PlayerData.Mission[MissionName].ScoreMission = 0
end
self:T( PlayerName )
self:T( PlayerData.Mission[MissionName] )
PlayerData.Score = self.Players[PlayerName].Score + Score
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
MESSAGE:NewType( string.format( "%s%s: %s! Player %s receives %d score!", self.DisplayMessagePrefix, Mission:GetText(), Text, PlayerName, Score ), MESSAGE.Type.Information ):ToAll()
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score )
end
end
--- Registers Mission Scores for possible multiple players that contributed in the Mission.
-- @param #SCORING self
@@ -818,20 +721,20 @@ function SCORING:_AddMissionScore( Mission, Text, Score )
local MissionName = Mission:GetName()
self:F( { Mission, Text, Score } )
self:F( self.Players )
self:E( { Mission, Text, Score } )
self:E( self.Players )
for PlayerName, PlayerData in pairs( self.Players ) do
self:F( PlayerData )
self:E( PlayerData )
if PlayerData.Mission[MissionName] then
PlayerData.Score = PlayerData.Score + Score
PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in " .. Mission:GetText() .. ". " ..
MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " ..
Score .. " mission score!",
MESSAGE.Type.Information ):ToAll()
60 ):ToAll()
self:ScoreCSV( PlayerName, "", "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score )
end
@@ -839,30 +742,17 @@ function SCORING:_AddMissionScore( Mission, Text, Score )
end
--- Handles the OnPlayerEnterUnit event for the scoring.
-- @param #SCORING self
-- @param Core.Event#EVENTDATA Event
--function SCORING:OnEventPlayerEnterUnit( Event )
-- if Event.IniUnit then
-- self:_AddPlayerFromUnit( Event.IniUnit )
-- self:SetScoringMenu( Event.IniGroup )
-- end
--end
--- Handles the OnBirth event for the scoring.
-- @param #SCORING self
-- @param Core.Event#EVENTDATA Event
function SCORING:OnEventBirth( Event )
function SCORING:OnEventPlayerEnterUnit( Event )
if Event.IniUnit then
if Event.IniObjectCategory == 1 then
local PlayerName = Event.IniUnit:GetPlayerName()
if PlayerName ~= "" then
self:_AddPlayerFromUnit( Event.IniUnit )
self:SetScoringMenu( Event.IniGroup )
end
end
self:_AddPlayerFromUnit( Event.IniUnit )
local Menu = MENU_GROUP:New( Event.IniGroup, 'Scoring' )
local ReportGroupSummary = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Summary report players in group', Menu, SCORING.ReportScoreGroupSummary, self, Event.IniGroup )
local ReportGroupDetailed = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Detailed report players in group', Menu, SCORING.ReportScoreGroupDetailed, self, Event.IniGroup )
local ReportToAllSummary = MENU_GROUP_COMMAND:New( Event.IniGroup, 'Summary report all players', Menu, SCORING.ReportScoreAllSummary, self, Event.IniGroup )
self:SetState( Event.IniUnit, "ScoringMenu", Menu )
end
end
@@ -871,7 +761,7 @@ end
-- @param Core.Event#EVENTDATA Event
function SCORING:OnEventPlayerLeaveUnit( Event )
if Event.IniUnit then
local Menu = self:GetState( Event.IniUnit:GetGroup(), "ScoringMenu" ) -- Core.Menu#MENU_GROUP
local Menu = self:GetState( Event.IniUnit, "ScoringMenu" ) -- Core.Menu#MENU_GROUP
if Menu then
-- TODO: Check if this fixes #281.
--Menu:Remove()
@@ -1012,19 +902,19 @@ function SCORING:_EventOnHit( Event )
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " ..
:New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " ..
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
MESSAGE.Type.Update
2
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
else
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " ..
:New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " ..
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
MESSAGE.Type.Update
2
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
@@ -1036,19 +926,19 @@ function SCORING:_EventOnHit( Event )
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " ..
:New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " ..
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
MESSAGE.Type.Update
2
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
else
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " ..
:New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " ..
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
MESSAGE.Type.Update
2
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
@@ -1057,8 +947,8 @@ function SCORING:_EventOnHit( Event )
end
else -- A scenery object was hit.
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.",
MESSAGE.Type.Update
:New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.",
2
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
@@ -1118,10 +1008,10 @@ function SCORING:_EventOnHit( Event )
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
:New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
MESSAGE.Type.Update
2
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
@@ -1131,10 +1021,10 @@ function SCORING:_EventOnHit( Event )
PlayerHit.Score = PlayerHit.Score + 1
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " ..
:New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " ..
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
"Score: +" .. PlayerHit.Score .. " = " .. Player.Score - Player.Penalty,
MESSAGE.Type.Update
2
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
@@ -1142,8 +1032,8 @@ function SCORING:_EventOnHit( Event )
end
else -- A scenery object was hit.
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.",
MESSAGE.Type.Update
:New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.",
2
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
@@ -1233,7 +1123,7 @@ function SCORING:_EventOnDeadOrCrash( Event )
local ThreatTypeTarget = TargetThreatType
local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1
local ThreatPenalty = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyPenalty / 10 )
self:F( { ThreatLevel = ThreatPenalty, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } )
self:E( { ThreatLevel = ThreatPenalty, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } )
Player.Penalty = Player.Penalty + ThreatPenalty
TargetDestroy.Penalty = TargetDestroy.Penalty + ThreatPenalty
@@ -1241,19 +1131,19 @@ function SCORING:_EventOnDeadOrCrash( Event )
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " ..
:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " ..
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
MESSAGE.Type.Information
15
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
else
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " ..
:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " ..
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
MESSAGE.Type.Information
15
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
@@ -1268,26 +1158,26 @@ function SCORING:_EventOnDeadOrCrash( Event )
local ThreatLevelPlayer = Player.ThreatLevel / 10 + 1
local ThreatScore = math.ceil( ( ThreatLevelTarget / ThreatLevelPlayer ) * self.ScaleDestroyScore / 10 )
self:F( { ThreatLevel = ThreatScore, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } )
self:E( { ThreatLevel = ThreatScore, ThreatLevelTarget = ThreatLevelTarget, ThreatTypeTarget = ThreatTypeTarget, ThreatLevelPlayer = ThreatLevelPlayer } )
Player.Score = Player.Score + ThreatScore
TargetDestroy.Score = TargetDestroy.Score + ThreatScore
TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " ..
:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " ..
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
MESSAGE.Type.Information
15
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
else
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " ..
:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " ..
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
MESSAGE.Type.Information
15
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
@@ -1301,9 +1191,9 @@ function SCORING:_EventOnDeadOrCrash( Event )
Player.Score = Player.Score + Score
TargetDestroy.Score = TargetDestroy.Score + Score
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " ..
:New( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " ..
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! Total: " .. Player.Score - Player.Penalty,
MESSAGE.Type.Information
15
)
:ToAllIf( self:IfMessagesScore() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesScore() and self:IfMessagesToCoalition() )
@@ -1313,17 +1203,17 @@ function SCORING:_EventOnDeadOrCrash( Event )
-- Check if there are Zones where the destruction happened.
for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do
self:F( { ScoringZone = ScoreZoneData } )
self:E( { ScoringZone = ScoreZoneData } )
local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE
local Score = ScoreZoneData.Score
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
Player.Score = Player.Score + Score
TargetDestroy.Score = TargetDestroy.Score + Score
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
:New( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " ..
"Total: " .. Player.Score - Player.Penalty,
MESSAGE.Type.Information )
15 )
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
@@ -1335,17 +1225,17 @@ function SCORING:_EventOnDeadOrCrash( Event )
else
-- Check if there are Zones where the destruction happened.
for ZoneName, ScoreZoneData in pairs( self.ScoringZones ) do
self:F( { ScoringZone = ScoreZoneData } )
self:E( { ScoringZone = ScoreZoneData } )
local ScoreZone = ScoreZoneData.ScoreZone -- Core.Zone#ZONE_BASE
local Score = ScoreZoneData.Score
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
Player.Score = Player.Score + Score
TargetDestroy.Score = TargetDestroy.Score + Score
MESSAGE
:NewType( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
:New( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " ..
"Total: " .. Player.Score - Player.Penalty,
MESSAGE.Type.Information
15
)
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
@@ -1450,7 +1340,7 @@ function SCORING:ReportDetailedPlayerDestroys( PlayerName )
local PenaltyDestroy = 0
for UnitName, UnitData in pairs( PlayerData.Destroy[CategoryID] ) do
self:F( { UnitData = UnitData } )
self:E( { UnitData = UnitData } )
if UnitData ~= {} then
Score = Score + UnitData.Score
ScoreDestroy = ScoreDestroy + UnitData.ScoreDestroy
@@ -1604,23 +1494,23 @@ function SCORING:ReportScoreGroupSummary( PlayerGroup )
local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName )
ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits
self:F( { ReportHits, ScoreHits, PenaltyHits } )
self:E( { ReportHits, ScoreHits, PenaltyHits } )
local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName )
ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys
self:F( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName )
ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges
self:F( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName )
ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals
self:F( { ReportGoals, ScoreGoals, PenaltyGoals } )
self:E( { ReportGoals, ScoreGoals, PenaltyGoals } )
local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName )
ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
self:E( { ReportMissions, ScoreMissions, PenaltyMissions } )
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
@@ -1632,7 +1522,7 @@ function SCORING:ReportScoreGroupSummary( PlayerGroup )
PlayerScore,
PlayerPenalty
)
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup )
MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup )
end
end
@@ -1656,23 +1546,23 @@ function SCORING:ReportScoreGroupDetailed( PlayerGroup )
local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName )
ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits
self:F( { ReportHits, ScoreHits, PenaltyHits } )
self:E( { ReportHits, ScoreHits, PenaltyHits } )
local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName )
ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys
self:F( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName )
ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges
self:F( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName )
ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals
self:F( { ReportGoals, ScoreGoals, PenaltyGoals } )
self:E( { ReportGoals, ScoreGoals, PenaltyGoals } )
local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName )
ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
self:E( { ReportMissions, ScoreMissions, PenaltyMissions } )
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
@@ -1689,7 +1579,7 @@ function SCORING:ReportScoreGroupDetailed( PlayerGroup )
ReportGoals,
ReportMissions
)
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup )
MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup )
end
end
@@ -1702,33 +1592,31 @@ function SCORING:ReportScoreAllSummary( PlayerGroup )
local PlayerMessage = ""
self:T( { "Summary Score Report of All Players", Players = self.Players } )
self:T( "Report Score All Players" )
for PlayerName, PlayerData in pairs( self.Players ) do
self:T( { PlayerName = PlayerName, PlayerGroup = PlayerGroup } )
if PlayerName then
local ReportHits, ScoreHits, PenaltyHits = self:ReportDetailedPlayerHits( PlayerName )
ReportHits = ReportHits ~= "" and "\n- " .. ReportHits or ReportHits
self:F( { ReportHits, ScoreHits, PenaltyHits } )
self:E( { ReportHits, ScoreHits, PenaltyHits } )
local ReportDestroys, ScoreDestroys, PenaltyDestroys = self:ReportDetailedPlayerDestroys( PlayerName )
ReportDestroys = ReportDestroys ~= "" and "\n- " .. ReportDestroys or ReportDestroys
self:F( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
self:E( { ReportDestroys, ScoreDestroys, PenaltyDestroys } )
local ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges = self:ReportDetailedPlayerCoalitionChanges( PlayerName )
ReportCoalitionChanges = ReportCoalitionChanges ~= "" and "\n- " .. ReportCoalitionChanges or ReportCoalitionChanges
self:F( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
self:E( { ReportCoalitionChanges, ScoreCoalitionChanges, PenaltyCoalitionChanges } )
local ReportGoals, ScoreGoals, PenaltyGoals = self:ReportDetailedPlayerGoals( PlayerName )
ReportGoals = ReportGoals ~= "" and "\n- " .. ReportGoals or ReportGoals
self:F( { ReportGoals, ScoreGoals, PenaltyGoals } )
self:E( { ReportGoals, ScoreGoals, PenaltyGoals } )
local ReportMissions, ScoreMissions, PenaltyMissions = self:ReportDetailedPlayerMissions( PlayerName )
ReportMissions = ReportMissions ~= "" and "\n- " .. ReportMissions or ReportMissions
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
self:E( { ReportMissions, ScoreMissions, PenaltyMissions } )
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
@@ -1740,7 +1628,7 @@ function SCORING:ReportScoreAllSummary( PlayerGroup )
PlayerScore,
PlayerPenalty
)
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Overview ):ToGroup( PlayerGroup )
MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup )
end
end
@@ -1788,7 +1676,7 @@ function SCORING:OpenCSV( ScoringCSV )
error( "A string containing the CSV file name must be given." )
end
else
self:F( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." )
self:E( "The MissionScripting.lua file has not been changed to allow lfs, io and os modules to be used..." )
end
return self
end

View File

@@ -1,6 +1,6 @@
--- **Functional** -- Provides defensive behaviour to a set of SAM sites within a running Mission.
--
-- ===
-- ====
--
-- @module Sead

View File

@@ -1,28 +1,44 @@
--- **Core** -- SPAWN class dynamically spawns new groups of units in your missions.
--- **Functional** -- Spawn dynamically new GROUPs in your missions.
--
-- ![Banner Image](..\Presentations\SPAWN\SPAWN.JPG)
--
-- ===
-- ====
--
-- The documentation of the SPAWN class can be found further in this document.
--
-- ===
-- ====
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPA%20-%20Spawning)
-- # Demo Missions
--
-- ### [SPAWN Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPA%20-%20Spawning)
--
-- ### [SPAWN Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPA%20-%20Spawning)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [SPAWN YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL)
--
-- ===
--
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL)
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ===
-- ### Contributions:
--
-- ### Author: **FlightControl**
-- ### Contributions: A lot of people within this community!
-- * **Aaron**: Posed the idea for Group position randomization at SpawnInZone and make the Unit randomization separate from the Group randomization.
-- * [**Entropy**](https://forums.eagle.ru/member.php?u=111471), **Afinegan**: Came up with the requirement for AIOnOff().
--
-- ===
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
--
-- @module Spawn
----BASE:TraceClass("SPAWN")
--- SPAWN Class
-- @type SPAWN
@@ -39,12 +55,8 @@
--- # SPAWN class, extends @{Base#BASE}
--
-- -- ![Banner Image](..\Presentations\SPAWN\SPAWN.JPG)
--
-- ===
--
-- The SPAWN class allows to spawn dynamically new groups.
-- Each SPAWN object needs to be have related **template groups** setup in the Mission Editor (ME),
-- Each SPAWN object needs to be have a related **template group** setup in the Mission Editor (ME),
-- which is a normal group with the **Late Activation** flag set.
-- This template group will never be activated in your mission.
-- SPAWN uses that **template group** to reference to all the characteristics
@@ -188,7 +200,6 @@
-- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}.
-- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Unit}.
-- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}.
-- * @{#SPAWN.SpawnAtAirbase}(): Spawn a new group at an @{Airbase}, which can be an airdrome, ship or helipad.
--
-- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object.
-- You can use the @{GROUP} object to do further actions with the DCSGroup.
@@ -259,12 +270,8 @@ SPAWN = {
-- @extends Wrapper.Group#GROUP.Takeoff
--- @field #SPAWN.Takeoff Takeoff
SPAWN.Takeoff = {
Air = 1,
Runway = 2,
Hot = 3,
Cold = 4,
}
SPAWN.Takeoff = GROUP.Takeoff
--- @type SPAWN.SpawnZoneTable
-- @list <Core.Zone#ZONE_BASE> SpawnZone
@@ -282,7 +289,7 @@ function SPAWN:New( SpawnTemplatePrefix )
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWN
self:F( { SpawnTemplatePrefix } )
local TemplateGroup = GROUP:FindByName( SpawnTemplatePrefix )
local TemplateGroup = Group.getByName( SpawnTemplatePrefix )
if TemplateGroup then
self.SpawnTemplatePrefix = SpawnTemplatePrefix
self.SpawnIndex = 0
@@ -309,7 +316,6 @@ function SPAWN:New( SpawnTemplatePrefix )
end
self:SetEventPriority( 5 )
self.SpawnHookScheduler = SCHEDULER:New( nil )
return self
end
@@ -327,7 +333,7 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix )
local self = BASE:Inherit( self, BASE:New() )
self:F( { SpawnTemplatePrefix, SpawnAliasPrefix } )
local TemplateGroup = GROUP:FindByName( SpawnTemplatePrefix )
local TemplateGroup = Group.getByName( SpawnTemplatePrefix )
if TemplateGroup then
self.SpawnTemplatePrefix = SpawnTemplatePrefix
self.SpawnAliasPrefix = SpawnAliasPrefix
@@ -355,7 +361,6 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix )
end
self:SetEventPriority( 5 )
self.SpawnHookScheduler = SCHEDULER:New( nil )
return self
end
@@ -515,73 +520,6 @@ function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable )
return self
end
--- Randomize templates to be used as the unit representatives for the Spawned group, defined using a SET_GROUP object.
-- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor,
-- but they will all follow the same Template route and have the same prefix name.
-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group.
-- @param #SPAWN self
-- @param Core.Set#SET_GROUP SpawnTemplateSet A SET_GROUP object set, that contains the groups that are possible unit representatives of the group to be spawned.
-- @return #SPAWN
-- @usage
-- -- NATO Tank Platoons invading Gori.
--
-- -- Choose between different 'US Tank Platoon Template' configurations to be spawned for the
-- -- 'US Tank Platoon Left', 'US Tank Platoon Middle' and 'US Tank Platoon Right' SPAWN objects.
--
-- -- Each new SPAWN will randomize the route, with a defined time interval of 200 seconds with 40% time variation (randomization) and
-- -- with a limit set of maximum 12 Units alive simulteneously and 150 Groups to be spawned during the whole mission.
--
-- Spawn_US_PlatoonSet = SET_GROUP:New():FilterPrefixes( "US Tank Platoon Templates" ):FilterOnce()
--
-- --- Now use the Spawn_US_PlatoonSet to define the templates using InitRandomizeTemplateSet.
-- Spawn_US_Platoon_Left = SPAWN:New( 'US Tank Platoon Left' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
function SPAWN:InitRandomizeTemplateSet( SpawnTemplateSet ) -- R2.3
self:F( { self.SpawnTemplatePrefix } )
self.SpawnTemplatePrefixTable = SpawnTemplateSet:GetSetNames()
self.SpawnRandomizeTemplate = true
for SpawnGroupID = 1, self.SpawnMaxGroups do
self:_RandomizeTemplate( SpawnGroupID )
end
return self
end
--- Randomize templates to be used as the unit representatives for the Spawned group, defined by specifying the prefix names.
-- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor,
-- but they will all follow the same Template route and have the same prefix name.
-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group.
-- @param #SPAWN self
-- @param #string SpawnTemplatePrefixes A string or a list of string that contains the prefixes of the groups that are possible unit representatives of the group to be spawned.
-- @return #SPAWN
-- @usage
-- -- NATO Tank Platoons invading Gori.
--
-- -- Choose between different 'US Tank Platoon Templates' configurations to be spawned for the
-- -- 'US Tank Platoon Left', 'US Tank Platoon Middle' and 'US Tank Platoon Right' SPAWN objects.
--
-- -- Each new SPAWN will randomize the route, with a defined time interval of 200 seconds with 40% time variation (randomization) and
-- -- with a limit set of maximum 12 Units alive simulteneously and 150 Groups to be spawned during the whole mission.
--
-- Spawn_US_Platoon_Left = SPAWN:New( 'US Tank Platoon Left' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
function SPAWN:InitRandomizeTemplatePrefixes( SpawnTemplatePrefixes ) --R2.3
self:F( { self.SpawnTemplatePrefix } )
local SpawnTemplateSet = SET_GROUP:New():FilterPrefixes( SpawnTemplatePrefixes ):FilterOnce()
self:InitRandomizeTemplateSet( SpawnTemplateSet )
return self
end
--- When spawning a new group, make the grouping of the units according the InitGrouping setting.
-- @param #SPAWN self
-- @param #number Grouping Indicates the maximum amount of units in the group.
@@ -631,13 +569,7 @@ end
-- @usage
-- -- RU Su-34 - AI Ship Attack
-- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically.
-- SpawnRU_SU34 = SPAWN
-- :New( 'Su-34' )
-- :Schedule( 2, 3, 1800, 0.4 )
-- :SpawnUncontrolled()
-- :InitRandomizeRoute( 1, 1, 3000 )
-- :InitRepeatOnEngineShutDown()
--
-- SpawnRU_SU34 = SPAWN:New( 'TF1 RU Su-34 Krymsk@AI - Attack Ships' ):Schedule( 2, 3, 1800, 0.4 ):SpawnUncontrolled():InitRandomizeRoute( 1, 1, 3000 ):RepeatOnEngineShutDown()
function SPAWN:InitRepeat()
self:F( { self.SpawnTemplatePrefix, self.SpawnIndex } )
@@ -651,16 +583,6 @@ end
--- Respawn group after landing.
-- @param #SPAWN self
-- @return #SPAWN self
-- @usage
-- -- RU Su-34 - AI Ship Attack
-- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically.
-- SpawnRU_SU34 = SPAWN
-- :New( 'Su-34' )
-- :Schedule( 2, 3, 1800, 0.4 )
-- :SpawnUncontrolled()
-- :InitRandomizeRoute( 1, 1, 3000 )
-- :InitRepeatOnLanding()
--
function SPAWN:InitRepeatOnLanding()
self:F( { self.SpawnTemplatePrefix } )
@@ -675,16 +597,6 @@ end
--- Respawn after landing when its engines have shut down.
-- @param #SPAWN self
-- @return #SPAWN self
-- @usage
-- -- RU Su-34 - AI Ship Attack
-- -- Re-SPAWN the Group(s) after each landing and Engine Shut-Down automatically.
-- SpawnRU_SU34 = SPAWN
-- :New( 'Su-34' )
-- :Schedule( 2, 3, 1800, 0.4 )
-- :SpawnUncontrolled()
-- :InitRandomizeRoute( 1, 1, 3000 )
-- :InitRepeatOnEngineShutDown()
--
function SPAWN:InitRepeatOnEngineShutDown()
self:F( { self.SpawnTemplatePrefix } )
@@ -701,8 +613,7 @@ end
-- @param #SPAWN self
-- @param #string SpawnCleanUpInterval The interval to check for inactive groups within seconds.
-- @return #SPAWN self
-- @usage
-- Spawn_Helicopter:InitCleanUp( 20 ) -- CleanUp the spawning of the helicopters every 20 seconds when they become inactive.
-- @usage Spawn_Helicopter:CleanUp( 20 ) -- CleanUp the spawning of the helicopters every 20 seconds when they become inactive.
function SPAWN:InitCleanUp( SpawnCleanUpInterval )
self:F( { self.SpawnTemplatePrefix, SpawnCleanUpInterval } )
@@ -729,11 +640,7 @@ end
-- @return #SPAWN self
-- @usage
-- -- Define an array of Groups.
-- Spawn_BE_Ground = SPAWN
-- :New( 'BE Ground' )
-- :InitLimit( 2, 24 )
-- :InitArray( 90, 10, 100, 50 )
--
-- Spawn_BE_Ground = SPAWN:New( 'BE Ground' ):InitLimit( 2, 24 ):InitArray( 90, "Diamond", 10, 100, 50 )
function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY )
self:F( { self.SpawnTemplatePrefix, SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY } )
@@ -974,7 +881,9 @@ function SPAWN:SpawnWithIndex( SpawnIndex )
-- If there is a SpawnFunction hook defined, call it.
if self.SpawnFunctionHook then
-- delay calling this for .1 seconds so that it hopefully comes after the BIRTH event of the group.
self.SpawnHookScheduler = SCHEDULER:New()
self.SpawnHookScheduler:Schedule( nil, self.SpawnFunctionHook, { self.SpawnGroups[self.SpawnIndex].Group, unpack( self.SpawnFunctionArguments)}, 0.1 )
-- self.SpawnFunctionHook( self.SpawnGroups[self.SpawnIndex].Group, unpack( self.SpawnFunctionArguments ) )
end
-- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats.
--if self.Repeat then
@@ -1073,53 +982,19 @@ function SPAWN:OnSpawnGroup( SpawnCallBackFunction, ... )
return self
end
--- Will spawn a group at an @{Airbase}.
--- Will spawn a group at an airbase.
-- This method is mostly advisable to be used if you want to simulate spawning units at an airbase.
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
-- You can use the returned group to further define the route to be followed.
--
-- The @{Airbase#AIRBASE} object must refer to a valid airbase known in the sim.
-- You can use the following enumerations to search for the pre-defined airbases on the current known maps of DCS:
--
-- * @{Airbase#AIRBASE.Caucasus}: The airbases on the Caucasus map.
-- * @{Airbase#AIRBASE.Nevada}: The airbases on the Nevada (NTTR) map.
-- * @{Airbase#AIRBASE.Normandy}: The airbases on the Normandy map.
--
-- Use the method @{Airbase#AIRBASE.FindByName}() to retrieve the airbase object.
-- The known AIRBASE objects are automatically imported at mission start by MOOSE.
-- Therefore, there isn't any New() constructor defined for AIRBASE objects.
--
-- Ships and Farps are added within the mission, and are therefore not known.
-- For these AIRBASE objects, there isn't an @{Airbase#AIRBASE} enumeration defined.
-- You need to provide the **exact name** of the airbase as the parameter to the @{Airbase#AIRBASE.FindByName}() method!
--
-- @param #SPAWN self
-- @param Wrapper.Airbase#AIRBASE SpawnAirbase The @{Airbase} where to spawn the group.
-- @param Wrapper.Airbase#AIRBASE Airbase The @{Airbase} where to spawn the group.
-- @param #SPAWN.Takeoff Takeoff (optional) The location and takeoff method. Default is Hot.
-- @param #number TakeoffAltitude (optional) The altitude above the ground.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
-- @usage
-- Spawn_Plane = SPAWN:New( "Plane" )
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Cold )
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Hot )
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Runway )
--
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( "Carrier" ), SPAWN.Takeoff.Cold )
--
-- Spawn_Heli = SPAWN:New( "Heli")
--
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Cold" ), SPAWN.Takeoff.Cold )
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Hot" ), SPAWN.Takeoff.Hot )
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Runway" ), SPAWN.Takeoff.Runway )
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Air" ), SPAWN.Takeoff.Air )
--
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "Carrier" ), SPAWN.Takeoff.Cold )
--
function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude ) -- R2.2
self:F( { self.SpawnTemplatePrefix, SpawnAirbase, Takeoff, TakeoffAltitude } )
function SPAWN:SpawnAtAirbase( Airbase, Takeoff ) -- R2.2
self:F( { self.SpawnTemplatePrefix, Airbase } )
local PointVec3 = SpawnAirbase:GetPointVec3()
local PointVec3 = Airbase:GetPointVec3()
self:T2(PointVec3)
Takeoff = Takeoff or SPAWN.Takeoff.Hot
@@ -1130,87 +1005,34 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude ) -- R2.2
if SpawnTemplate then
self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
local SpawnPoint = SpawnTemplate.route.points[1]
-- These are only for ships.
SpawnPoint.linkUnit = nil
SpawnPoint.helipadId = nil
SpawnPoint.airdromeId = nil
local AirbaseID = SpawnAirbase:GetID()
local AirbaseCategory = SpawnAirbase:GetDesc().category
self:F( { AirbaseCategory = AirbaseCategory } )
if AirbaseCategory == Airbase.Category.SHIP then
SpawnPoint.linkUnit = AirbaseID
SpawnPoint.helipadId = AirbaseID
elseif AirbaseCategory == Airbase.Category.HELIPAD then
SpawnPoint.linkUnit = AirbaseID
SpawnPoint.helipadId = AirbaseID
elseif AirbaseCategory == Airbase.Category.AIRDROME then
SpawnPoint.airdromeId = AirbaseID
end
SpawnPoint.alt = 0
SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
self:T( { "Current point of ", self.SpawnTemplatePrefix, Airbase } )
-- Translate the position of the Group Template to the Vec3.
for UnitID = 1, #SpawnTemplate.units do
self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
-- These cause a lot of confusion.
local UnitTemplate = SpawnTemplate.units[UnitID]
UnitTemplate.parking = nil
UnitTemplate.parking_id = nil
UnitTemplate.alt = 0
local SX = UnitTemplate.x
local SY = UnitTemplate.y
local BX = SpawnPoint.x
local BY = SpawnPoint.y
local BX = SpawnTemplate.route.points[1].x
local BY = SpawnTemplate.route.points[1].y
local TX = PointVec3.x + ( SX - BX )
local TY = PointVec3.z + ( SY - BY )
UnitTemplate.x = TX
UnitTemplate.y = TY
if Takeoff == GROUP.Takeoff.Air then
UnitTemplate.alt = PointVec3.y + ( TakeoffAltitude or 200 )
--else
-- UnitTemplate.alt = PointVec3.y + 10
end
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y )
SpawnTemplate.units[UnitID].x = TX
SpawnTemplate.units[UnitID].y = TY
SpawnTemplate.units[UnitID].alt = PointVec3.y
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
end
SpawnPoint.x = PointVec3.x
SpawnPoint.y = PointVec3.z
SpawnTemplate.route.points[1].x = PointVec3.x
SpawnTemplate.route.points[1].y = PointVec3.z
SpawnTemplate.route.points[1].alt = Airbase.y
SpawnTemplate.route.points[1].type = GROUPTEMPLATE.Takeoff[Takeoff]
SpawnTemplate.route.points[1].airdromeId = Airbase:GetID()
if Takeoff == GROUP.Takeoff.Air then
SpawnPoint.alt = PointVec3.y + ( TakeoffAltitude or 200 )
--else
-- SpawnPoint.alt = PointVec3.y + 10
end
SpawnTemplate.x = PointVec3.x
SpawnTemplate.y = PointVec3.z
local GroupSpawned = self:SpawnWithIndex( self.SpawnIndex )
-- When spawned in the air, we need to generate a Takeoff Event
if Takeoff == GROUP.Takeoff.Air then
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 1 )
end
end
return GroupSpawned
return self:SpawnWithIndex( self.SpawnIndex )
end
end
@@ -1246,8 +1068,6 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
if SpawnTemplate then
self:T( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } )
local TemplateHeight = SpawnTemplate.route.points[1].alt
-- Translate the position of the Group Template to the Vec3.
for UnitID = 1, #SpawnTemplate.units do
@@ -1261,20 +1081,16 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
local TY = Vec3.z + ( SY - BY )
SpawnTemplate.units[UnitID].x = TX
SpawnTemplate.units[UnitID].y = TY
if SpawnTemplate.CategoryID ~= Group.Category.SHIP then
SpawnTemplate.units[UnitID].alt = Vec3.y or TemplateHeight
end
SpawnTemplate.units[UnitID].alt = Vec3.y
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
end
SpawnTemplate.route.points[1].x = Vec3.x
SpawnTemplate.route.points[1].y = Vec3.z
if SpawnTemplate.CategoryID ~= Group.Category.SHIP then
SpawnTemplate.route.points[1].alt = Vec3.y or TemplateHeight
end
SpawnTemplate.route.points[1].alt = Vec3.y
SpawnTemplate.x = Vec3.x
SpawnTemplate.y = Vec3.z
SpawnTemplate.alt = Vec3.y or TemplateHeight
return self:SpawnWithIndex( self.SpawnIndex )
end
@@ -1289,31 +1105,14 @@ end
-- You can use the returned group to further define the route to be followed.
-- @param #SPAWN self
-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 coordinates where to spawn the group.
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
-- @usage
--
-- local SpawnVec2 = ZONE:New( ZoneName ):GetVec2()
--
-- -- Spawn at the zone center position at the height specified in the ME of the group template!
-- SpawnAirplanes:SpawnFromVec2( SpawnVec2 )
--
-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnFromVec2( SpawnVec2, 2000, 4000 )
--
function SPAWN:SpawnFromVec2( Vec2, MinHeight, MaxHeight, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, self.SpawnIndex, Vec2, MinHeight, MaxHeight, SpawnIndex } )
function SPAWN:SpawnFromVec2( Vec2, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, Vec2, SpawnIndex } )
local Height = nil
if MinHeight and MaxHeight then
Height = math.random( MinHeight, MaxHeight)
end
return self:SpawnFromVec3( { x = Vec2.x, y = Height, z = Vec2.y }, SpawnIndex ) -- y can be nil. In this case, spawn on the ground for vehicles, and in the template altitude for air.
local PointVec2 = POINT_VEC2:NewFromVec2( Vec2 )
return self:SpawnFromVec3( PointVec2:GetVec3(), SpawnIndex )
end
@@ -1322,26 +1121,14 @@ end
-- You can use the returned group to further define the route to be followed.
-- @param #SPAWN self
-- @param Wrapper.Unit#UNIT HostUnit The air or ground unit dropping or unloading the group.
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
-- @usage
--
-- local SpawnStatic = STATIC:FindByName( StaticName )
--
-- -- Spawn from the static position at the height specified in the ME of the group template!
-- SpawnAirplanes:SpawnFromUnit( SpawnStatic )
--
-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnFromUnit( SpawnStatic, 2000, 4000 )
--
function SPAWN:SpawnFromUnit( HostUnit, MinHeight, MaxHeight, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, HostUnit, MinHeight, MaxHeight, SpawnIndex } )
function SPAWN:SpawnFromUnit( HostUnit, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, HostUnit, SpawnIndex } )
if HostUnit and HostUnit:IsAlive() ~= nil then -- and HostUnit:getUnit(1):inAir() == false then
return self:SpawnFromVec2( HostUnit:GetVec2(), MinHeight, MaxHeight, SpawnIndex )
return self:SpawnFromVec3( HostUnit:GetVec3(), SpawnIndex )
end
return nil
@@ -1351,26 +1138,14 @@ end
-- You can use the returned group to further define the route to be followed.
-- @param #SPAWN self
-- @param Wrapper.Static#STATIC HostStatic The static dropping or unloading the group.
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
-- @usage
--
-- local SpawnStatic = STATIC:FindByName( StaticName )
--
-- -- Spawn from the static position at the height specified in the ME of the group template!
-- SpawnAirplanes:SpawnFromStatic( SpawnStatic )
--
-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnFromStatic( SpawnStatic, 2000, 4000 )
--
function SPAWN:SpawnFromStatic( HostStatic, MinHeight, MaxHeight, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, HostStatic, MinHeight, MaxHeight, SpawnIndex } )
function SPAWN:SpawnFromStatic( HostStatic, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, HostStatic, SpawnIndex } )
if HostStatic and HostStatic:IsAlive() then
return self:SpawnFromVec2( HostStatic:GetVec2(), MinHeight, MaxHeight, SpawnIndex )
return self:SpawnFromVec3( HostStatic:GetVec3(), SpawnIndex )
end
return nil
@@ -1383,38 +1158,17 @@ end
-- @param #SPAWN self
-- @param Core.Zone#ZONE Zone The zone where the group is to be spawned.
-- @param #boolean RandomizeGroup (optional) Randomization of the @{Group} position in the zone.
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil when nothing was spawned.
-- @usage
--
-- local SpawnZone = ZONE:New( ZoneName )
--
-- -- Spawn at the zone center position at the height specified in the ME of the group template!
-- SpawnAirplanes:SpawnInZone( SpawnZone )
--
-- -- Spawn in the zone at a random position at the height specified in the Me of the group template.
-- SpawnAirplanes:SpawnInZone( SpawnZone, true )
--
-- -- Spawn in the zone at a random position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnInZone( SpawnZone, true, 2000, 4000 )
--
-- -- Spawn at the zone center position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnInZone( SpawnZone, false, 2000, 4000 )
--
-- -- Spawn at the zone center position at the height randomized between 2000 and 4000 meters.
-- SpawnAirplanes:SpawnInZone( SpawnZone, nil, 2000, 4000 )
--
function SPAWN:SpawnInZone( Zone, RandomizeGroup, MinHeight, MaxHeight, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, Zone, RandomizeGroup, MinHeight, MaxHeight, SpawnIndex } )
function SPAWN:SpawnInZone( Zone, RandomizeGroup, SpawnIndex )
self:F( { self.SpawnTemplatePrefix, Zone, RandomizeGroup, SpawnIndex } )
if Zone then
if RandomizeGroup then
return self:SpawnFromVec2( Zone:GetRandomVec2(), MinHeight, MaxHeight, SpawnIndex )
return self:SpawnFromVec2( Zone:GetRandomVec2(), SpawnIndex )
else
return self:SpawnFromVec2( Zone:GetVec2(), MinHeight, MaxHeight, SpawnIndex )
return self:SpawnFromVec2( Zone:GetVec2(), SpawnIndex )
end
end
@@ -1927,7 +1681,6 @@ function SPAWN:_GetSpawnIndex( SpawnIndex )
if ( self.SpawnMaxGroups == 0 ) or ( SpawnIndex <= self.SpawnMaxGroups ) then
if ( self.SpawnMaxUnitsAlive == 0 ) or ( self.AliveUnits + #self.SpawnTemplate.units <= self.SpawnMaxUnitsAlive ) or self.UnControlled == true then
self:F( { SpawnCount = self.SpawnCount, SpawnIndex = SpawnIndex } )
if SpawnIndex and SpawnIndex >= self.SpawnCount + 1 then
self.SpawnCount = self.SpawnCount + 1
SpawnIndex = self.SpawnCount

View File

@@ -1,763 +0,0 @@
--- **Functional** -- (R2.3) Models the process to zone guarding and capturing.
--
-- ===
--
-- ![Banner Image](..\Presentations\ZONE_CAPTURE_COALITION\Dia1.JPG)
--
-- ===
--
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAZ - Capture Zones)
--
-- - CAZ-000 - Capture Zone: Demonstrates the basic concept of capturing a zone.
--
-- ===
--
-- ### [YouTube Playlist](https://www.youtube.com/watch?v=0m6K6Yxa-os&list=PL7ZUrU4zZUl0qqJsfa8DPvZWDY-OyDumE)
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Contributions: **Millertime** - Concept
--
-- ===
--
-- @module ZoneCaptureCoalition
do -- ZONE_CAPTURE_COALITION
--- @type ZONE_CAPTURE_COALITION
-- @extends Functional.ZoneGoalCoalition#ZONE_GOAL_COALITION
--- # ZONE\_CAPTURE\_COALITION class, extends @{ZoneGoalCoalition#ZONE_GOAL_COALITION}
--
-- Models the process to capture a Zone for a Coalition, which is guarded by another Coalition.
-- This is a powerful concept that allows to create very dynamic missions based on the different state transitions of various zones.
--
-- ---
--
-- ![Banner Image](..\Presentations\ZONE_CAPTURE_COALITION\Dia1.JPG)
--
-- ---
--
-- # 0. Player Experience
--
-- ![States](..\Presentations\ZONE_CAPTURE_COALITION\Dia3.JPG)
--
-- The above models the possible state transitions between the **Guarded**, **Attacked**, **Empty** and **Captured** states.
-- A zone has an __owning coalition__, that means that at a specific point in time, a zone can be owned by the red or blue coalition.
--
-- The Zone can be in the state **Guarded** by the __owning coalition__, which is the coalition that initially occupies the zone with units of its coalition.
-- Once units of an other coalition are entering the Zone, the state will change to **Attacked**. As long as these units remain in the zone, the state keeps set to Attacked.
-- When all units are destroyed in the Zone, the state will change to **Empty**, which expresses that the Zone is empty, and can be captured.
-- When units of the other coalition are in the Zone, and no other units of the owning coalition is in the Zone, the Zone is captured, and its state will change to **Captured**.
--
-- The zone needs to be monitored regularly for the presence of units to interprete the correct state transition required.
-- This monitoring process MUST be started using the @{#ZONE_CAPTURE_COALITION.Start}() method.
-- Otherwise no monitoring will be active and the zone will stay in the current state forever.
-- See further in chapter 3.3 for more information about this.
--
-- ## 1. ZONE\_CAPTURE\_COALITION constructor
--
-- * @{#ZONE_CAPTURE_COALITION.New}(): Creates a new ZONE\_CAPTURE\_COALITION object.
--
-- In order to use ZONE\_CAPTURE\_COALITION, you need to:
--
-- - Create a @{Zone} object from one of the ZONE\_ classes. Note that ZONE\_POLYGON\_ classes are not yet functional. The only functional ZONE\_ classses are those derived from a ZONE\_RADIUS.
--
-- ![New](..\Presentations\ZONE_CAPTURE_COALITION\Dia5.JPG)
--
-- Ensure that during the life cycle of the ZONE\_CAPTURE\_COALITION object, the object keeps alive.
-- It is best to declare the object globally within your script.
--
-- ## 2. ZONE\_CAPTURE\_COALITION is a finite state machine (FSM).
--
-- ![States](..\Presentations\ZONE_CAPTURE_COALITION\Dia4.JPG)
--
-- ### 2.1 ZONE\_CAPTURE\_COALITION States
--
-- * **Captured**: The Zone has been captured by an other coalition.
-- * **Attacked**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
-- * **Guarded**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
--
-- ### 2.2 ZONE\_CAPTURE\_COALITION Events
--
-- * **Capture**: The Zone has been captured by an other coalition.
-- * **Attack**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
-- * **Guard**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
--
-- ## 3. "Script It"
--
-- ZONE\_CAPTURE\_COALITION allows to take action on the various state transitions and add your custom code and logic.
--
-- ### 3.1. Take action using state- and event handlers.
--
-- ![States](..\Presentations\ZONE_CAPTURE_COALITION\Dia6.JPG)
--
-- The most important to understand is how states and events can be tailored.
-- Carefully study the diagram and the explanations.
--
-- **State Handlers** capture the moment:
--
-- - On Leave from the old state. Return false to cancel the transition.
-- - On Enter to the new state.
--
-- **Event Handlers** capture the moment:
--
-- - On Before the event is triggered. Return false to cancel the transition.
-- - On After the event is triggered.
--
--
--
-- ![States](..\Presentations\ZONE_CAPTURE_COALITION\Dia7.JPG)
--
-- Each handler can receive optionally 3 parameters:
--
-- - **From**: A string containing the From State.
-- - **Event**: A string containing the Event.
-- - **To**: A string containing the To State.
--
-- The mission designer can use these values to alter the logic.
-- For example:
--
-- --- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterGuarded( From, Event, To )
-- if From ~= "Empty" then
-- -- Display a message
-- end
-- end
--
-- This code checks that when the __Guarded__ state has been reached, that if the **From** state was __Empty__, then display a message.
--
-- ### 3.2. Example Event Handler.
--
-- --- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterGuarded( From, Event, To )
-- if From ~= To then
-- local Coalition = self:GetCoalition()
-- self:E( { Coalition = Coalition } )
-- if Coalition == coalition.side.BLUE then
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.Blue )
-- US_CC:MessageTypeToCoalition( string.format( "%s is under protection of the USA", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- RU_CC:MessageTypeToCoalition( string.format( "%s is under protection of the USA", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- else
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.Red )
-- RU_CC:MessageTypeToCoalition( string.format( "%s is under protection of Russia", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- US_CC:MessageTypeToCoalition( string.format( "%s is under protection of Russia", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- end
-- end
-- end
--
-- ### 3.3. Stop and Start the zone monitoring process.
--
-- At regular intervals, the state of the zone needs to be monitored.
-- The zone needs to be scanned for the presence of units within the zone boundaries.
-- Depending on the owning coalition of the zone and the presence of units (of the owning and/or other coalition(s)), the zone will transition to another state.
--
-- However, ... this scanning process is rather CPU intensive. Imagine you have 10 of these capture zone objects setup within your mission.
-- That would mean that your mission would check 10 capture zones simultaneously, each checking for the presence of units.
-- It would be highly **CPU inefficient**, as some of these zones are not required to be monitored (yet).
--
-- Therefore, the mission designer is given 2 methods that allow to take control of the CPU utilization efficiency:
--
-- - @{#ZONE_CAPTURE_COALITION.Start()}(): This starts the monitoring process.
-- - @{#ZONE_CAPTURE_COALITION.Stop()}(): This stops the monitoring process.
--
-- ### IMPORTANT
--
-- **Each capture zone object must have the monitoring process started specifically.
-- The monitoring process is NOT started by default!!!**
--
--
-- ## 4. Full Example
--
-- The following annotated code shows a real example of how ZONE\_CAPTURE\_COALITION can be applied.
--
-- The concept is simple.
--
-- The USA (US), blue coalition, needs to capture the Russian (RU), red coalition, zone, which is near groom lake.
--
-- A capture zone has been setup that guards the presence of the troops.
-- Troops are guarded by red forces. Blue is required to destroy the red forces and capture the zones.
--
-- At first, we setup the Command Centers
--
-- do
--
-- RU_CC = COMMANDCENTER:New( GROUP:FindByName( "REDHQ" ), "Russia HQ" )
-- US_CC = COMMANDCENTER:New( GROUP:FindByName( "BLUEHQ" ), "USA HQ" )
--
-- end
--
-- Next, we define the mission, and add some scoring to it.
--
-- do -- Missions
--
-- US_Mission_EchoBay = MISSION:New( US_CC, "Echo Bay", "Primary",
-- "Welcome trainee. The airport Groom Lake in Echo Bay needs to be captured.\n" ..
-- "There are five random capture zones located at the airbase.\n" ..
-- "Move to one of the capture zones, destroy the fuel tanks in the capture zone, " ..
-- "and occupy each capture zone with a platoon.\n " ..
-- "Your orders are to hold position until all capture zones are taken.\n" ..
-- "Use the map (F10) for a clear indication of the location of each capture zone.\n" ..
-- "Note that heavy resistance can be expected at the airbase!\n" ..
-- "Mission 'Echo Bay' is complete when all five capture zones are taken, and held for at least 5 minutes!"
-- , coalition.side.RED )
--
-- US_Mission_EchoBay:Start()
--
-- end
--
--
-- Now the real work starts.
-- We define a **CaptureZone** object, which is a ZONE object.
-- Within the mission, a trigger zone is created with the name __CaptureZone__, with the defined radius within the mission editor.
--
-- CaptureZone = ZONE:New( "CaptureZone" )
--
-- Next, we define the **ZoneCaptureCoalition** object, as explained above.
--
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( CaptureZone, coalition.side.RED )
--
-- Of course, we want to let the **ZoneCaptureCoalition** object do something when the state transitions.
-- Do accomodate this, it is very simple, as explained above.
-- We use **Event Handlers** to tailor the logic.
--
-- Here we place an Event Handler at the Guarded event. So when the **Guarded** event is triggered, then this method is called!
-- With the variables **From**, **Event**, **To**. Each of these variables containing a string.
--
-- We check if the previous state wasn't Guarded also.
-- If not, we retrieve the owning Coalition of the **ZoneCaptureCoalition**, using `self:GetCoalition()`.
-- So **Coalition** will contain the current owning coalition of the zone.
--
-- Depending on the zone ownership, different messages are sent.
-- Note the methods `ZoneCaptureCoalition:GetZoneName()`.
--
-- --- @param Functional.ZoneCaptureCoalition#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterGuarded( From, Event, To )
-- if From ~= To then
-- local Coalition = self:GetCoalition()
-- self:E( { Coalition = Coalition } )
-- if Coalition == coalition.side.BLUE then
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.Blue )
-- US_CC:MessageTypeToCoalition( string.format( "%s is under protection of the USA", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- RU_CC:MessageTypeToCoalition( string.format( "%s is under protection of the USA", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- else
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.Red )
-- RU_CC:MessageTypeToCoalition( string.format( "%s is under protection of Russia", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- US_CC:MessageTypeToCoalition( string.format( "%s is under protection of Russia", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- end
-- end
-- end
--
-- As you can see, not a rocket science.
-- Next is the Event Handler when the **Empty** state transition is triggered.
-- Now we smoke the ZoneCaptureCoalition with a green color, using `self:Smoke( SMOKECOLOR.Green )`.
--
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterEmpty()
-- self:Smoke( SMOKECOLOR.Green )
-- US_CC:MessageTypeToCoalition( string.format( "%s is unprotected, and can be captured!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- RU_CC:MessageTypeToCoalition( string.format( "%s is unprotected, and can be captured!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- end
--
-- The next Event Handlers speak for itself.
-- When the zone is Attacked, we smoke the zone white and send some messages to each coalition.
--
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterAttacked()
-- ZoneCaptureCoalition:Smoke( SMOKECOLOR.White )
-- local Coalition = self:GetCoalition()
-- self:E({Coalition = Coalition})
-- if Coalition == coalition.side.BLUE then
-- US_CC:MessageTypeToCoalition( string.format( "%s is under attack by Russia", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- RU_CC:MessageTypeToCoalition( string.format( "We are attacking %s", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- else
-- RU_CC:MessageTypeToCoalition( string.format( "%s is under attack by the USA", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- US_CC:MessageTypeToCoalition( string.format( "We are attacking %s", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- end
-- end
--
-- When the zone is Captured, we send some victory or loss messages to the correct coalition.
-- And we add some score.
--
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterCaptured()
-- local Coalition = self:GetCoalition()
-- self:E({Coalition = Coalition})
-- if Coalition == coalition.side.BLUE then
-- RU_CC:MessageTypeToCoalition( string.format( "%s is captured by the USA, we lost it!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- US_CC:MessageTypeToCoalition( string.format( "We captured %s, Excellent job!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- else
-- US_CC:MessageTypeToCoalition( string.format( "%s is captured by Russia, we lost it!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- RU_CC:MessageTypeToCoalition( string.format( "We captured %s, Excellent job!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- end
--
-- self:__Guard( 30 )
-- end
--
-- And this call is the most important of all!
-- In the context of the mission, we need to start the zone capture monitoring process.
-- Or nothing will be monitored and the zone won't change states.
-- We start the monitoring after 5 seconds, and will repeat every 30 seconds a check.
--
-- ZoneCaptureCoalition:Start( 5, 30 )
--
--
-- @field #ZONE_CAPTURE_COALITION
ZONE_CAPTURE_COALITION = {
ClassName = "ZONE_CAPTURE_COALITION",
}
--- @field #table ZONE_CAPTURE_COALITION.States
ZONE_CAPTURE_COALITION.States = {}
--- ZONE_CAPTURE_COALITION Constructor.
-- @param #ZONE_CAPTURE_COALITION self
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
-- @return #ZONE_CAPTURE_COALITION
-- @usage
--
-- AttackZone = ZONE:New( "AttackZone" )
--
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( AttackZone, coalition.side.RED ) -- Create a new ZONE_CAPTURE_COALITION object of zone AttackZone with ownership RED coalition.
-- ZoneCaptureCoalition:__Guard( 1 ) -- Start the Guarding of the AttackZone.
--
function ZONE_CAPTURE_COALITION:New( Zone, Coalition )
local self = BASE:Inherit( self, ZONE_GOAL_COALITION:New( Zone, Coalition ) ) -- #ZONE_CAPTURE_COALITION
self:F( { Zone = Zone, Coalition = Coalition } )
do
--- Captured State Handler OnLeave for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveCaptured
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Captured State Handler OnEnter for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterCaptured
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
end
do
--- Attacked State Handler OnLeave for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveAttacked
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Attacked State Handler OnEnter for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterAttacked
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
end
do
--- Guarded State Handler OnLeave for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveGuarded
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Guarded State Handler OnEnter for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterGuarded
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
end
do
--- Empty State Handler OnLeave for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveEmpty
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Empty State Handler OnEnter for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterEmpty
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
end
self:AddTransition( "*", "Guard", "Guarded" )
--- Guard Handler OnBefore for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeGuard
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Guard Handler OnAfter for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterGuard
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Guard Trigger for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] Guard
-- @param #ZONE_CAPTURE_COALITION self
--- Guard Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] __Guard
-- @param #ZONE_CAPTURE_COALITION self
-- @param #number Delay
self:AddTransition( "*", "Empty", "Empty" )
--- Empty Handler OnBefore for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeEmpty
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Empty Handler OnAfter for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterEmpty
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Empty Trigger for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] Empty
-- @param #ZONE_CAPTURE_COALITION self
--- Empty Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] __Empty
-- @param #ZONE_CAPTURE_COALITION self
-- @param #number Delay
self:AddTransition( { "Guarded", "Empty" }, "Attack", "Attacked" )
--- Attack Handler OnBefore for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeAttack
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Attack Handler OnAfter for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterAttack
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Attack Trigger for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] Attack
-- @param #ZONE_CAPTURE_COALITION self
--- Attack Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] __Attack
-- @param #ZONE_CAPTURE_COALITION self
-- @param #number Delay
self:AddTransition( { "Guarded", "Attacked", "Empty" }, "Capture", "Captured" )
--- Capture Handler OnBefore for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeCapture
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Capture Handler OnAfter for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterCapture
-- @param #ZONE_CAPTURE_COALITION self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Capture Trigger for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] Capture
-- @param #ZONE_CAPTURE_COALITION self
--- Capture Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
-- @function [parent=#ZONE_CAPTURE_COALITION] __Capture
-- @param #ZONE_CAPTURE_COALITION self
-- @param #number Delay
return self
end
--- @param #ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:onenterCaptured()
self:GetParent( self, ZONE_CAPTURE_COALITION ).onenterCaptured( self )
self.Goal:Achieved()
end
function ZONE_CAPTURE_COALITION:IsGuarded()
local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition )
self:F( { IsGuarded = IsGuarded } )
return IsGuarded
end
function ZONE_CAPTURE_COALITION:IsEmpty()
local IsEmpty = self.Zone:IsNoneInZone()
self:F( { IsEmpty = IsEmpty } )
return IsEmpty
end
function ZONE_CAPTURE_COALITION:IsCaptured()
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
self:F( { IsCaptured = IsCaptured } )
return IsCaptured
end
function ZONE_CAPTURE_COALITION:IsAttacked()
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
self:F( { IsAttacked = IsAttacked } )
return IsAttacked
end
--- Mark.
-- @param #ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:Mark()
local Coord = self.Zone:GetCoordinate()
local ZoneName = self:GetZoneName()
local State = self:GetState()
if self.MarkRed and self.MarkBlue then
self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } )
Coord:RemoveMark( self.MarkRed )
Coord:RemoveMark( self.MarkBlue )
end
if self.Coalition == coalition.side.BLUE then
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
else
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Red\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Red\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
end
end
--- Bound.
-- @param #ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:onenterGuarded()
--self:GetParent( self ):onenterGuarded()
if self.Coalition == coalition.side.BLUE then
--elf.ProtectZone:BoundZone( 12, country.id.USA )
else
--self.ProtectZone:BoundZone( 12, country.id.RUSSIA )
end
self:Mark()
end
function ZONE_CAPTURE_COALITION:onenterCaptured()
--self:GetParent( self ):onenterCaptured()
local NewCoalition = self.Zone:GetScannedCoalition()
self:F( { NewCoalition = NewCoalition } )
self:SetCoalition( NewCoalition )
self:Mark()
end
function ZONE_CAPTURE_COALITION:onenterEmpty()
--self:GetParent( self ):onenterEmpty()
self:Mark()
end
function ZONE_CAPTURE_COALITION:onenterAttacked()
--self:GetParent( self ):onenterAttacked()
self:Mark()
end
--- When started, check the Coalition status.
-- @param #ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:onafterGuard()
--self:F({BASE:GetParent( self )})
--BASE:GetParent( self ).onafterGuard( self )
if not self.SmokeScheduler then
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self )
end
end
function ZONE_CAPTURE_COALITION:IsCaptured()
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
self:F( { IsCaptured = IsCaptured } )
return IsCaptured
end
function ZONE_CAPTURE_COALITION:IsAttacked()
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
self:F( { IsAttacked = IsAttacked } )
return IsAttacked
end
--- Check status Coalition ownership.
-- @param #ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:StatusZone()
local State = self:GetState()
self:F( { State = self:GetState() } )
self:GetParent( self, ZONE_CAPTURE_COALITION ).StatusZone( self )
if State ~= "Guarded" and self:IsGuarded() then
self:Guard()
end
if State ~= "Empty" and self:IsEmpty() then
self:Empty()
end
if State ~= "Attacked" and self:IsAttacked() then
self:Attack()
end
if State ~= "Captured" and self:IsCaptured() then
self:Capture()
end
end
--- Starts the zone capturing monitoring process.
-- This process can be CPU intensive, ensure that you specify reasonable time intervals for the monitoring process.
-- Note that the monitoring process is NOT started automatically during the `:New()` constructor.
-- It is advised that the zone monitoring process is only started when the monitoring is of relevance in context of the current mission goals.
-- When the zone is of no relevance, it is advised NOT to start the monitoring process, or to stop the monitoring process to save CPU resources.
-- Therefore, the mission designer will need to use the `:Start()` method within his script to start the monitoring process specifically.
-- @param #ZONE_CAPTURE_COALITION self
-- @param #number StartInterval (optional) Specifies the start time interval in seconds when the zone state will be checked for the first time.
-- @param #number RepeatInterval (optional) Specifies the repeat time interval in seconds when the zone state will be checked repeatedly.
-- @usage
--
-- -- Setup the zone.
-- CaptureZone = ZONE:New( "CaptureZone" )
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( CaptureZone, coalition.side.RED )
--
-- -- This starts the monitoring process within 15 seconds, repeating every 15 seconds.
-- ZoneCaptureCoalition:Start()
--
-- -- This starts the monitoring process immediately, but repeats every 30 seconds.
-- ZoneCaptureCoalition:Start( 0, 30 )
--
function ZONE_CAPTURE_COALITION:Start( StartInterval, RepeatInterval )
StartInterval = StartInterval or 15
RepeatInterval = RepeatInterval or 15
if self.ScheduleStatusZone then
self:ScheduleStop( self.ScheduleStatusZone )
end
self.ScheduleStatusZone = self:ScheduleRepeat( StartInterval, RepeatInterval, 0.1, nil, self.StatusZone, self )
end
--- Stops the zone capturing monitoring process.
-- When the zone capturing monitor process is stopped, there won't be any changes anymore in the state and the owning coalition of the zone.
-- This method becomes really useful when the zone is of no relevance anymore within a long lasting mission.
-- In this case, it is advised to stop the monitoring process, not to consume unnecessary the CPU intensive scanning of units presence within the zone.
-- @param #ZONE_CAPTURE_COALITION self
-- @usage
-- -- Setup the zone.
-- CaptureZone = ZONE:New( "CaptureZone" )
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( CaptureZone, coalition.side.RED )
--
-- -- This starts the monitoring process within 15 seconds, repeating every 15 seconds.
-- ZoneCaptureCoalition:Start()
--
-- -- When the zone capturing is of no relevance anymore, stop the monitoring!
-- ZoneCaptureCoalition:Stop()
--
-- @usage
-- -- For example, one could stop the monitoring when the zone was captured!
-- --- @param Functional.Protect#ZONE_CAPTURE_COALITION self
-- function ZoneCaptureCoalition:OnEnterCaptured()
-- local Coalition = self:GetCoalition()
-- self:E({Coalition = Coalition})
-- if Coalition == coalition.side.BLUE then
-- RU_CC:MessageTypeToCoalition( string.format( "%s is captured by the USA, we lost it!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- US_CC:MessageTypeToCoalition( string.format( "We captured %s, Excellent job!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- else
-- US_CC:MessageTypeToCoalition( string.format( "%s is captured by Russia, we lost it!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- RU_CC:MessageTypeToCoalition( string.format( "We captured %s, Excellent job!", ZoneCaptureCoalition:GetZoneName() ), MESSAGE.Type.Information )
-- end
--
-- self:AddScore( "Captured", "Zone captured: Extra points granted.", 200 )
--
-- self:Stop()
-- end
--
function ZONE_CAPTURE_COALITION:Stop()
if self.ScheduleStatusZone then
self:ScheduleStop( self.ScheduleStatusZone )
end
end
end

View File

@@ -1,177 +0,0 @@
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone.
--
-- ===
--
-- ZONE_GOAL models processes that have a Goal with a defined achievement involving a Zone.
-- Derived classes implement the ways how the achievements can be realized.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module ZoneGoal
do -- Zone
--- @type ZONE_GOAL
-- @extends Core.Fsm#FSM
--- # ZONE_GOAL class, extends @{Fsm#FSM}
--
-- ZONE_GOAL models processes that have a Goal with a defined achievement involving a Zone.
-- Derived classes implement the ways how the achievements can be realized.
--
-- ## 1. ZONE_GOAL constructor
--
-- * @{#ZONE_GOAL.New}(): Creates a new ZONE_GOAL object.
--
-- ## 2. ZONE_GOAL is a finite state machine (FSM).
--
-- ### 2.1 ZONE_GOAL States
--
-- * None: Initial State
--
-- ### 2.2 ZONE_GOAL Events
--
-- * DestroyedUnit: A @{Unit} is destroyed in the Zone. The event will only get triggered if the method @{#ZONE_GOAL.MonitorDestroyedUnits}() is used.
--
-- @field #ZONE_GOAL
ZONE_GOAL = {
ClassName = "ZONE_GOAL",
}
--- ZONE_GOAL Constructor.
-- @param #ZONE_GOAL self
-- @param Core.Zone#ZONE_BASE Zone A @{Zone} object with the goal to be achieved.
-- @return #ZONE_GOAL
function ZONE_GOAL:New( Zone )
local self = BASE:Inherit( self, FSM:New() ) -- #ZONE_GOAL
self:F( { Zone = Zone } )
self.Zone = Zone -- Core.Zone#ZONE_BASE
self.Goal = GOAL:New()
self.SmokeTime = nil
self:AddTransition( "*", "DestroyedUnit", "*" )
--- DestroyedUnit Handler OnAfter for ZONE_GOAL
-- @function [parent=#ZONE_GOAL] OnAfterDestroyedUnit
-- @param #ZONE_GOAL self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Unit#UNIT DestroyedUnit The destroyed unit.
-- @param #string PlayerName The name of the player.
return self
end
--- Get the Zone
-- @param #ZONE_GOAL self
-- @return Core.Zone#ZONE_BASE
function ZONE_GOAL:GetZone()
return self.Zone
end
--- Get the name of the ProtectZone
-- @param #ZONE_GOAL self
-- @return #string
function ZONE_GOAL:GetZoneName()
return self.Zone:GetName()
end
--- Smoke the center of theh zone.
-- @param #ZONE_GOAL self
-- @param #SMOKECOLOR.Color SmokeColor
function ZONE_GOAL:Smoke( SmokeColor )
self:F( { SmokeColor = SmokeColor} )
self.SmokeColor = SmokeColor
end
--- Flare the center of the zone.
-- @param #ZONE_GOAL self
-- @param #SMOKECOLOR.Color FlareColor
function ZONE_GOAL:Flare( FlareColor )
self.Zone:FlareZone( FlareColor, math.random( 1, 360 ) )
end
--- When started, check the Smoke and the Zone status.
-- @param #ZONE_GOAL self
function ZONE_GOAL:onafterGuard()
--self:GetParent( self ):onafterStart()
self:F("Guard")
--self:ScheduleRepeat( 15, 15, 0.1, nil, self.StatusZone, self )
if not self.SmokeScheduler then
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self )
end
end
--- Check status Smoke.
-- @param #ZONE_GOAL self
function ZONE_GOAL:StatusSmoke()
self:F({self.SmokeTime, self.SmokeColor})
local CurrentTime = timer.getTime()
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
if self.SmokeColor then
self.Zone:GetCoordinate():Smoke( self.SmokeColor )
--self.SmokeColor = nil
self.SmokeTime = CurrentTime
end
end
end
--- @param #ZONE_GOAL self
-- @param Core.Event#EVENTDATA EventData
function ZONE_GOAL:__Destroyed( EventData )
self:F( { "EventDead", EventData } )
self:F( { EventData.IniUnit } )
local Vec3 = EventData.IniDCSUnit:getPosition().p
self:F( { Vec3 = Vec3 } )
local ZoneGoal = self:GetZone()
self:F({ZoneGoal})
if EventData.IniDCSUnit then
if ZoneGoal:IsVec3InZone(Vec3) then
local PlayerHits = _DATABASE.HITS[EventData.IniUnitName]
if PlayerHits then
for PlayerName, PlayerHit in pairs( PlayerHits.Players or {} ) do
self.Goal:AddPlayerContribution( PlayerName )
self:DestroyedUnit( EventData.IniUnitName, PlayerName )
end
end
end
end
end
--- Activate the event UnitDestroyed to be fired when a unit is destroyed in the zone.
-- @param #ZONE_GOAL self
function ZONE_GOAL:MonitorDestroyedUnits()
self:HandleEvent( EVENTS.Dead, self.__Destroyed )
self:HandleEvent( EVENTS.Crash, self.__Destroyed )
end
end

View File

@@ -1,452 +0,0 @@
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone and Cargo.
--
-- ===
--
-- ZONE_GOAL_CARGO models processes that have a Goal with a defined achievement involving a Zone and Cargo.
-- Derived classes implement the ways how the achievements can be realized.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module ZoneGoalCargo
do -- ZoneGoal
--- @type ZONE_GOAL_CARGO
-- @extends Functional.ZoneGoal#ZONE_GOAL
--- # ZONE_GOAL_CARGO class, extends @{ZoneGoal#ZONE_GOAL}
--
-- 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.
--
-- ## 1. ZONE_GOAL_CARGO constructor
--
-- * @{#ZONE_GOAL_CARGO.New}(): Creates a new ZONE_GOAL_CARGO object.
--
-- ## 2. ZONE_GOAL_CARGO is a finite state machine (FSM).
--
-- ### 2.1 ZONE_GOAL_CARGO States
--
-- * **Deployed**: The Zone has been captured by an other coalition.
-- * **Airborne**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
-- * **Loaded**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
--
-- ### 2.2 ZONE_GOAL_CARGO Events
--
-- * **Capture**: The Zone has been captured by an other coalition.
-- * **Attack**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
-- * **Guard**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
--
-- ### 2.3 ZONE_GOAL_CARGO State Machine
--
-- @field #ZONE_GOAL_CARGO
ZONE_GOAL_CARGO = {
ClassName = "ZONE_GOAL_CARGO",
}
--- @field #table ZONE_GOAL_CARGO.States
ZONE_GOAL_CARGO.States = {}
--- ZONE_GOAL_CARGO Constructor.
-- @param #ZONE_GOAL_CARGO self
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
-- @return #ZONE_GOAL_CARGO
function ZONE_GOAL_CARGO:New( Zone, Coalition )
local self = BASE:Inherit( self, ZONE_GOAL:New( Zone ) ) -- #ZONE_GOAL_CARGO
self:F( { Zone = Zone, Coalition = Coalition } )
self:SetCoalition( Coalition )
do
--- Captured State Handler OnLeave for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveCaptured
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Captured State Handler OnEnter for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterCaptured
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
end
do
--- Attacked State Handler OnLeave for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveAttacked
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Attacked State Handler OnEnter for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterAttacked
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
end
do
--- Guarded State Handler OnLeave for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveGuarded
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Guarded State Handler OnEnter for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterGuarded
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
end
do
--- Empty State Handler OnLeave for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveEmpty
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Empty State Handler OnEnter for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterEmpty
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
end
self:AddTransition( "*", "Guard", "Guarded" )
--- Guard Handler OnBefore for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeGuard
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Guard Handler OnAfter for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterGuard
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Guard Trigger for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] Guard
-- @param #ZONE_GOAL_CARGO self
--- Guard Asynchronous Trigger for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] __Guard
-- @param #ZONE_GOAL_CARGO self
-- @param #number Delay
self:AddTransition( "*", "Empty", "Empty" )
--- Empty Handler OnBefore for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeEmpty
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Empty Handler OnAfter for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterEmpty
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Empty Trigger for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] Empty
-- @param #ZONE_GOAL_CARGO self
--- Empty Asynchronous Trigger for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] __Empty
-- @param #ZONE_GOAL_CARGO self
-- @param #number Delay
self:AddTransition( { "Guarded", "Empty" }, "Attack", "Attacked" )
--- Attack Handler OnBefore for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeAttack
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Attack Handler OnAfter for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterAttack
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Attack Trigger for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] Attack
-- @param #ZONE_GOAL_CARGO self
--- Attack Asynchronous Trigger for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] __Attack
-- @param #ZONE_GOAL_CARGO self
-- @param #number Delay
self:AddTransition( { "Guarded", "Attacked", "Empty" }, "Capture", "Captured" )
--- Capture Handler OnBefore for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeCapture
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #boolean
--- Capture Handler OnAfter for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterCapture
-- @param #ZONE_GOAL_CARGO self
-- @param #string From
-- @param #string Event
-- @param #string To
--- Capture Trigger for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] Capture
-- @param #ZONE_GOAL_CARGO self
--- Capture Asynchronous Trigger for ZONE_GOAL_CARGO
-- @function [parent=#ZONE_GOAL_CARGO] __Capture
-- @param #ZONE_GOAL_CARGO self
-- @param #number Delay
return self
end
--- Set the owning coalition of the zone.
-- @param #ZONE_GOAL_CARGO self
-- @param DCSCoalition.DCSCoalition#coalition Coalition
function ZONE_GOAL_CARGO:SetCoalition( Coalition )
self.Coalition = Coalition
end
--- Get the owning coalition of the zone.
-- @param #ZONE_GOAL_CARGO self
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
function ZONE_GOAL_CARGO:GetCoalition()
return self.Coalition
end
--- Get the owning coalition name of the zone.
-- @param #ZONE_GOAL_CARGO self
-- @return #string Coalition name.
function ZONE_GOAL_CARGO:GetCoalitionName()
if self.Coalition == coalition.side.BLUE then
return "Blue"
end
if self.Coalition == coalition.side.RED then
return "Red"
end
if self.Coalition == coalition.side.NEUTRAL then
return "Neutral"
end
return ""
end
function ZONE_GOAL_CARGO:IsGuarded()
local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition )
self:F( { IsGuarded = IsGuarded } )
return IsGuarded
end
function ZONE_GOAL_CARGO:IsEmpty()
local IsEmpty = self.Zone:IsNoneInZone()
self:F( { IsEmpty = IsEmpty } )
return IsEmpty
end
function ZONE_GOAL_CARGO:IsCaptured()
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
self:F( { IsCaptured = IsCaptured } )
return IsCaptured
end
function ZONE_GOAL_CARGO:IsAttacked()
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
self:F( { IsAttacked = IsAttacked } )
return IsAttacked
end
--- Mark.
-- @param #ZONE_GOAL_CARGO self
function ZONE_GOAL_CARGO:Mark()
local Coord = self.Zone:GetCoordinate()
local ZoneName = self:GetZoneName()
local State = self:GetState()
if self.MarkRed and self.MarkBlue then
self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } )
Coord:RemoveMark( self.MarkRed )
Coord:RemoveMark( self.MarkBlue )
end
if self.Coalition == coalition.side.BLUE then
self.MarkBlue = Coord:MarkToCoalitionBlue( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
self.MarkRed = Coord:MarkToCoalitionRed( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
else
self.MarkRed = Coord:MarkToCoalitionRed( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
self.MarkBlue = Coord:MarkToCoalitionBlue( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
end
end
--- Bound.
-- @param #ZONE_GOAL_CARGO self
function ZONE_GOAL_CARGO:onenterGuarded()
--self:GetParent( self ):onenterGuarded()
if self.Coalition == coalition.side.BLUE then
--elf.ProtectZone:BoundZone( 12, country.id.USA )
else
--self.ProtectZone:BoundZone( 12, country.id.RUSSIA )
end
self:Mark()
end
function ZONE_GOAL_CARGO:onenterCaptured()
--self:GetParent( self ):onenterCaptured()
local NewCoalition = self.Zone:GetCoalition()
self:F( { NewCoalition = NewCoalition } )
self:SetCoalition( NewCoalition )
self:Mark()
end
function ZONE_GOAL_CARGO:onenterEmpty()
--self:GetParent( self ):onenterEmpty()
self:Mark()
end
function ZONE_GOAL_CARGO:onenterAttacked()
--self:GetParent( self ):onenterAttacked()
self:Mark()
end
--- When started, check the Coalition status.
-- @param #ZONE_GOAL_CARGO self
function ZONE_GOAL_CARGO:onafterGuard()
--self:F({BASE:GetParent( self )})
--BASE:GetParent( self ).onafterGuard( self )
if not self.SmokeScheduler then
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self )
end
if not self.ScheduleStatusZone then
self.ScheduleStatusZone = self:ScheduleRepeat( 15, 15, 0.1, nil, self.StatusZone, self )
end
end
function ZONE_GOAL_CARGO:IsCaptured()
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
self:F( { IsCaptured = IsCaptured } )
return IsCaptured
end
function ZONE_GOAL_CARGO:IsAttacked()
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
self:F( { IsAttacked = IsAttacked } )
return IsAttacked
end
--- Check status Coalition ownership.
-- @param #ZONE_GOAL_CARGO self
function ZONE_GOAL_CARGO:StatusZone()
local State = self:GetState()
self:F( { State = self:GetState() } )
self.Zone:Scan()
if State ~= "Guarded" and self:IsGuarded() then
self:Guard()
end
if State ~= "Empty" and self:IsEmpty() then
self:Empty()
end
if State ~= "Attacked" and self:IsAttacked() then
self:Attack()
end
if State ~= "Captured" and self:IsCaptured() then
self:Capture()
end
end
end

View File

@@ -1,113 +0,0 @@
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone for a Coalition.
--
-- ===
--
-- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition.
-- Derived classes implement the ways how the achievements can be realized.
--
-- ===
--
-- ### Author: **FlightControl**
--
-- ===
--
-- @module ZoneGoalCoalition
do -- ZoneGoal
--- @type ZONE_GOAL_COALITION
-- @extends Functional.ZoneGoal#ZONE_GOAL
--- # ZONE_GOAL_COALITION class, extends @{ZoneGoal#ZONE_GOAL}
--
-- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition.
-- Derived classes implement the ways how the achievements can be realized.
--
-- ## 1. ZONE_GOAL_COALITION constructor
--
-- * @{#ZONE_GOAL_COALITION.New}(): Creates a new ZONE_GOAL_COALITION object.
--
-- ## 2. ZONE_GOAL_COALITION is a finite state machine (FSM).
--
-- ### 2.1 ZONE_GOAL_COALITION States
--
-- ### 2.2 ZONE_GOAL_COALITION Events
--
-- ### 2.3 ZONE_GOAL_COALITION State Machine
--
-- @field #ZONE_GOAL_COALITION
ZONE_GOAL_COALITION = {
ClassName = "ZONE_GOAL_COALITION",
}
--- @field #table ZONE_GOAL_COALITION.States
ZONE_GOAL_COALITION.States = {}
--- ZONE_GOAL_COALITION Constructor.
-- @param #ZONE_GOAL_COALITION self
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
-- @return #ZONE_GOAL_COALITION
function ZONE_GOAL_COALITION:New( Zone, Coalition )
local self = BASE:Inherit( self, ZONE_GOAL:New( Zone ) ) -- #ZONE_GOAL_COALITION
self:F( { Zone = Zone, Coalition = Coalition } )
self:SetCoalition( Coalition )
return self
end
--- Set the owning coalition of the zone.
-- @param #ZONE_GOAL_COALITION self
-- @param DCSCoalition.DCSCoalition#coalition Coalition
function ZONE_GOAL_COALITION:SetCoalition( Coalition )
self.Coalition = Coalition
end
--- Get the owning coalition of the zone.
-- @param #ZONE_GOAL_COALITION self
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
function ZONE_GOAL_COALITION:GetCoalition()
return self.Coalition
end
--- Get the owning coalition name of the zone.
-- @param #ZONE_GOAL_COALITION self
-- @return #string Coalition name.
function ZONE_GOAL_COALITION:GetCoalitionName()
if self.Coalition == coalition.side.BLUE then
return "Blue"
end
if self.Coalition == coalition.side.RED then
return "Red"
end
if self.Coalition == coalition.side.NEUTRAL then
return "Neutral"
end
return ""
end
--- Check status Coalition ownership.
-- @param #ZONE_GOAL_COALITION self
function ZONE_GOAL_COALITION:StatusZone()
local State = self:GetState()
self:F( { State = self:GetState() } )
self.Zone:Scan( { Object.Category.UNIT, Object.Category.STATIC } )
end
end

View File

@@ -1,6 +1,5 @@
-- The order of the declarations is important here. Don't touch it.
--- Declare the event dispatcher based on the EVENT class
_EVENTDISPATCHER = EVENT:New() -- Core.Event#EVENT
@@ -11,5 +10,4 @@ _SCHEDULEDISPATCHER = SCHEDULEDISPATCHER:New() -- Core.Timer#SCHEDULEDISPATCHER
_DATABASE = DATABASE:New() -- Core.Database#DATABASE
_SETTINGS = SETTINGS:Set()
_SETTINGS:SetPlayerMenuOn()

View File

@@ -3,17 +3,90 @@
--
-- ===
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
--
-- ### Contributions:
--
-- ===
-- ====
--
-- @module CommandCenter
--- The REPORT class
-- @type REPORT
-- @extends Core.Base#BASE
REPORT = {
ClassName = "REPORT",
Title = "",
}
--- Create a new REPORT.
-- @param #REPORT self
-- @param #string Title
-- @return #REPORT
function REPORT:New( Title )
local self = BASE:Inherit( self, BASE:New() ) -- #REPORT
self.Report = {}
Title = Title or ""
if Title then
self.Title = Title
end
self:SetIndent( 3 )
return self
end
--- Has the REPORT Text?
-- @param #REPORT self
-- @return #boolean
function REPORT:HasText() --R2.1
return #self.Report > 0
end
--- Set indent of a REPORT.
-- @param #REPORT self
-- @param #number Indent
-- @return #REPORT
function REPORT:SetIndent( Indent ) --R2.1
self.Indent = Indent
return self
end
--- Add a new line to a REPORT.
-- @param #REPORT self
-- @param #string Text
-- @return #REPORT
function REPORT:Add( Text )
self.Report[#self.Report+1] = Text
return self
end
--- Add a new line to a REPORT.
-- @param #REPORT self
-- @param #string Text
-- @return #REPORT
function REPORT:AddIndent( Text ) --R2.1
self.Report[#self.Report+1] = string.rep(" ", self.Indent ) .. Text:gsub("\n","\n"..string.rep( " ", self.Indent ) )
return self
end
--- Produces the text of the report, taking into account an optional delimeter, which is \n by default.
-- @param #REPORT self
-- @param #string Delimiter (optional) A delimiter text.
-- @return #string The report text.
function REPORT:Text( Delimiter )
Delimiter = Delimiter or "\n"
local ReportText = ( self.Title ~= "" and self.Title .. Delimiter or self.Title ) .. table.concat( self.Report, Delimiter ) or ""
return ReportText
end
--- The COMMANDCENTER class
-- @type COMMANDCENTER
@@ -100,10 +173,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
function( self, EventData )
if EventData.IniObjectCategory == 1 then
local EventGroup = GROUP:Find( EventData.IniDCSGroup )
self:E( { CommandCenter = self:GetName(), EventGroup = EventGroup:GetName(), HasGroup = self:HasGroup( EventGroup ), EventData = EventData } )
if EventGroup and self:HasGroup( EventGroup ) then
local CommandCenterMenu = MENU_GROUP:New( EventGroup, self:GetText() )
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", CommandCenterMenu )
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", self.CommandCenterMenu )
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportMissionsStatus, self, EventGroup )
local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Players Report", MenuReporting, self.ReportMissionsPlayers, self, EventGroup )
self:ReportSummary( EventGroup )
@@ -114,30 +185,30 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
Mission:JoinUnit( PlayerUnit, PlayerGroup )
end
self:SetMenu()
_DATABASE:PlayerSettingsMenu( PlayerUnit )
end
end
end
)
-- -- When a player enters a client or a unit, the CommandCenter will check for each Mission and each Task in the Mission if the player has things to do.
-- -- For these elements, it will=
-- -- - Set the correct menu.
-- -- - Assign the PlayerUnit to the Task if required.
-- -- - Send a message to the other players in the group that this player has joined.
-- self:HandleEvent( EVENTS.PlayerEnterUnit,
-- --- @param #COMMANDCENTER self
-- -- @param Core.Event#EVENTDATA EventData
-- function( self, EventData )
-- local PlayerUnit = EventData.IniUnit
-- for MissionID, Mission in pairs( self:GetMissions() ) do
-- local Mission = Mission -- Tasking.Mission#MISSION
-- local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
-- Mission:JoinUnit( PlayerUnit, PlayerGroup )
-- end
-- self:SetMenu()
-- end
-- )
-- When a player enters a client or a unit, the CommandCenter will check for each Mission and each Task in the Mission if the player has things to do.
-- For these elements, it will=
-- - Set the correct menu.
-- - Assign the PlayerUnit to the Task if required.
-- - Send a message to the other players in the group that this player has joined.
self:HandleEvent( EVENTS.PlayerEnterUnit,
--- @param #COMMANDCENTER self
-- @param Core.Event#EVENTDATA EventData
function( self, EventData )
local PlayerUnit = EventData.IniUnit
for MissionID, Mission in pairs( self:GetMissions() ) do
local Mission = Mission -- Tasking.Mission#MISSION
local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
Mission:JoinUnit( PlayerUnit, PlayerGroup )
end
end
)
-- Handle when a player leaves a slot and goes back to spectators ...
-- The PlayerUnit will be UnAssigned from the Task.
@@ -203,24 +274,6 @@ function COMMANDCENTER:GetName()
return self.CommandCenterName
end
--- Gets the text string of the HQ command center.
-- @param #COMMANDCENTER self
-- @return #string
function COMMANDCENTER:GetText()
return "Command Center [" .. self.CommandCenterName .. "]"
end
--- Gets the short text string of the HQ command center.
-- @param #COMMANDCENTER self
-- @return #string
function COMMANDCENTER:GetShortText()
return "CC [" .. self.CommandCenterName .. "]"
end
--- Gets the POSITIONABLE of the HQ command center.
-- @param #COMMANDCENTER self
-- @return Wrapper.Positionable#POSITIONABLE
@@ -324,6 +377,8 @@ end
function COMMANDCENTER:SetMenu()
self:F()
self.CommandCenterMenu = self.CommandCenterMenu or MENU_COALITION:New( self.CommandCenterCoalition, "Command Center (" .. self:GetName() .. ")" )
local MenuTime = timer.getTime()
for MissionID, Mission in pairs( self:GetMissions() or {} ) do
local Mission = Mission -- Tasking.Mission#MISSION
@@ -375,20 +430,10 @@ end
-- @param #COMMANDCENTER self
-- @param #string Message
-- @param Wrapper.Group#GROUP TaskGroup
-- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown.
function COMMANDCENTER:MessageToGroup( Message, TaskGroup )
self:GetPositionable():MessageToGroup( Message, 15, TaskGroup, self:GetShortText() )
end
--- Send a CC message of a specified type to a GROUP.
-- @param #COMMANDCENTER self
-- @param #string Message
-- @param Wrapper.Group#GROUP TaskGroup
-- @param Core.Message#MESSAGE.MessageType MessageType The type of the message, resulting in automatic time duration and prefix of the message.
function COMMANDCENTER:MessageTypeToGroup( Message, TaskGroup, MessageType )
self:GetPositionable():MessageTypeToGroup( Message, MessageType, TaskGroup, self:GetShortText() )
self:GetPositionable():MessageToGroup( Message , 15, TaskGroup, self:GetName() )
end
@@ -404,35 +449,19 @@ function COMMANDCENTER:MessageToCoalition( Message )
end
--- Send a CC message of a specified type to the coalition of the CC.
-- @param #COMMANDCENTER self
-- @param #string Message The message.
-- @param Core.Message#MESSAGE.MessageType MessageType The type of the message, resulting in automatic time duration and prefix of the message.
function COMMANDCENTER:MessageTypeToCoalition( Message, MessageType )
local CCCoalition = self:GetPositionable():GetCoalition()
--TODO: Fix coalition bug!
self:GetPositionable():MessageTypeToCoalition( Message, MessageType, CCCoalition )
end
--- Report the status of all MISSIONs to a GROUP.
-- Each Mission is listed, with an indication how many Tasks are still to be completed.
-- @param #COMMANDCENTER self
function COMMANDCENTER:ReportSummary( ReportGroup )
self:F( ReportGroup )
function COMMANDCENTER:ReportMissionsStatus( ReportGroup )
self:E( ReportGroup )
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetName()
Report:Add( string.format( '%s - Report Summary Missions', Name ) )
Report:Add( "Status report of all missions." )
for MissionID, Mission in pairs( self.Missions ) do
local Mission = Mission -- Tasking.Mission#MISSION
Report:Add( " - " .. Mission:ReportSummary() )
Report:Add( " - " .. Mission:ReportStatus() )
end
self:MessageToGroup( Report:Text(), ReportGroup )
@@ -442,7 +471,7 @@ end
-- Each Mission is listed, with an indication how many Tasks are still to be completed.
-- @param #COMMANDCENTER self
function COMMANDCENTER:ReportMissionsPlayers( ReportGroup )
self:F( ReportGroup )
self:E( ReportGroup )
local Report = REPORT:New()
@@ -460,7 +489,7 @@ end
-- Report the details of a Mission, listing the Mission, and all the Task details.
-- @param #COMMANDCENTER self
function COMMANDCENTER:ReportDetails( ReportGroup, Task )
self:F( ReportGroup )
self:E( ReportGroup )
local Report = REPORT:New()

View File

@@ -3,7 +3,7 @@
-- ===
--
-- 1) @{DetectionManager#DETECTION_MANAGER} class, extends @{Fsm#FSM}
-- ===
-- ====================================================================
-- The @{DetectionManager#DETECTION_MANAGER} class defines the core functions to report detected objects to groups.
-- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour.
--
@@ -15,7 +15,7 @@
-- ---------------------------------
-- Derived DETECTION_MANAGER classes will reports detected units using the method @{DetectionManager#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour.
--
-- The time interval in seconds of the reporting can be changed using the methods @{DetectionManager#DETECTION_MANAGER.SetRefreshTimeInterval}().
-- The time interval in seconds of the reporting can be changed using the methods @{DetectionManager#DETECTION_MANAGER.SetReportInterval}().
-- To control how long a reporting message is displayed, use @{DetectionManager#DETECTION_MANAGER.SetReportDisplayTime}().
-- Derived classes need to implement the method @{DetectionManager#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report.
--
@@ -27,7 +27,7 @@
-- ===
--
-- 2) @{DetectionManager#DETECTION_REPORTING} class, extends @{DetectionManager#DETECTION_MANAGER}
-- ===
-- =========================================================================================
-- The @{DetectionManager#DETECTION_REPORTING} class implements detected units reporting. Reporting can be controlled using the reporting methods available in the @{DetectionManager#DETECTION_MANAGER} class.
--
-- 2.1) DETECTION_REPORTING constructor:
@@ -126,9 +126,10 @@ do -- DETECTION MANAGER
self:AddTransition( "Started", "Report", "Started" )
self:SetRefreshTimeInterval( 30 )
self:SetReportInterval( 30 )
self:SetReportDisplayTime( 25 )
self:E( { Detection = Detection } )
Detection:__Start( 3 )
return self
@@ -140,19 +141,21 @@ do -- DETECTION MANAGER
function DETECTION_MANAGER:onafterReport( From, Event, To )
self:__Report( -self._RefreshTimeInterval )
self:E( "onafterReport" )
self:__Report( -self._ReportInterval )
self:ProcessDetected( self.Detection )
end
--- Set the reporting time interval.
-- @param #DETECTION_MANAGER self
-- @param #number RefreshTimeInterval The interval in seconds when a report needs to be done.
-- @param #number ReportInterval The interval in seconds when a report needs to be done.
-- @return #DETECTION_MANAGER self
function DETECTION_MANAGER:SetRefreshTimeInterval( RefreshTimeInterval )
function DETECTION_MANAGER:SetReportInterval( ReportInterval )
self:F2()
self._RefreshTimeInterval = RefreshTimeInterval
self._ReportInterval = ReportInterval
end
@@ -253,6 +256,7 @@ do -- DETECTION_REPORTING
function DETECTION_REPORTING:ProcessDetected( Group, Detection )
self:F2( Group )
self:E( Group )
local DetectedMsg = {}
for DetectedAreaID, DetectedAreaData in pairs( Detection:GetDetectedAreas() ) do
local DetectedArea = DetectedAreaData -- Functional.Detection#DETECTION_AREAS.DetectedArea

View File

@@ -1,8 +1,8 @@
--- **Tasking** -- A MISSION is the main owner of a Mission orchestration within MOOSE.
--
-- ===
-- ====
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
--
-- ### Contributions:
--
@@ -46,7 +46,6 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi
self.MissionCoalition = MissionCoalition
self.Tasks = {}
self.TaskNumber = 0
self.PlayerNames = {} -- These are the players that achieved progress in the mission.
self:SetStartState( "IDLE" )
@@ -265,40 +264,23 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi
end
--- FSM function for a MISSION
-- FSM function for a MISSION
-- @param #MISSION self
-- @param #string From
-- @param #string Event
-- @param #string To
function MISSION:onenterCOMPLETED( From, Event, To )
self:GetCommandCenter():MessageTypeToCoalition( self:GetText() .. " has been completed! Good job guys!", MESSAGE.Type.Information )
self:GetCommandCenter():MessageToCoalition( self:GetName() .. " has been completed! Good job guys!" )
end
--- Gets the mission name.
-- @param #MISSION self
-- @return #MISSION self
function MISSION:GetName()
return self.Name
end
--- Gets the mission text.
-- @param #MISSION self
-- @return #MISSION self
function MISSION:GetText()
return string.format( 'Mission "%s (%s)"', self.Name, self.MissionPriority )
end
--- Gets the short mission text.
-- @param #MISSION self
-- @return #MISSION self
function MISSION:GetShortText()
return string.format( 'Mission "%s"', self.Name )
end
--- Add a Unit to join the Mission.
-- For each Task within the Mission, the Unit is joined with the Task.
-- If the Unit was not part of a Task in the Mission, false is returned.
@@ -308,7 +290,7 @@ end
-- @param Wrapper.Group#GROUP PlayerGroup The GROUP of the player joining the Mission.
-- @return #boolean true if Unit is part of a Task in the Mission.
function MISSION:JoinUnit( PlayerUnit, PlayerGroup )
self:I( { Mission = self:GetName(), PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
self:F( { PlayerUnit = PlayerUnit, PlayerGroup = PlayerGroup } )
local PlayerUnitAdded = false
@@ -403,16 +385,9 @@ end
function MISSION:SetMenu( MenuTime )
self:F( { self:GetName(), MenuTime } )
local MenuCount = {}
--for TaskID, Task in UTILS.spairs( self:GetTasks(), function( t, a, b ) return t[a]:ReportOrder( ReportGroup ) < t[b]:ReportOrder( ReportGroup ) end ) do
for TaskID, Task in pairs( self:GetTasks() ) do
local Task = Task -- Tasking.Task#TASK
local TaskType = Task:GetType()
MenuCount[TaskType] = MenuCount[TaskType] or 1
if MenuCount[TaskType] <= 10 then
Task:SetMenu( MenuTime )
MenuCount[TaskType] = MenuCount[TaskType] + 1
end
for _, TaskData in pairs( self:GetTasks() ) do
local Task = TaskData -- Tasking.Task#TASK
Task:SetMenu( MenuTime )
end
end
@@ -460,7 +435,7 @@ do -- Group Assignment
local MissionGroupName = MissionGroup:GetName()
self.AssignedGroups[MissionGroupName] = MissionGroup
self:I( string.format( "Mission %s is assigned to %s", MissionName, MissionGroupName ) )
self:E( string.format( "Mission %s is assigned to %s", MissionName, MissionGroupName ) )
return self
end
@@ -500,23 +475,7 @@ function MISSION:RemoveTaskMenu( Task )
end
--- Gets the root mission menu for the TaskGroup.
-- @param #MISSION self
-- @return Core.Menu#MENU_COALITION self
function MISSION:GetRootMenu( TaskGroup ) -- R2.2
local CommandCenter = self:GetCommandCenter()
local CommandCenterMenu = CommandCenter:GetMenu()
local MissionName = self:GetText()
--local MissionMenu = CommandCenterMenu:GetMenu( MissionName )
self.MissionMenu = MENU_COALITION:New( self.MissionCoalition, MissionName, CommandCenterMenu )
return self.MissionMenu
end
--- Gets the mission menu for the TaskGroup.
--- Gets the mission menu for the coalition.
-- @param #MISSION self
-- @return Core.Menu#MENU_COALITION self
function MISSION:GetMenu( TaskGroup ) -- R2.1 -- Changed Menu Structure
@@ -524,35 +483,30 @@ function MISSION:GetMenu( TaskGroup ) -- R2.1 -- Changed Menu Structure
local CommandCenter = self:GetCommandCenter()
local CommandCenterMenu = CommandCenter:GetMenu()
local MissionName = self:GetName()
--local MissionMenu = CommandCenterMenu:GetMenu( MissionName )
self.MissionGroupMenu = self.MissionGroupMenu or {}
self.MissionGroupMenu[TaskGroup] = self.MissionGroupMenu[TaskGroup] or {}
self.MissionMenu = self.MissionMenu or {}
self.MissionMenu[TaskGroup] = self.MissionMenu[TaskGroup] or {}
local GroupMenu = self.MissionGroupMenu[TaskGroup]
local Menu = self.MissionMenu[TaskGroup]
local CommandCenterText = CommandCenter:GetText()
CommandCenterMenu = MENU_GROUP:New( TaskGroup, CommandCenterText )
local MissionText = self:GetText()
self.MissionMenu = MENU_GROUP:New( TaskGroup, MissionText, CommandCenterMenu )
GroupMenu.BriefingMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Mission Briefing", self.MissionMenu, self.MenuReportBriefing, self, TaskGroup )
Menu.MainMenu = Menu.MainMenu or MENU_GROUP:New( TaskGroup, self:GetName(), CommandCenterMenu )
Menu.BriefingMenu = Menu.BriefingMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Mission Briefing", Menu.MainMenu, self.MenuReportBriefing, self, TaskGroup )
GroupMenu.MarkTasks = MENU_GROUP_COMMAND:New( TaskGroup, "Mark Task Locations on Map", self.MissionMenu, self.MarkTargetLocations, self, TaskGroup )
GroupMenu.TaskReportsMenu = MENU_GROUP:New( TaskGroup, "Task Reports", self.MissionMenu )
GroupMenu.ReportTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Tasks Summary", GroupMenu.TaskReportsMenu, self.MenuReportTasksSummary, self, TaskGroup )
GroupMenu.ReportPlannedTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Planned Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Planned" )
GroupMenu.ReportAssignedTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Assigned Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Assigned" )
GroupMenu.ReportSuccessTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Successful Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Success" )
GroupMenu.ReportFailedTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Failed Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Failed" )
GroupMenu.ReportHeldTasksMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Held Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Hold" )
Menu.TaskReportsMenu = Menu.TaskReportsMenu or MENU_GROUP:New( TaskGroup, "Task Reports", Menu.MainMenu )
Menu.ReportTasksMenu = Menu.ReportTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Tasks", Menu.TaskReportsMenu, self.MenuReportTasksSummary, self, TaskGroup )
Menu.ReportPlannedTasksMenu = Menu.ReportPlannedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Planned Tasks", Menu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Planned" )
Menu.ReportAssignedTasksMenu = Menu.ReportAssignedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Assigned Tasks", Menu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Assigned" )
Menu.ReportSuccessTasksMenu = Menu.ReportSuccessTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Successful Tasks", Menu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Success" )
Menu.ReportFailedTasksMenu = Menu.ReportFailedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Failed Tasks", Menu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Failed" )
Menu.ReportHeldTasksMenu = Menu.ReportHeldTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Held Tasks", Menu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Hold" )
GroupMenu.PlayerReportsMenu = MENU_GROUP:New( TaskGroup, "Statistics Reports", self.MissionMenu )
GroupMenu.ReportMissionHistory = MENU_GROUP_COMMAND:New( TaskGroup, "Report Mission Progress", GroupMenu.PlayerReportsMenu, self.MenuReportPlayersProgress, self, TaskGroup )
GroupMenu.ReportPlayersPerTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, "Report Players per Task", GroupMenu.PlayerReportsMenu, self.MenuReportPlayersPerTask, self, TaskGroup )
Menu.PlayerReportsMenu = Menu.PlayerReportsMenu or MENU_GROUP:New( TaskGroup, "Statistics Reports", Menu.MainMenu )
Menu.ReportMissionHistory = Menu.ReportPlayersHistory or MENU_GROUP_COMMAND:New( TaskGroup, "Report Mission Progress", Menu.PlayerReportsMenu, self.MenuReportPlayersProgress, self, TaskGroup )
Menu.ReportPlayersPerTaskMenu = Menu.ReportPlayersPerTaskMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Players per Task", Menu.PlayerReportsMenu, self.MenuReportPlayersPerTask, self, TaskGroup )
return self.MissionMenu
return Menu.MainMenu
end
@@ -569,18 +523,6 @@ function MISSION:GetTask( TaskName )
end
--- Return the next @{Task} ID to be completed within the @{Mission}.
-- @param #MISSION self
-- @param Tasking.Task#TASK Task is the @{Task} object.
-- @return Tasking.Task#TASK The task added.
function MISSION:GetNextTaskID( Task )
self.TaskNumber = self.TaskNumber + 1
return self.TaskNumber
end
--- Register a @{Task} to be completed within the @{Mission}.
-- Note that there can be multiple @{Task}s registered to be completed.
-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached.
@@ -590,7 +532,9 @@ end
function MISSION:AddTask( Task )
local TaskName = Task:GetTaskName()
self:I( { "==> Adding TASK ", MissionName = self:GetName(), TaskName = TaskName } )
self:F( TaskName )
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
self.Tasks[TaskName] = Task
@@ -599,7 +543,6 @@ function MISSION:AddTask( Task )
return Task
end
--- Removes a @{Task} to be completed within the @{Mission}.
-- Note that there can be multiple @{Task}s registered to be completed.
-- Each Task can be set a certain Goals. The Mission will not be completed until all Goals are reached.
@@ -609,7 +552,6 @@ end
function MISSION:RemoveTask( Task )
local TaskName = Task:GetTaskName()
self:I( { "<== Removing TASK ", MissionName = self:GetName(), TaskName = TaskName } )
self:F( TaskName )
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
@@ -625,6 +567,21 @@ function MISSION:RemoveTask( Task )
return nil
end
--- Return the next @{Task} ID to be completed within the @{Mission}.
-- @param #MISSION self
-- @param Tasking.Task#TASK Task is the @{Task} object.
-- @return Tasking.Task#TASK The task added.
function MISSION:GetNextTaskID( Task )
local TaskName = Task:GetTaskName()
self:F( TaskName )
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
self.Tasks[TaskName].n = self.Tasks[TaskName].n + 1
return self.Tasks[TaskName].n
end
--- Is the @{Mission} **COMPLETED**.
-- @param #MISSION self
-- @return #boolean
@@ -726,7 +683,7 @@ function MISSION:ReportBriefing()
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetText()
local Name = self:GetName()
-- Determine the status of the mission.
local Status = "<" .. self:GetState() .. ">"
@@ -739,57 +696,57 @@ function MISSION:ReportBriefing()
end
----- Create a status report of the Mission.
---- This reports provides a one liner of the mission status. It indicates how many players and how many Tasks.
----
---- Mission "<MissionName>" - Status "<MissionStatus>"
---- - Task Types: <TaskType>, <TaskType>
---- - <xx> Planned Tasks (xp)
---- - <xx> Assigned Tasks(xp)
---- - <xx> Success Tasks (xp)
---- - <xx> Hold Tasks (xp)
---- - <xx> Cancelled Tasks (xp)
---- - <xx> Aborted Tasks (xp)
---- - <xx> Failed Tasks (xp)
----
---- @param #MISSION self
---- @return #string
--function MISSION:ReportSummary()
--
-- local Report = REPORT:New()
--
-- -- List the name of the mission.
-- local Name = self:GetText()
--
-- -- Determine the status of the mission.
-- local Status = "<" .. self:GetState() .. ">"
--
-- Report:Add( string.format( '%s - Status "%s"', Name, Status ) )
--
-- local TaskTypes = self:GetTaskTypes()
--
-- Report:Add( string.format( " - Task Types: %s", table.concat(TaskTypes, ", " ) ) )
--
-- local TaskStatusList = { "Planned", "Assigned", "Success", "Hold", "Cancelled", "Aborted", "Failed" }
--
-- for TaskStatusID, TaskStatus in pairs( TaskStatusList ) do
-- local TaskCount = 0
-- local TaskPlayerCount = 0
-- -- Determine how many tasks are remaining.
-- for TaskID, Task in pairs( self:GetTasks() ) do
-- local Task = Task -- Tasking.Task#TASK
-- if Task:Is( TaskStatus ) then
-- TaskCount = TaskCount + 1
-- TaskPlayerCount = TaskPlayerCount + Task:GetPlayerCount()
-- end
-- end
-- if TaskCount > 0 then
-- Report:Add( string.format( " - %02d %s Tasks (%dp)", TaskCount, TaskStatus, TaskPlayerCount ) )
-- end
-- end
--
-- return Report:Text()
--end
--- Create a status report of the Mission.
-- This reports provides a one liner of the mission status. It indicates how many players and how many Tasks.
--
-- Mission "<MissionName>" - Status "<MissionStatus>"
-- - Task Types: <TaskType>, <TaskType>
-- - <xx> Planned Tasks (xp)
-- - <xx> Assigned Tasks(xp)
-- - <xx> Success Tasks (xp)
-- - <xx> Hold Tasks (xp)
-- - <xx> Cancelled Tasks (xp)
-- - <xx> Aborted Tasks (xp)
-- - <xx> Failed Tasks (xp)
--
-- @param #MISSION self
-- @return #string
function MISSION:ReportStatus()
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetName()
-- Determine the status of the mission.
local Status = "<" .. self:GetState() .. ">"
Report:Add( string.format( '%s - Status "%s"', Name, Status ) )
local TaskTypes = self:GetTaskTypes()
Report:Add( string.format( " - Task Types: %s", table.concat(TaskTypes, ", " ) ) )
local TaskStatusList = { "Planned", "Assigned", "Success", "Hold", "Cancelled", "Aborted", "Failed" }
for TaskStatusID, TaskStatus in pairs( TaskStatusList ) do
local TaskCount = 0
local TaskPlayerCount = 0
-- Determine how many tasks are remaining.
for TaskID, Task in pairs( self:GetTasks() ) do
local Task = Task -- Tasking.Task#TASK
if Task:Is( TaskStatus ) then
TaskCount = TaskCount + 1
TaskPlayerCount = TaskPlayerCount + Task:GetPlayerCount()
end
end
if TaskCount > 0 then
Report:Add( string.format( " - %02d %s Tasks (%dp)", TaskCount, TaskStatus, TaskPlayerCount ) )
end
end
return Report:Text()
end
--- Create an active player report of the Mission.
@@ -807,7 +764,7 @@ function MISSION:ReportPlayersPerTask( ReportGroup )
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetText()
local Name = self:GetName()
-- Determine the status of the mission.
local Status = "<" .. self:GetState() .. ">"
@@ -848,7 +805,7 @@ function MISSION:ReportPlayersProgress( ReportGroup )
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetText()
local Name = self:GetName()
-- Determine the status of the mission.
local Status = "<" .. self:GetState() .. ">"
@@ -884,42 +841,15 @@ function MISSION:ReportPlayersProgress( ReportGroup )
end
--- Mark all the target locations on the Map.
-- @param #MISSION self
-- @param Wrapper.Group#GROUP ReportGroup
-- @return #string
function MISSION:MarkTargetLocations( ReportGroup )
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetText()
-- Determine the status of the mission.
local Status = "<" .. self:GetState() .. ">"
Report:Add( string.format( '%s - %s - All Tasks are marked on the map. Select a Task from the Mission Menu and Join the Task!!!', Name, Status ) )
-- Determine how many tasks are remaining.
for TaskID, Task in UTILS.spairs( self:GetTasks(), function( t, a, b ) return t[a]:ReportOrder( ReportGroup ) < t[b]:ReportOrder( ReportGroup ) end ) do
local Task = Task -- Tasking.Task#TASK
Task:MenuMarkToGroup( ReportGroup )
end
return Report:Text()
end
--- Create a summary report of the Mission (one line).
-- @param #MISSION self
-- @param Wrapper.Group#GROUP ReportGroup
-- @return #string
function MISSION:ReportSummary( ReportGroup )
function MISSION:ReportSummary()
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetText()
local Name = self:GetName()
-- Determine the status of the mission.
local Status = "<" .. self:GetState() .. ">"
@@ -927,9 +857,9 @@ function MISSION:ReportSummary( ReportGroup )
Report:Add( string.format( '%s - %s - Task Overview Report', Name, Status ) )
-- Determine how many tasks are remaining.
for TaskID, Task in UTILS.spairs( self:GetTasks(), function( t, a, b ) return t[a]:ReportOrder( ReportGroup ) < t[b]:ReportOrder( ReportGroup ) end ) do
for TaskID, Task in pairs( self:GetTasks() ) do
local Task = Task -- Tasking.Task#TASK
Report:Add( "- " .. Task:ReportSummary( ReportGroup ) )
Report:Add( "- " .. Task:ReportSummary() )
end
return Report:Text()
@@ -940,12 +870,10 @@ end
-- @return #string
function MISSION:ReportOverview( ReportGroup, TaskStatus )
self:F( { TaskStatus = TaskStatus } )
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetText()
local Name = self:GetName()
-- Determine the status of the mission.
local Status = "<" .. self:GetState() .. ">"
@@ -953,16 +881,11 @@ function MISSION:ReportOverview( ReportGroup, TaskStatus )
Report:Add( string.format( '%s - %s - %s Tasks Report', Name, Status, TaskStatus ) )
-- Determine how many tasks are remaining.
local Tasks = 0
local TasksRemaining = 0
for TaskID, Task in UTILS.spairs( self:GetTasks(), function( t, a, b ) return t[a]:ReportOrder( ReportGroup ) < t[b]:ReportOrder( ReportGroup ) end ) do
local Task = Task -- Tasking.Task#TASK
if Task:Is( TaskStatus ) then
Report:Add( string.rep( "-", 140 ) )
Report:Add( Task:ReportOverview( ReportGroup ) )
end
Tasks = Tasks + 1
if Tasks >= 8 then
break
Report:Add( " - " .. Task:ReportOverview( ReportGroup ) )
end
end
@@ -977,7 +900,7 @@ function MISSION:ReportDetails( ReportGroup )
local Report = REPORT:New()
-- List the name of the mission.
local Name = self:GetText()
local Name = self:GetName()
-- Determine the status of the mission.
local Status = "<" .. self:GetState() .. ">"
@@ -988,7 +911,6 @@ function MISSION:ReportDetails( ReportGroup )
local TasksRemaining = 0
for TaskID, Task in pairs( self:GetTasks() ) do
local Task = Task -- Tasking.Task#TASK
Report:Add( string.rep( "-", 140 ) )
Report:Add( Task:ReportDetails( ReportGroup ) )
end
@@ -1013,18 +935,7 @@ function MISSION:MenuReportBriefing( ReportGroup )
local Report = self:ReportBriefing()
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Briefing )
end
--- Mark all the targets of the Mission on the Map.
-- @param #MISSION self
-- @param Wrapper.Group#GROUP ReportGroup
function MISSION:MenuMarkTargetLocations( ReportGroup )
local Report = self:MarkTargetLocations( ReportGroup )
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Overview )
self:GetCommandCenter():MessageToGroup( Report, ReportGroup )
end
@@ -1034,9 +945,9 @@ end
-- @param Wrapper.Group#GROUP ReportGroup
function MISSION:MenuReportTasksSummary( ReportGroup )
local Report = self:ReportSummary( ReportGroup )
local Report = self:ReportSummary()
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Overview )
self:GetCommandCenter():MessageToGroup( Report, ReportGroup )
end
@@ -1049,7 +960,7 @@ function MISSION:MenuReportTasksPerStatus( ReportGroup, TaskStatus )
local Report = self:ReportOverview( ReportGroup, TaskStatus )
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Overview )
self:GetCommandCenter():MessageToGroup( Report, ReportGroup )
end
@@ -1059,7 +970,7 @@ function MISSION:MenuReportPlayersPerTask( ReportGroup )
local Report = self:ReportPlayersPerTask()
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Overview )
self:GetCommandCenter():MessageToGroup( Report, ReportGroup )
end
--- @param #MISSION self
@@ -1068,7 +979,7 @@ function MISSION:MenuReportPlayersProgress( ReportGroup )
local Report = self:ReportPlayersProgress()
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Overview )
self:GetCommandCenter():MessageToGroup( Report, ReportGroup )
end

View File

@@ -1,12 +1,12 @@
--- **Tasking** -- This module contains the TASK class, the main engine to run human taskings.
--
-- ===
-- ====
--
-- ### Author: **FlightControl**
-- ### Author: **Sven Van de Velde (FlightControl)**
--
-- ### Contributions:
--
-- ===
-- ====
--
-- @module Task
@@ -17,7 +17,6 @@
-- @field Core.Fsm#FSM_PROCESS FsmTemplate
-- @field Tasking.Mission#MISSION Mission
-- @field Tasking.CommandCenter#COMMANDCENTER CommandCenter
-- @field Tasking.TaskInfo#TASKINFO TaskInfo
-- @extends Core.Fsm#FSM_TASK
---
@@ -176,34 +175,28 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing )
--- Goal Handler OnBefore for TASK
-- @function [parent=#TASK] OnBeforeGoal
-- @param #TASK self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player.
-- @param #string PlayerName The name of the player.
-- @return #boolean
--- Goal Handler OnAfter for TASK
-- @function [parent=#TASK] OnAfterGoal
-- @param #TASK self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player.
-- @param #string PlayerName The name of the player.
--- Goal Trigger for TASK
-- @function [parent=#TASK] Goal
-- @param #TASK self
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player.
-- @param #string PlayerName The name of the player.
--- Goal Asynchronous Trigger for TASK
-- @function [parent=#TASK] __Goal
-- @param #TASK self
-- @param #number Delay
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player.
-- @param #string PlayerName The name of the player.
@@ -213,7 +206,7 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing )
self:AddTransition( { "Failed", "Aborted", "Cancelled" }, "Replan", "Planned" )
self:AddTransition( "*", "TimeOut", "Cancelled" )
self:F( "New TASK " .. TaskName )
self:E( "New TASK " .. TaskName )
self.Processes = {}
self.Fsm = {}
@@ -231,7 +224,7 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing )
self.FsmTemplate = self.FsmTemplate or FSM_PROCESS:New()
self.TaskInfo = TASKINFO:New( self )
self.TaskInfo = {}
self.TaskProgress = {}
@@ -279,12 +272,12 @@ function TASK:JoinUnit( PlayerUnit, PlayerGroup )
-- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is added to the Task.
-- If the PlayerGroup is not assigned to the Task, the menu needs to be set. In that case, the PlayerUnit will become the GroupPlayer leader.
if self:IsStatePlanned() or self:IsStateReplanned() then
--self:SetMenuForGroup( PlayerGroup )
self:SetMenuForGroup( PlayerGroup )
--self:MessageToGroups( PlayerUnit:GetPlayerName() .. " is planning to join Task " .. self:GetName() )
end
if self:IsStateAssigned() then
local IsGroupAssigned = self:IsGroupAssigned( PlayerGroup )
self:F( { IsGroupAssigned = IsGroupAssigned } )
self:E( { IsGroupAssigned = IsGroupAssigned } )
if IsGroupAssigned then
self:AssignToUnit( PlayerUnit )
self:MessageToGroups( PlayerUnit:GetPlayerName() .. " joined Task " .. self:GetName() )
@@ -313,7 +306,7 @@ function TASK:AbortGroup( PlayerGroup )
-- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group.
if self:IsStateAssigned() then
local IsGroupAssigned = self:IsGroupAssigned( PlayerGroup )
self:F( { IsGroupAssigned = IsGroupAssigned } )
self:E( { IsGroupAssigned = IsGroupAssigned } )
if IsGroupAssigned then
local PlayerName = PlayerGroup:GetUnit(1):GetPlayerName()
--self:MessageToGroups( PlayerName .. " aborted Task " .. self:GetName() )
@@ -323,7 +316,7 @@ function TASK:AbortGroup( PlayerGroup )
-- Now check if the task needs to go to hold...
-- It will go to hold, if there are no players in the mission...
PlayerGroups:Flush( self )
PlayerGroups:Flush()
local IsRemaining = false
for GroupName, AssignedGroup in pairs( PlayerGroups:GetSet() or {} ) do
if self:IsGroupAssigned( AssignedGroup ) == true then
@@ -365,7 +358,7 @@ function TASK:CrashGroup( PlayerGroup )
-- If the PlayerUnit was the last unit of the PlayerGroup, the menu needs to be removed from the Group.
if self:IsStateAssigned() then
local IsGroupAssigned = self:IsGroupAssigned( PlayerGroup )
self:F( { IsGroupAssigned = IsGroupAssigned } )
self:E( { IsGroupAssigned = IsGroupAssigned } )
if IsGroupAssigned then
local PlayerName = PlayerGroup:GetUnit(1):GetPlayerName()
self:MessageToGroups( PlayerName .. " crashed! " )
@@ -374,7 +367,7 @@ function TASK:CrashGroup( PlayerGroup )
-- Now check if the task needs to go to hold...
-- It will go to hold, if there are no players in the mission...
PlayerGroups:Flush( self )
PlayerGroups:Flush()
local IsRemaining = false
for GroupName, AssignedGroup in pairs( PlayerGroups:GetSet() or {} ) do
if self:IsGroupAssigned( AssignedGroup ) == true then
@@ -427,11 +420,11 @@ do -- Group Assignment
local TaskGroupName = TaskGroup:GetName()
if self.AssignedGroups[TaskGroupName] then
--self:T( { "Task is assigned to:", TaskGroup:GetName() } )
self:T( { "Task is assigned to:", TaskGroup:GetName() } )
return true
end
--self:T( { "Task is not assigned to:", TaskGroup:GetName() } )
self:T( { "Task is not assigned to:", TaskGroup:GetName() } )
return false
end
@@ -446,7 +439,7 @@ do -- Group Assignment
local TaskGroupName = TaskGroup:GetName()
self.AssignedGroups[TaskGroupName] = TaskGroup
self:F( string.format( "Task %s is assigned to %s", TaskName, TaskGroupName ) )
self:E( string.format( "Task %s is assigned to %s", TaskName, TaskGroupName ) )
-- Set the group to be assigned at mission level. This allows to decide the menu options on mission level for this group.
self:GetMission():SetGroupAssigned( TaskGroup )
@@ -476,7 +469,7 @@ do -- Group Assignment
local TaskGroupName = TaskGroup:GetName()
self.AssignedGroups[TaskGroupName] = nil
--self:F( string.format( "Task %s is unassigned to %s", TaskName, TaskGroupName ) )
--self:E( string.format( "Task %s is unassigned to %s", TaskName, TaskGroupName ) )
-- Set the group to be assigned at mission level. This allows to decide the menu options on mission level for this group.
self:GetMission():ClearGroupAssignment( TaskGroup )
@@ -517,7 +510,7 @@ do -- Group Assignment
for UnitID, UnitData in pairs( TaskUnits ) do
local TaskUnit = UnitData -- Wrapper.Unit#UNIT
local PlayerName = TaskUnit:GetPlayerName()
self:F(PlayerName)
self:E(PlayerName)
if PlayerName ~= nil and PlayerName ~= "" then
self:AssignToUnit( TaskUnit )
CommandCenter:MessageToGroup(
@@ -566,7 +559,7 @@ end
function TASK:HasGroup( FindGroup )
local SetAttackGroup = self:GetGroups()
return SetAttackGroup:FindGroup( FindGroup:GetName() )
return SetAttackGroup:FindGroup(FindGroup)
end
@@ -620,7 +613,7 @@ function TASK:MessageToGroups( Message )
local Mission = self:GetMission()
local CC = Mission:GetCommandCenter()
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetAliveSet() ) do
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do
local TaskGroup = TaskGroup -- Wrapper.Group#GROUP
CC:MessageToGroup( Message, TaskGroup, TaskGroup:GetName() )
end
@@ -632,7 +625,7 @@ end
function TASK:SendBriefingToAssignedGroups()
self:F2()
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetAliveSet() ) do
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do
if self:IsGroupAssigned( TaskGroup ) then
TaskGroup:Message( self.TaskBriefing, 60 )
@@ -646,7 +639,7 @@ end
function TASK:UnAssignFromGroups()
self:F2()
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetAliveSet() ) do
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do
if self:IsGroupAssigned(TaskGroup) then
self:UnAssignFromGroup( TaskGroup )
end
@@ -661,7 +654,7 @@ end
function TASK:HasAliveUnits()
self:F()
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetAliveSet() ) do
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
if self:IsStateAssigned() then
if self:IsGroupAssigned( TaskGroup ) then
for TaskUnitID, TaskUnit in pairs( TaskGroup:GetUnits() ) do
@@ -686,9 +679,9 @@ function TASK:SetMenu( MenuTime ) --R2.1 Mission Reports and Task Reports added.
self:F( { self:GetName(), MenuTime } )
--self.SetGroup:Flush()
for TaskGroupID, TaskGroupData in pairs( self.SetGroup:GetAliveSet() ) do
for TaskGroupID, TaskGroupData in pairs( self.SetGroup:GetSet() ) do
local TaskGroup = TaskGroupData -- Wrapper.Group#GROUP
if TaskGroup:IsAlive() == true and TaskGroup:GetPlayerNames() then
if TaskGroup:IsAlive() and TaskGroup:GetPlayerNames() then
-- Set Mission Menus
@@ -733,10 +726,11 @@ function TASK:SetPlannedMenuForGroup( TaskGroup, MenuTime )
local CommandCenterMenu = CommandCenter:GetMenu()
local TaskType = self:GetType()
-- local TaskThreatLevel = self.TaskInfo["ThreatLevel"]
-- local TaskThreatLevelString = TaskThreatLevel and " [" .. string.rep( "■", TaskThreatLevel ) .. "]" or " []"
local TaskPlayerCount = self:GetPlayerCount()
local TaskPlayerString = string.format( " (%dp)", TaskPlayerCount )
-- local TaskText = string.format( "%s%s", self:GetName(), TaskPlayerString ) --, TaskThreatLevelString )
local TaskText = string.format( "%s", self:GetName() )
local TaskText = string.format( "%s%s", self:GetName(), TaskPlayerString ) --, TaskThreatLevelString )
local TaskName = string.format( "%s", self:GetName() )
local MissionMenu = Mission:GetMenu( TaskGroup )
@@ -744,18 +738,14 @@ function TASK:SetPlannedMenuForGroup( TaskGroup, MenuTime )
--local MissionMenu = Mission:GetMenu( TaskGroup )
self.MenuPlanned = self.MenuPlanned or {}
self.MenuPlanned[TaskGroup] = MENU_GROUP_DELAYED:New( TaskGroup, "Join Planned Task", MissionMenu, Mission.MenuReportTasksPerStatus, Mission, TaskGroup, "Planned" ):SetTime( MenuTime ):SetTag( "Tasking" )
local TaskTypeMenu = MENU_GROUP_DELAYED:New( TaskGroup, TaskType, self.MenuPlanned[TaskGroup] ):SetTime( MenuTime ):SetTag( "Tasking" )
local TaskTypeMenu = MENU_GROUP_DELAYED:New( TaskGroup, TaskText, TaskTypeMenu ):SetTime( MenuTime ):SetTag( "Tasking" )
local TaskPlannedMenu = MENU_GROUP:New( TaskGroup, "Join Planned Task", MissionMenu, Mission.MenuReportTasksPerStatus, Mission, TaskGroup, "Planned" ):SetTime( MenuTime )
local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskType, TaskPlannedMenu ):SetTime( MenuTime ):SetRemoveParent( true )
local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskText, TaskTypeMenu ):SetTime( MenuTime ):SetRemoveParent( true )
local ReportTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Status" ), TaskTypeMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true )
if not Mission:IsGroupAssigned( TaskGroup ) then
--self:F( { "Replacing Join Task menu" } )
local JoinTaskMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Join Task" ), TaskTypeMenu, self.MenuAssignToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
local MarkTaskMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Mark Task Location on Map" ), TaskTypeMenu, self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
local JoinTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Join Task" ), TaskTypeMenu, self.MenuAssignToGroup, { self = self, TaskGroup = TaskGroup } ):SetTime( MenuTime ):SetRemoveParent( true )
end
local ReportTaskMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Report Task Details" ), TaskTypeMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
return self
end
@@ -774,6 +764,8 @@ function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime )
local CommandCenterMenu = CommandCenter:GetMenu()
local TaskType = self:GetType()
-- local TaskThreatLevel = self.TaskInfo["ThreatLevel"]
-- local TaskThreatLevelString = TaskThreatLevel and " [" .. string.rep( "■", TaskThreatLevel ) .. "]" or " []"
local TaskPlayerCount = self:GetPlayerCount()
local TaskPlayerString = string.format( " (%dp)", TaskPlayerCount )
local TaskText = string.format( "%s%s", self:GetName(), TaskPlayerString ) --, TaskThreatLevelString )
@@ -783,11 +775,9 @@ function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime )
-- local MissionMenu = MENU_GROUP:New( TaskGroup, MissionName, CommandCenterMenu ):SetTime( MenuTime )
-- local MissionMenu = Mission:GetMenu( TaskGroup )
self.MenuAssigned = self.MenuAssigned or {}
self.MenuAssigned[TaskGroup] = MENU_GROUP_DELAYED:New( TaskGroup, string.format( "Assigned Task %s", TaskName ), MissionMenu ):SetTime( MenuTime ):SetTag( "Tasking" )
local TaskMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Abort Task" ), self.MenuAssigned[TaskGroup], self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
local MarkMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Mark Task Location on Map" ), self.MenuAssigned[TaskGroup], self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
local TaskTypeMenu = MENU_GROUP_COMMAND_DELAYED:New( TaskGroup, string.format( "Report Task Details" ), self.MenuAssigned[TaskGroup], self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
local TaskAssignedMenu = MENU_GROUP:New( TaskGroup, string.format( "Assigned Task %s", TaskName ), MissionMenu ):SetTime( MenuTime )
local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Status" ), TaskAssignedMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true )
local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Abort Group from Task" ), TaskAssignedMenu, self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true )
return self
end
@@ -799,9 +789,9 @@ end
function TASK:RemoveMenu( MenuTime )
self:F( { self:GetName(), MenuTime } )
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetAliveSet() ) do
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
local TaskGroup = TaskGroup -- Wrapper.Group#GROUP
if TaskGroup:IsAlive() == true and TaskGroup:GetPlayerNames() then
if TaskGroup:IsAlive() and TaskGroup:GetPlayerNames() then
self:RefreshMenus( TaskGroup, MenuTime )
end
end
@@ -824,20 +814,15 @@ function TASK:RefreshMenus( TaskGroup, MenuTime )
local MissionMenu = Mission:GetMenu( TaskGroup )
local TaskName = self:GetName()
self.MenuPlanned = self.MenuPlanned or {}
local PlannedMenu = self.MenuPlanned[TaskGroup]
self.MenuAssigned = self.MenuAssigned or {}
local AssignedMenu = self.MenuAssigned[TaskGroup]
local PlannedMenu = MissionMenu:GetMenu( "Planned Tasks" )
local AssignedMenu = MissionMenu:GetMenu( string.format( "Assigned Task %s", TaskName ) )
if PlannedMenu then
self.MenuPlanned[TaskGroup] = PlannedMenu:Remove( MenuTime , "Tasking" )
PlannedMenu:Set()
PlannedMenu:Remove( MenuTime )
end
if AssignedMenu then
self.MenuAssigned[TaskGroup] = AssignedMenu:Remove( MenuTime, "Tasking" )
AssignedMenu:Set()
AssignedMenu:Remove( MenuTime )
end
end
@@ -861,33 +846,16 @@ function TASK:RemoveAssignedMenuForGroup( TaskGroup )
end
--- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
function TASK:MenuAssignToGroup( TaskGroup )
function TASK.MenuAssignToGroup( MenuParam )
self:F( "Join Task menu selected")
local self = MenuParam.self
local TaskGroup = MenuParam.TaskGroup
self:E( "Assigned menu selected")
self:AssignToGroup( TaskGroup )
end
--- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
function TASK:MenuMarkToGroup( TaskGroup )
self:F()
self:UpdateTaskInfo( self.DetectedItem )
local Report = REPORT:New():SetIndent( 0 )
self.TaskInfo:Report( Report, "M", TaskGroup )
local TargetCoordinate = self.TaskInfo:GetData( "Coordinate" ) -- Core.Point#COORDINATE
local MarkText = Report:Text( ", " )
self:F( { Coordinate = TargetCoordinate, MarkText = MarkText } )
TargetCoordinate:MarkToGroup( MarkText, TaskGroup )
--Coordinate:MarkToAll( Briefing )
end
--- Report the task status.
-- @param #TASK self
function TASK:MenuTaskStatus( TaskGroup )
@@ -895,7 +863,7 @@ function TASK:MenuTaskStatus( TaskGroup )
local ReportText = self:ReportDetails( TaskGroup )
self:T( ReportText )
self:GetMission():GetCommandCenter():MessageTypeToGroup( ReportText, TaskGroup, MESSAGE.Type.Detailed )
self:GetMission():GetCommandCenter():MessageToGroup( ReportText, TaskGroup )
end
@@ -981,10 +949,10 @@ end
function TASK:RemoveStateMachine( TaskUnit )
self:F( { TaskUnit = TaskUnit:GetName(), HasFsm = ( self.Fsm[TaskUnit] ~= nil ) } )
--self:F( self.Fsm )
--self:E( self.Fsm )
--for TaskUnitT, Fsm in pairs( self.Fsm ) do
--local Fsm = Fsm -- Core.Fsm#FSM_PROCESS
--self:F( TaskUnitT )
--self:E( TaskUnitT )
--self.Fsm[TaskUnit] = nil
--end
@@ -994,7 +962,7 @@ function TASK:RemoveStateMachine( TaskUnit )
end
collectgarbage()
self:F( "Garbage Collected, Processes should be finalized now ...")
self:E( "Garbage Collected, Processes should be finalized now ...")
end
@@ -1049,6 +1017,19 @@ function TASK:SetType( TaskType )
self.TaskType = TaskType
end
--- Sets the Information on the Task
-- @param #TASK self
-- @param #string TaskInfo The key and title of the task information.
-- @param #string TaskInfoText The Task info text.
-- @param #number TaskInfoOrder The ordering, a number between 0 and 99.
function TASK:SetInfo( TaskInfo, TaskInfoText, TaskInfoOrder )
self.TaskInfo = self.TaskInfo or {}
self.TaskInfo[TaskInfo] = self.TaskInfo[TaskInfo] or {}
self.TaskInfo[TaskInfo].TaskInfoText = TaskInfoText
self.TaskInfo[TaskInfo].TaskInfoOrder = TaskInfoOrder
end
--- Gets the Type of the Task
-- @param #TASK self
-- @return #string TaskType
@@ -1186,7 +1167,7 @@ end
-- @param #string TaskBriefing
-- @return #TASK self
function TASK:SetBriefing( TaskBriefing )
self:F(TaskBriefing)
self:E(TaskBriefing)
self.TaskBriefing = TaskBriefing
return self
end
@@ -1208,9 +1189,10 @@ end
-- @param #string To
function TASK:onenterAssigned( From, Event, To, PlayerUnit, PlayerName )
--- This test is required, because the state transition will be fired also when the state does not change in case of an event.
if From ~= "Assigned" then
self:F( { From, Event, To, PlayerUnit:GetName(), PlayerName } )
self:E( { From, Event, To, PlayerUnit:GetName(), PlayerName } )
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " is assigned." )
@@ -1219,20 +1201,16 @@ function TASK:onenterAssigned( From, Event, To, PlayerUnit, PlayerName )
self:SetGoalTotal() -- Polymorphic to set the initial goal total!
if self.Dispatcher then
self:F( "Firing Assign event " )
self:E( "Firing Assign event " )
self.Dispatcher:Assign( self, PlayerUnit, PlayerName )
end
self:GetMission():__Start( 1 )
-- When the task is assigned, the task goal needs to be checked of the derived classes.
self:__Goal( -10, PlayerUnit, PlayerName ) -- Polymorphic
self:__Goal( -10 ) -- Polymorphic
self:SetMenu()
self:F( { "--> Task Assigned", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
self:F( { "--> Task Player Names", PlayerNames = self:GetPlayerNames() } )
end
end
@@ -1244,8 +1222,7 @@ end
-- @param #string To
function TASK:onenterSuccess( From, Event, To )
self:F( { "<-> Task Replanned", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
self:F( { "<-> Task Player Names", PlayerNames = self:GetPlayerNames() } )
self:E( "Task Success" )
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " is successful! Good job!" )
self:UnAssignFromGroups()
@@ -1262,8 +1239,7 @@ end
-- @param #string To
function TASK:onenterAborted( From, Event, To )
self:F( { "<-- Task Aborted", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
self:F( { "<-- Task Player Names", PlayerNames = self:GetPlayerNames() } )
self:E( "Task Aborted" )
if From ~= "Aborted" then
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has been aborted! Task may be replanned." )
@@ -1273,24 +1249,6 @@ function TASK:onenterAborted( From, Event, To )
end
--- FSM function for a TASK
-- @param #TASK self
-- @param #string From
-- @param #string Event
-- @param #string To
function TASK:onenterCancelled( From, Event, To )
self:F( { "<-- Task Cancelled", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
self:F( { "<-- Player Names", PlayerNames = self:GetPlayerNames() } )
if From ~= "Cancelled" then
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has been cancelled! The tactical situation has changed." )
self:UnAssignFromGroups()
self:SetMenu()
end
end
--- FSM function for a TASK
-- @param #TASK self
-- @param #string From
@@ -1298,8 +1256,7 @@ end
-- @param #string To
function TASK:onafterReplan( From, Event, To )
self:F( { "Task Replanned", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
self:F( { "Task Player Names", PlayerNames = self:GetPlayerNames() } )
self:E( "Task Replanned" )
self:GetMission():GetCommandCenter():MessageToCoalition( "Replanning Task " .. self:GetName() .. "." )
@@ -1314,8 +1271,7 @@ end
-- @param #string To
function TASK:onenterFailed( From, Event, To )
self:F( { "Task Failed", TaskName = self:GetName(), Mission = self:GetMission():GetName() } )
self:F( { "Task Player Names", PlayerNames = self:GetPlayerNames() } )
self:E( "Task Failed" )
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has failed!" )
@@ -1336,7 +1292,7 @@ function TASK:onstatechange( From, Event, To )
if self.Scores[To] then
local Scoring = self:GetScoring()
if Scoring then
self:F( { self.Scores[To].ScoreText, self.Scores[To].Score } )
self:E( { self.Scores[To].ScoreText, self.Scores[To].Score } )
Scoring:_AddMissionScore( self.Mission, self.Scores[To].ScoreText, self.Scores[To].Score )
end
end
@@ -1367,7 +1323,7 @@ function TASK:onbeforeTimeOut( From, Event, To )
return false
end
do -- Links
do -- Dispatcher
--- Set dispatcher of a task
-- @param #TASK self
@@ -1377,19 +1333,6 @@ do -- Links
self.Dispatcher = Dispatcher
end
--- Set detection of a task
-- @param #TASK self
-- @param Function.Detection#DETECTION_BASE Detection
-- @param DetectedItem
-- @return #TASK
function TASK:SetDetection( Detection, DetectedItem )
self:F( { DetectedItem, Detection } )
self.Detection = Detection
self.DetectedItem = DetectedItem
end
end
do -- Reporting
@@ -1397,38 +1340,72 @@ do -- Reporting
--- Create a summary report of the Task.
-- List the Task Name and Status
-- @param #TASK self
-- @param Wrapper.Group#GROUP ReportGroup
-- @return #string
function TASK:ReportSummary( ReportGroup )
function TASK:ReportSummary() --R2.1 fixed report. Now nicely formatted and contains the info required.
self:UpdateTaskInfo( self.DetectedItem )
local Report = REPORT:New()
-- List the name of the Task.
Report:Add( "Task " .. self:GetName() )
local Name = self:GetName()
-- Determine the status of the Task.
Report:Add( "State: <" .. self:GetState() .. ">" )
local Status = "<" .. self:GetState() .. ">"
self.TaskInfo:Report( Report, "S", ReportGroup )
return Report:Text( ', ' )
Report:Add( 'Task ' .. Name .. ' - State ' .. Status )
return Report:Text()
end
--- Create an overiew report of the Task.
-- List the Task Name and Status
-- @param #TASK self
-- @return #string
function TASK:ReportOverview( ReportGroup )
function TASK:ReportOverview( ReportGroup ) --R2.1 fixed report. Now nicely formatted and contains the info required.
self:UpdateTaskInfo( self.DetectedItem )
-- List the name of the Task.
local TaskName = self:GetName()
local Report = REPORT:New()
self.TaskInfo:Report( Report, "O", ReportGroup )
-- Determine the status of the Task.
local Status = "<" .. self:GetState() .. ">"
local Line = 0
local LineReport = REPORT:New()
for TaskInfoID, TaskInfo in UTILS.spairs( self.TaskInfo, function( t, a, b ) return t[a].TaskInfoOrder < t[b].TaskInfoOrder end ) do
self:F( { TaskInfo = TaskInfo } )
if Line < math.floor( TaskInfo.TaskInfoOrder / 10 ) then
if Line ~= 0 then
Report:AddIndent( LineReport:Text( ", " ) )
else
Report:Add( TaskName .. ":" .. LineReport:Text( ", " ))
end
LineReport = REPORT:New()
Line = math.floor( TaskInfo.TaskInfoOrder / 10 )
end
local TaskInfoIDText = string.format( "%s: ", TaskInfoID )
if type( TaskInfo.TaskInfoText ) == "string" then
LineReport:Add( TaskInfoIDText .. TaskInfo.TaskInfoText )
elseif type(TaskInfo) == "table" then
if TaskInfoID == "Coordinates" then
local FromCoordinate = ReportGroup:GetUnit(1):GetCoordinate()
local ToCoordinate = TaskInfo.TaskInfoText -- Core.Point#COORDINATE
--Report:Add( TaskInfoIDText )
LineReport:Add( ToCoordinate:ToString( ReportGroup ) )
--Report:AddIndent( ToCoordinate:ToStringBULLS( ReportGroup:GetCoalition() ) )
else
end
end
end
Report:AddIndent( LineReport:Text( ", " ) )
return Report:Text()
end
@@ -1441,7 +1418,7 @@ function TASK:GetPlayerCount() --R2.1 Get a count of the players.
local PlayerCount = 0
-- Loop each Unit active in the Task, and find Player Names.
for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetAliveSet() ) do
for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do
local PlayerGroup = PlayerGroup -- Wrapper.Group#GROUP
if self:IsGroupAssigned( PlayerGroup ) then
local PlayerNames = PlayerGroup:GetPlayerNames()
@@ -1461,7 +1438,7 @@ function TASK:GetPlayerNames() --R2.1 Get a map of the players.
local PlayerNameMap = {}
-- Loop each Unit active in the Task, and find Player Names.
for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetAliveSet() ) do
for TaskGroupID, PlayerGroup in pairs( self:GetGroups():GetSet() ) do
local PlayerGroup = PlayerGroup -- Wrapper.Group#GROUP
if self:IsGroupAssigned( PlayerGroup ) then
local PlayerNames = PlayerGroup:GetPlayerNames()
@@ -1482,8 +1459,6 @@ end
-- @return #string
function TASK:ReportDetails( ReportGroup )
self:UpdateTaskInfo( self.DetectedItem )
local Report = REPORT:New():SetIndent( 3 )
-- List the name of the Task.
@@ -1492,8 +1467,6 @@ function TASK:ReportDetails( ReportGroup )
-- Determine the status of the Task.
local Status = "<" .. self:GetState() .. ">"
Report:Add( "Task " .. Name .. " - " .. Status .. " - Detailed Report" )
-- Loop each Unit active in the Task, and find Player Names.
local PlayerNames = self:GetPlayerNames()
@@ -1502,14 +1475,30 @@ function TASK:ReportDetails( ReportGroup )
PlayerReport:Add( "Group " .. PlayerGroup:GetCallsign() .. ": " .. PlayerName )
end
local Players = PlayerReport:Text()
Report:Add( "Task: " .. Name .. " - " .. Status .. " - Detailed Report" )
Report:Add( " - Players:" )
Report:AddIndent( Players )
if Players ~= "" then
Report:AddIndent( "Players assigned:", "-" )
Report:AddIndent( Players )
for TaskInfoID, TaskInfo in pairs( self.TaskInfo, function( t, a, b ) return t[a].TaskInfoOrder < t[b].TaskInfoOrder end ) do
local TaskInfoIDText = string.format( " - %s: ", TaskInfoID )
if type( TaskInfo.TaskInfoText ) == "string" then
Report:Add( TaskInfoIDText .. TaskInfo.TaskInfoText )
elseif type(TaskInfo) == "table" then
if TaskInfoID == "Coordinates" then
local FromCoordinate = ReportGroup:GetUnit(1):GetCoordinate()
local ToCoordinate = TaskInfo.TaskInfoText -- Core.Point#COORDINATE
Report:Add( TaskInfoIDText )
Report:AddIndent( ToCoordinate:ToStringBRA( FromCoordinate ) .. ", " .. TaskInfo.TaskInfoText:ToStringAspect( FromCoordinate ) )
Report:AddIndent( ToCoordinate:ToStringBULLS( ReportGroup:GetCoalition() ) )
else
end
end
end
self.TaskInfo:Report( Report, "D", ReportGroup )
return Report:Text()
end

Some files were not shown because too many files have changed in this diff Show More