Compare commits

...

63 Commits

Author SHA1 Message Date
Frank
43ab4d5f38 Update Warehouse.lua
- Removed trace output of qitem and queue because it stalls the game when written to log file
2024-12-18 22:04:38 +01:00
Applevangelist
0427c0d3a7 #CTLD - Added GetLoadedCargo(Unit) 2024-12-18 12:34:30 +01:00
Applevangelist
014750ea7f #SET - Documentation fixes 2024-12-18 11:35:13 +01:00
Applevangelist
e4bbfce314 #MANTIS
- Better status overview
- Some fixes for SHORAD setup
2024-12-17 12:45:45 +01:00
Applevangelist
359429b17e #GROUP added Teleport(Coordinate) function leveraging Respawn(). Now also translate routes if there are any. 2024-12-15 13:34:13 +01:00
Applevangelist
6001f6abda #EVENT - another fix for scenery without getName function 2024-12-15 11:41:24 +01:00
Applevangelist
fd9b5d8d16 #AIRBASE type fix for single Helipad 2024-12-15 11:33:01 +01:00
Frank
b6f184388a ATIS
- Fixed length of niner sound file
2024-12-15 10:00:59 +01:00
Frank
d8471698ab Merge pull request #2197 from FlightControl-Master/FF/MasterDevel
SPAWNSTATIC
2024-12-14 16:54:50 +01:00
Frank
6204cecbbd SPAWNSTATIC
- moved AddStatic to after static spawn fixing registration of spawned static
2024-12-14 16:54:39 +01:00
Frank
ddeca49916 Merge pull request #2196 from FlightControl-Master/FF/MasterDevel
DATABASE (fix for SPAWNSTATIC)
2024-12-14 13:48:40 +01:00
Frank
d8dcf37886 DATABASE
- Fixed error that static was not returned in `DATABASE:AddStatic()` (leads to issues if a static object with the same name is spawned)
- Other minor changes
2024-12-14 13:48:04 +01:00
Frank
5ae41a208b Merge branch 'master' into FF/MasterDevel 2024-12-14 11:29:57 +01:00
Applevangelist
0462d900e6 xx 2024-12-13 12:08:54 +01:00
Frank
0f962461e1 DCS Iraq update
- `AIRBASE`: Added Iraq airports to enums
- `ATIS`: Added missing maps to enums
- `UTILS`: Added missing maps to enums
2024-12-12 00:22:44 +01:00
Applevangelist
aadc03c38d #CTLD Added option/value for my_ctld.TroopUnloadDistHoverHook 2024-12-11 14:17:58 +01:00
Applevangelist
683fa13bb2 #WEAPON - fix for name not available on target 2024-12-11 13:57:55 +01:00
Applevangelist
e4408a964d #MANTIS - update CHM assets 2024-12-11 13:54:01 +01:00
Frank
f97f33ab59 ATIS v1.1.0
- Added dynamic fog
2024-12-06 00:09:15 +01:00
Frank
f59102ee09 Merge branch 'master' into FF/MasterDevel 2024-12-05 21:06:06 +01:00
Frank
e42e4e1ddf Merge branch 'master' into FF/MasterDevel 2024-12-03 21:15:46 +01:00
Thomas
a30079c45b Update Mantis.lua
Less noise
2024-12-03 18:07:38 +01:00
Applevangelist
50ffd9aba6 #MANTIS - Correct detail data check is run even if automode isn't defined 2024-11-30 16:19:51 +01:00
Frank
936fec1f49 Update Range.lua 2024-11-26 23:06:31 +01:00
Applevangelist
9625d87dd5 #NET - fix for net.force_player_slot(PlayerID, SideID, SlotID ) not working at all - destroy blocked client instead 2024-11-26 10:43:20 +01:00
Frank
802139205c Update Unit.lua
- Fixed bug in `UNIT:GetDCSObject()` when DCS unit does not exist.
2024-11-24 21:54:05 +01:00
Frank
fb918cb2a4 Update DCS.lua 2024-11-21 23:43:58 +01:00
Frank
abb4de46d7 Controllable Detection Improvements/Fixes
- Fixed bug in detection functions for optical detection (enum incorrect)
- Fixed bug in order of return values of `CONTROLLABLE:IsTargetDetected` (both hoggit and DCS are WRONG and MOOSE adopted it).
2024-11-21 23:13:05 +01:00
Frank
dce9631399 Update Event.lua
- Set `Event.IniGroupName` from db in case group does not exist any more
2024-11-15 23:21:50 +01:00
Thomas
6c773786d2 Merge pull request #2186 from FlightControl-Master/Applevangelist-patch-2
Update Enums.lua
2024-11-10 13:46:00 +01:00
Thomas
8939963187 Update Enums.lua
OH58d weapons
2024-11-10 13:45:44 +01:00
Thomas
f9747d1c4c Merge pull request #2184 from FlightControl-Master/Applevangelist-pwsh-1
Update SRS.lua
2024-11-04 14:49:56 +01:00
Thomas
60a3d3409e Update SRS.lua
#MSRS Test to get the pwsh window to minimize
2024-11-04 14:49:26 +01:00
Applevangelist
b72124c0d9 #CONTROLLABLE Corrected parameter omissions 2024-10-31 18:16:02 +01:00
Applevangelist
d51e761b26 #CONTROLLABLE - Rollback changes for EPLRS command 2024-10-31 16:05:24 +01:00
Applevangelist
1445ef61a0 #AIRBASE - added bases from 2.9.9.2280 2024-10-30 17:09:38 +01:00
Applevangelist
dfe2ed2a98 #EVENT - Fix for TgtUnit Name being unobtainable 2024-10-29 13:57:21 +01:00
Applevangelist
be87103b53 #CTLD - fixed a collision when extracting on a possible distance key duplication 2024-10-29 13:18:55 +01:00
Applevangelist
2fb460c4bb #ATC_Ground - stop kicking players immediately for speeding 2024-10-29 11:37:06 +01:00
Applevangelist
216ea230a8 #BASE - Roll back to "old" serialize method for Trace 2024-10-27 13:25:13 +01:00
Applevangelist
90096163ee EPLRS - give group ID only if ground 2024-10-26 18:45:01 +02:00
Thomas
cd178d6a8c Merge pull request #2182 from FlightControl-Master/Applevangelist-patch-1
Update MarkerOps_Base.lua
2024-10-21 11:33:14 +02:00
Thomas
2aa0b5ddfb Update MarkerOps_Base.lua
Added data to FSM events
2024-10-21 11:32:47 +02:00
Applevangelist
37f819458a #AIRBOSS - Change event Land to event RunwayTouch 2024-10-11 08:06:05 +02:00
Applevangelist
168f4301d2 #GROUP - extended options to create callsigns for TTS with own function 2024-10-08 10:05:31 +02:00
Applevangelist
d5a406c60f #MSRS experimental - option to use PowerShell to execute SRS-TTS - set MSRS.UsePowerShell = true to test it. Known issue - PS window does not close until everything is executed. 2024-10-03 14:05:51 +02:00
Applevangelist
cb16210577 #SEAD - better event management of weapons, return earlier if no (H)ARM, return if SEAD Plane is nil 2024-10-03 14:03:06 +02:00
Applevangelist
8c0e0de45f xx 2024-10-01 12:10:21 +02:00
Applevangelist
3524cba4ef xx 2024-10-01 12:08:51 +02:00
Frank
5f8d1cf5b0 Update Warehouse.lua
- Added check for incorrect plane attribute
2024-10-01 09:07:51 +02:00
Applevangelist
846aa823d4 fixes for #SEAD and #SPAWN 2024-09-30 11:35:25 +02:00
Applevangelist
68298fc585 #EVENT Fix for scenery sometimes nit having a getName() function 2024-09-27 11:57:40 +02:00
Applevangelist
e9d75f6d94 #CSAR Beacon Name Fix 2024-09-26 09:06:57 +02:00
Thomas
8fa5277417 Merge pull request #2178 from brykeller/patch-2
Kiowa rescues sit on the skids, no doors need to be opened
2024-09-26 06:55:02 +02:00
Thomas
231f1f236d Merge pull request #2180 from brykeller/patch-3
Update CTLD.lua to update the correct Kiowa typename to OH58D
2024-09-26 06:53:21 +02:00
Bryan Keller
ece0a46f97 Update CTLD.lua to update the correct Kiowa typename to OH58D
Update CTLD.lua to update the correct Kiowa typename to OH58D
2024-09-25 18:59:26 -07:00
Bryan Keller
2c9b0b8376 Kiowa rescues sit on the skids, no doors need to be opened
Kiowa rescues sit on the skids, no doors need to be opened
2024-09-25 18:51:31 -07:00
Applevangelist
a798f2d61c Small fixes 2024-09-23 12:43:39 +02:00
Applevangelist
ae08c87822 #CTLD 2024-09-15 19:24:24 +02:00
Thomas
ae880e9d1c Merge pull request #2176 from Maintenance-Partnership-Systems/Minor-Doco-Fixes
Minor doco fixes
2024-09-15 11:16:08 +02:00
Michael Barnes
101d2e1de5 More incorrect AIRBASE constants in examples. 2024-09-15 18:48:42 +10:00
Michael Barnes
f6b7708567 Fixed some outdated references to AIRBASE constants in examples. 2024-09-15 18:34:18 +10:00
Applevangelist
051286acd1 #SPAWN - Tuning measures from DEVELOP encorporated 2024-09-08 13:24:09 +02:00
30 changed files with 1021 additions and 597 deletions

View File

@@ -34,11 +34,12 @@ local _TraceClassMethod = {}
local _ClassID = 0
---
--- Base class of everything
-- @type BASE
-- @field ClassName The name of the class.
-- @field ClassID The ID number of the class.
-- @field ClassNameAndID The name of the class concatenated with the ID number of the class.
-- @field #string ClassName The name of the class.
-- @field #number ClassID The ID number of the class.
-- @field #string ClassNameAndID The name of the class concatenated with the ID number of the class.
-- @field Core.Scheduler#SCHEDULER Scheduler The scheduler object.
--- BASE class
--
@@ -210,14 +211,6 @@ BASE._ = {
Schedules = {}, --- Contains the Schedulers Active
}
--- The Formation Class
-- @type FORMATION
-- @field Cone A cone formation.
FORMATION = {
Cone = "Cone",
Vee = "Vee",
}
--- BASE constructor.
--
-- This is an example how to use the BASE:New() constructor in a new class definition when inheriting from BASE.
@@ -1416,7 +1409,7 @@ function BASE:E( Arguments )
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
else
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, BASE:_Serialize(Arguments) ) )
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, UTILS.BasicSerialize(Arguments) ) )
end
end
@@ -1443,7 +1436,7 @@ function BASE:I( Arguments )
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
else
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, BASE:_Serialize(Arguments)) )
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, UTILS.BasicSerialize(Arguments)) )
end
end

View File

@@ -211,10 +211,9 @@ function DATABASE:AddStatic( DCSStaticName )
if not self.STATICS[DCSStaticName] then
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
return self.STATICS[DCSStaticName]
end
return nil
return self.STATICS[DCSStaticName]
end
@@ -224,12 +223,11 @@ function DATABASE:DeleteStatic( DCSStaticName )
self.STATICS[DCSStaticName] = nil
end
--- Finds a STATIC based on the StaticName.
--- Finds a STATIC based on the Static Name.
-- @param #DATABASE self
-- @param #string StaticName
-- @param #string StaticName Name of the static object.
-- @return Wrapper.Static#STATIC The found STATIC.
function DATABASE:FindStatic( StaticName )
local StaticFound = self.STATICS[StaticName]
return StaticFound
end
@@ -241,9 +239,8 @@ end
function DATABASE:AddDynamicCargo( Name )
if not self.DYNAMICCARGO[Name] then
self.DYNAMICCARGO[Name] = DYNAMICCARGO:Register(Name)
return self.DYNAMICCARGO[Name]
end
return nil
return self.DYNAMICCARGO[Name]
end
--- Finds a DYNAMICCARGO based on the Dynamic Cargo Name.
@@ -1582,12 +1579,29 @@ end
-- @param DCS#Airbase airbase Airbase.
-- @return #DATABASE self
function DATABASE:_RegisterAirbase(airbase)
local IsSyria = UTILS.GetDCSMap() == "Syria" and true or false
local countHSyria = 0
if airbase then
-- Get the airbase name.
local DCSAirbaseName = airbase:getName()
-- DCS 2.9.8.1107 added 143 helipads all named H with the same object ID ..
if IsSyria and DCSAirbaseName == "H" and countHSyria > 0 then
--[[
local p = airbase:getPosition().p
local mgrs = COORDINATE:New(p.x,p.z,p.y):ToStringMGRS()
self:I("Airbase on Syria map named H @ "..mgrs)
countHSyria = countHSyria + 1
if countHSyria > 1 then return self end
--]]
return self
elseif IsSyria and DCSAirbaseName == "H" and countHSyria == 0 then
countHSyria = countHSyria + 1
end
-- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
local airbaseID=airbase:getID()

View File

@@ -1329,6 +1329,7 @@ function EVENT:onEvent( Event )
end
Event.IniDCSGroupName = Event.IniUnit and Event.IniUnit.GroupName or ""
Event.IniGroupName=Event.IniDCSGroupName --At least set the group name because group might not exist any more
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
@@ -1371,7 +1372,7 @@ function EVENT:onEvent( Event )
-- Scenery
---
Event.IniDCSUnit = Event.initiator
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
Event.IniDCSUnitName = Event.IniDCSUnit.getName and Event.IniDCSUnit:getName() or "Scenery no name "..math.random(1,20000)
Event.IniUnitName = Event.IniDCSUnitName
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
Event.IniCategory = Event.IniDCSUnit:getDesc().category
@@ -1473,11 +1474,13 @@ function EVENT:onEvent( Event )
-- SCENERY
---
Event.TgtDCSUnit = Event.target
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
Event.TgtDCSUnitName = Event.TgtDCSUnit.getName and Event.TgtDCSUnit.getName() or nil
if Event.TgtDCSUnitName~=nil then
Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
end
end
end

View File

@@ -108,26 +108,30 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
--- On after "MarkAdded" event. Triggered when a Marker is added to the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
-- @param #string Text The text on the marker
-- @param #table Keywords Table of matching keywords found in the Event text
-- @param #string From The From state.
-- @param #string Event The Event called.
-- @param #string To The To state.
-- @param #string Text The text on the marker.
-- @param #table Keywords Table of matching keywords found in the Event text.
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
-- @param #number MarkerID Id of this marker
-- @param #number CoalitionNumber Coalition of the marker creator
-- @param #number MarkerID Id of this marker.
-- @param #number CoalitionNumber Coalition of the marker creator.
-- @param #string PlayerName Name of the player creating/changing the mark. nil if it cannot be obtained.
-- @param Core.Event#EVENTDATA EventData the event data table.
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
-- @param #MARKEROPS_BASE self
-- @param #string From The From state
-- @param #string Event The Event called
-- @param #string To The To state
-- @param #string Text The text on the marker
-- @param #table Keywords Table of matching keywords found in the Event text
-- @param #string From The From state.
-- @param #string Event The Event called.
-- @param #string To The To state.
-- @param #string Text The text on the marker.
-- @param #table Keywords Table of matching keywords found in the Event text.
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
-- @param #number MarkerID Id of this marker
-- @param #number CoalitionNumber Coalition of the marker creator
-- @param #number MarkerID Id of this marker.
-- @param #number CoalitionNumber Coalition of the marker creator.
-- @param #string PlayerName Name of the player creating/changing the mark. nil if it cannot be obtained.
-- @param Core.Event#EVENTDATA EventData the event data table
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
@@ -167,7 +171,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
if Eventtext~=nil then
if self:_MatchTag(Eventtext) then
local matchtable = self:_MatchKeywords(Eventtext)
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition)
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
end
end
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
@@ -177,7 +181,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
if Eventtext~=nil then
if self:_MatchTag(Eventtext) then
local matchtable = self:_MatchKeywords(Eventtext)
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition)
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
end
end
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then

View File

@@ -75,35 +75,37 @@ MESSAGE.Type = {
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{#MESSAGE.ToClient} or @{#MESSAGE.ToCoalition} or @{#MESSAGE.ToAll} to send these Messages to the respective recipients.
-- @param self
-- @param #string MessageText is the text of the Message.
-- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel.
-- @param #string MessageCategory (optional) is a string expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ".
-- @param #string Text is the text of the Message.
-- @param #number Duration Duration in seconds how long the message text is shown.
-- @param #string Category (Optional) String expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ".
-- @param #boolean ClearScreen (optional) Clear all previous messages if true.
-- @return #MESSAGE
-- @return #MESSAGE self
-- @usage
--
-- -- Create a series of new Messages.
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- -- Create a series of new Messages.
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" )
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
--
function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen )
function MESSAGE:New( Text, Duration, Category, ClearScreen )
local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText, MessageDuration, MessageCategory } )
self:F( { Text, Duration, Category } )
self.MessageType = nil
-- When no MessageCategory is given, we don't show it as a title...
if MessageCategory and MessageCategory ~= "" then
if MessageCategory:sub( -1 ) ~= "\n" then
self.MessageCategory = MessageCategory .. ": "
if Category and Category ~= "" then
if Category:sub( -1 ) ~= "\n" then
self.MessageCategory = Category .. ": "
else
self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n"
self.MessageCategory = Category:sub( 1, -2 ) .. ":\n"
end
else
self.MessageCategory = ""
@@ -114,9 +116,9 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen
self.ClearScreen = ClearScreen
end
self.MessageDuration = MessageDuration or 5
self.MessageDuration = Duration or 5
self.MessageTime = timer.getTime()
self.MessageText = MessageText:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
self.MessageText = Text:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
self.MessageSent = false
self.MessageGroup = false

View File

