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

View File

@@ -211,10 +211,9 @@ function DATABASE:AddStatic( DCSStaticName )
if not self.STATICS[DCSStaticName] then if not self.STATICS[DCSStaticName] then
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName ) self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
return self.STATICS[DCSStaticName]
end end
return nil return self.STATICS[DCSStaticName]
end end
@@ -224,12 +223,11 @@ function DATABASE:DeleteStatic( DCSStaticName )
self.STATICS[DCSStaticName] = nil self.STATICS[DCSStaticName] = nil
end end
--- Finds a STATIC based on the StaticName. --- Finds a STATIC based on the Static Name.
-- @param #DATABASE self -- @param #DATABASE self
-- @param #string StaticName -- @param #string StaticName Name of the static object.
-- @return Wrapper.Static#STATIC The found STATIC. -- @return Wrapper.Static#STATIC The found STATIC.
function DATABASE:FindStatic( StaticName ) function DATABASE:FindStatic( StaticName )
local StaticFound = self.STATICS[StaticName] local StaticFound = self.STATICS[StaticName]
return StaticFound return StaticFound
end end
@@ -241,9 +239,8 @@ end
function DATABASE:AddDynamicCargo( Name ) function DATABASE:AddDynamicCargo( Name )
if not self.DYNAMICCARGO[Name] then if not self.DYNAMICCARGO[Name] then
self.DYNAMICCARGO[Name] = DYNAMICCARGO:Register(Name) self.DYNAMICCARGO[Name] = DYNAMICCARGO:Register(Name)
return self.DYNAMICCARGO[Name]
end end
return nil return self.DYNAMICCARGO[Name]
end end
--- Finds a DYNAMICCARGO based on the Dynamic Cargo Name. --- Finds a DYNAMICCARGO based on the Dynamic Cargo Name.
@@ -1582,12 +1579,29 @@ end
-- @param DCS#Airbase airbase Airbase. -- @param DCS#Airbase airbase Airbase.
-- @return #DATABASE self -- @return #DATABASE self
function DATABASE:_RegisterAirbase(airbase) function DATABASE:_RegisterAirbase(airbase)
local IsSyria = UTILS.GetDCSMap() == "Syria" and true or false
local countHSyria = 0
if airbase then if airbase then
-- Get the airbase name. -- Get the airbase name.
local DCSAirbaseName = airbase:getName() 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. -- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
local airbaseID=airbase:getID() local airbaseID=airbase:getID()

View File

