Compare commits

..

77 Commits

Author SHA1 Message Date
Frank
8bf56b8b1a Update Airboss.lua
- Fixed AI handling (got lost in some merge with develop branch and was using FLIGHTGROUPS)
2023-07-26 16:36:44 +02:00
Applevangelist
f31741f934 #AI_ESCORT
* Improve documentation
2023-07-25 12:01:18 +02:00
Applevangelist
46258492bd #AIRBASE, #ATIS
* Additions
2023-07-23 12:37:57 +02:00
Applevangelist
6481f66e27 #MANTIS
* Added IDs for Current Hill Assets, keyword "CHM" for group names
2023-07-16 11:27:34 +02:00
Thomas
5954b8692f Update Spot.lua
Fix
2023-07-15 09:36:24 +02:00
Applevangelist
f6fdecf892 Merge remote-tracking branch 'origin/master' 2023-07-13 16:15:11 +02:00
Applevangelist
53fb77b50d #SPAWN 2023-07-13 16:15:06 +02:00
Applevangelist
04a9dc3a8c #SPAWN
* Added method to init spawn position
2023-07-13 16:13:00 +02:00
Applevangelist
10b9a32f29 #SPOT
* Fix for switching laser off and on again not follwing unit any more
2023-07-12 17:54:17 +02:00
Applevangelist
40fa929eb0 * Added omissed DetectedItem.Name found by @Nocke 2023-07-07 15:14:33 +02:00
Applevangelist
8c8ef19f01 #CONTROLLABLE
* Added TaskGroundEscort
2023-07-03 16:44:46 +02:00
Applevangelist
1eaa3d309d #SCORING
* typo
2023-07-01 13:15:59 +02:00
Applevangelist
a52cd5612a Merge remote-tracking branch 'origin/master' 2023-07-01 13:12:29 +02:00
Applevangelist
e82ed762be Merge remote-tracking branch 'origin/master' 2023-07-01 13:11:46 +02:00
Applevangelist
0bb16ec827 #AIRBASE
* Fix for nil error in finding parking for a group

#MANTIS
* Added SAM type "SHORAD" as designator

#SCORING
* fix for non local problem

#UTILS
* fix for OneLineSerialize
2023-07-01 13:11:21 +02:00
Thomas
a978420a67 Point - BRAANATO (#1969)
corrected Track to be direction of travel of bogey (self in this case)
2023-06-26 13:25:23 +02:00
Applevangelist
f59326bf10 #ATIS
* Fix for airbases which have no runways, e.g. Naqoura Syria
2023-06-24 14:03:43 +02:00
Thomas
d937ab2679 CTLD (#1967)
* Added option for troops subcategories in menu
2023-06-22 13:46:11 +02:00
Applevangelist
7164e211f2 #AIRBASE
- Nicosia unused atm
2023-06-21 10:42:35 +02:00
Applevangelist
dae78d7ac1 #Positionable, Unit - remove pcall 2023-06-16 11:06:46 +02:00
Applevangelist
254468c723 #NET
* Improvements
2023-06-15 14:51:36 +02:00
Applevangelist
71be4d99d6 #POSITIONABLE:GetRelativeCoordinate( x, y, z ) 2023-06-14 17:40:33 +02:00
Frank
f86fc845e7 Update Timer.lua
- Timer stop is using protected call now because it can crash the whole script.
2023-06-13 21:53:19 +02:00
Frank
cc907b9c14 Update Unit.lua
- UNIT:IsAlive() fixed so it is consistent with GROUP:IsAlive()
2023-06-13 19:02:55 +02:00
Applevangelist
241b2beee1 * Makes calls for GetAmmo() and GetVec3() safer with pcall()
* Small docu fix Ben-Gurion
2023-06-13 08:39:56 +02:00
Frank
12f260e857 Update Unit.lua
- Added `UNIT:IsExist` function.
2023-06-12 23:01:19 +02:00
Thomas
096d145cf9 Update Airbase.lua (#1957)
Deleted raj al … airbases #1955
2023-06-12 06:22:51 +02:00
Thomas
b3883301a2 Update Airbase.lua
Corrected enumerator for Ben-Gurion (Ben_Gurion)
2023-06-11 12:33:01 +02:00
Applevangelist
3a7521c492 #UTILS
* Sinai TIme
2023-06-10 19:08:46 +02:00
Applevangelist
caa5a96235 fix 2023-06-10 19:06:22 +02:00
Applevangelist
cee1c592ba #UTILS
* Sinai TIme
2023-06-10 19:04:40 +02:00
Frank
f1fc9f0b27 Update Utils.lua
- Added parameters time zone and magvar for Sinai map
2023-06-10 10:08:22 +02:00
Applevangelist
e9adcb0dd5 #AIRBASE
* Sinai airfield enumerator
2023-06-09 15:13:45 +02:00
Applevangelist
afe2b675e5 #RAT
* Fixes from dev
2023-06-08 13:59:59 +02:00
Applevangelist
2c14ee74b0 #SCORING
* Can leave text empty on some instances
2023-06-08 13:58:26 +02:00
Frank
f351d2a37e Merge pull request #1951 from FlightControl-Master/FF/MasterDevel
Update RAT.lua
2023-06-08 09:45:49 +02:00
Frank
4cb0e70184 Update RAT.lua
- Fixed RATMANAGER spamming due to not accounting for planned/scheduled groups
2023-06-08 09:43:11 +02:00
Applevangelist
41bb2551d3 #CTLD
* Ensure new menus can be build if player changes helos
2023-06-03 12:34:18 +02:00
Applevangelist
55ed394782 #UNIT #CTLD
* Stabilize that sometimes a unit coordinate cannot be found
2023-06-02 08:44:14 +02:00
Applevangelist
dd7a883a33 Fixes 2023-06-01 10:02:51 +02:00
Applevangelist
f7acbc3928 #CSAR
* Corrected flare distance to kms
2023-05-30 07:38:19 +02:00
Applevangelist
2318578126 #SPAWN
* Logic fix for the last parameter of `NewFromTemplate()`
2023-05-28 15:27:34 +02:00
Applevangelist
3e6f25f17c #UTILS
* Added UTILS.PrintTableToLog()
2023-05-26 08:28:08 +02:00
Applevangelist
0cd6a59ce4 #CONTROLLER
* Fix for Link4
2023-05-25 08:57:15 +02:00
Applevangelist
91a445961b #RESCUEHELO
* Small fix to get the coordinate of an ejected/crashed unit
2023-05-25 08:23:31 +02:00
Frank
749e9b7e08 Update Event.lua
Fixed bug that statics are handled incorrectly if they are the target object of an event (*e.g.* hit event)
2023-05-24 11:16:01 +02:00
Applevangelist
905d29b279 #SPAWN
* Tweaked NewFromTemplate, and gave a better example
2023-05-22 17:57:03 +02:00
Applevangelist
5f97299cb2 Small Fix 2023-05-20 12:12:18 +02:00
Applevangelist
60b75a4c8f #POINT
* Added FindClosestStatic()
2023-05-19 17:11:54 +02:00
Applevangelist
0868286f27 #WAREHOUSE
* Fixed one omission for SHIP transport types
2023-05-17 10:26:29 +02:00
Applevangelist
ffcc46cb2d #CTLD
* Changed VHF modulation to AM
* Added option to have a different sound file for UHF, in case you want to silent FC3 radios
* Thanks to Streakeagle
2023-05-17 09:34:54 +02:00
Frank
21bcd64c9d Update Controllable.lua
Corrected parameters for enroute tasks according to hoggit for
- CONTROLLABLE:EnRouteTaskFAC
- CONTROLLABLE:EnRouteTaskFAC_EngageGroup
2023-05-13 23:35:58 +02:00
Applevangelist
943b68f38f #CTLD
* placement of dropped crates to better align to unit length
2023-05-11 15:31:24 +02:00
Applevangelist
256b93087f #AI_A2X...
* Fixes
2023-05-09 09:48:21 +02:00
Applevangelist
7ed0d7eec3 #AI_A2X...
* Fixes
2023-05-09 09:44:41 +02:00
Applevangelist
9b8154246f #COORDINATE
* Added `IsInSteepArea()`and `IsInFlatArea()`
2023-05-05 10:31:23 +02:00
Frank
c360759e49 Merge pull request #1939 from FlightControl-Master/FF/MasterDevel
Update Socket.lua
2023-04-25 21:42:53 +02:00
Frank
d8b80aab1a Update Socket.lua
- Added `SOCKET:SendTextToSpeech()` function
2023-04-25 21:20:16 +02:00
Applevangelist
b96ebc1872 #SCENERY
* Added update of Life0 value if `GetLife()`is called
#SET_SCENERY
* Added Documentation
2023-04-25 09:12:31 +02:00
Applevangelist
6896dc155a #SCENERY
* Added update of Life0 value if `GetLife()`is called
#SET_SCENERY
* Added Documentation
2023-04-25 09:12:25 +02:00
Applevangelist
1060d63808 #SET_SCENERY
* Added functions to count Life0, Life and RelativeLife points of SET_SCENERY
2023-04-24 16:44:38 +02:00
Thomas
88b6540f5b AIRBASE - add Normandy AFBs (#1937)
Add Normandy AFBs
2023-04-24 11:09:03 +02:00
Frank
302e785f32 Merge pull request #1936 from FlightControl-Master/FF/MasterDevel
Remove Junk
2023-04-22 14:05:09 +02:00
Frank
1507cc0b42 Remove Junk
**ZONE**
- Added `ZONE_RADIUS:RemoveJunk()` function
- Added `ZONE_POLYGON_BASE:RemoveJunk()` function (not working)

**POSITIONABLE**
- Added `Explosion`
2023-04-22 14:02:18 +02:00
Applevangelist
240307ef94 #CTLD
* Docu changes
2023-04-20 08:23:03 +02:00
Applevangelist
90c74bd82c #SET
- Minus one log entry
2023-04-20 08:06:43 +02:00
Thomas
9414096de7 Added active ZONE filtering (#1935)
for groups, units, clients entering/leaving zones to be used with `FilterStart()`
2023-04-19 09:51:53 +02:00
Applevangelist
07c3be9d6a Fixes for getPlayername() errors 2023-04-18 10:24:56 +02:00
Applevangelist
9869dbd95a #CTLD
* Include current group structure in load/save functions
2023-04-16 16:10:46 +02:00
Frank
49b702106a Update Weapon.lua
- Decreased min possible time step to 0.00001 seconds
2023-04-16 12:29:57 +02:00
Applevangelist
8eb09beb96 Merge remote-tracking branch 'origin/master' 2023-04-15 16:19:46 +02:00
Applevangelist
b402a99a25 #CTLD
* Small fix allowing minus signs in template names for repairs
2023-04-15 16:19:35 +02:00
Applevangelist
ad8938cd74 #CTLD
* Small fix allowing minus signs in template names for repairs
2023-04-15 16:17:01 +02:00
Applevangelist
ee409c45a0 #CTLD
* Allow save/loadback with precise(r) coordinates for vehicles and troops.
2023-04-13 15:51:21 +02:00
Applevangelist
9d5da3388d smaller docu item 2023-04-13 15:28:41 +02:00
Applevangelist
9e138aa149 #DATABASE
* Small fix for CLIENT:FindByName()
2023-04-04 10:33:04 +02:00
Applevangelist
cf94c4d043 #NET
* Fix for ucid can be nil
2023-04-03 12:15:29 +02:00
32 changed files with 2133 additions and 822 deletions

View File

@@ -1687,6 +1687,20 @@ do -- AI_A2A_DISPATCHER
return DefenderSquadron
end
--- Get a resource count from a specific squadron
-- @param #AI_A2A_DISPATCHER self
-- @param #string Squadron Name of the squadron.
-- @return #number Number of airframes available or nil if the squadron does not exist
function AI_A2A_DISPATCHER:QuerySquadron(Squadron)
local Squadron = self:GetSquadron(Squadron)
if Squadron.ResourceCount then
self:T2(string.format("%s = %s",Squadron.Name,Squadron.ResourceCount))
return Squadron.ResourceCount
end
self:F({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
return nil
end
--- [DEPRECATED - Might create problems launching planes] Set the Squadron visible before startup of the dispatcher.
-- All planes will be spawned as uncontrolled on the parking spot.

View File

@@ -1,4 +1,4 @@
--- **AI** - Create an automated A2G defense system based on a detection network of reconnaissance vehicles and air units, coordinating SEAD, BAI and CAS operations.
--- **AI** - Create an automated A2G defense system with reconnaissance units, coordinating SEAD, BAI and CAS operations.
--
-- ===
--
@@ -951,7 +951,7 @@ do -- AI_A2G_DISPATCHER
AI_A2G_DISPATCHER.DefenseQueue = {}
--- Defense approach types.
-- @type #AI_A2G_DISPATCHER.DefenseApproach
-- @type AI_A2G_DISPATCHER.DefenseApproach
AI_A2G_DISPATCHER.DefenseApproach = {
Random = 1,
Distance = 2,
@@ -1806,6 +1806,19 @@ do -- AI_A2G_DISPATCHER
return DefenderSquadron
end
--- Get a resource count from a specific squadron
-- @param #AI_A2G_DISPATCHER self
-- @param #string Squadron Name of the squadron.
-- @return #number Number of airframes available or nil if the squadron does not exist
function AI_A2G_DISPATCHER:QuerySquadron(Squadron)
local Squadron = self:GetSquadron(Squadron)
if Squadron.ResourceCount then
self:T2(string.format("%s = %s",Squadron.Name,Squadron.ResourceCount))
return Squadron.ResourceCount
end
self:F({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
return nil
end
--- Set the Squadron visible before startup of the dispatcher.
-- All planes will be spawned as uncontrolled on the parking spot.
@@ -1839,7 +1852,7 @@ do -- AI_A2G_DISPATCHER
--- Check if the Squadron is visible before startup of the dispatcher.
-- @param #AI_A2G_DISPATCHER self
-- @param #string SquadronName The squadron name.
-- @return #bool true if visible.
-- @return #boolean true if visible.
-- @usage
--
-- -- Set the Squadron visible before startup of dispatcher.

View File

@@ -947,7 +947,7 @@ do -- AI_AIR_DISPATCHER
AI_AIR_DISPATCHER.DefenseQueue = {}
--- Defense approach types
-- @type #AI_AIR_DISPATCHER.DefenseApproach
-- @type AI_AIR_DISPATCHER.DefenseApproach
AI_AIR_DISPATCHER.DefenseApproach = {
Random = 1,
Distance = 2,
@@ -1852,7 +1852,7 @@ do -- AI_AIR_DISPATCHER
--- Check if the Squadron is visible before startup of the dispatcher.
-- @param #AI_AIR_DISPATCHER self
-- @param #string SquadronName The squadron name.
-- @return #bool true if visible.
-- @return #boolean true if visible.
-- @usage
--
-- -- Set the Squadron visible before startup of dispatcher.

View File

@@ -147,8 +147,8 @@
-- @image Escorting.JPG
--- @type AI_ESCORT
---
-- @type AI_ESCORT
-- @extends AI.AI_Formation#AI_FORMATION
@@ -168,11 +168,14 @@
--
-- -- First find the GROUP object and the CLIENT object.
-- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
-- local EscortGroup = SET_GROUP:New():FilterPrefixes("Escort"):FilterOnce() -- The the group name of the escorts contains "Escort".
--
-- -- Now use these 2 objects to construct the new EscortPlanes object.
-- EscortPlanes = AI_ESCORT:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
--
-- EscortPlanes:MenusAirplanes() -- create menus for airplanes
-- EscortPlanes:__Start(2)
--
--
-- @field #AI_ESCORT
AI_ESCORT = {
ClassName = "AI_ESCORT",
@@ -189,7 +192,7 @@ AI_ESCORT = {
TaskPoints = {}
}
--- @field Functional.Detection#DETECTION_AREAS
-- @field Functional.Detection#DETECTION_AREAS
AI_ESCORT.Detection = nil
--- MENUPARAM type
@@ -211,10 +214,14 @@ AI_ESCORT.Detection = nil
--
-- -- First find the GROUP object and the CLIENT object.
-- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client.
-- local EscortGroup = SET_GROUP:New():FilterPrefixes("Escort"):FilterOnce() -- The the group name of the escorts contains "Escort".
--
-- -- Now use these 2 objects to construct the new EscortPlanes object.
-- EscortPlanes = AI_ESCORT:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
-- EscortPlanes:MenusAirplanes() -- create menus for airplanes
-- EscortPlanes:__Start(2)
--
--
function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
local self = BASE:Inherit( self, AI_FORMATION:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) ) -- #AI_ESCORT
@@ -227,10 +234,17 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
self.EscortGroupSet = EscortGroupSet
self.EscortGroupSet:SetSomeIteratorLimit( 8 )
self.EscortBriefing = EscortBriefing
self.Menu = {}
self.Menu.HoldAtEscortPosition = self.Menu.HoldAtEscortPosition or {}
self.Menu.HoldAtLeaderPosition = self.Menu.HoldAtLeaderPosition or {}
self.Menu.Flare = self.Menu.Flare or {}
self.Menu.Smoke = self.Menu.Smoke or {}
self.Menu.Targets = self.Menu.Targets or {}
self.Menu.ROE = self.Menu.ROE or {}
self.Menu.ROT = self.Menu.ROT or {}
-- if not EscortBriefing then
-- EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " ..
@@ -250,7 +264,7 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
EscortGroupSet:ForEachGroup(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
-- Set EscortGroup known at EscortUnit.
if not self.PlayerUnit._EscortGroups then
@@ -325,14 +339,14 @@ function AI_ESCORT:_InitEscortRoute( EscortGroup )
end
--- @param #AI_ESCORT self
-- @param #AI_ESCORT self
-- @param Core.Set#SET_GROUP EscortGroupSet
function AI_ESCORT:onafterStart( EscortGroupSet )
self:F()
EscortGroupSet:ForEachGroup(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
EscortGroup:WayPointInitialize()
@@ -370,7 +384,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
self:_InitFlightMenus()
self.EscortGroupSet:ForSomeGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
self:_InitEscortMenus( EscortGroup )
@@ -378,7 +392,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
self:SetFlightModeFormation( EscortGroup )
--- @param #AI_ESCORT self
-- @param #AI_ESCORT self
-- @param Core.Event#EVENTDATA EventData
function EscortGroup:OnEventDeadOrCrash( EventData )
self:F( { "EventDead", EventData } )
@@ -394,14 +408,14 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
end
--- @param #AI_ESCORT self
-- @param #AI_ESCORT self
-- @param Core.Set#SET_GROUP EscortGroupSet
function AI_ESCORT:onafterStop( EscortGroupSet )
self:F()
EscortGroupSet:ForEachGroup(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
EscortGroup:WayPointInitialize()
@@ -443,9 +457,9 @@ end
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
-- @param #number ZLevels The amount of levels on the Z-axis.
-- @return #AI_ESCORT
@@ -493,9 +507,9 @@ end
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
-- @param #number ZLevels The amount of levels on the Z-axis.
-- @return #AI_ESCORT
@@ -550,7 +564,7 @@ function AI_ESCORT:SetFlightMenuFormation( Formation )
local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation,
function ( self, Formation, ... )
self.EscortGroupSet:ForSomeGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup, self, Formation, Arguments )
if EscortGroup:IsAir() then
self:E({FormationID=FormationID})
@@ -580,7 +594,7 @@ end
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @return #AI_ESCORT
function AI_ESCORT:MenuFormationTrail( XStart, XSpace, YStart )
@@ -594,7 +608,7 @@ end
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
-- @return #AI_ESCORT
function AI_ESCORT:MenuFormationStack( XStart, XSpace, YStart, YSpace )
@@ -609,8 +623,8 @@ end
-- This menu will appear under **Formation**.
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
-- @return #AI_ESCORT
function AI_ESCORT:MenuFormationLeftLine( XStart, YStart, ZStart, ZSpace )
@@ -625,8 +639,8 @@ end
-- This menu will appear under **Formation**.
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
-- @return #AI_ESCORT
function AI_ESCORT:MenuFormationRightLine( XStart, YStart, ZStart, ZSpace )
@@ -642,8 +656,8 @@ end
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
-- @return #AI_ESCORT
function AI_ESCORT:MenuFormationLeftWing( XStart, XSpace, YStart, ZStart, ZSpace )
@@ -659,8 +673,8 @@ end
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
-- @return #AI_ESCORT
function AI_ESCORT:MenuFormationRightWing( XStart, XSpace, YStart, ZStart, ZSpace )
@@ -676,9 +690,9 @@ end
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
-- @return #AI_ESCORT
function AI_ESCORT:MenuFormationCenterWing( XStart, XSpace, YStart, YSpace, ZStart, ZSpace )
@@ -694,9 +708,9 @@ end
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
-- @return #AI_ESCORT
function AI_ESCORT:MenuFormationVic( XStart, XSpace, YStart, YSpace, ZStart, ZSpace )
@@ -712,9 +726,9 @@ end
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
-- @param #number ZLevels The amount of levels on the Z-axis.
-- @return #AI_ESCORT
@@ -764,7 +778,7 @@ end
function AI_ESCORT:SetFlightMenuHoldAtEscortPosition()
for _, MenuHoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do
for _, MenuHoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition or {} ) do
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
local FlightMenuHoldPosition = MENU_GROUP_COMMAND
@@ -785,7 +799,7 @@ end
function AI_ESCORT:SetEscortMenuHoldAtEscortPosition( EscortGroup )
for _, HoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do
for _, HoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition or {}) do
if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName()
local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu )
@@ -853,7 +867,7 @@ end
function AI_ESCORT:SetFlightMenuHoldAtLeaderPosition()
for _, MenuHoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition ) do
for _, MenuHoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition or {}) do
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
local FlightMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND
@@ -874,7 +888,7 @@ end
function AI_ESCORT:SetEscortMenuHoldAtLeaderPosition( EscortGroup )
for _, HoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition ) do
for _, HoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition or {}) do
if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName()
@@ -999,7 +1013,7 @@ end
function AI_ESCORT:SetFlightMenuFlare()
for _, MenuFlare in pairs( self.Menu.Flare) do
for _, MenuFlare in pairs( self.Menu.Flare or {}) do
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
local FlightMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuFlare.MenuText, FlightMenuReportNavigation )
@@ -1014,7 +1028,7 @@ end
function AI_ESCORT:SetEscortMenuFlare( EscortGroup )
for _, MenuFlare in pairs( self.Menu.Flare) do
for _, MenuFlare in pairs( self.Menu.Flare or {}) do
if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName()
@@ -1059,7 +1073,7 @@ end
function AI_ESCORT:SetFlightMenuSmoke()
for _, MenuSmoke in pairs( self.Menu.Smoke) do
for _, MenuSmoke in pairs( self.Menu.Smoke or {}) do
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
local FlightMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuSmoke.MenuText, FlightMenuReportNavigation )
@@ -1076,7 +1090,7 @@ end
function AI_ESCORT:SetEscortMenuSmoke( EscortGroup )
for _, MenuSmoke in pairs( self.Menu.Smoke) do
for _, MenuSmoke in pairs( self.Menu.Smoke or {}) do
if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName()
@@ -1169,7 +1183,7 @@ function AI_ESCORT:SetFlightMenuTargets()
local FlightMenuAttackNearbyAir = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Attack nearest airborne targets", self.FlightMenuAttack, AI_ESCORT._FlightAttackNearestTarget, self, self.__Enum.ReportType.Air ):SetTag( "Attack" )
local FlightMenuAttackNearbyGround = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Attack nearest ground targets", self.FlightMenuAttack, AI_ESCORT._FlightAttackNearestTarget, self, self.__Enum.ReportType.Ground ):SetTag( "Attack" )
for _, MenuTargets in pairs( self.Menu.Targets) do
for _, MenuTargets in pairs( self.Menu.Targets or {}) do
MenuTargets.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, MenuTargets.Interval, MenuTargets.Interval )
end
@@ -1179,7 +1193,7 @@ end
function AI_ESCORT:SetEscortMenuTargets( EscortGroup )
for _, MenuTargets in pairs( self.Menu.Targets) do
for _, MenuTargets in pairs( self.Menu.Targets or {} or {}) do
if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName()
--local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu )
@@ -1231,7 +1245,7 @@ function AI_ESCORT:MenuAssistedAttack()
self:F()
self.EscortGroupSet:ForSomeGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
if not EscortGroup:IsAir() then
-- Request assistance from other escorts.
@@ -1246,7 +1260,7 @@ end
function AI_ESCORT:SetFlightMenuROE()
for _, MenuROE in pairs( self.Menu.ROE) do
for _, MenuROE in pairs( self.Menu.ROE or {}) do
local FlightMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", self.FlightMenu )
local FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", FlightMenuROE, AI_ESCORT._FlightROEHoldFire, self, "Holding weapons!" )
@@ -1261,7 +1275,7 @@ end
function AI_ESCORT:SetEscortMenuROE( EscortGroup )
for _, MenuROE in pairs( self.Menu.ROE) do
for _, MenuROE in pairs( self.Menu.ROE or {}) do
if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName()
@@ -1302,7 +1316,7 @@ end
function AI_ESCORT:SetFlightMenuROT()
for _, MenuROT in pairs( self.Menu.ROT) do
for _, MenuROT in pairs( self.Menu.ROT or {}) do
local FlightMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", self.FlightMenu )
local FlightMenuROTNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", FlightMenuROT, AI_ESCORT._FlightROTNoReaction, self, "Fighting until death!" )
@@ -1317,7 +1331,7 @@ end
function AI_ESCORT:SetEscortMenuROT( EscortGroup )
for _, MenuROT in pairs( self.Menu.ROT) do
for _, MenuROT in pairs( self.Menu.ROT or {}) do
if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName()
@@ -1375,7 +1389,7 @@ function AI_ESCORT:SetEscortMenuResumeMission( EscortGroup )
end
--- @param #AI_ESCORT self
-- @param #AI_ESCORT self
-- @param Wrapper.Group#GROUP OrbitGroup
-- @param Wrapper.Group#GROUP EscortGroup
-- @param #number OrbitHeight
@@ -1419,7 +1433,7 @@ function AI_ESCORT:_HoldPosition( OrbitGroup, EscortGroup, OrbitHeight, OrbitSec
end
--- @param #AI_ESCORT self
-- @param #AI_ESCORT self
-- @param Wrapper.Group#GROUP OrbitGroup
-- @param #number OrbitHeight
-- @param #number OrbitSeconds
@@ -1428,7 +1442,7 @@ function AI_ESCORT:_FlightHoldPosition( OrbitGroup, OrbitHeight, OrbitSeconds )
local EscortUnit = self.PlayerUnit
self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup, OrbitGroup )
if EscortGroup:IsAir() then
if OrbitGroup == nil then
@@ -1456,7 +1470,7 @@ end
function AI_ESCORT:_FlightJoinUp()
self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
if EscortGroup:IsAir() then
self:_JoinUp( EscortGroup )
@@ -1471,7 +1485,7 @@ end
-- @param #AI_ESCORT self
-- @param #number XStart The start position on the X-axis in meters for the first group.
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
-- @param #number YStart The start position on the Y-axis in meters for the first group.
-- @return #AI_ESCORT
function AI_ESCORT:_EscortFormationTrail( EscortGroup, XStart, XSpace, YStart )
@@ -1483,7 +1497,7 @@ end
function AI_ESCORT:_FlightFormationTrail( XStart, XSpace, YStart )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
if EscortGroup:IsAir() then
self:_EscortFormationTrail( EscortGroup, XStart, XSpace, YStart )
@@ -1510,7 +1524,7 @@ end
function AI_ESCORT:_FlightFormationStack( XStart, XSpace, YStart, YSpace )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
if EscortGroup:IsAir() then
self:_EscortFormationStack( EscortGroup, XStart, XSpace, YStart, YSpace )
@@ -1533,7 +1547,7 @@ end
function AI_ESCORT:_FlightFlare( Color, Message )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
if EscortGroup:IsAir() then
self:_Flare( EscortGroup, Color, Message )
@@ -1556,7 +1570,7 @@ end
function AI_ESCORT:_FlightSmoke( Color, Message )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
if EscortGroup:IsAir() then
self:_Smoke( EscortGroup, Color, Message )
@@ -1587,7 +1601,7 @@ end
function AI_ESCORT:_FlightSwitchReportNearbyTargets( ReportTargets )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup )
if EscortGroup:IsAir() then
self:_EscortSwitchReportNearbyTargets( EscortGroup, ReportTargets )
@@ -1679,7 +1693,7 @@ function AI_ESCORT:_ScanTargets( ScanDuration )
end
--- @param Wrapper.Group#GROUP EscortGroup
-- @param Wrapper.Group#GROUP EscortGroup
-- @param #AI_ESCORT self
function AI_ESCORT.___Resume( EscortGroup, self )
@@ -1701,7 +1715,7 @@ function AI_ESCORT.___Resume( EscortGroup, self )
end
--- @param #AI_ESCORT self
-- @param #AI_ESCORT self
-- @param Wrapper.Group#GROUP EscortGroup
-- @param #number WayPoint
function AI_ESCORT:_ResumeMission( EscortGroup, WayPoint )
@@ -1723,7 +1737,7 @@ function AI_ESCORT:_ResumeMission( EscortGroup, WayPoint )
end
--- @param #AI_ESCORT self
-- @param #AI_ESCORT self
-- @param Wrapper.Group#GROUP EscortGroup The escort group that will attack the detected item.
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem )
@@ -1743,7 +1757,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem )
local AttackUnitTasks = {}
DetectedSet:ForEachUnit(
--- @param Wrapper.Unit#UNIT DetectedUnit
-- @param Wrapper.Unit#UNIT DetectedUnit
function( DetectedUnit, Tasks )
if DetectedUnit:IsAlive() then
AttackUnitTasks[#AttackUnitTasks+1] = EscortGroup:TaskAttackUnit( DetectedUnit )
@@ -1767,7 +1781,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem )
local Tasks = {}
DetectedSet:ForEachUnit(
--- @param Wrapper.Unit#UNIT DetectedUnit
-- @param Wrapper.Unit#UNIT DetectedUnit
function( DetectedUnit, Tasks )
if DetectedUnit:IsAlive() then
Tasks[#Tasks+1] = EscortGroup:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 )
@@ -1795,7 +1809,7 @@ end
function AI_ESCORT:_FlightAttackTarget( DetectedItem )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup
-- @param Core.Group#GROUP EscortGroup
function( EscortGroup, DetectedItem )
if EscortGroup:IsAir() then
self:_AttackTarget( EscortGroup, DetectedItem )
@@ -1842,7 +1856,7 @@ end
---
--- @param #AI_ESCORT self
-- @param #AI_ESCORT self
-- @param Wrapper.Group#GROUP EscortGroup The escort group that will attack the detected item.
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem )
@@ -1854,7 +1868,7 @@ function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem )
local Tasks = {}
DetectedSet:ForEachUnit(
--- @param Wrapper.Unit#UNIT DetectedUnit
-- @param Wrapper.Unit#UNIT DetectedUnit
function( DetectedUnit, Tasks )
if DetectedUnit:IsAlive() then
Tasks[#Tasks+1] = EscortGroup:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 )
@@ -1881,7 +1895,7 @@ end
function AI_ESCORT:_FlightROEHoldFire( EscortROEMessage )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup
-- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup )
self:_ROE( EscortGroup, EscortGroup.OptionROEHoldFire, EscortROEMessage )
end
@@ -1890,7 +1904,7 @@ end
function AI_ESCORT:_FlightROEOpenFire( EscortROEMessage )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup
-- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup )
self:_ROE( EscortGroup, EscortGroup.OptionROEOpenFire, EscortROEMessage )
end
@@ -1899,7 +1913,7 @@ end
function AI_ESCORT:_FlightROEReturnFire( EscortROEMessage )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup
-- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup )
self:_ROE( EscortGroup, EscortGroup.OptionROEReturnFire, EscortROEMessage )
end
@@ -1908,7 +1922,7 @@ end
function AI_ESCORT:_FlightROEWeaponFree( EscortROEMessage )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup
-- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup )
self:_ROE( EscortGroup, EscortGroup.OptionROEWeaponFree, EscortROEMessage )
end
@@ -1924,7 +1938,7 @@ end
function AI_ESCORT:_FlightROTNoReaction( EscortROTMessage )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup
-- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup )
self:_ROT( EscortGroup, EscortGroup.OptionROTNoReaction, EscortROTMessage )
end
@@ -1933,7 +1947,7 @@ end
function AI_ESCORT:_FlightROTPassiveDefense( EscortROTMessage )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup
-- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup )
self:_ROT( EscortGroup, EscortGroup.OptionROTPassiveDefense, EscortROTMessage )
end
@@ -1942,7 +1956,7 @@ end
function AI_ESCORT:_FlightROTEvadeFire( EscortROTMessage )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup
-- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup )
self:_ROT( EscortGroup, EscortGroup.OptionROTEvadeFire, EscortROTMessage )
end
@@ -1951,7 +1965,7 @@ end
function AI_ESCORT:_FlightROTVertical( EscortROTMessage )
self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup
-- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup )
self:_ROT( EscortGroup, EscortGroup.OptionROTVertical, EscortROTMessage )
end
@@ -2178,5 +2192,3 @@ function AI_ESCORT:_FlightReportTargetsScheduler()
return false
end