@@ -1709,7 +1709,7 @@ do
--- Iterate the SET_GROUP and return true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE}
-- @param #SET_GROUP self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
-- @return #boolean true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE}, false otherwise
-- @usage
-- local MyZone = ZONE:New("Zone1")
@@ -1756,7 +1756,7 @@ do
--- Iterate the SET_GROUP and return true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE}
-- @param #SET_GROUP self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE}, false otherwise.
-- @usage
-- local MyZone = ZONE:New("Zone1")
@@ -1781,7 +1781,7 @@ do
--- Iterate the SET_GROUP and return true if at least one @{#UNIT} of one @{Wrapper.Group#GROUP} of the @{#SET_GROUP} is in @{Core.Zone}
-- @param #SET_GROUP self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise.
-- @usage
-- local MyZone = ZONE:New("Zone1")
@@ -1807,7 +1807,7 @@ do
--- Iterate the SET_GROUP and return true if at least one @{Wrapper.Group#GROUP} of the @{#SET_GROUP} is partly in @{Core.Zone}.
-- Will return false if a @{Wrapper.Group#GROUP} is fully in the @{Core.Zone}
-- @param #SET_GROUP self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise.
-- @usage
-- local MyZone = ZONE:New("Zone1")
@@ -1842,7 +1842,7 @@ do
-- This could also be achieved with `not SET_GROUP:AnyPartlyInZone(Zone)`, but it's easier for the
-- mission designer to add a dedicated method
-- @param #SET_GROUP self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
-- @return #boolean true if no @{Wrapper.Group#GROUP} is inside the @{Core.Zone#ZONE} in any way, false otherwise.
-- @usage
-- local MyZone = ZONE:New("Zone1")
@@ -1869,7 +1869,7 @@ do
-- That could easily be done with SET_GROUP:ForEachGroupCompletelyInZone(), but this function
-- provides an easy to use shortcut...
-- @param #SET_GROUP self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
-- @return #number the number of GROUPs completely in the Zone
-- @usage
-- local MyZone = ZONE:New("Zone1")
@@ -1891,7 +1891,7 @@ do
--- Iterate the SET_GROUP and count how many UNITs are completely in the Zone
-- @param #SET_GROUP self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
-- @return #number the number of GROUPs completely in the Zone
-- @usage
-- local MyZone = ZONE:New("Zone1")
@@ -2706,7 +2706,7 @@ do -- SET_UNIT
--- Check if no element of the SET_UNIT is in the Zone.
-- @param #SET_UNIT self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
-- @return #boolean
function SET_UNIT:IsNotInZone( Zone )
@@ -3746,7 +3746,7 @@ do -- SET_STATIC
--- Check if no element of the SET_STATIC is in the Zone.
-- @param #SET_STATIC self
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
-- @return #boolean
function SET_STATIC:IsNotInZone( Zone )
@@ -7936,22 +7936,31 @@ do -- SET_OPSGROUP
--- Handles the OnBirth event for the Set.
-- @param #SET_OPSGROUP self
-- @param Core.Event#EVENTDATA Event Event data.
function SET_OPSGROUP:_EventOnBirth( Event )
function SET_OPSGROUP:_EventOnBirth(Event)
--self:F3( { Event } )
if Event.IniDCSUnit and Event.IniDCSGroup then
local DCSgroup=Event.IniDCSGroup --DCS#Group
local DCSgroup = Event.IniDCSGroup --DCS#Group
if DCSgroup:getInitialSize() == DCSgroup:getSize() then -- This seems to be not a good check as even for the first birth event, getSize returns the total number of units in the group.
local groupname, group = self:AddInDatabase( Event )
if group and group:CountAliveUnits()==DCSgroup:getInitialSize() then
if group and self:IsIncludeObject( group ) then
self:Add( groupname, group )
end
-- group:CountAliveUnits() alternative as this fails for Respawn/Teleport
local CountAliveActive = 0
for index, data in pairs(DCSgroup:getUnits()) do
if data:isExist() and data:isActive() then
CountAliveActive = CountAliveActive + 1
end
end
if DCSgroup:getInitialSize() == DCSgroup:getSize() then
local groupname, group = self:AddInDatabase(Event)
-- group:CountAliveUnits() alternative
if group and CountAliveActive == DCSgroup:getInitialSize() then
if group and self:IsIncludeObject(group) then
self:Add(groupname, group)
end
end
end
end
end
end
@@ -8355,14 +8364,17 @@ do -- SET_SCENERY
-- @param #SET_SCENERY self
-- @return Core.Point#COORDINATE The center coordinate of all the objects in the set.
function SET_SCENERY:GetCoordinate()
--[[
local Coordinate = COORDINATE:New({0,0,0})
local Item = self:GetRandomSurely()
if Item then
Coordinate:GetCoordinate()
end
--]]
local Coordinate = self:GetFirst():GetCoordinate()
local x1 = Coordinate.x
local x2 = Coordinate.x

View File

@@ -1226,7 +1226,7 @@ end
-- @param Core.Point#COORDINATE Coordinate The position to spawn from
-- @return #SPAWN self
function SPAWN:InitPositionCoordinate(Coordinate)
self:T2( { self.SpawnTemplatePrefix, Coordinate:GetVec2()} )
--self:T2( { self.SpawnTemplatePrefix, Coordinate:GetVec2()} )
self:InitPositionVec2(Coordinate:GetVec2())
return self
end
@@ -1236,10 +1236,10 @@ end
-- @param DCS#Vec2 Vec2 The position to spawn from
-- @return #SPAWN self
function SPAWN:InitPositionVec2(Vec2)
self:T2( { self.SpawnTemplatePrefix, Vec2} )
--self:T2( { self.SpawnTemplatePrefix, Vec2} )
self.SpawnInitPosition = Vec2
self.SpawnFromNewPosition = true
self:T2("MaxGroups:"..self.SpawnMaxGroups)
--self:T2("MaxGroups:"..self.SpawnMaxGroups)
for SpawnGroupID = 1, self.SpawnMaxGroups do
self:_SetInitialPosition( SpawnGroupID )
end
@@ -1334,7 +1334,7 @@ function SPAWN:InitCleanUp( SpawnCleanUpInterval )
self.SpawnCleanUpTimeStamps = {}
local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup()
self:T2( { "CleanUp Scheduler:", SpawnGroup } )
--self:T2( { "CleanUp Scheduler:", SpawnGroup } )
self.CleanUpScheduler = SCHEDULER:New( self, self._SpawnCleanUpScheduler, {}, 1, SpawnCleanUpInterval, 0.2 )
return self
@@ -1367,7 +1367,7 @@ function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY )
local SpawnYIndex = 0
for SpawnGroupID = 1, self.SpawnMaxGroups do
self:T2( { SpawnX, SpawnY, SpawnXIndex, SpawnYIndex } )
--self:T2( { SpawnX, SpawnY, SpawnXIndex, SpawnYIndex } )
self.SpawnGroups[SpawnGroupID].Visible = true
self.SpawnGroups[SpawnGroupID].Spawned = false
@@ -1391,7 +1391,7 @@ function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY )
self.SpawnGroups[SpawnGroupID].Visible = true
self:HandleEvent( EVENTS.Birth, self._OnBirth )
--self:HandleEvent( EVENTS.Dead, self._OnDeadOrCrash )
self:HandleEvent( EVENTS.Dead, self._OnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._OnDeadOrCrash )
self:HandleEvent( EVENTS.RemoveUnit, self._OnDeadOrCrash )
self:HandleEvent( EVENTS.UnitLost, self._OnDeadOrCrash )
@@ -1591,7 +1591,7 @@ end
-- @param #string SpawnIndex The index of the group to be spawned.
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
--[[
local set = SET_GROUP:New():FilterAlive():FilterPrefixes({self.SpawnTemplatePrefix, self.SpawnAliasPrefix}):FilterOnce()
local aliveunits = 0
set:ForEachGroupAlive(
@@ -1602,12 +1602,12 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
if aliveunits ~= self.AliveUnits then
self.AliveUnits = aliveunits
self:T2("***** self.AliveUnits accounting failure! Corrected! *****")
--self:T2("***** self.AliveUnits accounting failure! Corrected! *****")
end
set= nil
self:T2( { SpawnTemplatePrefix = self.SpawnTemplatePrefix, SpawnIndex = SpawnIndex, AliveUnits = self.AliveUnits, SpawnMaxGroups = self.SpawnMaxGroups } )
--]]
--self:T2( { SpawnTemplatePrefix = self.SpawnTemplatePrefix, SpawnIndex = SpawnIndex, AliveUnits = self.AliveUnits, SpawnMaxGroups = self.SpawnMaxGroups } )
if self:_GetSpawnIndex( SpawnIndex ) then
@@ -1622,12 +1622,12 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate
local SpawnZone = self.SpawnGroups[self.SpawnIndex].SpawnZone
self:T2( SpawnTemplate.name )
--self:T2( SpawnTemplate.name )
if SpawnTemplate then
local PointVec3 = POINT_VEC3:New( SpawnTemplate.route.points[1].x, SpawnTemplate.route.points[1].alt, SpawnTemplate.route.points[1].y )
self:T2( { "Current point of ", self.SpawnTemplatePrefix, PointVec3 } )
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, PointVec3 } )
-- If RandomizePosition, then Randomize the formation in the zone band, keeping the template.
if self.SpawnRandomizePosition then
@@ -1639,7 +1639,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
for UnitID = 1, #SpawnTemplate.units do
SpawnTemplate.units[UnitID].x = SpawnTemplate.units[UnitID].x + (RandomVec2.x - CurrentX)
SpawnTemplate.units[UnitID].y = SpawnTemplate.units[UnitID].y + (RandomVec2.y - CurrentY)
self:T2( 'SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
--self:T2( 'SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
end
end
@@ -1660,13 +1660,13 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
end
end
if (not inZone) then
self:T2("Could not place unit within zone and within radius!")
--self:T2("Could not place unit within zone and within radius!")
RandomVec2 = SpawnZone:GetRandomVec2()
end
end
SpawnTemplate.units[UnitID].x = RandomVec2.x
SpawnTemplate.units[UnitID].y = RandomVec2.y
self:T2( 'SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
--self:T2( 'SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
end
end
@@ -1887,6 +1887,7 @@ end
--- Spawns new groups at varying time intervals.
-- This is useful if you want to have continuity within your missions of certain (AI) groups to be present (alive) within your missions.
-- **WARNING** - Setting a very low SpawnTime heavily impacts your mission performance and CPU time, it is NOT useful to check the alive state of an object every split second! Be reasonable and stay at 15 seconds and above!
-- @param #SPAWN self
-- @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.
@@ -1909,6 +1910,14 @@ function SPAWN:SpawnScheduled( SpawnTime, SpawnTimeVariation, WithDelay )
local SpawnTime = SpawnTime or 60
local SpawnTimeVariation = SpawnTimeVariation or 0.5
-- Noob catch
if SpawnTime < 15 then
self:E("****SPAWN SCHEDULED****\nWARNING - Setting a very low SpawnTime heavily impacts your mission performance and CPU time, it is NOT useful to check the alive state of an object every "..tostring(SpawnTime).." seconds.\nSetting to 15 second intervals.\n*****")
SpawnTime = 15
end
if SpawnTimeVariation > 1 or SpawnTimeVariation < 0 then SpawnTimeVariation = 0.5 end
if SpawnTime ~= nil and SpawnTimeVariation ~= nil then
local InitialDelay = 0
if WithDelay or self.DelayOnOff == true then
@@ -2024,7 +2033,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Get position of airbase.
local PointVec3 = SpawnAirbase:GetCoordinate()
self:T2( PointVec3 )
--self:T2( PointVec3 )
-- Set take off type. Default is hot.
Takeoff = Takeoff or SPAWN.Takeoff.Hot
@@ -2053,7 +2062,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
--self:F( { GroupAlive = GroupAlive } )
-- Debug output
self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
-- Template group, unit and its attributes.
local TemplateGroup = GROUP:FindByName( self.SpawnTemplatePrefix )
@@ -2102,7 +2111,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Check if we spawn on ground.
local spawnonground = not (Takeoff == SPAWN.Takeoff.Air)
self:T2( { spawnonground = spawnonground, TOtype = Takeoff, TOair = Takeoff == SPAWN.Takeoff.Air } )
--self:T2( { spawnonground = spawnonground, TOtype = Takeoff, TOair = Takeoff == SPAWN.Takeoff.Air } )
-- Check where we actually spawn if we spawn on ground.
local spawnonship = false
@@ -2156,7 +2165,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Number of free parking spots at the airbase.
if spawnonship or spawnonfarp or spawnonrunway then
-- These places work procedural and have some kind of build in queue ==> Less effort.
self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
--self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
--[[
@@ -2169,18 +2178,18 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
if ishelo then
if termtype == nil then
-- Helo is spawned. Try exclusive helo spots first.
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
if nfree < nunits then
-- Not enough helo ports. Let's try also other terminal types.
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
end
else
-- No terminal type specified. We try all spots except shelters.
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
end
@@ -2189,23 +2198,23 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
if termtype == nil then
if isbomber or istransport or istanker or isawacs then
-- First we fill the potentially bigger spots.
self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig ) )
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
if nfree < nunits then
-- Now we try the smaller ones.
self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig ) )
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
end
else
self:T2( string.format( "Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft ) )
--self:T2( string.format( "Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
end
else
-- Terminal type explicitly given.
self:T2( string.format( "Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring( termtype ) ) )
--self:T2( string.format( "Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring( termtype ) ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
end
@@ -2215,12 +2224,12 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Debug: Get parking data.
--[[
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
--self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
for _,_spot in pairs(parkingdata) do
self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
--self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
end
self:T2(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
--self:T2(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
]]
-- Set this to true if not enough spots are available for emergency air start.
@@ -2315,7 +2324,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
SpawnTemplate.parked = true
for UnitID = 1, nunits do
self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
--self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
-- Template of the current unit.
local UnitTemplate = SpawnTemplate.units[UnitID]
@@ -2333,7 +2342,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Ships and FARPS seem to have a build in queue.
if spawnonship or spawnonfarp or spawnonrunway then
self:T2( string.format( "Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
--self:T2( string.format( "Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
-- Spawn on ship. We take only the position of the ship.
SpawnTemplate.units[UnitID].x = PointVec3.x -- TX
@@ -2342,7 +2351,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
else
self:T2( string.format( "Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID] ) )
--self:T2( string.format( "Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID] ) )
-- Get coordinates of parking spot.
SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x
@@ -2354,7 +2363,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
else
self:T2( string.format( "Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
--self:T2( string.format( "Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
-- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
SpawnTemplate.units[UnitID].x = TX
@@ -2371,9 +2380,9 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
end
-- Debug output.
self:T2( string.format( "Group %s unit number %d: Parking = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking ) ) )
self:T2( string.format( "Group %s unit number %d: Parking ID = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking_id ) ) )
self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
--self:T2( string.format( "Group %s unit number %d: Parking = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking ) ) )
--self:T2( string.format( "Group %s unit number %d: Parking ID = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking_id ) ) )
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
end
end
@@ -2451,10 +2460,10 @@ function SPAWN:SpawnAtParkingSpot( Airbase, Spots, Takeoff )
-- Get parking spot data.
local spot = Airbase:GetParkingSpotData( TerminalID )
self:T2( { spot = spot } )
--self:T2( { spot = spot } )
if spot and spot.Free then
self:T2( string.format( "Adding parking spot ID=%d TermType=%d", spot.TerminalID, spot.TerminalType ) )
--self:T2( string.format( "Adding parking spot ID=%d TermType=%d", spot.TerminalID, spot.TerminalType ) )
table.insert( Parkingdata, spot )
end
@@ -2486,7 +2495,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
-- Get position of airbase.
local PointVec3 = SpawnAirbase:GetCoordinate()
self:T2( PointVec3 )
--self:T2( PointVec3 )
-- Set take off type. Default is hot.
local Takeoff = SPAWN.Takeoff.Cold
@@ -2502,7 +2511,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
local GroupAlive = self:GetGroupFromIndex( SpawnIndex )
-- Debug output
self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
-- Template group, unit and its attributes.
local TemplateGroup = GROUP:FindByName( self.SpawnTemplatePrefix )
@@ -2546,7 +2555,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
-- Check if we spawn on ground.
local spawnonground = not (Takeoff == SPAWN.Takeoff.Air)
self:T2( { spawnonground = spawnonground, TOtype = Takeoff, TOair = Takeoff == SPAWN.Takeoff.Air } )
--self:T2( { spawnonground = spawnonground, TOtype = Takeoff, TOair = Takeoff == SPAWN.Takeoff.Air } )
-- Check where we actually spawn if we spawn on ground.
local spawnonship = false
@@ -2588,7 +2597,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
-- Number of free parking spots at the airbase.
if spawnonship or spawnonfarp or spawnonrunway then
-- These places work procedural and have some kind of build in queue ==> Less effort.
self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
--self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
--[[
@@ -2601,18 +2610,18 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
if ishelo then
if termtype == nil then
-- Helo is spawned. Try exclusive helo spots first.
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
if nfree < nunits then
-- Not enough helo ports. Let's try also other terminal types.
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
end
else
-- No terminal type specified. We try all spots except shelters.
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
end
@@ -2624,23 +2633,23 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
-- TODO: Some attributes are "Helicopters", "Bombers", "Transports", "Battleplanes". Need to check it out.
if isbomber or istransport then
-- First we fill the potentially bigger spots.
self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig ) )
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
if nfree < nunits then
-- Now we try the smaller ones.
self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig ) )
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
end
else
self:T2( string.format( "Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft ) )
--self:T2( string.format( "Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
end
else
-- Terminal type explicitly given.
self:T2( string.format( "Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring( termtype ) ) )
--self:T2( string.format( "Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring( termtype ) ) )
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots
end
@@ -2650,12 +2659,12 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
-- Debug: Get parking data.
--[[
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
--self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
for _,_spot in pairs(parkingdata) do
self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
--self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
end
self:T2(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
--self:T2(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
]]
-- Set this to true if not enough spots are available for emergency air start.
@@ -2733,7 +2742,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
-- Ships and FARPS seem to have a build in queue.
if spawnonship or spawnonfarp or spawnonrunway then
self:T2( string.format( "Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
--self:T2( string.format( "Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
-- Spawn on ship. We take only the position of the ship.
SpawnTemplate.units[UnitID].x = PointVec3.x -- TX
@@ -2742,7 +2751,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
else
self:T2( string.format( "Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID] ) )
--self:T2( string.format( "Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID] ) )
-- Get coordinates of parking spot.
SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x
@@ -2754,7 +2763,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
else
self:T2( string.format( "Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
--self:T2( string.format( "Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
-- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
SpawnTemplate.units[UnitID].x = TX
@@ -2771,9 +2780,9 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
end
-- Debug output.
self:T2( string.format( "Group %s unit number %d: Parking = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking ) ) )
self:T2( string.format( "Group %s unit number %d: Parking ID = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking_id ) ) )
self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
--self:T2( string.format( "Group %s unit number %d: Parking = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking ) ) )
--self:T2( string.format( "Group %s unit number %d: Parking ID = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking_id ) ) )
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
end
end
@@ -2871,7 +2880,7 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
--self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } )
local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 )
self:T2( PointVec3 )
--self:T2( PointVec3 )
if SpawnIndex then
else
@@ -2884,7 +2893,7 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
if SpawnTemplate then
self:T2( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } )
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } )
local TemplateHeight = SpawnTemplate.route and SpawnTemplate.route.points[1].alt or nil
@@ -2909,7 +2918,7 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
if SpawnTemplate.CategoryID ~= Group.Category.SHIP then
SpawnTemplate.units[UnitID].alt = Vec3.y or TemplateHeight
end
self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
end
SpawnTemplate.route.points[1].x = Vec3.x
SpawnTemplate.route.points[1].y = Vec3.z
@@ -3168,10 +3177,10 @@ function SPAWN:SpawnGroupName( SpawnIndex )
if SpawnIndex then
local SpawnName = string.format( '%s#%03d', SpawnPrefix, SpawnIndex )
self:T2( SpawnName )
--self:T2( SpawnName )
return SpawnName
else
self:T2( SpawnPrefix )
--self:T2( SpawnPrefix )
return SpawnPrefix
end
@@ -3499,7 +3508,7 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
if SpawnInitKeepUnitIFF == false then
UnitPrefix, Rest = string.match( SpawnTemplate.units[UnitID].name, "^([^#]+)#?" ):gsub( "^%s*(.-)%s*$", "%1" )
SpawnTemplate.units[UnitID].name = string.format( '%s#%03d-%02d', UnitPrefix, SpawnIndex, UnitID )
self:T2( { UnitPrefix, Rest } )
--self:T2( { UnitPrefix, Rest } )
--else
--UnitPrefix=SpawnTemplate.units[UnitID].name
end
@@ -3713,7 +3722,7 @@ function SPAWN:_RandomizeRoute( SpawnIndex )
SpawnTemplate.route.points[t].alt = nil
end
self:T2( 'SpawnTemplate.route.points[' .. t .. '].x = ' .. SpawnTemplate.route.points[t].x .. ', SpawnTemplate.route.points[' .. t .. '].y = ' .. SpawnTemplate.route.points[t].y )
--self:T2( 'SpawnTemplate.route.points[' .. t .. '].x = ' .. SpawnTemplate.route.points[t].x .. ', SpawnTemplate.route.points[' .. t .. '].y = ' .. SpawnTemplate.route.points[t].y )
end
end
@@ -3756,15 +3765,15 @@ end
-- @param #number SpawnIndex
-- @return #SPAWN self
function SPAWN:_SetInitialPosition( SpawnIndex )
self:T2( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } )
--self:T2( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } )
if self.SpawnFromNewPosition then
self:T2( "Preparing Spawn at Vec2 ", self.SpawnInitPosition )
--self:T2( "Preparing Spawn at Vec2 ", self.SpawnInitPosition )
local SpawnVec2 = self.SpawnInitPosition
self:T2( { SpawnVec2 = SpawnVec2 } )
--self:T2( { SpawnVec2 = SpawnVec2 } )
local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate
@@ -3774,11 +3783,11 @@ function SPAWN:_SetInitialPosition( SpawnIndex )
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:T2( { Route = SpawnTemplate.route } )
--self:T2( { Route = SpawnTemplate.route } )
for UnitID = 1, #SpawnTemplate.units do
local UnitTemplate = SpawnTemplate.units[UnitID]
self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
--self:T2( '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
@@ -3789,7 +3798,7 @@ function SPAWN:_SetInitialPosition( SpawnIndex )
UnitTemplate.y = TY
-- TODO: Manage altitude based on landheight...
-- SpawnTemplate.units[UnitID].alt = SpawnVec2:
self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
end
SpawnTemplate.route.points[1].x = SpawnVec2.x
@@ -3812,26 +3821,26 @@ function SPAWN:_RandomizeZones( SpawnIndex )
if self.SpawnRandomizeZones then
local SpawnZone = nil -- Core.Zone#ZONE_BASE
while not SpawnZone do
self:T2( { SpawnZoneTableCount = #self.SpawnZoneTable, self.SpawnZoneTable } )
--self:T2( { SpawnZoneTableCount = #self.SpawnZoneTable, self.SpawnZoneTable } )
local ZoneID = math.random( #self.SpawnZoneTable )
self:T2( ZoneID )
--self:T2( ZoneID )
SpawnZone = self.SpawnZoneTable[ZoneID]:GetZoneMaybe()
end
self:T2( "Preparing Spawn in Zone", SpawnZone:GetName() )
--self:T2( "Preparing Spawn in Zone", SpawnZone:GetName() )
local SpawnVec2 = SpawnZone:GetRandomVec2()
self:T2( { SpawnVec2 = SpawnVec2 } )
--self:T2( { SpawnVec2 = SpawnVec2 } )
local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate
self.SpawnGroups[SpawnIndex].SpawnZone = SpawnZone
self:T2( { Route = SpawnTemplate.route } )
--self:T2( { Route = SpawnTemplate.route } )
for UnitID = 1, #SpawnTemplate.units do
local UnitTemplate = SpawnTemplate.units[UnitID]
self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
--self:T2( '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
@@ -3842,7 +3851,7 @@ function SPAWN:_RandomizeZones( SpawnIndex )
UnitTemplate.y = TY
-- TODO: Manage altitude based on landheight...
-- SpawnTemplate.units[UnitID].alt = SpawnVec2:
self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
end
SpawnTemplate.x = SpawnVec2.x
SpawnTemplate.y = SpawnVec2.y
@@ -3897,11 +3906,11 @@ end
-- @param #number SpawnIndex Spawn index.
-- @return #number self.SpawnIndex
function SPAWN:_GetSpawnIndex( SpawnIndex )
self:T2( { template=self.SpawnTemplatePrefix, SpawnIndex=SpawnIndex, SpawnMaxGroups=self.SpawnMaxGroups, SpawnMaxUnitsAlive=self.SpawnMaxUnitsAlive, AliveUnits=self.AliveUnits, TemplateUnits=#self.SpawnTemplate.units } )
--self:T2( { template=self.SpawnTemplatePrefix, SpawnIndex=SpawnIndex, SpawnMaxGroups=self.SpawnMaxGroups, SpawnMaxUnitsAlive=self.SpawnMaxUnitsAlive, AliveUnits=self.AliveUnits, TemplateUnits=#self.SpawnTemplate.units } )
if (self.SpawnMaxGroups == 0) or (SpawnIndex <= self.SpawnMaxGroups) then
if (self.SpawnMaxUnitsAlive == 0) or (self.AliveUnits + #self.SpawnTemplate.units <= self.SpawnMaxUnitsAlive) or self.UnControlled == true then
self:T2( { SpawnCount = self.SpawnCount, SpawnIndex = SpawnIndex } )
--self:T2( { SpawnCount = self.SpawnCount, SpawnIndex = SpawnIndex } )
if SpawnIndex and SpawnIndex >= self.SpawnCount + 1 then
self.SpawnCount = self.SpawnCount + 1
SpawnIndex = self.SpawnCount
@@ -3932,22 +3941,57 @@ function SPAWN:_OnBirth( EventData )
if SpawnGroup then
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
self:T2( { "Birth Event:", EventPrefix, self.SpawnTemplatePrefix } )
--self:T2( { "Birth Event:", EventPrefix, self.SpawnTemplatePrefix } )
if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
self.AliveUnits = self.AliveUnits + 1
self:T2( "Alive Units: " .. self.AliveUnits )
--self:T2( "Alive Units: " .. self.AliveUnits )
end
end
end
end
---
-- @param #SPAWN self
-- @return #number count
function SPAWN:_CountAliveUnits()
local count = 0
--self:I("self.SpawnAliasPrefix="..tostring(self.SpawnAliasPrefix).." | self.SpawnTemplatePrefix="..tostring(self.SpawnTemplatePrefix))
if self.SpawnAliasPrefix then
if not self.SpawnAliasPrefixEscaped then self.SpawnAliasPrefixEscaped = string.gsub(self.SpawnAliasPrefix,"[%p%s]",".") end
--self:I("self.SpawnAliasPrefixEscaped="..tostring(self.SpawnAliasPrefixEscaped))
local SpawnAliasPrefix = self.SpawnAliasPrefixEscaped
local agroups = GROUP:FindAllByMatching(SpawnAliasPrefix)
for _,_grp in pairs(agroups) do
--self:I("Group Name = " .. _grp:GetName())
local game = self:_GetPrefixFromGroupName(_grp.GroupName)
--self:I("Game = "..game)
--self:I("Count = ".._grp:CountAliveUnits())
if game and game == self.SpawnAliasPrefix then
count = count + _grp:CountAliveUnits()
end
end
else
if not self.SpawnTemplatePrefixEscaped then self.SpawnTemplatePrefixEscaped = string.gsub(self.SpawnTemplatePrefix,"[%p%s]",".") end
local SpawnTemplatePrefix = self.SpawnTemplatePrefixEscaped
local groups = GROUP:FindAllByMatching(SpawnTemplatePrefix)
for _,_grp in pairs(groups) do
local game = self:_GetPrefixFromGroupName(_grp.GroupName)
if game and game == self.SpawnTemplatePrefix then
count = count + _grp:CountAliveUnits()
end
end
end
self.AliveUnits = count
return self
end
---
-- @param #SPAWN self
-- @param Core.Event#EVENTDATA EventData
function SPAWN:_OnDeadOrCrash( EventData )
self:T2( "Dead or crash event ID "..tostring(EventData.id or 0))
self:T2( "Dead or crash event for "..tostring(EventData.IniUnitName or "none") )
--self:I( "Dead or crash event ID "..tostring(EventData.id or 0))
--self:I( "Dead or crash event for "..tostring(EventData.IniUnitName or "none") )
--if EventData.id == EVENTS.Dead then return end
@@ -3959,12 +4003,14 @@ function SPAWN:_OnDeadOrCrash( EventData )
local EventPrefix = self:_GetPrefixFromGroupName(unit.GroupName)
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
self:T2( { "Dead event: " .. EventPrefix } )
self:T2(string.format("EventPrefix = %s | SpawnAliasPrefix = %s | Old AliveUnits = %d",EventPrefix or "",self.SpawnAliasPrefix or "",self.AliveUnits or 0))
--self:I(string.format("EventPrefix = %s | SpawnAliasPrefix = %s | Old AliveUnits = %d",EventPrefix or "",self.SpawnAliasPrefix or "",self.AliveUnits or 0))
if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) and self.AliveUnits > 0 then
self.AliveUnits = self.AliveUnits - 1
--self:I( { "Dead event: " .. EventPrefix } )
--self.AliveUnits = self.AliveUnits - 1
self:ScheduleOnce(1,self._CountAliveUnits,self)
--self.AliveUnits = self:_CountAliveUnits()
--self:I( "New Alive Units: " .. self.AliveUnits )
end
self:T2( "New Alive Units: " .. self.AliveUnits )
end
end
end
@@ -3980,9 +4026,9 @@ function SPAWN:_OnTakeOff( EventData )
if SpawnGroup then
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
self:T2( { "TakeOff event: " .. EventPrefix } )
--self:T2( { "TakeOff event: " .. EventPrefix } )
if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
self:T2( "self.Landed = false" )
--self:T2( "self.Landed = false" )
SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", false )
end
end
@@ -4000,13 +4046,13 @@ function SPAWN:_OnLand( EventData )
if SpawnGroup then
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
self:T2( { "Land event: " .. EventPrefix } )
--self:T2( { "Land event: " .. EventPrefix } )
if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
-- TODO: Check if this is the last unit of the group that lands.
SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", true )
if self.RepeatOnLanding then
local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup )
self:T2( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } )
--self:T2( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } )
-- self:ReSpawn( SpawnGroupIndex )
-- Delay respawn by three seconds due to DCS 2.5.4.26368 OB bug https://github.com/FlightControl-Master/MOOSE/issues/1076
-- Bug was initially only for engine shutdown event but after ED "fixed" it, it now happens on landing events.
@@ -4029,13 +4075,13 @@ function SPAWN:_OnEngineShutDown( EventData )
if SpawnGroup then
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
self:T2( { "EngineShutdown event: " .. EventPrefix } )
--self:T2( { "EngineShutdown event: " .. EventPrefix } )
if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
-- todo: test if on the runway
local Landed = SpawnGroup:GetState( SpawnGroup, "Spawn_Landed" )
if Landed and self.RepeatOnEngineShutDown then
local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup )
self:T2( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } )
--self:T2( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } )
-- self:ReSpawn( SpawnGroupIndex )
-- Delay respawn by three seconds due to DCS 2.5.4 OB bug https://github.com/FlightControl-Master/MOOSE/issues/1076
SCHEDULER:New( nil, self.ReSpawn, { self, SpawnGroupIndex }, 3 )
@@ -4064,7 +4110,7 @@ function SPAWN:_SpawnCleanUpScheduler()
--self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } )
local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup()
self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
--self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
local IsHelo = false
@@ -4081,7 +4127,7 @@ function SPAWN:_SpawnCleanUpScheduler()
self.SpawnCleanUpTimeStamps[SpawnUnitName] = self.SpawnCleanUpTimeStamps[SpawnUnitName] or {}
local Stamp = self.SpawnCleanUpTimeStamps[SpawnUnitName]
self:T2( { SpawnUnitName, Stamp } )
--self:T2( { SpawnUnitName, Stamp } )
if Stamp.Vec2 then
if (SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1) or IsHelo then
@@ -4089,7 +4135,7 @@ function SPAWN:_SpawnCleanUpScheduler()
if (Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y) or (SpawnUnit:GetLife() <= 1) then
-- If the plane is not moving or dead , and is on the ground, assign it with a timestamp...
if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then
self:T2( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } )
--self:T2( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } )
--self:ReSpawn( SpawnCursor )
SCHEDULER:New( nil, self.ReSpawn, { self, SpawnCursor }, 3 )
Stamp.Vec2 = nil
@@ -4118,7 +4164,7 @@ function SPAWN:_SpawnCleanUpScheduler()
SpawnGroup, SpawnCursor = self:GetNextAliveGroup( SpawnCursor )
self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
--self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
end

View File

@@ -535,12 +535,6 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
-- Name of the spawned static.
Template.name = self.InitStaticName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex)
-- Add and register the new static.
local mystatic=_DATABASE:AddStatic(Template.name)
-- Debug output.
self:T(Template)
-- Add static to the game.
local Static=nil --DCS#StaticObject
@@ -577,12 +571,28 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
self:T("Spawning Static")
self:T2({Template=Template})
Static=coalition.addStaticObject(CountryID, Template)
if Static then
self:T(string.format("Succesfully spawned static object \"%s\" ID=%d", Static:getName(), Static:getID()))
--[[
local static=StaticObject.getByName(Static:getName())
if static then
env.info(string.format("FF got static from StaticObject.getByName"))
else
env.error(string.format("FF error did NOT get static from StaticObject.getByName"))
end ]]
else
self:E(string.format("ERROR: DCS static object \"%s\" is nil!", tostring(Template.name)))
end
end
-- Add and register the new static.
local mystatic=_DATABASE:AddStatic(Template.name)
-- If there is a SpawnFunction hook defined, call it.
if self.SpawnFunctionHook then
-- delay calling this for .3 seconds so that it hopefully comes after the BIRTH event of the group.
self:ScheduleOnce(0.3,self.SpawnFunctionHook,mystatic, unpack(self.SpawnFunctionArguments))
self:ScheduleOnce(0.3, self.SpawnFunctionHook, mystatic, unpack(self.SpawnFunctionArguments))
end
return mystatic

View File

@@ -14,6 +14,7 @@ do -- world
-- @field #world.event event [https://wiki.hoggitworld.com/view/DCS_enum_world](https://wiki.hoggitworld.com/view/DCS_enum_world)
-- @field #world.BirthPlace BirthPlace The birthplace enumerator is used to define where an aircraft or helicopter has spawned in association with birth events.
-- @field #world.VolumeType VolumeType The volumeType enumerator defines the types of 3d geometery used within the [world.searchObjects](https://wiki.hoggitworld.com/view/DCS_func_searchObjects) function.
-- @field #world.weather weather Weather functions for fog etc.
--- The world singleton contains functions centered around two different but extremely useful functions.
-- * Events and event handlers are all governed within world.
@@ -132,6 +133,36 @@ do -- world
-- @function [parent=#world] getAirbases
-- @param #number coalitionId The coalition side number ID. Default is all airbases are returned.
-- @return #table Table of DCS airbase objects.
--- Weather functions.
-- @type world.weather
--- Fog animation data structure.
-- @type world.FogAnimation
-- @field #number time
-- @field #number visibility
-- @field #number thickness
--- Returns the current fog thickness.
-- @function [parent=#world.weather] getFogThickness Returns the fog thickness.
-- @return #number Fog thickness in meters. If there is no fog, zero is returned.
--- Sets the fog thickness instantly. Any current fog animation is discarded.
-- @function [parent=#world.weather] setFogThickness
-- @param #number thickness Fog thickness in meters. Set to zero to disable fog.
--- Returns the current fog visibility distance.
-- @function [parent=#world.weather] getFogVisibilityDistance Returns the current maximum visibility distance in meters. Returns zero if fog is not present.
--- Instantly sets the maximum visibility distance of fog at sea level when looking at the horizon. Any current fog animation is discarded. Set zero to disable the fog.
-- @function [parent=#world.weather] setFogVisibilityDistance
-- @param #number visibility Max fog visibility in meters. Set to zero to disable fog.
--- Sets fog animation keys. Time is set in seconds and relative to the current simulation time, where time=0 is the current moment.
-- Time must be increasing. Previous animation is always discarded despite the data being correct.
-- @function [parent=#world.weather] setFogAnimation
-- @param #world.FogAnimation animation List of fog animations
end -- world
@@ -407,7 +438,7 @@ do -- coalition
-- @param #table groupData Group data table.
-- @return DCS#Group The spawned Group object.
--- Dynamically spawns a static object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addGroup)
--- Dynamically spawns a static object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addStaticObject)
-- @function [parent=#coalition] addStaticObject
-- @param #number countryId Id of the country.
-- @param #table groupData Group data table.
@@ -420,6 +451,7 @@ end -- coalition
do -- Types
--- Descriptors.
-- @type Desc
-- @field #number speedMax0 Max speed in meters/second at zero altitude.
-- @field #number massEmpty Empty mass in kg.
@@ -1013,14 +1045,16 @@ do -- Spot
end -- Spot
do -- Controller
--- Controller is an object that performs A.I.-tasks. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C.
--
-- This class has 2 types of functions:
--
-- * Tasks
-- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics.
-- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics.
--
-- @type Controller
-- @field #Controller.Detection Detection Enum contains identifiers of surface types.
-- @field #Controller.Detection Detection Enum contains identifiers of surface types.
--- Enables and disables the controller.
-- Note: Now it works only for ground / naval groups!
@@ -1079,18 +1113,18 @@ do -- Controller
-- Detection
--- Enum contains identifiers of surface types.
--- Enum containing detection types.
-- @type Controller.Detection
-- @field VISUAL
-- @field OPTIC
-- @field RADAR
-- @field IRST
-- @field RWR
-- @field DLINK
-- @field #number VISUAL Visual detection. Numeric value 1.
-- @field #number OPTIC Optical detection. Numeric value 2.
-- @field #number RADAR Radar detection. Numeric value 4.
-- @field #number IRST Infra-red search and track detection. Numeric value 8.
-- @field #number RWR Radar Warning Receiver detection. Numeric value 16.
-- @field #number DLINK Data link detection. Numeric value 32.
--- Detected target.
-- @type DetectedTarget
-- @field Wrapper.Object#Object object The target
-- @type Controller.DetectedTarget
-- @field DCS#Object object The target
-- @field #boolean visible The target is visible
-- @field #boolean type The target type is known
-- @field #boolean distance Distance to the target is known
@@ -1103,9 +1137,9 @@ do -- Controller
-- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
-- @return #boolean detected True if the target is detected.
-- @return #boolean visible Has effect only if detected is true. True if the target is visible now.
-- @return #boolean type Has effect only if detected is true. True if the target type is known.
-- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known.
-- @return #ModelTime lastTime Has effect only if visible is false. Last time when target was seen.
-- @return #boolean type Has effect only if detected is true. True if the target type is known.
-- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known.
-- @return #Vec3 lastPos Has effect only if visible is false. Last position of the target when it was seen.
-- @return #Vec3 lastVel Has effect only if visible is false. Last velocity of the target when it was seen.
@@ -1131,6 +1165,7 @@ end -- Controller
do -- Unit
--- Unit.
-- @type Unit
-- @extends #CoalitionObject
-- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically.

View File

@@ -18,7 +18,7 @@
-- ### Author: FlightControl - Framework Design & Programming
-- ### Refactoring to use the Runway auto-detection: Applevangelist
-- @date August 2022
-- Last Update Nov 2023
-- Last Update Oct 2024
--
-- ===
--
@@ -721,14 +721,18 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
if NotInRunwayZone then
local Taxi = Client:GetState( self, "Taxi" )
if IsOnGround then
local Taxi = Client:GetState( self, "Taxi" )
self:T( Taxi )
if Taxi == false then
local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed )
Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " ..
Velocity:ToString() , 20, "ATC" )
Client:SetState( self, "Taxi", true )
Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0 )
end
-- TODO: GetVelocityKMH function usage
@@ -737,7 +741,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
local IsAboveRunway = Client:IsAboveRunway()
self:T( {IsAboveRunway, IsOnGround, Velocity:Get() })
if IsOnGround then
if IsOnGround and not Taxi then
local Speeding = false
if AirbaseMeta.MaximumKickSpeed then
if Velocity:Get() > AirbaseMeta.MaximumKickSpeed then
@@ -749,15 +753,17 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
end
end
if Speeding == true then
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
" has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
Client:Destroy()
Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0 )
--MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
-- " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
--Client:Destroy()
Client:SetState( self, "Speeding", true )
local SpeedingWarnings = Client:GetState( self, "Warnings" )
Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
Client:Message( "Warning " .. SpeedingWarnings .. "/3! Airbase traffic rule violation! Slow down now! Your speed is " ..
Velocity:ToString(), 5, "ATC" )
end
end
if IsOnGround then
local Speeding = false
@@ -1035,23 +1041,23 @@ end
-- The following airbases are monitored at the Nevada region.
-- Use the @{Wrapper.Airbase#AIRBASE.Nevada} enumeration to select the airbases to be monitored.
--
-- * `AIRBASE.Nevada.Beatty_Airport`
-- * `AIRBASE.Nevada.Boulder_City_Airport`
-- * `AIRBASE.Nevada.Creech_AFB`
-- * `AIRBASE.Nevada.Beatty`
-- * `AIRBASE.Nevada.Boulder_City`
-- * `AIRBASE.Nevada.Creech`
-- * `AIRBASE.Nevada.Echo_Bay`
-- * `AIRBASE.Nevada.Groom_Lake_AFB`
-- * `AIRBASE.Nevada.Henderson_Executive_Airport`
-- * `AIRBASE.Nevada.Jean_Airport`
-- * `AIRBASE.Nevada.Laughlin_Airport`
-- * `AIRBASE.Nevada.Groom_Lake`
-- * `AIRBASE.Nevada.Henderson_Executive`
-- * `AIRBASE.Nevada.Jean`
-- * `AIRBASE.Nevada.Laughlin`
-- * `AIRBASE.Nevada.Lincoln_County`
-- * `AIRBASE.Nevada.McCarran_International_Airport`
-- * `AIRBASE.Nevada.McCarran_International`
-- * `AIRBASE.Nevada.Mesquite`
-- * `AIRBASE.Nevada.Mina_Airport`
-- * `AIRBASE.Nevada.Nellis_AFB`
-- * `AIRBASE.Nevada.Mina`
-- * `AIRBASE.Nevada.Nellis`
-- * `AIRBASE.Nevada.North_Las_Vegas`
-- * `AIRBASE.Nevada.Pahute_Mesa_Airstrip`
-- * `AIRBASE.Nevada.Tonopah_Airport`
-- * `AIRBASE.Nevada.Tonopah_Test_Range_Airfield`
-- * `AIRBASE.Nevada.Pahute_Mesa`
-- * `AIRBASE.Nevada.Tonopah`
-- * `AIRBASE.Nevada.Tonopah_Test_Range`
--
-- # Installation
--
@@ -1088,10 +1094,10 @@ end
--
-- -- Monitor specific airbases.
-- ATC_Ground = ATC_GROUND_NEVADA:New(
-- { AIRBASE.Nevada.Laughlin_Airport,
-- { AIRBASE.Nevada.Laughlin,
-- AIRBASE.Nevada.Lincoln_County,
-- AIRBASE.Nevada.North_Las_Vegas,
-- AIRBASE.Nevada.McCarran_International_Airport
-- AIRBASE.Nevada.McCarran_International
-- }
-- )
--
@@ -1330,33 +1336,33 @@ end
-- The following airbases are monitored at the PersianGulf region.
-- Use the @{Wrapper.Airbase#AIRBASE.PersianGulf} enumeration to select the airbases to be monitored.
--
-- * `AIRBASE.PersianGulf.Abu_Musa_Island_Airport`
-- * `AIRBASE.PersianGulf.Al_Dhafra_AB`
-- * `AIRBASE.PersianGulf.Abu_Musa_Island`
-- * `AIRBASE.PersianGulf.Al_Dhafra_AFB`
-- * `AIRBASE.PersianGulf.Al_Maktoum_Intl`
-- * `AIRBASE.PersianGulf.Al_Minhad_AB`
-- * `AIRBASE.PersianGulf.Al_Minhad_AFB`
-- * `AIRBASE.PersianGulf.Bandar_Abbas_Intl`
-- * `AIRBASE.PersianGulf.Bandar_Lengeh`
-- * `AIRBASE.PersianGulf.Dubai_Intl`
-- * `AIRBASE.PersianGulf.Fujairah_Intl`
-- * `AIRBASE.PersianGulf.Havadarya`
-- * `AIRBASE.PersianGulf.Kerman_Airport`
-- * `AIRBASE.PersianGulf.Kerman`
-- * `AIRBASE.PersianGulf.Khasab`
-- * `AIRBASE.PersianGulf.Lar_Airbase`
-- * `AIRBASE.PersianGulf.Lar`
-- * `AIRBASE.PersianGulf.Qeshm_Island`
-- * `AIRBASE.PersianGulf.Sharjah_Intl`
-- * `AIRBASE.PersianGulf.Shiraz_International_Airport`
-- * `AIRBASE.PersianGulf.Shiraz_Intl`
-- * `AIRBASE.PersianGulf.Sir_Abu_Nuayr`
-- * `AIRBASE.PersianGulf.Sirri_Island`
-- * `AIRBASE.PersianGulf.Tunb_Island_AFB`
-- * `AIRBASE.PersianGulf.Tunb_Kochak`
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel_Airport`
-- * `AIRBASE.PersianGulf.Bandar_e_Jask_airfield`
-- * `AIRBASE.PersianGulf.Abu_Dhabi_International_Airport`
-- * `AIRBASE.PersianGulf.Al_Bateen_Airport`
-- * `AIRBASE.PersianGulf.Kish_International_Airport`
-- * `AIRBASE.PersianGulf.Al_Ain_International_Airport`
-- * `AIRBASE.PersianGulf.Lavan_Island_Airport`
-- * `AIRBASE.PersianGulf.Jiroft_Airport`
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel`
-- * `AIRBASE.PersianGulf.Bandar_e_Jask`
-- * `AIRBASE.PersianGulf.Abu_Dhabi_Intl`
-- * `AIRBASE.PersianGulf.Al_Bateen`
-- * `AIRBASE.PersianGulf.Kish_Intl`
-- * `AIRBASE.PersianGulf.Al_Ain_Intl`
-- * `AIRBASE.PersianGulf.Lavan_Island`
-- * `AIRBASE.PersianGulf.Jiroft`
--
-- # Installation
--
@@ -1391,8 +1397,8 @@ end
-- AirbasePoliceCaucasus = ATC_GROUND_PERSIANGULF:New()
--
-- ATC_Ground = ATC_GROUND_PERSIANGULF:New(
-- { AIRBASE.PersianGulf.Kerman_Airport,
-- AIRBASE.PersianGulf.Al_Minhad_AB
-- { AIRBASE.PersianGulf.Kerman,
-- AIRBASE.PersianGulf.Al_Minhad_AFB
-- }
-- )
--

View File

@@ -652,7 +652,7 @@ do -- DETECTION_BASE
if DetectedObject:isExist() then
local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity = DetectionUnit:IsTargetDetected(
local TargetIsDetected, TargetIsVisible, TargetKnowType, TargetKnowDistance, TargetLastTime, TargetLastPos, TargetLastVelocity = DetectionUnit:IsTargetDetected(
DetectedObject,
self.DetectVisual,
self.DetectOptical,

View File

@@ -22,7 +22,7 @@
-- @module Functional.Mantis
-- @image Functional.Mantis.jpg
--
-- Last Update: July 2024
-- Last Update: Sep 2024
-------------------------------------------------------------------------
--- **MANTIS** class, extends Core.Base#BASE
@@ -439,27 +439,50 @@ MANTIS.SamDataSMA = {
-- @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" },
["LAV-AD CH"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_LAVAD" },
["HQ-22 CH"] = { Range=170, Blindspot=5, Height=27, Type="Long", Radar="CH_HQ22_LN" },
-- units from CH (Military Assets by Currenthill)
-- https://www.currenthill.com/
-- group name MUST contain CHM to ID launcher type correctly!
["2S38 CHM"] = { Range=8, Blindspot=0.5, Height=6, Type="Short", Radar="2S38" },
["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
["PantsirS2 CHM"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
["PGL-625 CHM"] = { Range=10, Blindspot=0.5, Height=5, Type="Short", Radar="PGL_625" },
["HQ-17A CHM"] = { Range=20, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
["M903PAC2 CHM"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
["M903PAC3 CHM"] = { Range=120, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
["NASAMS3-AMRAAMER CHM"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
["NASAMS3-AIM9X2 CHM"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
["C-RAM CHM"] = { Range=2, Blindspot=0, Height=2, Type="Short", Radar="CH_Centurion_C_RAM" },
["PGZ-09 CHM"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="CH_PGZ09" },
["S350-9M100 CHM"] = { Range=15, Blindspot=1.5, Height=8, Type="Short", Radar="CH_S350_50P6_9M100" },
["S350-9M96D CHM"] = { Range=150, Blindspot=2.5, Height=30, Type="Long", Radar="CH_S350_50P6_9M96D" },
["LAV-AD CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_LAVAD" },
["HQ-22 CHM"] = { Range=170, Blindspot=5, Height=27, Type="Long", Radar="CH_HQ22_LN" },
["PGZ-95 CHM"] = { Range=2, Blindspot=0, Height=2, Type="Short", Radar="CH_PGZ95" },
["LD-3000 CHM"] = { Range=3, Blindspot=0, Height=3, Type="Short", Radar="CH_LD3000_stationary" },
["LD-3000M CHM"] = { Range=3, Blindspot=0, Height=3, Type="Short", Radar="CH_LD3000" },
["FlaRakRad CHM"] = { Range=8, Blindspot=1.5, Height=6, Type="Short", Radar="HQ17A" },
["IRIS-T SLM CHM"] = { Range=40, Blindspot=0.5, Height=20, Type="Medium", Radar="CH_IRIST_SLM" },
["M903PAC2KAT1 CHM"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="CH_MIM104_M903_PAC2_KAT1" },
["Skynex CHM"] = { Range=3.5, Blindspot=0, Height=3.5, Type="Short", Radar="CH_SkynexHX" },
["Skyshield CHM"] = { Range=3.5, Blindspot=0, Height=3.5, Type="Short", Radar="CH_Skyshield_Gun" },
["WieselOzelot CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_Wiesel2Ozelot" },
["BukM3-9M317M CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317M" },
["BukM3-9M317MA CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317MA" },
["SkySabre CHM"] = { Range=30, Blindspot=0.5, Height=10, Type="Medium", Radar="CH_SkySabreLN" },
["Stormer CHM"] = { Range=7.5, Blindspot=0.3, Height=7, Type="Short", Radar="CH_StormerHVM" },
["THAAD CHM"] = { Range=200, Blindspot=40, Height=150, Type="Long", Radar="CH_THAAD_M1120" },
["USInfantryFIM92K CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_USInfantry_FIM92" },
["RBS98M CHM"] = { Range=20, Blindspot=0, Height=8, Type="Short", Radar="RBS-98" },
["RBS70 CHM"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-70" },
["RBS90 CHM"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-90" },
["RBS103A CHM"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
["RBS103B CHM"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_Rb103B" },
["RBS103AM CHM"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
["RBS103BM CHM"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_HX_Rb103B" },
["Lvkv9040M CHM"] = { Range=4, Blindspot=0, Height=2.5, Type="Short", Radar="LvKv9040" },
}
-----------------------------------------------------------------------
@@ -640,7 +663,7 @@ do
-- TODO Version
-- @field #string version
self.version="0.8.18"
self.version="0.8.20"
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
--- FSM Functions ---
@@ -1396,7 +1419,7 @@ do
-- @return #string type Long, medium or short range
-- @return #number blind "blind" spot
function MANTIS:_GetSAMDataFromUnits(grpname,mod,sma,chm)
self:T(self.lid.."_GetSAMRangeFromUnits")
self:T(self.lid.."_GetSAMDataFromUnits")
local found = false
local range = self.checkradius
local height = 3000
@@ -1449,7 +1472,7 @@ do
-- @return #string type Long, medium or short range
-- @return #number blind "blind" spot
function MANTIS:_GetSAMRange(grpname)
self:T(self.lid.."_GetSAMRange")
self:T(self.lid.."_GetSAMRange for "..tostring(grpname))
local range = self.checkradius
local height = 3000
local type = MANTIS.SamType.MEDIUM
@@ -1466,9 +1489,9 @@ do
elseif string.find(grpname,"CHM",1,true) then
CHMod = true
end
if self.automode then
--if self.automode then
for idx,entry in pairs(self.SamData) do
--self:I("ID = " .. idx)
self:T("ID = " .. idx)
if string.find(grpname,idx,1,true) then
local _entry = entry -- #MANTIS.SamData
type = _entry.Type
@@ -1476,18 +1499,21 @@ do
range = _entry.Range * 1000 * radiusscale -- max firing range
height = _entry.Height * 1000 -- max firing height
blind = _entry.Blindspot
--self:I("Matching Groupname = " .. grpname .. " Range= " .. range)
self:T("Matching Groupname = " .. grpname .. " Range= " .. range)
found = true
break
end
end
end
--end
-- secondary filter if not found
if (not found and self.automode) or HDSmod or SMAMod or CHMod then
if (not found) 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
if string.find(grpname,"SHORAD",1,true) then
type = MANTIS.SamType.SHORT -- force short on match
end
return range, height, type, blind
end
@@ -1651,6 +1677,10 @@ do
function MANTIS:_CheckLoop(samset,detset,dlink,limit)
self:T(self.lid .. "CheckLoop " .. #detset .. " Coordinates")
local switchedon = 0
local statusreport = REPORT:New("\nMANTIS Status")
local instatusred = 0
local instatusgreen = 0
local SEADactive = 0
for _,_data in pairs (samset) do
local samcoordinate = _data[2]
local name = _data[1]
@@ -1673,7 +1703,7 @@ do
elseif (not self.UseEmOnOff) and switchedon < limit then
samgroup:OptionAlarmStateRed()
switchedon = switchedon + 1
switch = true
switch = true
end
if self.SamStateTracker[name] ~= "RED" and switch then
self:__RedState(1,samgroup)
@@ -1691,7 +1721,7 @@ do
-- debug output
if (self.debug or self.verbose) and switch then
local text = string.format("SAM %s in alarm state RED!", name)
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
--local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug
if self.verbose then self:I(self.lid..text) end
end
end --end alive
@@ -1709,12 +1739,26 @@ do
end
if self.debug or self.verbose then
local text = string.format("SAM %s in alarm state GREEN!", name)
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
--local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
if self.verbose then self:I(self.lid..text) end
end
end --end alive
end --end check
end --for for loop
end --end check
end --for loop
if self.debug then
for _,_status in pairs(self.SamStateTracker) do
if _status == "GREEN" then
instatusgreen=instatusgreen+1
elseif _status == "RED" then
instatusred=instatusred+1
end
end
statusreport:Add("+-----------------------------+")
statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred))
statusreport:Add(string.format("+ SAM in GREEN State: %2d",instatusgreen))
statusreport:Add("+-----------------------------+")
MESSAGE:New(statusreport:Text(),10,nil,true):ToAll():ToLog()
end
return self
end
@@ -1828,7 +1872,7 @@ do
end
--]]
if self.autoshorad then
self.Shorad = SHORAD:New(self.name.."-SHORAD",self.name.."-SHORAD",self.SAM_Group,self.ShoradActDistance,self.ShoradTime,self.coalition,self.UseEmOnOff)
self.Shorad = SHORAD:New(self.name.."-SHORAD","SHORAD",self.SAM_Group,self.ShoradActDistance,self.ShoradTime,self.coalition,self.UseEmOnOff)
self.Shorad:SetDefenseLimits(80,95)
self.ShoradLink = true
self.Shorad.Groupset=self.ShoradGroupSet

View File

@@ -2987,7 +2987,7 @@ function RANGE:_DisplayBombTargets( _unitname )
end
end
self:_DisplayMessageToGroup( _unit, _text, 120, true, true, _multiplayer )
self:_DisplayMessageToGroup( _unit, _text, 150, true, true, _multiplayer )
end
end
@@ -3453,10 +3453,10 @@ function RANGE:_AddF10Commands( _unitName )
-- Range menu
local _rangePath = MENU_GROUP:New( group, self.rangename, _rootMenu )
local _statsPath = MENU_GROUP:New( group, "Statistics", _rangePath )
local _markPath = MENU_GROUP:New( group, "Mark Targets", _rangePath )
local _settingsPath = MENU_GROUP:New( group, "My Settings", _rangePath )
local _infoPath = MENU_GROUP:New( group, "Range Info", _rangePath )
local _markPath = MENU_GROUP:New( group, "Mark Targets", _rangePath )
local _statsPath = MENU_GROUP:New( group, "Statistics", _rangePath )
local _settingsPath = MENU_GROUP:New( group, "My Settings", _rangePath )
-- F10/On the Range/<Range Name>/My Settings/
local _mysmokePath = MENU_GROUP:New( group, "Smoke Color", _settingsPath )

View File

@@ -19,7 +19,7 @@
--
-- ### Authors: **applevangelist**, **FlightControl**
--
-- Last Update: Dec 2023
-- Last Update: Oct 2024
--
-- ===
--
@@ -28,6 +28,16 @@
---
-- @type SEAD
-- @field #string ClassName The Class Name.
-- @field #table TargetSkill Table of target skills.
-- @field #table SEADGroupPrefixes Table of SEAD prefixes.
-- @field #table SuppressedGroups Table of currently suppressed groups.
-- @field #number EngagementRange Engagement Range.
-- @field #number Padding Padding in seconds.
-- @field #function CallBack Callback function for suppression plans.
-- @field #boolean UseCallBack Switch for callback function to be used.
-- @field #boolean debug Debug switch.
-- @field #boolen WeaponTrack Track switch, if true track weapon speed for 30 secs.
-- @extends Core.Base#BASE
--- Make SAM sites execute evasive and defensive behaviour when being fired upon.
@@ -56,10 +66,11 @@ SEAD = {
SEADGroupPrefixes = {},
SuppressedGroups = {},
EngagementRange = 75, -- default 75% engagement range Feature Request #1355
Padding = 10,
Padding = 15,
CallBack = nil,
UseCallBack = false,
debug = false,
WeaponTrack = false,
}
--- Missile enumerators
@@ -144,7 +155,7 @@ function SEAD:New( SEADGroupPrefixes, Padding )
self:AddTransition("*", "ManageEvasion", "*")
self:AddTransition("*", "CalculateHitZone", "*")
self:I("*** SEAD - Started Version 0.4.6")
self:I("*** SEAD - Started Version 0.4.8")
return self
end
@@ -371,7 +382,7 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
reach = wpndata[1] * 1.1
local mach = wpndata[2]
wpnspeed = math.floor(mach * 340.29)
if Weapon then
if Weapon and Weapon:GetSpeed() > 0 then
wpnspeed = Weapon:GetSpeed()
self:T(string.format("*** SEAD - Weapon Speed from WEAPON: %f m/s",wpnspeed))
end
@@ -452,22 +463,30 @@ end
-- @return #SEAD self
function SEAD:HandleEventShot( EventData )
self:T( { EventData.id } )
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
local SEADUnit = EventData.IniDCSUnit
local SEADUnitName = EventData.IniDCSUnitName
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
local SEADWeaponName = EventData.WeaponName -- return weapon type
local WeaponWrapper = WEAPON:New(EventData.Weapon)
--local SEADWeaponSpeed = WeaponWrapper:GetSpeed() -- mps
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
--self:T({ SEADWeapon })
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
local SEADWeaponName = EventData.WeaponName or "None" -- return weapon type
if self:_CheckHarms(SEADWeaponName) then
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
if not SEADPlane then return self end -- case IniUnit is empty
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
local SEADUnit = EventData.IniDCSUnit
local SEADUnitName = EventData.IniDCSUnitName
local WeaponWrapper = WEAPON:New(EventData.Weapon) -- Wrapper.Weapon#WEAPON
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
self:T( '*** SEAD - Weapon Match' )
if self.WeaponTrack == true then
WeaponWrapper:SetFuncTrack(function(weapon) env.info(string.format("*** Weapon Speed: %d m/s",weapon:GetSpeed() or -1)) end)
WeaponWrapper:StartTrack(0.1)
WeaponWrapper:StopTrack(30)
end
local _targetskill = "Random"
local _targetgroupname = "none"
local _target = EventData.Weapon:getTarget() -- Identify target
@@ -520,7 +539,7 @@ function SEAD:HandleEventShot( EventData )
end
if SEADGroupFound == true then -- yes we are being attacked
if string.find(SEADWeaponName,"ADM_141",1,true) then
self:__ManageEvasion(2,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
self:__ManageEvasion(2,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,2,WeaponWrapper)
else
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
end

View File

@@ -8433,12 +8433,14 @@ function WAREHOUSE:_GetAttribute(group)
local attribute=WAREHOUSE.Attribute.OTHER_UNKNOWN --#WAREHOUSE.Attribute
if group then
local groupCat=group:GetCategory()
-----------
--- Air ---
-----------
-- Planes
local transportplane=group:HasAttribute("Transports") and group:HasAttribute("Planes")
local transportplane=group:HasAttribute("Transports") and group:HasAttribute("Planes") and groupCat==Group.Category.AIRPLANE
local awacs=group:HasAttribute("AWACS")
local fighter=group:HasAttribute("Fighters") or group:HasAttribute("Interceptors") or group:HasAttribute("Multirole fighters") or (group:HasAttribute("Bombers") and not group:HasAttribute("Strategic bombers"))
local bomber=group:HasAttribute("Strategic bombers")
@@ -8593,7 +8595,6 @@ end
-- @param #WAREHOUSE.Queueitem qitem Item of queue to be removed.
-- @param #table queue The queue from which the item should be deleted.
function WAREHOUSE:_DeleteQueueItem(qitem, queue)
self:F({qitem=qitem, queue=queue})
for i=1,#queue do
local _item=queue[i] --#WAREHOUSE.Queueitem

View File

@@ -291,7 +291,7 @@
-- ## Nevada: Nellis AFB
--
-- -- ATIS Nellis AFB on 270.10 MHz AM.
-- atisNellis=ATIS:New(AIRBASE.Nevada.Nellis_AFB, 270.1)
-- atisNellis=ATIS:New(AIRBASE.Nevada.Nellis, 270.1)
-- atisNellis:SetRadioRelayUnitName("Radio Relay Nellis")
-- atisNellis:SetActiveRunway("21L")
-- atisNellis:SetTowerFrequencies({327.000, 132.550})
@@ -302,7 +302,7 @@
-- ## Persian Gulf: Abu Dhabi International Airport
--
-- -- ATIS Abu Dhabi International on 125.1 MHz AM.
-- atisAbuDhabi=ATIS:New(AIRBASE.PersianGulf.Abu_Dhabi_International_Airport, 125.1)
-- atisAbuDhabi=ATIS:New(AIRBASE.PersianGulf.Abu_Dhabi_Intl, 125.1)
-- atisAbuDhabi:SetRadioRelayUnitName("Radio Relay Abu Dhabi International Airport")
-- atisAbuDhabi:SetMetricUnits()
-- atisAbuDhabi:SetActiveRunway("L")
@@ -498,6 +498,9 @@ ATIS.Alphabet = {
-- @field #number Syria +5° (East).
-- @field #number MarianaIslands +2° (East).
-- @field #number SinaiMap +5° (East).
-- @field #number Kola +15° (East).
-- @field #number Afghanistan +3° (East).
-- @field #number Iraq +4.4° (East).
ATIS.RunwayM2T = {
Caucasus = 0,
Nevada = 12,
@@ -508,6 +511,9 @@ ATIS.RunwayM2T = {
MarianaIslands = 2,
Falklands = 12,
SinaiMap = 5,
Kola = 15,
Afghanistan = 3,
Iraq=4.4
}
--- Whether ICAO phraseology is used for ATIS broadcasts.
@@ -521,6 +527,9 @@ ATIS.RunwayM2T = {
-- @field #boolean MarianaIslands true.
-- @field #boolean Falklands true.
-- @field #boolean SinaiMap true.
-- @field #boolean Kola true.
-- @field #boolean Afghanistan true.
-- @field #boolean Iraq true.
ATIS.ICAOPhraseology = {
Caucasus = true,
Nevada = false,
@@ -531,6 +540,9 @@ ATIS.ICAOPhraseology = {
MarianaIslands = true,
Falklands = true,
SinaiMap = true,
Kola = true,
Afghanistan = true,
Iraq = true,
}
--- Nav point data.
@@ -619,83 +631,83 @@ ATIS.ICAOPhraseology = {
-- @field #ATIS.Soundfile TACANChannel
-- @field #ATIS.Soundfile VORFrequency
ATIS.Sound = {
ActiveRunway = { filename = "ActiveRunway.ogg", duration = 0.99 },
ActiveRunwayDeparture = { filename = "ActiveRunwayDeparture.ogg", duration = 0.99 },
ActiveRunwayArrival = { filename = "ActiveRunwayArrival.ogg", duration = 0.99 },
AdviceOnInitial = { filename = "AdviceOnInitial.ogg", duration = 3.00 },
Airport = { filename = "Airport.ogg", duration = 0.66 },
Altimeter = { filename = "Altimeter.ogg", duration = 0.68 },
At = { filename = "At.ogg", duration = 0.41 },
CloudBase = { filename = "CloudBase.ogg", duration = 0.82 },
CloudCeiling = { filename = "CloudCeiling.ogg", duration = 0.61 },
CloudsBroken = { filename = "CloudsBroken.ogg", duration = 1.07 },
CloudsFew = { filename = "CloudsFew.ogg", duration = 0.99 },
CloudsNo = { filename = "CloudsNo.ogg", duration = 1.01 },
CloudsNotAvailable = { filename = "CloudsNotAvailable.ogg", duration = 2.35 },
CloudsOvercast = { filename = "CloudsOvercast.ogg", duration = 0.83 },
CloudsScattered = { filename = "CloudsScattered.ogg", duration = 1.18 },
Decimal = { filename = "Decimal.ogg", duration = 0.54 },
DegreesCelsius = { filename = "DegreesCelsius.ogg", duration = 1.27 },
DegreesFahrenheit = { filename = "DegreesFahrenheit.ogg", duration = 1.23 },
DewPoint = { filename = "DewPoint.ogg", duration = 0.65 },
Dust = { filename = "Dust.ogg", duration = 0.54 },
Elevation = { filename = "Elevation.ogg", duration = 0.78 },
EndOfInformation = { filename = "EndOfInformation.ogg", duration = 1.15 },
Feet = { filename = "Feet.ogg", duration = 0.45 },
Fog = { filename = "Fog.ogg", duration = 0.47 },
Gusting = { filename = "Gusting.ogg", duration = 0.55 },
HectoPascal = { filename = "HectoPascal.ogg", duration = 1.15 },
Hundred = { filename = "Hundred.ogg", duration = 0.47 },
InchesOfMercury = { filename = "InchesOfMercury.ogg", duration = 1.16 },
Information = { filename = "Information.ogg", duration = 0.85 },
Kilometers = { filename = "Kilometers.ogg", duration = 0.78 },
Knots = { filename = "Knots.ogg", duration = 0.59 },
Left = { filename = "Left.ogg", duration = 0.54 },
MegaHertz = { filename = "MegaHertz.ogg", duration = 0.87 },
Meters = { filename = "Meters.ogg", duration = 0.59 },
MetersPerSecond = { filename = "MetersPerSecond.ogg", duration = 1.14 },
Miles = { filename = "Miles.ogg", duration = 0.60 },
MillimetersOfMercury = { filename = "MillimetersOfMercury.ogg", duration = 1.53 },
Minus = { filename = "Minus.ogg", duration = 0.64 },
N0 = { filename = "N-0.ogg", duration = 0.55 },
N1 = { filename = "N-1.ogg", duration = 0.41 },
N2 = { filename = "N-2.ogg", duration = 0.37 },
N3 = { filename = "N-3.ogg", duration = 0.41 },
N4 = { filename = "N-4.ogg", duration = 0.37 },
N5 = { filename = "N-5.ogg", duration = 0.43 },
N6 = { filename = "N-6.ogg", duration = 0.55 },
N7 = { filename = "N-7.ogg", duration = 0.43 },
N8 = { filename = "N-8.ogg", duration = 0.38 },
N9 = { filename = "N-9.ogg", duration = 0.55 },
NauticalMiles = { filename = "NauticalMiles.ogg", duration = 1.04 },
None = { filename = "None.ogg", duration = 0.43 },
QFE = { filename = "QFE.ogg", duration = 0.63 },
QNH = { filename = "QNH.ogg", duration = 0.71 },
Rain = { filename = "Rain.ogg", duration = 0.41 },
Right = { filename = "Right.ogg", duration = 0.44 },
Snow = { filename = "Snow.ogg", duration = 0.48 },
SnowStorm = { filename = "SnowStorm.ogg", duration = 0.82 },
StatuteMiles = { filename = "StatuteMiles.ogg", duration = 1.15 },
SunriseAt = { filename = "SunriseAt.ogg", duration = 0.92 },
SunsetAt = { filename = "SunsetAt.ogg", duration = 0.95 },
Temperature = { filename = "Temperature.ogg", duration = 0.64 },
Thousand = { filename = "Thousand.ogg", duration = 0.55 },
ThunderStorm = { filename = "ThunderStorm.ogg", duration = 0.81 },
TimeLocal = { filename = "TimeLocal.ogg", duration = 0.90 },
TimeZulu = { filename = "TimeZulu.ogg", duration = 0.86 },
TowerFrequency = { filename = "TowerFrequency.ogg", duration = 1.19 },
Visibilty = { filename = "Visibility.ogg", duration = 0.79 },
WeatherPhenomena = { filename = "WeatherPhenomena.ogg", duration = 1.07 },
WindFrom = { filename = "WindFrom.ogg", duration = 0.60 },
ActiveRunway = { filename = "ActiveRunway.ogg", duration = 0.85 },
ActiveRunwayDeparture = { filename = "ActiveRunwayDeparture.ogg", duration = 1.50 },
ActiveRunwayArrival = { filename = "ActiveRunwayArrival.ogg", duration = 1.38 },
AdviceOnInitial = { filename = "AdviceOnInitial.ogg", duration = 2.98 },
Airport = { filename = "Airport.ogg", duration = 0.55 },
Altimeter = { filename = "Altimeter.ogg", duration = 0.91 },
At = { filename = "At.ogg", duration = 0.32 },
CloudBase = { filename = "CloudBase.ogg", duration = 0.69 },
CloudCeiling = { filename = "CloudCeiling.ogg", duration = 0.53 },
CloudsBroken = { filename = "CloudsBroken.ogg", duration = 0.81 },
CloudsFew = { filename = "CloudsFew.ogg", duration = 0.74 },
CloudsNo = { filename = "CloudsNo.ogg", duration = 0.69},
CloudsNotAvailable = { filename = "CloudsNotAvailable.ogg", duration = 2.64 },
CloudsOvercast = { filename = "CloudsOvercast.ogg", duration = 0.82 },
CloudsScattered = { filename = "CloudsScattered.ogg", duration = 0.89 },
Decimal = { filename = "Decimal.ogg", duration = 0.71 },
DegreesCelsius = { filename = "DegreesCelsius.ogg", duration = 1.08 },
DegreesFahrenheit = { filename = "DegreesFahrenheit.ogg", duration = 1.07 },
DewPoint = { filename = "DewPoint.ogg", duration = 0.59 },
Dust = { filename = "Dust.ogg", duration = 0.37 },
Elevation = { filename = "Elevation.ogg", duration = 0.92 },
EndOfInformation = { filename = "EndOfInformation.ogg", duration = 1.24 },
Feet = { filename = "Feet.ogg", duration = 0.34 },
Fog = { filename = "Fog.ogg", duration = 0.41 },
Gusting = { filename = "Gusting.ogg", duration = 0.58 },
HectoPascal = { filename = "HectoPascal.ogg", duration = 0.92 },
Hundred = { filename = "Hundred.ogg", duration = 0.53 },
ILSFrequency = { filename = "ILSFrequency.ogg", duration = 1.30 },
InnerNDBFrequency = { filename = "InnerNDBFrequency.ogg", duration = 1.56 },
OuterNDBFrequency = { filename = "OuterNDBFrequency.ogg", duration = 1.59 },
RunwayLength = { filename = "RunwayLength.ogg", duration = 0.91 },
VORFrequency = { filename = "VORFrequency.ogg", duration = 1.38 },
TACANChannel = { filename = "TACANChannel.ogg", duration = 0.88 },
PRMGChannel = { filename = "PRMGChannel.ogg", duration = 1.18 },
RSBNChannel = { filename = "RSBNChannel.ogg", duration = 1.14 },
Zulu = { filename = "Zulu.ogg", duration = 0.62 },
InchesOfMercury = { filename = "InchesOfMercury.ogg", duration = 1.26 },
Information = { filename = "Information.ogg", duration = 0.99 },
InnerNDBFrequency = { filename = "InnerNDBFrequency.ogg", duration = 1.69 },
Kilometers = { filename = "Kilometers.ogg", duration = 0.93 },
Knots = { filename = "Knots.ogg", duration = 0.46 },
Left = { filename = "Left.ogg", duration = 0.41 },
MegaHertz = { filename = "MegaHertz.ogg", duration = 0.83 },
Meters = { filename = "Meters.ogg", duration = 0.55 },
MetersPerSecond = { filename = "MetersPerSecond.ogg", duration = 1.03 },
Miles = { filename = "Miles.ogg", duration = 0.44 },
MillimetersOfMercury = { filename = "MillimetersOfMercury.ogg", duration = 1.59 },
Minus = { filename = "Minus.ogg", duration = 0.55 },
N0 = { filename = "N-0.ogg", duration = 0.52 },
N1 = { filename = "N-1.ogg", duration = 0.35 },
N2 = { filename = "N-2.ogg", duration = 0.41 },
N3 = { filename = "N-3.ogg", duration = 0.34 },
N4 = { filename = "N-4.ogg", duration = 0.37 },
N5 = { filename = "N-5.ogg", duration = 0.40 },
N6 = { filename = "N-6.ogg", duration = 0.46 },
N7 = { filename = "N-7.ogg", duration = 0.52 },
N8 = { filename = "N-8.ogg", duration = 0.36 },
N9 = { filename = "N-9.ogg", duration = 0.51 },
NauticalMiles = { filename = "NauticalMiles.ogg", duration = 0.93 },
None = { filename = "None.ogg", duration = 0.33 },
OuterNDBFrequency = { filename = "OuterNDBFrequency.ogg", duration = 1.70 },
PRMGChannel = { filename = "PRMGChannel.ogg", duration = 1.27 },
QFE = { filename = "QFE.ogg", duration = 0.90 },
QNH = { filename = "QNH.ogg", duration = 0.94 },
Rain = { filename = "Rain.ogg", duration = 0.35 },
Right = { filename = "Right.ogg", duration = 0.31 },
RSBNChannel = { filename = "RSBNChannel.ogg", duration = 1.26 },
RunwayLength = { filename = "RunwayLength.ogg", duration = 0.81 },
Snow = { filename = "Snow.ogg", duration = 0.40 },
SnowStorm = { filename = "SnowStorm.ogg", duration = 0.73 },
StatuteMiles = { filename = "StatuteMiles.ogg", duration = 0.90 },
SunriseAt = { filename = "SunriseAt.ogg", duration = 0.82 },
SunsetAt = { filename = "SunsetAt.ogg", duration = 0.87 },
TACANChannel = { filename = "TACANChannel.ogg", duration = 0.81 },
Temperature = { filename = "Temperature.ogg", duration = 0.70 },
Thousand = { filename = "Thousand.ogg", duration = 0.58 },
ThunderStorm = { filename = "ThunderStorm.ogg", duration = 0.79 },
TimeLocal = { filename = "TimeLocal.ogg", duration = 0.83 },
TimeZulu = { filename = "TimeZulu.ogg", duration = 0.83 },
TowerFrequency = { filename = "TowerFrequency.ogg", duration = 1.05 },
Visibilty = { filename = "Visibility.ogg", duration = 1.16 },
VORFrequency = { filename = "VORFrequency.ogg", duration = 1.28 },
WeatherPhenomena = { filename = "WeatherPhenomena.ogg", duration = 1.09 },
WindFrom = { filename = "WindFrom.ogg", duration = 0.63 },
Zulu = { filename = "Zulu.ogg", duration = 0.51 },
}
---
@@ -954,7 +966,7 @@ _ATIS = {}
--- ATIS class version.
-- @field #string version
ATIS.version = "1.0.0"
ATIS.version = "1.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@@ -2080,34 +2092,32 @@ function ATIS:onafterBroadcast( From, Event, To )
---------------
-- Get mission weather info. Most of this is static.
local clouds, visibility, turbulence, fog, dust, static = self:GetMissionWeather()
-- Check that fog is actually "thick" enough to reach the airport. If an airport is in the mountains, fog might not affect it as it is measured from sea level.
if fog and fog.thickness < height + 25 then
fog = nil
end
-- Dust only up to 1500 ft = 457 m ASL.
if dust and height + 25 > UTILS.FeetToMeters( 1500 ) then
dust = nil
end
local clouds, visibility, turbulence, dustdens, static = self:GetMissionWeather()
local dust=false
local fog=false
------------------
--- Visibility ---
------------------
-- Get min visibility.
local visibilitymin = visibility
if fog then
if fog.visibility < visibilitymin then
visibilitymin = fog.visibility
if dustdens then
-- Dust only up to 1500 ft = 457 m ASL.
if UTILS.FeetToMeters( 1500 )> height+25 then
dust=true
visibility=math.min(visibility, dustdens)
end
end
if dust then
if dust < visibilitymin then
visibilitymin = dust
else -- As of DCS 2.9.10.3948 (December 2024), fog and dust are mutually exclusive!
-- Get current fog visibility and thickness
local fvis=world.weather.getFogVisibilityDistance()
local fheight=world.weather.getFogThickness()
if fvis>0 and fheight>height+25 then
fog=true
visibility=math.min(visibility, fvis)
end
end
@@ -2115,7 +2125,7 @@ function ATIS:onafterBroadcast( From, Event, To )
if self.metric then
-- Visibility in km.
local reportedviz = UTILS.Round( visibilitymin / 1000 )
local reportedviz = UTILS.Round( visibility / 1000 )
-- max reported visibility 9999 m
if reportedviz > 10 then
reportedviz = 10
@@ -2123,7 +2133,7 @@ function ATIS:onafterBroadcast( From, Event, To )
VISIBILITY = string.format( "%d", reportedviz )
else
-- max reported visibility 10 NM
local reportedviz = UTILS.Round( UTILS.MetersToSM( visibilitymin ) )
local reportedviz = UTILS.Round( UTILS.MetersToSM( visibility ) )
if reportedviz > 10 then
reportedviz = 10
end
@@ -3350,28 +3360,13 @@ function ATIS:GetMissionWeather()
dust = weather.dust_density
end
-- Fog
--[[
["enable_fog"] = false,
["fog"] =
{
["thickness"] = 0,
["visibility"] = 25,
}, -- end of ["fog"]
]]
local fog = nil
if weather.enable_fog == true then
fog = weather.fog
end
self:T( "FF weather:" )
self:T( { clouds = clouds } )
self:T( { visibility = visibility } )
self:T( { turbulence = turbulence } )
self:T( { fog = fog } )
self:T( { dust = dust } )
self:T( { static = static } )
return clouds, visibility, turbulence, fog, dust, static
return clouds, visibility, turbulence, dust, static
end
--- Get thousands of a number.

View File

@@ -3614,7 +3614,7 @@ function AIRBOSS:onafterStart( From, Event, To )
-- Handle events.
self:HandleEvent( EVENTS.Birth )
self:HandleEvent( EVENTS.Land )
self:HandleEvent( EVENTS.RunwayTouch )
self:HandleEvent( EVENTS.EngineShutdown )
self:HandleEvent( EVENTS.Takeoff )
self:HandleEvent( EVENTS.Crash )
@@ -4379,7 +4379,7 @@ function AIRBOSS:onafterStop( From, Event, To )
-- Unhandle events.
self:UnHandleEvent( EVENTS.Birth )
self:UnHandleEvent( EVENTS.Land )
self:UnHandleEvent( EVENTS.RunwayTouch )
self:UnHandleEvent( EVENTS.EngineShutdown )
self:UnHandleEvent( EVENTS.Takeoff )
self:UnHandleEvent( EVENTS.Crash )
@@ -8289,7 +8289,7 @@ end
--- Airboss event handler for event land.
-- @param #AIRBOSS self
-- @param Core.Event#EVENTDATA EventData
function AIRBOSS:OnEventLand( EventData )
function AIRBOSS:OnEventRunwayTouch( EventData )
self:F3( { eventland = EventData } )
-- Nil checks.

View File

@@ -308,7 +308,7 @@ CSAR.AircraftType["AH-64D_BLK_II"] = 2
CSAR.AircraftType["Bronco-OV-10A"] = 2
CSAR.AircraftType["MH-60R"] = 10
CSAR.AircraftType["OH-6A"] = 2
CSAR.AircraftType["OH-58D"] = 2
CSAR.AircraftType["OH58D"] = 2
CSAR.AircraftType["CH-47Fbl1"] = 31
--- CSAR class version.
@@ -841,9 +841,9 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla
local BeaconName
if _playerName then
BeaconName = _unitName..math.random(1,10000)
elseif _unitName then
BeaconName = _playerName..math.random(1,10000)
elseif _unitName then
BeaconName = _unitName..math.random(1,10000)
else
BeaconName = "Ghost-1-1"..math.random(1,10000)
end

View File

@@ -24,7 +24,7 @@
-- @module Ops.CTLD
-- @image OPS_CTLD.jpg
-- Last Update Sep 2024
-- Last Update Dec 2024
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -836,6 +836,9 @@ do
-- my_ctld.enableChinookGCLoading = true -- this will effectively suppress the crate load and drop for CTLD_CARGO.Enum.STATIc types for CTLD for the Chinook
-- my_ctld.TroopUnloadDistGround = 5 -- If hovering, spawn dropped troops this far away in meters from the helo
-- my_ctld.TroopUnloadDistHover = 1.5 -- If grounded, spawn dropped troops this far away in meters from the helo
-- my_ctld.TroopUnloadDistGroundHerc = 25 -- On the ground, unload troops this far behind the Hercules
-- my_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook
-- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook
--
-- ## 2.1 CH-47 Chinook support
--
@@ -895,7 +898,7 @@ do
-- ["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
-- ["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
-- ["OH-6A"] = {type="OH-6A", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 7, cargoweightlimit = 550},
-- ["OH-58D"] = {type="OH58D", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 14, cargoweightlimit = 400},
-- ["OH58D"] = {type="OH58D", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 14, cargoweightlimit = 400},
-- ["CH-47Fbl1"] = {type="CH-47Fbl1", crates=true, troops=true, cratelimit = 4, trooplimit = 31, length = 20, cargoweightlimit = 8000},
--
-- ### 2.2.2 Activate and deactivate zones
@@ -1233,6 +1236,9 @@ CTLD = {
DynamicCargo = {},
ChinookTroopCircleRadius = 5,
TroopUnloadDistGround = 5,
TroopUnloadDistGroundHerc = 25,
TroopUnloadDistGroundHook = 15,
TroopUnloadDistHoverHook = 5,
TroopUnloadDistHover = 1.5,
UserSetGroup = nil,
}
@@ -1272,6 +1278,12 @@ CTLD.RadioModulation = {
FM = 1,
}
--- Loaded Cargo
-- @type CTLD.LoadedCargo
-- @field #number Troopsloaded
-- @field #number Cratesloaded
-- @field #table Cargo Table of #CTLD_CARGO objects
--- Zone Info.
-- @type CTLD.CargoZone
-- @field #string name Name of Zone.
@@ -1333,13 +1345,13 @@ CTLD.UnitTypeCapabilities = {
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
["OH-6A"] = {type="OH-6A", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 7, cargoweightlimit = 550},
["OH-58D"] = {type="OH58D", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 14, cargoweightlimit = 400},
["OH58D"] = {type="OH58D", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 14, cargoweightlimit = 400},
["CH-47Fbl1"] = {type="CH-47Fbl1", crates=true, troops=true, cratelimit = 4, trooplimit = 31, length = 20, cargoweightlimit = 10800},
}
--- CTLD class version.
-- @field #string version
CTLD.version="1.1.16"
CTLD.version="1.1.20"
--- Instantiate a new CTLD.
-- @param #CTLD self
@@ -2425,6 +2437,7 @@ end
local nearestGroup = nil
local nearestGroupIndex = -1
local nearestDistance = 10000000
local maxdistance = 0
local nearestList = {}
local distancekeys = {}
local extractdistance = self.CrateDistance * self.ExtractFactor
@@ -2436,8 +2449,14 @@ end
nearestGroup = v
nearestGroupIndex = k
nearestDistance = distance
if math.floor(distance) > maxdistance then maxdistance = math.floor(distance) end
if nearestList[math.floor(distance)] then
distance = maxdistance+1
maxdistance = distance
end
table.insert(nearestList, math.floor(distance), v)
distancekeys[#distancekeys+1] = math.floor(distance)
--self:I(string.format("Adding group %s distance %dm",nearestGroup:GetName(),distance))
end
end
@@ -2490,7 +2509,7 @@ end
nearestGroup.ExtractTime = timer.getTime()
local loadcargotype = CTLD_CARGO:New(self.CargoCounter, Cargotype.Name, Cargotype.Templates, Cargotype.CargoType, true, true, Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass)
self:T({cargotype=loadcargotype})
local running = math.floor(nearestDistance / 4)+10 -- time run to helo plus boarding
local running = math.floor(nearestDistance / 4)+20 -- time run to helo plus boarding
loaded.Troopsloaded = loaded.Troopsloaded + troopsize
table.insert(loaded.Cargo,loadcargotype)
self.Loaded_Cargo[unitname] = loaded
@@ -2505,26 +2524,32 @@ end
local Angle = math.floor((heading+160)%360)
Point = coord:Translate(8,Angle):GetVec2()
if Point then
nearestGroup:RouteToVec2(Point,4)
nearestGroup:RouteToVec2(Point,5)
end
end
-- clean up:
if type(Cargotype.Templates) == "table" and Cargotype.Templates[2] then
local hassecondaries = false
if type(Cargotype.Templates) == "table" and Cargotype.Templates[2] then
for _,_key in pairs (Cargotype.Templates) do
table.insert(secondarygroups,_key)
hassecondaries = true
end
end
nearestGroup:Destroy(false,running)
local destroytimer = math.random(10,20)
--self:I("Destroying Group "..nearestGroup:GetName().." in "..destroytimer.." seconds!")
nearestGroup:Destroy(false,destroytimer)
end
end
end
-- clean up secondary groups
for _,_name in pairs(secondarygroups) do
for _,_group in pairs(nearestList) do
if _group and _group:IsAlive() then
local groupname = string.match(_group:GetName(), "(.+)-(.+)$")
if _name == groupname then
_group:Destroy(false,15)
if hassecondaries == true then
for _,_name in pairs(secondarygroups) do
for _,_group in pairs(nearestList) do
if _group and _group:IsAlive() then
local groupname = string.match(_group:GetName(), "(.+)-(.+)$")
if _name == groupname then
_group:Destroy(false,15)
end
end
end
end
@@ -3408,8 +3433,8 @@ function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
local template = _DATABASE:GetGroupTemplate(Template)
--UTILS.PrintTableToLog(template)
local numbertroops = #template.units
local slightshift = math.abs(math.random(0,200)/100)
local newcenter = Coordinate:Translate(Radius+slightshift,((Heading+270)%360))
local slightshift = math.abs(math.random(1,500)/100)
local newcenter = Coordinate:Translate(Radius+slightshift,((Heading+270+math.random(1,10))%360))
for i=1,360,math.floor(360/numbertroops) do
local phead = ((Heading+270+i)%360)
local post = newcenter:Translate(Radius,phead)
@@ -3484,7 +3509,15 @@ function CTLD:_UnloadTroops(Group, Unit)
randomcoord = Group:GetCoordinate()
-- slightly left from us
local Angle = (heading+270)%360
if IsHerc or IsHook then Angle = (heading+180)%360 end
local offset = hoverunload and self.TroopUnloadDistHover or self.TroopUnloadDistGround
if IsHerc then offset = self.TroopUnloadDistGroundHerc or 25 end
if IsHook then
offset = self.TroopUnloadDistGroundHook or 15
if self.TroopUnloadDistHoverHook then
offset = self.TroopUnloadDistHoverHook or 5
end
end
randomcoord:Translate(offset,Angle,nil,true)
end
local tempcount = 0
@@ -3494,7 +3527,7 @@ function CTLD:_UnloadTroops(Group, Unit)
self.TroopCounter = self.TroopCounter + 1
tempcount = tempcount+1
local alias = string.format("%s-%d", _template, math.random(1,100000))
local rad = 2.5+tempcount
local rad = 2.5+(tempcount*2)
local Positions = self:_GetUnitPositions(randomcoord,rad,heading,_template)
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
--:InitRandomizeUnits(true,20,2)
@@ -4269,7 +4302,7 @@ end
-- @param #string SubCategory Name of sub-category (optional).
-- @param #boolean DontShowInMenu (optional) If set to "true" this won't show up in the menu.
-- @param Core.Zone#ZONE Location (optional) If set, the cargo item is **only** available here. Can be a #ZONE object or the name of a zone as #string.
-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH-58D"}.
-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH58D"}.
-- @param #string Category Static category name (optional). If set, spawn cargo crate with an alternate category type, e.g. "Cargos".
-- @param #string TypeName Static type name (optional). If set, spawn cargo crate with an alternate type shape, e.g. "iso_container".
-- @param #string ShapeName Static shape name (optional). If set, spawn cargo crate with an alternate type sub-shape, e.g. "iso_container_cargo".
@@ -4353,7 +4386,7 @@ end
-- @param #string SubCategory Name of the sub-category (optional).
-- @param #boolean DontShowInMenu (optional) If set to "true" this won't show up in the menu.
-- @param Core.Zone#ZONE Location (optional) If set, the cargo item is **only** available here. Can be a #ZONE object or the name of a zone as #string.
-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH-58D"}
-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH58D"}
-- @param #string Category Static category name (optional). If set, spawn cargo crate with an alternate category type, e.g. "Cargos".
-- @param #string TypeName Static type name (optional). If set, spawn cargo crate with an alternate type shape, e.g. "iso_container".
-- @param #string ShapeName Static shape name (optional). If set, spawn cargo crate with an alternate type sub-shape, e.g. "iso_container_cargo".
@@ -5356,6 +5389,27 @@ end
return Stock
end
--- User - Query the cargo loaded from a specific unit
-- @param #CTLD self
-- @param Wrapper.Unit#UNIT Unit The (client) unit to query.
-- @return #number Troopsloaded
-- @return #number Cratesloaded
-- @return #table Cargo Table of #CTLD_CARGO objects
function CTLD:GetLoadedCargo(Unit)
local Troops = 0
local Crates = 0
local Cargo = {}
if Unit and Unit:IsAlive() then
local name = Unit:GetName()
if self.Loaded_Cargo[name] then
Troops = self.Loaded_Cargo[name].Troopsloaded or 0
Crates = self.Loaded_Cargo[name].Cratesloaded or 0
Cargo = self.Loaded_Cargo[name].Cargo or {}
end
end
return Troops, Crates, Cargo
end
--- User - function to get a table of statics cargo in stock
-- @param #CTLD self
-- @return #table Table Table of Stock, indexed by cargo type name

View File

@@ -52,6 +52,7 @@
-- @field #table poptions Provider options. Each element is a data structure of type `MSRS.ProvierOptions`.
-- @field #string provider Provider of TTS (win, gcloud, azure, amazon).
-- @field #string backend Backend used as interface to SRS (MSRS.Backend.SRSEXE or MSRS.Backend.GRPC).
-- @field #boolean UsePowerShell Use PowerShell to execute the command and not cmd.exe
-- @extends Core.Base#BASE
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
@@ -256,11 +257,12 @@ MSRS = {
ConfigFilePath = "Config\\",
ConfigLoaded = false,
poptions = {},
UsePowerShell = false,
}
--- MSRS class version.
-- @field #string version
MSRS.version="0.3.0"
MSRS.version="0.3.3"
--- Voices
-- @type MSRS.Voices
@@ -588,7 +590,7 @@ function MSRS:SetBackendSRSEXE()
end
--- Set the default backend.
-- @param #MSRS self
-- @param #string Backend
function MSRS.SetDefaultBackend(Backend)
MSRS.backend=Backend or MSRS.Backend.SRSEXE
end
@@ -1375,20 +1377,25 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
modus=modus:gsub("1", "FM")
-- Command.
local pwsh = string.format('Start-Process -WindowStyle Hidden -WorkingDirectory \"%s\" -FilePath \"%s\" -ArgumentList \'-f "%s" -m "%s" -c %s -p %s -n "%s" -v "%.1f"', path, exe, freqs, modus, coal, port, label,volume )
local command=string.format('"%s\\%s" -f "%s" -m "%s" -c %s -p %s -n "%s" -v "%.1f"', path, exe, freqs, modus, coal, port, label,volume)
-- Set voice or gender/culture.
if voice then
if voice and self.UsePowerShell ~= true then
-- Use a specific voice (no need for gender and/or culture.
command=command..string.format(" --voice=\"%s\"", tostring(voice))
pwsh=pwsh..string.format(" --voice=\"%s\"", tostring(voice))
else
-- Add gender.
if gender and gender~="female" then
command=command..string.format(" -g %s", tostring(gender))
pwsh=pwsh..string.format(" -g %s", tostring(gender))
end
-- Add culture.
if culture and culture~="en-GB" then
command=command..string.format(" -l %s", tostring(culture))
pwsh=pwsh..string.format(" -l %s", tostring(culture))
end
end
@@ -1396,12 +1403,14 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
if coordinate then
local lat,lon,alt=self:_GetLatLongAlt(coordinate)
command=command..string.format(" -L %.4f -O %.4f -A %d", lat, lon, alt)
pwsh=pwsh..string.format(" -L %.4f -O %.4f -A %d", lat, lon, alt)
end
-- Set provider options
if self.provider==MSRS.Provider.GOOGLE then
local pops=self:GetProviderOptions()
command=command..string.format(' --ssml -G "%s"', pops.credentials)
pwsh=pwsh..string.format(' --ssml -G "%s"', pops.credentials)
elseif self.provider==MSRS.Provider.WINDOWS then
-- Nothing to do.
else
@@ -1415,8 +1424,12 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
-- Debug output.
self:T("MSRS command from _GetCommand="..command)
return command
if self.UsePowerShell == true then
return pwsh
else
return command
end
end
--- Execute SRS command to play sound using the `DCS-SR-ExternalAudio.exe`.
@@ -1424,7 +1437,7 @@ end
-- @param #string command Command to executer
-- @return #number Return value of os.execute() command.
function MSRS:_ExecCommand(command)
self:F( {command=command} )
self:T2( {command=command} )
-- Skip this function if _GetCommand was not able to find the executable
if string.find(command, "CommandNotFound") then return 0 end
@@ -1432,7 +1445,13 @@ function MSRS:_ExecCommand(command)
local batContent = command.." && exit"
-- Create a tmp file.
local filename=os.getenv('TMP').."\\MSRS-"..MSRS.uuid()..".bat"
if self.UsePowerShell == true then
filename=os.getenv('TMP').."\\MSRS-"..MSRS.uuid()..".ps1"
batContent = command .. "\'"
self:I({batContent=batContent})
end
local script=io.open(filename, "w+")
script:write(batContent)
script:close()
@@ -1441,7 +1460,7 @@ function MSRS:_ExecCommand(command)
self:T("MSRS batch content: "..batContent)
local res=nil
if true then
if self.UsePowerShell ~= true then
-- Create a tmp file.
local filenvbs = os.getenv('TMP') .. "\\MSRS-"..MSRS.uuid()..".vbs"
@@ -1469,23 +1488,20 @@ function MSRS:_ExecCommand(command)
timer.scheduleFunction(os.remove, filenvbs, timer.getTime()+1)
self:T("MSRS vbs and batch file removed")
elseif false then
-- Create a tmp file.
local filenvbs = os.getenv('TMP') .. "\\MSRS-"..MSRS.uuid()..".vbs"
-- VBS script
local script = io.open(filenvbs, "w+")
script:write(string.format('Set oShell = CreateObject ("Wscript.Shell")\n'))
script:write(string.format('Dim strArgs\n'))
script:write(string.format('strArgs = "cmd /c %s"\n', filename))
script:write(string.format('oShell.Run strArgs, 0, false'))
script:close()
local runvbs=string.format('cscript.exe //Nologo //B "%s"', filenvbs)
elseif self.UsePowerShell == true then
local pwsh = string.format('start /min "" powershell.exe -ExecutionPolicy Unrestricted -WindowStyle Hidden -Command "%s"',filename)
--env.info("[MSRS] TextToSpeech Command :\n" .. pwsh.."\n")
if string.len(pwsh) > 255 then
self:E("[MSRS] - pwsh string too long")
end
-- Play file in 0.01 seconds
res=os.execute(runvbs)
res=os.execute(pwsh)
-- Remove file in 1 second.
timer.scheduleFunction(os.remove, filename, timer.getTime()+1)
else
-- Play command.

View File

@@ -1195,18 +1195,18 @@ ENUMS.Storage.weapons.UH1H.M60_MG_Right_Door = {4,15,46,177}
ENUMS.Storage.weapons.UH1H.M134_MiniGun_Left_Door = {4,15,46,174}
ENUMS.Storage.weapons.UH1H.M60_MG_Left_Door = {4,15,46,176}
-- Kiowa
ENUMS.Storage.weapons.OH58.FIM92 = {4,4,7,446}
ENUMS.Storage.weapons.OH58.MG_M3P100 = {4,15,46,2578}
ENUMS.Storage.weapons.OH58.MG_M3P200 = {4,15,46,2577}
ENUMS.Storage.weapons.OH58.MG_M3P300 = {4,15,46,2576}
ENUMS.Storage.weapons.OH58.MG_M3P400 = {4,15,46,2575}
ENUMS.Storage.weapons.OH58.MG_M3P500 = {4,15,46,2574}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Blue = {4,5,9,484}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Green = {4,5,9,485}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Red = {4,5,9,483}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Violet = {4,5,9,486}
ENUMS.Storage.weapons.OH58.Smk_Grenade_White = {4,5,9,488}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Yellow = {4,5,9,487}
ENUMS.Storage.weapons.OH58.FIM92 = {4,4,7,449}
ENUMS.Storage.weapons.OH58.MG_M3P100 = {4,15,46,2608}
ENUMS.Storage.weapons.OH58.MG_M3P200 = {4,15,46,2607}
ENUMS.Storage.weapons.OH58.MG_M3P300 = {4,15,46,2606}
ENUMS.Storage.weapons.OH58.MG_M3P400 = {4,15,46,2605}
ENUMS.Storage.weapons.OH58.MG_M3P500 = {4,15,46,2604}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Blue = {4,5,9,486}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Green = {4,5,9,487}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Red = {4,5,9,485}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Violet = {4,5,9,488}
ENUMS.Storage.weapons.OH58.Smk_Grenade_White = {4,5,9,490}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Yellow = {4,5,9,489}
-- Apache
ENUMS.Storage.weapons.AH64D.AN_APG78 = {4,15,44,2138}
ENUMS.Storage.weapons.AH64D.Internal_Aux_FuelTank = {1,3,43,1700}

View File

@@ -56,6 +56,8 @@ BIGSMOKEPRESET = {
-- @field #string Falklands South Atlantic map.
-- @field #string Sinai Sinai map.
-- @field #string Kola Kola map.
-- @field #string Afghanistan Afghanistan map
-- @field #string Iraq Iraq map
DCSMAP = {
Caucasus="Caucasus",
NTTR="Nevada",
@@ -68,6 +70,7 @@ DCSMAP = {
Sinai="SinaiMap",
Kola="Kola",
Afghanistan="Afghanistan",
Iraq="Iraq"
}
@@ -1786,6 +1789,8 @@ function UTILS.GetMagneticDeclination(map)
declination=15
elseif map==DCSMAP.Afghanistan then
declination=3
elseif map==DCSMAP.Iraq then
declination=4.4
else
declination=0
end
@@ -2315,9 +2320,9 @@ function UTILS.IsLoadingDoorOpen( unit_name )
return true
end
if type_name == "OH-58D" and (unit:getDrawArgumentValue(35) > 0 or unit:getDrawArgumentValue(421) == -1) then
BASE:T(unit_name .. " cargo door is open")
return true
if type_name == "OH58D" then
BASE:T(unit_name .. " front door(s) are open")
return true -- no doors on this one ;)
end
if type_name == "CH-47Fbl1" and (unit:getDrawArgumentValue(86) > 0.5) then
@@ -2523,7 +2528,7 @@ end
--- Function to save an object to a file
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
-- @param #string Filename The name of the file. Existing file will be overwritten.
-- @param #table Data The LUA data structure to save. This will be e.g. a table of text lines with an \\n at the end of each line.
-- @param #string Data The data structure to save. This will be e.g. a string of text lines with an \\n at the end of each line.
-- @return #boolean outcome True if saving is possible, else false.
function UTILS.SaveToFile(Path,Filename,Data)
-- Thanks to @FunkyFranky

View File

@@ -63,6 +63,11 @@
-- To be able to distinguish easily in your code the difference between a AIRBASE API call and a DCS Airbase API call,
-- the first letter of the method is also capitalized. So, by example, the DCS Airbase method DCSWrapper.Airbase#Airbase.getName()
-- is implemented in the AIRBASE class as @{#AIRBASE.GetName}().
--
-- ## Note on the "H" heli pads in the Syria map:
--
-- As of the time of writing (Oct 2024, DCS DCS 2.9.8.1107), these 143 objects have the **same name and object ID**, which makes them unusable in Moose, e.g. you cannot find a specific one for spawning etc.
-- Waiting for Ugra and ED to fix this issue.
--
-- @field #AIRBASE AIRBASE
AIRBASE = {
@@ -248,6 +253,9 @@ AIRBASE.Nevada = {
-- * AIRBASE.Normandy.Villacoublay
-- * AIRBASE.Normandy.Vrigny
-- * AIRBASE.Normandy.West_Malling
-- * AIRBASE.Normandy.Eastchurch
-- * AIRBASE.Normandy.Headcorn
-- * AIRBASE.Normandy.Hawkinge
--
-- @field Normandy
AIRBASE.Normandy = {
@@ -330,6 +338,9 @@ AIRBASE.Normandy = {
["Villacoublay"] = "Villacoublay",
["Vrigny"] = "Vrigny",
["West_Malling"] = "West Malling",
["Eastchurch"] = "Eastchurch",
["Headcorn"] = "Headcorn",
["Hawkinge"] = "Hawkinge",
}
--- Airbases of the Persion Gulf Map:
@@ -450,6 +461,7 @@ AIRBASE.TheChannel = {
-- * AIRBASE.Syria.Gaziantep
-- * AIRBASE.Syria.Gazipasa
-- * AIRBASE.Syria.Gecitkale
-- * AIRBASE.Syria.H
-- * AIRBASE.Syria.H3
-- * AIRBASE.Syria.H3_Northwest
-- * AIRBASE.Syria.H3_Southwest
@@ -497,6 +509,10 @@ AIRBASE.TheChannel = {
-- * AIRBASE.Syria.Tha_lah
-- * AIRBASE.Syria.Tiyas
-- * AIRBASE.Syria.Wujah_Al_Hajar
-- * AIRBASE.Syria.Ben_Gurion
-- * AIRBASE.Syria.Hatzor
-- * AIRBASE.Syria.Palmashim
-- * AIRBASE.Syria.Tel_Nof
--
--@field Syria
AIRBASE.Syria={
@@ -518,6 +534,7 @@ AIRBASE.Syria={
["Gaziantep"] = "Gaziantep",
["Gazipasa"] = "Gazipasa",
["Gecitkale"] = "Gecitkale",
["H"] = "H",
["H3"] = "H3",
["H3_Northwest"] = "H3 Northwest",
["H3_Southwest"] = "H3 Southwest",
@@ -565,6 +582,10 @@ AIRBASE.Syria={
["Tha_lah"] = "Tha'lah",
["Tiyas"] = "Tiyas",
["Wujah_Al_Hajar"] = "Wujah Al Hajar",
["Ben_Gurion"] = "Ben Gurion",
["Hatzor"] = "Hatzor",
["Palmashim"] = "Palmashim",
["Tel_Nof"] = "Tel Nof",
}
--- Airbases of the Mariana Islands map:
@@ -752,12 +773,14 @@ AIRBASE.Sinai = {
--
-- * AIRBASE.Kola.Banak
-- * AIRBASE.Kola.Bodo
-- * AIRBASE.Kola.Ivalo
-- * AIRBASE.Kola.Jokkmokk
-- * AIRBASE.Kola.Kalixfors
-- * AIRBASE.Kola.Kallax
-- * AIRBASE.Kola.Kemi_Tornio
-- * AIRBASE.Kola.Kirkenes
-- * AIRBASE.Kola.Kiruna
-- * AIRBASE.Kola.Kuusamo
-- * AIRBASE.Kola.Monchegorsk
-- * AIRBASE.Kola.Murmansk_International
-- * AIRBASE.Kola.Olenya
@@ -766,25 +789,31 @@ AIRBASE.Sinai = {
-- * AIRBASE.Kola.Severomorsk_3
-- * AIRBASE.Kola.Vidsel
-- * AIRBASE.Kola.Vuojarvi
--
-- * AIRBASE.Kola.Andoya
-- * AIRBASE.Kola.Alakourtti
--
-- @field Kola
AIRBASE.Kola = {
["Banak"] = "Banak",
["Bodo"] = "Bodo",
["Ivalo"] = "Ivalo",
["Jokkmokk"] = "Jokkmokk",
["Kalixfors"] = "Kalixfors",
["Kallax"] = "Kallax",
["Kemi_Tornio"] = "Kemi Tornio",
["Kirkenes"] = "Kirkenes",
["Kiruna"] = "Kiruna",
["Kuusamo"] = "Kuusamo",
["Monchegorsk"] = "Monchegorsk",
["Murmansk_International"] = "Murmansk International",
["Olenya"] = "Olenya",
["Rovaniemi"] = "Rovaniemi",
["Severomorsk_1"] = "Severomorsk-1",
["Severomorsk_3"] = "Severomorsk-3",
["Vuojarvi"] = "Vuojarvi",
["Kirkenes"] = "Kirkenes",
["Kallax"] = "Kallax",
["Vidsel"] = "Vidsel",
["Vuojarvi"] = "Vuojarvi",
["Andoya"] = "Andoya",
["Alakourtti"] = "Alakourtti",
}
--- Airbases of the Afghanistan map
@@ -824,6 +853,39 @@ AIRBASE.Afghanistan = {
["Tarinkot"] = "Tarinkot",
}
--- Airbases of the Iraq map
--
-- * `AIRBASE.Iraq.Baghdad_International_Airport` Baghdad International Airport
-- * `AIRBASE.Iraq.Sulaimaniyah_International_Airport` Sulaimaniyah International Airport
-- * `AIRBASE.Iraq.Al_Sahra_Airport` Al-Sahra Airport
-- * `AIRBASE.Iraq.Erbil_International_Airport` Erbil International Airport
-- * `AIRBASE.Iraq.Al_Taji_Airport` Al-Taji Airport
-- * `AIRBASE.Iraq.Al_Asad_Airbase` Al-Asad Airbase
-- * `AIRBASE.Iraq.Al_Salam_Airbase` Al-Salam Airbase
-- * `AIRBASE.Iraq.Balad_Airbase` Balad Airbase
-- * `AIRBASE.Iraq.Kirkuk_International_Airport` Kirkuk International Airport
-- * `AIRBASE.Iraq.Bashur_Airport` Bashur Airport
-- * `AIRBASE.Iraq.Al_Taquddum_Airport` Al-Taquddum Airport
-- * `AIRBASE.Iraq.Qayyarah_Airfield_West` Qayyarah Airfield West
-- * `AIRBASE.Iraq.K1_Base` K1 Base
--
-- @field Iraq
AIRBASE.Iraq = {
["Baghdad_International_Airport"] = "Baghdad International Airport",
["Sulaimaniyah_International_Airport"] = "Sulaimaniyah International Airport",
["Al_Sahra_Airport"] = "Al-Sahra Airport",
["Erbil_International_Airport"] = "Erbil International Airport",
["Al_Taji_Airport"] = "Al-Taji Airport",
["Al_Asad_Airbase"] = "Al-Asad Airbase",
["Al_Salam_Airbase"] = "Al-Salam Airbase",
["Balad_Airbase"] = "Balad Airbase",
["Kirkuk_International_Airport"] = "Kirkuk International Airport",
["Bashur_Airport"] = "Bashur Airport",
["Al_Taquddum_Airport"] = "Al-Taquddum Airport",
["Qayyarah_Airfield_West"] = "Qayyarah Airfield West",
["K1_Base"] = "K1 Base",
}
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
-- @type AIRBASE.ParkingSpot
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.
@@ -926,7 +988,7 @@ function AIRBASE:Register(AirbaseName)
-- Debug info.
--self:I({airbase=AirbaseName, descriptors=self.descriptors})
-- Category.
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
@@ -937,22 +999,22 @@ function AIRBASE:Register(AirbaseName)
--end
-- Set category.
if self.category==Airbase.Category.AIRDROME then
self.isAirdrome=true
elseif self.category==Airbase.Category.HELIPAD then
if self.category==Airbase.Category.AIRDROME then
self.isAirdrome=true
elseif self.category==Airbase.Category.HELIPAD or self.descriptors.typeName=="FARP_SINGLE_01" then
self.isHelipad=true
elseif self.category==Airbase.Category.SHIP then
self.isShip=true
-- DCS bug: Oil rigs and gas platforms have category=2 (ship). Also they cannot be retrieved by coalition.getStaticObjects()
if self.descriptors.typeName=="Oil rig" or self.descriptors.typeName=="Ga" then
self.isHelipad=true
elseif self.category==Airbase.Category.SHIP then
self.isShip=true
-- DCS bug: Oil rigs and gas platforms have category=2 (ship). Also they cannot be retrieved by coalition.getStaticObjects()
if self.descriptors.typeName=="Oil rig" or self.descriptors.typeName=="Ga" then
self.isHelipad=true
self.isShip=false
self.category=Airbase.Category.HELIPAD
_DATABASE:AddStatic(AirbaseName)
end
else
self:E("ERROR: Unknown airbase category!")
self.isShip=false
self.category=Airbase.Category.HELIPAD
_DATABASE:AddStatic(AirbaseName)
end
else
self:E("ERROR: Unknown airbase category!")
end
-- Init Runways.
self:_InitRunways()

View File

@@ -902,7 +902,11 @@ function CONTROLLABLE:CommandEPLRS( SwitchOnOff, Delay )
groupId = self:GetID(),
},
}
--if self:IsGround() then
--CommandEPLRS.params.groupId = self:GetID()
--end
if Delay and Delay > 0 then
SCHEDULER:New( nil, self.CommandEPLRS, { self, SwitchOnOff }, Delay )
else
@@ -937,7 +941,7 @@ function CONTROLLABLE:CommandSetUnlimitedFuel(OnOff, Delay)
end
--- Set radio frequency. See [DCS command EPLRS](https://wiki.hoggitworld.com/view/DCS_command_setFrequency)
--- Set radio frequency. See [DCS command SetFrequency](https://wiki.hoggitworld.com/view/DCS_command_setFrequency)
-- @param #CONTROLLABLE self
-- @param #number Frequency Radio frequency in MHz.
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
@@ -956,7 +960,7 @@ function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Power, Delay )
}
if Delay and Delay > 0 then
SCHEDULER:New( nil, self.CommandSetFrequency, { self, Frequency, Modulation, Power } )
SCHEDULER:New( nil, self.CommandSetFrequency, { self, Frequency, Modulation, Power },Delay )
else
self:SetCommand( CommandSetFrequency )
end
@@ -964,7 +968,7 @@ function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Power, Delay )
return self
end
--- [AIR] Set radio frequency. See [DCS command EPLRS](https://wiki.hoggitworld.com/view/DCS_command_setFrequencyForUnit)
--- [AIR] Set radio frequency. See [DCS command SetFrequencyForUnit](https://wiki.hoggitworld.com/view/DCS_command_setFrequencyForUnit)
-- @param #CONTROLLABLE self
-- @param #number Frequency Radio frequency in MHz.
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
@@ -983,7 +987,7 @@ function CONTROLLABLE:CommandSetFrequencyForUnit(Frequency,Modulation,Power,Unit
},
}
if Delay and Delay>0 then
SCHEDULER:New(nil,self.CommandSetFrequencyForUnit,{self,Frequency,Modulation,Power,UnitID})
SCHEDULER:New(nil,self.CommandSetFrequencyForUnit,{self,Frequency,Modulation,Power,UnitID},Delay)
else
self:SetCommand(CommandSetFrequencyForUnit)
end
@@ -1009,7 +1013,11 @@ function CONTROLLABLE:TaskEPLRS( SwitchOnOff, idx )
groupId = self:GetID(),
},
}
--if self:IsGround() then
--CommandEPLRS.params.groupId = self:GetID()
--end
return self:TaskWrappedAction( CommandEPLRS, idx or 1 )
end
@@ -2997,7 +3005,7 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad
if DCSControllable then
local DetectionVisual = (DetectVisual and DetectVisual == true) and Controller.Detection.VISUAL or nil
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTICAL or nil
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTIC or nil
local DetectionRadar = (DetectRadar and DetectRadar == true) and Controller.Detection.RADAR or nil
local DetectionIRST = (DetectIRST and DetectIRST == true) and Controller.Detection.IRST or nil
local DetectionRWR = (DetectRWR and DetectRWR == true) and Controller.Detection.RWR or nil
@@ -3031,26 +3039,27 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad
return nil
end
--- Check if a target is detected.
--- Check if a DCS object (unit or static) is detected by the controllable.
-- Note that after a target is detected it remains "detected" for a certain amount of time, even if the controllable cannot "see" the target any more with it's sensors.
-- The optional parametes specify the detection methods that can be applied.
--
-- If **no** detection method is given, the detection will use **all** the available methods by default.
-- If **at least one** detection method is specified, only the methods set to *true* will be used.
-- @param #CONTROLLABLE self
-- @param DCS#Object DCSObject The DCS object that is checked.
-- @param #CONTROLLABLE self
-- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets.
-- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets.
-- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar.
-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST.
-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR.
-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link.
-- @return #boolean True if target is detected.
-- @return #boolean True if target is visible by line of sight.
-- @return #number Mission time when target was detected.
-- @return #boolean True if target type is known.
-- @return #boolean True if distance to target is known.
-- @return DCS#Vec3 Last known position vector of the target.
-- @return DCS#Vec3 Last known velocity vector of the target.
-- @return #boolean `true` if target is detected.
-- @return #boolean `true` if target is *currently* visible by line of sight. Target must be detected (first parameter returns `true`).
-- @return #boolean `true` if target type is known. Target must be detected (first parameter returns `true`).
-- @return #boolean `true` if distance to target is known. Target must be detected (first parameter returns `true`).
-- @return #number Mission time in seconds when target was last detected. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
-- @return DCS#Vec3 Last known position vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
-- @return DCS#Vec3 Last known velocity vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK )
self:F2( self.ControllableName )
@@ -3059,7 +3068,7 @@ function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical,
if DCSControllable then
local DetectionVisual = (DetectVisual and DetectVisual == true) and Controller.Detection.VISUAL or nil
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTICAL or nil
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTIC or nil
local DetectionRadar = (DetectRadar and DetectRadar == true) and Controller.Detection.RADAR or nil
local DetectionIRST = (DetectIRST and DetectIRST == true) and Controller.Detection.IRST or nil
local DetectionRWR = (DetectRWR and DetectRWR == true) and Controller.Detection.RWR or nil
@@ -3067,10 +3076,10 @@ function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical,
local Controller = self:_GetController()
local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity
local TargetIsDetected, TargetIsVisible, TargetKnowType, TargetKnowDistance, TargetLastTime, TargetLastPos, TargetLastVelocity
= Controller:isTargetDetected( DCSObject, DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK )
return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity
return TargetIsDetected, TargetIsVisible, TargetKnowType, TargetKnowDistance, TargetLastTime, TargetLastPos, TargetLastVelocity
end
return nil
@@ -3078,6 +3087,7 @@ end
--- Check if a certain UNIT is detected by the controllable.
-- The optional parametes specify the detection methods that can be applied.
--
-- If **no** detection method is given, the detection will use **all** the available methods by default.
-- If **at least one** detection method is specified, only the methods set to *true* will be used.
-- @param #CONTROLLABLE self
@@ -3088,13 +3098,13 @@ end
-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST.
-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR.
-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link.
-- @return #boolean True if target is detected.
-- @return #boolean True if target is visible by line of sight.
-- @return #number Mission time when target was detected.
-- @return #boolean True if target type is known.
-- @return #boolean True if distance to target is known.
-- @return DCS#Vec3 Last known position vector of the target.
-- @return DCS#Vec3 Last known velocity vector of the target.
-- @return #boolean `true` if target is detected.
-- @return #boolean `true` if target is *currently* visible by line of sight. Target must be detected (first parameter returns `true`).
-- @return #boolean `true` if target type is known. Target must be detected (first parameter returns `true`).
-- @return #boolean `true` if distance to target is known. Target must be detected (first parameter returns `true`).
-- @return #number Mission time in seconds when target was last detected. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
-- @return DCS#Vec3 Last known position vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
-- @return DCS#Vec3 Last known velocity vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
function CONTROLLABLE:IsUnitDetected( Unit, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK )
self:F2( self.ControllableName )

View File

@@ -458,7 +458,7 @@ function DYNAMICCARGO:_UpdatePosition()
self:T(self.lid.." AGL: "..agl or -1)
local isunloaded = true
local client
local playername
local playername = self.Owner
if count > 0 and (agl > 0 or self.testing) then
self:T(self.lid.." Possible alive helos: "..count or -1)
if agl ~= 0 or self.testing then
@@ -470,6 +470,11 @@ function DYNAMICCARGO:_UpdatePosition()
self.Owner = playername
_DATABASE:CreateEventDynamicCargoUnloaded(self)
end
elseif count > 0 and agl == 0 then
self:T(self.lid.." moved! LOADED -> UNLOADED by "..tostring(playername))
self.CargoState = DYNAMICCARGO.State.UNLOADED
self.Owner = playername
_DATABASE:CreateEventDynamicCargoUnloaded(self)
end
end
self.LastPosition = pos

View File

@@ -360,7 +360,7 @@ end
-- @return DCS#Group The DCS Group.
function GROUP:GetDCSObject()
if (not self.LastCallDCSObject) or (self.LastCallDCSObject and timer.getTime() - self.LastCallDCSObject > 1) then
--if (not self.LastCallDCSObject) or (self.LastCallDCSObject and timer.getTime() - self.LastCallDCSObject > 1) then
-- Get DCS group.
local DCSGroup = Group.getByName( self.GroupName )
@@ -369,14 +369,14 @@ function GROUP:GetDCSObject()
self.LastCallDCSObject = timer.getTime()
self.DCSObject = DCSGroup
return DCSGroup
else
self.DCSObject = nil
self.LastCallDCSObject = nil
-- else
-- self.DCSObject = nil
-- self.LastCallDCSObject = nil
end
else
return self.DCSObject
end
--else
--return self.DCSObject
--end
--self:E(string.format("ERROR: Could not get DCS group object of group %s because DCS object could not be found!", tostring(self.GroupName)))
return nil
@@ -485,20 +485,24 @@ function GROUP:Destroy( GenerateEvent, delay )
self:ScheduleOnce(delay, GROUP.Destroy, self, GenerateEvent)
else
local DCSGroup = self:GetDCSObject()
--local DCSGroup = self:GetDCSObject()
local DCSGroup = Group.getByName( self.GroupName )
if DCSGroup then
for Index, UnitData in pairs( DCSGroup:getUnits() ) do
if GenerateEvent and GenerateEvent == true then
if self:IsAir() then
self:CreateEventCrash( timer.getTime(), UnitData )
--self:ScheduleOnce(1,self.CreateEventCrash,self,timer.getTime(),UnitData)
else
self:CreateEventDead( timer.getTime(), UnitData )
--self:ScheduleOnce(1,self.CreateEventDead,self,timer.getTime(),UnitData)
end
elseif GenerateEvent == false then
-- Do nothing!
else
self:CreateEventRemoveUnit( timer.getTime(), UnitData )
--self:ScheduleOnce(1,self.CreateEventRemoveUnit,self,timer.getTime(),UnitData)
end
end
USERFLAG:New( self:GetName() ):Set( 100 )
@@ -1985,15 +1989,11 @@ end
-- - @{#GROUP.InitHeight}: Set the height for the units in meters for the respawned group. (This is applicable for air units).
-- - @{#GROUP.InitRandomizeHeading}: Randomize the headings for the units within the respawned group.
-- - @{#GROUP.InitZone}: Set the respawn @{Core.Zone} for the respawned group.
-- - @{#GROUP.InitRandomizeZones}: Randomize the respawn @{Core.Zone} between one of the @{Core.Zone}s given for the respawned group.
-- - @{#GROUP.InitRandomizePositionZone}: Randomize the positions of the units of the respawned group within the @{Core.Zone}.
-- - @{#GROUP.InitRandomizePositionRadius}: Randomize the positions of the units of the respawned group in a circle band.
-- - @{#GROUP.InitRandomizeTemplates}: Randomize the Template for the respawned group.
--
--
-- Notes:
--
-- - When InitZone or InitRandomizeZones is not used, the position of the respawned group will be its current position.
-- - The current alive group will always be destroyed and respawned using the template definition.
--
-- @param Wrapper.Group#GROUP self
@@ -2015,10 +2015,24 @@ function GROUP:Respawn( Template, Reset )
end
return h
end
local function TransFormRoute(Template,OldPos,NewPos)
if Template.route and Template.route.points then
for _,_point in ipairs(Template.route.points) do
--self:I(string.format("Point x = %f Point y = %f",_point.x,_point.y))
_point.x = _point.x - OldPos.x + NewPos.x
_point.y = _point.y - OldPos.y + NewPos.y
--self:I(string.format("Point x = %f Point y = %f",_point.x,_point.y))
end
end
return Template
end
-- First check if group is alive.
if self:IsAlive() then
local OldPos = self:GetVec2()
-- Respawn zone.
local Zone = self.InitRespawnZone -- Core.Zone#ZONE
@@ -2031,6 +2045,8 @@ function GROUP:Respawn( Template, Reset )
-- X, Y
Template.x = Vec3.x
Template.y = Vec3.z
local NewPos = { x = Vec3.x, y = Vec3.z }
--Template.x = nil
--Template.y = nil
@@ -2085,11 +2101,13 @@ function GROUP:Respawn( Template, Reset )
-- Set heading.
Template.units[UnitID].heading = _Heading(self.InitRespawnHeading and self.InitRespawnHeading or GroupUnit:GetHeading())
Template.units[UnitID].psi = -Template.units[UnitID].heading
-- Debug.
--self:F( { UnitID, Template.units[UnitID], Template.units[UnitID] } )
end
end
Template = TransFormRoute(Template,OldPos,NewPos)
elseif Reset==false then -- Reset=false or nil
@@ -2128,11 +2146,13 @@ function GROUP:Respawn( Template, Reset )
-- Heading
Template.units[UnitID].heading = self.InitRespawnHeading and self.InitRespawnHeading or TemplateUnitData.heading
-- Debug.
--self:F( { UnitID, Template.units[UnitID], Template.units[UnitID] } )
end
Template = TransFormRoute(Template,OldPos,NewPos)
else
local units=self:GetUnits()
@@ -2181,10 +2201,11 @@ function GROUP:Respawn( Template, Reset )
-- Destroy old group. Dont trigger any dead/crash events since this is a respawn.
self:Destroy(false)
--self:T({Template=Template})
--UTILS.PrintTableToLog(Template)
-- Spawn new group.
_DATABASE:Spawn(Template)
self:ScheduleOnce(0.1,_DATABASE.Spawn,_DATABASE,Template)
--_DATABASE:Spawn(Template)
-- Reset events.
self:ResetEvents()
@@ -2192,6 +2213,29 @@ function GROUP:Respawn( Template, Reset )
return self
end
--- Respawn the @{Wrapper.Group} at a @{Core.Point#COORDINATE}.
-- The method will setup the new group template according the Init(Respawn) settings provided for the group.
-- These settings can be provided by calling the relevant Init...() methods of the Group prior.
--
-- - @{#GROUP.InitHeading}: Set the heading for the units in degrees within the respawned group.
-- - @{#GROUP.InitHeight}: Set the height for the units in meters for the respawned group. (This is applicable for air units).
-- - @{#GROUP.InitRandomizeHeading}: Randomize the headings for the units within the respawned group.
-- - @{#GROUP.InitRandomizePositionZone}: Randomize the positions of the units of the respawned group within the @{Core.Zone}.
-- - @{#GROUP.InitRandomizePositionRadius}: Randomize the positions of the units of the respawned group in a circle band.
--
-- Notes:
--
-- - When no coordinate is given, the position of the respawned group will be its current position.
-- - The current alive group will always be destroyed first.
-- - The new group will have all of its original units and health restored.
--
-- @param Wrapper.Group#GROUP self
-- @param Core.Point#COORDINATE Coordinate Where to respawn the group. Can be handed as a @{Core.Zone#ZONE_BASE} object.
-- @return Wrapper.Group#GROUP self
function GROUP:Teleport(Coordinate)
self:InitZone(Coordinate)
return self:Respawn(nil,false)
end
--- Respawn a group at an airbase.
-- Note that the group has to be on parking spots at the airbase already in order for this to work.
@@ -2333,8 +2377,11 @@ end
-- @return #table The mission route defined by points.
function GROUP:GetTaskRoute()
--self:F2( self.GroupName )
return UTILS.DeepCopy( _DATABASE.Templates.Groups[self.GroupName].Template.route.points )
if _DATABASE.Templates.Groups[self.GroupName].Template and _DATABASE.Templates.Groups[self.GroupName].Template.route and _DATABASE.Templates.Groups[self.GroupName].Template.route.points then
return UTILS.DeepCopy( _DATABASE.Templates.Groups[self.GroupName].Template.route.points )
else
return {}
end
end
--- Return the route of a group by using the global _DATABASE object (an instance of @{Core.Database#DATABASE}).
@@ -2926,8 +2973,10 @@ end
-- @param #GROUP self
-- @param #boolean ShortCallsign Return a shortened customized callsign, i.e. "Ghostrider 9" and not "Ghostrider 9 1"
-- @param #boolean Keepnumber (Player only) Return customized callsign, incl optional numbers at the end, e.g. "Aerial 1-1#Ghostrider 109" results in "Ghostrider 109", if you want to e.g. use historical US Navy Callsigns
-- @param #table CallsignTranslations Table to translate between DCS standard callsigns and bespoke ones. Overrides personal/parsed callsigns if set
-- @param #table CallsignTranslations (Optional) Table to translate between DCS standard callsigns and bespoke ones. Overrides personal/parsed callsigns if set
-- callsigns from playername or group name.
-- @param #func CustomFunction (Optional) For player names only(!). If given, this function will return the callsign. Needs to take the groupname and the playername as first arguments.
-- @param #arg ... (Optional) Comma separated arguments to add to the CustomFunction call after groupname and playername.
-- @return #string Callsign
-- @usage
-- -- suppose there are three groups with one (client) unit each:
@@ -2948,8 +2997,12 @@ end
-- -- Apollo for Slot 2 or Apollo 403 if Keepnumber is set
-- -- Apollo for Slot 3
-- -- Bengal-4 for Slot 4
function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations)
--
-- -- Using a custom function (for player units **only**):
-- -- Imagine your playernames are looking like so: "[Squadname] | Cpt Apple" and you only want to have the last word as callsign, i.e. "Apple" here. Then this custom function will return this:
-- local callsign = mygroup:GetCustomCallSign(true,false,nil,function(groupname,playername) return string.match(playername,"([%a]+)$") end)
--
function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations,CustomFunction,...)
--self:I("GetCustomCallSign")
local callsign = "Ghost 1"
@@ -2963,7 +3016,14 @@ function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations)
local callnumbermajor = string.char(string.byte(callnumber,1)) -- 9
local callnumberminor = string.char(string.byte(callnumber,2)) -- 1
local personalized = false
local playername = IsPlayer == true and self:GetPlayerName() or shortcallsign
if CustomFunction and IsPlayer then
local arguments = arg or {}
local callsign = CustomFunction(groupname,playername,unpack(arguments))
return callsign
end
-- prioritize bespoke callsigns over parsing, prefer parsing over default callsigns
if CallsignTranslations and CallsignTranslations[callsignroot] then
callsignroot = CallsignTranslations[callsignroot]
@@ -2975,9 +3035,9 @@ function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations)
shortcallsign = string.match(groupname,"#%s*([%a]+)") or "Ghost" -- Ghostrider
end
personalized = true
elseif IsPlayer and string.find(self:GetPlayerName(),"|") then
elseif IsPlayer and string.find(playername,"|") then
-- personalized flight name in group naming
shortcallsign = string.match(self:GetPlayerName(),"|%s*([%a]+)") or string.match(self:GetPlayerName(),"|%s*([%d]+)") or "Ghost" -- Ghostrider
shortcallsign = string.match(playername,"|%s*([%a]+)") or string.match(self:GetPlayerName(),"|%s*([%d]+)") or "Ghost" -- Ghostrider
personalized = true
end

View File

@@ -43,7 +43,7 @@ do
-- @field #NET
NET = {
ClassName = "NET",
Version = "0.1.3",
Version = "0.1.4",
BlockTime = 600,
BlockedPilots = {},
BlockedUCIDs = {},
@@ -67,6 +67,9 @@ function NET:New()
self.KnownPilots = {}
self:SetBlockMessage()
self:SetUnblockMessage()
self.BlockedSides = {}
self.BlockedSides[1] = false
self.BlockedSides[2] = false
-- Start State.
self:SetStartState("Stopped")
@@ -160,11 +163,12 @@ end
-- @param #string PlayerSlot
-- @return #boolean IsBlocked
function NET:IsAnyBlocked(UCID,Name,PlayerID,PlayerSide,PlayerSlot)
self:T({UCID,Name,PlayerID,PlayerSide,PlayerSlot})
local blocked = false
local TNow = timer.getTime()
-- UCID
if UCID and self.BlockedUCIDs[UCID] and TNow < self.BlockedUCIDs[UCID] then
return true
blocked = true
end
-- ID/Name
if PlayerID and not Name then
@@ -172,16 +176,18 @@ function NET:IsAnyBlocked(UCID,Name,PlayerID,PlayerSide,PlayerSlot)
end
-- Name
if Name and self.BlockedPilots[Name] and TNow < self.BlockedPilots[Name] then
return true
blocked = true
end
-- Side
if PlayerSide and self.BlockedSides[PlayerSide] and TNow < self.BlockedSides[PlayerSide] then
return true
self:T({time = self.BlockedSides[PlayerSide]})
if PlayerSide and type(self.BlockedSides[PlayerSide]) == "number" and TNow < self.BlockedSides[PlayerSide] then
blocked = true
end
-- Slot
if PlayerSlot and self.BlockedSlots[PlayerSlot] and TNow < self.BlockedSlots[PlayerSlot] then
return true
blocked = true
end
self:T("IsAnyBlocked: "..tostring(blocked))
return blocked
end
@@ -200,19 +206,27 @@ function NET:_EventHandler(EventData)
local ucid = self:GetPlayerUCID(nil,name) or "none"
local PlayerID = self:GetPlayerIDByName(name) or "none"
local PlayerSide, PlayerSlot = self:GetSlot(data.IniUnit)
if not PlayerSide then PlayerSide = EventData.IniCoalition end
if not PlayerSlot then PlayerSlot = EventData.IniUnit:GetID() end
local TNow = timer.getTime()
self:T(self.lid.."Event for: "..name.." | UCID: "..ucid)
self:T(self.lid.."Event for: "..name.." | UCID: "..ucid .. " | ID/SIDE/SLOT "..PlayerID.."/"..PlayerSide.."/"..PlayerSlot)
-- Joining
if data.id == EVENTS.PlayerEnterUnit or data.id == EVENTS.PlayerEnterAircraft then
self:T(self.lid.."Pilot Joining: "..name.." | UCID: "..ucid.." | Event ID: "..data.id)
-- Check for blockages
local blocked = self:IsAnyBlocked(ucid,name,PlayerID,PlayerSide,PlayerSlot)
if blocked and PlayerID and tonumber(PlayerID) ~= 1 then
if blocked and PlayerID then -- and tonumber(PlayerID) ~= 1 then
self:T("Player blocked")
-- block pilot
local outcome = net.force_player_slot(tonumber(PlayerID), 0, '' )
local outcome = net.force_player_slot(tonumber(PlayerID), PlayerSide, data.IniUnit:GetID() )
self:T({Blocked_worked=outcome})
if outcome == false then
local unit = data.IniUnit
local sched = TIMER:New(unit.Destroy,unit,3):Start(3)
self:__PlayerBlocked(5,unit,name,1)
end
else
local client = CLIENT:FindByPlayerName(name) or data.IniUnit
if not self.KnownPilots[name] or (self.KnownPilots[name] and TNow-self.KnownPilots[name].timestamp > 3) then
@@ -225,6 +239,7 @@ function NET:_EventHandler(EventData)
slot = PlayerSlot,
timestamp = TNow,
}
--UTILS.PrintTableToLog(self.KnownPilots[name])
end
return self
end
@@ -350,11 +365,10 @@ end
--- Block a specific coalition side, does NOT automatically kick all players of that side or kick out joined players
-- @param #NET self
-- @param #number side The side to block - 1 : Red, 2 : Blue
-- @param #number Side The side to block - 1 : Red, 2 : Blue
-- @param #number Seconds Seconds (optional) Number of seconds the player has to wait before rejoining.
-- @return #NET self
function NET:BlockSide(Side,Seconds)
self:T({Side,Seconds})
local addon = Seconds or self.BlockTime
if Side == 1 or Side == 2 then
self.BlockedSides[Side] = timer.getTime()+addon
@@ -367,10 +381,9 @@ end
-- @param #number Seconds Seconds (optional) Number of seconds the player has to wait before rejoining.
-- @return #NET self
function NET:UnblockSide(Side,Seconds)
self:T({Side,Seconds})
local addon = Seconds or self.BlockTime
if Side == 1 or Side == 2 then
self.BlockedSides[Side] = nil
self.BlockedSides[Side] = false
end
return self
end
@@ -485,8 +498,11 @@ end
-- @param Wrapper.Client#CLIENT Client The client
-- @return #number PlayerID or nil
function NET:GetPlayerIDFromClient(Client)
self:T("GetPlayerIDFromClient")
self:T({Client=Client})
if Client then
local name = Client:GetPlayerName()
self:T({name=name})
local id = self:GetPlayerIDByName(name)
return id
else
@@ -682,16 +698,19 @@ end
-- @return #number SideID i.e. 0 : spectators, 1 : Red, 2 : Blue
-- @return #number SlotID
function NET:GetSlot(Client)
self:T("NET.GetSlot")
local PlayerID = self:GetPlayerIDFromClient(Client)
self:T("NET.GetSlot PlayerID = "..tostring(PlayerID))
if PlayerID then
local side,slot = net.get_slot(tonumber(PlayerID))
self:T("NET.GetSlot side, slot = "..tostring(side)..","..tostring(slot))
return side,slot
else
return nil,nil
end
end
--- Force the slot for a specific client.
--- Force the slot for a specific client. If this returns false, it didn't work via `net` (which is ALWAYS the case as of Nov 2024)!
-- @param #NET self
-- @param Wrapper.Client#CLIENT Client The client
-- @param #number SideID i.e. 0 : spectators, 1 : Red, 2 : Blue
@@ -699,19 +718,22 @@ end
-- @return #boolean Success
function NET:ForceSlot(Client,SideID,SlotID)
local PlayerID = self:GetPlayerIDFromClient(Client)
if PlayerID and tonumber(PlayerID) ~= 1 then
return net.force_player_slot(tonumber(PlayerID), SideID, SlotID or '' )
local SlotID = SlotID or Client:GetID()
if PlayerID then -- and tonumber(PlayerID) ~= 1 then
return net.force_player_slot(tonumber(PlayerID), SideID, SlotID )
else
return false
end
end
--- Force a client back to spectators.
--- Force a client back to spectators. If this returns false, it didn't work via `net` (which is ALWAYS the case as of Nov 2024)!
-- @param #NET self
-- @param Wrapper.Client#CLIENT Client The client
-- @return #boolean Succes
function NET:ReturnToSpectators(Client)
local outcome = self:ForceSlot(Client,0)
-- workaround
local sched = TIMER:New(Client.Destroy,Client,1):Start(1)
return outcome
end
@@ -781,7 +803,7 @@ function NET:onafterStatus(From,Event,To)
local function HouseHold(tavolo)
local TNow = timer.getTime()
for _,entry in pairs (tavolo) do
if entry >= TNow then entry = nil end
if type(entry) == "number" and entry >= TNow then entry = false end
end
end

View File

@@ -61,6 +61,8 @@ function STATIC:Register( StaticName )
if DCSStatic then
local Life0 = DCSStatic:getLife() or 1
self.Life0 = Life0
else
self:E(string.format("Static object %s does not exist!", tostring(self.StaticName)))
end
return self

View File

@@ -240,7 +240,9 @@ end
-- @return DCS#Unit The DCS Group.
function UNIT:GetDCSObject()
if (not self.LastCallDCSObject) or (self.LastCallDCSObject and timer.getTime() - self.LastCallDCSObject > 1) then
-- FF: Added checks that DCSObject exists because otherwise there were problems when respawning the unit right after it was initially spawned (e.g. teleport in OPSGROUP).
-- Got "Unit does not exit" after coalition.addGroup() when trying to access unit data because LastCallDCSObject<=1.
if (not self.LastCallDCSObject) or (self.LastCallDCSObject and timer.getTime()-self.LastCallDCSObject>1) or (self.DCSObject==nil) or (self.DCSObject:isExist()==false) then
-- Get DCS group.
local DCSUnit = Unit.getByName( self.UnitName )

View File

@@ -385,24 +385,26 @@ function WEAPON:GetTarget()
--Target name
local name=object:getName()
-- Debug info.
self:T(self.lid..string.format("Got Target Object %s, category=%d", object:getName(), category))
if category==Object.Category.UNIT then
target=UNIT:FindByName(name)
elseif category==Object.Category.STATIC then
target=STATIC:FindByName(name, false)
elseif category==Object.Category.SCENERY then
self:E(self.lid..string.format("ERROR: Scenery target not implemented yet!"))
else
self:E(self.lid..string.format("ERROR: Object category=%d is not implemented yet!", category))
if name then
-- Debug info.
self:T(self.lid..string.format("Got Target Object %s, category=%d", name, category))
if category==Object.Category.UNIT then
target=UNIT:FindByName(name)
elseif category==Object.Category.STATIC then
target=STATIC:FindByName(name, false)
elseif category==Object.Category.SCENERY then
self:E(self.lid..string.format("ERROR: Scenery target not implemented yet!"))
else
self:E(self.lid..string.format("ERROR: Object category=%d is not implemented yet!", category))
end
end
end
end