@@ -1329,6 +1329,7 @@ function EVENT:onEvent( Event )
end end
Event.IniDCSGroupName = Event.IniUnit and Event.IniUnit.GroupName or "" 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 if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
Event.IniDCSGroupName = Event.IniDCSGroup:getName() Event.IniDCSGroupName = Event.IniDCSGroup:getName()
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName ) Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
@@ -1371,7 +1372,7 @@ function EVENT:onEvent( Event )
-- Scenery -- Scenery
--- ---
Event.IniDCSUnit = Event.initiator 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.IniUnitName = Event.IniDCSUnitName
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator ) Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
Event.IniCategory = Event.IniDCSUnit:getDesc().category Event.IniCategory = Event.IniDCSUnit:getDesc().category
@@ -1473,11 +1474,13 @@ function EVENT:onEvent( Event )
-- SCENERY -- SCENERY
--- ---
Event.TgtDCSUnit = Event.target Event.TgtDCSUnit = Event.target
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() Event.TgtDCSUnitName = Event.TgtDCSUnit.getName and Event.TgtDCSUnit.getName() or nil
Event.TgtUnitName = Event.TgtDCSUnitName if Event.TgtDCSUnitName~=nil then
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target ) Event.TgtUnitName = Event.TgtDCSUnitName
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
end
end 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. --- On after "MarkAdded" event. Triggered when a Marker is added to the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded -- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded
-- @param #MARKEROPS_BASE self -- @param #MARKEROPS_BASE self
-- @param #string From The From state -- @param #string From The From state.
-- @param #string Event The Event called -- @param #string Event The Event called.
-- @param #string To The To state -- @param #string To The To state.
-- @param #string Text The text on the marker -- @param #string Text The text on the marker.
-- @param #table Keywords Table of matching keywords found in the Event text -- @param #table Keywords Table of matching keywords found in the Event text.
-- @param Core.Point#COORDINATE Coord Coordinate of the marker. -- @param Core.Point#COORDINATE Coord Coordinate of the marker.
-- @param #number MarkerID Id of this marker -- @param #number MarkerID Id of this marker.
-- @param #number CoalitionNumber Coalition of the marker creator -- @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. --- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged -- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
-- @param #MARKEROPS_BASE self -- @param #MARKEROPS_BASE self
-- @param #string From The From state -- @param #string From The From state.
-- @param #string Event The Event called -- @param #string Event The Event called.
-- @param #string To The To state -- @param #string To The To state.
-- @param #string Text The text on the marker -- @param #string Text The text on the marker.
-- @param #table Keywords Table of matching keywords found in the Event text -- @param #table Keywords Table of matching keywords found in the Event text.
-- @param Core.Point#COORDINATE Coord Coordinate of the marker. -- @param Core.Point#COORDINATE Coord Coordinate of the marker.
-- @param #number MarkerID Id of this marker -- @param #number MarkerID Id of this marker.
-- @param #number CoalitionNumber Coalition of the marker creator -- @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. --- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted -- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
@@ -167,7 +171,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
if Eventtext~=nil then if Eventtext~=nil then
if self:_MatchTag(Eventtext) then if self:_MatchTag(Eventtext) then
local matchtable = self:_MatchKeywords(Eventtext) local matchtable = self:_MatchKeywords(Eventtext)
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition) self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
end end
end end
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
@@ -177,7 +181,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
if Eventtext~=nil then if Eventtext~=nil then
if self:_MatchTag(Eventtext) then if self:_MatchTag(Eventtext) then
local matchtable = self:_MatchKeywords(Eventtext) local matchtable = self:_MatchKeywords(Eventtext)
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition) self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
end end
end end
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then 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. --- 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 self
-- @param #string MessageText is the text of the Message. -- @param #string Text 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 #number Duration Duration in seconds how long the message text is shown.
-- @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 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. -- @param #boolean ClearScreen (optional) Clear all previous messages if true.
-- @return #MESSAGE -- @return #MESSAGE self
-- @usage -- @usage
-- --
-- -- Create a series of new Messages. -- -- Create a series of new Messages.
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score". -- -- 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". -- -- 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".
-- -- 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" ) -- 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" ) -- 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" ) -- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed 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() ) local self = BASE:Inherit( self, BASE:New() )
self:F( { MessageText, MessageDuration, MessageCategory } )
self:F( { Text, Duration, Category } )
self.MessageType = nil self.MessageType = nil
-- When no MessageCategory is given, we don't show it as a title... -- When no MessageCategory is given, we don't show it as a title...
if MessageCategory and MessageCategory ~= "" then if Category and Category ~= "" then
if MessageCategory:sub( -1 ) ~= "\n" then if Category:sub( -1 ) ~= "\n" then
self.MessageCategory = MessageCategory .. ": " self.MessageCategory = Category .. ": "
else else
self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n" self.MessageCategory = Category:sub( 1, -2 ) .. ":\n"
end end
else else
self.MessageCategory = "" self.MessageCategory = ""
@@ -114,9 +116,9 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen
self.ClearScreen = ClearScreen self.ClearScreen = ClearScreen
end end
self.MessageDuration = MessageDuration or 5 self.MessageDuration = Duration or 5
self.MessageTime = timer.getTime() 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.MessageSent = false
self.MessageGroup = 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} --- 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 #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 -- @return #boolean true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE}, false otherwise
-- @usage -- @usage
-- local MyZone = ZONE:New("Zone1") -- 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} --- 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 #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. -- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE}, false otherwise.
-- @usage -- @usage
-- local MyZone = ZONE:New("Zone1") -- 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} --- 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 #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. -- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise.
-- @usage -- @usage
-- local MyZone = ZONE:New("Zone1") -- 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}. --- 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} -- Will return false if a @{Wrapper.Group#GROUP} is fully in the @{Core.Zone}
-- @param #SET_GROUP self -- @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. -- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise.
-- @usage -- @usage
-- local MyZone = ZONE:New("Zone1") -- 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 -- This could also be achieved with `not SET_GROUP:AnyPartlyInZone(Zone)`, but it's easier for the
-- mission designer to add a dedicated method -- mission designer to add a dedicated method
-- @param #SET_GROUP self -- @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. -- @return #boolean true if no @{Wrapper.Group#GROUP} is inside the @{Core.Zone#ZONE} in any way, false otherwise.
-- @usage -- @usage
-- local MyZone = ZONE:New("Zone1") -- local MyZone = ZONE:New("Zone1")
@@ -1869,7 +1869,7 @@ do
-- That could easily be done with SET_GROUP:ForEachGroupCompletelyInZone(), but this function -- That could easily be done with SET_GROUP:ForEachGroupCompletelyInZone(), but this function
-- provides an easy to use shortcut... -- provides an easy to use shortcut...
-- @param #SET_GROUP self -- @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 -- @return #number the number of GROUPs completely in the Zone
-- @usage -- @usage
-- local MyZone = ZONE:New("Zone1") -- local MyZone = ZONE:New("Zone1")
@@ -1891,7 +1891,7 @@ do
--- Iterate the SET_GROUP and count how many UNITs are completely in the Zone --- Iterate the SET_GROUP and count how many UNITs are completely in the Zone
-- @param #SET_GROUP self -- @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 -- @return #number the number of GROUPs completely in the Zone
-- @usage -- @usage
-- local MyZone = ZONE:New("Zone1") -- local MyZone = ZONE:New("Zone1")
@@ -2706,7 +2706,7 @@ do -- SET_UNIT
--- Check if no element of the SET_UNIT is in the Zone. --- Check if no element of the SET_UNIT is in the Zone.
-- @param #SET_UNIT self -- @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 -- @return #boolean
function SET_UNIT:IsNotInZone( Zone ) function SET_UNIT:IsNotInZone( Zone )
@@ -3746,7 +3746,7 @@ do -- SET_STATIC
--- Check if no element of the SET_STATIC is in the Zone. --- Check if no element of the SET_STATIC is in the Zone.
-- @param #SET_STATIC self -- @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 -- @return #boolean
function SET_STATIC:IsNotInZone( Zone ) function SET_STATIC:IsNotInZone( Zone )
@@ -7936,22 +7936,31 @@ do -- SET_OPSGROUP
--- Handles the OnBirth event for the Set. --- Handles the OnBirth event for the Set.
-- @param #SET_OPSGROUP self -- @param #SET_OPSGROUP self
-- @param Core.Event#EVENTDATA Event Event data. -- @param Core.Event#EVENTDATA Event Event data.
function SET_OPSGROUP:_EventOnBirth( Event ) function SET_OPSGROUP:_EventOnBirth(Event)
--self:F3( { Event } ) --self:F3( { Event } )
if Event.IniDCSUnit and Event.IniDCSGroup then 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. -- group:CountAliveUnits() alternative as this fails for Respawn/Teleport
local CountAliveActive = 0
local groupname, group = self:AddInDatabase( Event ) for index, data in pairs(DCSgroup:getUnits()) do
if data:isExist() and data:isActive() then
if group and group:CountAliveUnits()==DCSgroup:getInitialSize() then CountAliveActive = CountAliveActive + 1
if group and self:IsIncludeObject( group ) then end
self:Add( groupname, group ) 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 end
end end
@@ -8355,14 +8364,17 @@ do -- SET_SCENERY
-- @param #SET_SCENERY self -- @param #SET_SCENERY self
-- @return Core.Point#COORDINATE The center coordinate of all the objects in the set. -- @return Core.Point#COORDINATE The center coordinate of all the objects in the set.
function SET_SCENERY:GetCoordinate() function SET_SCENERY:GetCoordinate()
--[[
local Coordinate = COORDINATE:New({0,0,0}) local Coordinate = COORDINATE:New({0,0,0})
local Item = self:GetRandomSurely() local Item = self:GetRandomSurely()
if Item then if Item then
Coordinate:GetCoordinate() Coordinate:GetCoordinate()
end end
--]]
local Coordinate = self:GetFirst():GetCoordinate()
local x1 = Coordinate.x local x1 = Coordinate.x
local x2 = Coordinate.x local x2 = Coordinate.x

View File

@@ -1226,7 +1226,7 @@ end
-- @param Core.Point#COORDINATE Coordinate The position to spawn from -- @param Core.Point#COORDINATE Coordinate The position to spawn from
-- @return #SPAWN self -- @return #SPAWN self
function SPAWN:InitPositionCoordinate(Coordinate) function SPAWN:InitPositionCoordinate(Coordinate)
self:T2( { self.SpawnTemplatePrefix, Coordinate:GetVec2()} ) --self:T2( { self.SpawnTemplatePrefix, Coordinate:GetVec2()} )
self:InitPositionVec2(Coordinate:GetVec2()) self:InitPositionVec2(Coordinate:GetVec2())
return self return self
end end
@@ -1236,10 +1236,10 @@ end
-- @param DCS#Vec2 Vec2 The position to spawn from -- @param DCS#Vec2 Vec2 The position to spawn from
-- @return #SPAWN self -- @return #SPAWN self
function SPAWN:InitPositionVec2(Vec2) function SPAWN:InitPositionVec2(Vec2)
self:T2( { self.SpawnTemplatePrefix, Vec2} ) --self:T2( { self.SpawnTemplatePrefix, Vec2} )
self.SpawnInitPosition = Vec2 self.SpawnInitPosition = Vec2
self.SpawnFromNewPosition = true self.SpawnFromNewPosition = true
self:T2("MaxGroups:"..self.SpawnMaxGroups) --self:T2("MaxGroups:"..self.SpawnMaxGroups)
for SpawnGroupID = 1, self.SpawnMaxGroups do for SpawnGroupID = 1, self.SpawnMaxGroups do
self:_SetInitialPosition( SpawnGroupID ) self:_SetInitialPosition( SpawnGroupID )
end end
@@ -1334,7 +1334,7 @@ function SPAWN:InitCleanUp( SpawnCleanUpInterval )
self.SpawnCleanUpTimeStamps = {} self.SpawnCleanUpTimeStamps = {}
local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup() 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 ) self.CleanUpScheduler = SCHEDULER:New( self, self._SpawnCleanUpScheduler, {}, 1, SpawnCleanUpInterval, 0.2 )
return self return self
@@ -1367,7 +1367,7 @@ function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY )
local SpawnYIndex = 0 local SpawnYIndex = 0
for SpawnGroupID = 1, self.SpawnMaxGroups do 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].Visible = true
self.SpawnGroups[SpawnGroupID].Spawned = false self.SpawnGroups[SpawnGroupID].Spawned = false
@@ -1391,7 +1391,7 @@ function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY )
self.SpawnGroups[SpawnGroupID].Visible = true self.SpawnGroups[SpawnGroupID].Visible = true
self:HandleEvent( EVENTS.Birth, self._OnBirth ) 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.Crash, self._OnDeadOrCrash )
self:HandleEvent( EVENTS.RemoveUnit, self._OnDeadOrCrash ) self:HandleEvent( EVENTS.RemoveUnit, self._OnDeadOrCrash )
self:HandleEvent( EVENTS.UnitLost, self._OnDeadOrCrash ) self:HandleEvent( EVENTS.UnitLost, self._OnDeadOrCrash )
@@ -1591,7 +1591,7 @@ end
-- @param #string SpawnIndex The index of the group to be spawned. -- @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. -- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth ) function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
--[[
local set = SET_GROUP:New():FilterAlive():FilterPrefixes({self.SpawnTemplatePrefix, self.SpawnAliasPrefix}):FilterOnce() local set = SET_GROUP:New():FilterAlive():FilterPrefixes({self.SpawnTemplatePrefix, self.SpawnAliasPrefix}):FilterOnce()
local aliveunits = 0 local aliveunits = 0
set:ForEachGroupAlive( set:ForEachGroupAlive(
@@ -1602,12 +1602,12 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
if aliveunits ~= self.AliveUnits then if aliveunits ~= self.AliveUnits then
self.AliveUnits = aliveunits self.AliveUnits = aliveunits
self:T2("***** self.AliveUnits accounting failure! Corrected! *****") --self:T2("***** self.AliveUnits accounting failure! Corrected! *****")
end end
set= nil 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 if self:_GetSpawnIndex( SpawnIndex ) then
@@ -1622,12 +1622,12 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate
local SpawnZone = self.SpawnGroups[self.SpawnIndex].SpawnZone local SpawnZone = self.SpawnGroups[self.SpawnIndex].SpawnZone
self:T2( SpawnTemplate.name ) --self:T2( SpawnTemplate.name )
if SpawnTemplate then if SpawnTemplate then
local PointVec3 = POINT_VEC3:New( SpawnTemplate.route.points[1].x, SpawnTemplate.route.points[1].alt, SpawnTemplate.route.points[1].y ) 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 RandomizePosition, then Randomize the formation in the zone band, keeping the template.
if self.SpawnRandomizePosition then if self.SpawnRandomizePosition then
@@ -1639,7 +1639,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
for UnitID = 1, #SpawnTemplate.units do for UnitID = 1, #SpawnTemplate.units do
SpawnTemplate.units[UnitID].x = SpawnTemplate.units[UnitID].x + (RandomVec2.x - CurrentX) SpawnTemplate.units[UnitID].x = SpawnTemplate.units[UnitID].x + (RandomVec2.x - CurrentX)
SpawnTemplate.units[UnitID].y = SpawnTemplate.units[UnitID].y + (RandomVec2.y - CurrentY) 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
end end
@@ -1660,13 +1660,13 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
end end
end end
if (not inZone) then 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() RandomVec2 = SpawnZone:GetRandomVec2()
end end
end end
SpawnTemplate.units[UnitID].x = RandomVec2.x SpawnTemplate.units[UnitID].x = RandomVec2.x
SpawnTemplate.units[UnitID].y = RandomVec2.y 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
end end
@@ -1887,6 +1887,7 @@ end
--- Spawns new groups at varying time intervals. --- 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. -- 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 #SPAWN self
-- @param #number SpawnTime The time interval defined in seconds between each new spawn of new groups. -- @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. -- @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 SpawnTime = SpawnTime or 60
local SpawnTimeVariation = SpawnTimeVariation or 0.5 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 if SpawnTime ~= nil and SpawnTimeVariation ~= nil then
local InitialDelay = 0 local InitialDelay = 0
if WithDelay or self.DelayOnOff == true then if WithDelay or self.DelayOnOff == true then
@@ -2024,7 +2033,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Get position of airbase. -- Get position of airbase.
local PointVec3 = SpawnAirbase:GetCoordinate() local PointVec3 = SpawnAirbase:GetCoordinate()
self:T2( PointVec3 ) --self:T2( PointVec3 )
-- Set take off type. Default is hot. -- Set take off type. Default is hot.
Takeoff = Takeoff or SPAWN.Takeoff.Hot Takeoff = Takeoff or SPAWN.Takeoff.Hot
@@ -2053,7 +2062,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
--self:F( { GroupAlive = GroupAlive } ) --self:F( { GroupAlive = GroupAlive } )
-- Debug output -- Debug output
self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } ) --self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
-- Template group, unit and its attributes. -- Template group, unit and its attributes.
local TemplateGroup = GROUP:FindByName( self.SpawnTemplatePrefix ) local TemplateGroup = GROUP:FindByName( self.SpawnTemplatePrefix )
@@ -2102,7 +2111,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Check if we spawn on ground. -- Check if we spawn on ground.
local spawnonground = not (Takeoff == SPAWN.Takeoff.Air) 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. -- Check where we actually spawn if we spawn on ground.
local spawnonship = false local spawnonship = false
@@ -2156,7 +2165,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Number of free parking spots at the airbase. -- Number of free parking spots at the airbase.
if spawnonship or spawnonfarp or spawnonrunway then if spawnonship or spawnonfarp or spawnonrunway then
-- These places work procedural and have some kind of build in queue ==> Less effort. -- 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 ) nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true ) spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
--[[ --[[
@@ -2169,18 +2178,18 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
if ishelo then if ishelo then
if termtype == nil then if termtype == nil then
-- Helo is spawned. Try exclusive helo spots first. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
if nfree < nunits then if nfree < nunits then
-- Not enough helo ports. Let's try also other terminal types. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
end end
else else
-- No terminal type specified. We try all spots except shelters. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
end end
@@ -2189,23 +2198,23 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
if termtype == nil then if termtype == nil then
if isbomber or istransport or istanker or isawacs then if isbomber or istransport or istanker or isawacs then
-- First we fill the potentially bigger spots. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
if nfree < nunits then if nfree < nunits then
-- Now we try the smaller ones. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
end end
else 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
end end
else else
-- Terminal type explicitly given. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
end end
@@ -2215,12 +2224,12 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Debug: Get parking data. -- Debug: Get parking data.
--[[ --[[
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype) 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 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)) SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
end 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. -- 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 SpawnTemplate.parked = true
for UnitID = 1, nunits do 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. -- Template of the current unit.
local UnitTemplate = SpawnTemplate.units[UnitID] 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. -- Ships and FARPS seem to have a build in queue.
if spawnonship or spawnonfarp or spawnonrunway then 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. -- Spawn on ship. We take only the position of the ship.
SpawnTemplate.units[UnitID].x = PointVec3.x -- TX SpawnTemplate.units[UnitID].x = PointVec3.x -- TX
@@ -2342,7 +2351,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
else 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. -- Get coordinates of parking spot.
SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x
@@ -2354,7 +2363,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
else 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. -- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
SpawnTemplate.units[UnitID].x = TX SpawnTemplate.units[UnitID].x = TX
@@ -2371,9 +2380,9 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
end end
-- Debug output. -- 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 = %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( 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( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
end end
end end
@@ -2451,10 +2460,10 @@ function SPAWN:SpawnAtParkingSpot( Airbase, Spots, Takeoff )
-- Get parking spot data. -- Get parking spot data.
local spot = Airbase:GetParkingSpotData( TerminalID ) local spot = Airbase:GetParkingSpotData( TerminalID )
self:T2( { spot = spot } ) --self:T2( { spot = spot } )
if spot and spot.Free then 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 ) table.insert( Parkingdata, spot )
end end
@@ -2486,7 +2495,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
-- Get position of airbase. -- Get position of airbase.
local PointVec3 = SpawnAirbase:GetCoordinate() local PointVec3 = SpawnAirbase:GetCoordinate()
self:T2( PointVec3 ) --self:T2( PointVec3 )
-- Set take off type. Default is hot. -- Set take off type. Default is hot.
local Takeoff = SPAWN.Takeoff.Cold local Takeoff = SPAWN.Takeoff.Cold
@@ -2502,7 +2511,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
local GroupAlive = self:GetGroupFromIndex( SpawnIndex ) local GroupAlive = self:GetGroupFromIndex( SpawnIndex )
-- Debug output -- Debug output
self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } ) --self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
-- Template group, unit and its attributes. -- Template group, unit and its attributes.
local TemplateGroup = GROUP:FindByName( self.SpawnTemplatePrefix ) local TemplateGroup = GROUP:FindByName( self.SpawnTemplatePrefix )
@@ -2546,7 +2555,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
-- Check if we spawn on ground. -- Check if we spawn on ground.
local spawnonground = not (Takeoff == SPAWN.Takeoff.Air) 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. -- Check where we actually spawn if we spawn on ground.
local spawnonship = false local spawnonship = false
@@ -2588,7 +2597,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
-- Number of free parking spots at the airbase. -- Number of free parking spots at the airbase.
if spawnonship or spawnonfarp or spawnonrunway then if spawnonship or spawnonfarp or spawnonrunway then
-- These places work procedural and have some kind of build in queue ==> Less effort. -- 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 ) nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true ) spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
--[[ --[[
@@ -2601,18 +2610,18 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
if ishelo then if ishelo then
if termtype == nil then if termtype == nil then
-- Helo is spawned. Try exclusive helo spots first. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
if nfree < nunits then if nfree < nunits then
-- Not enough helo ports. Let's try also other terminal types. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
end end
else else
-- No terminal type specified. We try all spots except shelters. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
end 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. -- TODO: Some attributes are "Helicopters", "Bombers", "Transports", "Battleplanes". Need to check it out.
if isbomber or istransport then if isbomber or istransport then
-- First we fill the potentially bigger spots. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
if nfree < nunits then if nfree < nunits then
-- Now we try the smaller ones. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
end end
else 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
end end
else else
-- Terminal type explicitly given. -- 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 ) spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
nfree = #spots nfree = #spots
end end
@@ -2650,12 +2659,12 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
-- Debug: Get parking data. -- Debug: Get parking data.
--[[ --[[
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype) 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 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)) SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
end 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. -- 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. -- Ships and FARPS seem to have a build in queue.
if spawnonship or spawnonfarp or spawnonrunway then 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. -- Spawn on ship. We take only the position of the ship.
SpawnTemplate.units[UnitID].x = PointVec3.x -- TX SpawnTemplate.units[UnitID].x = PointVec3.x -- TX
@@ -2742,7 +2751,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
else 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. -- Get coordinates of parking spot.
SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x
@@ -2754,7 +2763,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
else 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. -- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
SpawnTemplate.units[UnitID].x = TX SpawnTemplate.units[UnitID].x = TX
@@ -2771,9 +2780,9 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
end end
-- Debug output. -- 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 = %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( 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( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
end end
end end
@@ -2871,7 +2880,7 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
--self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } ) --self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } )
local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 ) local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 )
self:T2( PointVec3 ) --self:T2( PointVec3 )
if SpawnIndex then if SpawnIndex then
else else
@@ -2884,7 +2893,7 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
if SpawnTemplate then 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 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 if SpawnTemplate.CategoryID ~= Group.Category.SHIP then
SpawnTemplate.units[UnitID].alt = Vec3.y or TemplateHeight SpawnTemplate.units[UnitID].alt = Vec3.y or TemplateHeight
end 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 end
SpawnTemplate.route.points[1].x = Vec3.x SpawnTemplate.route.points[1].x = Vec3.x
SpawnTemplate.route.points[1].y = Vec3.z SpawnTemplate.route.points[1].y = Vec3.z
@@ -3168,10 +3177,10 @@ function SPAWN:SpawnGroupName( SpawnIndex )
if SpawnIndex then if SpawnIndex then
local SpawnName = string.format( '%s#%03d', SpawnPrefix, SpawnIndex ) local SpawnName = string.format( '%s#%03d', SpawnPrefix, SpawnIndex )
self:T2( SpawnName ) --self:T2( SpawnName )
return SpawnName return SpawnName
else else
self:T2( SpawnPrefix ) --self:T2( SpawnPrefix )
return SpawnPrefix return SpawnPrefix
end end
@@ -3499,7 +3508,7 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
if SpawnInitKeepUnitIFF == false then if SpawnInitKeepUnitIFF == false then
UnitPrefix, Rest = string.match( SpawnTemplate.units[UnitID].name, "^([^#]+)#?" ):gsub( "^%s*(.-)%s*$", "%1" ) UnitPrefix, Rest = string.match( SpawnTemplate.units[UnitID].name, "^([^#]+)#?" ):gsub( "^%s*(.-)%s*$", "%1" )
SpawnTemplate.units[UnitID].name = string.format( '%s#%03d-%02d', UnitPrefix, SpawnIndex, UnitID ) SpawnTemplate.units[UnitID].name = string.format( '%s#%03d-%02d', UnitPrefix, SpawnIndex, UnitID )
self:T2( { UnitPrefix, Rest } ) --self:T2( { UnitPrefix, Rest } )
--else --else
--UnitPrefix=SpawnTemplate.units[UnitID].name --UnitPrefix=SpawnTemplate.units[UnitID].name
end end
@@ -3713,7 +3722,7 @@ function SPAWN:_RandomizeRoute( SpawnIndex )
SpawnTemplate.route.points[t].alt = nil SpawnTemplate.route.points[t].alt = nil
end 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
end end
@@ -3756,15 +3765,15 @@ end
-- @param #number SpawnIndex -- @param #number SpawnIndex
-- @return #SPAWN self -- @return #SPAWN self
function SPAWN:_SetInitialPosition( SpawnIndex ) function SPAWN:_SetInitialPosition( SpawnIndex )
self:T2( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } ) --self:T2( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } )
if self.SpawnFromNewPosition then if self.SpawnFromNewPosition then
self:T2( "Preparing Spawn at Vec2 ", self.SpawnInitPosition ) --self:T2( "Preparing Spawn at Vec2 ", self.SpawnInitPosition )
local SpawnVec2 = self.SpawnInitPosition local SpawnVec2 = self.SpawnInitPosition
self:T2( { SpawnVec2 = SpawnVec2 } ) --self:T2( { SpawnVec2 = SpawnVec2 } )
local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate 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].x = SpawnTemplate.route.points[1].x or 0
SpawnTemplate.route.points[1].y = SpawnTemplate.route.points[1].y 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 for UnitID = 1, #SpawnTemplate.units do
local UnitTemplate = SpawnTemplate.units[UnitID] 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 SX = UnitTemplate.x
local SY = UnitTemplate.y local SY = UnitTemplate.y
local BX = SpawnTemplate.route.points[1].x local BX = SpawnTemplate.route.points[1].x
@@ -3789,7 +3798,7 @@ function SPAWN:_SetInitialPosition( SpawnIndex )
UnitTemplate.y = TY UnitTemplate.y = TY
-- TODO: Manage altitude based on landheight... -- TODO: Manage altitude based on landheight...
-- SpawnTemplate.units[UnitID].alt = SpawnVec2: -- 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 end
SpawnTemplate.route.points[1].x = SpawnVec2.x SpawnTemplate.route.points[1].x = SpawnVec2.x
@@ -3812,26 +3821,26 @@ function SPAWN:_RandomizeZones( SpawnIndex )
if self.SpawnRandomizeZones then if self.SpawnRandomizeZones then
local SpawnZone = nil -- Core.Zone#ZONE_BASE local SpawnZone = nil -- Core.Zone#ZONE_BASE
while not SpawnZone do while not SpawnZone do
self:T2( { SpawnZoneTableCount = #self.SpawnZoneTable, self.SpawnZoneTable } ) --self:T2( { SpawnZoneTableCount = #self.SpawnZoneTable, self.SpawnZoneTable } )
local ZoneID = math.random( #self.SpawnZoneTable ) local ZoneID = math.random( #self.SpawnZoneTable )
self:T2( ZoneID ) --self:T2( ZoneID )
SpawnZone = self.SpawnZoneTable[ZoneID]:GetZoneMaybe() SpawnZone = self.SpawnZoneTable[ZoneID]:GetZoneMaybe()
end end
self:T2( "Preparing Spawn in Zone", SpawnZone:GetName() ) --self:T2( "Preparing Spawn in Zone", SpawnZone:GetName() )
local SpawnVec2 = SpawnZone:GetRandomVec2() local SpawnVec2 = SpawnZone:GetRandomVec2()
self:T2( { SpawnVec2 = SpawnVec2 } ) --self:T2( { SpawnVec2 = SpawnVec2 } )
local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate
self.SpawnGroups[SpawnIndex].SpawnZone = SpawnZone self.SpawnGroups[SpawnIndex].SpawnZone = SpawnZone
self:T2( { Route = SpawnTemplate.route } ) --self:T2( { Route = SpawnTemplate.route } )
for UnitID = 1, #SpawnTemplate.units do for UnitID = 1, #SpawnTemplate.units do
local UnitTemplate = SpawnTemplate.units[UnitID] 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 SX = UnitTemplate.x
local SY = UnitTemplate.y local SY = UnitTemplate.y
local BX = SpawnTemplate.route.points[1].x local BX = SpawnTemplate.route.points[1].x
@@ -3842,7 +3851,7 @@ function SPAWN:_RandomizeZones( SpawnIndex )
UnitTemplate.y = TY UnitTemplate.y = TY
-- TODO: Manage altitude based on landheight... -- TODO: Manage altitude based on landheight...
-- SpawnTemplate.units[UnitID].alt = SpawnVec2: -- 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 end
SpawnTemplate.x = SpawnVec2.x SpawnTemplate.x = SpawnVec2.x
SpawnTemplate.y = SpawnVec2.y SpawnTemplate.y = SpawnVec2.y
@@ -3897,11 +3906,11 @@ end
-- @param #number SpawnIndex Spawn index. -- @param #number SpawnIndex Spawn index.
-- @return #number self.SpawnIndex -- @return #number self.SpawnIndex
function SPAWN:_GetSpawnIndex( 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.SpawnMaxGroups == 0) or (SpawnIndex <= self.SpawnMaxGroups) then
if (self.SpawnMaxUnitsAlive == 0) or (self.AliveUnits + #self.SpawnTemplate.units <= self.SpawnMaxUnitsAlive) or self.UnControlled == true 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 if SpawnIndex and SpawnIndex >= self.SpawnCount + 1 then
self.SpawnCount = self.SpawnCount + 1 self.SpawnCount = self.SpawnCount + 1
SpawnIndex = self.SpawnCount SpawnIndex = self.SpawnCount
@@ -3932,22 +3941,57 @@ function SPAWN:_OnBirth( EventData )
if SpawnGroup then if SpawnGroup then
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group! 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 if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
self.AliveUnits = self.AliveUnits + 1 self.AliveUnits = self.AliveUnits + 1
self:T2( "Alive Units: " .. self.AliveUnits ) --self:T2( "Alive Units: " .. self.AliveUnits )
end end
end end
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 #SPAWN self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function SPAWN:_OnDeadOrCrash( EventData ) function SPAWN:_OnDeadOrCrash( EventData )
self:T2( "Dead or crash event ID "..tostring(EventData.id or 0)) --self:I( "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 for "..tostring(EventData.IniUnitName or "none") )
--if EventData.id == EVENTS.Dead then return end --if EventData.id == EVENTS.Dead then return end
@@ -3959,12 +4003,14 @@ function SPAWN:_OnDeadOrCrash( EventData )
local EventPrefix = self:_GetPrefixFromGroupName(unit.GroupName) local EventPrefix = self:_GetPrefixFromGroupName(unit.GroupName)
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group! if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
self:T2( { "Dead event: " .. EventPrefix } ) --self:I(string.format("EventPrefix = %s | SpawnAliasPrefix = %s | Old AliveUnits = %d",EventPrefix or "",self.SpawnAliasPrefix or "",self.AliveUnits or 0))
self:T2(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 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 end
self:T2( "New Alive Units: " .. self.AliveUnits )
end end
end end
end end
@@ -3980,9 +4026,9 @@ function SPAWN:_OnTakeOff( EventData )
if SpawnGroup then if SpawnGroup then
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group! 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 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 ) SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", false )
end end
end end
@@ -4000,13 +4046,13 @@ function SPAWN:_OnLand( EventData )
if SpawnGroup then if SpawnGroup then
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group! 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 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. -- TODO: Check if this is the last unit of the group that lands.
SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", true ) SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", true )
if self.RepeatOnLanding then if self.RepeatOnLanding then
local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup )
self:T2( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) --self:T2( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } )
-- self:ReSpawn( 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 -- 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. -- 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 if SpawnGroup then
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup ) local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group! 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 if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
-- todo: test if on the runway -- todo: test if on the runway
local Landed = SpawnGroup:GetState( SpawnGroup, "Spawn_Landed" ) local Landed = SpawnGroup:GetState( SpawnGroup, "Spawn_Landed" )
if Landed and self.RepeatOnEngineShutDown then if Landed and self.RepeatOnEngineShutDown then
local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup ) local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup )
self:T2( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } ) --self:T2( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } )
-- self:ReSpawn( 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 -- 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 ) SCHEDULER:New( nil, self.ReSpawn, { self, SpawnGroupIndex }, 3 )
@@ -4064,7 +4110,7 @@ function SPAWN:_SpawnCleanUpScheduler()
--self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } ) --self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } )
local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup() local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup()
self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } ) --self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
local IsHelo = false local IsHelo = false
@@ -4081,7 +4127,7 @@ function SPAWN:_SpawnCleanUpScheduler()
self.SpawnCleanUpTimeStamps[SpawnUnitName] = self.SpawnCleanUpTimeStamps[SpawnUnitName] or {} self.SpawnCleanUpTimeStamps[SpawnUnitName] = self.SpawnCleanUpTimeStamps[SpawnUnitName] or {}
local Stamp = self.SpawnCleanUpTimeStamps[SpawnUnitName] local Stamp = self.SpawnCleanUpTimeStamps[SpawnUnitName]
self:T2( { SpawnUnitName, Stamp } ) --self:T2( { SpawnUnitName, Stamp } )
if Stamp.Vec2 then if Stamp.Vec2 then
if (SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1) or IsHelo 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 (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 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 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 ) --self:ReSpawn( SpawnCursor )
SCHEDULER:New( nil, self.ReSpawn, { self, SpawnCursor }, 3 ) SCHEDULER:New( nil, self.ReSpawn, { self, SpawnCursor }, 3 )
Stamp.Vec2 = nil Stamp.Vec2 = nil
@@ -4118,7 +4164,7 @@ function SPAWN:_SpawnCleanUpScheduler()
SpawnGroup, SpawnCursor = self:GetNextAliveGroup( SpawnCursor ) SpawnGroup, SpawnCursor = self:GetNextAliveGroup( SpawnCursor )
self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } ) --self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
end end