View File

@@ -88,6 +88,7 @@ DATABASE = {
WAREHOUSES = {},
FLIGHTGROUPS = {},
FLIGHTCONTROLS = {},
OPSZONES = {},
PATHLINES = {},
}
@@ -580,6 +581,46 @@ do -- Zone_Goal
end
end -- Zone_Goal
do -- OpsZone
--- Finds a @{Ops.OpsZone#OPSZONE} based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
-- @return Ops.OpsZone#OPSZONE The found OPSZONE.
function DATABASE:FindOpsZone( ZoneName )
local ZoneFound = self.OPSZONES[ZoneName]
return ZoneFound
end
--- Adds a @{Ops.OpsZone#OPSZONE} based on the zone name in the DATABASE.
-- @param #DATABASE self
-- @param Ops.OpsZone#OPSZONE OpsZone The zone.
function DATABASE:AddOpsZone( OpsZone )
if OpsZone then
local ZoneName=OpsZone:GetName()
if not self.OPSZONES[ZoneName] then
self.OPSZONES[ZoneName] = OpsZone
end
end
end
--- Deletes a @{Ops.OpsZone#OPSZONE} from the DATABASE based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
function DATABASE:DeleteOpsZone( ZoneName )
self.OPSZONES[ZoneName] = nil
end
end -- OpsZone
do -- cargo
--- Adds a Cargo based on the Cargo Name in the DATABASE.
@@ -1083,7 +1124,7 @@ end
-- @param #string AirbaseName Name of the airbase.
-- @return #number Category.
function DATABASE:GetCategoryFromAirbase( AirbaseName )
return self.AIRBASES[AirbaseName]:GetCategory()
return self.AIRBASES[AirbaseName]:GetAirbaseCategory()
end
@@ -1599,10 +1640,10 @@ end
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called object in the database. The function needs to accept a CLIENT parameter.
-- @return #DATABASE self
function DATABASE:ForEachClient( IteratorFunction, ... )
function DATABASE:ForEachClient( IteratorFunction, FinalizeFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self.CLIENTS )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.CLIENTS )
return self
end
@@ -1611,10 +1652,10 @@ end
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a CLIENT parameter.
-- @return #DATABASE self
function DATABASE:ForEachCargo( IteratorFunction, ... )
function DATABASE:ForEachCargo( IteratorFunction, FinalizeFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self.CARGOS )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.CARGOS )
return self
end

View File

@@ -1224,7 +1224,7 @@ function EVENT:onEvent( Event )
if Event.TgtObjectCategory == Object.Category.STATIC then
-- get base data
Event.TgtDCSUnit = Event.target
if Event.target:isExist() and Event.id ~= 33 and not Event.TgtObjectCategory == Object.Category.COORDINATE then -- leave out ejected seat object
if Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )

View File

@@ -540,7 +540,7 @@ do -- COORDINATE
local gotscenery=false
local function EvaluateZone(ZoneObject)
BASE:T({ZoneObject})
if ZoneObject then
-- Get category of scanned object.
@@ -603,6 +603,46 @@ do -- COORDINATE
return set
end
--- Scan/find STATICS within a certain radius around the coordinate using the world.searchObjects() DCS API function.
-- @param #COORDINATE self
-- @param #number radius (Optional) Scan radius in meters. Default 100 m.
-- @return Core.Set#SET_UNIT Set of units.
function COORDINATE:ScanStatics(radius)
local _,_,_,_,statics=self:ScanObjects(radius, false, true, false)
local set=SET_STATIC:New()
for _,stat in pairs(statics) do
set:AddStatic(STATIC:Find(stat))
end
return set
end
--- Find the closest static to the COORDINATE within a certain radius.
-- @param #COORDINATE self
-- @param #number radius Scan radius in meters. Default 100 m.
-- @return Wrapper.Static#STATIC The closest static or #nil if no unit is inside the given radius.
function COORDINATE:FindClosestStatic(radius)
local units=self:ScanStatics(radius)
local umin=nil --Wrapper.Unit#UNIT
local dmin=math.huge
for _,_unit in pairs(units.Set) do
local unit=_unit --Wrapper.Static#STATIC
local coordinate=unit:GetCoordinate()
local d=self:Get2DDistance(coordinate)
if d<dmin then
dmin=d
umin=unit
end
end
return umin
end
--- Find the closest unit to the COORDINATE within a certain radius.
-- @param #COORDINATE self
@@ -2904,8 +2944,13 @@ do -- COORDINATE
if alt < 1 then
alttext = "very low"
end
local track = UTILS.BearingToCardinal(bearing) or "North"
-- corrected Track to be direction of travel of bogey (self in this case)
local track = "Maneuver"
if self.Heading then
track = UTILS.BearingToCardinal(self.Heading) or "North"
end
if rangeNM > 3 then
if SSML then -- google says "oh" instead of zero, be aware
@@ -3283,7 +3328,52 @@ do -- COORDINATE
return self:GetTemperatureText( nil, Settings )
end
--- Function to check if a coordinate is in a steep (>8% elevation) area of the map
-- @param #COORDINATE self
-- @param #number Radius (Optional) Radius to check around the coordinate, defaults to 50m (100m diameter)
-- @param #number Minelevation (Optional) Elevation from which on a area is defined as steep, defaults to 8% (8m height gain across 100 meters)
-- @return #boolen IsSteep If true, area is steep
-- @return #number MaxElevation Elevation in meters measured over 100m
function COORDINATE:IsInSteepArea(Radius,Minelevation)
local steep = false
local elev = Minelevation or 8
local bdelta = 0
local h0 = self:GetLandHeight()
local radius = Radius or 50
local diam = radius * 2
for i=0,150,30 do
local polar = math.fmod(i+180,360)
local c1 = self:Translate(radius,i,false,false)
local c2 = self:Translate(radius,polar,false,false)
local h1 = c1:GetLandHeight()
local h2 = c2:GetLandHeight()
local d1 = math.abs(h1-h2)
local d2 = math.abs(h0-h1)
local d3 = math.abs(h0-h2)
local dm = d1 > d2 and d1 or d2
local dm1 = dm > d3 and dm or d3
bdelta = dm1 > bdelta and dm1 or bdelta
self:T(string.format("d1=%d, d2=%d, d3=%d, max delta=%d",d1,d2,d3,bdelta))
end
local steepness = bdelta / (radius / 100)
if steepness >= elev then steep = true end
return steep, math.floor(steepness)
end
--- Function to check if a coordinate is in a flat (<8% elevation) area of the map
-- @param #COORDINATE self
-- @param #number Radius (Optional) Radius to check around the coordinate, defaults to 50m (100m diameter)
-- @param #number Minelevation (Optional) Elevation from which on a area is defined as steep, defaults to 8% (8m height gain across 100 meters)
-- @return #boolen IsFlat If true, area is flat
-- @return #number MaxElevation Elevation in meters measured over 100m
function COORDINATE:IsInFlatArea(Radius,Minelevation)
local steep, elev = self:IsInSteepArea(Radius,Minelevation)
local flat = not steep
return flat, elev
end
end
do -- POINT_VEC3