View File

@@ -535,12 +535,6 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
-- Name of the spawned static. -- Name of the spawned static.
Template.name = self.InitStaticName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex) 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. -- Add static to the game.
local Static=nil --DCS#StaticObject local Static=nil --DCS#StaticObject
@@ -577,12 +571,28 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
self:T("Spawning Static") self:T("Spawning Static")
self:T2({Template=Template}) self:T2({Template=Template})
Static=coalition.addStaticObject(CountryID, 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 end
-- Add and register the new static.
local mystatic=_DATABASE:AddStatic(Template.name)
-- If there is a SpawnFunction hook defined, call it. -- If there is a SpawnFunction hook defined, call it.
if self.SpawnFunctionHook then if self.SpawnFunctionHook then
-- delay calling this for .3 seconds so that it hopefully comes after the BIRTH event of the group. -- 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 end
return mystatic 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.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.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.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. --- The world singleton contains functions centered around two different but extremely useful functions.
-- * Events and event handlers are all governed within world. -- * Events and event handlers are all governed within world.
@@ -132,6 +133,36 @@ do -- world
-- @function [parent=#world] getAirbases -- @function [parent=#world] getAirbases
-- @param #number coalitionId The coalition side number ID. Default is all airbases are returned. -- @param #number coalitionId The coalition side number ID. Default is all airbases are returned.
-- @return #table Table of DCS airbase objects. -- @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 end -- world
@@ -407,7 +438,7 @@ do -- coalition
-- @param #table groupData Group data table. -- @param #table groupData Group data table.
-- @return DCS#Group The spawned Group object. -- @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 -- @function [parent=#coalition] addStaticObject
-- @param #number countryId Id of the country. -- @param #number countryId Id of the country.
-- @param #table groupData Group data table. -- @param #table groupData Group data table.
@@ -420,6 +451,7 @@ end -- coalition
do -- Types do -- Types
--- Descriptors.
-- @type Desc -- @type Desc
-- @field #number speedMax0 Max speed in meters/second at zero altitude. -- @field #number speedMax0 Max speed in meters/second at zero altitude.
-- @field #number massEmpty Empty mass in kg. -- @field #number massEmpty Empty mass in kg.
@@ -1013,14 +1045,16 @@ do -- Spot
end -- Spot end -- Spot
do -- Controller 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. --- 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: -- This class has 2 types of functions:
-- --
-- * Tasks -- * 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 -- @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. --- Enables and disables the controller.
-- Note: Now it works only for ground / naval groups! -- Note: Now it works only for ground / naval groups!
@@ -1079,18 +1113,18 @@ do -- Controller
-- Detection -- Detection
--- Enum contains identifiers of surface types. --- Enum containing detection types.
-- @type Controller.Detection -- @type Controller.Detection
-- @field VISUAL -- @field #number VISUAL Visual detection. Numeric value 1.
-- @field OPTIC -- @field #number OPTIC Optical detection. Numeric value 2.
-- @field RADAR -- @field #number RADAR Radar detection. Numeric value 4.
-- @field IRST -- @field #number IRST Infra-red search and track detection. Numeric value 8.
-- @field RWR -- @field #number RWR Radar Warning Receiver detection. Numeric value 16.
-- @field DLINK -- @field #number DLINK Data link detection. Numeric value 32.
--- Detected target. --- Detected target.
-- @type DetectedTarget -- @type Controller.DetectedTarget
-- @field Wrapper.Object#Object object The target -- @field DCS#Object object The target
-- @field #boolean visible The target is visible -- @field #boolean visible The target is visible
-- @field #boolean type The target type is known -- @field #boolean type The target type is known
-- @field #boolean distance Distance to the target 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 -- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
-- @return #boolean detected True if the target is detected. -- @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 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 #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 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. -- @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 do -- Unit
--- Unit.
-- @type Unit -- @type Unit
-- @extends #CoalitionObject -- @extends #CoalitionObject
-- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically. -- @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 -- ### Author: FlightControl - Framework Design & Programming
-- ### Refactoring to use the Runway auto-detection: Applevangelist -- ### Refactoring to use the Runway auto-detection: Applevangelist
-- @date August 2022 -- @date August 2022
-- Last Update Nov 2023 -- Last Update Oct 2024
-- --
-- === -- ===
-- --
@@ -721,14 +721,18 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
if NotInRunwayZone then if NotInRunwayZone then
local Taxi = Client:GetState( self, "Taxi" )
if IsOnGround then if IsOnGround then
local Taxi = Client:GetState( self, "Taxi" )
self:T( Taxi ) self:T( Taxi )
if Taxi == false then if Taxi == false then
local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed ) local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed )
Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " .. Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " ..
Velocity:ToString() , 20, "ATC" ) Velocity:ToString() , 20, "ATC" )
Client:SetState( self, "Taxi", true ) Client:SetState( self, "Taxi", true )
Client:SetState( self, "Speeding", false )
Client:SetState( self, "Warnings", 0 )
end end
-- TODO: GetVelocityKMH function usage -- TODO: GetVelocityKMH function usage
@@ -737,7 +741,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
local IsAboveRunway = Client:IsAboveRunway() local IsAboveRunway = Client:IsAboveRunway()
self:T( {IsAboveRunway, IsOnGround, Velocity:Get() }) self:T( {IsAboveRunway, IsOnGround, Velocity:Get() })
if IsOnGround then if IsOnGround and not Taxi then
local Speeding = false local Speeding = false
if AirbaseMeta.MaximumKickSpeed then if AirbaseMeta.MaximumKickSpeed then
if Velocity:Get() > AirbaseMeta.MaximumKickSpeed then if Velocity:Get() > AirbaseMeta.MaximumKickSpeed then
@@ -749,15 +753,17 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
end end
end end
if Speeding == true then if Speeding == true then
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() .. --MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
" has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll() -- " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
Client:Destroy() --Client:Destroy()
Client:SetState( self, "Speeding", false ) Client:SetState( self, "Speeding", true )
Client:SetState( self, "Warnings", 0 ) 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
end end
if IsOnGround then if IsOnGround then
local Speeding = false local Speeding = false
@@ -1035,23 +1041,23 @@ end
-- The following airbases are monitored at the Nevada region. -- The following airbases are monitored at the Nevada region.
-- Use the @{Wrapper.Airbase#AIRBASE.Nevada} enumeration to select the airbases to be monitored. -- Use the @{Wrapper.Airbase#AIRBASE.Nevada} enumeration to select the airbases to be monitored.
-- --
-- * `AIRBASE.Nevada.Beatty_Airport` -- * `AIRBASE.Nevada.Beatty`
-- * `AIRBASE.Nevada.Boulder_City_Airport` -- * `AIRBASE.Nevada.Boulder_City`
-- * `AIRBASE.Nevada.Creech_AFB` -- * `AIRBASE.Nevada.Creech`
-- * `AIRBASE.Nevada.Echo_Bay` -- * `AIRBASE.Nevada.Echo_Bay`
-- * `AIRBASE.Nevada.Groom_Lake_AFB` -- * `AIRBASE.Nevada.Groom_Lake`
-- * `AIRBASE.Nevada.Henderson_Executive_Airport` -- * `AIRBASE.Nevada.Henderson_Executive`
-- * `AIRBASE.Nevada.Jean_Airport` -- * `AIRBASE.Nevada.Jean`
-- * `AIRBASE.Nevada.Laughlin_Airport` -- * `AIRBASE.Nevada.Laughlin`
-- * `AIRBASE.Nevada.Lincoln_County` -- * `AIRBASE.Nevada.Lincoln_County`
-- * `AIRBASE.Nevada.McCarran_International_Airport` -- * `AIRBASE.Nevada.McCarran_International`
-- * `AIRBASE.Nevada.Mesquite` -- * `AIRBASE.Nevada.Mesquite`
-- * `AIRBASE.Nevada.Mina_Airport` -- * `AIRBASE.Nevada.Mina`
-- * `AIRBASE.Nevada.Nellis_AFB` -- * `AIRBASE.Nevada.Nellis`
-- * `AIRBASE.Nevada.North_Las_Vegas` -- * `AIRBASE.Nevada.North_Las_Vegas`
-- * `AIRBASE.Nevada.Pahute_Mesa_Airstrip` -- * `AIRBASE.Nevada.Pahute_Mesa`
-- * `AIRBASE.Nevada.Tonopah_Airport` -- * `AIRBASE.Nevada.Tonopah`
-- * `AIRBASE.Nevada.Tonopah_Test_Range_Airfield` -- * `AIRBASE.Nevada.Tonopah_Test_Range`
-- --
-- # Installation -- # Installation
-- --
@@ -1088,10 +1094,10 @@ end
-- --
-- -- Monitor specific airbases. -- -- Monitor specific airbases.
-- ATC_Ground = ATC_GROUND_NEVADA:New( -- ATC_Ground = ATC_GROUND_NEVADA:New(
-- { AIRBASE.Nevada.Laughlin_Airport, -- { AIRBASE.Nevada.Laughlin,
-- AIRBASE.Nevada.Lincoln_County, -- AIRBASE.Nevada.Lincoln_County,
-- AIRBASE.Nevada.North_Las_Vegas, -- 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. -- The following airbases are monitored at the PersianGulf region.
-- Use the @{Wrapper.Airbase#AIRBASE.PersianGulf} enumeration to select the airbases to be monitored. -- Use the @{Wrapper.Airbase#AIRBASE.PersianGulf} enumeration to select the airbases to be monitored.
-- --
-- * `AIRBASE.PersianGulf.Abu_Musa_Island_Airport` -- * `AIRBASE.PersianGulf.Abu_Musa_Island`
-- * `AIRBASE.PersianGulf.Al_Dhafra_AB` -- * `AIRBASE.PersianGulf.Al_Dhafra_AFB`
-- * `AIRBASE.PersianGulf.Al_Maktoum_Intl` -- * `AIRBASE.PersianGulf.Al_Maktoum_Intl`
-- * `AIRBASE.PersianGulf.Al_Minhad_AB` -- * `AIRBASE.PersianGulf.Al_Minhad_AFB`
-- * `AIRBASE.PersianGulf.Bandar_Abbas_Intl` -- * `AIRBASE.PersianGulf.Bandar_Abbas_Intl`
-- * `AIRBASE.PersianGulf.Bandar_Lengeh` -- * `AIRBASE.PersianGulf.Bandar_Lengeh`
-- * `AIRBASE.PersianGulf.Dubai_Intl` -- * `AIRBASE.PersianGulf.Dubai_Intl`
-- * `AIRBASE.PersianGulf.Fujairah_Intl` -- * `AIRBASE.PersianGulf.Fujairah_Intl`
-- * `AIRBASE.PersianGulf.Havadarya` -- * `AIRBASE.PersianGulf.Havadarya`
-- * `AIRBASE.PersianGulf.Kerman_Airport` -- * `AIRBASE.PersianGulf.Kerman`
-- * `AIRBASE.PersianGulf.Khasab` -- * `AIRBASE.PersianGulf.Khasab`
-- * `AIRBASE.PersianGulf.Lar_Airbase` -- * `AIRBASE.PersianGulf.Lar`
-- * `AIRBASE.PersianGulf.Qeshm_Island` -- * `AIRBASE.PersianGulf.Qeshm_Island`
-- * `AIRBASE.PersianGulf.Sharjah_Intl` -- * `AIRBASE.PersianGulf.Sharjah_Intl`
-- * `AIRBASE.PersianGulf.Shiraz_International_Airport` -- * `AIRBASE.PersianGulf.Shiraz_Intl`
-- * `AIRBASE.PersianGulf.Sir_Abu_Nuayr` -- * `AIRBASE.PersianGulf.Sir_Abu_Nuayr`
-- * `AIRBASE.PersianGulf.Sirri_Island` -- * `AIRBASE.PersianGulf.Sirri_Island`
-- * `AIRBASE.PersianGulf.Tunb_Island_AFB` -- * `AIRBASE.PersianGulf.Tunb_Island_AFB`
-- * `AIRBASE.PersianGulf.Tunb_Kochak` -- * `AIRBASE.PersianGulf.Tunb_Kochak`
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel_Airport` -- * `AIRBASE.PersianGulf.Sas_Al_Nakheel`
-- * `AIRBASE.PersianGulf.Bandar_e_Jask_airfield` -- * `AIRBASE.PersianGulf.Bandar_e_Jask`
-- * `AIRBASE.PersianGulf.Abu_Dhabi_International_Airport` -- * `AIRBASE.PersianGulf.Abu_Dhabi_Intl`
-- * `AIRBASE.PersianGulf.Al_Bateen_Airport` -- * `AIRBASE.PersianGulf.Al_Bateen`
-- * `AIRBASE.PersianGulf.Kish_International_Airport` -- * `AIRBASE.PersianGulf.Kish_Intl`
-- * `AIRBASE.PersianGulf.Al_Ain_International_Airport` -- * `AIRBASE.PersianGulf.Al_Ain_Intl`
-- * `AIRBASE.PersianGulf.Lavan_Island_Airport` -- * `AIRBASE.PersianGulf.Lavan_Island`
-- * `AIRBASE.PersianGulf.Jiroft_Airport` -- * `AIRBASE.PersianGulf.Jiroft`
-- --
-- # Installation -- # Installation
-- --
@@ -1391,8 +1397,8 @@ end
-- AirbasePoliceCaucasus = ATC_GROUND_PERSIANGULF:New() -- AirbasePoliceCaucasus = ATC_GROUND_PERSIANGULF:New()
-- --
-- ATC_Ground = ATC_GROUND_PERSIANGULF:New( -- ATC_Ground = ATC_GROUND_PERSIANGULF:New(
-- { AIRBASE.PersianGulf.Kerman_Airport, -- { AIRBASE.PersianGulf.Kerman,
-- AIRBASE.PersianGulf.Al_Minhad_AB -- AIRBASE.PersianGulf.Al_Minhad_AFB
-- } -- }
-- ) -- )
-- --

View File

@@ -652,7 +652,7 @@ do -- DETECTION_BASE
if DetectedObject:isExist() then 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, DetectedObject,
self.DetectVisual, self.DetectVisual,
self.DetectOptical, self.DetectOptical,

View File

@@ -22,7 +22,7 @@
-- @module Functional.Mantis -- @module Functional.Mantis
-- @image Functional.Mantis.jpg -- @image Functional.Mantis.jpg
-- --
-- Last Update: July 2024 -- Last Update: Sep 2024
------------------------------------------------------------------------- -------------------------------------------------------------------------
--- **MANTIS** class, extends Core.Base#BASE --- **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 Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
-- @field #string Radar Radar typename on unit level (used as key) -- @field #string Radar Radar typename on unit level (used as key)
MANTIS.SamDataCH = { MANTIS.SamDataCH = {
-- units from CH (Military Assets by Currenthill) -- units from CH (Military Assets by Currenthill)
-- https://www.currenthill.com/ -- https://www.currenthill.com/
-- group name MUST contain CHM to ID launcher type correctly! -- group name MUST contain CHM to ID launcher type correctly!
["2S38 CH"] = { Range=8, Blindspot=0.5, Height=6, Type="Short", Radar="2S38" }, ["2S38 CHM"] = { Range=8, Blindspot=0.5, Height=6, Type="Short", Radar="2S38" },
["PantsirS1 CH"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" }, ["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
["PantsirS2 CH"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" }, ["PantsirS2 CHM"] = { 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" }, ["PGL-625 CHM"] = { 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" }, ["HQ-17A CHM"] = { 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" }, ["M903PAC2 CHM"] = { 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" }, ["M903PAC3 CHM"] = { Range=120, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
["TorM2 CH"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" }, ["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
["TorM2K CH"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" }, ["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
["TorM2M CH"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" }, ["TorM2M CHM"] = { 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-AMRAAMER CHM"] = { 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" }, ["NASAMS3-AIM9X2 CHM"] = { 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" }, ["C-RAM CHM"] = { 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" }, ["PGZ-09 CHM"] = { 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-9M100 CHM"] = { 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" }, ["S350-9M96D CHM"] = { 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" }, ["LAV-AD CHM"] = { 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" }, ["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 -- TODO Version
-- @field #string version -- @field #string version
self.version="0.8.18" self.version="0.8.20"
self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
--- FSM Functions --- --- FSM Functions ---
@@ -1396,7 +1419,7 @@ do
-- @return #string type Long, medium or short range -- @return #string type Long, medium or short range
-- @return #number blind "blind" spot -- @return #number blind "blind" spot
function MANTIS:_GetSAMDataFromUnits(grpname,mod,sma,chm) function MANTIS:_GetSAMDataFromUnits(grpname,mod,sma,chm)
self:T(self.lid.."_GetSAMRangeFromUnits") self:T(self.lid.."_GetSAMDataFromUnits")
local found = false local found = false
local range = self.checkradius local range = self.checkradius
local height = 3000 local height = 3000
@@ -1449,7 +1472,7 @@ do
-- @return #string type Long, medium or short range -- @return #string type Long, medium or short range
-- @return #number blind "blind" spot -- @return #number blind "blind" spot
function MANTIS:_GetSAMRange(grpname) function MANTIS:_GetSAMRange(grpname)
self:T(self.lid.."_GetSAMRange") self:T(self.lid.."_GetSAMRange for "..tostring(grpname))
local range = self.checkradius local range = self.checkradius
local height = 3000 local height = 3000
local type = MANTIS.SamType.MEDIUM local type = MANTIS.SamType.MEDIUM
@@ -1466,9 +1489,9 @@ do
elseif string.find(grpname,"CHM",1,true) then elseif string.find(grpname,"CHM",1,true) then
CHMod = true CHMod = true
end end
if self.automode then --if self.automode then
for idx,entry in pairs(self.SamData) do for idx,entry in pairs(self.SamData) do
--self:I("ID = " .. idx) self:T("ID = " .. idx)
if string.find(grpname,idx,1,true) then if string.find(grpname,idx,1,true) then
local _entry = entry -- #MANTIS.SamData local _entry = entry -- #MANTIS.SamData
type = _entry.Type type = _entry.Type
@@ -1476,18 +1499,21 @@ do
range = _entry.Range * 1000 * radiusscale -- max firing range range = _entry.Range * 1000 * radiusscale -- max firing range
height = _entry.Height * 1000 -- max firing height height = _entry.Height * 1000 -- max firing height
blind = _entry.Blindspot blind = _entry.Blindspot
--self:I("Matching Groupname = " .. grpname .. " Range= " .. range) self:T("Matching Groupname = " .. grpname .. " Range= " .. range)
found = true found = true
break break
end end
end end
end --end
-- secondary filter if not found -- 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) range, height, type = self:_GetSAMDataFromUnits(grpname,HDSmod,SMAMod,CHMod)
elseif not found then elseif not found then
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname)) self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
end end
if string.find(grpname,"SHORAD",1,true) then
type = MANTIS.SamType.SHORT -- force short on match
end
return range, height, type, blind return range, height, type, blind
end end
@@ -1651,6 +1677,10 @@ do
function MANTIS:_CheckLoop(samset,detset,dlink,limit) function MANTIS:_CheckLoop(samset,detset,dlink,limit)
self:T(self.lid .. "CheckLoop " .. #detset .. " Coordinates") self:T(self.lid .. "CheckLoop " .. #detset .. " Coordinates")
local switchedon = 0 local switchedon = 0
local statusreport = REPORT:New("\nMANTIS Status")
local instatusred = 0
local instatusgreen = 0
local SEADactive = 0
for _,_data in pairs (samset) do for _,_data in pairs (samset) do
local samcoordinate = _data[2] local samcoordinate = _data[2]
local name = _data[1] local name = _data[1]
@@ -1673,7 +1703,7 @@ do
elseif (not self.UseEmOnOff) and switchedon < limit then elseif (not self.UseEmOnOff) and switchedon < limit then
samgroup:OptionAlarmStateRed() samgroup:OptionAlarmStateRed()
switchedon = switchedon + 1 switchedon = switchedon + 1
switch = true switch = true
end end
if self.SamStateTracker[name] ~= "RED" and switch then if self.SamStateTracker[name] ~= "RED" and switch then
self:__RedState(1,samgroup) self:__RedState(1,samgroup)
@@ -1691,7 +1721,7 @@ do
-- debug output -- debug output
if (self.debug or self.verbose) and switch then if (self.debug or self.verbose) and switch then
local text = string.format("SAM %s in alarm state RED!", name) 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 if self.verbose then self:I(self.lid..text) end
end end
end --end alive end --end alive
@@ -1709,12 +1739,26 @@ do
end end
if self.debug or self.verbose then if self.debug or self.verbose then
local text = string.format("SAM %s in alarm state GREEN!", name) 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 if self.verbose then self:I(self.lid..text) end
end end
end --end alive end --end alive
end --end check end --end check
end --for for loop 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 return self
end end
@@ -1828,7 +1872,7 @@ do
end end
--]] --]]
if self.autoshorad then 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.Shorad:SetDefenseLimits(80,95)
self.ShoradLink = true self.ShoradLink = true
self.Shorad.Groupset=self.ShoradGroupSet self.Shorad.Groupset=self.ShoradGroupSet

View File

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

View File

@@ -19,7 +19,7 @@
-- --
-- ### Authors: **applevangelist**, **FlightControl** -- ### Authors: **applevangelist**, **FlightControl**
-- --
-- Last Update: Dec 2023 -- Last Update: Oct 2024
-- --
-- === -- ===
-- --
@@ -28,6 +28,16 @@
--- ---
-- @type SEAD -- @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 -- @extends Core.Base#BASE
--- Make SAM sites execute evasive and defensive behaviour when being fired upon. --- Make SAM sites execute evasive and defensive behaviour when being fired upon.
@@ -56,10 +66,11 @@ SEAD = {
SEADGroupPrefixes = {}, SEADGroupPrefixes = {},
SuppressedGroups = {}, SuppressedGroups = {},
EngagementRange = 75, -- default 75% engagement range Feature Request #1355 EngagementRange = 75, -- default 75% engagement range Feature Request #1355
Padding = 10, Padding = 15,
CallBack = nil, CallBack = nil,
UseCallBack = false, UseCallBack = false,
debug = false, debug = false,
WeaponTrack = false,
} }
--- Missile enumerators --- Missile enumerators
@@ -144,7 +155,7 @@ function SEAD:New( SEADGroupPrefixes, Padding )
self:AddTransition("*", "ManageEvasion", "*") self:AddTransition("*", "ManageEvasion", "*")
self:AddTransition("*", "CalculateHitZone", "*") self:AddTransition("*", "CalculateHitZone", "*")
self:I("*** SEAD - Started Version 0.4.6") self:I("*** SEAD - Started Version 0.4.8")
return self return self
end end
@@ -371,7 +382,7 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
reach = wpndata[1] * 1.1 reach = wpndata[1] * 1.1
local mach = wpndata[2] local mach = wpndata[2]
wpnspeed = math.floor(mach * 340.29) wpnspeed = math.floor(mach * 340.29)
if Weapon then if Weapon and Weapon:GetSpeed() > 0 then
wpnspeed = Weapon:GetSpeed() wpnspeed = Weapon:GetSpeed()
self:T(string.format("*** SEAD - Weapon Speed from WEAPON: %f m/s",wpnspeed)) self:T(string.format("*** SEAD - Weapon Speed from WEAPON: %f m/s",wpnspeed))
end end
@@ -452,22 +463,30 @@ end
-- @return #SEAD self -- @return #SEAD self
function SEAD:HandleEventShot( EventData ) function SEAD:HandleEventShot( EventData )
self:T( { EventData.id } ) 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) local SEADWeapon = EventData.Weapon -- Identify the weapon fired
--self:T({ SEADWeapon }) local SEADWeaponName = EventData.WeaponName or "None" -- return weapon type
if self:_CheckHarms(SEADWeaponName) then 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' ) 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 _targetskill = "Random"
local _targetgroupname = "none" local _targetgroupname = "none"
local _target = EventData.Weapon:getTarget() -- Identify target local _target = EventData.Weapon:getTarget() -- Identify target
@@ -520,7 +539,7 @@ function SEAD:HandleEventShot( EventData )
end end
if SEADGroupFound == true then -- yes we are being attacked if SEADGroupFound == true then -- yes we are being attacked
if string.find(SEADWeaponName,"ADM_141",1,true) then 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 else
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper) self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
end end

View File

@@ -8433,12 +8433,14 @@ function WAREHOUSE:_GetAttribute(group)
local attribute=WAREHOUSE.Attribute.OTHER_UNKNOWN --#WAREHOUSE.Attribute local attribute=WAREHOUSE.Attribute.OTHER_UNKNOWN --#WAREHOUSE.Attribute
if group then if group then
local groupCat=group:GetCategory()
----------- -----------
--- Air --- --- Air ---
----------- -----------
-- Planes -- 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 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 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") local bomber=group:HasAttribute("Strategic bombers")
@@ -8593,7 +8595,6 @@ end
-- @param #WAREHOUSE.Queueitem qitem Item of queue to be removed. -- @param #WAREHOUSE.Queueitem qitem Item of queue to be removed.
-- @param #table queue The queue from which the item should be deleted. -- @param #table queue The queue from which the item should be deleted.
function WAREHOUSE:_DeleteQueueItem(qitem, queue) function WAREHOUSE:_DeleteQueueItem(qitem, queue)
self:F({qitem=qitem, queue=queue})
for i=1,#queue do for i=1,#queue do
local _item=queue[i] --#WAREHOUSE.Queueitem local _item=queue[i] --#WAREHOUSE.Queueitem

View File

@@ -291,7 +291,7 @@
-- ## Nevada: Nellis AFB -- ## Nevada: Nellis AFB
-- --
-- -- ATIS Nellis AFB on 270.10 MHz AM. -- -- 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:SetRadioRelayUnitName("Radio Relay Nellis")
-- atisNellis:SetActiveRunway("21L") -- atisNellis:SetActiveRunway("21L")
-- atisNellis:SetTowerFrequencies({327.000, 132.550}) -- atisNellis:SetTowerFrequencies({327.000, 132.550})
@@ -302,7 +302,7 @@
-- ## Persian Gulf: Abu Dhabi International Airport -- ## Persian Gulf: Abu Dhabi International Airport
-- --
-- -- ATIS Abu Dhabi International on 125.1 MHz AM. -- -- 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:SetRadioRelayUnitName("Radio Relay Abu Dhabi International Airport")
-- atisAbuDhabi:SetMetricUnits() -- atisAbuDhabi:SetMetricUnits()
-- atisAbuDhabi:SetActiveRunway("L") -- atisAbuDhabi:SetActiveRunway("L")
@@ -498,6 +498,9 @@ ATIS.Alphabet = {
-- @field #number Syria +5° (East). -- @field #number Syria +5° (East).
-- @field #number MarianaIslands +2° (East). -- @field #number MarianaIslands +2° (East).
-- @field #number SinaiMap +5° (East). -- @field #number SinaiMap +5° (East).
-- @field #number Kola +15° (East).
-- @field #number Afghanistan +3° (East).
-- @field #number Iraq +4.4° (East).
ATIS.RunwayM2T = { ATIS.RunwayM2T = {
Caucasus = 0, Caucasus = 0,
Nevada = 12, Nevada = 12,
@@ -508,6 +511,9 @@ ATIS.RunwayM2T = {
MarianaIslands = 2, MarianaIslands = 2,
Falklands = 12, Falklands = 12,
SinaiMap = 5, SinaiMap = 5,
Kola = 15,
Afghanistan = 3,
Iraq=4.4
} }
--- Whether ICAO phraseology is used for ATIS broadcasts. --- Whether ICAO phraseology is used for ATIS broadcasts.
@@ -521,6 +527,9 @@ ATIS.RunwayM2T = {
-- @field #boolean MarianaIslands true. -- @field #boolean MarianaIslands true.
-- @field #boolean Falklands true. -- @field #boolean Falklands true.
-- @field #boolean SinaiMap true. -- @field #boolean SinaiMap true.
-- @field #boolean Kola true.
-- @field #boolean Afghanistan true.
-- @field #boolean Iraq true.
ATIS.ICAOPhraseology = { ATIS.ICAOPhraseology = {
Caucasus = true, Caucasus = true,
Nevada = false, Nevada = false,
@@ -531,6 +540,9 @@ ATIS.ICAOPhraseology = {
MarianaIslands = true, MarianaIslands = true,
Falklands = true, Falklands = true,
SinaiMap = true, SinaiMap = true,
Kola = true,
Afghanistan = true,
Iraq = true,
} }
--- Nav point data. --- Nav point data.
@@ -619,83 +631,83 @@ ATIS.ICAOPhraseology = {
-- @field #ATIS.Soundfile TACANChannel -- @field #ATIS.Soundfile TACANChannel
-- @field #ATIS.Soundfile VORFrequency -- @field #ATIS.Soundfile VORFrequency
ATIS.Sound = { ATIS.Sound = {
ActiveRunway = { filename = "ActiveRunway.ogg", duration = 0.99 }, ActiveRunway = { filename = "ActiveRunway.ogg", duration = 0.85 },
ActiveRunwayDeparture = { filename = "ActiveRunwayDeparture.ogg", duration = 0.99 }, ActiveRunwayDeparture = { filename = "ActiveRunwayDeparture.ogg", duration = 1.50 },
ActiveRunwayArrival = { filename = "ActiveRunwayArrival.ogg", duration = 0.99 }, ActiveRunwayArrival = { filename = "ActiveRunwayArrival.ogg", duration = 1.38 },
AdviceOnInitial = { filename = "AdviceOnInitial.ogg", duration = 3.00 }, AdviceOnInitial = { filename = "AdviceOnInitial.ogg", duration = 2.98 },
Airport = { filename = "Airport.ogg", duration = 0.66 }, Airport = { filename = "Airport.ogg", duration = 0.55 },
Altimeter = { filename = "Altimeter.ogg", duration = 0.68 }, Altimeter = { filename = "Altimeter.ogg", duration = 0.91 },
At = { filename = "At.ogg", duration = 0.41 }, At = { filename = "At.ogg", duration = 0.32 },
CloudBase = { filename = "CloudBase.ogg", duration = 0.82 }, CloudBase = { filename = "CloudBase.ogg", duration = 0.69 },
CloudCeiling = { filename = "CloudCeiling.ogg", duration = 0.61 }, CloudCeiling = { filename = "CloudCeiling.ogg", duration = 0.53 },
CloudsBroken = { filename = "CloudsBroken.ogg", duration = 1.07 }, CloudsBroken = { filename = "CloudsBroken.ogg", duration = 0.81 },
CloudsFew = { filename = "CloudsFew.ogg", duration = 0.99 }, CloudsFew = { filename = "CloudsFew.ogg", duration = 0.74 },
CloudsNo = { filename = "CloudsNo.ogg", duration = 1.01 }, CloudsNo = { filename = "CloudsNo.ogg", duration = 0.69},
CloudsNotAvailable = { filename = "CloudsNotAvailable.ogg", duration = 2.35 }, CloudsNotAvailable = { filename = "CloudsNotAvailable.ogg", duration = 2.64 },
CloudsOvercast = { filename = "CloudsOvercast.ogg", duration = 0.83 }, CloudsOvercast = { filename = "CloudsOvercast.ogg", duration = 0.82 },
CloudsScattered = { filename = "CloudsScattered.ogg", duration = 1.18 }, CloudsScattered = { filename = "CloudsScattered.ogg", duration = 0.89 },
Decimal = { filename = "Decimal.ogg", duration = 0.54 }, Decimal = { filename = "Decimal.ogg", duration = 0.71 },
DegreesCelsius = { filename = "DegreesCelsius.ogg", duration = 1.27 }, DegreesCelsius = { filename = "DegreesCelsius.ogg", duration = 1.08 },
DegreesFahrenheit = { filename = "DegreesFahrenheit.ogg", duration = 1.23 }, DegreesFahrenheit = { filename = "DegreesFahrenheit.ogg", duration = 1.07 },
DewPoint = { filename = "DewPoint.ogg", duration = 0.65 }, DewPoint = { filename = "DewPoint.ogg", duration = 0.59 },
Dust = { filename = "Dust.ogg", duration = 0.54 }, Dust = { filename = "Dust.ogg", duration = 0.37 },
Elevation = { filename = "Elevation.ogg", duration = 0.78 }, Elevation = { filename = "Elevation.ogg", duration = 0.92 },
EndOfInformation = { filename = "EndOfInformation.ogg", duration = 1.15 }, EndOfInformation = { filename = "EndOfInformation.ogg", duration = 1.24 },
Feet = { filename = "Feet.ogg", duration = 0.45 }, Feet = { filename = "Feet.ogg", duration = 0.34 },
Fog = { filename = "Fog.ogg", duration = 0.47 }, Fog = { filename = "Fog.ogg", duration = 0.41 },
Gusting = { filename = "Gusting.ogg", duration = 0.55 }, Gusting = { filename = "Gusting.ogg", duration = 0.58 },
HectoPascal = { filename = "HectoPascal.ogg", duration = 1.15 }, HectoPascal = { filename = "HectoPascal.ogg", duration = 0.92 },
Hundred = { filename = "Hundred.ogg", duration = 0.47 }, Hundred = { filename = "Hundred.ogg", duration = 0.53 },
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 },
ILSFrequency = { filename = "ILSFrequency.ogg", duration = 1.30 }, ILSFrequency = { filename = "ILSFrequency.ogg", duration = 1.30 },
InnerNDBFrequency = { filename = "InnerNDBFrequency.ogg", duration = 1.56 }, InchesOfMercury = { filename = "InchesOfMercury.ogg", duration = 1.26 },
OuterNDBFrequency = { filename = "OuterNDBFrequency.ogg", duration = 1.59 }, Information = { filename = "Information.ogg", duration = 0.99 },
RunwayLength = { filename = "RunwayLength.ogg", duration = 0.91 }, InnerNDBFrequency = { filename = "InnerNDBFrequency.ogg", duration = 1.69 },
VORFrequency = { filename = "VORFrequency.ogg", duration = 1.38 }, Kilometers = { filename = "Kilometers.ogg", duration = 0.93 },
TACANChannel = { filename = "TACANChannel.ogg", duration = 0.88 }, Knots = { filename = "Knots.ogg", duration = 0.46 },
PRMGChannel = { filename = "PRMGChannel.ogg", duration = 1.18 }, Left = { filename = "Left.ogg", duration = 0.41 },
RSBNChannel = { filename = "RSBNChannel.ogg", duration = 1.14 }, MegaHertz = { filename = "MegaHertz.ogg", duration = 0.83 },
Zulu = { filename = "Zulu.ogg", duration = 0.62 }, 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. --- ATIS class version.
-- @field #string version -- @field #string version
ATIS.version = "1.0.0" ATIS.version = "1.0.1"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@@ -2080,34 +2092,32 @@ function ATIS:onafterBroadcast( From, Event, To )
--------------- ---------------
-- Get mission weather info. Most of this is static. -- Get mission weather info. Most of this is static.
local clouds, visibility, turbulence, fog, dust, static = self:GetMissionWeather() local clouds, visibility, turbulence, dustdens, 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. local dust=false
if fog and fog.thickness < height + 25 then local fog=false
fog = nil
end
-- Dust only up to 1500 ft = 457 m ASL.
if dust and height + 25 > UTILS.FeetToMeters( 1500 ) then
dust = nil
end
------------------ ------------------
--- Visibility --- --- Visibility ---
------------------ ------------------
-- Get min visibility. if dustdens then
local visibilitymin = visibility
-- Dust only up to 1500 ft = 457 m ASL.
if fog then if UTILS.FeetToMeters( 1500 )> height+25 then
if fog.visibility < visibilitymin then dust=true
visibilitymin = fog.visibility visibility=math.min(visibility, dustdens)
end end
end
else -- As of DCS 2.9.10.3948 (December 2024), fog and dust are mutually exclusive!
if dust then
if dust < visibilitymin then -- Get current fog visibility and thickness
visibilitymin = dust 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
end end
@@ -2115,7 +2125,7 @@ function ATIS:onafterBroadcast( From, Event, To )
if self.metric then if self.metric then
-- Visibility in km. -- Visibility in km.
local reportedviz = UTILS.Round( visibilitymin / 1000 ) local reportedviz = UTILS.Round( visibility / 1000 )
-- max reported visibility 9999 m -- max reported visibility 9999 m
if reportedviz > 10 then if reportedviz > 10 then
reportedviz = 10 reportedviz = 10
@@ -2123,7 +2133,7 @@ function ATIS:onafterBroadcast( From, Event, To )
VISIBILITY = string.format( "%d", reportedviz ) VISIBILITY = string.format( "%d", reportedviz )
else else
-- max reported visibility 10 NM -- max reported visibility 10 NM
local reportedviz = UTILS.Round( UTILS.MetersToSM( visibilitymin ) ) local reportedviz = UTILS.Round( UTILS.MetersToSM( visibility ) )
if reportedviz > 10 then if reportedviz > 10 then
reportedviz = 10 reportedviz = 10
end end
@@ -3350,28 +3360,13 @@ function ATIS:GetMissionWeather()
dust = weather.dust_density dust = weather.dust_density
end 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( "FF weather:" )
self:T( { clouds = clouds } ) self:T( { clouds = clouds } )
self:T( { visibility = visibility } ) self:T( { visibility = visibility } )
self:T( { turbulence = turbulence } ) self:T( { turbulence = turbulence } )
self:T( { fog = fog } )
self:T( { dust = dust } ) self:T( { dust = dust } )
self:T( { static = static } ) self:T( { static = static } )
return clouds, visibility, turbulence, fog, dust, static return clouds, visibility, turbulence, dust, static
end end
--- Get thousands of a number. --- Get thousands of a number.

View File

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

View File

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

View File

@@ -24,7 +24,7 @@
-- @module Ops.CTLD -- @module Ops.CTLD
-- @image OPS_CTLD.jpg -- @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.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.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.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 -- ## 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},
-- ["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-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}, -- ["CH-47Fbl1"] = {type="CH-47Fbl1", crates=true, troops=true, cratelimit = 4, trooplimit = 31, length = 20, cargoweightlimit = 8000},
-- --
-- ### 2.2.2 Activate and deactivate zones -- ### 2.2.2 Activate and deactivate zones
@@ -1233,6 +1236,9 @@ CTLD = {
DynamicCargo = {}, DynamicCargo = {},
ChinookTroopCircleRadius = 5, ChinookTroopCircleRadius = 5,
TroopUnloadDistGround = 5, TroopUnloadDistGround = 5,
TroopUnloadDistGroundHerc = 25,
TroopUnloadDistGroundHook = 15,
TroopUnloadDistHoverHook = 5,
TroopUnloadDistHover = 1.5, TroopUnloadDistHover = 1.5,
UserSetGroup = nil, UserSetGroup = nil,
} }
@@ -1272,6 +1278,12 @@ CTLD.RadioModulation = {
FM = 1, FM = 1,
} }
--- Loaded Cargo
-- @type CTLD.LoadedCargo
-- @field #number Troopsloaded
-- @field #number Cratesloaded
-- @field #table Cargo Table of #CTLD_CARGO objects
--- Zone Info. --- Zone Info.
-- @type CTLD.CargoZone -- @type CTLD.CargoZone
-- @field #string name Name of Zone. -- @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 ["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450}, ["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
["OH-6A"] = {type="OH-6A", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 7, cargoweightlimit = 550}, ["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}, ["CH-47Fbl1"] = {type="CH-47Fbl1", crates=true, troops=true, cratelimit = 4, trooplimit = 31, length = 20, cargoweightlimit = 10800},
} }
--- CTLD class version. --- CTLD class version.
-- @field #string version -- @field #string version
CTLD.version="1.1.16" CTLD.version="1.1.20"
--- Instantiate a new CTLD. --- Instantiate a new CTLD.
-- @param #CTLD self -- @param #CTLD self
@@ -2425,6 +2437,7 @@ end
local nearestGroup = nil local nearestGroup = nil
local nearestGroupIndex = -1 local nearestGroupIndex = -1
local nearestDistance = 10000000 local nearestDistance = 10000000
local maxdistance = 0
local nearestList = {} local nearestList = {}
local distancekeys = {} local distancekeys = {}
local extractdistance = self.CrateDistance * self.ExtractFactor local extractdistance = self.CrateDistance * self.ExtractFactor
@@ -2436,8 +2449,14 @@ end
nearestGroup = v nearestGroup = v
nearestGroupIndex = k nearestGroupIndex = k
nearestDistance = distance 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) table.insert(nearestList, math.floor(distance), v)
distancekeys[#distancekeys+1] = math.floor(distance) distancekeys[#distancekeys+1] = math.floor(distance)
--self:I(string.format("Adding group %s distance %dm",nearestGroup:GetName(),distance))
end end
end end
@@ -2490,7 +2509,7 @@ end
nearestGroup.ExtractTime = timer.getTime() nearestGroup.ExtractTime = timer.getTime()
local loadcargotype = CTLD_CARGO:New(self.CargoCounter, Cargotype.Name, Cargotype.Templates, Cargotype.CargoType, true, true, Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass) local loadcargotype = CTLD_CARGO:New(self.CargoCounter, Cargotype.Name, Cargotype.Templates, Cargotype.CargoType, true, true, Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass)
self:T({cargotype=loadcargotype}) self:T({cargotype=loadcargotype})
local running = math.floor(nearestDistance / 4)+10 -- time run to helo plus boarding local running = math.floor(nearestDistance / 4)+20 -- time run to helo plus boarding
loaded.Troopsloaded = loaded.Troopsloaded + troopsize loaded.Troopsloaded = loaded.Troopsloaded + troopsize
table.insert(loaded.Cargo,loadcargotype) table.insert(loaded.Cargo,loadcargotype)
self.Loaded_Cargo[unitname] = loaded self.Loaded_Cargo[unitname] = loaded
@@ -2505,26 +2524,32 @@ end
local Angle = math.floor((heading+160)%360) local Angle = math.floor((heading+160)%360)
Point = coord:Translate(8,Angle):GetVec2() Point = coord:Translate(8,Angle):GetVec2()
if Point then if Point then
nearestGroup:RouteToVec2(Point,4) nearestGroup:RouteToVec2(Point,5)
end end
end end
-- clean up: -- 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 for _,_key in pairs (Cargotype.Templates) do
table.insert(secondarygroups,_key) table.insert(secondarygroups,_key)
hassecondaries = true
end end
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 end
end end
-- clean up secondary groups -- clean up secondary groups
for _,_name in pairs(secondarygroups) do if hassecondaries == true then
for _,_group in pairs(nearestList) do for _,_name in pairs(secondarygroups) do
if _group and _group:IsAlive() then for _,_group in pairs(nearestList) do
local groupname = string.match(_group:GetName(), "(.+)-(.+)$") if _group and _group:IsAlive() then
if _name == groupname then local groupname = string.match(_group:GetName(), "(.+)-(.+)$")
_group:Destroy(false,15) if _name == groupname then
_group:Destroy(false,15)
end
end end
end end
end end
@@ -3408,8 +3433,8 @@ function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
local template = _DATABASE:GetGroupTemplate(Template) local template = _DATABASE:GetGroupTemplate(Template)
--UTILS.PrintTableToLog(template) --UTILS.PrintTableToLog(template)
local numbertroops = #template.units local numbertroops = #template.units
local slightshift = math.abs(math.random(0,200)/100) local slightshift = math.abs(math.random(1,500)/100)
local newcenter = Coordinate:Translate(Radius+slightshift,((Heading+270)%360)) local newcenter = Coordinate:Translate(Radius+slightshift,((Heading+270+math.random(1,10))%360))
for i=1,360,math.floor(360/numbertroops) do for i=1,360,math.floor(360/numbertroops) do
local phead = ((Heading+270+i)%360) local phead = ((Heading+270+i)%360)
local post = newcenter:Translate(Radius,phead) local post = newcenter:Translate(Radius,phead)
@@ -3484,7 +3509,15 @@ function CTLD:_UnloadTroops(Group, Unit)
randomcoord = Group:GetCoordinate() randomcoord = Group:GetCoordinate()
-- slightly left from us -- slightly left from us
local Angle = (heading+270)%360 local Angle = (heading+270)%360
if IsHerc or IsHook then Angle = (heading+180)%360 end
local offset = hoverunload and self.TroopUnloadDistHover or self.TroopUnloadDistGround 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) randomcoord:Translate(offset,Angle,nil,true)
end end
local tempcount = 0 local tempcount = 0
@@ -3494,7 +3527,7 @@ function CTLD:_UnloadTroops(Group, Unit)
self.TroopCounter = self.TroopCounter + 1 self.TroopCounter = self.TroopCounter + 1
tempcount = tempcount+1 tempcount = tempcount+1
local alias = string.format("%s-%d", _template, math.random(1,100000)) 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) local Positions = self:_GetUnitPositions(randomcoord,rad,heading,_template)
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias) self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
--:InitRandomizeUnits(true,20,2) --:InitRandomizeUnits(true,20,2)
@@ -4269,7 +4302,7 @@ end
-- @param #string SubCategory Name of sub-category (optional). -- @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 #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 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 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 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". -- @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 #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 #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 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 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 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". -- @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 return Stock
end 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 --- User - function to get a table of statics cargo in stock
-- @param #CTLD self -- @param #CTLD self
-- @return #table Table Table of Stock, indexed by cargo type name -- @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 #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 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 #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 -- @extends Core.Base#BASE
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde --- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
@@ -256,11 +257,12 @@ MSRS = {
ConfigFilePath = "Config\\", ConfigFilePath = "Config\\",
ConfigLoaded = false, ConfigLoaded = false,
poptions = {}, poptions = {},
UsePowerShell = false,
} }
--- MSRS class version. --- MSRS class version.
-- @field #string version -- @field #string version
MSRS.version="0.3.0" MSRS.version="0.3.3"
--- Voices --- Voices
-- @type MSRS.Voices -- @type MSRS.Voices
@@ -588,7 +590,7 @@ function MSRS:SetBackendSRSEXE()
end end
--- Set the default backend. --- Set the default backend.
-- @param #MSRS self -- @param #string Backend
function MSRS.SetDefaultBackend(Backend) function MSRS.SetDefaultBackend(Backend)
MSRS.backend=Backend or MSRS.Backend.SRSEXE MSRS.backend=Backend or MSRS.Backend.SRSEXE
end end
@@ -1375,20 +1377,25 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
modus=modus:gsub("1", "FM") modus=modus:gsub("1", "FM")
-- Command. -- 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) 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. -- 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. -- Use a specific voice (no need for gender and/or culture.
command=command..string.format(" --voice=\"%s\"", tostring(voice)) command=command..string.format(" --voice=\"%s\"", tostring(voice))
pwsh=pwsh..string.format(" --voice=\"%s\"", tostring(voice))
else else
-- Add gender. -- Add gender.
if gender and gender~="female" then if gender and gender~="female" then
command=command..string.format(" -g %s", tostring(gender)) command=command..string.format(" -g %s", tostring(gender))
pwsh=pwsh..string.format(" -g %s", tostring(gender))
end end
-- Add culture. -- Add culture.
if culture and culture~="en-GB" then if culture and culture~="en-GB" then
command=command..string.format(" -l %s", tostring(culture)) command=command..string.format(" -l %s", tostring(culture))
pwsh=pwsh..string.format(" -l %s", tostring(culture))
end end
end end
@@ -1396,12 +1403,14 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
if coordinate then if coordinate then
local lat,lon,alt=self:_GetLatLongAlt(coordinate) local lat,lon,alt=self:_GetLatLongAlt(coordinate)
command=command..string.format(" -L %.4f -O %.4f -A %d", lat, lon, alt) 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 end
-- Set provider options -- Set provider options
if self.provider==MSRS.Provider.GOOGLE then if self.provider==MSRS.Provider.GOOGLE then
local pops=self:GetProviderOptions() local pops=self:GetProviderOptions()
command=command..string.format(' --ssml -G "%s"', pops.credentials) 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 elseif self.provider==MSRS.Provider.WINDOWS then
-- Nothing to do. -- Nothing to do.
else else
@@ -1415,8 +1424,12 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
-- Debug output. -- Debug output.
self:T("MSRS command from _GetCommand="..command) self:T("MSRS command from _GetCommand="..command)
return command if self.UsePowerShell == true then
return pwsh
else
return command
end
end end
--- Execute SRS command to play sound using the `DCS-SR-ExternalAudio.exe`. --- Execute SRS command to play sound using the `DCS-SR-ExternalAudio.exe`.
@@ -1424,7 +1437,7 @@ end
-- @param #string command Command to executer -- @param #string command Command to executer
-- @return #number Return value of os.execute() command. -- @return #number Return value of os.execute() command.
function MSRS:_ExecCommand(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 -- Skip this function if _GetCommand was not able to find the executable
if string.find(command, "CommandNotFound") then return 0 end if string.find(command, "CommandNotFound") then return 0 end
@@ -1432,7 +1445,13 @@ function MSRS:_ExecCommand(command)
local batContent = command.." && exit" local batContent = command.." && exit"
-- Create a tmp file. -- Create a tmp file.
local filename=os.getenv('TMP').."\\MSRS-"..MSRS.uuid()..".bat" 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+") local script=io.open(filename, "w+")
script:write(batContent) script:write(batContent)
script:close() script:close()
@@ -1441,7 +1460,7 @@ function MSRS:_ExecCommand(command)
self:T("MSRS batch content: "..batContent) self:T("MSRS batch content: "..batContent)
local res=nil local res=nil
if true then if self.UsePowerShell ~= true then
-- Create a tmp file. -- Create a tmp file.
local filenvbs = os.getenv('TMP') .. "\\MSRS-"..MSRS.uuid()..".vbs" 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) timer.scheduleFunction(os.remove, filenvbs, timer.getTime()+1)
self:T("MSRS vbs and batch file removed") self:T("MSRS vbs and batch file removed")
elseif false then elseif self.UsePowerShell == true 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)
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 -- 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 else
-- Play command. -- 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.M134_MiniGun_Left_Door = {4,15,46,174}
ENUMS.Storage.weapons.UH1H.M60_MG_Left_Door = {4,15,46,176} ENUMS.Storage.weapons.UH1H.M60_MG_Left_Door = {4,15,46,176}
-- Kiowa -- Kiowa
ENUMS.Storage.weapons.OH58.FIM92 = {4,4,7,446} ENUMS.Storage.weapons.OH58.FIM92 = {4,4,7,449}
ENUMS.Storage.weapons.OH58.MG_M3P100 = {4,15,46,2578} ENUMS.Storage.weapons.OH58.MG_M3P100 = {4,15,46,2608}
ENUMS.Storage.weapons.OH58.MG_M3P200 = {4,15,46,2577} ENUMS.Storage.weapons.OH58.MG_M3P200 = {4,15,46,2607}
ENUMS.Storage.weapons.OH58.MG_M3P300 = {4,15,46,2576} ENUMS.Storage.weapons.OH58.MG_M3P300 = {4,15,46,2606}
ENUMS.Storage.weapons.OH58.MG_M3P400 = {4,15,46,2575} ENUMS.Storage.weapons.OH58.MG_M3P400 = {4,15,46,2605}
ENUMS.Storage.weapons.OH58.MG_M3P500 = {4,15,46,2574} ENUMS.Storage.weapons.OH58.MG_M3P500 = {4,15,46,2604}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Blue = {4,5,9,484} ENUMS.Storage.weapons.OH58.Smk_Grenade_Blue = {4,5,9,486}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Green = {4,5,9,485} ENUMS.Storage.weapons.OH58.Smk_Grenade_Green = {4,5,9,487}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Red = {4,5,9,483} ENUMS.Storage.weapons.OH58.Smk_Grenade_Red = {4,5,9,485}
ENUMS.Storage.weapons.OH58.Smk_Grenade_Violet = {4,5,9,486} ENUMS.Storage.weapons.OH58.Smk_Grenade_Violet = {4,5,9,488}
ENUMS.Storage.weapons.OH58.Smk_Grenade_White = {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,487} ENUMS.Storage.weapons.OH58.Smk_Grenade_Yellow = {4,5,9,489}
-- Apache -- Apache
ENUMS.Storage.weapons.AH64D.AN_APG78 = {4,15,44,2138} ENUMS.Storage.weapons.AH64D.AN_APG78 = {4,15,44,2138}
ENUMS.Storage.weapons.AH64D.Internal_Aux_FuelTank = {1,3,43,1700} 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 Falklands South Atlantic map.
-- @field #string Sinai Sinai map. -- @field #string Sinai Sinai map.
-- @field #string Kola Kola map. -- @field #string Kola Kola map.
-- @field #string Afghanistan Afghanistan map
-- @field #string Iraq Iraq map
DCSMAP = { DCSMAP = {
Caucasus="Caucasus", Caucasus="Caucasus",
NTTR="Nevada", NTTR="Nevada",
@@ -68,6 +70,7 @@ DCSMAP = {
Sinai="SinaiMap", Sinai="SinaiMap",
Kola="Kola", Kola="Kola",
Afghanistan="Afghanistan", Afghanistan="Afghanistan",
Iraq="Iraq"
} }
@@ -1786,6 +1789,8 @@ function UTILS.GetMagneticDeclination(map)
declination=15 declination=15
elseif map==DCSMAP.Afghanistan then elseif map==DCSMAP.Afghanistan then
declination=3 declination=3
elseif map==DCSMAP.Iraq then
declination=4.4
else else
declination=0 declination=0
end end
@@ -2315,9 +2320,9 @@ function UTILS.IsLoadingDoorOpen( unit_name )
return true return true
end end
if type_name == "OH-58D" and (unit:getDrawArgumentValue(35) > 0 or unit:getDrawArgumentValue(421) == -1) then if type_name == "OH58D" then
BASE:T(unit_name .. " cargo door is open") BASE:T(unit_name .. " front door(s) are open")
return true return true -- no doors on this one ;)
end end
if type_name == "CH-47Fbl1" and (unit:getDrawArgumentValue(86) > 0.5) then 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 --- Function to save an object to a file
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
-- @param #string Filename The name of the file. Existing file will be overwritten. -- @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. -- @return #boolean outcome True if saving is possible, else false.
function UTILS.SaveToFile(Path,Filename,Data) function UTILS.SaveToFile(Path,Filename,Data)
-- Thanks to @FunkyFranky -- 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, -- 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() -- 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}(). -- 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 -- @field #AIRBASE AIRBASE
AIRBASE = { AIRBASE = {
@@ -248,6 +253,9 @@ AIRBASE.Nevada = {
-- * AIRBASE.Normandy.Villacoublay -- * AIRBASE.Normandy.Villacoublay
-- * AIRBASE.Normandy.Vrigny -- * AIRBASE.Normandy.Vrigny
-- * AIRBASE.Normandy.West_Malling -- * AIRBASE.Normandy.West_Malling
-- * AIRBASE.Normandy.Eastchurch
-- * AIRBASE.Normandy.Headcorn
-- * AIRBASE.Normandy.Hawkinge
-- --
-- @field Normandy -- @field Normandy
AIRBASE.Normandy = { AIRBASE.Normandy = {
@@ -330,6 +338,9 @@ AIRBASE.Normandy = {
["Villacoublay"] = "Villacoublay", ["Villacoublay"] = "Villacoublay",
["Vrigny"] = "Vrigny", ["Vrigny"] = "Vrigny",
["West_Malling"] = "West Malling", ["West_Malling"] = "West Malling",
["Eastchurch"] = "Eastchurch",
["Headcorn"] = "Headcorn",
["Hawkinge"] = "Hawkinge",
} }
--- Airbases of the Persion Gulf Map: --- Airbases of the Persion Gulf Map:
@@ -450,6 +461,7 @@ AIRBASE.TheChannel = {
-- * AIRBASE.Syria.Gaziantep -- * AIRBASE.Syria.Gaziantep
-- * AIRBASE.Syria.Gazipasa -- * AIRBASE.Syria.Gazipasa
-- * AIRBASE.Syria.Gecitkale -- * AIRBASE.Syria.Gecitkale
-- * AIRBASE.Syria.H
-- * AIRBASE.Syria.H3 -- * AIRBASE.Syria.H3
-- * AIRBASE.Syria.H3_Northwest -- * AIRBASE.Syria.H3_Northwest
-- * AIRBASE.Syria.H3_Southwest -- * AIRBASE.Syria.H3_Southwest
@@ -497,6 +509,10 @@ AIRBASE.TheChannel = {
-- * AIRBASE.Syria.Tha_lah -- * AIRBASE.Syria.Tha_lah
-- * AIRBASE.Syria.Tiyas -- * AIRBASE.Syria.Tiyas
-- * AIRBASE.Syria.Wujah_Al_Hajar -- * AIRBASE.Syria.Wujah_Al_Hajar
-- * AIRBASE.Syria.Ben_Gurion
-- * AIRBASE.Syria.Hatzor
-- * AIRBASE.Syria.Palmashim
-- * AIRBASE.Syria.Tel_Nof
-- --
--@field Syria --@field Syria
AIRBASE.Syria={ AIRBASE.Syria={
@@ -518,6 +534,7 @@ AIRBASE.Syria={
["Gaziantep"] = "Gaziantep", ["Gaziantep"] = "Gaziantep",
["Gazipasa"] = "Gazipasa", ["Gazipasa"] = "Gazipasa",
["Gecitkale"] = "Gecitkale", ["Gecitkale"] = "Gecitkale",
["H"] = "H",
["H3"] = "H3", ["H3"] = "H3",
["H3_Northwest"] = "H3 Northwest", ["H3_Northwest"] = "H3 Northwest",
["H3_Southwest"] = "H3 Southwest", ["H3_Southwest"] = "H3 Southwest",
@@ -565,6 +582,10 @@ AIRBASE.Syria={
["Tha_lah"] = "Tha'lah", ["Tha_lah"] = "Tha'lah",
["Tiyas"] = "Tiyas", ["Tiyas"] = "Tiyas",
["Wujah_Al_Hajar"] = "Wujah Al Hajar", ["Wujah_Al_Hajar"] = "Wujah Al Hajar",
["Ben_Gurion"] = "Ben Gurion",
["Hatzor"] = "Hatzor",
["Palmashim"] = "Palmashim",
["Tel_Nof"] = "Tel Nof",
} }
--- Airbases of the Mariana Islands map: --- Airbases of the Mariana Islands map:
@@ -752,12 +773,14 @@ AIRBASE.Sinai = {
-- --
-- * AIRBASE.Kola.Banak -- * AIRBASE.Kola.Banak
-- * AIRBASE.Kola.Bodo -- * AIRBASE.Kola.Bodo
-- * AIRBASE.Kola.Ivalo
-- * AIRBASE.Kola.Jokkmokk -- * AIRBASE.Kola.Jokkmokk
-- * AIRBASE.Kola.Kalixfors -- * AIRBASE.Kola.Kalixfors
-- * AIRBASE.Kola.Kallax -- * AIRBASE.Kola.Kallax
-- * AIRBASE.Kola.Kemi_Tornio -- * AIRBASE.Kola.Kemi_Tornio
-- * AIRBASE.Kola.Kirkenes -- * AIRBASE.Kola.Kirkenes
-- * AIRBASE.Kola.Kiruna -- * AIRBASE.Kola.Kiruna
-- * AIRBASE.Kola.Kuusamo
-- * AIRBASE.Kola.Monchegorsk -- * AIRBASE.Kola.Monchegorsk
-- * AIRBASE.Kola.Murmansk_International -- * AIRBASE.Kola.Murmansk_International
-- * AIRBASE.Kola.Olenya -- * AIRBASE.Kola.Olenya
@@ -766,25 +789,31 @@ AIRBASE.Sinai = {
-- * AIRBASE.Kola.Severomorsk_3 -- * AIRBASE.Kola.Severomorsk_3
-- * AIRBASE.Kola.Vidsel -- * AIRBASE.Kola.Vidsel
-- * AIRBASE.Kola.Vuojarvi -- * AIRBASE.Kola.Vuojarvi
-- -- * AIRBASE.Kola.Andoya
-- * AIRBASE.Kola.Alakourtti
--
-- @field Kola -- @field Kola
AIRBASE.Kola = { AIRBASE.Kola = {
["Banak"] = "Banak", ["Banak"] = "Banak",
["Bodo"] = "Bodo", ["Bodo"] = "Bodo",
["Ivalo"] = "Ivalo",
["Jokkmokk"] = "Jokkmokk", ["Jokkmokk"] = "Jokkmokk",
["Kalixfors"] = "Kalixfors", ["Kalixfors"] = "Kalixfors",
["Kallax"] = "Kallax",
["Kemi_Tornio"] = "Kemi Tornio", ["Kemi_Tornio"] = "Kemi Tornio",
["Kirkenes"] = "Kirkenes",
["Kiruna"] = "Kiruna", ["Kiruna"] = "Kiruna",
["Kuusamo"] = "Kuusamo",
["Monchegorsk"] = "Monchegorsk", ["Monchegorsk"] = "Monchegorsk",
["Murmansk_International"] = "Murmansk International", ["Murmansk_International"] = "Murmansk International",
["Olenya"] = "Olenya", ["Olenya"] = "Olenya",
["Rovaniemi"] = "Rovaniemi", ["Rovaniemi"] = "Rovaniemi",
["Severomorsk_1"] = "Severomorsk-1", ["Severomorsk_1"] = "Severomorsk-1",
["Severomorsk_3"] = "Severomorsk-3", ["Severomorsk_3"] = "Severomorsk-3",
["Vuojarvi"] = "Vuojarvi",
["Kirkenes"] = "Kirkenes",
["Kallax"] = "Kallax",
["Vidsel"] = "Vidsel", ["Vidsel"] = "Vidsel",
["Vuojarvi"] = "Vuojarvi",
["Andoya"] = "Andoya",
["Alakourtti"] = "Alakourtti",
} }
--- Airbases of the Afghanistan map --- Airbases of the Afghanistan map
@@ -824,6 +853,39 @@ AIRBASE.Afghanistan = {
["Tarinkot"] = "Tarinkot", ["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". --- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
-- @type AIRBASE.ParkingSpot -- @type AIRBASE.ParkingSpot
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot. -- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.
@@ -926,7 +988,7 @@ function AIRBASE:Register(AirbaseName)
-- Debug info. -- Debug info.
--self:I({airbase=AirbaseName, descriptors=self.descriptors}) --self:I({airbase=AirbaseName, descriptors=self.descriptors})
-- Category. -- Category.
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
@@ -937,22 +999,22 @@ function AIRBASE:Register(AirbaseName)
--end --end
-- Set category. -- Set category.
if self.category==Airbase.Category.AIRDROME then if self.category==Airbase.Category.AIRDROME then
self.isAirdrome=true self.isAirdrome=true
elseif self.category==Airbase.Category.HELIPAD then 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 self.isHelipad=true
elseif self.category==Airbase.Category.SHIP then self.isShip=false
self.isShip=true self.category=Airbase.Category.HELIPAD
-- DCS bug: Oil rigs and gas platforms have category=2 (ship). Also they cannot be retrieved by coalition.getStaticObjects() _DATABASE:AddStatic(AirbaseName)
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!")
end end
else
self:E("ERROR: Unknown airbase category!")
end
-- Init Runways. -- Init Runways.
self:_InitRunways() self:_InitRunways()

View File

@@ -902,7 +902,11 @@ function CONTROLLABLE:CommandEPLRS( SwitchOnOff, Delay )
groupId = self:GetID(), groupId = self:GetID(),
}, },
} }
--if self:IsGround() then
--CommandEPLRS.params.groupId = self:GetID()
--end
if Delay and Delay > 0 then if Delay and Delay > 0 then
SCHEDULER:New( nil, self.CommandEPLRS, { self, SwitchOnOff }, Delay ) SCHEDULER:New( nil, self.CommandEPLRS, { self, SwitchOnOff }, Delay )
else else
@@ -937,7 +941,7 @@ function CONTROLLABLE:CommandSetUnlimitedFuel(OnOff, Delay)
end 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 #CONTROLLABLE self
-- @param #number Frequency Radio frequency in MHz. -- @param #number Frequency Radio frequency in MHz.
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`. -- @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 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 else
self:SetCommand( CommandSetFrequency ) self:SetCommand( CommandSetFrequency )
end end
@@ -964,7 +968,7 @@ function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Power, Delay )
return self return self
end 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 #CONTROLLABLE self
-- @param #number Frequency Radio frequency in MHz. -- @param #number Frequency Radio frequency in MHz.
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`. -- @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 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 else
self:SetCommand(CommandSetFrequencyForUnit) self:SetCommand(CommandSetFrequencyForUnit)
end end
@@ -1009,7 +1013,11 @@ function CONTROLLABLE:TaskEPLRS( SwitchOnOff, idx )
groupId = self:GetID(), groupId = self:GetID(),
}, },
} }
--if self:IsGround() then
--CommandEPLRS.params.groupId = self:GetID()
--end
return self:TaskWrappedAction( CommandEPLRS, idx or 1 ) return self:TaskWrappedAction( CommandEPLRS, idx or 1 )
end end
@@ -2997,7 +3005,7 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad
if DCSControllable then if DCSControllable then
local DetectionVisual = (DetectVisual and DetectVisual == true) and Controller.Detection.VISUAL or nil 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 DetectionRadar = (DetectRadar and DetectRadar == true) and Controller.Detection.RADAR or nil
local DetectionIRST = (DetectIRST and DetectIRST == true) and Controller.Detection.IRST 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 local DetectionRWR = (DetectRWR and DetectRWR == true) and Controller.Detection.RWR or nil
@@ -3031,26 +3039,27 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad
return nil return nil
end 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. -- 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 **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. -- If **at least one** detection method is specified, only the methods set to *true* will be used.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @param DCS#Object DCSObject The DCS object that is checked. -- @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 DetectVisual (Optional) If *false*, do not include visually detected targets.
-- @param #boolean DetectOptical (Optional) If *false*, do not include optically 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 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 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 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. -- @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 detected.
-- @return #boolean True if target is visible by line of sight. -- @return #boolean `true` if target is *currently* visible by line of sight. Target must be detected (first parameter returns `true`).
-- @return #number Mission time when target was detected. -- @return #boolean `true` if target type is known. Target must be detected (first parameter returns `true`).
-- @return #boolean True if target type is known. -- @return #boolean `true` if distance to target is known. Target must be detected (first parameter returns `true`).
-- @return #boolean True if distance to target is known. -- @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. -- @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. -- @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 ) function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK )
self:F2( self.ControllableName ) self:F2( self.ControllableName )
@@ -3059,7 +3068,7 @@ function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical,
if DCSControllable then if DCSControllable then
local DetectionVisual = (DetectVisual and DetectVisual == true) and Controller.Detection.VISUAL or nil 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 DetectionRadar = (DetectRadar and DetectRadar == true) and Controller.Detection.RADAR or nil
local DetectionIRST = (DetectIRST and DetectIRST == true) and Controller.Detection.IRST 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 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 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 ) = 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 end
return nil return nil
@@ -3078,6 +3087,7 @@ end
--- Check if a certain UNIT is detected by the controllable. --- Check if a certain UNIT is detected by the controllable.
-- The optional parametes specify the detection methods that can be applied. -- 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 **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. -- If **at least one** detection method is specified, only the methods set to *true* will be used.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
@@ -3088,13 +3098,13 @@ end
-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST. -- @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 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. -- @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 detected.
-- @return #boolean True if target is visible by line of sight. -- @return #boolean `true` if target is *currently* visible by line of sight. Target must be detected (first parameter returns `true`).
-- @return #number Mission time when target was detected. -- @return #boolean `true` if target type is known. Target must be detected (first parameter returns `true`).
-- @return #boolean True if target type is known. -- @return #boolean `true` if distance to target is known. Target must be detected (first parameter returns `true`).
-- @return #boolean True if distance to target is known. -- @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. -- @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. -- @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 ) function CONTROLLABLE:IsUnitDetected( Unit, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK )
self:F2( self.ControllableName ) self:F2( self.ControllableName )

View File

@@ -458,7 +458,7 @@ function DYNAMICCARGO:_UpdatePosition()
self:T(self.lid.." AGL: "..agl or -1) self:T(self.lid.." AGL: "..agl or -1)
local isunloaded = true local isunloaded = true
local client local client
local playername local playername = self.Owner
if count > 0 and (agl > 0 or self.testing) then if count > 0 and (agl > 0 or self.testing) then
self:T(self.lid.." Possible alive helos: "..count or -1) self:T(self.lid.." Possible alive helos: "..count or -1)
if agl ~= 0 or self.testing then if agl ~= 0 or self.testing then
@@ -470,6 +470,11 @@ function DYNAMICCARGO:_UpdatePosition()
self.Owner = playername self.Owner = playername
_DATABASE:CreateEventDynamicCargoUnloaded(self) _DATABASE:CreateEventDynamicCargoUnloaded(self)
end 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
end end
self.LastPosition = pos self.LastPosition = pos

View File

@@ -360,7 +360,7 @@ end
-- @return DCS#Group The DCS Group. -- @return DCS#Group The DCS Group.
function GROUP:GetDCSObject() 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. -- Get DCS group.
local DCSGroup = Group.getByName( self.GroupName ) local DCSGroup = Group.getByName( self.GroupName )
@@ -369,14 +369,14 @@ function GROUP:GetDCSObject()
self.LastCallDCSObject = timer.getTime() self.LastCallDCSObject = timer.getTime()
self.DCSObject = DCSGroup self.DCSObject = DCSGroup
return DCSGroup return DCSGroup
else -- else
self.DCSObject = nil -- self.DCSObject = nil
self.LastCallDCSObject = nil -- self.LastCallDCSObject = nil
end end
else --else
return self.DCSObject --return self.DCSObject
end --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))) --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 return nil
@@ -485,20 +485,24 @@ function GROUP:Destroy( GenerateEvent, delay )
self:ScheduleOnce(delay, GROUP.Destroy, self, GenerateEvent) self:ScheduleOnce(delay, GROUP.Destroy, self, GenerateEvent)
else else
local DCSGroup = self:GetDCSObject() --local DCSGroup = self:GetDCSObject()
local DCSGroup = Group.getByName( self.GroupName )
if DCSGroup then if DCSGroup then
for Index, UnitData in pairs( DCSGroup:getUnits() ) do for Index, UnitData in pairs( DCSGroup:getUnits() ) do
if GenerateEvent and GenerateEvent == true then if GenerateEvent and GenerateEvent == true then
if self:IsAir() then if self:IsAir() then
self:CreateEventCrash( timer.getTime(), UnitData ) self:CreateEventCrash( timer.getTime(), UnitData )
--self:ScheduleOnce(1,self.CreateEventCrash,self,timer.getTime(),UnitData)
else else
self:CreateEventDead( timer.getTime(), UnitData ) self:CreateEventDead( timer.getTime(), UnitData )
--self:ScheduleOnce(1,self.CreateEventDead,self,timer.getTime(),UnitData)
end end
elseif GenerateEvent == false then elseif GenerateEvent == false then
-- Do nothing! -- Do nothing!
else else
self:CreateEventRemoveUnit( timer.getTime(), UnitData ) self:CreateEventRemoveUnit( timer.getTime(), UnitData )
--self:ScheduleOnce(1,self.CreateEventRemoveUnit,self,timer.getTime(),UnitData)
end end
end end
USERFLAG:New( self:GetName() ):Set( 100 ) 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.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.InitRandomizeHeading}: Randomize the headings for the units within the respawned group.
-- - @{#GROUP.InitZone}: Set the respawn @{Core.Zone} for 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.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.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: -- 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. -- - The current alive group will always be destroyed and respawned using the template definition.
-- --
-- @param Wrapper.Group#GROUP self -- @param Wrapper.Group#GROUP self
@@ -2015,10 +2015,24 @@ function GROUP:Respawn( Template, Reset )
end end
return h return h
end 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. -- First check if group is alive.
if self:IsAlive() then if self:IsAlive() then
local OldPos = self:GetVec2()
-- Respawn zone. -- Respawn zone.
local Zone = self.InitRespawnZone -- Core.Zone#ZONE local Zone = self.InitRespawnZone -- Core.Zone#ZONE
@@ -2031,6 +2045,8 @@ function GROUP:Respawn( Template, Reset )
-- X, Y -- X, Y
Template.x = Vec3.x Template.x = Vec3.x
Template.y = Vec3.z Template.y = Vec3.z
local NewPos = { x = Vec3.x, y = Vec3.z }
--Template.x = nil --Template.x = nil
--Template.y = nil --Template.y = nil
@@ -2085,11 +2101,13 @@ function GROUP:Respawn( Template, Reset )
-- Set heading. -- Set heading.
Template.units[UnitID].heading = _Heading(self.InitRespawnHeading and self.InitRespawnHeading or GroupUnit:GetHeading()) Template.units[UnitID].heading = _Heading(self.InitRespawnHeading and self.InitRespawnHeading or GroupUnit:GetHeading())
Template.units[UnitID].psi = -Template.units[UnitID].heading Template.units[UnitID].psi = -Template.units[UnitID].heading
-- Debug. -- Debug.
--self:F( { UnitID, Template.units[UnitID], Template.units[UnitID] } ) --self:F( { UnitID, Template.units[UnitID], Template.units[UnitID] } )
end end
end end
Template = TransFormRoute(Template,OldPos,NewPos)
elseif Reset==false then -- Reset=false or nil elseif Reset==false then -- Reset=false or nil
@@ -2128,11 +2146,13 @@ function GROUP:Respawn( Template, Reset )
-- Heading -- Heading
Template.units[UnitID].heading = self.InitRespawnHeading and self.InitRespawnHeading or TemplateUnitData.heading Template.units[UnitID].heading = self.InitRespawnHeading and self.InitRespawnHeading or TemplateUnitData.heading
-- Debug. -- Debug.
--self:F( { UnitID, Template.units[UnitID], Template.units[UnitID] } ) --self:F( { UnitID, Template.units[UnitID], Template.units[UnitID] } )
end end
Template = TransFormRoute(Template,OldPos,NewPos)
else else
local units=self:GetUnits() 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. -- Destroy old group. Dont trigger any dead/crash events since this is a respawn.
self:Destroy(false) self:Destroy(false)
--self:T({Template=Template}) --UTILS.PrintTableToLog(Template)
-- Spawn new group. -- Spawn new group.
_DATABASE:Spawn(Template) self:ScheduleOnce(0.1,_DATABASE.Spawn,_DATABASE,Template)
--_DATABASE:Spawn(Template)
-- Reset events. -- Reset events.
self:ResetEvents() self:ResetEvents()
@@ -2192,6 +2213,29 @@ function GROUP:Respawn( Template, Reset )
return self return self
end 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. --- 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. -- 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. -- @return #table The mission route defined by points.
function GROUP:GetTaskRoute() function GROUP:GetTaskRoute()
--self:F2( self.GroupName ) --self:F2( self.GroupName )
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 ) return UTILS.DeepCopy( _DATABASE.Templates.Groups[self.GroupName].Template.route.points )
else
return {}
end
end end
--- Return the route of a group by using the global _DATABASE object (an instance of @{Core.Database#DATABASE}). --- 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 #GROUP self
-- @param #boolean ShortCallsign Return a shortened customized callsign, i.e. "Ghostrider 9" and not "Ghostrider 9 1" -- @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 #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. -- 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 -- @return #string Callsign
-- @usage -- @usage
-- -- suppose there are three groups with one (client) unit each: -- -- 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 2 or Apollo 403 if Keepnumber is set
-- -- Apollo for Slot 3 -- -- Apollo for Slot 3
-- -- Bengal-4 for Slot 4 -- -- 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") --self:I("GetCustomCallSign")
local callsign = "Ghost 1" local callsign = "Ghost 1"
@@ -2963,7 +3016,14 @@ function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations)
local callnumbermajor = string.char(string.byte(callnumber,1)) -- 9 local callnumbermajor = string.char(string.byte(callnumber,1)) -- 9
local callnumberminor = string.char(string.byte(callnumber,2)) -- 1 local callnumberminor = string.char(string.byte(callnumber,2)) -- 1
local personalized = false 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 -- prioritize bespoke callsigns over parsing, prefer parsing over default callsigns
if CallsignTranslations and CallsignTranslations[callsignroot] then if CallsignTranslations and CallsignTranslations[callsignroot] then
callsignroot = CallsignTranslations[callsignroot] callsignroot = CallsignTranslations[callsignroot]
@@ -2975,9 +3035,9 @@ function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations)
shortcallsign = string.match(groupname,"#%s*([%a]+)") or "Ghost" -- Ghostrider shortcallsign = string.match(groupname,"#%s*([%a]+)") or "Ghost" -- Ghostrider
end end
personalized = true personalized = true
elseif IsPlayer and string.find(self:GetPlayerName(),"|") then elseif IsPlayer and string.find(playername,"|") then
-- personalized flight name in group naming -- 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 personalized = true
end end

View File

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

View File

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

View File

@@ -240,7 +240,9 @@ end
-- @return DCS#Unit The DCS Group. -- @return DCS#Unit The DCS Group.
function UNIT:GetDCSObject() 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. -- Get DCS group.
local DCSUnit = Unit.getByName( self.UnitName ) local DCSUnit = Unit.getByName( self.UnitName )

View File

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