View File

@@ -904,6 +904,8 @@ end
do -- SET_GROUP
--- @type SET_GROUP #SET_GROUP
-- @field Core.Timer#TIMER ZoneTimer
-- @field #number ZoneTimerInterval
-- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_GROUP} class to build sets of groups belonging to certain:
@@ -1343,6 +1345,25 @@ do -- SET_GROUP
end
return self
end
--- [Internal] Private function for use of continous zone filter
-- @param #SET_GROUP self
-- @return #SET_GROUP self
function SET_GROUP:_ContinousZoneFilter()
local Database = _DATABASE.GROUPS
for ObjectName, Object in pairs( Database ) do
if self:IsIncludeObject( Object ) and self:IsNotInSet(Object) then
self:Add( ObjectName, Object )
elseif (not self:IsIncludeObject( Object )) and self:IsInSet(Object) then
self:Remove(ObjectName)
end
end
return self
end
--- Builds a set of groups that are only active.
-- Only the groups that are active will be included within the set.
@@ -1381,10 +1402,46 @@ do -- SET_GROUP
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash )
if self.Filter.Zones then
self.ZoneTimer = TIMER:New(self._ContinousZoneFilter,self)
local timing = self.ZoneTimerInterval or 30
self.ZoneTimer:Start(timing,timing)
end
end
return self
end
--- Set filter timer interval for FilterZones if using active filtering with FilterStart().
-- @param #SET_GROUP self
-- @param #number Seconds Seconds between check intervals, defaults to 30. **Caution** - do not be too agressive with timing! Groups are usually not moving fast enough
-- to warrant a check of below 10 seconds.
-- @return #SET_GROUP self
function SET_GROUP:FilterZoneTimer(Seconds)
self.ZoneTimerInterval = Seconds or 30
return self
end
--- Stops the filtering.
-- @param #SET_GROUP self
-- @return #SET_GROUP self
function SET_GROUP:FilterStop()
if _DATABASE then
self:UnHandleEvent(EVENTS.Birth)
self:UnHandleEvent(EVENTS.Dead)
self:UnHandleEvent(EVENTS.Crash)
self:UnHandleEvent(EVENTS.RemoveUnit)
if self.Filter.Zones and self.ZoneTimer and self.ZoneTimer:IsRunning() then
self.ZoneTimer:Stop()
end
end
return self
end
--- Handles the OnDead or OnCrash event for alive groups set.
-- Note: The GROUP object in the SET_GROUP collection will only be removed if the last unit is destroyed of the GROUP.
@@ -1888,7 +1945,7 @@ do -- SET_GROUP
if self.Filter.Zones then
local MGroupZone = false
for ZoneName, Zone in pairs( self.Filter.Zones ) do
self:T3( "Zone:", ZoneName )
--self:I( "Zone:", ZoneName )
if MGroup:IsInZone(Zone) then
MGroupZone = true
end
@@ -1956,6 +2013,8 @@ end
do -- SET_UNIT
--- @type SET_UNIT
-- @field Core.Timer#TIMER ZoneTimer
-- @field #number ZoneTimerInterval
-- @extends Core.Set#SET_BASE
--- Mission designers can use the SET_UNIT class to build sets of units belonging to certain:
@@ -2347,7 +2406,56 @@ do -- SET_UNIT
return CountU
end
--- [Internal] Private function for use of continous zone filter
-- @param #SET_UNIT self
-- @return #SET_UNIT self
function SET_UNIT:_ContinousZoneFilter()
local Database = _DATABASE.UNITS
for ObjectName, Object in pairs( Database ) do
if self:IsIncludeObject( Object ) and self:IsNotInSet(Object) then
self:Add( ObjectName, Object )
elseif (not self:IsIncludeObject( Object )) and self:IsInSet(Object) then
self:Remove(ObjectName)
end
end
return self
end
--- Set filter timer interval for FilterZones if using active filtering with FilterStart().
-- @param #SET_UNIT self
-- @param #number Seconds Seconds between check intervals, defaults to 30. **Caution** - do not be too agressive with timing! Groups are usually not moving fast enough
-- to warrant a check of below 10 seconds.
-- @return #SET_UNIT self
function SET_UNIT:FilterZoneTimer(Seconds)
self.ZoneTimerInterval = Seconds or 30
return self
end
--- Stops the filtering.
-- @param #SET_UNIT self
-- @return #SET_UNIT self
function SET_UNIT:FilterStop()
if _DATABASE then
self:UnHandleEvent(EVENTS.Birth)
self:UnHandleEvent(EVENTS.Dead)
self:UnHandleEvent(EVENTS.Crash)
self:UnHandleEvent(EVENTS.RemoveUnit)
if self.Filter.Zones and self.ZoneTimer and self.ZoneTimer:IsRunning() then
self.ZoneTimer:Stop()
end
end
return self
end
--- Starts the filtering.
-- @param #SET_UNIT self
-- @return #SET_UNIT self
@@ -2359,6 +2467,11 @@ do -- SET_UNIT
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash )
if self.Filter.Zones then
self.ZoneTimer = TIMER:New(self._ContinousZoneFilter,self)
local timing = self.ZoneTimerInterval or 30
self.ZoneTimer:Start(timing,timing)
end
end
return self
@@ -3834,6 +3947,8 @@ end
do -- SET_CLIENT
--- @type SET_CLIENT
-- @field Core.Timer#TIMER ZoneTimer
-- @field #number ZoneTimerInterval
-- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_CLIENT} class to build sets of units belonging to certain:
@@ -4141,6 +4256,54 @@ do -- SET_CLIENT
return self
end
--- [Internal] Private function for use of continous zone filter
-- @param #SET_CLIENT self
-- @return #SET_CLIENT self
function SET_CLIENT:_ContinousZoneFilter()
local Database = _DATABASE.CLIENTS
for ObjectName, Object in pairs( Database ) do
if self:IsIncludeObject( Object ) and self:IsNotInSet(Object) then
self:Add( ObjectName, Object )
elseif (not self:IsIncludeObject( Object )) and self:IsInSet(Object) then
self:Remove(ObjectName)
end
end
return self
end
--- Set filter timer interval for FilterZones if using active filtering with FilterStart().
-- @param #SET_CLIENT self
-- @param #number Seconds Seconds between check intervals, defaults to 30. **Caution** - do not be too agressive with timing! Groups are usually not moving fast enough
-- to warrant a check of below 10 seconds.
-- @return #SET_CLIENT self
function SET_CLIENT:FilterZoneTimer(Seconds)
self.ZoneTimerInterval = Seconds or 30
return self
end
--- Stops the filtering.
-- @param #SET_CLIENT self
-- @return #SET_CLIENT self
function SET_CLIENT:FilterStop()
if _DATABASE then
self:UnHandleEvent(EVENTS.Birth)
self:UnHandleEvent(EVENTS.Dead)
self:UnHandleEvent(EVENTS.Crash)
if self.Filter.Zones and self.ZoneTimer and self.ZoneTimer:IsRunning() then
self.ZoneTimer:Stop()
end
end
return self
end
--- Starts the filtering.
-- @param #SET_CLIENT self
-- @return #SET_CLIENT self
@@ -4151,6 +4314,11 @@ do -- SET_CLIENT
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
if self.Filter.Zones then
self.ZoneTimer = TIMER:New(self._ContinousZoneFilter,self)
local timing = self.ZoneTimerInterval or 30
self.ZoneTimer:Start(timing,timing)
end
end
return self
@@ -7629,7 +7797,7 @@ do -- SET_SCENERY
end
---
--- [Internal] Determine if an object is to be included in the SET
-- @param #SET_SCENERY self
-- @param Wrapper.Scenery#SCENERY MScenery
-- @return #SET_SCENERY self
@@ -7637,4 +7805,47 @@ do -- SET_SCENERY
self:F2( MScenery )
return true
end
--- Count overall initial (Life0) lifepoints of the SET objects.
-- @param #SET_SCENERY self
-- @return #number LIfe0Points
function SET_SCENERY:GetLife0()
local life0 = 0
self:ForEachScenery(
function(obj)
local Obj = obj -- Wrapper.Scenery#SCENERY
life0 = life0 + Obj:GetLife0()
end
)
return life0
end
--- Count overall current lifepoints of the SET objects.
-- @param #SET_SCENERY self
-- @return #number LifePoints
function SET_SCENERY:GetLife()
local life = 0
self:ForEachScenery(
function(obj)
local Obj = obj -- Wrapper.Scenery#SCENERY
life = life + Obj:GetLife()
end
)
return life
end
--- Calculate current relative lifepoints of the SET objects, i.e. Life divided by Life0 as percentage value, eg 75 meaning 75% alive.
-- **CAVEAT**: Some objects change their life value or "hitpoints" **after** the first hit. Hence we will adjust the Life0 value to 120%
-- of the last life value if life exceeds life0 ata any point.
-- Thus will will get a smooth percentage decrease, if you use this e.g. as success criteria for a bombing task.
-- @param #SET_SCENERY self
-- @return #number LifePoints
function SET_SCENERY:GetRelativeLife()
local life = self:GetLife()
local life0 = self:GetLife0()
self:T3(string.format("Set Lifepoints: %d life0 | %d life",life0,life))
local rlife = math.floor((life / life0) * 100)
return rlife
end
end

View File

@@ -162,7 +162,17 @@
-- ### Array formation
--
-- * @{#SPAWN.InitArray}(): Make groups visible before they are actually activated, and order these groups like a battalion in an array.
--
--
-- ### Group initial position - if wanted different from template position, for use with e.g. @{#SPAWN.SpawnScheduled}().
--
-- * @{#SPAWN.InitPositionCoordinate}(): Set initial position of group via a COORDINATE.
-- * @{#SPAWN.InitPositionVec2}(): Set initial position of group via a VEC2.
--
-- ### Set the positions of a group's units to absolute positions, or relative positions to unit No. 1
--
-- * @{#SPAWN.InitSetUnitRelativePositions}(): Spawn the UNITs of this group with individual relative positions to unit #1 and individual headings.
-- * @{#SPAWN.InitSetUnitAbsolutePositions}(): Spawn the UNITs of this group with individual absolute positions and individual headings.
--
-- ### Position randomization
--
-- * @{#SPAWN.InitRandomizePosition}(): Randomizes the position of @{Wrapper.Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens.
@@ -268,7 +278,7 @@ SPAWN = {
-- @type SPAWN.Takeoff
-- @extends Wrapper.Group#GROUP.Takeoff
--- @field #SPAWN.Takeoff Takeoff
-- @field #SPAWN.Takeoff Takeoff
SPAWN.Takeoff = {
Air = 1,
Runway = 2,
@@ -276,7 +286,7 @@ SPAWN.Takeoff = {
Cold = 4,
}
--- @type SPAWN.SpawnZoneTable
-- @type SPAWN.SpawnZoneTable
-- @list <Core.Zone#ZONE_BASE> SpawnZone
--- Creates the main object to spawn a @{Wrapper.Group} defined in the DCS ME.
@@ -335,7 +345,7 @@ end
-- @param #SPAWN self
-- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template.
-- @param #string SpawnAliasPrefix is the name that will be given to the Group at runtime.
-- @return #SPAWN
-- @return #SPAWN self
-- @usage
-- -- NATO helicopters engaging in the battle field.
-- Spawn_BE_KA50 = SPAWN:NewWithAlias( 'BE KA-50@RAMP-Ground Defense', 'Helicopter Attacking a City' )
@@ -385,32 +395,129 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix )
return self
end
--- Creates a new SPAWN instance to create new groups based on the provided template.
--- Creates a new SPAWN instance to create new groups based on the provided template. This will also register the template for future use.
-- @param #SPAWN self
-- @param #table SpawnTemplate is the Template of the Group. This must be a valid Group Template structure!
-- @param #string SpawnTemplatePrefix is the name of the Group that will be given at each spawn.
-- @param #string SpawnAliasPrefix is the name that will be given to the Group at runtime.
-- @return #SPAWN
-- @param #table SpawnTemplate is the Template of the Group. This must be a valid Group Template structure - see [Hoggit Wiki](https://wiki.hoggitworld.com/view/DCS_func_addGroup)!
-- @param #string SpawnTemplatePrefix [Mandatory] is the name of the template and the prefix of the GROUP on spawn. The name in the template **will** be overwritten!
-- @param #string SpawnAliasPrefix [Optional] is the prefix that will be given to the GROUP on spawn.
-- @param #boolean NoMooseNamingPostfix [Optional] If true, skip the Moose naming additions (like groupname#001-01) - **but** you need to ensure yourself no duplicate group names exist!
-- @return #SPAWN self
-- @usage
-- -- Create a new SPAWN object based on a Group Template defined from scratch.
-- Spawn_BE_KA50 = SPAWN:NewWithAlias( 'BE KA-50@RAMP-Ground Defense', 'Helicopter Attacking a City' )
-- @usage
--
-- -- Create a new CSAR_Spawn object based on a normal Group Template to spawn a soldier.
-- local CSAR_Spawn = SPAWN:NewWithFromTemplate( Template, "CSAR", "Pilot" )
--
function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix )
local self = BASE:Inherit( self, BASE:New() )
self:F( { SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix } )
if SpawnAliasPrefix == nil or SpawnAliasPrefix == "" then
BASE:I( "ERROR: in function NewFromTemplate, required parameter SpawnAliasPrefix is not set" )
-- -- Spawn a P51 Mustang from scratch
-- local ttemp =
-- {
-- ["modulation"] = 0,
-- ["tasks"] =
-- {
-- }, -- end of ["tasks"]
-- ["task"] = "Reconnaissance",
-- ["uncontrolled"] = false,
-- ["route"] =
-- {
-- ["points"] =
-- {
-- [1] =
-- {
-- ["alt"] = 2000,
-- ["action"] = "Turning Point",
-- ["alt_type"] = "BARO",
-- ["speed"] = 125,
-- ["task"] =
-- {
-- ["id"] = "ComboTask",
-- ["params"] =
-- {
-- ["tasks"] =
-- {
-- }, -- end of ["tasks"]
-- }, -- end of ["params"]
-- }, -- end of ["task"]
-- ["type"] = "Turning Point",
-- ["ETA"] = 0,
-- ["ETA_locked"] = true,
-- ["y"] = 666285.71428571,
-- ["x"] = -312000,
-- ["formation_template"] = "",
-- ["speed_locked"] = true,
-- }, -- end of [1]
-- }, -- end of ["points"]
-- }, -- end of ["route"]
-- ["groupId"] = 1,
-- ["hidden"] = false,
-- ["units"] =
-- {
-- [1] =
-- {
-- ["alt"] = 2000,
-- ["alt_type"] = "BARO",
-- ["livery_id"] = "USAF 364th FS",
-- ["skill"] = "High",
-- ["speed"] = 125,
-- ["type"] = "TF-51D",
-- ["unitId"] = 1,
-- ["psi"] = 0,
-- ["y"] = 666285.71428571,
-- ["x"] = -312000,
-- ["name"] = "P51-1-1",
-- ["payload"] =
-- {
-- ["pylons"] =
-- {
-- }, -- end of ["pylons"]
-- ["fuel"] = 340.68,
-- ["flare"] = 0,
-- ["chaff"] = 0,
-- ["gun"] = 100,
-- }, -- end of ["payload"]
-- ["heading"] = 0,
-- ["callsign"] =
-- {
-- [1] = 1,
-- [2] = 1,
-- ["name"] = "Enfield11",
-- [3] = 1,
-- }, -- end of ["callsign"]
-- ["onboard_num"] = "010",
-- }, -- end of [1]
-- }, -- end of ["units"]
-- ["y"] = 666285.71428571,
-- ["x"] = -312000,
-- ["name"] = "P51",
-- ["communication"] = true,
-- ["start_time"] = 0,
-- ["frequency"] = 124,
-- }
--
--
-- local mustang = SPAWN:NewFromTemplate(ttemp,"P51D")
-- -- you MUST set the next three:
-- mustang:InitCountry(country.id.FRANCE)
-- mustang:InitCategory(Group.Category.AIRPLANE)
-- mustang:InitCoalition(coalition.side.BLUE)
-- mustang:OnSpawnGroup(
-- function(grp)
-- MESSAGE:New("Group Spawned: "..grp:GetName(),15,"SPAWN"):ToAll()
-- end
-- )
-- mustang:Spawn()
--
function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix, NoMooseNamingPostfix )
local self = BASE:Inherit( self, BASE:New() )
self:F( { SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPrefix } )
--if SpawnAliasPrefix == nil or SpawnAliasPrefix == "" then
--BASE:I( "ERROR: in function NewFromTemplate, required parameter SpawnAliasPrefix is not set" )
--return nil
--end
if SpawnTemplatePrefix == nil or SpawnTemplatePrefix == "" then
BASE:I( "ERROR: in function NewFromTemplate, required parameter SpawnTemplatePrefix is not set" )
return nil
end
if SpawnTemplate then
self.SpawnTemplate = SpawnTemplate -- Contains the template structure for a Group Spawn from the Mission Editor. Note that this group must have lateActivation always on!!!
self.SpawnTemplatePrefix = SpawnTemplatePrefix
self.SpawnAliasPrefix = SpawnAliasPrefix
self.SpawnAliasPrefix = SpawnAliasPrefix or SpawnTemplatePrefix
self.SpawnTemplate.name = SpawnTemplatePrefix
self.SpawnIndex = 0
self.SpawnCount = 0 -- The internal counter of the amount of spawning the has happened since SpawnStart.
self.AliveUnits = 0 -- Contains the counter how many units are currently alive
@@ -435,7 +542,11 @@ function SPAWN:NewFromTemplate( SpawnTemplate, SpawnTemplatePrefix, SpawnAliasPr
self.SpawnInitModex = nil
self.SpawnInitAirbase = nil
self.TweakedTemplate = true -- Check if the user is using self made template.
self.MooseNameing = true
if NoMooseNamingPostfix == true then
self.MooseNameing = false
end
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
else
error( "There is no template provided for SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" )
@@ -946,7 +1057,7 @@ end
--- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types.
-- @param #SPAWN self
-- @param #table SpawnZoneTable A table with @{Core.Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Core.Zone}s objects.
-- @return #SPAWN
-- @return #SPAWN self
-- @usage
--
-- -- Create a zone table of the 2 zones.
@@ -976,6 +1087,31 @@ function SPAWN:InitRandomizeZones( SpawnZoneTable )
return self
end
--- This method sets a spawn position for the group that is different from the location of the template.
-- @param #SPAWN self
-- @param Core.Point#COORDINATE Coordinate The position to spawn from
-- @return #SPAWN self
function SPAWN:InitPositionCoordinate(Coordinate)
self:T( { self.SpawnTemplatePrefix, Coordinate:GetVec2()} )
self:InitPositionVec2(Coordinate:GetVec2())
return self
end
--- This method sets a spawn position for the group that is different from the location of the template.
-- @param #SPAWN self
-- @param DCS#Vec2 Vec2 The position to spawn from
-- @return #SPAWN self
function SPAWN:InitPositionVec2(Vec2)
self:T( { self.SpawnTemplatePrefix, Vec2} )
self.SpawnInitPosition = Vec2
self.SpawnFromNewPosition = true
self:I("MaxGroups:"..self.SpawnMaxGroups)
for SpawnGroupID = 1, self.SpawnMaxGroups do
self:_SetInitialPosition( SpawnGroupID )
end
return self
end
--- For planes and helicopters, when these groups go home and land on their home airbases and FARPs, they normally would taxi to the parking spot, shut-down their engines and wait forever until the Group is removed by the runtime environment.
-- This method is used to re-spawn automatically (so no extra call is needed anymore) the same group after it has landed.
-- This will enable a spawned group to be re-spawned after it lands, until it is destroyed...
@@ -1275,7 +1411,12 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
self:F2( { SpawnTemplatePrefix = self.SpawnTemplatePrefix, SpawnIndex = SpawnIndex, AliveUnits = self.AliveUnits, SpawnMaxGroups = self.SpawnMaxGroups } )
if self:_GetSpawnIndex( SpawnIndex ) then
if self.SpawnFromNewPosition then
self:_SetInitialPosition( SpawnIndex )
end
if self.SpawnGroups[self.SpawnIndex].Visible then
self.SpawnGroups[self.SpawnIndex].Group:Activate()
else
@@ -1513,7 +1654,7 @@ end
-- @param #number SpawnTime The time interval defined in seconds between each new spawn of new groups.
-- @param #number SpawnTimeVariation The variation to be applied on the defined time interval between each new spawn.
-- The variation is a number between 0 and 1, representing the % of variation to be applied on the time interval.
-- @param #boolen WithDelay Do not spawn the **first** group immediately, but delay the spawn as per the calculation below.
-- @param #boolean WithDelay Do not spawn the **first** group immediately, but delay the spawn as per the calculation below.
-- Effectively the same as @{InitDelayOn}().
-- @return #SPAWN self
-- @usage
@@ -3026,7 +3167,11 @@ function SPAWN:_GetTemplate( SpawnTemplatePrefix )
self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnTemplatePrefix } )
local SpawnTemplate = nil
if _DATABASE.Templates.Groups[SpawnTemplatePrefix] == nil then
error( 'No Template exists for SpawnTemplatePrefix = ' .. SpawnTemplatePrefix )
end
local Template = _DATABASE.Templates.Groups[SpawnTemplatePrefix].Template
self:F( { Template = Template } )
@@ -3060,6 +3205,11 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
if self.TweakedTemplate ~= nil and self.TweakedTemplate == true then
BASE:I( "WARNING: You are using a tweaked template." )
SpawnTemplate = self.SpawnTemplate
if self.MooseNameing == true then
SpawnTemplate.name = self:SpawnGroupName( SpawnIndex )
else
SpawnTemplate.name = self:SpawnGroupName()
end
else
SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix )
SpawnTemplate.name = self:SpawnGroupName( SpawnIndex )
@@ -3190,6 +3340,57 @@ function SPAWN:_RandomizeTemplate( SpawnIndex )
return self
end
--- Private method that sets the DCS#Vec2 where the Group will be spawned.
-- @param #SPAWN self
-- @param #number SpawnIndex
-- @return #SPAWN self
function SPAWN:_SetInitialPosition( SpawnIndex )
self:T( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } )
if self.SpawnFromNewPosition then
self:T( "Preparing Spawn at Vec2 ", self.SpawnInitPosition )
local SpawnVec2 = self.SpawnInitPosition
self:T( { SpawnVec2 = SpawnVec2 } )
local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate
SpawnTemplate.route = SpawnTemplate.route or {}
SpawnTemplate.route.points = SpawnTemplate.route.points or {}
SpawnTemplate.route.points[1] = SpawnTemplate.route.points[1] or {}
SpawnTemplate.route.points[1].x = SpawnTemplate.route.points[1].x or 0
SpawnTemplate.route.points[1].y = SpawnTemplate.route.points[1].y or 0
self:T( { Route = SpawnTemplate.route } )
for UnitID = 1, #SpawnTemplate.units do
local UnitTemplate = SpawnTemplate.units[UnitID]
self:T( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
local SX = UnitTemplate.x
local SY = UnitTemplate.y
local BX = SpawnTemplate.route.points[1].x
local BY = SpawnTemplate.route.points[1].y
local TX = SpawnVec2.x + (SX - BX)
local TY = SpawnVec2.y + (SY - BY)
UnitTemplate.x = TX
UnitTemplate.y = TY
-- TODO: Manage altitude based on landheight...
-- SpawnTemplate.units[UnitID].alt = SpawnVec2:
self:T( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
end
SpawnTemplate.route.points[1].x = SpawnVec2.x
SpawnTemplate.route.points[1].y = SpawnVec2.y
SpawnTemplate.x = SpawnVec2.x
SpawnTemplate.y = SpawnVec2.y
end
return self
end
--- Private method that randomizes the @{Core.Zone}s where the Group will be spawned.
-- @param #SPAWN self
-- @param #number SpawnIndex
@@ -3309,7 +3510,7 @@ end
-- TODO Need to delete this... _DATABASE does this now ...
--- @param #SPAWN self
-- @param #SPAWN self
-- @param Core.Event#EVENTDATA EventData
function SPAWN:_OnBirth( EventData )
self:F( self.SpawnTemplatePrefix )
@@ -3329,7 +3530,7 @@ function SPAWN:_OnBirth( EventData )
end
--- @param #SPAWN self
-- @param #SPAWN self
-- @param Core.Event#EVENTDATA EventData
function SPAWN:_OnDeadOrCrash( EventData )
self:F( self.SpawnTemplatePrefix )

View File

@@ -33,7 +33,8 @@
do
--- @type SPOT
---
-- @type SPOT
-- @extends Core.Fsm#FSM
@@ -228,7 +229,8 @@ do
-- @param #number LaserCode Laser code.
-- @param #number Duration Duration of lasing in seconds.
function SPOT:onafterLaseOn( From, Event, To, Target, LaserCode, Duration )
self:F( { "LaseOn", Target, LaserCode, Duration } )
self:T({From, Event, To})
self:T2( { "LaseOn", Target, LaserCode, Duration } )
local function StopLase( self )
self:LaseOff()
@@ -256,6 +258,8 @@ do
self:HandleEvent( EVENTS.Dead )
self:__Lasing( -1 )
return self
end
@@ -268,7 +272,7 @@ do
-- @param #number LaserCode Laser code.
-- @param #number Duration Duration of lasing in seconds.
function SPOT:onafterLaseOnCoordinate(From, Event, To, Coordinate, LaserCode, Duration)
self:F( { "LaseOnCoordinate", Coordinate, LaserCode, Duration } )
self:T2( { "LaseOnCoordinate", Coordinate, LaserCode, Duration } )
local function StopLase( self )
self:LaseOff()
@@ -290,12 +294,14 @@ do
end
self:__Lasing(-1)
return self
end
--- @param #SPOT self
---
-- @param #SPOT self
-- @param Core.Event#EVENTDATA EventData
function SPOT:OnEventDead(EventData)
self:F( { Dead = EventData.IniDCSUnitName, Target = self.Target } )
self:T2( { Dead = EventData.IniDCSUnitName, Target = self.Target } )
if self.Target then
if EventData.IniDCSUnitName == self.TargetName then
self:F( {"Target dead ", self.TargetName } )
@@ -309,42 +315,51 @@ do
self:LaseOff()
end
end
return self
end
--- @param #SPOT self
---
-- @param #SPOT self
-- @param From
-- @param Event
-- @param To
function SPOT:onafterLasing( From, Event, To )
if self.Target and self.Target:IsAlive() then
self.SpotIR:setPoint( self.Target:GetPointVec3():AddY(1):AddY(math.random(-100,100)/100):AddX(math.random(-100,100)/100):GetVec3() )
self.SpotLaser:setPoint( self.Target:GetPointVec3():AddY(1):GetVec3() )
self:__Lasing( -0.2 )
elseif self.TargetCoord then
self:T({From, Event, To})
-- Wiggle the IR spot a bit.
local irvec3={x=self.TargetCoord.x+math.random(-100,100)/100, y=self.TargetCoord.y+math.random(-100,100)/100, z=self.TargetCoord.z} --#DCS.Vec3
local lsvec3={x=self.TargetCoord.x, y=self.TargetCoord.y, z=self.TargetCoord.z} --#DCS.Vec3
if self.Lasing then
if self.Target and self.Target:IsAlive() then
self.SpotIR:setPoint( self.Target:GetPointVec3():AddY(1):AddY(math.random(-100,100)/100):AddX(math.random(-100,100)/100):GetVec3() )
self.SpotLaser:setPoint( self.Target:GetPointVec3():AddY(1):GetVec3() )
self:__Lasing(0.2)
elseif self.TargetCoord then
self.SpotIR:setPoint(irvec3)
self.SpotLaser:setPoint(lsvec3)
self:__Lasing(-0.25)
else
self:F( { "Target is not alive", self.Target:IsAlive() } )
-- Wiggle the IR spot a bit.
local irvec3={x=self.TargetCoord.x+math.random(-100,100)/100, y=self.TargetCoord.y+math.random(-100,100)/100, z=self.TargetCoord.z} --#DCS.Vec3
local lsvec3={x=self.TargetCoord.x, y=self.TargetCoord.y, z=self.TargetCoord.z} --#DCS.Vec3
self.SpotIR:setPoint(irvec3)
self.SpotLaser:setPoint(lsvec3)
self:__Lasing(0.2)
else
self:F( { "Target is not alive", self.Target:IsAlive() } )
end
end
return self
end
--- @param #SPOT self
---
-- @param #SPOT self
-- @param From
-- @param Event
-- @param To
-- @return #SPOT
function SPOT:onafterLaseOff( From, Event, To )
self:F( {"Stopped lasing for ", self.Target and self.Target:GetName() or "coord", SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
self:T({From, Event, To})
self:T2( {"Stopped lasing for ", self.Target and self.Target:GetName() or "coord", SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
self.Lasing = false
@@ -383,4 +398,4 @@ do
return self
end
end
end

View File

@@ -107,7 +107,7 @@ _TIMERID=0
--- TIMER class version.
-- @field #string version
TIMER.version="0.1.2"
TIMER.version="0.2.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -222,7 +222,20 @@ function TIMER:Stop(Delay)
-- Remove timer function.
self:T(self.lid..string.format("Stopping timer by removing timer function after %d calls!", self.ncalls))
timer.removeFunction(self.tid)
-- We use a pcall here because if the DCS timer does not exist any more, it crashes the whole script!
local status=pcall(
function ()
timer.removeFunction(self.tid)
end
)
-- Debug messages.
if status then
self:T2(self.lid..string.format("Stopped timer!"))
else
self:E(self.lid..string.format("WARNING: Could not remove timer function! isrunning=%s", tostring(self.isrunning)))
end
-- Not running any more.
self.isrunning=false

View File

@@ -1001,6 +1001,24 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
end
--- Remove junk inside the zone using the `world.removeJunk` function.
-- @param #ZONE_RADIUS self
-- @return #number Number of deleted objects.
function ZONE_RADIUS:RemoveJunk()
local radius=self.Radius
local vec3=self:GetVec3()
local volS = {
id = world.VolumeType.SPHERE,
params = {point = vec3, radius = radius}
}
local n=world.removeJunk(volS)
return n
end
--- Count the number of different coalitions inside the zone.
-- @param #ZONE_RADIUS self
-- @return #table Table of DCS units and DCS statics inside the zone.
@@ -2141,6 +2159,35 @@ function ZONE_POLYGON_BASE:GetZoneQuad(ZoneName, DoNotRegisterZone)
return zone
end
--- Remove junk inside the zone. Due to DCS limitations, this works only for rectangular zones. So we get the smallest rectangular zone encompassing all points points of the polygon zone.
-- @param #ZONE_POLYGON_BASE self
-- @param #number Height Height of the box in meters. Default 1000.
-- @return #number Number of removed objects.
function ZONE_POLYGON_BASE:RemoveJunk(Height)
Height=Height or 1000
local vec2SW, vec2NE=self:GetBoundingVec2()
local vec3SW={x=vec2SW.x, y=-Height, z=vec2SW.y} --DCS#Vec3
local vec3NE={x=vec2NE.x, y= Height, z=vec2NE.y} --DCS#Vec3
--local coord1=COORDINATE:NewFromVec3(vec3SW):MarkToAll("SW")
--local coord1=COORDINATE:NewFromVec3(vec3NE):MarkToAll("NE")
local volume = {
id = world.VolumeType.BOX,
params = {
min=vec3SW,
max=vec3SW
}
}
local n=world.removeJunk(volume)
return n
end
--- Smokes the zone boundaries in a color.
-- @param #ZONE_POLYGON_BASE self
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color.

View File

@@ -2354,6 +2354,7 @@ do -- DETECTION_TYPES
if not DetectedItem then
DetectedItem = self:AddDetectedItem( "TYPE", DetectedTypeName )
DetectedItem.TypeName = DetectedTypeName
DetectedItem.Name = DetectedUnitName -- fix by @Nocke
end
DetectedItem.Set:AddUnit( DetectedUnit )

View File

@@ -22,7 +22,7 @@
-- @module Functional.Mantis
-- @image Functional.Mantis.jpg
--
-- Last Update: Oct 2022
-- Last Update: July 2023
-------------------------------------------------------------------------
--- **MANTIS** class, extends Core.Base#BASE
@@ -104,9 +104,13 @@
-- * Silkworm (though strictly speaking this is a surface to ship missile)
-- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2
--
-- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M
-- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA"
--
-- * From CH: 2S38, PantsirS1, PantsirS2, PGL-625, HQ-17A, M903PAC2, M903PAC3, TorM2, TorM2K, TorM2M, NASAMS3-AMRAAMER, NASAMS3-AIM9X2, C-RAM, PGZ-09, S350-9M100, S350-9M96D
-- **NOTE** If you are using the Military Assets by Currenthill (CH), please note that the **group name** for CH-SAM types also needs to contain the keyword "CHM"
--
-- Following the example started above, an SA-6 site group name should start with "Red SAM SA-6" then, or a blue Patriot installation with e.g. "Blue SAM Patriot".
-- **NOTE** If you are using the High-Digit-Sam Mod, please note that the **group name** for the following SAM types also needs to contain the keyword "HDS":
--
@@ -369,6 +373,7 @@ MANTIS.SamData = {
["SA-20A"] = { Range=150, Blindspot=5, Height=27, Type="Long" , Radar="S-300PMU1"},
["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"},
["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
["SHORAD"] = { Range=3, Blindspot=0, Height=3, Type="Short", Radar="Igla" }
}
--- SAM data HDS
@@ -415,6 +420,35 @@ MANTIS.SamDataSMA = {
["Lvkv9040M SMA"] = { Range=4, Blindspot=0, Height=2.5, Type="Short", Radar="LvKv9040" },
}
--- SAM data CH
-- @type MANTIS.SamDataCH
-- @field #number Range Max firing range in km
-- @field #number Blindspot no-firing range (green circle)
-- @field #number Height Max firing height in km
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
-- @field #string Radar Radar typename on unit level (used as key)
MANTIS.SamDataCH = {
-- units from CH (Military Assets by Currenthill)
-- https://www.currenthill.com/
-- group name MUST contain CHM to ID launcher type correctly!
["2S38 CH"] = { Range=8, Blindspot=0.5, Height=6, Type="Short", Radar="2S38" },
["PantsirS1 CH"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
["PantsirS2 CH"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
["PGL-625 CH"] = { Range=10, Blindspot=0.5, Height=5, Type="Short", Radar="PGL_625" },
["HQ-17A CH"] = { Range=20, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
["M903PAC2 CH"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
["M903PAC3 CH"] = { Range=120, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
["TorM2 CH"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
["TorM2K CH"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
["TorM2M CH"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
["NASAMS3-AMRAAMER CH"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
["NASAMS3-AIM9X2 CH"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
["C-RAM CH"] = { Range=2, Blindspot=0, Height=2, Type="Short", Radar="CH_Centurion_C_RAM" },
["PGZ-09 CH"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="CH_PGZ09" },
["S350-9M100 CH"] = { Range=15, Blindspot=1.5, Height=8, Type="Short", Radar="CH_S350_50P6_9M100" },
["S350-9M96D CH"] = { Range=150, Blindspot=2.5, Height=30, Type="Long", Radar="CH_S350_50P6_9M96D" },
}
-----------------------------------------------------------------------
-- MANTIS System
-----------------------------------------------------------------------
@@ -578,7 +612,7 @@ do
-- TODO Version
-- @field #string version
self.version="0.8.9"
self.version="0.8.11"
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
--- FSM Functions ---
@@ -1299,11 +1333,12 @@ do
-- @param #string grpname Name of the group
-- @param #boolean mod HDS mod flag
-- @param #boolean sma SMA mod flag
-- @param #boolean chm CH mod flag
-- @return #number range Max firing range
-- @return #number height Max firing height
-- @return #string type Long, medium or short range
-- @return #number blind "blind" spot
function MANTIS:_GetSAMDataFromUnits(grpname,mod,sma)
function MANTIS:_GetSAMDataFromUnits(grpname,mod,sma,chm)
self:T(self.lid.."_GetSAMRangeFromUnits")
local found = false
local range = self.checkradius
@@ -1318,8 +1353,10 @@ do
SAMData = self.SamDataHDS
elseif sma then
SAMData = self.SamDataSMA
elseif chm then
SAMData = self.SamDataCH
end
--self:I("Looking to auto-match for "..grpname)
--self:T("Looking to auto-match for "..grpname)
for _,_unit in pairs(units) do
local unit = _unit -- Wrapper.Unit#UNIT
local type = string.lower(unit:GetTypeName())
@@ -1364,10 +1401,13 @@ do
local found = false
local HDSmod = false
local SMAMod = false
local CHMod = false
if string.find(grpname,"HDS",1,true) then
HDSmod = true
elseif string.find(grpname,"SMA",1,true) then
SMAMod = true
elseif string.find(grpname,"CHM",1,true) then
CHMod = true
end
if self.automode then
for idx,entry in pairs(self.SamData) do
@@ -1386,8 +1426,8 @@ do
end
end
-- secondary filter if not found
if (not found and self.automode) or HDSmod or SMAMod then
range, height, type = self:_GetSAMDataFromUnits(grpname,HDSmod,SMAMod)
if (not found and self.automode) or HDSmod or SMAMod or CHMod then
range, height, type = self:_GetSAMDataFromUnits(grpname,HDSmod,SMAMod,CHMod)
elseif not found then
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
end

View File

@@ -26,9 +26,9 @@
--
-- ===
--
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
-- ### Author: **funkyfranky**
--
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
-- ### Contributions: FlightControl, Applevangelist
--
-- ====
-- @module Functional.PseudoATC
@@ -44,7 +44,7 @@
-- @field #number mrefresh Interval in seconds after which the F10 menu is refreshed. E.g. by the closest airports. Default is 120 sec.
-- @field #number talt Interval in seconds between reporting altitude until touchdown. Default 3 sec.
-- @field #boolean chatty Display some messages on events like take-off and touchdown.
-- @field #boolean eventsmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler.
-- @field #boolean eventsmoose [Deprecated] If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler.
-- @field #boolean reportplayername If true, use playername not callsign on callouts
-- @extends Core.Base#BASE
@@ -100,13 +100,14 @@ PSEUDOATC.id="PseudoATC | "
--- PSEUDOATC version.
-- @field #number version
PSEUDOATC.version="0.9.5"
PSEUDOATC.version="0.10.5"
-----------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-- DONE: Add takeoff event.
-- DONE: Add user functions.
-- DONE: Refactor to use Moose event handling only
-----------------------------------------------------------------------------------------------------------------------------------------
@@ -131,23 +132,14 @@ function PSEUDOATC:Start()
self:F()
-- Debug info
self:E(PSEUDOATC.id.."Starting PseudoATC")
self:I(PSEUDOATC.id.."Starting PseudoATC")
-- Handle events.
if self.eventsmoose then
self:T(PSEUDOATC.id.."Events are handled by MOOSE.")
self:HandleEvent(EVENTS.Birth, self._OnBirth)
self:HandleEvent(EVENTS.Land, self._PlayerLanded)
self:HandleEvent(EVENTS.Takeoff, self._PlayerTakeOff)
self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft)
self:HandleEvent(EVENTS.Crash, self._PlayerLeft)
--self:HandleEvent(EVENTS.Ejection, self._PlayerLeft)
--self:HandleEvent(EVENTS.PilotDead, self._PlayerLeft)
else
self:T(PSEUDOATC.id.."Events are handled by DCS.")
-- Events are handled directly by DCS.
world.addEventHandler(self)
end
self:HandleEvent(EVENTS.Birth, self._OnBirth)
self:HandleEvent(EVENTS.Land, self._PlayerLanded)
self:HandleEvent(EVENTS.Takeoff, self._PlayerTakeOff)
self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft)
self:HandleEvent(EVENTS.Crash, self._PlayerLeft)
end
@@ -199,7 +191,7 @@ function PSEUDOATC:SetMenuRefresh(interval)
self.mrefresh=interval or 120
end
--- Enable/disable event handling by MOOSE or DCS.
--- [Deprecated] Enable/disable event handling by MOOSE or DCS.
-- @param #PSEUDOATC self
-- @param #boolean switch If true, events are handled by MOOSE (default). If false, events are handled directly by DCS.
function PSEUDOATC:SetEventsMoose(switch)
@@ -216,84 +208,6 @@ end
-----------------------------------------------------------------------------------------------------------------------------------------
-- Event Handling
--- Event handler for suppressed groups.
--@param #PSEUDOATC self
--@param #table Event Event data table. Holds event.id, event.initiator and event.target etc.
function PSEUDOATC:onEvent(Event)
if Event == nil or Event.initiator == nil or Unit.getByName(Event.initiator:getName()) == nil then
return true
end
local DCSiniunit = Event.initiator
local DCSplace = Event.place
local DCSsubplace = Event.subplace
local EventData={}
local _playerunit=nil
local _playername=nil
if Event.initiator then
EventData.IniUnitName = Event.initiator:getName()
EventData.IniDCSGroup = Event.initiator:getGroup()
EventData.IniGroupName = Event.initiator:getGroup():getName()
-- Get player unit and name. This returns nil,nil if the event was not fired by a player unit. And these are the only events we are interested in.
_playerunit, _playername = self:_GetPlayerUnitAndName(EventData.IniUnitName)
end
if Event.place then
EventData.Place=Event.place
EventData.PlaceName=Event.place:getName()
end
if Event.subplace then
EventData.SubPlace=Event.subplace
EventData.SubPlaceName=Event.subplace:getName()
end
-- Event info.
self:T3(PSEUDOATC.id..string.format("EVENT: Event in onEvent with ID = %s", tostring(Event.id)))
self:T3(PSEUDOATC.id..string.format("EVENT: Ini unit = %s" , tostring(EventData.IniUnitName)))
self:T3(PSEUDOATC.id..string.format("EVENT: Ini group = %s" , tostring(EventData.IniGroupName)))
self:T3(PSEUDOATC.id..string.format("EVENT: Ini player = %s" , tostring(_playername)))
self:T3(PSEUDOATC.id..string.format("EVENT: Place = %s" , tostring(EventData.PlaceName)))
self:T3(PSEUDOATC.id..string.format("EVENT: SubPlace = %s" , tostring(EventData.SubPlaceName)))
-- Event birth.
if Event.id == world.event.S_EVENT_BIRTH and _playername then
self:_OnBirth(EventData)
end
-- Event takeoff.
if Event.id == world.event.S_EVENT_TAKEOFF and _playername and EventData.Place then
self:_PlayerTakeOff(EventData)
end
-- Event land.
if Event.id == world.event.S_EVENT_LAND and _playername and EventData.Place then
self:_PlayerLanded(EventData)
end
-- Event player left unit
if Event.id == world.event.S_EVENT_PLAYER_LEAVE_UNIT and _playername then
self:_PlayerLeft(EventData)
end
-- Event crash ==> player left unit
if Event.id == world.event.S_EVENT_CRASH and _playername then
self:_PlayerLeft(EventData)
end
--[[
-- Event eject ==> player left unit
if Event.id == world.event.S_EVENT_EJECTION and _playername then
self:_PlayerLeft(EventData)
end
-- Event pilot dead ==> player left unit
if Event.id == world.event.S_EVENT_PILOT_DEAD and _playername then
self:_PlayerLeft(EventData)
end
]]
end
--- Function called my MOOSE event handler when a player enters a unit.
-- @param #PSEUDOATC self
@@ -303,7 +217,9 @@ function PSEUDOATC:_OnBirth(EventData)
-- Get unit and player.
local _unitName=EventData.IniUnitName
local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
--local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
local _unit = EventData.IniUnit
local _playername = EventData.IniPlayerName
-- Check if a player entered.
if _unit and _playername then
@@ -320,7 +236,10 @@ function PSEUDOATC:_PlayerLeft(EventData)
-- Get unit and player.
local _unitName=EventData.IniUnitName
local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
--local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
local _unit = EventData.IniUnit
local _playername = EventData.IniPlayerName
-- Check if a player left.
if _unit and _playername then
@@ -335,18 +254,16 @@ function PSEUDOATC:_PlayerLanded(EventData)
self:F({EventData=EventData})
-- Get unit, player and place.
local _unitName=EventData.IniUnitName
local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
local _unitName=EventData.IniUnitName
local _unit = EventData.IniUnit
local _playername = EventData.IniPlayerName
--local _unit, _playername=self:_GetPlayerUnitAndName(_unitName)
local _base=nil
local _baseName=nil
if EventData.place then
_base=EventData.place
_baseName=EventData.place:getName()
end
-- if EventData.subplace then
-- local _subPlace=EventData.subplace
-- local _subPlaceName=EventData.subplace:getName()
-- end
-- Call landed function.
if _unit and _playername and _base then
@@ -361,8 +278,10 @@ function PSEUDOATC:_PlayerTakeOff(EventData)
self:F({EventData=EventData})
-- Get unit, player and place.
local _unitName=EventData.IniUnitName
local _unit,_playername=self:_GetPlayerUnitAndName(_unitName)
local _unitName=EventData.IniUnitName
local _unit = EventData.IniUnit
local _playername = EventData.IniPlayerName
--local _unit,_playername=self:_GetPlayerUnitAndName(_unitName)
local _base=nil
local _baseName=nil
if EventData.place then
@@ -450,9 +369,6 @@ function PSEUDOATC:PlayerLanded(unit, place)
local group=unit:GetGroup()
local GID=group:GetID()
local UID=unit:GetDCSObject():getID()
--local PlayerName=self.group[GID].player[UID].playername
--local UnitName=self.group[GID].player[UID].unitname
--local GroupName=self.group[GID].player[UID].groupname
local PlayerName = unit:GetPlayerName() or "Ghost"
local UnitName = unit:GetName() or "Ghostplane"
local GroupName = group:GetName() or "Ghostgroup"
@@ -483,12 +399,6 @@ function PSEUDOATC:PlayerTakeOff(unit, place)
-- Gather some information.
local group=unit:GetGroup()
--local GID=group:GetID()
--local UID=unit:GetDCSObject():getID()
--local PlayerName=self.group[GID].player[UID].playername
--local CallSign=self.group[GID].player[UID].callsign
--local UnitName=self.group[GID].player[UID].unitname
--local GroupName=self.group[GID].player[UID].groupname
local PlayerName = unit:GetPlayerName() or "Ghost"
local UnitName = unit:GetName() or "Ghostplane"
local GroupName = group:GetName() or "Ghostgroup"
@@ -926,7 +836,7 @@ function PSEUDOATC:AltitudeTimeStart(GID, UID)
self:T(PSEUDOATC.id..string.format("Starting altitude report timer for player ID %d.", UID))
-- Start timer. Altitude is reported every ~3 seconds.
self.group[GID].player[UID].altimer, self.group[GID].player[UID].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, GID, UID, 0.1, true}, 1, 3)
self.group[GID].player[UID].altimer, self.group[GID].player[UID].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, GID, UID, 1, true}, 1, 3)
end
--- Stop/destroy DCS scheduler function for reporting altitude.

View File

@@ -5490,7 +5490,7 @@ function RAT:_ATCInit(airports_map)
if not RAT.ATC.init then
local text
text="Starting RAT ATC.\nSimultanious = "..RAT.ATC.Nclearance.."\n".."Delay = "..RAT.ATC.delay
BASE:T(RAT.id..text)
BASE:T(RAT.id..text)
RAT.ATC.init=true
for _,ap in pairs(airports_map) do
local name=ap:GetName()
@@ -5671,9 +5671,9 @@ function RAT:_ATCClearForLanding(airport, flight)
-- Debug message.
local text1=string.format("ATC %s: Flight %s cleared for landing (flag=%d).", airport, flight, flagvalue)
if string.find(flight,"#") then
flight = string.match(flight,"^(.+)#")
end
if string.find(flight,"#") then
flight = string.match(flight,"^(.+)#")
end
local text2=string.format("ATC %s: Flight %s you are cleared for landing.", airport, flight)
BASE:T( RAT.id..text1)
MESSAGE:New(text2, 10):ToAllIf(RAT.ATC.messages)
@@ -5716,9 +5716,9 @@ function RAT:_ATCFlightLanded(name)
local text1=string.format("ATC %s: Flight %s landed. Tholding = %i:%02d, Tfinal = %i:%02d.", dest, name, Thold/60, Thold%60, Tfinal/60, Tfinal%60)
local text2=string.format("ATC %s: Number of flights still on final %d.", dest, RAT.ATC.airport[dest].Nonfinal)
local text3=string.format("ATC %s: Traffic report: Number of planes landed in total %d. Flights/hour = %3.2f.", dest, RAT.ATC.airport[dest].traffic, TrafficPerHour)
if string.find(name,"#") then
name = string.match(name,"^(.+)#")
end
if string.find(name,"#") then
name = string.match(name,"^(.+)#")
end
local text4=string.format("ATC %s: Flight %s landed. Welcome to %s.", dest, name, dest)
BASE:T(RAT.id..text1)
BASE:T(RAT.id..text2)
@@ -5832,6 +5832,7 @@ RATMANAGER={
rat={},
name={},
alive={},
planned={},
min={},
nrat=0,
ntot=nil,
@@ -5880,6 +5881,7 @@ function RATMANAGER:Add(ratobject,min)
self.rat[self.nrat]=ratobject
self.alive[self.nrat]=0
self.planned[self.nrat]=0
self.name[self.nrat]=ratobject.alias
self.min[self.nrat]=min or 1
@@ -6020,11 +6022,25 @@ function RATMANAGER:_Manage()
for i=1,self.nrat do
for j=1,N[i] do
time=time+self.dTspawn
SCHEDULER:New(nil, RAT._SpawnWithRoute, {self.rat[i]}, time)
self.planned[i]=self.planned[i]+1
SCHEDULER:New(nil, RATMANAGER._Spawn, {self, i}, time)
end
end
end
--- Instantly starts the RAT manager and spawns the initial random number RAT groups for each RAT object.
-- @param #RATMANAGER self
-- @param #RATMANAGER RATMANAGER self object.
-- @param #number i Index.
function RATMANAGER:_Spawn(i)
local rat=self.rat[i] --#RAT
rat:_SpawnWithRoute()
self.planned[i]=self.planned[i]-1
end
--- Counts the number of alive RAT objects.
-- @param #RATMANAGER self
function RATMANAGER:_Count()
@@ -6053,7 +6069,7 @@ function RATMANAGER:_Count()
ntotal=ntotal+n
-- Debug output.
local text=string.format("Number of alive groups of %s = %d", self.name[i], n)
local text=string.format("Number of alive groups of %s = %d, planned=%d", self.name[i], n, self.planned[i])
self:T(RATMANAGER.id..text)
end
@@ -6083,9 +6099,10 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
local M={}
local P={}
for i=1,nrat do
local a=alive[i]+self.planned[i]
N[#N+1]=0
M[#M+1]=math.max(alive[i], min[i])
P[#P+1]=math.max(min[i]-alive[i],0)
M[#M+1]=math.max(a, min[i])
P[#P+1]=math.max(min[i]-a,0)
end
-- Min/max group arrays.
@@ -6102,7 +6119,7 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
-- Number of new groups to be added.
local nnew=ntot
for i=1,nrat do
nnew=nnew-alive[i]
nnew=nnew-alive[i]-self.planned[i]
end
for i=1,nrat-1 do
@@ -6134,7 +6151,7 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
end
-- Debug info
self:T3(string.format("RATMANAGER: i=%d, alive=%d, min=%d, mini=%d, maxi=%d, add=%d, sumN=%d, sumP=%d", j, alive[j], min[j], mini[j], maxi[j], N[j],sN, sP))
self:T3(string.format("RATMANAGER: i=%d, alive=%d, planned=%d, min=%d, mini=%d, maxi=%d, add=%d, sumN=%d, sumP=%d", j, alive[j], self.planned[i], min[j], mini[j], maxi[j], N[j],sN, sP))
end
@@ -6149,7 +6166,7 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
-- Debug info
local text=RATMANAGER.id.."\n"
for i=1,nrat do
text=text..string.format("%s: i=%d, alive=%d, min=%d, mini=%d, maxi=%d, add=%d\n", self.name[i], i, alive[i], min[i], mini[i], maxi[i], N[i])
text=text..string.format("%s: i=%d, alive=%d, planned=%d, min=%d, mini=%d, maxi=%d, add=%d\n", self.name[i], i, alive[i], self.planned[i], min[i], mini[i], maxi[i], N[i])
end
text=text..string.format("Total # of groups to add = %d", sum(N, done))
self:T(text)

View File

@@ -715,11 +715,11 @@ function SCORING:AddGoalScorePlayer( PlayerName, GoalTag, Text, Score )
PlayerData.Goals[GoalTag] = PlayerData.Goals[GoalTag] or { Score = 0 }
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
PlayerData.Score = PlayerData.Score + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
MESSAGE.Type.Information )
:ToAll()
if Text then
MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
MESSAGE.Type.Information )
:ToAll()
end
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, nil )
end
end
@@ -738,7 +738,7 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score )
local PlayerName = PlayerUnit:GetPlayerName()
self:F( { PlayerUnit.UnitName, PlayerName, GoalTag, Text, Score } )
self:T2( { PlayerUnit.UnitName, PlayerName, GoalTag, Text, Score } )
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
if PlayerName then
@@ -747,11 +747,12 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score )
PlayerData.Goals[GoalTag] = PlayerData.Goals[GoalTag] or { Score = 0 }
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
PlayerData.Score = PlayerData.Score + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
if Text then
MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
MESSAGE.Type.Information )
:ToAll()
end
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() )
end
end
@@ -784,11 +785,12 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
PlayerData.Score = self.Players[PlayerName].Score + Score
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score,
MESSAGE.Type.Information )
:ToAll()
if Text then
MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score,
MESSAGE.Type.Information )
:ToAll()
end
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
end
end
@@ -820,9 +822,11 @@ function SCORING:_AddMissionGoalScore( Mission, PlayerName, Text, Score )
PlayerData.Score = self.Players[PlayerName].Score + Score
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
MESSAGE:NewType( string.format( "%s%s: %s! Player %s receives %d score!", self.DisplayMessagePrefix, Mission:GetText(), Text, PlayerName, Score ), MESSAGE.Type.Information ):ToAll()
if Text then
MESSAGE:NewType( string.format( "%s%s: %s! Player %s receives %d score!", self.DisplayMessagePrefix, Mission:GetText(), Text, PlayerName, Score ), MESSAGE.Type.Information ):ToAll()
end
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score )
end
end
@@ -847,11 +851,12 @@ function SCORING:_AddMissionScore( Mission, Text, Score )
PlayerData.Score = PlayerData.Score + Score
PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in " .. Mission:GetText() .. ". " .. Score .. " mission score!",
if Text then
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in " .. Mission:GetText() .. ". " .. Score .. " mission score!",
MESSAGE.Type.Information )
:ToAll()
end
self:ScoreCSV( PlayerName, "", "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score )
end
end
@@ -1762,9 +1767,9 @@ function SCORING:SecondsToClock( sSeconds )
-- return nil;
return "00:00:00";
else
nHours = string.format( "%02.f", math.floor( nSeconds / 3600 ) );
nMins = string.format( "%02.f", math.floor( nSeconds / 60 - (nHours * 60) ) );
nSecs = string.format( "%02.f", math.floor( nSeconds - nHours * 3600 - nMins * 60 ) );
local nHours = string.format( "%02.f", math.floor( nSeconds / 3600 ) );
local nMins = string.format( "%02.f", math.floor( nSeconds / 60 - (nHours * 60) ) );
local nSecs = string.format( "%02.f", math.floor( nSeconds - nHours * 3600 - nMins * 60 ) );
return nHours .. ":" .. nMins .. ":" .. nSecs
end
end

View File

@@ -1798,7 +1798,7 @@ _WAREHOUSEDB = {
--- Warehouse class version.
-- @field #string version
WAREHOUSE.version="1.0.2"
WAREHOUSE.version="1.0.2a"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Warehouse todo list.
@@ -4561,7 +4561,8 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request)
self:_ErrorMessage("ERROR: Cargo transport by train not supported yet!")
return
elseif Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.NAVALCARRIER then
elseif Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.NAVALCARRIER
or Request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or Request.transporttype==WAREHOUSE.TransportType.WARSHIP then
-- Spawn Ship in port zone
spawngroup=self:_SpawnAssetGroundNaval(_alias, _assetitem, Request, self.portzone)
@@ -5829,62 +5830,65 @@ function WAREHOUSE:_SpawnAssetRequest(Request)
-- Get stock item.
local asset=cargoassets[i] --#WAREHOUSE.Assetitem
if not asset.spawned then
-- Set asset status to not spawned until we capture its birth event.
asset.spawned=false
asset.iscargo=true
-- Set request ID.
asset.rid=Request.uid
-- Spawn group name.
local _alias=asset.spawngroupname
--Request add asset by id.
Request.assets[asset.uid]=asset
-- Spawn an asset group.
local _group=nil --Wrapper.Group#GROUP
if asset.category==Group.Category.GROUND then
-- Spawn ground troops.
_group=self:_SpawnAssetGroundNaval(_alias, asset, Request, self.spawnzone, Request.lateActivation)
elseif asset.category==Group.Category.AIRPLANE or asset.category==Group.Category.HELICOPTER then
-- Spawn air units.
if Parking[asset.uid] then
_group=self:_SpawnAssetAircraft(_alias, asset, Request, Parking[asset.uid], UnControlled, Request.lateActivation)
else
_group=self:_SpawnAssetAircraft(_alias, asset, Request, nil, UnControlled, Request.lateActivation)
end
elseif asset.category==Group.Category.TRAIN then
-- Spawn train.
if self.rail then
--TODO: Rail should only get one asset because they would spawn on top!
-- Spawn naval assets.
-- Set asset status to not spawned until we capture its birth event.
asset.iscargo=true
-- Set request ID.
asset.rid=Request.uid
-- Spawn group name.
local _alias=asset.spawngroupname
--Request add asset by id.
Request.assets[asset.uid]=asset
-- Spawn an asset group.
local _group=nil --Wrapper.Group#GROUP
if asset.category==Group.Category.GROUND then
-- Spawn ground troops.
_group=self:_SpawnAssetGroundNaval(_alias, asset, Request, self.spawnzone, Request.lateActivation)
elseif asset.category==Group.Category.AIRPLANE or asset.category==Group.Category.HELICOPTER then
-- Spawn air units.
if Parking[asset.uid] then
_group=self:_SpawnAssetAircraft(_alias, asset, Request, Parking[asset.uid], UnControlled, Request.lateActivation)
else
_group=self:_SpawnAssetAircraft(_alias, asset, Request, nil, UnControlled, Request.lateActivation)
end
elseif asset.category==Group.Category.TRAIN then
-- Spawn train.
if self.rail then
--TODO: Rail should only get one asset because they would spawn on top!
-- Spawn naval assets.
_group=self:_SpawnAssetGroundNaval(_alias, asset, Request, self.spawnzone, Request.lateActivation)
end
--self:E(self.lid.."ERROR: Spawning of TRAIN assets not possible yet!")
elseif asset.category==Group.Category.SHIP then
-- Spawn naval assets.
_group=self:_SpawnAssetGroundNaval(_alias, asset, Request, self.portzone, Request.lateActivation)
else
self:E(self.lid.."ERROR: Unknown asset category!")
end
--self:E(self.lid.."ERROR: Spawning of TRAIN assets not possible yet!")
elseif asset.category==Group.Category.SHIP then
-- Spawn naval assets.
_group=self:_SpawnAssetGroundNaval(_alias, asset, Request, self.portzone, Request.lateActivation)
else
self:E(self.lid.."ERROR: Unknown asset category!")
-- Trigger event.
if _group then
self:__AssetSpawned(0.01, _group, asset, Request)
end
end
-- Trigger event.
if _group then
self:__AssetSpawned(0.01, _group, asset, Request)
end
end
end

View File

@@ -1,3 +1,4 @@
---@diagnostic disable: cast-local-type
--- **Ops** - Automatic Terminal Information Service (ATIS).
--
-- ===
@@ -418,6 +419,8 @@ ATIS.RunwayM2T = {
TheChannel = -10,
Syria = 5,
MarianaIslands = 2,
Falklands = 12,
Sinai = 5,
}
--- Whether ICAO phraseology is used for ATIS broadcasts.
@@ -429,6 +432,8 @@ ATIS.RunwayM2T = {
-- @field #boolean TheChannel true.
-- @field #boolean Syria true.
-- @field #boolean MarianaIslands true.
-- @field #boolean Falklands true.
-- @field #boolean Sinai true.
ATIS.ICAOPhraseology = {
Caucasus = true,
Nevada = false,
@@ -436,7 +441,9 @@ ATIS.ICAOPhraseology = {
PersianGulf = true,
TheChannel = true,
Syria = true,
MarianaIslands = true
MarianaIslands = true,
Falklands = true,
Sinai = true,
}
--- Nav point data.
@@ -608,15 +615,16 @@ _ATIS = {}
--- ATIS class version.
-- @field #string version
ATIS.version = "0.9.14"
ATIS.version = "0.9.15"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Add new Normandy airfields.
-- TODO: Zulu time --> Zulu in output.
-- TODO: Correct fog for elevation.
-- DONE: Zulu time --> Zulu in output.
-- DONE: Fix for AB not having a runway - Helopost like Naqoura
-- DONE: Add new Normandy airfields.
-- DONE: Use new AIRBASE system to set start/landing runway
-- DONE: SetILS doesn't work
-- DONE: Visibility reported twice over SRS
@@ -1270,7 +1278,8 @@ end
-- @param #string Event Event.
-- @param #string To To state.
function ATIS:onafterStart( From, Event, To )
self:I("Airbase category is "..self.airbase:GetAirbaseCategory())
-- Check that this is an airdrome.
if self.airbase:GetAirbaseCategory() == Airbase.Category.SHIP then
self:E( self.lid .. string.format( "ERROR: Cannot start ATIS for airbase %s! Only AIRDROMES are supported but NOT SHIPS.", self.airbasename ) )
@@ -1821,7 +1830,10 @@ function ATIS:onafterBroadcast( From, Event, To )
-- Airbase name
subtitle = string.format( "%s", self.airbasename )
if (not self.ATISforFARPs) and self.airbasename:find( "AFB" ) == nil and self.airbasename:find( "Airport" ) == nil and self.airbasename:find( "Airstrip" ) == nil and self.airbasename:find( "airfield" ) == nil and self.airbasename:find( "AB" ) == nil then
if (not self.ATISforFARPs) and self.airbasename:find( "AFB" ) == nil and self.airbasename:find( "Airport" ) == nil
and self.airbasename:find( "Airstrip" ) == nil and self.airbasename:find( "airfield" ) == nil and self.airbasename:find( "AB" ) == nil
and self.airbasename:find( "Field" ) == nil
then
subtitle = subtitle .. " Airport"
end
if not self.useSRS then
@@ -2139,16 +2151,20 @@ function ATIS:onafterBroadcast( From, Event, To )
end
end
alltext = alltext .. ";\n" .. subtitle
local _RUNACT
if not self.ATISforFARPs then
-- Active runway.
local subtitle=string.format("Active runway %s", runwayLanding)
if rwyLandingLeft==true then
subtitle=subtitle.." Left"
elseif rwyLandingLeft==false then
subtitle=subtitle.." Right"
if runwayLanding then
local subtitle=string.format("Active runway %s", runwayLanding)
if rwyLandingLeft==true then
subtitle=subtitle.." Left"
elseif rwyLandingLeft==false then
subtitle=subtitle.." Right"
end
end
local _RUNACT = subtitle
_RUNACT = subtitle
if not self.useSRS then
self:Transmission(ATIS.Sound.ActiveRunway, 1.0, subtitle)
self.radioqueue:Number2Transmission(runwayLanding)
@@ -2509,8 +2525,11 @@ function ATIS:GetActiveRunway(Takeoff)
else
runway=self.airbase:GetActiveRunwayLanding()
end
return runway.name, runway.isLeft
if runway then -- some ABs have NO runways, e.g. Syria Naqoura
return runway.name, runway.isLeft
else
return nil, nil
end
end
--- Get runway from user supplied magnetic heading.

View File

@@ -5822,27 +5822,64 @@ function AIRBOSS:_ScanCarrierZone()
-- Get aircraft type name.
local actype = group:GetTypeName()
-- Create a new flight group
if knownflight then
-- Debug output.
self:T2(self.lid..string.format("Known flight group %s of type %s in CCA.", groupname, actype))
-- Check if flight is AI and if we want to handle it at all.
if knownflight.ai and knownflight.flag == -100 and self.handleai and false then --Disabled AI handling because of incorrect OPSGROUP reference!
if knownflight.ai and self.handleai then
local putintomarshal = false
-- Defines if AI group should be handled by the airboss.
local iscarriersquad=true
-- Get flight group.
local flight = _DATABASE:GetOpsGroup( groupname )
if flight and flight:IsInbound() and flight.destbase:GetName() == self.carrier:GetName() then
if flight.ishelo then
-- Check if AI group is part of the group set if a set was defined.
if self.squadsetAI then
local group=self.squadsetAI:FindGroup(groupname)
if group then
iscarriersquad=true
else
putintomarshal = true
iscarriersquad=false
end
flight.airboss = self
end
-- Send AI flight to marshal stack.
if putintomarshal then
-- Check if group was explicitly excluded.
if self.excludesetAI then
local group=self.excludesetAI:FindGroup(groupname)
if group then
iscarriersquad=false
end
end
-- Get distance to carrier.
local dist=knownflight.group:GetCoordinate():Get2DDistance(self:GetCoordinate())
-- Close in distance. Is >0 if AC comes closer wrt to first detected distance d0.
local closein=knownflight.dist0-dist
-- Debug info.
self:T3(self.lid..string.format("Known AI flight group %s closed in by %.1f NM", knownflight.groupname, UTILS.MetersToNM(closein)))
-- Is this group the tanker?
local istanker=self.tanker and self.tanker.tanker:GetName()==groupname
-- Is this group the AWACS?
local isawacs=self.awacs and self.awacs.tanker:GetName()==groupname
-- Send tanker to marshal stack?
local tanker2marshal = istanker and self.tanker:IsReturning() and self.tanker.airbase:GetName()==self.airbase:GetName() and knownflight.flag==-100 and self.tanker.recovery==true
-- Send AWACS to marhsal stack?
local awacs2marshal = isawacs and self.awacs:IsReturning() and self.awacs.airbase:GetName()==self.airbase:GetName() and knownflight.flag==-100 and self.awacs.recovery==true
-- Put flight into Marshal.
local putintomarshal=closein>UTILS.NMToMeters(5) and knownflight.flag==-100 and iscarriersquad and istanker==false and isawacs==false
-- Send AI flight to marshal stack if group closes in more than 5 and has initial flag value.
if putintomarshal or tanker2marshal or awacs2marshal then
-- Get the next free stack for current recovery case.
local stack = self:_GetFreeStack( knownflight.ai )
@@ -8102,7 +8139,7 @@ end
-- @param Core.Event#EVENTDATA EventData
function AIRBOSS:OnEventBirth( EventData )
self:F3( { eventbirth = EventData } )
-- Nil checks.
if EventData == nil then
self:E( self.lid .. "ERROR: EventData=nil in event BIRTH!" )
@@ -8114,7 +8151,9 @@ function AIRBOSS:OnEventBirth( EventData )
self:E( EventData )
return
end
if EventData.IniObjectCategory ~= Object.Category.UNIT then return end
local _unitName = EventData.IniUnitName
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
@@ -9792,23 +9831,23 @@ function AIRBOSS:_Groove( playerData )
end
end
-- Long V/STOL groove time Wave Off over 75 seconds to IC - TOPGUN level Only. --pene testing (WIP)--- Need to think more about this.
-- Long V/STOL groove time Wave Off over 75 seconds to IC - TOPGUN level Only. --pene testing (WIP)--- Need to think more about this.
--if rho>=RAR and rho<=RIC and not playerData.waveoff and playerData.difficulty==AIRBOSS.Difficulty.HARD and playerData.actype== AIRBOSS.AircraftCarrier.AV8B then
-- Get groove time
--local vSlow=groovedata.time
-- If too slow wave off.
--if vSlow >75 then
-- LSO Wave off!
--self:RadioTransmission(self.LSORadio, self.LSOCall.WAVEOFF, nil, nil, nil, true)
--playerData.Tlso=timer.getTime()
-- Player was waved Off
--playerData.waveoff=true
--return
--end
--end
--end
-- Groovedata step.
@@ -10162,7 +10201,7 @@ function AIRBOSS:_GetSternCoord()
elseif case==2 or case==1 then
-- V/Stol: Translate 8 meters port.
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8, FB-90, true, true)
end
end
elseif self.carriertype==AIRBOSS.CarrierType.STENNIS then
-- Stennis: translate 7 meters starboard wrt Final bearing.
self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 7, FB + 90, true, true )
@@ -11302,7 +11341,7 @@ function AIRBOSS:_GetOptLandingCoordinate()
self.landingcoord:SetAltitude(UTILS.FeetToMeters(120))
end
else
-- Ideally we want to land between 2nd and 3rd wire.

View File

@@ -30,7 +30,7 @@
-- @module Ops.CSAR
-- @image OPS_CSAR.jpg
-- Date: January 2023
-- Date: May 2023
-------------------------------------------------------------------------
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
@@ -292,7 +292,7 @@ CSAR.AircraftType["Bronco-OV-10A"] = 2
--- CSAR class version.
-- @field #string version
CSAR.version="1.0.17"
CSAR.version="1.0.18"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
@@ -316,7 +316,7 @@ function CSAR:New(Coalition, Template, Alias)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #CSAR
BASE:T({Coalition, Prefixes, Alias})
BASE:T({Coalition, Template, Alias})
--set Coalition
if Coalition and type(Coalition)=="string" then
@@ -1880,7 +1880,7 @@ function CSAR:_SignalFlare(_unitName)
if _SETTINGS:IsImperial() then
_distance = string.format("%.1fnm",UTILS.MetersToNM(_closest.distance))
else
_distance = string.format("%.1fkm",_closest.distance)
_distance = string.format("%.1fkm",_closest.distance/1000)
end
local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
@@ -2175,6 +2175,7 @@ function CSAR:_AddBeaconToGroup(_group, _freq)
if _group:IsAlive() then
local _radioUnit = _group:GetUnit(1)
if _radioUnit then
local name = _radioUnit:GetName()
local Frequency = _freq -- Freq in Hertz
local name = _radioUnit:GetName()
local Sound = "l10n/DEFAULT/"..self.radioSound

File diff suppressed because it is too large Load Diff

View File

@@ -805,7 +805,9 @@ function RESCUEHELO:_OnEventCrashOrEject(EventData)
self:T(self.lid..text)
-- Get coordinate of unit.
local coord=unit:GetCoordinate()
--local coord=unit:GetCoordinate()
local Vec3 = EventData.IniDCSUnit:getPoint() -- Vec3
local coord = COORDINATE:NewFromVec3(Vec3)
if coord and self.rescuezone:IsCoordinateInZone(coord) then

View File

@@ -49,17 +49,19 @@ SOCKET = {
-- @field #string BOMBRESULT Range bombing.
-- @field #string STRAFERESULT Range strafeing result.
-- @field #string LSOGRADE Airboss LSO grade.
-- @field #string TTS Text-To-Speech.
SOCKET.DataType={
TEXT="moose_text",
BOMBRESULT="moose_bomb_result",
STRAFERESULT="moose_strafe_result",
LSOGRADE="moose_lso_grade",
TTS="moose_text2speech"
}
--- SOCKET class version.
-- @field #string version
SOCKET.version="0.2.0"
SOCKET.version="0.3.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -140,7 +142,7 @@ end
--- Send a text message.
-- @param #SOCKET self
-- @param #string Text Test message.
-- @param #string Text Text message.
-- @return #SOCKET self
function SOCKET:SendText(Text)
@@ -154,4 +156,32 @@ function SOCKET:SendText(Text)
return self
end
--- Send a text-to-speech message.
-- @param #SOCKET self
-- @param #string Text The text message to speek.
-- @param #number Provider The TTS provider: 0=Microsoft (default), 1=Google.
-- @param #string Voice The specific voice to use, e.g. `"Microsoft David Desktop"` or "`en-US-Standard-A`". If not set, the service will choose a voice based on the other parameters such as culture and gender.
-- @param #string Culture The Culture or language code, *e.g.* `"en-US"`.
-- @param #string Gender The Gender, *i.e.* "male", "female". Default "female".
-- @param #number Volume The volume. Microsoft: [0,100] default 50, Google: [-96, 10] default 0.
-- @return #SOCKET self
function SOCKET:SendTextToSpeech(Text, Provider, Voice, Culture, Gender, Volume)
Text=Text or "Hello World!"
local message={}
message.command = SOCKET.DataType.TTS
message.text = Text
message.provider=Provider
message.voice = Voice
message.culture = Culture
message.gender = Gender
message.volume = Volume
self:SendTable(message)
return self
end

View File

@@ -43,7 +43,7 @@ BIGSMOKEPRESET = {
HugeSmoke=8,
}
--- DCS map as returned by env.mission.theatre.
--- DCS map as returned by `env.mission.theatre`.
-- @type DCSMAP
-- @field #string Caucasus Caucasus map.
-- @field #string Normandy Normandy map.
@@ -53,6 +53,7 @@ BIGSMOKEPRESET = {
-- @field #string Syria Syria map.
-- @field #string MarianaIslands Mariana Islands map.
-- @field #string Falklands South Atlantic map.
-- @field #string Sinai Sinai map.
DCSMAP = {
Caucasus="Caucasus",
NTTR="Nevada",
@@ -62,6 +63,7 @@ DCSMAP = {
Syria="Syria",
MarianaIslands="MarianaIslands",
Falklands="Falklands",
Sinai="SinaiMap"
}
@@ -297,14 +299,14 @@ end
-- @param #table tbl Input table.
UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
lookup_table = {}
local lookup_table = {}
local function _Serialize( tbl )
if type(tbl) == 'table' then --function only works for tables!
if lookup_table[tbl] then
return lookup_table[object]
return lookup_table[tbl]
end
local tbl_str = {}
@@ -385,6 +387,23 @@ UTILS.BasicSerialize = function(s)
end
end
function UTILS.PrintTableToLog(table, indent)
if not table then
BASE:E("No table passed!")
return
end
if not indent then indent = 0 end
for k, v in pairs(table) do
if type(v) == "table" then
BASE:I(string.rep(" ", indent) .. tostring(k) .. " = {")
UTILS.PrintTableToLog(v, indent + 1)
BASE:I(string.rep(" ", indent) .. "}")
else
BASE:I(string.rep(" ", indent) .. tostring(k) .. " = " .. tostring(v))
end
end
end
UTILS.ToDegree = function(angle)
return angle*180/math.pi
@@ -1373,7 +1392,7 @@ function UTILS.TACANToFrequency(TACANChannel, TACANMode)
end
--- Returns the DCS map/theatre as optained by env.mission.theatre
--- Returns the DCS map/theatre as optained by `env.mission.theatre`.
-- @return #string DCS map name.
function UTILS.GetDCSMap()
return env.mission.theatre
@@ -1429,6 +1448,7 @@ end
-- * Syria +5 (East)
-- * Mariana Islands +2 (East)
-- * Falklands +12 (East) - note there's a LOT of deviation across the map, as we're closer to the South Pole
-- * Sinai +4.8 (East)
-- @param #string map (Optional) Map for which the declination is returned. Default is from env.mission.theatre
-- @return #number Declination in degrees.
function UTILS.GetMagneticDeclination(map)
@@ -1453,6 +1473,8 @@ function UTILS.GetMagneticDeclination(map)
declination=2
elseif map==DCSMAP.Falklands then
declination=12
elseif map==DCSMAP.Sinai then
declination=4.8
else
declination=0
end
@@ -1668,6 +1690,8 @@ function UTILS.GMTToLocalTimeDifference()
return 10 -- Guam is UTC+10 hours.
elseif theatre==DCSMAP.Falklands then
return -3 -- Fireland is UTC-3 hours.
elseif theatre==DCSMAP.Sinai then
return 2 -- Currently map is +2 but should be +3 (DCS bug?)
else
BASE:E(string.format("ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring(theatre)))
return 0

View File

@@ -11,8 +11,8 @@
-- @module Wrapper.Airbase
-- @image Wrapper_Airbase.JPG
--- @type AIRBASE
---
-- @type AIRBASE
-- @field #string ClassName Name of the class, i.e. "AIRBASE".
-- @field #table CategoryName Names of airbase categories.
-- @field #string AirbaseName Name of the airbase.
@@ -198,8 +198,47 @@ AIRBASE.Nevada = {
-- * AIRBASE.Normandy.Needs_Oar_Point
-- * AIRBASE.Normandy.Funtington
-- * AIRBASE.Normandy.Tangmere
-- * AIRBASE.Normandy.Ford_AF
--
-- * AIRBASE.Normandy.Ford
-- * AIRBASE.Normandy.Argentan
-- * AIRBASE.Normandy.Goulet
-- * AIRBASE.Normandy.Barville
-- * AIRBASE.Normandy.Essay
-- * AIRBASE.Normandy.Hauterive
-- * AIRBASE.Normandy.Lymington
-- * AIRBASE.Normandy.Vrigny
-- * AIRBASE.Normandy.Odiham
-- * AIRBASE.Normandy.Conches
-- * AIRBASE.Normandy.West_Malling
-- * AIRBASE.Normandy.Villacoublay
-- * AIRBASE.Normandy.Kenley
-- * AIRBASE.Normandy.Beauvais_Tille
-- * AIRBASE.Normandy.Cormeilles_en_Vexin
-- * AIRBASE.Normandy.Creil
-- * AIRBASE.Normandy.Guyancourt
-- * AIRBASE.Normandy.Lonrai
-- * AIRBASE.Normandy.Dinan_Trelivan
-- * AIRBASE.Normandy.Heathrow
-- * AIRBASE.Normandy.Fecamp_Benouville
-- * AIRBASE.Normandy.Farnborough
-- * AIRBASE.Normandy.Friston
-- * AIRBASE.Normandy.Deanland
-- * AIRBASE.Normandy.Triqueville
-- * AIRBASE.Normandy.Poix
-- * AIRBASE.Normandy.Orly
-- * AIRBASE.Normandy.Stoney_Cross
-- * AIRBASE.Normandy.Amiens_Glisy
-- * AIRBASE.Normandy.Ronai
-- * AIRBASE.Normandy.Rouen_Boos
-- * AIRBASE.Normandy.Deauville
-- * AIRBASE.Normandy.Saint_Aubin
-- * AIRBASE.Normandy.Flers
-- * AIRBASE.Normandy.Avranches_Le_Val_Saint_Pere
-- * AIRBASE.Normandy.Gravesend
-- * AIRBASE.Normandy.Beaumont_le_Roger
-- * AIRBASE.Normandy.Broglie
-- * AIRBASE.Normandy.Bernay_Saint_Martin
-- * AIRBASE.Normandy.Saint_Andre_de_lEure
--
-- @field Normandy
AIRBASE.Normandy = {
["Saint_Pierre_du_Mont"] = "Saint Pierre du Mont",
@@ -232,14 +271,46 @@ AIRBASE.Normandy = {
["Needs_Oar_Point"] = "Needs Oar Point",
["Funtington"] = "Funtington",
["Tangmere"] = "Tangmere",
["Ford_AF"] = "Ford_AF",
["Goulet"] = "Goulet",
["Ford"] = "Ford",
["Argentan"] = "Argentan",
["Vrigny"] = "Vrigny",
["Goulet"] = "Goulet",
["Barville"] = "Barville",
["Essay"] = "Essay",
["Hauterive"] = "Hauterive",
["Barville"] = "Barville",
["Lymington"] = "Lymington",
["Vrigny"] = "Vrigny",
["Odiham"] = "Odiham",
["Conches"] = "Conches",
["West_Malling"] = "West Malling",
["Villacoublay"] = "Villacoublay",
["Kenley"] = "Kenley",
["Beauvais_Tille"] = "Beauvais-Tille",
["Cormeilles_en_Vexin"] = "Cormeilles-en-Vexin",
["Creil"] = "Creil",
["Guyancourt"] = "Guyancourt",
["Lonrai"] = "Lonrai",
["Dinan_Trelivan"] = "Dinan-Trelivan",
["Heathrow"] = "Heathrow",
["Fecamp_Benouville"] = "Fecamp-Benouville",
["Farnborough"] = "Farnborough",
["Friston"] = "Friston",
["Deanland "] = "Deanland ",
["Triqueville"] = "Triqueville",
["Poix"] = "Poix",
["Orly"] = "Orly",
["Stoney_Cross"] = "Stoney Cross",
["Amiens_Glisy"] = "Amiens-Glisy",
["Ronai"] = "Ronai",
["Rouen_Boos"] = "Rouen-Boos",
["Deauville"] = "Deauville",
["Saint_Aubin"] = "Saint-Aubin",
["Flers"] = "Flers",
["Avranches_Le_Val_Saint_Pere"] = "Avranches Le Val-Saint-Pere",
["Gravesend"] = "Gravesend",
["Beaumont_le_Roger"] = "Beaumont-le-Roger",
["Broglie"] = "Broglie",
["Bernay_Saint_Martin"] = "Bernay Saint Martin",
["Saint_Andre_de_lEure"] = "Saint-Andre-de-lEure",
}
--- Airbases of the Persion Gulf Map:
@@ -355,7 +426,7 @@ AIRBASE.TheChannel = {
-- * AIRBASE.Syria.Al_Dumayr
-- * AIRBASE.Syria.Gazipasa
-- * AIRBASE.Syria.Hatay
-- * AIRBASE.Syria.Nicosia
-- * AIRBASE.Syria.Nicosia [Deactivated by ED as of June/2023]
-- * AIRBASE.Syria.Pinarbashi
-- * AIRBASE.Syria.Paphos
-- * AIRBASE.Syria.Kingsfield
@@ -396,8 +467,8 @@ AIRBASE.TheChannel = {
-- * AIRBASE.Syria.H3_Northwest
-- * AIRBASE.Syria.H3_Southwest
-- * AIRBASE.Syria.Kharab_Ishk
-- * AIRBASE.Syria.Raj_al_Issa_East
-- * AIRBASE.Syria.Raj_al_Issa_West
-- * AIRBASE.Syria.Raj_al_Issa_East (deleted by ED)
-- * AIRBASE.Syria.Raj_al_Issa_West (deleted by ED)
-- * AIRBASE.Syria.Ruwayshid
-- * AIRBASE.Syria.Sanliurfa
-- * AIRBASE.Syria.Tal_Siman
@@ -419,9 +490,8 @@ AIRBASE.Syria={
["Wujah_Al_Hajar"]="Wujah Al Hajar",
["Al_Dumayr"]="Al-Dumayr",
["Gazipasa"]="Gazipasa",
--["Ru_Convoy_4"]="Ru Convoy-4",
["Hatay"]="Hatay",
["Nicosia"]="Nicosia",
--["Nicosia"]="Nicosia",
["Pinarbashi"]="Pinarbashi",
["Paphos"]="Paphos",
["Kingsfield"]="Kingsfield",
@@ -462,8 +532,8 @@ AIRBASE.Syria={
["H3_Northwest"]="H3 Northwest",
["H3_Southwest"]="H3 Southwest",
["Kharab_Ishk"]="Kharab Ishk",
["Raj_al_Issa_East"]="Raj al Issa East",
["Raj_al_Issa_West"]="Raj al Issa West",
-- ["Raj_al_Issa_East"]="Raj al Issa East",
-- ["Raj_al_Issa_West"]="Raj al Issa West",
["Ruwayshid"]="Ruwayshid",
["Sanliurfa"]="Sanliurfa",
["Tal_Siman"]="Tal Siman",
@@ -478,6 +548,8 @@ AIRBASE.Syria={
-- * AIRBASE.MarianaIslands.Saipan_Intl
-- * AIRBASE.MarianaIslands.Tinian_Intl
-- * AIRBASE.MarianaIslands.Olf_Orote
-- * AIRBASE.MarianaIslands.Pagan_Airstrip
-- * AIRBASE.MarianaIslands.North_West_Field
--
-- @field MarianaIslands
AIRBASE.MarianaIslands = {
@@ -487,6 +559,8 @@ AIRBASE.MarianaIslands = {
["Saipan_Intl"] = "Saipan Intl",
["Tinian_Intl"] = "Tinian Intl",
["Olf_Orote"] = "Olf Orote",
["Pagan_Airstrip"] = "Pagan Airstrip",
["North_West_Field"] = "North West Field",
}
--- Airbases of the South Atlantic map:
@@ -548,6 +622,72 @@ AIRBASE.SouthAtlantic={
["Gull_Point"] = "Gull Point",
}
--- Airbases of the Sinai map:
--
-- * AIRBASE.Sinai.Abu_Suwayr
-- * AIRBASE.Sinai.Sde_Dov
-- * AIRBASE.Sinai.AzZaqaziq
-- * AIRBASE.Sinai.Hatzor
-- * AIRBASE.Sinai.Kedem
-- * AIRBASE.Sinai.Nevatim
-- * AIRBASE.Sinai.Cairo_International_Airport
-- * AIRBASE.Sinai.Al_Ismailiyah
-- * AIRBASE.Sinai.As_Salihiyah
-- * AIRBASE.Sinai.Fayed
-- * AIRBASE.Sinai.Bilbeis_Air_Base
-- * AIRBASE.Sinai.Ramon_Airbase
-- * AIRBASE.Sinai.Kibrit_Air_Base
-- * AIRBASE.Sinai.El_Arish
-- * AIRBASE.Sinai.Ovda
-- * AIRBASE.Sinai.Melez
-- * AIRBASE.Sinai.Al_Mansurah
-- * AIRBASE.Sinai.Palmahim
-- * AIRBASE.Sinai.Baluza
-- * AIRBASE.Sinai.El_Gora
-- * AIRBASE.Sinai.Difarsuwar_Airfield
-- * AIRBASE.Sinai.Wadi_al_Jandali
-- * AIRBASE.Sinai.St_Catherine
-- * AIRBASE.Sinai.Tel_Nof
-- * AIRBASE.Sinai.Abu_Rudeis
-- * AIRBASE.Sinai.Inshas_Airbase
-- * AIRBASE.Sinai.Ben_Gurion
-- * AIRBASE.Sinai.Bir_Hasanah
-- * AIRBASE.Sinai.Cairo_West
--
-- @field Sinai
AIRBASE.Sinai = {
["Hatzerim"] = "Hatzerim",
["Abu_Suwayr"] = "Abu Suwayr",
["Sde_Dov"] = "Sde Dov",
["AzZaqaziq"] = "AzZaqaziq",
["Hatzor"] = "Hatzor",
["Kedem"] = "Kedem",
["Nevatim"] = "Nevatim",
["Cairo_International_Airport"] = "Cairo International Airport",
["Al_Ismailiyah"] = "Al Ismailiyah",
["As_Salihiyah"] = "As Salihiyah",
["Fayed"] = "Fayed",
["Bilbeis_Air_Base"] = "Bilbeis Air Base",
["Ramon_Airbase"] = "Ramon Airbase",
["Kibrit_Air_Base"] = "Kibrit Air Base",
["El_Arish"] = "El Arish",
["Ovda"] = "Ovda",
["Melez"] = "Melez",
["Al_Mansurah"] = "Al Mansurah",
["Palmahim"] = "Palmahim",
["Baluza"] = "Baluza",
["El_Gora"] = "El Gora",
["Difarsuwar_Airfield"] = "Difarsuwar Airfield",
["Wadi_al_Jandali"] = "Wadi al Jandali",
["St_Catherine"] = "St Catherine",
["Tel_Nof"] = "Tel Nof",
["Abu_Rudeis"] = "Abu Rudeis",
["Inshas_Airbase"] = "Inshas Airbase",
["Ben_Gurion"] = "Ben-Gurion",
["Bir_Hasanah"] = "Bir Hasanah",
["Cairo_West"] = "Cairo West",
}
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
-- @type AIRBASE.ParkingSpot
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.
@@ -651,7 +791,13 @@ function AIRBASE:Register(AirbaseName)
-- Category.
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
-- H2 is bugged
--if self.AirbaseName == "H4" and self.descriptors == nil then
--self:E("***** H4 on Syria map is currently bugged!")
--return nil
--end
-- Set category.
if self.category==Airbase.Category.AIRDROME then
self.isAirdrome=true
@@ -1365,16 +1511,16 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
-- Get the aircraft size, i.e. it's longest side of x,z.
local aircraft = nil -- fix local problem below
local _aircraftsize, ax,ay,az
-- SU27 dimensions as default
local _aircraftsize = 23
local ax = 23 -- l
local ay = 7 -- h
local az = 17 -- w
if group and group.ClassName == "GROUP" then
aircraft=group:GetUnit(1)
_aircraftsize, ax,ay,az=aircraft:GetObjectSize()
else
-- SU27 dimensions
_aircraftsize = 23
ax = 23 -- length
ay = 7 -- height
az = 17 -- width
if aircraft then
_aircraftsize, ax,ay,az=aircraft:GetObjectSize()
end
end
@@ -2224,3 +2370,17 @@ function AIRBASE:CheckOnRunWay(group, radius, despawn)
return false
end
--- Get category of airbase.
-- @param #AIRBASE self
-- @return #number Category of airbase from GetDesc().category.
function AIRBASE:GetCategory()
return self.category
end
--- Get category name of airbase.
-- @param #AIRBASE self
-- @return #string Category of airbase, i.e. Airdrome, Ship, or Helipad
function AIRBASE:GetCategoryName()
return AIRBASE.CategoryName[self.category]
end

View File

@@ -52,6 +52,7 @@
-- * @{#CONTROLLABLE.TaskEmbarking}: (AIR) Move the controllable to a Vec2 Point, wait for a defined duration and embark a controllable.
-- * @{#CONTROLLABLE.TaskEmbarkToTransport}: (GROUND) Embark to a Transport landed at a location.
-- * @{#CONTROLLABLE.TaskEscort}: (AIR) Escort another airborne controllable.
-- * @{#CONTROLLABLE.TaskGroundEscort}: (AIR/HELO) Escort a ground controllable.
-- * @{#CONTROLLABLE.TaskFAC_AttackGroup}: (AIR + GROUND) The task makes the controllable/unit a FAC and orders the FAC to control the target (enemy ground controllable) destruction.
-- * @{#CONTROLLABLE.TaskFireAtPoint}: (GROUND) Fire some or all ammunition at a VEC2 point.
-- * @{#CONTROLLABLE.TaskFollow}: (AIR) Following another airborne controllable.
@@ -690,7 +691,8 @@ function CONTROLLABLE:CommandActivateACLS( UnitID, Name, Delay )
if Delay and Delay > 0 then
SCHEDULER:New( nil, self.CommandActivateACLS, { self, UnitID, Name }, Delay )
else
self:SetCommand( CommandActivateACLS )
local controller = self:_GetController()
controller:setCommand( CommandActivateACLS )
end
return self
@@ -711,7 +713,8 @@ function CONTROLLABLE:CommandDeactivateACLS( Delay )
if Delay and Delay > 0 then
SCHEDULER:New( nil, self.CommandDeactivateACLS, { self }, Delay )
else
self:SetCommand( CommandDeactivateACLS )
local controller = self:_GetController()
controller:setCommand( CommandDeactivateACLS )
end
return self
@@ -761,7 +764,7 @@ function CONTROLLABLE:CommandActivateLink4(Frequency, UnitID, Callsign, Delay)
local CommandActivateLink4= {
id = "ActivateLink4",
params= {
["frequency "] = freq*1000000,
["frequency"] = freq*1000000,
["unitId"] = UnitID or self:GetID(),
["name"] = Callsign or "LNK",
}
@@ -772,7 +775,8 @@ function CONTROLLABLE:CommandActivateLink4(Frequency, UnitID, Callsign, Delay)
if Delay and Delay>0 then
SCHEDULER:New(nil, self.CommandActivateLink4, {self, Frequency, UnitID, Callsign}, Delay)
else
self:SetCommand(CommandActivateLink4)
local controller = self:_GetController()
controller:setCommand(CommandActivateLink4)
end
return self
@@ -810,7 +814,8 @@ function CONTROLLABLE:CommandDeactivateLink4(Delay)
if Delay and Delay>0 then
SCHEDULER:New(nil, self.CommandDeactivateLink4, {self}, Delay)
else
self:SetCommand(CommandDeactivateLink4)
local controller = self:_GetController()
controller:setCommand(CommandDeactivateLink4)
end
return self
@@ -1266,7 +1271,7 @@ end
--- (AIR) Orbit at a position with at a given altitude and speed. Optionally, a race track pattern can be specified.
-- @param #CONTROLLABLE self
-- @param Core.Point#COORDINATE Coord Coordinate at which the CONTROLLABLE orbits.
-- @param Core.Point#COORDINATE Coord Coordinate at which the CONTROLLABLE orbits. Can also be given as a `DCS#Vec3` or `DCS#Vec2` object.
-- @param #number Altitude Altitude in meters of the orbit pattern. Default y component of Coord.
-- @param #number Speed Speed [m/s] flying the orbit pattern. Default 128 m/s = 250 knots.
-- @param Core.Point#COORDINATE CoordRaceTrack (Optional) If this coordinate is specified, the CONTROLLABLE will fly a race-track pattern using this and the initial coordinate.
@@ -1275,11 +1280,11 @@ function CONTROLLABLE:TaskOrbit( Coord, Altitude, Speed, CoordRaceTrack )
local Pattern = AI.Task.OrbitPattern.CIRCLE
local P1 = Coord:GetVec2()
local P1 = {x=Coord.x, y=Coord.z or Coord.y}
local P2 = nil
if CoordRaceTrack then
Pattern = AI.Task.OrbitPattern.RACE_TRACK
P2 = CoordRaceTrack:GetVec2()
P2 = {x=CoordRaceTrack.x, y=CoordRaceTrack.z or CoordRaceTrack.y}
end
local Task = {
@@ -1476,15 +1481,53 @@ function CONTROLLABLE:TaskFollow( FollowControllable, Vec3, LastWaypointIndex )
return DCSTask
end
--- (AIR/HELO) Escort a ground controllable.
-- The unit / controllable will follow lead unit of the other controllable, additional units of both controllables will continue following their leaders.
-- The unit / controllable will also protect that controllable from threats of specified types.
-- @param #CONTROLLABLE self
-- @param #CONTROLLABLE FollowControllable The controllable to be escorted.
-- @param #number LastWaypointIndex (optional) Detach waypoint of another controllable. Once reached the unit / controllable Escort task is finished.
-- @param #number OrbitDistance (optional) Maximum distance helo will orbit around the ground unit in meters. Defaults to 2000 meters.
-- @param DCS#AttributeNameArray TargetTypes (optional) Array of AttributeName that is contains threat categories allowed to engage. Default {"Ground vehicles"}. See [https://wiki.hoggit.us/view/DCS_enum_attributes](https://wiki.hoggit.us/view/DCS_enum_attributes)
-- @return DCS#Task The DCS task structure.
function CONTROLLABLE:TaskGroundEscort( FollowControllable, LastWaypointIndex, OrbitDistance, TargetTypes )
-- Escort = {
-- id = 'GroundEscort',
-- params = {
-- groupId = Group.ID, -- must
-- engagementDistMax = Distance, -- Must. With his task it does not appear to actually define the range AI are allowed to attack at, rather it defines the size length of the orbit. The helicopters will fly up to this set distance before returning to the escorted group.
-- lastWptIndexFlag = boolean, -- optional
-- lastWptIndex = number, -- optional
-- targetTypes = array of AttributeName, -- must
-- lastWptIndexFlagChangedManually = boolean, -- must be true
-- }
-- }
local DCSTask = {
id = 'GroundEscort',
params = {
groupId = FollowControllable and FollowControllable:GetID() or nil,
engagementDistMax = OrbitDistance or 2000,
lastWptIndexFlag = LastWaypointIndex and true or false,
lastWptIndex = LastWaypointIndex,
targetTypes = TargetTypes or {"Ground vehicles"},
lastWptIndexFlagChangedManually = true,
},
}
return DCSTask
end
--- (AIR) Escort another airborne controllable.
-- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders.
-- The unit / controllable will also protect that controllable from threats of specified types.
-- @param #CONTROLLABLE self
-- @param #CONTROLLABLE FollowControllable The controllable to be escorted.
-- @param DCS#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around.
-- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished.
-- @param #number EngagementDistance Maximal distance from escorted controllable to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax.
-- @param DCS#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. Default {"Air"}.
-- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Escort task is finished.
-- @param #number EngagementDistance Maximal distance from escorted controllable to threat in meters. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax.
-- @param DCS#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. Default {"Air"}. See https://wiki.hoggit.us/view/DCS_enum_attributes
-- @return DCS#Task The DCS task structure.
function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes )
@@ -1500,8 +1543,7 @@ function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, E
-- }
-- }
local DCSTask
DCSTask = {
local DCSTask = {
id = 'Escort',
params = {
groupId = FollowControllable and FollowControllable:GetID() or nil,
@@ -1692,7 +1734,9 @@ function CONTROLLABLE:EnRouteTaskSEAD(TargetTypes, Priority)
return DCSTask
end
--- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets.
--- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now;
-- it just allows the unit/controllable to engage the target controllable as well as other assigned targets.
-- See [hoggit](https://wiki.hoggitworld.com/view/DCS_task_engageGroup).
-- @param #CONTROLLABLE self
-- @param #CONTROLLABLE AttackGroup The Controllable to be attacked.
-- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first.
@@ -1741,6 +1785,7 @@ function CONTROLLABLE:EnRouteTaskEngageGroup( AttackGroup, Priority, WeaponType,
end
--- (AIR) Search and attack the Unit.
-- See [hoggit](https://wiki.hoggitworld.com/view/DCS_task_engageUnit).
-- @param #CONTROLLABLE self
-- @param Wrapper.Unit#UNIT EngageUnit The UNIT.
-- @param #number Priority (optional) All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first.
@@ -1776,6 +1821,7 @@ function CONTROLLABLE:EnRouteTaskEngageUnit( EngageUnit, Priority, GroupAttack,
end
--- (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters.
-- [hoggit](https://wiki.hoggitworld.com/view/DCS_task_awacs).
-- @param #CONTROLLABLE self
-- @return DCS#Task The DCS task structure.
function CONTROLLABLE:EnRouteTaskAWACS()
@@ -1789,6 +1835,7 @@ function CONTROLLABLE:EnRouteTaskAWACS()
end
--- (AIR) Aircraft will act as a tanker for friendly units. No parameters.
-- See [hoggit](https://wiki.hoggitworld.com/view/DCS_task_tanker).
-- @param #CONTROLLABLE self
-- @return DCS#Task The DCS task structure.
function CONTROLLABLE:EnRouteTaskTanker()
@@ -1804,6 +1851,7 @@ end
-- En-route tasks for ground units/controllables
--- (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts). No parameters.
-- See [hoggit](https://wiki.hoggitworld.com/view/DCS_task_ewr).
-- @param #CONTROLLABLE self
-- @return DCS#Task The DCS task structure.
function CONTROLLABLE:EnRouteTaskEWR()
@@ -1821,14 +1869,17 @@ end
--- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose the target (enemy ground controllable) as well as other assigned targets.
-- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC.
-- If the task is assigned to the controllable lead unit will be a FAC.
-- See [hoggit](https://wiki.hoggitworld.com/view/DCS_task_fac_engageGroup).
-- @param #CONTROLLABLE self
-- @param #CONTROLLABLE AttackGroup Target CONTROLLABLE.
-- @param #number Priority (Optional) All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. Default is 0.
-- @param #number WeaponType (Optional) Bitmask of weapon types those allowed to use. Default is "Auto".
-- @param DCS#AI.Task.Designation Designation (Optional) Designation type.
-- @param #boolean Datalink (optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default.
-- @param #number CallsignID CallsignID, e.g. `CALLSIGN.JTAC.Anvil` for ground or `CALLSIGN.Aircraft.Ford` for air.
-- @param #number CallsignNumber Callsign first number, e.g. 2 for `Ford-2`.
-- @return DCS#Task The DCS task structure.
function CONTROLLABLE:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponType, Designation, Datalink )
function CONTROLLABLE:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponType, Designation, Datalink, Frequency, Modulation, CallsignID, CallsignNumber )
local DCSTask = {
id = 'FAC_EngageControllable',
@@ -1837,6 +1888,10 @@ function CONTROLLABLE:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponT
weaponType = WeaponType or "Auto",
designation = Designation,
datalink = Datalink and Datalink or false,
frequency = (Frequency or 133)*1000000,
modulation = Modulation or radio.modulation.AM,
callname = CallsignID,
number = CallsignNumber,
priority = Priority or 0,
},
}
@@ -1845,27 +1900,26 @@ function CONTROLLABLE:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponT
end
--- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose a targets (enemy ground controllable) around as well as other assigned targets.
-- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC.
-- If the task is assigned to the controllable lead unit will be a FAC.
-- Assigns the controlled group to act as a Forward Air Controller or JTAC. Any detected targets will be assigned as targets to the player via the JTAC radio menu.
-- Target designation is set to auto and is dependent on the circumstances.
-- See [hoggit](https://wiki.hoggitworld.com/view/DCS_task_fac).
-- @param #CONTROLLABLE self
-- @param DCS#Distance Radius The maximal distance from the FAC to a target.
-- @param #number Frequency Frequency in MHz. Default 133 MHz.
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
-- @param #number CallsignID CallsignID, e.g. `CALLSIGN.JTAC.Anvil` for ground or `CALLSIGN.Aircraft.Ford` for air.
-- @param #number CallsignNumber Callsign first number, e.g. 2 for `Ford-2`.
-- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first.
-- @return DCS#Task The DCS task structure.
function CONTROLLABLE:EnRouteTaskFAC( Radius, Priority )
-- FAC = {
-- id = 'FAC',
-- params = {
-- radius = Distance,
-- priority = number
-- }
-- }
function CONTROLLABLE:EnRouteTaskFAC( Frequency, Modulation, CallsignID, CallsignNumber, Priority )
local DCSTask = {
id = 'FAC',
params = {
radius = Radius,
priority = Priority
frequency = (Frequency or 133)*1000000,
modulation = Modulation or radio.modulation.AM,
callname = CallsignID,
number = CallsignNumber,
priority = Priority or 0
}
}

View File

@@ -4,8 +4,8 @@
--
-- ===
--
-- ### Author: **applevangelist**
-- # Last Update Feb 2023
-- ### Author: **Applevangelist**
-- # Last Update June 2023
--
-- ===
--
@@ -42,7 +42,7 @@ do
-- @field #NET
NET = {
ClassName = "NET",
Version = "0.1.0",
Version = "0.1.2",
BlockTime = 600,
BlockedPilots = {},
BlockedUCIDs = {},
@@ -90,7 +90,7 @@ function NET:New()
-- @param #string From State.
-- @param #string Event Trigger.
-- @param #string To State.
-- @param Wrapper.Unit#UNIT Client Unit Object.
-- @param Wrapper.Client#CLIENT Client Object.
-- @param #string Name Name of joining Pilot.
-- @return #NET self
@@ -196,7 +196,7 @@ function NET:_EventHandler(EventData)
-- Get Player Data
local name = data.IniPlayerName and data.IniPlayerName or data.IniUnit:GetPlayerName()
local ucid = self:GetPlayerUCID(nil,name)
local ucid = self:GetPlayerUCID(nil,name) or "none"
local PlayerID = self:GetPlayerIDByName(name) or "none"
local PlayerSide, PlayerSlot = self:GetSlot(data.IniUnit)
local TNow = timer.getTime()
@@ -220,7 +220,8 @@ function NET:_EventHandler(EventData)
side = PlayerSide,
slot = PlayerSlot,
}
self:__PlayerJoined(1,data.IniUnit,name)
local client = CLIENT:FindByPlayerName(name) or data.IniUnit
self:__PlayerJoined(1,client,name)
return self
end
end
@@ -807,7 +808,7 @@ function NET:onafterRun(From,Event,To)
self:HandleEvent(EVENTS.Ejection,self._EventHandler)
self:HandleEvent(EVENTS.Crash,self._EventHandler)
self:HandleEvent(EVENTS.SelfKillPilot,self._EventHandler)
self:__Status(-30)
self:__Status(-10)
end
--- Stop the event functions

View File

@@ -237,22 +237,23 @@ end
-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE.
-- @return #nil The POSITIONABLE is not existing or alive.
function POSITIONABLE:GetVec3()
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
--local status, vec3 = pcall(
-- function()
-- local vec3 = DCSPositionable:getPoint()
-- return vec3
--end
--)
local vec3 = DCSPositionable:getPoint()
if vec3 then
--if status then
return vec3
else
self:E( "ERROR: Cannot get vec3!" )
end
--else
--self:E( { "Cannot get Vec3 from DCS Object", Positionable = self, Alive = self:IsAlive() } )
--end
end
-- ERROR!
self:E( { "Cannot GetVec3", Positionable = self, Alive = self:IsAlive() } )
self:E( { "Cannot get the Positionable DCS Object for GetVec3", Positionable = self, Alive = self:IsAlive() } )
return nil
end
@@ -394,6 +395,35 @@ function POSITIONABLE:GetCoordinate()
return nil
end
--- Triggers an explosion at the coordinates of the positionable.
-- @param #POSITIONABLE self
-- @param #number power Power of the explosion in kg TNT. Default 100 kg TNT.
-- @param #number delay (Optional) Delay of explosion in seconds.
-- @return #POSITIONABLE self
function POSITIONABLE:Explode(power, delay)
-- Default.
power=power or 100
-- Check if delay or not.
if delay and delay>0 then
-- Delayed call.
self:ScheduleOnce(delay, POSITIONABLE.Explode, self, power, 0)
else
local coord=self:GetCoord()
if coord then
-- Create an explotion at the coordinate of the positionable.
coord:Explosion(power)
end
end
return self
end
--- Returns a COORDINATE object, which is offset with respect to the orientation of the POSITIONABLE.
-- @param #POSITIONABLE self
-- @param #number x Offset in the direction "the nose" of the unit is pointing in meters. Default 0 m.
@@ -435,6 +465,115 @@ function POSITIONABLE:GetOffsetCoordinate( x, y, z )
return coord
end
--- Returns a COORDINATE object, which is transformed to be relative to the POSITIONABLE. Inverse of @{#POSITIONABLE.GetOffsetCoordinate}.
-- @param #POSITIONABLE self
-- @param #number x Offset along the world x-axis in meters. Default 0 m.
-- @param #number y Offset along the world y-axis in meters. Default 0 m.
-- @param #number z Offset along the world z-axis in meters. Default 0 m.
-- @return Core.Point#COORDINATE The relative COORDINATE with respect to the orientation of the POSITIONABLE.
function POSITIONABLE:GetRelativeCoordinate( x, y, z )
-- Default if nil.
x = x or 0
y = y or 0
z = z or 0
-- Vector from the origin of the map to self.
local selfPos = self:GetVec3()
-- Vectors making up self's local coordinate system.
local X = self:GetOrientationX()
local Y = self:GetOrientationY()
local Z = self:GetOrientationZ()
-- Offset from self to self's position (still in the world coordinate system).
local off = {
x = x - selfPos.x,
y = y - selfPos.y,
z = z - selfPos.z
}
-- The end result
local res = { x = 0, y = 0, z = 0 }
-- Matrix equation to solve:
-- | X.x, Y.x, Z.x | | res.x | | off.x |
-- | X.y, Y.y, Z.y | . | res.y | = | off.y |
-- | X.z, Y.z, Z.z | | res.z | | off.z |
-- Use gaussian elimination to solve the system of equations.
-- https://en.wikipedia.org/wiki/Gaussian_elimination
local mat = {
{ X.x, Y.x, Z.x, off.x },
{ X.y, Y.y, Z.y, off.y },
{ X.z, Y.z, Z.z, off.z }
}
-- Matrix dimensions
local m = 3
local n = 4
-- Pivot indices
local h = 1
local k = 1
while h <= m and k <= n do
local v_max = math.abs( mat[h][k] )
local i_max = h
for i = h,m,1 do
local value = math.abs( mat[i][k] )
if value > v_max then
i_max = i
v_max = value
end
end
if mat[i_max][k] == 0 then
-- Already all 0s, nothing to do.
k = k + 1
else
-- Swap rows h and i_max
local tmp = mat[h]
mat[h] = mat[i_max]
mat[i_max] = tmp
for i = h + 1,m,1 do
-- The scaling factor to use to reduce all values in this column
local f = mat[i][k] / mat[h][k]
mat[i][k] = 0
for j = k+1,n,1 do
mat[i][j] = mat[i][j] - f*mat[h][j]
end
end
h = h + 1
k = k + 1
end
end
-- mat is now in row echelon form:
-- | #, #, #, # |
-- | 0, #, #, # |
-- | 0, 0, #, # |
--
-- and the linear equation is now effectively:
-- | #, #, # | | res.x | | # |
-- | 0, #, # | . | res.y | = | # |
-- | 0, 0, # | | res.z | | # |
-- this resulting system of equations can be easily solved via substitution.
res.z = mat[3][4] / mat[3][3]
res.y = (mat[2][4] - res.z * mat[2][3]) / mat[2][2]
res.x = (mat[1][4] - res.y * mat[1][2] - res.z * mat[1][3]) / mat[1][1]
local coord = COORDINATE:NewFromVec3( res )
-- Return the relative coordinate.
return coord
end
--- Returns a random @{DCS#Vec3} vector within a range, indicating the point in 3D of the POSITIONABLE within the mission.
-- @param #POSITIONABLE self
-- @param #number Radius

View File

@@ -63,12 +63,18 @@ function SCENERY:GetDCSObject()
end
--- Get current life points from the SCENERY Object.
-- **CAVEAT**: Some objects change their life value or "hitpoints" **after** the first hit. Hence we will adjust the life0 value to 120%
-- of the last life value if life exceeds life0 (initial life) at any point. Thus will will get a smooth percentage decrease, if you use this e.g. as success
-- criteria for a bombing task.
--@param #SCENERY self
--@return #number life
function SCENERY:GetLife()
local life = 0
if self.SceneryObject then
life = self.SceneryObject:getLife()
if life > self.Life0 then
self.Life0 = math.floor(life * 1.2)
end
end
return life
end
@@ -110,11 +116,13 @@ end
--@param #number Radius (optional) Search radius around coordinate, defaults to 100
--@return #SCENERY Scenery Object or `nil` if it cannot be found
function SCENERY:FindByName(Name, Coordinate, Radius)
local radius = Radius or 100
local name = Name or "unknown"
local scenery = nil
BASE:T({name, radius, Coordinate:GetVec2()})
---
-- @param Core.Point#COORDINATE coordinate
-- @param #number radius
@@ -170,6 +178,7 @@ function SCENERY:FindByZoneName( ZoneName )
zone = ZONE:FindByName(ZoneName)
end
local _id = zone:GetProperty('OBJECT ID')
BASE:T("Object ID ".._id)
if not _id then
-- this zone has no object ID
BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName))
@@ -235,4 +244,4 @@ end
--@return #SCENERY self
function SCENERY:Destroy()
return self
end
end

View File

@@ -25,6 +25,7 @@
-- @field #string ClassName Name of the class.
-- @field #string UnitName Name of the unit.
-- @field #string GroupName Name of the group the unit belongs to.
-- @field #table DCSUnit The DCS Unit object from the API.
-- @extends Wrapper.Controllable#CONTROLLABLE
--- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the global _DATABASE object (an instance of @{Core.Database#DATABASE}).
@@ -92,6 +93,7 @@ UNIT = {
ClassName="UNIT",
UnitName=nil,
GroupName=nil,
DCSUnit = nil,
}
@@ -124,6 +126,7 @@ function UNIT:Register( UnitName )
if group then
self.GroupName=group:getName()
end
self.DCSUnit = unit
end
-- Set event prio.
@@ -175,7 +178,11 @@ function UNIT:GetDCSObject()
if DCSUnit then
return DCSUnit
end
if self.DCSUnit then
return self.DCSUnit
end
return nil
end
@@ -313,19 +320,36 @@ function UNIT:IsActive()
return nil
end
--- Returns if the Unit is alive.
-- If the Unit is not alive, nil is returned.
-- If the Unit is alive and active, true is returned.
-- If the Unit is alive but not active, false is returned.
--- Returns if the unit is exists in the mission.
-- If not even the DCS unit object does exist, `nil` is returned.
-- If the unit object exists, the value of the DCS API function [isExist](https://wiki.hoggitworld.com/view/DCS_func_isExist) is returned.
-- @param #UNIT self
-- @return #boolean `true` if Unit is alive and active. `false` if Unit is alive but not active. `nil` if the Unit is not existing or is not alive.
-- @return #boolean Returns `true` if unit exists in the mission.
function UNIT:IsExist()
local DCSUnit = self:GetDCSObject() -- DCS#Unit
if DCSUnit then
local exists = DCSUnit:isExist()
return exists
end
return nil
end
--- Returns if the Unit is alive.
-- If the Unit is not alive/existent, `nil` is returned.
-- If the Unit is alive and active, `true` is returned.
-- If the Unit is alive but not active, `false`` is returned.
-- @param #UNIT self
-- @return #boolean Returns `true` if Unit is alive and active, `false` if it exists but is not active and `nil` if the object does not exist or DCS `isExist` function returns false.
function UNIT:IsAlive()
self:F3( self.UnitName )
local DCSUnit = self:GetDCSObject() -- DCS#Unit
if DCSUnit then
local UnitIsAlive = DCSUnit:isExist() and DCSUnit:isActive() -- and DCSUnit:getLife() > 1
if DCSUnit and DCSUnit:isExist() then
local UnitIsAlive = DCSUnit:isActive()
return UnitIsAlive
end
@@ -674,20 +698,27 @@ end
--- Returns the Unit's ammunition.
-- @param #UNIT self
-- @return DCS#Unit.Ammo Table with ammuntion of the unit (or nil). This can be a complex table!
-- @return DCS#Unit.Ammo Table with ammuntion of the unit (or nil). This can be a complex table!
function UNIT:GetAmmo()
self:F2( self.UnitName )
local DCSUnit = self:GetDCSObject()
if DCSUnit then
--local status, unitammo = pcall(
-- function()
-- local UnitAmmo = DCSUnit:getAmmo()
-- return UnitAmmo
--end
--)
--if status then
--return unitammo
--end
local UnitAmmo = DCSUnit:getAmmo()
return UnitAmmo
end
return nil
end
--- Sets the Unit's Internal Cargo Mass, in kg
-- @param #UNIT self
-- @param #number mass to set cargo to

View File

@@ -804,7 +804,7 @@ function WEAPON:_TrackWeapon(time)
-- Return next time the function is called or nil to stop the scheduler.
if self.tracking then
if self.dtTrack and self.dtTrack>0.001 then
if self.dtTrack and self.dtTrack>=0.00001 then
return time+self.dtTrack
else
return nil