mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43ab4d5f38 | ||
|
|
0427c0d3a7 | ||
|
|
014750ea7f | ||
|
|
e4bbfce314 | ||
|
|
359429b17e | ||
|
|
6001f6abda | ||
|
|
fd9b5d8d16 | ||
|
|
b6f184388a | ||
|
|
d8471698ab | ||
|
|
6204cecbbd | ||
|
|
ddeca49916 | ||
|
|
d8dcf37886 | ||
|
|
5ae41a208b | ||
|
|
0462d900e6 | ||
|
|
0f962461e1 | ||
|
|
aadc03c38d | ||
|
|
683fa13bb2 | ||
|
|
e4408a964d | ||
|
|
f97f33ab59 | ||
|
|
f59102ee09 | ||
|
|
e42e4e1ddf | ||
|
|
a30079c45b | ||
|
|
50ffd9aba6 | ||
|
|
936fec1f49 | ||
|
|
9625d87dd5 | ||
|
|
802139205c | ||
|
|
fb918cb2a4 | ||
|
|
abb4de46d7 | ||
|
|
dce9631399 | ||
|
|
6c773786d2 | ||
|
|
8939963187 | ||
|
|
f9747d1c4c | ||
|
|
60a3d3409e | ||
|
|
b72124c0d9 | ||
|
|
d51e761b26 | ||
|
|
1445ef61a0 | ||
|
|
dfe2ed2a98 | ||
|
|
be87103b53 | ||
|
|
2fb460c4bb | ||
|
|
216ea230a8 | ||
|
|
90096163ee | ||
|
|
cd178d6a8c | ||
|
|
2aa0b5ddfb | ||
|
|
37f819458a | ||
|
|
168f4301d2 | ||
|
|
d5a406c60f | ||
|
|
cb16210577 | ||
|
|
8c0e0de45f | ||
|
|
3524cba4ef | ||
|
|
5f8d1cf5b0 | ||
|
|
846aa823d4 | ||
|
|
68298fc585 | ||
|
|
e9d75f6d94 | ||
|
|
8fa5277417 | ||
|
|
231f1f236d | ||
|
|
ece0a46f97 | ||
|
|
2c9b0b8376 | ||
|
|
a798f2d61c | ||
|
|
ae08c87822 | ||
|
|
ae880e9d1c | ||
|
|
101d2e1de5 | ||
|
|
f6b7708567 | ||
|
|
051286acd1 |
@@ -34,11 +34,12 @@ local _TraceClassMethod = {}
|
||||
|
||||
local _ClassID = 0
|
||||
|
||||
---
|
||||
--- Base class of everything
|
||||
-- @type BASE
|
||||
-- @field ClassName The name of the class.
|
||||
-- @field ClassID The ID number of the class.
|
||||
-- @field ClassNameAndID The name of the class concatenated with the ID number of the class.
|
||||
-- @field #string ClassName The name of the class.
|
||||
-- @field #number ClassID The ID number of the class.
|
||||
-- @field #string ClassNameAndID The name of the class concatenated with the ID number of the class.
|
||||
-- @field Core.Scheduler#SCHEDULER Scheduler The scheduler object.
|
||||
|
||||
--- BASE class
|
||||
--
|
||||
@@ -210,14 +211,6 @@ BASE._ = {
|
||||
Schedules = {}, --- Contains the Schedulers Active
|
||||
}
|
||||
|
||||
--- The Formation Class
|
||||
-- @type FORMATION
|
||||
-- @field Cone A cone formation.
|
||||
FORMATION = {
|
||||
Cone = "Cone",
|
||||
Vee = "Vee",
|
||||
}
|
||||
|
||||
--- BASE constructor.
|
||||
--
|
||||
-- This is an example how to use the BASE:New() constructor in a new class definition when inheriting from BASE.
|
||||
@@ -1416,7 +1409,7 @@ function BASE:E( Arguments )
|
||||
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
||||
else
|
||||
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, BASE:_Serialize(Arguments) ) )
|
||||
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, UTILS.BasicSerialize(Arguments) ) )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1443,7 +1436,7 @@ function BASE:I( Arguments )
|
||||
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, UTILS.BasicSerialize( Arguments ) ) )
|
||||
else
|
||||
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, BASE:_Serialize(Arguments)) )
|
||||
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, UTILS.BasicSerialize(Arguments)) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -211,10 +211,9 @@ function DATABASE:AddStatic( DCSStaticName )
|
||||
|
||||
if not self.STATICS[DCSStaticName] then
|
||||
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
|
||||
return self.STATICS[DCSStaticName]
|
||||
end
|
||||
|
||||
return nil
|
||||
return self.STATICS[DCSStaticName]
|
||||
end
|
||||
|
||||
|
||||
@@ -224,12 +223,11 @@ function DATABASE:DeleteStatic( DCSStaticName )
|
||||
self.STATICS[DCSStaticName] = nil
|
||||
end
|
||||
|
||||
--- Finds a STATIC based on the StaticName.
|
||||
--- Finds a STATIC based on the Static Name.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string StaticName
|
||||
-- @param #string StaticName Name of the static object.
|
||||
-- @return Wrapper.Static#STATIC The found STATIC.
|
||||
function DATABASE:FindStatic( StaticName )
|
||||
|
||||
local StaticFound = self.STATICS[StaticName]
|
||||
return StaticFound
|
||||
end
|
||||
@@ -241,9 +239,8 @@ end
|
||||
function DATABASE:AddDynamicCargo( Name )
|
||||
if not self.DYNAMICCARGO[Name] then
|
||||
self.DYNAMICCARGO[Name] = DYNAMICCARGO:Register(Name)
|
||||
return self.DYNAMICCARGO[Name]
|
||||
end
|
||||
return nil
|
||||
return self.DYNAMICCARGO[Name]
|
||||
end
|
||||
|
||||
--- Finds a DYNAMICCARGO based on the Dynamic Cargo Name.
|
||||
@@ -1582,12 +1579,29 @@ end
|
||||
-- @param DCS#Airbase airbase Airbase.
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:_RegisterAirbase(airbase)
|
||||
|
||||
|
||||
local IsSyria = UTILS.GetDCSMap() == "Syria" and true or false
|
||||
local countHSyria = 0
|
||||
|
||||
if airbase then
|
||||
|
||||
-- Get the airbase name.
|
||||
local DCSAirbaseName = airbase:getName()
|
||||
|
||||
|
||||
-- DCS 2.9.8.1107 added 143 helipads all named H with the same object ID ..
|
||||
if IsSyria and DCSAirbaseName == "H" and countHSyria > 0 then
|
||||
--[[
|
||||
local p = airbase:getPosition().p
|
||||
local mgrs = COORDINATE:New(p.x,p.z,p.y):ToStringMGRS()
|
||||
self:I("Airbase on Syria map named H @ "..mgrs)
|
||||
countHSyria = countHSyria + 1
|
||||
if countHSyria > 1 then return self end
|
||||
--]]
|
||||
return self
|
||||
elseif IsSyria and DCSAirbaseName == "H" and countHSyria == 0 then
|
||||
countHSyria = countHSyria + 1
|
||||
end
|
||||
|
||||
-- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
|
||||
local airbaseID=airbase:getID()
|
||||
|
||||
|
||||
@@ -1329,6 +1329,7 @@ function EVENT:onEvent( Event )
|
||||
end
|
||||
|
||||
Event.IniDCSGroupName = Event.IniUnit and Event.IniUnit.GroupName or ""
|
||||
Event.IniGroupName=Event.IniDCSGroupName --At least set the group name because group might not exist any more
|
||||
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
|
||||
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
|
||||
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
||||
@@ -1371,7 +1372,7 @@ function EVENT:onEvent( Event )
|
||||
-- Scenery
|
||||
---
|
||||
Event.IniDCSUnit = Event.initiator
|
||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||
Event.IniDCSUnitName = Event.IniDCSUnit.getName and Event.IniDCSUnit:getName() or "Scenery no name "..math.random(1,20000)
|
||||
Event.IniUnitName = Event.IniDCSUnitName
|
||||
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
@@ -1473,11 +1474,13 @@ function EVENT:onEvent( Event )
|
||||
-- SCENERY
|
||||
---
|
||||
Event.TgtDCSUnit = Event.target
|
||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
Event.TgtDCSUnitName = Event.TgtDCSUnit.getName and Event.TgtDCSUnit.getName() or nil
|
||||
if Event.TgtDCSUnitName~=nil then
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
Event.TgtUnit = SCENERY:Register( Event.TgtDCSUnitName, Event.target )
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -108,26 +108,30 @@ function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
||||
--- On after "MarkAdded" event. Triggered when a Marker is added to the F10 map.
|
||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded
|
||||
-- @param #MARKEROPS_BASE self
|
||||
-- @param #string From The From state
|
||||
-- @param #string Event The Event called
|
||||
-- @param #string To The To state
|
||||
-- @param #string Text The text on the marker
|
||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||
-- @param #string From The From state.
|
||||
-- @param #string Event The Event called.
|
||||
-- @param #string To The To state.
|
||||
-- @param #string Text The text on the marker.
|
||||
-- @param #table Keywords Table of matching keywords found in the Event text.
|
||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||
-- @param #number MarkerID Id of this marker
|
||||
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||
-- @param #number MarkerID Id of this marker.
|
||||
-- @param #number CoalitionNumber Coalition of the marker creator.
|
||||
-- @param #string PlayerName Name of the player creating/changing the mark. nil if it cannot be obtained.
|
||||
-- @param Core.Event#EVENTDATA EventData the event data table.
|
||||
|
||||
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
|
||||
-- @param #MARKEROPS_BASE self
|
||||
-- @param #string From The From state
|
||||
-- @param #string Event The Event called
|
||||
-- @param #string To The To state
|
||||
-- @param #string Text The text on the marker
|
||||
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||
-- @param #string From The From state.
|
||||
-- @param #string Event The Event called.
|
||||
-- @param #string To The To state.
|
||||
-- @param #string Text The text on the marker.
|
||||
-- @param #table Keywords Table of matching keywords found in the Event text.
|
||||
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||
-- @param #number MarkerID Id of this marker
|
||||
-- @param #number CoalitionNumber Coalition of the marker creator
|
||||
-- @param #number MarkerID Id of this marker.
|
||||
-- @param #number CoalitionNumber Coalition of the marker creator.
|
||||
-- @param #string PlayerName Name of the player creating/changing the mark. nil if it cannot be obtained.
|
||||
-- @param Core.Event#EVENTDATA EventData the event data table
|
||||
|
||||
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
|
||||
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
|
||||
@@ -167,7 +171,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
if Eventtext~=nil then
|
||||
if self:_MatchTag(Eventtext) then
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition)
|
||||
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
end
|
||||
end
|
||||
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
||||
@@ -177,7 +181,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
if Eventtext~=nil then
|
||||
if self:_MatchTag(Eventtext) then
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition)
|
||||
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
end
|
||||
end
|
||||
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||
|
||||
@@ -75,35 +75,37 @@ MESSAGE.Type = {
|
||||
|
||||
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{#MESSAGE.ToClient} or @{#MESSAGE.ToCoalition} or @{#MESSAGE.ToAll} to send these Messages to the respective recipients.
|
||||
-- @param self
|
||||
-- @param #string MessageText is the text of the Message.
|
||||
-- @param #number MessageDuration is a number in seconds of how long the MESSAGE should be shown on the display panel.
|
||||
-- @param #string MessageCategory (optional) is a string expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ".
|
||||
-- @param #string Text is the text of the Message.
|
||||
-- @param #number Duration Duration in seconds how long the message text is shown.
|
||||
-- @param #string Category (Optional) String expressing the "category" of the Message. The category will be shown as the first text in the message followed by a ": ".
|
||||
-- @param #boolean ClearScreen (optional) Clear all previous messages if true.
|
||||
-- @return #MESSAGE
|
||||
-- @return #MESSAGE self
|
||||
-- @usage
|
||||
--
|
||||
-- -- Create a series of new Messages.
|
||||
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
|
||||
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
|
||||
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
||||
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
||||
-- -- Create a series of new Messages.
|
||||
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
|
||||
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
|
||||
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
||||
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" )
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
|
||||
--
|
||||
function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen )
|
||||
function MESSAGE:New( Text, Duration, Category, ClearScreen )
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
self:F( { MessageText, MessageDuration, MessageCategory } )
|
||||
|
||||
self:F( { Text, Duration, Category } )
|
||||
|
||||
self.MessageType = nil
|
||||
|
||||
-- When no MessageCategory is given, we don't show it as a title...
|
||||
if MessageCategory and MessageCategory ~= "" then
|
||||
if MessageCategory:sub( -1 ) ~= "\n" then
|
||||
self.MessageCategory = MessageCategory .. ": "
|
||||
if Category and Category ~= "" then
|
||||
if Category:sub( -1 ) ~= "\n" then
|
||||
self.MessageCategory = Category .. ": "
|
||||
else
|
||||
self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n"
|
||||
self.MessageCategory = Category:sub( 1, -2 ) .. ":\n"
|
||||
end
|
||||
else
|
||||
self.MessageCategory = ""
|
||||
@@ -114,9 +116,9 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen
|
||||
self.ClearScreen = ClearScreen
|
||||
end
|
||||
|
||||
self.MessageDuration = MessageDuration or 5
|
||||
self.MessageDuration = Duration or 5
|
||||
self.MessageTime = timer.getTime()
|
||||
self.MessageText = MessageText:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
|
||||
self.MessageText = Text:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
|
||||
|
||||
self.MessageSent = false
|
||||
self.MessageGroup = false
|
||||
|
||||
@@ -1709,7 +1709,7 @@ do
|
||||
|
||||
--- Iterate the SET_GROUP and return true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE}
|
||||
-- @param #SET_GROUP self
|
||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
||||
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||
-- @return #boolean true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE}, false otherwise
|
||||
-- @usage
|
||||
-- local MyZone = ZONE:New("Zone1")
|
||||
@@ -1756,7 +1756,7 @@ do
|
||||
|
||||
--- Iterate the SET_GROUP and return true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE}
|
||||
-- @param #SET_GROUP self
|
||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
||||
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE}, false otherwise.
|
||||
-- @usage
|
||||
-- local MyZone = ZONE:New("Zone1")
|
||||
@@ -1781,7 +1781,7 @@ do
|
||||
|
||||
--- Iterate the SET_GROUP and return true if at least one @{#UNIT} of one @{Wrapper.Group#GROUP} of the @{#SET_GROUP} is in @{Core.Zone}
|
||||
-- @param #SET_GROUP self
|
||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
||||
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise.
|
||||
-- @usage
|
||||
-- local MyZone = ZONE:New("Zone1")
|
||||
@@ -1807,7 +1807,7 @@ do
|
||||
--- Iterate the SET_GROUP and return true if at least one @{Wrapper.Group#GROUP} of the @{#SET_GROUP} is partly in @{Core.Zone}.
|
||||
-- Will return false if a @{Wrapper.Group#GROUP} is fully in the @{Core.Zone}
|
||||
-- @param #SET_GROUP self
|
||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
||||
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||
-- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise.
|
||||
-- @usage
|
||||
-- local MyZone = ZONE:New("Zone1")
|
||||
@@ -1842,7 +1842,7 @@ do
|
||||
-- This could also be achieved with `not SET_GROUP:AnyPartlyInZone(Zone)`, but it's easier for the
|
||||
-- mission designer to add a dedicated method
|
||||
-- @param #SET_GROUP self
|
||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
||||
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||
-- @return #boolean true if no @{Wrapper.Group#GROUP} is inside the @{Core.Zone#ZONE} in any way, false otherwise.
|
||||
-- @usage
|
||||
-- local MyZone = ZONE:New("Zone1")
|
||||
@@ -1869,7 +1869,7 @@ do
|
||||
-- That could easily be done with SET_GROUP:ForEachGroupCompletelyInZone(), but this function
|
||||
-- provides an easy to use shortcut...
|
||||
-- @param #SET_GROUP self
|
||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
||||
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||
-- @return #number the number of GROUPs completely in the Zone
|
||||
-- @usage
|
||||
-- local MyZone = ZONE:New("Zone1")
|
||||
@@ -1891,7 +1891,7 @@ do
|
||||
|
||||
--- Iterate the SET_GROUP and count how many UNITs are completely in the Zone
|
||||
-- @param #SET_GROUP self
|
||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
||||
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||
-- @return #number the number of GROUPs completely in the Zone
|
||||
-- @usage
|
||||
-- local MyZone = ZONE:New("Zone1")
|
||||
@@ -2706,7 +2706,7 @@ do -- SET_UNIT
|
||||
|
||||
--- Check if no element of the SET_UNIT is in the Zone.
|
||||
-- @param #SET_UNIT self
|
||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
||||
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||
-- @return #boolean
|
||||
function SET_UNIT:IsNotInZone( Zone )
|
||||
|
||||
@@ -3746,7 +3746,7 @@ do -- SET_STATIC
|
||||
|
||||
--- Check if no element of the SET_STATIC is in the Zone.
|
||||
-- @param #SET_STATIC self
|
||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
||||
-- @param Core.Zone#ZONE Zone The Zone to be tested for.
|
||||
-- @return #boolean
|
||||
function SET_STATIC:IsNotInZone( Zone )
|
||||
|
||||
@@ -7936,22 +7936,31 @@ do -- SET_OPSGROUP
|
||||
--- Handles the OnBirth event for the Set.
|
||||
-- @param #SET_OPSGROUP self
|
||||
-- @param Core.Event#EVENTDATA Event Event data.
|
||||
function SET_OPSGROUP:_EventOnBirth( Event )
|
||||
function SET_OPSGROUP:_EventOnBirth(Event)
|
||||
--self:F3( { Event } )
|
||||
|
||||
if Event.IniDCSUnit and Event.IniDCSGroup then
|
||||
local DCSgroup=Event.IniDCSGroup --DCS#Group
|
||||
local DCSgroup = Event.IniDCSGroup --DCS#Group
|
||||
|
||||
if DCSgroup:getInitialSize() == DCSgroup:getSize() then -- This seems to be not a good check as even for the first birth event, getSize returns the total number of units in the group.
|
||||
|
||||
local groupname, group = self:AddInDatabase( Event )
|
||||
|
||||
if group and group:CountAliveUnits()==DCSgroup:getInitialSize() then
|
||||
if group and self:IsIncludeObject( group ) then
|
||||
self:Add( groupname, group )
|
||||
end
|
||||
-- group:CountAliveUnits() alternative as this fails for Respawn/Teleport
|
||||
local CountAliveActive = 0
|
||||
for index, data in pairs(DCSgroup:getUnits()) do
|
||||
if data:isExist() and data:isActive() then
|
||||
CountAliveActive = CountAliveActive + 1
|
||||
end
|
||||
end
|
||||
|
||||
if DCSgroup:getInitialSize() == DCSgroup:getSize() then
|
||||
|
||||
local groupname, group = self:AddInDatabase(Event)
|
||||
|
||||
-- group:CountAliveUnits() alternative
|
||||
if group and CountAliveActive == DCSgroup:getInitialSize() then
|
||||
if group and self:IsIncludeObject(group) then
|
||||
self:Add(groupname, group)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8355,14 +8364,17 @@ do -- SET_SCENERY
|
||||
-- @param #SET_SCENERY self
|
||||
-- @return Core.Point#COORDINATE The center coordinate of all the objects in the set.
|
||||
function SET_SCENERY:GetCoordinate()
|
||||
|
||||
--[[
|
||||
local Coordinate = COORDINATE:New({0,0,0})
|
||||
|
||||
|
||||
local Item = self:GetRandomSurely()
|
||||
|
||||
if Item then
|
||||
Coordinate:GetCoordinate()
|
||||
end
|
||||
--]]
|
||||
|
||||
local Coordinate = self:GetFirst():GetCoordinate()
|
||||
|
||||
local x1 = Coordinate.x
|
||||
local x2 = Coordinate.x
|
||||
|
||||
@@ -1226,7 +1226,7 @@ end
|
||||
-- @param Core.Point#COORDINATE Coordinate The position to spawn from
|
||||
-- @return #SPAWN self
|
||||
function SPAWN:InitPositionCoordinate(Coordinate)
|
||||
self:T2( { self.SpawnTemplatePrefix, Coordinate:GetVec2()} )
|
||||
--self:T2( { self.SpawnTemplatePrefix, Coordinate:GetVec2()} )
|
||||
self:InitPositionVec2(Coordinate:GetVec2())
|
||||
return self
|
||||
end
|
||||
@@ -1236,10 +1236,10 @@ end
|
||||
-- @param DCS#Vec2 Vec2 The position to spawn from
|
||||
-- @return #SPAWN self
|
||||
function SPAWN:InitPositionVec2(Vec2)
|
||||
self:T2( { self.SpawnTemplatePrefix, Vec2} )
|
||||
--self:T2( { self.SpawnTemplatePrefix, Vec2} )
|
||||
self.SpawnInitPosition = Vec2
|
||||
self.SpawnFromNewPosition = true
|
||||
self:T2("MaxGroups:"..self.SpawnMaxGroups)
|
||||
--self:T2("MaxGroups:"..self.SpawnMaxGroups)
|
||||
for SpawnGroupID = 1, self.SpawnMaxGroups do
|
||||
self:_SetInitialPosition( SpawnGroupID )
|
||||
end
|
||||
@@ -1334,7 +1334,7 @@ function SPAWN:InitCleanUp( SpawnCleanUpInterval )
|
||||
self.SpawnCleanUpTimeStamps = {}
|
||||
|
||||
local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup()
|
||||
self:T2( { "CleanUp Scheduler:", SpawnGroup } )
|
||||
--self:T2( { "CleanUp Scheduler:", SpawnGroup } )
|
||||
|
||||
self.CleanUpScheduler = SCHEDULER:New( self, self._SpawnCleanUpScheduler, {}, 1, SpawnCleanUpInterval, 0.2 )
|
||||
return self
|
||||
@@ -1367,7 +1367,7 @@ function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY )
|
||||
local SpawnYIndex = 0
|
||||
|
||||
for SpawnGroupID = 1, self.SpawnMaxGroups do
|
||||
self:T2( { SpawnX, SpawnY, SpawnXIndex, SpawnYIndex } )
|
||||
--self:T2( { SpawnX, SpawnY, SpawnXIndex, SpawnYIndex } )
|
||||
|
||||
self.SpawnGroups[SpawnGroupID].Visible = true
|
||||
self.SpawnGroups[SpawnGroupID].Spawned = false
|
||||
@@ -1391,7 +1391,7 @@ function SPAWN:InitArray( SpawnAngle, SpawnWidth, SpawnDeltaX, SpawnDeltaY )
|
||||
self.SpawnGroups[SpawnGroupID].Visible = true
|
||||
|
||||
self:HandleEvent( EVENTS.Birth, self._OnBirth )
|
||||
--self:HandleEvent( EVENTS.Dead, self._OnDeadOrCrash )
|
||||
self:HandleEvent( EVENTS.Dead, self._OnDeadOrCrash )
|
||||
self:HandleEvent( EVENTS.Crash, self._OnDeadOrCrash )
|
||||
self:HandleEvent( EVENTS.RemoveUnit, self._OnDeadOrCrash )
|
||||
self:HandleEvent( EVENTS.UnitLost, self._OnDeadOrCrash )
|
||||
@@ -1591,7 +1591,7 @@ end
|
||||
-- @param #string SpawnIndex The index of the group to be spawned.
|
||||
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
|
||||
function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
||||
|
||||
--[[
|
||||
local set = SET_GROUP:New():FilterAlive():FilterPrefixes({self.SpawnTemplatePrefix, self.SpawnAliasPrefix}):FilterOnce()
|
||||
local aliveunits = 0
|
||||
set:ForEachGroupAlive(
|
||||
@@ -1602,12 +1602,12 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
||||
|
||||
if aliveunits ~= self.AliveUnits then
|
||||
self.AliveUnits = aliveunits
|
||||
self:T2("***** self.AliveUnits accounting failure! Corrected! *****")
|
||||
--self:T2("***** self.AliveUnits accounting failure! Corrected! *****")
|
||||
end
|
||||
|
||||
set= nil
|
||||
|
||||
self:T2( { SpawnTemplatePrefix = self.SpawnTemplatePrefix, SpawnIndex = SpawnIndex, AliveUnits = self.AliveUnits, SpawnMaxGroups = self.SpawnMaxGroups } )
|
||||
--]]
|
||||
--self:T2( { SpawnTemplatePrefix = self.SpawnTemplatePrefix, SpawnIndex = SpawnIndex, AliveUnits = self.AliveUnits, SpawnMaxGroups = self.SpawnMaxGroups } )
|
||||
|
||||
if self:_GetSpawnIndex( SpawnIndex ) then
|
||||
|
||||
@@ -1622,12 +1622,12 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
||||
|
||||
local SpawnTemplate = self.SpawnGroups[self.SpawnIndex].SpawnTemplate
|
||||
local SpawnZone = self.SpawnGroups[self.SpawnIndex].SpawnZone
|
||||
self:T2( SpawnTemplate.name )
|
||||
--self:T2( SpawnTemplate.name )
|
||||
|
||||
if SpawnTemplate then
|
||||
|
||||
local PointVec3 = POINT_VEC3:New( SpawnTemplate.route.points[1].x, SpawnTemplate.route.points[1].alt, SpawnTemplate.route.points[1].y )
|
||||
self:T2( { "Current point of ", self.SpawnTemplatePrefix, PointVec3 } )
|
||||
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, PointVec3 } )
|
||||
|
||||
-- If RandomizePosition, then Randomize the formation in the zone band, keeping the template.
|
||||
if self.SpawnRandomizePosition then
|
||||
@@ -1639,7 +1639,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
||||
for UnitID = 1, #SpawnTemplate.units do
|
||||
SpawnTemplate.units[UnitID].x = SpawnTemplate.units[UnitID].x + (RandomVec2.x - CurrentX)
|
||||
SpawnTemplate.units[UnitID].y = SpawnTemplate.units[UnitID].y + (RandomVec2.y - CurrentY)
|
||||
self:T2( 'SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
--self:T2( 'SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1660,13 +1660,13 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
||||
end
|
||||
end
|
||||
if (not inZone) then
|
||||
self:T2("Could not place unit within zone and within radius!")
|
||||
--self:T2("Could not place unit within zone and within radius!")
|
||||
RandomVec2 = SpawnZone:GetRandomVec2()
|
||||
end
|
||||
end
|
||||
SpawnTemplate.units[UnitID].x = RandomVec2.x
|
||||
SpawnTemplate.units[UnitID].y = RandomVec2.y
|
||||
self:T2( 'SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
--self:T2( 'SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1887,6 +1887,7 @@ end
|
||||
|
||||
--- Spawns new groups at varying time intervals.
|
||||
-- This is useful if you want to have continuity within your missions of certain (AI) groups to be present (alive) within your missions.
|
||||
-- **WARNING** - Setting a very low SpawnTime heavily impacts your mission performance and CPU time, it is NOT useful to check the alive state of an object every split second! Be reasonable and stay at 15 seconds and above!
|
||||
-- @param #SPAWN self
|
||||
-- @param #number SpawnTime The time interval defined in seconds between each new spawn of new groups.
|
||||
-- @param #number SpawnTimeVariation The variation to be applied on the defined time interval between each new spawn.
|
||||
@@ -1909,6 +1910,14 @@ function SPAWN:SpawnScheduled( SpawnTime, SpawnTimeVariation, WithDelay )
|
||||
local SpawnTime = SpawnTime or 60
|
||||
local SpawnTimeVariation = SpawnTimeVariation or 0.5
|
||||
|
||||
-- Noob catch
|
||||
if SpawnTime < 15 then
|
||||
self:E("****SPAWN SCHEDULED****\nWARNING - Setting a very low SpawnTime heavily impacts your mission performance and CPU time, it is NOT useful to check the alive state of an object every "..tostring(SpawnTime).." seconds.\nSetting to 15 second intervals.\n*****")
|
||||
SpawnTime = 15
|
||||
end
|
||||
|
||||
if SpawnTimeVariation > 1 or SpawnTimeVariation < 0 then SpawnTimeVariation = 0.5 end
|
||||
|
||||
if SpawnTime ~= nil and SpawnTimeVariation ~= nil then
|
||||
local InitialDelay = 0
|
||||
if WithDelay or self.DelayOnOff == true then
|
||||
@@ -2024,7 +2033,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
|
||||
-- Get position of airbase.
|
||||
local PointVec3 = SpawnAirbase:GetCoordinate()
|
||||
self:T2( PointVec3 )
|
||||
--self:T2( PointVec3 )
|
||||
|
||||
-- Set take off type. Default is hot.
|
||||
Takeoff = Takeoff or SPAWN.Takeoff.Hot
|
||||
@@ -2053,7 +2062,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
--self:F( { GroupAlive = GroupAlive } )
|
||||
|
||||
-- Debug output
|
||||
self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
|
||||
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
|
||||
|
||||
-- Template group, unit and its attributes.
|
||||
local TemplateGroup = GROUP:FindByName( self.SpawnTemplatePrefix )
|
||||
@@ -2102,7 +2111,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
|
||||
-- Check if we spawn on ground.
|
||||
local spawnonground = not (Takeoff == SPAWN.Takeoff.Air)
|
||||
self:T2( { spawnonground = spawnonground, TOtype = Takeoff, TOair = Takeoff == SPAWN.Takeoff.Air } )
|
||||
--self:T2( { spawnonground = spawnonground, TOtype = Takeoff, TOair = Takeoff == SPAWN.Takeoff.Air } )
|
||||
|
||||
-- Check where we actually spawn if we spawn on ground.
|
||||
local spawnonship = false
|
||||
@@ -2156,7 +2165,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
-- Number of free parking spots at the airbase.
|
||||
if spawnonship or spawnonfarp or spawnonrunway then
|
||||
-- These places work procedural and have some kind of build in queue ==> Less effort.
|
||||
self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
--self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
|
||||
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
|
||||
--[[
|
||||
@@ -2169,18 +2178,18 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
if ishelo then
|
||||
if termtype == nil then
|
||||
-- Helo is spawned. Try exclusive helo spots first.
|
||||
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
|
||||
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
if nfree < nunits then
|
||||
-- Not enough helo ports. Let's try also other terminal types.
|
||||
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
|
||||
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
end
|
||||
else
|
||||
-- No terminal type specified. We try all spots except shelters.
|
||||
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
|
||||
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
end
|
||||
@@ -2189,23 +2198,23 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
if termtype == nil then
|
||||
if isbomber or istransport or istanker or isawacs then
|
||||
-- First we fill the potentially bigger spots.
|
||||
self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig ) )
|
||||
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
if nfree < nunits then
|
||||
-- Now we try the smaller ones.
|
||||
self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig ) )
|
||||
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
end
|
||||
else
|
||||
self:T2( string.format( "Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft ) )
|
||||
--self:T2( string.format( "Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
end
|
||||
else
|
||||
-- Terminal type explicitly given.
|
||||
self:T2( string.format( "Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring( termtype ) ) )
|
||||
--self:T2( string.format( "Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring( termtype ) ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
end
|
||||
@@ -2215,12 +2224,12 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
-- Debug: Get parking data.
|
||||
--[[
|
||||
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
|
||||
self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
||||
--self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
||||
for _,_spot in pairs(parkingdata) do
|
||||
self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
|
||||
--self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
|
||||
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
|
||||
end
|
||||
self:T2(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
||||
--self:T2(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
||||
]]
|
||||
|
||||
-- Set this to true if not enough spots are available for emergency air start.
|
||||
@@ -2315,7 +2324,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
SpawnTemplate.parked = true
|
||||
|
||||
for UnitID = 1, nunits do
|
||||
self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
--self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
|
||||
-- Template of the current unit.
|
||||
local UnitTemplate = SpawnTemplate.units[UnitID]
|
||||
@@ -2333,7 +2342,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
-- Ships and FARPS seem to have a build in queue.
|
||||
if spawnonship or spawnonfarp or spawnonrunway then
|
||||
|
||||
self:T2( string.format( "Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
--self:T2( string.format( "Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
|
||||
-- Spawn on ship. We take only the position of the ship.
|
||||
SpawnTemplate.units[UnitID].x = PointVec3.x -- TX
|
||||
@@ -2342,7 +2351,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
|
||||
else
|
||||
|
||||
self:T2( string.format( "Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID] ) )
|
||||
--self:T2( string.format( "Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID] ) )
|
||||
|
||||
-- Get coordinates of parking spot.
|
||||
SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x
|
||||
@@ -2354,7 +2363,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
|
||||
else
|
||||
|
||||
self:T2( string.format( "Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
--self:T2( string.format( "Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
|
||||
-- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
|
||||
SpawnTemplate.units[UnitID].x = TX
|
||||
@@ -2371,9 +2380,9 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
||||
end
|
||||
|
||||
-- Debug output.
|
||||
self:T2( string.format( "Group %s unit number %d: Parking = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking ) ) )
|
||||
self:T2( string.format( "Group %s unit number %d: Parking ID = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking_id ) ) )
|
||||
self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
--self:T2( string.format( "Group %s unit number %d: Parking = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking ) ) )
|
||||
--self:T2( string.format( "Group %s unit number %d: Parking ID = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking_id ) ) )
|
||||
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2451,10 +2460,10 @@ function SPAWN:SpawnAtParkingSpot( Airbase, Spots, Takeoff )
|
||||
-- Get parking spot data.
|
||||
local spot = Airbase:GetParkingSpotData( TerminalID )
|
||||
|
||||
self:T2( { spot = spot } )
|
||||
--self:T2( { spot = spot } )
|
||||
|
||||
if spot and spot.Free then
|
||||
self:T2( string.format( "Adding parking spot ID=%d TermType=%d", spot.TerminalID, spot.TerminalType ) )
|
||||
--self:T2( string.format( "Adding parking spot ID=%d TermType=%d", spot.TerminalID, spot.TerminalType ) )
|
||||
table.insert( Parkingdata, spot )
|
||||
end
|
||||
|
||||
@@ -2486,7 +2495,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
|
||||
-- Get position of airbase.
|
||||
local PointVec3 = SpawnAirbase:GetCoordinate()
|
||||
self:T2( PointVec3 )
|
||||
--self:T2( PointVec3 )
|
||||
|
||||
-- Set take off type. Default is hot.
|
||||
local Takeoff = SPAWN.Takeoff.Cold
|
||||
@@ -2502,7 +2511,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
local GroupAlive = self:GetGroupFromIndex( SpawnIndex )
|
||||
|
||||
-- Debug output
|
||||
self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
|
||||
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
|
||||
|
||||
-- Template group, unit and its attributes.
|
||||
local TemplateGroup = GROUP:FindByName( self.SpawnTemplatePrefix )
|
||||
@@ -2546,7 +2555,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
|
||||
-- Check if we spawn on ground.
|
||||
local spawnonground = not (Takeoff == SPAWN.Takeoff.Air)
|
||||
self:T2( { spawnonground = spawnonground, TOtype = Takeoff, TOair = Takeoff == SPAWN.Takeoff.Air } )
|
||||
--self:T2( { spawnonground = spawnonground, TOtype = Takeoff, TOair = Takeoff == SPAWN.Takeoff.Air } )
|
||||
|
||||
-- Check where we actually spawn if we spawn on ground.
|
||||
local spawnonship = false
|
||||
@@ -2588,7 +2597,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
-- Number of free parking spots at the airbase.
|
||||
if spawnonship or spawnonfarp or spawnonrunway then
|
||||
-- These places work procedural and have some kind of build in queue ==> Less effort.
|
||||
self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
--self:T2( string.format( "Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
nfree = SpawnAirbase:GetFreeParkingSpotsNumber( termtype, true )
|
||||
spots = SpawnAirbase:GetFreeParkingSpotsTable( termtype, true )
|
||||
--[[
|
||||
@@ -2601,18 +2610,18 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
if ishelo then
|
||||
if termtype == nil then
|
||||
-- Helo is spawned. Try exclusive helo spots first.
|
||||
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
|
||||
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
if nfree < nunits then
|
||||
-- Not enough helo ports. Let's try also other terminal types.
|
||||
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
|
||||
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
end
|
||||
else
|
||||
-- No terminal type specified. We try all spots except shelters.
|
||||
self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
|
||||
--self:T2( string.format( "Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
end
|
||||
@@ -2624,23 +2633,23 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
-- TODO: Some attributes are "Helicopters", "Bombers", "Transports", "Battleplanes". Need to check it out.
|
||||
if isbomber or istransport then
|
||||
-- First we fill the potentially bigger spots.
|
||||
self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig ) )
|
||||
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
if nfree < nunits then
|
||||
-- Now we try the smaller ones.
|
||||
self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig ) )
|
||||
--self:T2( string.format( "Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
end
|
||||
else
|
||||
self:T2( string.format( "Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft ) )
|
||||
--self:T2( string.format( "Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
end
|
||||
else
|
||||
-- Terminal type explicitly given.
|
||||
self:T2( string.format( "Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring( termtype ) ) )
|
||||
--self:T2( string.format( "Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring( termtype ) ) )
|
||||
spots = SpawnAirbase:FindFreeParkingSpotForAircraft( TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata )
|
||||
nfree = #spots
|
||||
end
|
||||
@@ -2650,12 +2659,12 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
-- Debug: Get parking data.
|
||||
--[[
|
||||
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
|
||||
self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
||||
--self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
||||
for _,_spot in pairs(parkingdata) do
|
||||
self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
|
||||
--self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
|
||||
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
|
||||
end
|
||||
self:T2(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
||||
--self:T2(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
||||
]]
|
||||
|
||||
-- Set this to true if not enough spots are available for emergency air start.
|
||||
@@ -2733,7 +2742,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
-- Ships and FARPS seem to have a build in queue.
|
||||
if spawnonship or spawnonfarp or spawnonrunway then
|
||||
|
||||
self:T2( string.format( "Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
--self:T2( string.format( "Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
|
||||
-- Spawn on ship. We take only the position of the ship.
|
||||
SpawnTemplate.units[UnitID].x = PointVec3.x -- TX
|
||||
@@ -2742,7 +2751,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
|
||||
else
|
||||
|
||||
self:T2( string.format( "Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID] ) )
|
||||
--self:T2( string.format( "Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID] ) )
|
||||
|
||||
-- Get coordinates of parking spot.
|
||||
SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x
|
||||
@@ -2754,7 +2763,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
|
||||
else
|
||||
|
||||
self:T2( string.format( "Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
--self:T2( string.format( "Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName() ) )
|
||||
|
||||
-- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
|
||||
SpawnTemplate.units[UnitID].x = TX
|
||||
@@ -2771,9 +2780,9 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
||||
end
|
||||
|
||||
-- Debug output.
|
||||
self:T2( string.format( "Group %s unit number %d: Parking = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking ) ) )
|
||||
self:T2( string.format( "Group %s unit number %d: Parking ID = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking_id ) ) )
|
||||
self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
--self:T2( string.format( "Group %s unit number %d: Parking = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking ) ) )
|
||||
--self:T2( string.format( "Group %s unit number %d: Parking ID = %s", self.SpawnTemplatePrefix, UnitID, tostring( UnitTemplate.parking_id ) ) )
|
||||
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2871,7 +2880,7 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
||||
--self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } )
|
||||
|
||||
local PointVec3 = POINT_VEC3:NewFromVec3( Vec3 )
|
||||
self:T2( PointVec3 )
|
||||
--self:T2( PointVec3 )
|
||||
|
||||
if SpawnIndex then
|
||||
else
|
||||
@@ -2884,7 +2893,7 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
||||
|
||||
if SpawnTemplate then
|
||||
|
||||
self:T2( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } )
|
||||
--self:T2( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } )
|
||||
|
||||
local TemplateHeight = SpawnTemplate.route and SpawnTemplate.route.points[1].alt or nil
|
||||
|
||||
@@ -2909,7 +2918,7 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
||||
if SpawnTemplate.CategoryID ~= Group.Category.SHIP then
|
||||
SpawnTemplate.units[UnitID].alt = Vec3.y or TemplateHeight
|
||||
end
|
||||
self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
end
|
||||
SpawnTemplate.route.points[1].x = Vec3.x
|
||||
SpawnTemplate.route.points[1].y = Vec3.z
|
||||
@@ -3168,10 +3177,10 @@ function SPAWN:SpawnGroupName( SpawnIndex )
|
||||
|
||||
if SpawnIndex then
|
||||
local SpawnName = string.format( '%s#%03d', SpawnPrefix, SpawnIndex )
|
||||
self:T2( SpawnName )
|
||||
--self:T2( SpawnName )
|
||||
return SpawnName
|
||||
else
|
||||
self:T2( SpawnPrefix )
|
||||
--self:T2( SpawnPrefix )
|
||||
return SpawnPrefix
|
||||
end
|
||||
|
||||
@@ -3499,7 +3508,7 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
||||
if SpawnInitKeepUnitIFF == false then
|
||||
UnitPrefix, Rest = string.match( SpawnTemplate.units[UnitID].name, "^([^#]+)#?" ):gsub( "^%s*(.-)%s*$", "%1" )
|
||||
SpawnTemplate.units[UnitID].name = string.format( '%s#%03d-%02d', UnitPrefix, SpawnIndex, UnitID )
|
||||
self:T2( { UnitPrefix, Rest } )
|
||||
--self:T2( { UnitPrefix, Rest } )
|
||||
--else
|
||||
--UnitPrefix=SpawnTemplate.units[UnitID].name
|
||||
end
|
||||
@@ -3713,7 +3722,7 @@ function SPAWN:_RandomizeRoute( SpawnIndex )
|
||||
SpawnTemplate.route.points[t].alt = nil
|
||||
end
|
||||
|
||||
self:T2( 'SpawnTemplate.route.points[' .. t .. '].x = ' .. SpawnTemplate.route.points[t].x .. ', SpawnTemplate.route.points[' .. t .. '].y = ' .. SpawnTemplate.route.points[t].y )
|
||||
--self:T2( 'SpawnTemplate.route.points[' .. t .. '].x = ' .. SpawnTemplate.route.points[t].x .. ', SpawnTemplate.route.points[' .. t .. '].y = ' .. SpawnTemplate.route.points[t].y )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3756,15 +3765,15 @@ end
|
||||
-- @param #number SpawnIndex
|
||||
-- @return #SPAWN self
|
||||
function SPAWN:_SetInitialPosition( SpawnIndex )
|
||||
self:T2( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } )
|
||||
--self:T2( { self.SpawnTemplatePrefix, SpawnIndex, self.SpawnRandomizeZones } )
|
||||
|
||||
if self.SpawnFromNewPosition then
|
||||
|
||||
self:T2( "Preparing Spawn at Vec2 ", self.SpawnInitPosition )
|
||||
--self:T2( "Preparing Spawn at Vec2 ", self.SpawnInitPosition )
|
||||
|
||||
local SpawnVec2 = self.SpawnInitPosition
|
||||
|
||||
self:T2( { SpawnVec2 = SpawnVec2 } )
|
||||
--self:T2( { SpawnVec2 = SpawnVec2 } )
|
||||
|
||||
local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate
|
||||
|
||||
@@ -3774,11 +3783,11 @@ function SPAWN:_SetInitialPosition( SpawnIndex )
|
||||
SpawnTemplate.route.points[1].x = SpawnTemplate.route.points[1].x or 0
|
||||
SpawnTemplate.route.points[1].y = SpawnTemplate.route.points[1].y or 0
|
||||
|
||||
self:T2( { Route = SpawnTemplate.route } )
|
||||
--self:T2( { Route = SpawnTemplate.route } )
|
||||
|
||||
for UnitID = 1, #SpawnTemplate.units do
|
||||
local UnitTemplate = SpawnTemplate.units[UnitID]
|
||||
self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
|
||||
--self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
|
||||
local SX = UnitTemplate.x
|
||||
local SY = UnitTemplate.y
|
||||
local BX = SpawnTemplate.route.points[1].x
|
||||
@@ -3789,7 +3798,7 @@ function SPAWN:_SetInitialPosition( SpawnIndex )
|
||||
UnitTemplate.y = TY
|
||||
-- TODO: Manage altitude based on landheight...
|
||||
-- SpawnTemplate.units[UnitID].alt = SpawnVec2:
|
||||
self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
|
||||
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
|
||||
end
|
||||
|
||||
SpawnTemplate.route.points[1].x = SpawnVec2.x
|
||||
@@ -3812,26 +3821,26 @@ function SPAWN:_RandomizeZones( SpawnIndex )
|
||||
if self.SpawnRandomizeZones then
|
||||
local SpawnZone = nil -- Core.Zone#ZONE_BASE
|
||||
while not SpawnZone do
|
||||
self:T2( { SpawnZoneTableCount = #self.SpawnZoneTable, self.SpawnZoneTable } )
|
||||
--self:T2( { SpawnZoneTableCount = #self.SpawnZoneTable, self.SpawnZoneTable } )
|
||||
local ZoneID = math.random( #self.SpawnZoneTable )
|
||||
self:T2( ZoneID )
|
||||
--self:T2( ZoneID )
|
||||
SpawnZone = self.SpawnZoneTable[ZoneID]:GetZoneMaybe()
|
||||
end
|
||||
|
||||
self:T2( "Preparing Spawn in Zone", SpawnZone:GetName() )
|
||||
--self:T2( "Preparing Spawn in Zone", SpawnZone:GetName() )
|
||||
|
||||
local SpawnVec2 = SpawnZone:GetRandomVec2()
|
||||
|
||||
self:T2( { SpawnVec2 = SpawnVec2 } )
|
||||
--self:T2( { SpawnVec2 = SpawnVec2 } )
|
||||
|
||||
local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate
|
||||
self.SpawnGroups[SpawnIndex].SpawnZone = SpawnZone
|
||||
|
||||
self:T2( { Route = SpawnTemplate.route } )
|
||||
--self:T2( { Route = SpawnTemplate.route } )
|
||||
|
||||
for UnitID = 1, #SpawnTemplate.units do
|
||||
local UnitTemplate = SpawnTemplate.units[UnitID]
|
||||
self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
|
||||
--self:T2( 'Before Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
|
||||
local SX = UnitTemplate.x
|
||||
local SY = UnitTemplate.y
|
||||
local BX = SpawnTemplate.route.points[1].x
|
||||
@@ -3842,7 +3851,7 @@ function SPAWN:_RandomizeZones( SpawnIndex )
|
||||
UnitTemplate.y = TY
|
||||
-- TODO: Manage altitude based on landheight...
|
||||
-- SpawnTemplate.units[UnitID].alt = SpawnVec2:
|
||||
self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
|
||||
--self:T2( 'After Translation SpawnTemplate.units[' .. UnitID .. '].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units[' .. UnitID .. '].y = ' .. UnitTemplate.y )
|
||||
end
|
||||
SpawnTemplate.x = SpawnVec2.x
|
||||
SpawnTemplate.y = SpawnVec2.y
|
||||
@@ -3897,11 +3906,11 @@ end
|
||||
-- @param #number SpawnIndex Spawn index.
|
||||
-- @return #number self.SpawnIndex
|
||||
function SPAWN:_GetSpawnIndex( SpawnIndex )
|
||||
self:T2( { template=self.SpawnTemplatePrefix, SpawnIndex=SpawnIndex, SpawnMaxGroups=self.SpawnMaxGroups, SpawnMaxUnitsAlive=self.SpawnMaxUnitsAlive, AliveUnits=self.AliveUnits, TemplateUnits=#self.SpawnTemplate.units } )
|
||||
--self:T2( { template=self.SpawnTemplatePrefix, SpawnIndex=SpawnIndex, SpawnMaxGroups=self.SpawnMaxGroups, SpawnMaxUnitsAlive=self.SpawnMaxUnitsAlive, AliveUnits=self.AliveUnits, TemplateUnits=#self.SpawnTemplate.units } )
|
||||
|
||||
if (self.SpawnMaxGroups == 0) or (SpawnIndex <= self.SpawnMaxGroups) then
|
||||
if (self.SpawnMaxUnitsAlive == 0) or (self.AliveUnits + #self.SpawnTemplate.units <= self.SpawnMaxUnitsAlive) or self.UnControlled == true then
|
||||
self:T2( { SpawnCount = self.SpawnCount, SpawnIndex = SpawnIndex } )
|
||||
--self:T2( { SpawnCount = self.SpawnCount, SpawnIndex = SpawnIndex } )
|
||||
if SpawnIndex and SpawnIndex >= self.SpawnCount + 1 then
|
||||
self.SpawnCount = self.SpawnCount + 1
|
||||
SpawnIndex = self.SpawnCount
|
||||
@@ -3932,22 +3941,57 @@ function SPAWN:_OnBirth( EventData )
|
||||
if SpawnGroup then
|
||||
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
|
||||
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
||||
self:T2( { "Birth Event:", EventPrefix, self.SpawnTemplatePrefix } )
|
||||
--self:T2( { "Birth Event:", EventPrefix, self.SpawnTemplatePrefix } )
|
||||
if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
|
||||
self.AliveUnits = self.AliveUnits + 1
|
||||
self:T2( "Alive Units: " .. self.AliveUnits )
|
||||
--self:T2( "Alive Units: " .. self.AliveUnits )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---
|
||||
-- @param #SPAWN self
|
||||
-- @return #number count
|
||||
function SPAWN:_CountAliveUnits()
|
||||
local count = 0
|
||||
--self:I("self.SpawnAliasPrefix="..tostring(self.SpawnAliasPrefix).." | self.SpawnTemplatePrefix="..tostring(self.SpawnTemplatePrefix))
|
||||
if self.SpawnAliasPrefix then
|
||||
if not self.SpawnAliasPrefixEscaped then self.SpawnAliasPrefixEscaped = string.gsub(self.SpawnAliasPrefix,"[%p%s]",".") end
|
||||
--self:I("self.SpawnAliasPrefixEscaped="..tostring(self.SpawnAliasPrefixEscaped))
|
||||
local SpawnAliasPrefix = self.SpawnAliasPrefixEscaped
|
||||
local agroups = GROUP:FindAllByMatching(SpawnAliasPrefix)
|
||||
for _,_grp in pairs(agroups) do
|
||||
--self:I("Group Name = " .. _grp:GetName())
|
||||
local game = self:_GetPrefixFromGroupName(_grp.GroupName)
|
||||
--self:I("Game = "..game)
|
||||
--self:I("Count = ".._grp:CountAliveUnits())
|
||||
if game and game == self.SpawnAliasPrefix then
|
||||
count = count + _grp:CountAliveUnits()
|
||||
end
|
||||
end
|
||||
else
|
||||
if not self.SpawnTemplatePrefixEscaped then self.SpawnTemplatePrefixEscaped = string.gsub(self.SpawnTemplatePrefix,"[%p%s]",".") end
|
||||
local SpawnTemplatePrefix = self.SpawnTemplatePrefixEscaped
|
||||
local groups = GROUP:FindAllByMatching(SpawnTemplatePrefix)
|
||||
for _,_grp in pairs(groups) do
|
||||
local game = self:_GetPrefixFromGroupName(_grp.GroupName)
|
||||
if game and game == self.SpawnTemplatePrefix then
|
||||
count = count + _grp:CountAliveUnits()
|
||||
end
|
||||
end
|
||||
end
|
||||
self.AliveUnits = count
|
||||
return self
|
||||
end
|
||||
|
||||
---
|
||||
-- @param #SPAWN self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function SPAWN:_OnDeadOrCrash( EventData )
|
||||
self:T2( "Dead or crash event ID "..tostring(EventData.id or 0))
|
||||
self:T2( "Dead or crash event for "..tostring(EventData.IniUnitName or "none") )
|
||||
--self:I( "Dead or crash event ID "..tostring(EventData.id or 0))
|
||||
--self:I( "Dead or crash event for "..tostring(EventData.IniUnitName or "none") )
|
||||
|
||||
--if EventData.id == EVENTS.Dead then return end
|
||||
|
||||
@@ -3959,12 +4003,14 @@ function SPAWN:_OnDeadOrCrash( EventData )
|
||||
local EventPrefix = self:_GetPrefixFromGroupName(unit.GroupName)
|
||||
|
||||
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
||||
self:T2( { "Dead event: " .. EventPrefix } )
|
||||
self:T2(string.format("EventPrefix = %s | SpawnAliasPrefix = %s | Old AliveUnits = %d",EventPrefix or "",self.SpawnAliasPrefix or "",self.AliveUnits or 0))
|
||||
--self:I(string.format("EventPrefix = %s | SpawnAliasPrefix = %s | Old AliveUnits = %d",EventPrefix or "",self.SpawnAliasPrefix or "",self.AliveUnits or 0))
|
||||
if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) and self.AliveUnits > 0 then
|
||||
self.AliveUnits = self.AliveUnits - 1
|
||||
--self:I( { "Dead event: " .. EventPrefix } )
|
||||
--self.AliveUnits = self.AliveUnits - 1
|
||||
self:ScheduleOnce(1,self._CountAliveUnits,self)
|
||||
--self.AliveUnits = self:_CountAliveUnits()
|
||||
--self:I( "New Alive Units: " .. self.AliveUnits )
|
||||
end
|
||||
self:T2( "New Alive Units: " .. self.AliveUnits )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3980,9 +4026,9 @@ function SPAWN:_OnTakeOff( EventData )
|
||||
if SpawnGroup then
|
||||
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
|
||||
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
||||
self:T2( { "TakeOff event: " .. EventPrefix } )
|
||||
--self:T2( { "TakeOff event: " .. EventPrefix } )
|
||||
if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
|
||||
self:T2( "self.Landed = false" )
|
||||
--self:T2( "self.Landed = false" )
|
||||
SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", false )
|
||||
end
|
||||
end
|
||||
@@ -4000,13 +4046,13 @@ function SPAWN:_OnLand( EventData )
|
||||
if SpawnGroup then
|
||||
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
|
||||
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
||||
self:T2( { "Land event: " .. EventPrefix } )
|
||||
--self:T2( { "Land event: " .. EventPrefix } )
|
||||
if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
|
||||
-- TODO: Check if this is the last unit of the group that lands.
|
||||
SpawnGroup:SetState( SpawnGroup, "Spawn_Landed", true )
|
||||
if self.RepeatOnLanding then
|
||||
local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup )
|
||||
self:T2( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } )
|
||||
--self:T2( { "Landed:", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } )
|
||||
-- self:ReSpawn( SpawnGroupIndex )
|
||||
-- Delay respawn by three seconds due to DCS 2.5.4.26368 OB bug https://github.com/FlightControl-Master/MOOSE/issues/1076
|
||||
-- Bug was initially only for engine shutdown event but after ED "fixed" it, it now happens on landing events.
|
||||
@@ -4029,13 +4075,13 @@ function SPAWN:_OnEngineShutDown( EventData )
|
||||
if SpawnGroup then
|
||||
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
|
||||
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
||||
self:T2( { "EngineShutdown event: " .. EventPrefix } )
|
||||
--self:T2( { "EngineShutdown event: " .. EventPrefix } )
|
||||
if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
|
||||
-- todo: test if on the runway
|
||||
local Landed = SpawnGroup:GetState( SpawnGroup, "Spawn_Landed" )
|
||||
if Landed and self.RepeatOnEngineShutDown then
|
||||
local SpawnGroupIndex = self:GetSpawnIndexFromGroup( SpawnGroup )
|
||||
self:T2( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } )
|
||||
--self:T2( { "EngineShutDown: ", "ReSpawn:", SpawnGroup:GetName(), SpawnGroupIndex } )
|
||||
-- self:ReSpawn( SpawnGroupIndex )
|
||||
-- Delay respawn by three seconds due to DCS 2.5.4 OB bug https://github.com/FlightControl-Master/MOOSE/issues/1076
|
||||
SCHEDULER:New( nil, self.ReSpawn, { self, SpawnGroupIndex }, 3 )
|
||||
@@ -4064,7 +4110,7 @@ function SPAWN:_SpawnCleanUpScheduler()
|
||||
--self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } )
|
||||
|
||||
local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup()
|
||||
self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
|
||||
--self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
|
||||
|
||||
local IsHelo = false
|
||||
|
||||
@@ -4081,7 +4127,7 @@ function SPAWN:_SpawnCleanUpScheduler()
|
||||
|
||||
self.SpawnCleanUpTimeStamps[SpawnUnitName] = self.SpawnCleanUpTimeStamps[SpawnUnitName] or {}
|
||||
local Stamp = self.SpawnCleanUpTimeStamps[SpawnUnitName]
|
||||
self:T2( { SpawnUnitName, Stamp } )
|
||||
--self:T2( { SpawnUnitName, Stamp } )
|
||||
|
||||
if Stamp.Vec2 then
|
||||
if (SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1) or IsHelo then
|
||||
@@ -4089,7 +4135,7 @@ function SPAWN:_SpawnCleanUpScheduler()
|
||||
if (Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y) or (SpawnUnit:GetLife() <= 1) then
|
||||
-- If the plane is not moving or dead , and is on the ground, assign it with a timestamp...
|
||||
if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then
|
||||
self:T2( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } )
|
||||
--self:T2( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } )
|
||||
--self:ReSpawn( SpawnCursor )
|
||||
SCHEDULER:New( nil, self.ReSpawn, { self, SpawnCursor }, 3 )
|
||||
Stamp.Vec2 = nil
|
||||
@@ -4118,7 +4164,7 @@ function SPAWN:_SpawnCleanUpScheduler()
|
||||
|
||||
SpawnGroup, SpawnCursor = self:GetNextAliveGroup( SpawnCursor )
|
||||
|
||||
self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
|
||||
--self:T2( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -535,12 +535,6 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
-- Name of the spawned static.
|
||||
Template.name = self.InitStaticName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex)
|
||||
|
||||
-- Add and register the new static.
|
||||
local mystatic=_DATABASE:AddStatic(Template.name)
|
||||
|
||||
-- Debug output.
|
||||
self:T(Template)
|
||||
|
||||
-- Add static to the game.
|
||||
local Static=nil --DCS#StaticObject
|
||||
|
||||
@@ -577,12 +571,28 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
self:T("Spawning Static")
|
||||
self:T2({Template=Template})
|
||||
Static=coalition.addStaticObject(CountryID, Template)
|
||||
|
||||
if Static then
|
||||
self:T(string.format("Succesfully spawned static object \"%s\" ID=%d", Static:getName(), Static:getID()))
|
||||
--[[
|
||||
local static=StaticObject.getByName(Static:getName())
|
||||
if static then
|
||||
env.info(string.format("FF got static from StaticObject.getByName"))
|
||||
else
|
||||
env.error(string.format("FF error did NOT get static from StaticObject.getByName"))
|
||||
end ]]
|
||||
else
|
||||
self:E(string.format("ERROR: DCS static object \"%s\" is nil!", tostring(Template.name)))
|
||||
end
|
||||
end
|
||||
|
||||
-- Add and register the new static.
|
||||
local mystatic=_DATABASE:AddStatic(Template.name)
|
||||
|
||||
-- If there is a SpawnFunction hook defined, call it.
|
||||
if self.SpawnFunctionHook then
|
||||
-- delay calling this for .3 seconds so that it hopefully comes after the BIRTH event of the group.
|
||||
self:ScheduleOnce(0.3,self.SpawnFunctionHook,mystatic, unpack(self.SpawnFunctionArguments))
|
||||
self:ScheduleOnce(0.3, self.SpawnFunctionHook, mystatic, unpack(self.SpawnFunctionArguments))
|
||||
end
|
||||
|
||||
return mystatic
|
||||
|
||||
@@ -14,6 +14,7 @@ do -- world
|
||||
-- @field #world.event event [https://wiki.hoggitworld.com/view/DCS_enum_world](https://wiki.hoggitworld.com/view/DCS_enum_world)
|
||||
-- @field #world.BirthPlace BirthPlace The birthplace enumerator is used to define where an aircraft or helicopter has spawned in association with birth events.
|
||||
-- @field #world.VolumeType VolumeType The volumeType enumerator defines the types of 3d geometery used within the [world.searchObjects](https://wiki.hoggitworld.com/view/DCS_func_searchObjects) function.
|
||||
-- @field #world.weather weather Weather functions for fog etc.
|
||||
|
||||
--- The world singleton contains functions centered around two different but extremely useful functions.
|
||||
-- * Events and event handlers are all governed within world.
|
||||
@@ -132,6 +133,36 @@ do -- world
|
||||
-- @function [parent=#world] getAirbases
|
||||
-- @param #number coalitionId The coalition side number ID. Default is all airbases are returned.
|
||||
-- @return #table Table of DCS airbase objects.
|
||||
|
||||
|
||||
--- Weather functions.
|
||||
-- @type world.weather
|
||||
|
||||
--- Fog animation data structure.
|
||||
-- @type world.FogAnimation
|
||||
-- @field #number time
|
||||
-- @field #number visibility
|
||||
-- @field #number thickness
|
||||
|
||||
--- Returns the current fog thickness.
|
||||
-- @function [parent=#world.weather] getFogThickness Returns the fog thickness.
|
||||
-- @return #number Fog thickness in meters. If there is no fog, zero is returned.
|
||||
|
||||
--- Sets the fog thickness instantly. Any current fog animation is discarded.
|
||||
-- @function [parent=#world.weather] setFogThickness
|
||||
-- @param #number thickness Fog thickness in meters. Set to zero to disable fog.
|
||||
|
||||
--- Returns the current fog visibility distance.
|
||||
-- @function [parent=#world.weather] getFogVisibilityDistance Returns the current maximum visibility distance in meters. Returns zero if fog is not present.
|
||||
|
||||
--- Instantly sets the maximum visibility distance of fog at sea level when looking at the horizon. Any current fog animation is discarded. Set zero to disable the fog.
|
||||
-- @function [parent=#world.weather] setFogVisibilityDistance
|
||||
-- @param #number visibility Max fog visibility in meters. Set to zero to disable fog.
|
||||
|
||||
--- Sets fog animation keys. Time is set in seconds and relative to the current simulation time, where time=0 is the current moment.
|
||||
-- Time must be increasing. Previous animation is always discarded despite the data being correct.
|
||||
-- @function [parent=#world.weather] setFogAnimation
|
||||
-- @param #world.FogAnimation animation List of fog animations
|
||||
|
||||
end -- world
|
||||
|
||||
@@ -407,7 +438,7 @@ do -- coalition
|
||||
-- @param #table groupData Group data table.
|
||||
-- @return DCS#Group The spawned Group object.
|
||||
|
||||
--- Dynamically spawns a static object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addGroup)
|
||||
--- Dynamically spawns a static object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_addStaticObject)
|
||||
-- @function [parent=#coalition] addStaticObject
|
||||
-- @param #number countryId Id of the country.
|
||||
-- @param #table groupData Group data table.
|
||||
@@ -420,6 +451,7 @@ end -- coalition
|
||||
|
||||
do -- Types
|
||||
|
||||
--- Descriptors.
|
||||
-- @type Desc
|
||||
-- @field #number speedMax0 Max speed in meters/second at zero altitude.
|
||||
-- @field #number massEmpty Empty mass in kg.
|
||||
@@ -1013,14 +1045,16 @@ do -- Spot
|
||||
end -- Spot
|
||||
|
||||
do -- Controller
|
||||
|
||||
--- Controller is an object that performs A.I.-tasks. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C.
|
||||
--
|
||||
-- This class has 2 types of functions:
|
||||
--
|
||||
-- * Tasks
|
||||
-- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics.
|
||||
-- * Commands: Commands are instant actions those required zero time to perform. Commands may be used both for control unit/group behavior and control game mechanics.
|
||||
--
|
||||
-- @type Controller
|
||||
-- @field #Controller.Detection Detection Enum contains identifiers of surface types.
|
||||
-- @field #Controller.Detection Detection Enum contains identifiers of surface types.
|
||||
|
||||
--- Enables and disables the controller.
|
||||
-- Note: Now it works only for ground / naval groups!
|
||||
@@ -1079,18 +1113,18 @@ do -- Controller
|
||||
|
||||
-- Detection
|
||||
|
||||
--- Enum contains identifiers of surface types.
|
||||
--- Enum containing detection types.
|
||||
-- @type Controller.Detection
|
||||
-- @field VISUAL
|
||||
-- @field OPTIC
|
||||
-- @field RADAR
|
||||
-- @field IRST
|
||||
-- @field RWR
|
||||
-- @field DLINK
|
||||
-- @field #number VISUAL Visual detection. Numeric value 1.
|
||||
-- @field #number OPTIC Optical detection. Numeric value 2.
|
||||
-- @field #number RADAR Radar detection. Numeric value 4.
|
||||
-- @field #number IRST Infra-red search and track detection. Numeric value 8.
|
||||
-- @field #number RWR Radar Warning Receiver detection. Numeric value 16.
|
||||
-- @field #number DLINK Data link detection. Numeric value 32.
|
||||
|
||||
--- Detected target.
|
||||
-- @type DetectedTarget
|
||||
-- @field Wrapper.Object#Object object The target
|
||||
-- @type Controller.DetectedTarget
|
||||
-- @field DCS#Object object The target
|
||||
-- @field #boolean visible The target is visible
|
||||
-- @field #boolean type The target type is known
|
||||
-- @field #boolean distance Distance to the target is known
|
||||
@@ -1103,9 +1137,9 @@ do -- Controller
|
||||
-- @param #Controller.Detection detection Controller.Detection detection1, Controller.Detection detection2, ... Controller.Detection detectionN
|
||||
-- @return #boolean detected True if the target is detected.
|
||||
-- @return #boolean visible Has effect only if detected is true. True if the target is visible now.
|
||||
-- @return #boolean type Has effect only if detected is true. True if the target type is known.
|
||||
-- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known.
|
||||
-- @return #ModelTime lastTime Has effect only if visible is false. Last time when target was seen.
|
||||
-- @return #boolean type Has effect only if detected is true. True if the target type is known.
|
||||
-- @return #boolean distance Has effect only if detected is true. True if the distance to the target is known.
|
||||
-- @return #Vec3 lastPos Has effect only if visible is false. Last position of the target when it was seen.
|
||||
-- @return #Vec3 lastVel Has effect only if visible is false. Last velocity of the target when it was seen.
|
||||
|
||||
@@ -1131,6 +1165,7 @@ end -- Controller
|
||||
|
||||
do -- Unit
|
||||
|
||||
--- Unit.
|
||||
-- @type Unit
|
||||
-- @extends #CoalitionObject
|
||||
-- @field ID Identifier of an unit. It assigned to an unit by the Mission Editor automatically.
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
-- ### Author: FlightControl - Framework Design & Programming
|
||||
-- ### Refactoring to use the Runway auto-detection: Applevangelist
|
||||
-- @date August 2022
|
||||
-- Last Update Nov 2023
|
||||
-- Last Update Oct 2024
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -721,14 +721,18 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
|
||||
if NotInRunwayZone then
|
||||
|
||||
local Taxi = Client:GetState( self, "Taxi" )
|
||||
|
||||
if IsOnGround then
|
||||
local Taxi = Client:GetState( self, "Taxi" )
|
||||
|
||||
self:T( Taxi )
|
||||
if Taxi == false then
|
||||
local Velocity = VELOCITY:New( AirbaseMeta.KickSpeed or self.KickSpeed )
|
||||
Client:Message( "Welcome to " .. AirbaseID .. ". The maximum taxiing speed is " ..
|
||||
Velocity:ToString() , 20, "ATC" )
|
||||
Client:SetState( self, "Taxi", true )
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0 )
|
||||
end
|
||||
|
||||
-- TODO: GetVelocityKMH function usage
|
||||
@@ -737,7 +741,7 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
local IsAboveRunway = Client:IsAboveRunway()
|
||||
self:T( {IsAboveRunway, IsOnGround, Velocity:Get() })
|
||||
|
||||
if IsOnGround then
|
||||
if IsOnGround and not Taxi then
|
||||
local Speeding = false
|
||||
if AirbaseMeta.MaximumKickSpeed then
|
||||
if Velocity:Get() > AirbaseMeta.MaximumKickSpeed then
|
||||
@@ -749,15 +753,17 @@ function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
|
||||
end
|
||||
end
|
||||
if Speeding == true then
|
||||
MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
|
||||
" has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
Client:Destroy()
|
||||
Client:SetState( self, "Speeding", false )
|
||||
Client:SetState( self, "Warnings", 0 )
|
||||
--MESSAGE:New( "Penalty! Player " .. Client:GetPlayerName() ..
|
||||
-- " has been kicked, due to a severe airbase traffic rule violation ...", 10, "ATC" ):ToAll()
|
||||
--Client:Destroy()
|
||||
Client:SetState( self, "Speeding", true )
|
||||
local SpeedingWarnings = Client:GetState( self, "Warnings" )
|
||||
Client:SetState( self, "Warnings", SpeedingWarnings + 1 )
|
||||
Client:Message( "Warning " .. SpeedingWarnings .. "/3! Airbase traffic rule violation! Slow down now! Your speed is " ..
|
||||
Velocity:ToString(), 5, "ATC" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
if IsOnGround then
|
||||
|
||||
local Speeding = false
|
||||
@@ -1035,23 +1041,23 @@ end
|
||||
-- The following airbases are monitored at the Nevada region.
|
||||
-- Use the @{Wrapper.Airbase#AIRBASE.Nevada} enumeration to select the airbases to be monitored.
|
||||
--
|
||||
-- * `AIRBASE.Nevada.Beatty_Airport`
|
||||
-- * `AIRBASE.Nevada.Boulder_City_Airport`
|
||||
-- * `AIRBASE.Nevada.Creech_AFB`
|
||||
-- * `AIRBASE.Nevada.Beatty`
|
||||
-- * `AIRBASE.Nevada.Boulder_City`
|
||||
-- * `AIRBASE.Nevada.Creech`
|
||||
-- * `AIRBASE.Nevada.Echo_Bay`
|
||||
-- * `AIRBASE.Nevada.Groom_Lake_AFB`
|
||||
-- * `AIRBASE.Nevada.Henderson_Executive_Airport`
|
||||
-- * `AIRBASE.Nevada.Jean_Airport`
|
||||
-- * `AIRBASE.Nevada.Laughlin_Airport`
|
||||
-- * `AIRBASE.Nevada.Groom_Lake`
|
||||
-- * `AIRBASE.Nevada.Henderson_Executive`
|
||||
-- * `AIRBASE.Nevada.Jean`
|
||||
-- * `AIRBASE.Nevada.Laughlin`
|
||||
-- * `AIRBASE.Nevada.Lincoln_County`
|
||||
-- * `AIRBASE.Nevada.McCarran_International_Airport`
|
||||
-- * `AIRBASE.Nevada.McCarran_International`
|
||||
-- * `AIRBASE.Nevada.Mesquite`
|
||||
-- * `AIRBASE.Nevada.Mina_Airport`
|
||||
-- * `AIRBASE.Nevada.Nellis_AFB`
|
||||
-- * `AIRBASE.Nevada.Mina`
|
||||
-- * `AIRBASE.Nevada.Nellis`
|
||||
-- * `AIRBASE.Nevada.North_Las_Vegas`
|
||||
-- * `AIRBASE.Nevada.Pahute_Mesa_Airstrip`
|
||||
-- * `AIRBASE.Nevada.Tonopah_Airport`
|
||||
-- * `AIRBASE.Nevada.Tonopah_Test_Range_Airfield`
|
||||
-- * `AIRBASE.Nevada.Pahute_Mesa`
|
||||
-- * `AIRBASE.Nevada.Tonopah`
|
||||
-- * `AIRBASE.Nevada.Tonopah_Test_Range`
|
||||
--
|
||||
-- # Installation
|
||||
--
|
||||
@@ -1088,10 +1094,10 @@ end
|
||||
--
|
||||
-- -- Monitor specific airbases.
|
||||
-- ATC_Ground = ATC_GROUND_NEVADA:New(
|
||||
-- { AIRBASE.Nevada.Laughlin_Airport,
|
||||
-- { AIRBASE.Nevada.Laughlin,
|
||||
-- AIRBASE.Nevada.Lincoln_County,
|
||||
-- AIRBASE.Nevada.North_Las_Vegas,
|
||||
-- AIRBASE.Nevada.McCarran_International_Airport
|
||||
-- AIRBASE.Nevada.McCarran_International
|
||||
-- }
|
||||
-- )
|
||||
--
|
||||
@@ -1330,33 +1336,33 @@ end
|
||||
-- The following airbases are monitored at the PersianGulf region.
|
||||
-- Use the @{Wrapper.Airbase#AIRBASE.PersianGulf} enumeration to select the airbases to be monitored.
|
||||
--
|
||||
-- * `AIRBASE.PersianGulf.Abu_Musa_Island_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Al_Dhafra_AB`
|
||||
-- * `AIRBASE.PersianGulf.Abu_Musa_Island`
|
||||
-- * `AIRBASE.PersianGulf.Al_Dhafra_AFB`
|
||||
-- * `AIRBASE.PersianGulf.Al_Maktoum_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Al_Minhad_AB`
|
||||
-- * `AIRBASE.PersianGulf.Al_Minhad_AFB`
|
||||
-- * `AIRBASE.PersianGulf.Bandar_Abbas_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Bandar_Lengeh`
|
||||
-- * `AIRBASE.PersianGulf.Dubai_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Fujairah_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Havadarya`
|
||||
-- * `AIRBASE.PersianGulf.Kerman_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Kerman`
|
||||
-- * `AIRBASE.PersianGulf.Khasab`
|
||||
-- * `AIRBASE.PersianGulf.Lar_Airbase`
|
||||
-- * `AIRBASE.PersianGulf.Lar`
|
||||
-- * `AIRBASE.PersianGulf.Qeshm_Island`
|
||||
-- * `AIRBASE.PersianGulf.Sharjah_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Shiraz_International_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Shiraz_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Sir_Abu_Nuayr`
|
||||
-- * `AIRBASE.PersianGulf.Sirri_Island`
|
||||
-- * `AIRBASE.PersianGulf.Tunb_Island_AFB`
|
||||
-- * `AIRBASE.PersianGulf.Tunb_Kochak`
|
||||
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Bandar_e_Jask_airfield`
|
||||
-- * `AIRBASE.PersianGulf.Abu_Dhabi_International_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Al_Bateen_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Kish_International_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Al_Ain_International_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Lavan_Island_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Jiroft_Airport`
|
||||
-- * `AIRBASE.PersianGulf.Sas_Al_Nakheel`
|
||||
-- * `AIRBASE.PersianGulf.Bandar_e_Jask`
|
||||
-- * `AIRBASE.PersianGulf.Abu_Dhabi_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Al_Bateen`
|
||||
-- * `AIRBASE.PersianGulf.Kish_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Al_Ain_Intl`
|
||||
-- * `AIRBASE.PersianGulf.Lavan_Island`
|
||||
-- * `AIRBASE.PersianGulf.Jiroft`
|
||||
--
|
||||
-- # Installation
|
||||
--
|
||||
@@ -1391,8 +1397,8 @@ end
|
||||
-- AirbasePoliceCaucasus = ATC_GROUND_PERSIANGULF:New()
|
||||
--
|
||||
-- ATC_Ground = ATC_GROUND_PERSIANGULF:New(
|
||||
-- { AIRBASE.PersianGulf.Kerman_Airport,
|
||||
-- AIRBASE.PersianGulf.Al_Minhad_AB
|
||||
-- { AIRBASE.PersianGulf.Kerman,
|
||||
-- AIRBASE.PersianGulf.Al_Minhad_AFB
|
||||
-- }
|
||||
-- )
|
||||
--
|
||||
|
||||
@@ -652,7 +652,7 @@ do -- DETECTION_BASE
|
||||
|
||||
if DetectedObject:isExist() then
|
||||
|
||||
local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity = DetectionUnit:IsTargetDetected(
|
||||
local TargetIsDetected, TargetIsVisible, TargetKnowType, TargetKnowDistance, TargetLastTime, TargetLastPos, TargetLastVelocity = DetectionUnit:IsTargetDetected(
|
||||
DetectedObject,
|
||||
self.DetectVisual,
|
||||
self.DetectOptical,
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
-- @module Functional.Mantis
|
||||
-- @image Functional.Mantis.jpg
|
||||
--
|
||||
-- Last Update: July 2024
|
||||
-- Last Update: Sep 2024
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **MANTIS** class, extends Core.Base#BASE
|
||||
@@ -439,27 +439,50 @@ MANTIS.SamDataSMA = {
|
||||
-- @field #string Type #MANTIS.SamType of SAM, i.e. SHORT, MEDIUM or LONG (range)
|
||||
-- @field #string Radar Radar typename on unit level (used as key)
|
||||
MANTIS.SamDataCH = {
|
||||
-- units from CH (Military Assets by Currenthill)
|
||||
-- https://www.currenthill.com/
|
||||
-- group name MUST contain CHM to ID launcher type correctly!
|
||||
["2S38 CH"] = { Range=8, Blindspot=0.5, Height=6, Type="Short", Radar="2S38" },
|
||||
["PantsirS1 CH"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
|
||||
["PantsirS2 CH"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
|
||||
["PGL-625 CH"] = { Range=10, Blindspot=0.5, Height=5, Type="Short", Radar="PGL_625" },
|
||||
["HQ-17A CH"] = { Range=20, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
|
||||
["M903PAC2 CH"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
|
||||
["M903PAC3 CH"] = { Range=120, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
|
||||
["TorM2 CH"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
|
||||
["TorM2K CH"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
|
||||
["TorM2M CH"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
|
||||
["NASAMS3-AMRAAMER CH"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
|
||||
["NASAMS3-AIM9X2 CH"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
|
||||
["C-RAM CH"] = { Range=2, Blindspot=0, Height=2, Type="Short", Radar="CH_Centurion_C_RAM" },
|
||||
["PGZ-09 CH"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="CH_PGZ09" },
|
||||
["S350-9M100 CH"] = { Range=15, Blindspot=1.5, Height=8, Type="Short", Radar="CH_S350_50P6_9M100" },
|
||||
["S350-9M96D CH"] = { Range=150, Blindspot=2.5, Height=30, Type="Long", Radar="CH_S350_50P6_9M96D" },
|
||||
["LAV-AD CH"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_LAVAD" },
|
||||
["HQ-22 CH"] = { Range=170, Blindspot=5, Height=27, Type="Long", Radar="CH_HQ22_LN" },
|
||||
-- units from CH (Military Assets by Currenthill)
|
||||
-- https://www.currenthill.com/
|
||||
-- group name MUST contain CHM to ID launcher type correctly!
|
||||
["2S38 CHM"] = { Range=8, Blindspot=0.5, Height=6, Type="Short", Radar="2S38" },
|
||||
["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
|
||||
["PantsirS2 CHM"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
|
||||
["PGL-625 CHM"] = { Range=10, Blindspot=0.5, Height=5, Type="Short", Radar="PGL_625" },
|
||||
["HQ-17A CHM"] = { Range=20, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
|
||||
["M903PAC2 CHM"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
|
||||
["M903PAC3 CHM"] = { Range=120, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
|
||||
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
|
||||
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
|
||||
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
|
||||
["NASAMS3-AMRAAMER CHM"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
|
||||
["NASAMS3-AIM9X2 CHM"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
|
||||
["C-RAM CHM"] = { Range=2, Blindspot=0, Height=2, Type="Short", Radar="CH_Centurion_C_RAM" },
|
||||
["PGZ-09 CHM"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="CH_PGZ09" },
|
||||
["S350-9M100 CHM"] = { Range=15, Blindspot=1.5, Height=8, Type="Short", Radar="CH_S350_50P6_9M100" },
|
||||
["S350-9M96D CHM"] = { Range=150, Blindspot=2.5, Height=30, Type="Long", Radar="CH_S350_50P6_9M96D" },
|
||||
["LAV-AD CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_LAVAD" },
|
||||
["HQ-22 CHM"] = { Range=170, Blindspot=5, Height=27, Type="Long", Radar="CH_HQ22_LN" },
|
||||
["PGZ-95 CHM"] = { Range=2, Blindspot=0, Height=2, Type="Short", Radar="CH_PGZ95" },
|
||||
["LD-3000 CHM"] = { Range=3, Blindspot=0, Height=3, Type="Short", Radar="CH_LD3000_stationary" },
|
||||
["LD-3000M CHM"] = { Range=3, Blindspot=0, Height=3, Type="Short", Radar="CH_LD3000" },
|
||||
["FlaRakRad CHM"] = { Range=8, Blindspot=1.5, Height=6, Type="Short", Radar="HQ17A" },
|
||||
["IRIS-T SLM CHM"] = { Range=40, Blindspot=0.5, Height=20, Type="Medium", Radar="CH_IRIST_SLM" },
|
||||
["M903PAC2KAT1 CHM"] = { Range=160, Blindspot=3, Height=24.5, Type="Long", Radar="CH_MIM104_M903_PAC2_KAT1" },
|
||||
["Skynex CHM"] = { Range=3.5, Blindspot=0, Height=3.5, Type="Short", Radar="CH_SkynexHX" },
|
||||
["Skyshield CHM"] = { Range=3.5, Blindspot=0, Height=3.5, Type="Short", Radar="CH_Skyshield_Gun" },
|
||||
["WieselOzelot CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_Wiesel2Ozelot" },
|
||||
["BukM3-9M317M CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317M" },
|
||||
["BukM3-9M317MA CHM"] = { Range=70, Blindspot=0.25, Height=35, Type="Medium", Radar="CH_BukM3_9A317MA" },
|
||||
["SkySabre CHM"] = { Range=30, Blindspot=0.5, Height=10, Type="Medium", Radar="CH_SkySabreLN" },
|
||||
["Stormer CHM"] = { Range=7.5, Blindspot=0.3, Height=7, Type="Short", Radar="CH_StormerHVM" },
|
||||
["THAAD CHM"] = { Range=200, Blindspot=40, Height=150, Type="Long", Radar="CH_THAAD_M1120" },
|
||||
["USInfantryFIM92K CHM"] = { Range=8, Blindspot=0.2, Height=4.8, Type="Short", Radar="CH_USInfantry_FIM92" },
|
||||
["RBS98M CHM"] = { Range=20, Blindspot=0, Height=8, Type="Short", Radar="RBS-98" },
|
||||
["RBS70 CHM"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-70" },
|
||||
["RBS90 CHM"] = { Range=8, Blindspot=0, Height=5.5, Type="Short", Radar="RBS-90" },
|
||||
["RBS103A CHM"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_Rb103A" },
|
||||
["RBS103B CHM"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_Rb103B" },
|
||||
["RBS103AM CHM"] = { Range=150, Blindspot=3, Height=24.5, Type="Long", Radar="LvS-103_Lavett103_HX_Rb103A" },
|
||||
["RBS103BM CHM"] = { Range=35, Blindspot=0, Height=36, Type="Medium", Radar="LvS-103_Lavett103_HX_Rb103B" },
|
||||
["Lvkv9040M CHM"] = { Range=4, Blindspot=0, Height=2.5, Type="Short", Radar="LvKv9040" },
|
||||
}
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
@@ -640,7 +663,7 @@ do
|
||||
|
||||
-- TODO Version
|
||||
-- @field #string version
|
||||
self.version="0.8.18"
|
||||
self.version="0.8.20"
|
||||
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||
|
||||
--- FSM Functions ---
|
||||
@@ -1396,7 +1419,7 @@ do
|
||||
-- @return #string type Long, medium or short range
|
||||
-- @return #number blind "blind" spot
|
||||
function MANTIS:_GetSAMDataFromUnits(grpname,mod,sma,chm)
|
||||
self:T(self.lid.."_GetSAMRangeFromUnits")
|
||||
self:T(self.lid.."_GetSAMDataFromUnits")
|
||||
local found = false
|
||||
local range = self.checkradius
|
||||
local height = 3000
|
||||
@@ -1449,7 +1472,7 @@ do
|
||||
-- @return #string type Long, medium or short range
|
||||
-- @return #number blind "blind" spot
|
||||
function MANTIS:_GetSAMRange(grpname)
|
||||
self:T(self.lid.."_GetSAMRange")
|
||||
self:T(self.lid.."_GetSAMRange for "..tostring(grpname))
|
||||
local range = self.checkradius
|
||||
local height = 3000
|
||||
local type = MANTIS.SamType.MEDIUM
|
||||
@@ -1466,9 +1489,9 @@ do
|
||||
elseif string.find(grpname,"CHM",1,true) then
|
||||
CHMod = true
|
||||
end
|
||||
if self.automode then
|
||||
--if self.automode then
|
||||
for idx,entry in pairs(self.SamData) do
|
||||
--self:I("ID = " .. idx)
|
||||
self:T("ID = " .. idx)
|
||||
if string.find(grpname,idx,1,true) then
|
||||
local _entry = entry -- #MANTIS.SamData
|
||||
type = _entry.Type
|
||||
@@ -1476,18 +1499,21 @@ do
|
||||
range = _entry.Range * 1000 * radiusscale -- max firing range
|
||||
height = _entry.Height * 1000 -- max firing height
|
||||
blind = _entry.Blindspot
|
||||
--self:I("Matching Groupname = " .. grpname .. " Range= " .. range)
|
||||
self:T("Matching Groupname = " .. grpname .. " Range= " .. range)
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
--end
|
||||
-- secondary filter if not found
|
||||
if (not found and self.automode) or HDSmod or SMAMod or CHMod then
|
||||
if (not found) or HDSmod or SMAMod or CHMod then
|
||||
range, height, type = self:_GetSAMDataFromUnits(grpname,HDSmod,SMAMod,CHMod)
|
||||
elseif not found then
|
||||
self:E(self.lid .. string.format("*****Could not match radar data for %s! Will default to midrange values!",grpname))
|
||||
end
|
||||
if string.find(grpname,"SHORAD",1,true) then
|
||||
type = MANTIS.SamType.SHORT -- force short on match
|
||||
end
|
||||
return range, height, type, blind
|
||||
end
|
||||
|
||||
@@ -1651,6 +1677,10 @@ do
|
||||
function MANTIS:_CheckLoop(samset,detset,dlink,limit)
|
||||
self:T(self.lid .. "CheckLoop " .. #detset .. " Coordinates")
|
||||
local switchedon = 0
|
||||
local statusreport = REPORT:New("\nMANTIS Status")
|
||||
local instatusred = 0
|
||||
local instatusgreen = 0
|
||||
local SEADactive = 0
|
||||
for _,_data in pairs (samset) do
|
||||
local samcoordinate = _data[2]
|
||||
local name = _data[1]
|
||||
@@ -1673,7 +1703,7 @@ do
|
||||
elseif (not self.UseEmOnOff) and switchedon < limit then
|
||||
samgroup:OptionAlarmStateRed()
|
||||
switchedon = switchedon + 1
|
||||
switch = true
|
||||
switch = true
|
||||
end
|
||||
if self.SamStateTracker[name] ~= "RED" and switch then
|
||||
self:__RedState(1,samgroup)
|
||||
@@ -1691,7 +1721,7 @@ do
|
||||
-- debug output
|
||||
if (self.debug or self.verbose) and switch then
|
||||
local text = string.format("SAM %s in alarm state RED!", name)
|
||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||
--local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug
|
||||
if self.verbose then self:I(self.lid..text) end
|
||||
end
|
||||
end --end alive
|
||||
@@ -1709,12 +1739,26 @@ do
|
||||
end
|
||||
if self.debug or self.verbose then
|
||||
local text = string.format("SAM %s in alarm state GREEN!", name)
|
||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||
--local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||
if self.verbose then self:I(self.lid..text) end
|
||||
end
|
||||
end --end alive
|
||||
end --end check
|
||||
end --for for loop
|
||||
end --end check
|
||||
end --for loop
|
||||
if self.debug then
|
||||
for _,_status in pairs(self.SamStateTracker) do
|
||||
if _status == "GREEN" then
|
||||
instatusgreen=instatusgreen+1
|
||||
elseif _status == "RED" then
|
||||
instatusred=instatusred+1
|
||||
end
|
||||
end
|
||||
statusreport:Add("+-----------------------------+")
|
||||
statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred))
|
||||
statusreport:Add(string.format("+ SAM in GREEN State: %2d",instatusgreen))
|
||||
statusreport:Add("+-----------------------------+")
|
||||
MESSAGE:New(statusreport:Text(),10,nil,true):ToAll():ToLog()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1828,7 +1872,7 @@ do
|
||||
end
|
||||
--]]
|
||||
if self.autoshorad then
|
||||
self.Shorad = SHORAD:New(self.name.."-SHORAD",self.name.."-SHORAD",self.SAM_Group,self.ShoradActDistance,self.ShoradTime,self.coalition,self.UseEmOnOff)
|
||||
self.Shorad = SHORAD:New(self.name.."-SHORAD","SHORAD",self.SAM_Group,self.ShoradActDistance,self.ShoradTime,self.coalition,self.UseEmOnOff)
|
||||
self.Shorad:SetDefenseLimits(80,95)
|
||||
self.ShoradLink = true
|
||||
self.Shorad.Groupset=self.ShoradGroupSet
|
||||
|
||||
@@ -2987,7 +2987,7 @@ function RANGE:_DisplayBombTargets( _unitname )
|
||||
end
|
||||
end
|
||||
|
||||
self:_DisplayMessageToGroup( _unit, _text, 120, true, true, _multiplayer )
|
||||
self:_DisplayMessageToGroup( _unit, _text, 150, true, true, _multiplayer )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3453,10 +3453,10 @@ function RANGE:_AddF10Commands( _unitName )
|
||||
-- Range menu
|
||||
local _rangePath = MENU_GROUP:New( group, self.rangename, _rootMenu )
|
||||
|
||||
local _statsPath = MENU_GROUP:New( group, "Statistics", _rangePath )
|
||||
local _markPath = MENU_GROUP:New( group, "Mark Targets", _rangePath )
|
||||
local _settingsPath = MENU_GROUP:New( group, "My Settings", _rangePath )
|
||||
local _infoPath = MENU_GROUP:New( group, "Range Info", _rangePath )
|
||||
local _markPath = MENU_GROUP:New( group, "Mark Targets", _rangePath )
|
||||
local _statsPath = MENU_GROUP:New( group, "Statistics", _rangePath )
|
||||
local _settingsPath = MENU_GROUP:New( group, "My Settings", _rangePath )
|
||||
|
||||
-- F10/On the Range/<Range Name>/My Settings/
|
||||
local _mysmokePath = MENU_GROUP:New( group, "Smoke Color", _settingsPath )
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
--
|
||||
-- ### Authors: **applevangelist**, **FlightControl**
|
||||
--
|
||||
-- Last Update: Dec 2023
|
||||
-- Last Update: Oct 2024
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -28,6 +28,16 @@
|
||||
|
||||
---
|
||||
-- @type SEAD
|
||||
-- @field #string ClassName The Class Name.
|
||||
-- @field #table TargetSkill Table of target skills.
|
||||
-- @field #table SEADGroupPrefixes Table of SEAD prefixes.
|
||||
-- @field #table SuppressedGroups Table of currently suppressed groups.
|
||||
-- @field #number EngagementRange Engagement Range.
|
||||
-- @field #number Padding Padding in seconds.
|
||||
-- @field #function CallBack Callback function for suppression plans.
|
||||
-- @field #boolean UseCallBack Switch for callback function to be used.
|
||||
-- @field #boolean debug Debug switch.
|
||||
-- @field #boolen WeaponTrack Track switch, if true track weapon speed for 30 secs.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- Make SAM sites execute evasive and defensive behaviour when being fired upon.
|
||||
@@ -56,10 +66,11 @@ SEAD = {
|
||||
SEADGroupPrefixes = {},
|
||||
SuppressedGroups = {},
|
||||
EngagementRange = 75, -- default 75% engagement range Feature Request #1355
|
||||
Padding = 10,
|
||||
Padding = 15,
|
||||
CallBack = nil,
|
||||
UseCallBack = false,
|
||||
debug = false,
|
||||
WeaponTrack = false,
|
||||
}
|
||||
|
||||
--- Missile enumerators
|
||||
@@ -144,7 +155,7 @@ function SEAD:New( SEADGroupPrefixes, Padding )
|
||||
self:AddTransition("*", "ManageEvasion", "*")
|
||||
self:AddTransition("*", "CalculateHitZone", "*")
|
||||
|
||||
self:I("*** SEAD - Started Version 0.4.6")
|
||||
self:I("*** SEAD - Started Version 0.4.8")
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -371,7 +382,7 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
|
||||
reach = wpndata[1] * 1.1
|
||||
local mach = wpndata[2]
|
||||
wpnspeed = math.floor(mach * 340.29)
|
||||
if Weapon then
|
||||
if Weapon and Weapon:GetSpeed() > 0 then
|
||||
wpnspeed = Weapon:GetSpeed()
|
||||
self:T(string.format("*** SEAD - Weapon Speed from WEAPON: %f m/s",wpnspeed))
|
||||
end
|
||||
@@ -452,22 +463,30 @@ end
|
||||
-- @return #SEAD self
|
||||
function SEAD:HandleEventShot( EventData )
|
||||
self:T( { EventData.id } )
|
||||
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
|
||||
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
|
||||
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
|
||||
local SEADUnit = EventData.IniDCSUnit
|
||||
local SEADUnitName = EventData.IniDCSUnitName
|
||||
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
||||
local SEADWeaponName = EventData.WeaponName -- return weapon type
|
||||
|
||||
local WeaponWrapper = WEAPON:New(EventData.Weapon)
|
||||
--local SEADWeaponSpeed = WeaponWrapper:GetSpeed() -- mps
|
||||
|
||||
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
||||
--self:T({ SEADWeapon })
|
||||
|
||||
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
||||
local SEADWeaponName = EventData.WeaponName or "None" -- return weapon type
|
||||
|
||||
if self:_CheckHarms(SEADWeaponName) then
|
||||
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
|
||||
|
||||
if not SEADPlane then return self end -- case IniUnit is empty
|
||||
|
||||
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
|
||||
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
|
||||
local SEADUnit = EventData.IniDCSUnit
|
||||
local SEADUnitName = EventData.IniDCSUnitName
|
||||
|
||||
local WeaponWrapper = WEAPON:New(EventData.Weapon) -- Wrapper.Weapon#WEAPON
|
||||
|
||||
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
||||
|
||||
self:T( '*** SEAD - Weapon Match' )
|
||||
if self.WeaponTrack == true then
|
||||
WeaponWrapper:SetFuncTrack(function(weapon) env.info(string.format("*** Weapon Speed: %d m/s",weapon:GetSpeed() or -1)) end)
|
||||
WeaponWrapper:StartTrack(0.1)
|
||||
WeaponWrapper:StopTrack(30)
|
||||
end
|
||||
local _targetskill = "Random"
|
||||
local _targetgroupname = "none"
|
||||
local _target = EventData.Weapon:getTarget() -- Identify target
|
||||
@@ -520,7 +539,7 @@ function SEAD:HandleEventShot( EventData )
|
||||
end
|
||||
if SEADGroupFound == true then -- yes we are being attacked
|
||||
if string.find(SEADWeaponName,"ADM_141",1,true) then
|
||||
self:__ManageEvasion(2,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
|
||||
self:__ManageEvasion(2,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,2,WeaponWrapper)
|
||||
else
|
||||
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,0,WeaponWrapper)
|
||||
end
|
||||
|
||||
@@ -8433,12 +8433,14 @@ function WAREHOUSE:_GetAttribute(group)
|
||||
local attribute=WAREHOUSE.Attribute.OTHER_UNKNOWN --#WAREHOUSE.Attribute
|
||||
|
||||
if group then
|
||||
|
||||
local groupCat=group:GetCategory()
|
||||
|
||||
-----------
|
||||
--- Air ---
|
||||
-----------
|
||||
-- Planes
|
||||
local transportplane=group:HasAttribute("Transports") and group:HasAttribute("Planes")
|
||||
local transportplane=group:HasAttribute("Transports") and group:HasAttribute("Planes") and groupCat==Group.Category.AIRPLANE
|
||||
local awacs=group:HasAttribute("AWACS")
|
||||
local fighter=group:HasAttribute("Fighters") or group:HasAttribute("Interceptors") or group:HasAttribute("Multirole fighters") or (group:HasAttribute("Bombers") and not group:HasAttribute("Strategic bombers"))
|
||||
local bomber=group:HasAttribute("Strategic bombers")
|
||||
@@ -8593,7 +8595,6 @@ end
|
||||
-- @param #WAREHOUSE.Queueitem qitem Item of queue to be removed.
|
||||
-- @param #table queue The queue from which the item should be deleted.
|
||||
function WAREHOUSE:_DeleteQueueItem(qitem, queue)
|
||||
self:F({qitem=qitem, queue=queue})
|
||||
|
||||
for i=1,#queue do
|
||||
local _item=queue[i] --#WAREHOUSE.Queueitem
|
||||
|
||||
@@ -291,7 +291,7 @@
|
||||
-- ## Nevada: Nellis AFB
|
||||
--
|
||||
-- -- ATIS Nellis AFB on 270.10 MHz AM.
|
||||
-- atisNellis=ATIS:New(AIRBASE.Nevada.Nellis_AFB, 270.1)
|
||||
-- atisNellis=ATIS:New(AIRBASE.Nevada.Nellis, 270.1)
|
||||
-- atisNellis:SetRadioRelayUnitName("Radio Relay Nellis")
|
||||
-- atisNellis:SetActiveRunway("21L")
|
||||
-- atisNellis:SetTowerFrequencies({327.000, 132.550})
|
||||
@@ -302,7 +302,7 @@
|
||||
-- ## Persian Gulf: Abu Dhabi International Airport
|
||||
--
|
||||
-- -- ATIS Abu Dhabi International on 125.1 MHz AM.
|
||||
-- atisAbuDhabi=ATIS:New(AIRBASE.PersianGulf.Abu_Dhabi_International_Airport, 125.1)
|
||||
-- atisAbuDhabi=ATIS:New(AIRBASE.PersianGulf.Abu_Dhabi_Intl, 125.1)
|
||||
-- atisAbuDhabi:SetRadioRelayUnitName("Radio Relay Abu Dhabi International Airport")
|
||||
-- atisAbuDhabi:SetMetricUnits()
|
||||
-- atisAbuDhabi:SetActiveRunway("L")
|
||||
@@ -498,6 +498,9 @@ ATIS.Alphabet = {
|
||||
-- @field #number Syria +5° (East).
|
||||
-- @field #number MarianaIslands +2° (East).
|
||||
-- @field #number SinaiMap +5° (East).
|
||||
-- @field #number Kola +15° (East).
|
||||
-- @field #number Afghanistan +3° (East).
|
||||
-- @field #number Iraq +4.4° (East).
|
||||
ATIS.RunwayM2T = {
|
||||
Caucasus = 0,
|
||||
Nevada = 12,
|
||||
@@ -508,6 +511,9 @@ ATIS.RunwayM2T = {
|
||||
MarianaIslands = 2,
|
||||
Falklands = 12,
|
||||
SinaiMap = 5,
|
||||
Kola = 15,
|
||||
Afghanistan = 3,
|
||||
Iraq=4.4
|
||||
}
|
||||
|
||||
--- Whether ICAO phraseology is used for ATIS broadcasts.
|
||||
@@ -521,6 +527,9 @@ ATIS.RunwayM2T = {
|
||||
-- @field #boolean MarianaIslands true.
|
||||
-- @field #boolean Falklands true.
|
||||
-- @field #boolean SinaiMap true.
|
||||
-- @field #boolean Kola true.
|
||||
-- @field #boolean Afghanistan true.
|
||||
-- @field #boolean Iraq true.
|
||||
ATIS.ICAOPhraseology = {
|
||||
Caucasus = true,
|
||||
Nevada = false,
|
||||
@@ -531,6 +540,9 @@ ATIS.ICAOPhraseology = {
|
||||
MarianaIslands = true,
|
||||
Falklands = true,
|
||||
SinaiMap = true,
|
||||
Kola = true,
|
||||
Afghanistan = true,
|
||||
Iraq = true,
|
||||
}
|
||||
|
||||
--- Nav point data.
|
||||
@@ -619,83 +631,83 @@ ATIS.ICAOPhraseology = {
|
||||
-- @field #ATIS.Soundfile TACANChannel
|
||||
-- @field #ATIS.Soundfile VORFrequency
|
||||
ATIS.Sound = {
|
||||
ActiveRunway = { filename = "ActiveRunway.ogg", duration = 0.99 },
|
||||
ActiveRunwayDeparture = { filename = "ActiveRunwayDeparture.ogg", duration = 0.99 },
|
||||
ActiveRunwayArrival = { filename = "ActiveRunwayArrival.ogg", duration = 0.99 },
|
||||
AdviceOnInitial = { filename = "AdviceOnInitial.ogg", duration = 3.00 },
|
||||
Airport = { filename = "Airport.ogg", duration = 0.66 },
|
||||
Altimeter = { filename = "Altimeter.ogg", duration = 0.68 },
|
||||
At = { filename = "At.ogg", duration = 0.41 },
|
||||
CloudBase = { filename = "CloudBase.ogg", duration = 0.82 },
|
||||
CloudCeiling = { filename = "CloudCeiling.ogg", duration = 0.61 },
|
||||
CloudsBroken = { filename = "CloudsBroken.ogg", duration = 1.07 },
|
||||
CloudsFew = { filename = "CloudsFew.ogg", duration = 0.99 },
|
||||
CloudsNo = { filename = "CloudsNo.ogg", duration = 1.01 },
|
||||
CloudsNotAvailable = { filename = "CloudsNotAvailable.ogg", duration = 2.35 },
|
||||
CloudsOvercast = { filename = "CloudsOvercast.ogg", duration = 0.83 },
|
||||
CloudsScattered = { filename = "CloudsScattered.ogg", duration = 1.18 },
|
||||
Decimal = { filename = "Decimal.ogg", duration = 0.54 },
|
||||
DegreesCelsius = { filename = "DegreesCelsius.ogg", duration = 1.27 },
|
||||
DegreesFahrenheit = { filename = "DegreesFahrenheit.ogg", duration = 1.23 },
|
||||
DewPoint = { filename = "DewPoint.ogg", duration = 0.65 },
|
||||
Dust = { filename = "Dust.ogg", duration = 0.54 },
|
||||
Elevation = { filename = "Elevation.ogg", duration = 0.78 },
|
||||
EndOfInformation = { filename = "EndOfInformation.ogg", duration = 1.15 },
|
||||
Feet = { filename = "Feet.ogg", duration = 0.45 },
|
||||
Fog = { filename = "Fog.ogg", duration = 0.47 },
|
||||
Gusting = { filename = "Gusting.ogg", duration = 0.55 },
|
||||
HectoPascal = { filename = "HectoPascal.ogg", duration = 1.15 },
|
||||
Hundred = { filename = "Hundred.ogg", duration = 0.47 },
|
||||
InchesOfMercury = { filename = "InchesOfMercury.ogg", duration = 1.16 },
|
||||
Information = { filename = "Information.ogg", duration = 0.85 },
|
||||
Kilometers = { filename = "Kilometers.ogg", duration = 0.78 },
|
||||
Knots = { filename = "Knots.ogg", duration = 0.59 },
|
||||
Left = { filename = "Left.ogg", duration = 0.54 },
|
||||
MegaHertz = { filename = "MegaHertz.ogg", duration = 0.87 },
|
||||
Meters = { filename = "Meters.ogg", duration = 0.59 },
|
||||
MetersPerSecond = { filename = "MetersPerSecond.ogg", duration = 1.14 },
|
||||
Miles = { filename = "Miles.ogg", duration = 0.60 },
|
||||
MillimetersOfMercury = { filename = "MillimetersOfMercury.ogg", duration = 1.53 },
|
||||
Minus = { filename = "Minus.ogg", duration = 0.64 },
|
||||
N0 = { filename = "N-0.ogg", duration = 0.55 },
|
||||
N1 = { filename = "N-1.ogg", duration = 0.41 },
|
||||
N2 = { filename = "N-2.ogg", duration = 0.37 },
|
||||
N3 = { filename = "N-3.ogg", duration = 0.41 },
|
||||
N4 = { filename = "N-4.ogg", duration = 0.37 },
|
||||
N5 = { filename = "N-5.ogg", duration = 0.43 },
|
||||
N6 = { filename = "N-6.ogg", duration = 0.55 },
|
||||
N7 = { filename = "N-7.ogg", duration = 0.43 },
|
||||
N8 = { filename = "N-8.ogg", duration = 0.38 },
|
||||
N9 = { filename = "N-9.ogg", duration = 0.55 },
|
||||
NauticalMiles = { filename = "NauticalMiles.ogg", duration = 1.04 },
|
||||
None = { filename = "None.ogg", duration = 0.43 },
|
||||
QFE = { filename = "QFE.ogg", duration = 0.63 },
|
||||
QNH = { filename = "QNH.ogg", duration = 0.71 },
|
||||
Rain = { filename = "Rain.ogg", duration = 0.41 },
|
||||
Right = { filename = "Right.ogg", duration = 0.44 },
|
||||
Snow = { filename = "Snow.ogg", duration = 0.48 },
|
||||
SnowStorm = { filename = "SnowStorm.ogg", duration = 0.82 },
|
||||
StatuteMiles = { filename = "StatuteMiles.ogg", duration = 1.15 },
|
||||
SunriseAt = { filename = "SunriseAt.ogg", duration = 0.92 },
|
||||
SunsetAt = { filename = "SunsetAt.ogg", duration = 0.95 },
|
||||
Temperature = { filename = "Temperature.ogg", duration = 0.64 },
|
||||
Thousand = { filename = "Thousand.ogg", duration = 0.55 },
|
||||
ThunderStorm = { filename = "ThunderStorm.ogg", duration = 0.81 },
|
||||
TimeLocal = { filename = "TimeLocal.ogg", duration = 0.90 },
|
||||
TimeZulu = { filename = "TimeZulu.ogg", duration = 0.86 },
|
||||
TowerFrequency = { filename = "TowerFrequency.ogg", duration = 1.19 },
|
||||
Visibilty = { filename = "Visibility.ogg", duration = 0.79 },
|
||||
WeatherPhenomena = { filename = "WeatherPhenomena.ogg", duration = 1.07 },
|
||||
WindFrom = { filename = "WindFrom.ogg", duration = 0.60 },
|
||||
ActiveRunway = { filename = "ActiveRunway.ogg", duration = 0.85 },
|
||||
ActiveRunwayDeparture = { filename = "ActiveRunwayDeparture.ogg", duration = 1.50 },
|
||||
ActiveRunwayArrival = { filename = "ActiveRunwayArrival.ogg", duration = 1.38 },
|
||||
AdviceOnInitial = { filename = "AdviceOnInitial.ogg", duration = 2.98 },
|
||||
Airport = { filename = "Airport.ogg", duration = 0.55 },
|
||||
Altimeter = { filename = "Altimeter.ogg", duration = 0.91 },
|
||||
At = { filename = "At.ogg", duration = 0.32 },
|
||||
CloudBase = { filename = "CloudBase.ogg", duration = 0.69 },
|
||||
CloudCeiling = { filename = "CloudCeiling.ogg", duration = 0.53 },
|
||||
CloudsBroken = { filename = "CloudsBroken.ogg", duration = 0.81 },
|
||||
CloudsFew = { filename = "CloudsFew.ogg", duration = 0.74 },
|
||||
CloudsNo = { filename = "CloudsNo.ogg", duration = 0.69},
|
||||
CloudsNotAvailable = { filename = "CloudsNotAvailable.ogg", duration = 2.64 },
|
||||
CloudsOvercast = { filename = "CloudsOvercast.ogg", duration = 0.82 },
|
||||
CloudsScattered = { filename = "CloudsScattered.ogg", duration = 0.89 },
|
||||
Decimal = { filename = "Decimal.ogg", duration = 0.71 },
|
||||
DegreesCelsius = { filename = "DegreesCelsius.ogg", duration = 1.08 },
|
||||
DegreesFahrenheit = { filename = "DegreesFahrenheit.ogg", duration = 1.07 },
|
||||
DewPoint = { filename = "DewPoint.ogg", duration = 0.59 },
|
||||
Dust = { filename = "Dust.ogg", duration = 0.37 },
|
||||
Elevation = { filename = "Elevation.ogg", duration = 0.92 },
|
||||
EndOfInformation = { filename = "EndOfInformation.ogg", duration = 1.24 },
|
||||
Feet = { filename = "Feet.ogg", duration = 0.34 },
|
||||
Fog = { filename = "Fog.ogg", duration = 0.41 },
|
||||
Gusting = { filename = "Gusting.ogg", duration = 0.58 },
|
||||
HectoPascal = { filename = "HectoPascal.ogg", duration = 0.92 },
|
||||
Hundred = { filename = "Hundred.ogg", duration = 0.53 },
|
||||
ILSFrequency = { filename = "ILSFrequency.ogg", duration = 1.30 },
|
||||
InnerNDBFrequency = { filename = "InnerNDBFrequency.ogg", duration = 1.56 },
|
||||
OuterNDBFrequency = { filename = "OuterNDBFrequency.ogg", duration = 1.59 },
|
||||
RunwayLength = { filename = "RunwayLength.ogg", duration = 0.91 },
|
||||
VORFrequency = { filename = "VORFrequency.ogg", duration = 1.38 },
|
||||
TACANChannel = { filename = "TACANChannel.ogg", duration = 0.88 },
|
||||
PRMGChannel = { filename = "PRMGChannel.ogg", duration = 1.18 },
|
||||
RSBNChannel = { filename = "RSBNChannel.ogg", duration = 1.14 },
|
||||
Zulu = { filename = "Zulu.ogg", duration = 0.62 },
|
||||
InchesOfMercury = { filename = "InchesOfMercury.ogg", duration = 1.26 },
|
||||
Information = { filename = "Information.ogg", duration = 0.99 },
|
||||
InnerNDBFrequency = { filename = "InnerNDBFrequency.ogg", duration = 1.69 },
|
||||
Kilometers = { filename = "Kilometers.ogg", duration = 0.93 },
|
||||
Knots = { filename = "Knots.ogg", duration = 0.46 },
|
||||
Left = { filename = "Left.ogg", duration = 0.41 },
|
||||
MegaHertz = { filename = "MegaHertz.ogg", duration = 0.83 },
|
||||
Meters = { filename = "Meters.ogg", duration = 0.55 },
|
||||
MetersPerSecond = { filename = "MetersPerSecond.ogg", duration = 1.03 },
|
||||
Miles = { filename = "Miles.ogg", duration = 0.44 },
|
||||
MillimetersOfMercury = { filename = "MillimetersOfMercury.ogg", duration = 1.59 },
|
||||
Minus = { filename = "Minus.ogg", duration = 0.55 },
|
||||
N0 = { filename = "N-0.ogg", duration = 0.52 },
|
||||
N1 = { filename = "N-1.ogg", duration = 0.35 },
|
||||
N2 = { filename = "N-2.ogg", duration = 0.41 },
|
||||
N3 = { filename = "N-3.ogg", duration = 0.34 },
|
||||
N4 = { filename = "N-4.ogg", duration = 0.37 },
|
||||
N5 = { filename = "N-5.ogg", duration = 0.40 },
|
||||
N6 = { filename = "N-6.ogg", duration = 0.46 },
|
||||
N7 = { filename = "N-7.ogg", duration = 0.52 },
|
||||
N8 = { filename = "N-8.ogg", duration = 0.36 },
|
||||
N9 = { filename = "N-9.ogg", duration = 0.51 },
|
||||
NauticalMiles = { filename = "NauticalMiles.ogg", duration = 0.93 },
|
||||
None = { filename = "None.ogg", duration = 0.33 },
|
||||
OuterNDBFrequency = { filename = "OuterNDBFrequency.ogg", duration = 1.70 },
|
||||
PRMGChannel = { filename = "PRMGChannel.ogg", duration = 1.27 },
|
||||
QFE = { filename = "QFE.ogg", duration = 0.90 },
|
||||
QNH = { filename = "QNH.ogg", duration = 0.94 },
|
||||
Rain = { filename = "Rain.ogg", duration = 0.35 },
|
||||
Right = { filename = "Right.ogg", duration = 0.31 },
|
||||
RSBNChannel = { filename = "RSBNChannel.ogg", duration = 1.26 },
|
||||
RunwayLength = { filename = "RunwayLength.ogg", duration = 0.81 },
|
||||
Snow = { filename = "Snow.ogg", duration = 0.40 },
|
||||
SnowStorm = { filename = "SnowStorm.ogg", duration = 0.73 },
|
||||
StatuteMiles = { filename = "StatuteMiles.ogg", duration = 0.90 },
|
||||
SunriseAt = { filename = "SunriseAt.ogg", duration = 0.82 },
|
||||
SunsetAt = { filename = "SunsetAt.ogg", duration = 0.87 },
|
||||
TACANChannel = { filename = "TACANChannel.ogg", duration = 0.81 },
|
||||
Temperature = { filename = "Temperature.ogg", duration = 0.70 },
|
||||
Thousand = { filename = "Thousand.ogg", duration = 0.58 },
|
||||
ThunderStorm = { filename = "ThunderStorm.ogg", duration = 0.79 },
|
||||
TimeLocal = { filename = "TimeLocal.ogg", duration = 0.83 },
|
||||
TimeZulu = { filename = "TimeZulu.ogg", duration = 0.83 },
|
||||
TowerFrequency = { filename = "TowerFrequency.ogg", duration = 1.05 },
|
||||
Visibilty = { filename = "Visibility.ogg", duration = 1.16 },
|
||||
VORFrequency = { filename = "VORFrequency.ogg", duration = 1.28 },
|
||||
WeatherPhenomena = { filename = "WeatherPhenomena.ogg", duration = 1.09 },
|
||||
WindFrom = { filename = "WindFrom.ogg", duration = 0.63 },
|
||||
Zulu = { filename = "Zulu.ogg", duration = 0.51 },
|
||||
}
|
||||
|
||||
---
|
||||
@@ -954,7 +966,7 @@ _ATIS = {}
|
||||
|
||||
--- ATIS class version.
|
||||
-- @field #string version
|
||||
ATIS.version = "1.0.0"
|
||||
ATIS.version = "1.0.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -2080,34 +2092,32 @@ function ATIS:onafterBroadcast( From, Event, To )
|
||||
---------------
|
||||
|
||||
-- Get mission weather info. Most of this is static.
|
||||
local clouds, visibility, turbulence, fog, dust, static = self:GetMissionWeather()
|
||||
|
||||
-- Check that fog is actually "thick" enough to reach the airport. If an airport is in the mountains, fog might not affect it as it is measured from sea level.
|
||||
if fog and fog.thickness < height + 25 then
|
||||
fog = nil
|
||||
end
|
||||
|
||||
-- Dust only up to 1500 ft = 457 m ASL.
|
||||
if dust and height + 25 > UTILS.FeetToMeters( 1500 ) then
|
||||
dust = nil
|
||||
end
|
||||
local clouds, visibility, turbulence, dustdens, static = self:GetMissionWeather()
|
||||
|
||||
local dust=false
|
||||
local fog=false
|
||||
|
||||
------------------
|
||||
--- Visibility ---
|
||||
------------------
|
||||
|
||||
-- Get min visibility.
|
||||
local visibilitymin = visibility
|
||||
|
||||
if fog then
|
||||
if fog.visibility < visibilitymin then
|
||||
visibilitymin = fog.visibility
|
||||
if dustdens then
|
||||
|
||||
-- Dust only up to 1500 ft = 457 m ASL.
|
||||
if UTILS.FeetToMeters( 1500 )> height+25 then
|
||||
dust=true
|
||||
visibility=math.min(visibility, dustdens)
|
||||
end
|
||||
end
|
||||
|
||||
if dust then
|
||||
if dust < visibilitymin then
|
||||
visibilitymin = dust
|
||||
|
||||
else -- As of DCS 2.9.10.3948 (December 2024), fog and dust are mutually exclusive!
|
||||
|
||||
-- Get current fog visibility and thickness
|
||||
local fvis=world.weather.getFogVisibilityDistance()
|
||||
local fheight=world.weather.getFogThickness()
|
||||
|
||||
if fvis>0 and fheight>height+25 then
|
||||
fog=true
|
||||
visibility=math.min(visibility, fvis)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2115,7 +2125,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
||||
|
||||
if self.metric then
|
||||
-- Visibility in km.
|
||||
local reportedviz = UTILS.Round( visibilitymin / 1000 )
|
||||
local reportedviz = UTILS.Round( visibility / 1000 )
|
||||
-- max reported visibility 9999 m
|
||||
if reportedviz > 10 then
|
||||
reportedviz = 10
|
||||
@@ -2123,7 +2133,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
||||
VISIBILITY = string.format( "%d", reportedviz )
|
||||
else
|
||||
-- max reported visibility 10 NM
|
||||
local reportedviz = UTILS.Round( UTILS.MetersToSM( visibilitymin ) )
|
||||
local reportedviz = UTILS.Round( UTILS.MetersToSM( visibility ) )
|
||||
if reportedviz > 10 then
|
||||
reportedviz = 10
|
||||
end
|
||||
@@ -3350,28 +3360,13 @@ function ATIS:GetMissionWeather()
|
||||
dust = weather.dust_density
|
||||
end
|
||||
|
||||
-- Fog
|
||||
--[[
|
||||
["enable_fog"] = false,
|
||||
["fog"] =
|
||||
{
|
||||
["thickness"] = 0,
|
||||
["visibility"] = 25,
|
||||
}, -- end of ["fog"]
|
||||
]]
|
||||
local fog = nil
|
||||
if weather.enable_fog == true then
|
||||
fog = weather.fog
|
||||
end
|
||||
|
||||
self:T( "FF weather:" )
|
||||
self:T( { clouds = clouds } )
|
||||
self:T( { visibility = visibility } )
|
||||
self:T( { turbulence = turbulence } )
|
||||
self:T( { fog = fog } )
|
||||
self:T( { dust = dust } )
|
||||
self:T( { static = static } )
|
||||
return clouds, visibility, turbulence, fog, dust, static
|
||||
return clouds, visibility, turbulence, dust, static
|
||||
end
|
||||
|
||||
--- Get thousands of a number.
|
||||
|
||||
@@ -3614,7 +3614,7 @@ function AIRBOSS:onafterStart( From, Event, To )
|
||||
|
||||
-- Handle events.
|
||||
self:HandleEvent( EVENTS.Birth )
|
||||
self:HandleEvent( EVENTS.Land )
|
||||
self:HandleEvent( EVENTS.RunwayTouch )
|
||||
self:HandleEvent( EVENTS.EngineShutdown )
|
||||
self:HandleEvent( EVENTS.Takeoff )
|
||||
self:HandleEvent( EVENTS.Crash )
|
||||
@@ -4379,7 +4379,7 @@ function AIRBOSS:onafterStop( From, Event, To )
|
||||
|
||||
-- Unhandle events.
|
||||
self:UnHandleEvent( EVENTS.Birth )
|
||||
self:UnHandleEvent( EVENTS.Land )
|
||||
self:UnHandleEvent( EVENTS.RunwayTouch )
|
||||
self:UnHandleEvent( EVENTS.EngineShutdown )
|
||||
self:UnHandleEvent( EVENTS.Takeoff )
|
||||
self:UnHandleEvent( EVENTS.Crash )
|
||||
@@ -8289,7 +8289,7 @@ end
|
||||
--- Airboss event handler for event land.
|
||||
-- @param #AIRBOSS self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AIRBOSS:OnEventLand( EventData )
|
||||
function AIRBOSS:OnEventRunwayTouch( EventData )
|
||||
self:F3( { eventland = EventData } )
|
||||
|
||||
-- Nil checks.
|
||||
|
||||
@@ -308,7 +308,7 @@ CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
||||
CSAR.AircraftType["Bronco-OV-10A"] = 2
|
||||
CSAR.AircraftType["MH-60R"] = 10
|
||||
CSAR.AircraftType["OH-6A"] = 2
|
||||
CSAR.AircraftType["OH-58D"] = 2
|
||||
CSAR.AircraftType["OH58D"] = 2
|
||||
CSAR.AircraftType["CH-47Fbl1"] = 31
|
||||
|
||||
--- CSAR class version.
|
||||
@@ -841,9 +841,9 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla
|
||||
local BeaconName
|
||||
|
||||
if _playerName then
|
||||
BeaconName = _unitName..math.random(1,10000)
|
||||
elseif _unitName then
|
||||
BeaconName = _playerName..math.random(1,10000)
|
||||
elseif _unitName then
|
||||
BeaconName = _unitName..math.random(1,10000)
|
||||
else
|
||||
BeaconName = "Ghost-1-1"..math.random(1,10000)
|
||||
end
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
-- @module Ops.CTLD
|
||||
-- @image OPS_CTLD.jpg
|
||||
|
||||
-- Last Update Sep 2024
|
||||
-- Last Update Dec 2024
|
||||
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -836,6 +836,9 @@ do
|
||||
-- my_ctld.enableChinookGCLoading = true -- this will effectively suppress the crate load and drop for CTLD_CARGO.Enum.STATIc types for CTLD for the Chinook
|
||||
-- my_ctld.TroopUnloadDistGround = 5 -- If hovering, spawn dropped troops this far away in meters from the helo
|
||||
-- my_ctld.TroopUnloadDistHover = 1.5 -- If grounded, spawn dropped troops this far away in meters from the helo
|
||||
-- my_ctld.TroopUnloadDistGroundHerc = 25 -- On the ground, unload troops this far behind the Hercules
|
||||
-- my_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook
|
||||
-- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook
|
||||
--
|
||||
-- ## 2.1 CH-47 Chinook support
|
||||
--
|
||||
@@ -895,7 +898,7 @@ do
|
||||
-- ["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
|
||||
-- ["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
|
||||
-- ["OH-6A"] = {type="OH-6A", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 7, cargoweightlimit = 550},
|
||||
-- ["OH-58D"] = {type="OH58D", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 14, cargoweightlimit = 400},
|
||||
-- ["OH58D"] = {type="OH58D", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 14, cargoweightlimit = 400},
|
||||
-- ["CH-47Fbl1"] = {type="CH-47Fbl1", crates=true, troops=true, cratelimit = 4, trooplimit = 31, length = 20, cargoweightlimit = 8000},
|
||||
--
|
||||
-- ### 2.2.2 Activate and deactivate zones
|
||||
@@ -1233,6 +1236,9 @@ CTLD = {
|
||||
DynamicCargo = {},
|
||||
ChinookTroopCircleRadius = 5,
|
||||
TroopUnloadDistGround = 5,
|
||||
TroopUnloadDistGroundHerc = 25,
|
||||
TroopUnloadDistGroundHook = 15,
|
||||
TroopUnloadDistHoverHook = 5,
|
||||
TroopUnloadDistHover = 1.5,
|
||||
UserSetGroup = nil,
|
||||
}
|
||||
@@ -1272,6 +1278,12 @@ CTLD.RadioModulation = {
|
||||
FM = 1,
|
||||
}
|
||||
|
||||
--- Loaded Cargo
|
||||
-- @type CTLD.LoadedCargo
|
||||
-- @field #number Troopsloaded
|
||||
-- @field #number Cratesloaded
|
||||
-- @field #table Cargo Table of #CTLD_CARGO objects
|
||||
|
||||
--- Zone Info.
|
||||
-- @type CTLD.CargoZone
|
||||
-- @field #string name Name of Zone.
|
||||
@@ -1333,13 +1345,13 @@ CTLD.UnitTypeCapabilities = {
|
||||
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
|
||||
["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
|
||||
["OH-6A"] = {type="OH-6A", crates=false, troops=true, cratelimit = 0, trooplimit = 4, length = 7, cargoweightlimit = 550},
|
||||
["OH-58D"] = {type="OH58D", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 14, cargoweightlimit = 400},
|
||||
["OH58D"] = {type="OH58D", crates=false, troops=false, cratelimit = 0, trooplimit = 0, length = 14, cargoweightlimit = 400},
|
||||
["CH-47Fbl1"] = {type="CH-47Fbl1", crates=true, troops=true, cratelimit = 4, trooplimit = 31, length = 20, cargoweightlimit = 10800},
|
||||
}
|
||||
|
||||
--- CTLD class version.
|
||||
-- @field #string version
|
||||
CTLD.version="1.1.16"
|
||||
CTLD.version="1.1.20"
|
||||
|
||||
--- Instantiate a new CTLD.
|
||||
-- @param #CTLD self
|
||||
@@ -2425,6 +2437,7 @@ end
|
||||
local nearestGroup = nil
|
||||
local nearestGroupIndex = -1
|
||||
local nearestDistance = 10000000
|
||||
local maxdistance = 0
|
||||
local nearestList = {}
|
||||
local distancekeys = {}
|
||||
local extractdistance = self.CrateDistance * self.ExtractFactor
|
||||
@@ -2436,8 +2449,14 @@ end
|
||||
nearestGroup = v
|
||||
nearestGroupIndex = k
|
||||
nearestDistance = distance
|
||||
if math.floor(distance) > maxdistance then maxdistance = math.floor(distance) end
|
||||
if nearestList[math.floor(distance)] then
|
||||
distance = maxdistance+1
|
||||
maxdistance = distance
|
||||
end
|
||||
table.insert(nearestList, math.floor(distance), v)
|
||||
distancekeys[#distancekeys+1] = math.floor(distance)
|
||||
--self:I(string.format("Adding group %s distance %dm",nearestGroup:GetName(),distance))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2490,7 +2509,7 @@ end
|
||||
nearestGroup.ExtractTime = timer.getTime()
|
||||
local loadcargotype = CTLD_CARGO:New(self.CargoCounter, Cargotype.Name, Cargotype.Templates, Cargotype.CargoType, true, true, Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass)
|
||||
self:T({cargotype=loadcargotype})
|
||||
local running = math.floor(nearestDistance / 4)+10 -- time run to helo plus boarding
|
||||
local running = math.floor(nearestDistance / 4)+20 -- time run to helo plus boarding
|
||||
loaded.Troopsloaded = loaded.Troopsloaded + troopsize
|
||||
table.insert(loaded.Cargo,loadcargotype)
|
||||
self.Loaded_Cargo[unitname] = loaded
|
||||
@@ -2505,26 +2524,32 @@ end
|
||||
local Angle = math.floor((heading+160)%360)
|
||||
Point = coord:Translate(8,Angle):GetVec2()
|
||||
if Point then
|
||||
nearestGroup:RouteToVec2(Point,4)
|
||||
nearestGroup:RouteToVec2(Point,5)
|
||||
end
|
||||
end
|
||||
-- clean up:
|
||||
if type(Cargotype.Templates) == "table" and Cargotype.Templates[2] then
|
||||
local hassecondaries = false
|
||||
if type(Cargotype.Templates) == "table" and Cargotype.Templates[2] then
|
||||
for _,_key in pairs (Cargotype.Templates) do
|
||||
table.insert(secondarygroups,_key)
|
||||
hassecondaries = true
|
||||
end
|
||||
end
|
||||
nearestGroup:Destroy(false,running)
|
||||
local destroytimer = math.random(10,20)
|
||||
--self:I("Destroying Group "..nearestGroup:GetName().." in "..destroytimer.." seconds!")
|
||||
nearestGroup:Destroy(false,destroytimer)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- clean up secondary groups
|
||||
for _,_name in pairs(secondarygroups) do
|
||||
for _,_group in pairs(nearestList) do
|
||||
if _group and _group:IsAlive() then
|
||||
local groupname = string.match(_group:GetName(), "(.+)-(.+)$")
|
||||
if _name == groupname then
|
||||
_group:Destroy(false,15)
|
||||
if hassecondaries == true then
|
||||
for _,_name in pairs(secondarygroups) do
|
||||
for _,_group in pairs(nearestList) do
|
||||
if _group and _group:IsAlive() then
|
||||
local groupname = string.match(_group:GetName(), "(.+)-(.+)$")
|
||||
if _name == groupname then
|
||||
_group:Destroy(false,15)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3408,8 +3433,8 @@ function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
|
||||
local template = _DATABASE:GetGroupTemplate(Template)
|
||||
--UTILS.PrintTableToLog(template)
|
||||
local numbertroops = #template.units
|
||||
local slightshift = math.abs(math.random(0,200)/100)
|
||||
local newcenter = Coordinate:Translate(Radius+slightshift,((Heading+270)%360))
|
||||
local slightshift = math.abs(math.random(1,500)/100)
|
||||
local newcenter = Coordinate:Translate(Radius+slightshift,((Heading+270+math.random(1,10))%360))
|
||||
for i=1,360,math.floor(360/numbertroops) do
|
||||
local phead = ((Heading+270+i)%360)
|
||||
local post = newcenter:Translate(Radius,phead)
|
||||
@@ -3484,7 +3509,15 @@ function CTLD:_UnloadTroops(Group, Unit)
|
||||
randomcoord = Group:GetCoordinate()
|
||||
-- slightly left from us
|
||||
local Angle = (heading+270)%360
|
||||
if IsHerc or IsHook then Angle = (heading+180)%360 end
|
||||
local offset = hoverunload and self.TroopUnloadDistHover or self.TroopUnloadDistGround
|
||||
if IsHerc then offset = self.TroopUnloadDistGroundHerc or 25 end
|
||||
if IsHook then
|
||||
offset = self.TroopUnloadDistGroundHook or 15
|
||||
if self.TroopUnloadDistHoverHook then
|
||||
offset = self.TroopUnloadDistHoverHook or 5
|
||||
end
|
||||
end
|
||||
randomcoord:Translate(offset,Angle,nil,true)
|
||||
end
|
||||
local tempcount = 0
|
||||
@@ -3494,7 +3527,7 @@ function CTLD:_UnloadTroops(Group, Unit)
|
||||
self.TroopCounter = self.TroopCounter + 1
|
||||
tempcount = tempcount+1
|
||||
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
||||
local rad = 2.5+tempcount
|
||||
local rad = 2.5+(tempcount*2)
|
||||
local Positions = self:_GetUnitPositions(randomcoord,rad,heading,_template)
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||
--:InitRandomizeUnits(true,20,2)
|
||||
@@ -4269,7 +4302,7 @@ end
|
||||
-- @param #string SubCategory Name of sub-category (optional).
|
||||
-- @param #boolean DontShowInMenu (optional) If set to "true" this won't show up in the menu.
|
||||
-- @param Core.Zone#ZONE Location (optional) If set, the cargo item is **only** available here. Can be a #ZONE object or the name of a zone as #string.
|
||||
-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH-58D"}.
|
||||
-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH58D"}.
|
||||
-- @param #string Category Static category name (optional). If set, spawn cargo crate with an alternate category type, e.g. "Cargos".
|
||||
-- @param #string TypeName Static type name (optional). If set, spawn cargo crate with an alternate type shape, e.g. "iso_container".
|
||||
-- @param #string ShapeName Static shape name (optional). If set, spawn cargo crate with an alternate type sub-shape, e.g. "iso_container_cargo".
|
||||
@@ -4353,7 +4386,7 @@ end
|
||||
-- @param #string SubCategory Name of the sub-category (optional).
|
||||
-- @param #boolean DontShowInMenu (optional) If set to "true" this won't show up in the menu.
|
||||
-- @param Core.Zone#ZONE Location (optional) If set, the cargo item is **only** available here. Can be a #ZONE object or the name of a zone as #string.
|
||||
-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH-58D"}
|
||||
-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH58D"}
|
||||
-- @param #string Category Static category name (optional). If set, spawn cargo crate with an alternate category type, e.g. "Cargos".
|
||||
-- @param #string TypeName Static type name (optional). If set, spawn cargo crate with an alternate type shape, e.g. "iso_container".
|
||||
-- @param #string ShapeName Static shape name (optional). If set, spawn cargo crate with an alternate type sub-shape, e.g. "iso_container_cargo".
|
||||
@@ -5356,6 +5389,27 @@ end
|
||||
return Stock
|
||||
end
|
||||
|
||||
--- User - Query the cargo loaded from a specific unit
|
||||
-- @param #CTLD self
|
||||
-- @param Wrapper.Unit#UNIT Unit The (client) unit to query.
|
||||
-- @return #number Troopsloaded
|
||||
-- @return #number Cratesloaded
|
||||
-- @return #table Cargo Table of #CTLD_CARGO objects
|
||||
function CTLD:GetLoadedCargo(Unit)
|
||||
local Troops = 0
|
||||
local Crates = 0
|
||||
local Cargo = {}
|
||||
if Unit and Unit:IsAlive() then
|
||||
local name = Unit:GetName()
|
||||
if self.Loaded_Cargo[name] then
|
||||
Troops = self.Loaded_Cargo[name].Troopsloaded or 0
|
||||
Crates = self.Loaded_Cargo[name].Cratesloaded or 0
|
||||
Cargo = self.Loaded_Cargo[name].Cargo or {}
|
||||
end
|
||||
end
|
||||
return Troops, Crates, Cargo
|
||||
end
|
||||
|
||||
--- User - function to get a table of statics cargo in stock
|
||||
-- @param #CTLD self
|
||||
-- @return #table Table Table of Stock, indexed by cargo type name
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
-- @field #table poptions Provider options. Each element is a data structure of type `MSRS.ProvierOptions`.
|
||||
-- @field #string provider Provider of TTS (win, gcloud, azure, amazon).
|
||||
-- @field #string backend Backend used as interface to SRS (MSRS.Backend.SRSEXE or MSRS.Backend.GRPC).
|
||||
-- @field #boolean UsePowerShell Use PowerShell to execute the command and not cmd.exe
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
|
||||
@@ -256,11 +257,12 @@ MSRS = {
|
||||
ConfigFilePath = "Config\\",
|
||||
ConfigLoaded = false,
|
||||
poptions = {},
|
||||
UsePowerShell = false,
|
||||
}
|
||||
|
||||
--- MSRS class version.
|
||||
-- @field #string version
|
||||
MSRS.version="0.3.0"
|
||||
MSRS.version="0.3.3"
|
||||
|
||||
--- Voices
|
||||
-- @type MSRS.Voices
|
||||
@@ -588,7 +590,7 @@ function MSRS:SetBackendSRSEXE()
|
||||
end
|
||||
|
||||
--- Set the default backend.
|
||||
-- @param #MSRS self
|
||||
-- @param #string Backend
|
||||
function MSRS.SetDefaultBackend(Backend)
|
||||
MSRS.backend=Backend or MSRS.Backend.SRSEXE
|
||||
end
|
||||
@@ -1375,20 +1377,25 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
||||
modus=modus:gsub("1", "FM")
|
||||
|
||||
-- Command.
|
||||
local pwsh = string.format('Start-Process -WindowStyle Hidden -WorkingDirectory \"%s\" -FilePath \"%s\" -ArgumentList \'-f "%s" -m "%s" -c %s -p %s -n "%s" -v "%.1f"', path, exe, freqs, modus, coal, port, label,volume )
|
||||
|
||||
local command=string.format('"%s\\%s" -f "%s" -m "%s" -c %s -p %s -n "%s" -v "%.1f"', path, exe, freqs, modus, coal, port, label,volume)
|
||||
|
||||
-- Set voice or gender/culture.
|
||||
if voice then
|
||||
if voice and self.UsePowerShell ~= true then
|
||||
-- Use a specific voice (no need for gender and/or culture.
|
||||
command=command..string.format(" --voice=\"%s\"", tostring(voice))
|
||||
pwsh=pwsh..string.format(" --voice=\"%s\"", tostring(voice))
|
||||
else
|
||||
-- Add gender.
|
||||
if gender and gender~="female" then
|
||||
command=command..string.format(" -g %s", tostring(gender))
|
||||
pwsh=pwsh..string.format(" -g %s", tostring(gender))
|
||||
end
|
||||
-- Add culture.
|
||||
if culture and culture~="en-GB" then
|
||||
command=command..string.format(" -l %s", tostring(culture))
|
||||
pwsh=pwsh..string.format(" -l %s", tostring(culture))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1396,12 +1403,14 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
||||
if coordinate then
|
||||
local lat,lon,alt=self:_GetLatLongAlt(coordinate)
|
||||
command=command..string.format(" -L %.4f -O %.4f -A %d", lat, lon, alt)
|
||||
pwsh=pwsh..string.format(" -L %.4f -O %.4f -A %d", lat, lon, alt)
|
||||
end
|
||||
|
||||
-- Set provider options
|
||||
if self.provider==MSRS.Provider.GOOGLE then
|
||||
local pops=self:GetProviderOptions()
|
||||
command=command..string.format(' --ssml -G "%s"', pops.credentials)
|
||||
pwsh=pwsh..string.format(' --ssml -G "%s"', pops.credentials)
|
||||
elseif self.provider==MSRS.Provider.WINDOWS then
|
||||
-- Nothing to do.
|
||||
else
|
||||
@@ -1415,8 +1424,12 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
||||
|
||||
-- Debug output.
|
||||
self:T("MSRS command from _GetCommand="..command)
|
||||
|
||||
return command
|
||||
|
||||
if self.UsePowerShell == true then
|
||||
return pwsh
|
||||
else
|
||||
return command
|
||||
end
|
||||
end
|
||||
|
||||
--- Execute SRS command to play sound using the `DCS-SR-ExternalAudio.exe`.
|
||||
@@ -1424,7 +1437,7 @@ end
|
||||
-- @param #string command Command to executer
|
||||
-- @return #number Return value of os.execute() command.
|
||||
function MSRS:_ExecCommand(command)
|
||||
self:F( {command=command} )
|
||||
self:T2( {command=command} )
|
||||
|
||||
-- Skip this function if _GetCommand was not able to find the executable
|
||||
if string.find(command, "CommandNotFound") then return 0 end
|
||||
@@ -1432,7 +1445,13 @@ function MSRS:_ExecCommand(command)
|
||||
local batContent = command.." && exit"
|
||||
-- Create a tmp file.
|
||||
local filename=os.getenv('TMP').."\\MSRS-"..MSRS.uuid()..".bat"
|
||||
|
||||
|
||||
if self.UsePowerShell == true then
|
||||
filename=os.getenv('TMP').."\\MSRS-"..MSRS.uuid()..".ps1"
|
||||
batContent = command .. "\'"
|
||||
self:I({batContent=batContent})
|
||||
end
|
||||
|
||||
local script=io.open(filename, "w+")
|
||||
script:write(batContent)
|
||||
script:close()
|
||||
@@ -1441,7 +1460,7 @@ function MSRS:_ExecCommand(command)
|
||||
self:T("MSRS batch content: "..batContent)
|
||||
|
||||
local res=nil
|
||||
if true then
|
||||
if self.UsePowerShell ~= true then
|
||||
|
||||
-- Create a tmp file.
|
||||
local filenvbs = os.getenv('TMP') .. "\\MSRS-"..MSRS.uuid()..".vbs"
|
||||
@@ -1469,23 +1488,20 @@ function MSRS:_ExecCommand(command)
|
||||
timer.scheduleFunction(os.remove, filenvbs, timer.getTime()+1)
|
||||
self:T("MSRS vbs and batch file removed")
|
||||
|
||||
elseif false then
|
||||
|
||||
-- Create a tmp file.
|
||||
local filenvbs = os.getenv('TMP') .. "\\MSRS-"..MSRS.uuid()..".vbs"
|
||||
|
||||
-- VBS script
|
||||
local script = io.open(filenvbs, "w+")
|
||||
script:write(string.format('Set oShell = CreateObject ("Wscript.Shell")\n'))
|
||||
script:write(string.format('Dim strArgs\n'))
|
||||
script:write(string.format('strArgs = "cmd /c %s"\n', filename))
|
||||
script:write(string.format('oShell.Run strArgs, 0, false'))
|
||||
script:close()
|
||||
|
||||
local runvbs=string.format('cscript.exe //Nologo //B "%s"', filenvbs)
|
||||
elseif self.UsePowerShell == true then
|
||||
|
||||
local pwsh = string.format('start /min "" powershell.exe -ExecutionPolicy Unrestricted -WindowStyle Hidden -Command "%s"',filename)
|
||||
--env.info("[MSRS] TextToSpeech Command :\n" .. pwsh.."\n")
|
||||
|
||||
if string.len(pwsh) > 255 then
|
||||
self:E("[MSRS] - pwsh string too long")
|
||||
end
|
||||
|
||||
-- Play file in 0.01 seconds
|
||||
res=os.execute(runvbs)
|
||||
res=os.execute(pwsh)
|
||||
|
||||
-- Remove file in 1 second.
|
||||
timer.scheduleFunction(os.remove, filename, timer.getTime()+1)
|
||||
|
||||
else
|
||||
-- Play command.
|
||||
|
||||
@@ -1195,18 +1195,18 @@ ENUMS.Storage.weapons.UH1H.M60_MG_Right_Door = {4,15,46,177}
|
||||
ENUMS.Storage.weapons.UH1H.M134_MiniGun_Left_Door = {4,15,46,174}
|
||||
ENUMS.Storage.weapons.UH1H.M60_MG_Left_Door = {4,15,46,176}
|
||||
-- Kiowa
|
||||
ENUMS.Storage.weapons.OH58.FIM92 = {4,4,7,446}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P100 = {4,15,46,2578}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P200 = {4,15,46,2577}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P300 = {4,15,46,2576}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P400 = {4,15,46,2575}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P500 = {4,15,46,2574}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_Blue = {4,5,9,484}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_Green = {4,5,9,485}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_Red = {4,5,9,483}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_Violet = {4,5,9,486}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_White = {4,5,9,488}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_Yellow = {4,5,9,487}
|
||||
ENUMS.Storage.weapons.OH58.FIM92 = {4,4,7,449}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P100 = {4,15,46,2608}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P200 = {4,15,46,2607}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P300 = {4,15,46,2606}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P400 = {4,15,46,2605}
|
||||
ENUMS.Storage.weapons.OH58.MG_M3P500 = {4,15,46,2604}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_Blue = {4,5,9,486}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_Green = {4,5,9,487}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_Red = {4,5,9,485}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_Violet = {4,5,9,488}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_White = {4,5,9,490}
|
||||
ENUMS.Storage.weapons.OH58.Smk_Grenade_Yellow = {4,5,9,489}
|
||||
-- Apache
|
||||
ENUMS.Storage.weapons.AH64D.AN_APG78 = {4,15,44,2138}
|
||||
ENUMS.Storage.weapons.AH64D.Internal_Aux_FuelTank = {1,3,43,1700}
|
||||
|
||||
@@ -56,6 +56,8 @@ BIGSMOKEPRESET = {
|
||||
-- @field #string Falklands South Atlantic map.
|
||||
-- @field #string Sinai Sinai map.
|
||||
-- @field #string Kola Kola map.
|
||||
-- @field #string Afghanistan Afghanistan map
|
||||
-- @field #string Iraq Iraq map
|
||||
DCSMAP = {
|
||||
Caucasus="Caucasus",
|
||||
NTTR="Nevada",
|
||||
@@ -68,6 +70,7 @@ DCSMAP = {
|
||||
Sinai="SinaiMap",
|
||||
Kola="Kola",
|
||||
Afghanistan="Afghanistan",
|
||||
Iraq="Iraq"
|
||||
}
|
||||
|
||||
|
||||
@@ -1786,6 +1789,8 @@ function UTILS.GetMagneticDeclination(map)
|
||||
declination=15
|
||||
elseif map==DCSMAP.Afghanistan then
|
||||
declination=3
|
||||
elseif map==DCSMAP.Iraq then
|
||||
declination=4.4
|
||||
else
|
||||
declination=0
|
||||
end
|
||||
@@ -2315,9 +2320,9 @@ function UTILS.IsLoadingDoorOpen( unit_name )
|
||||
return true
|
||||
end
|
||||
|
||||
if type_name == "OH-58D" and (unit:getDrawArgumentValue(35) > 0 or unit:getDrawArgumentValue(421) == -1) then
|
||||
BASE:T(unit_name .. " cargo door is open")
|
||||
return true
|
||||
if type_name == "OH58D" then
|
||||
BASE:T(unit_name .. " front door(s) are open")
|
||||
return true -- no doors on this one ;)
|
||||
end
|
||||
|
||||
if type_name == "CH-47Fbl1" and (unit:getDrawArgumentValue(86) > 0.5) then
|
||||
@@ -2523,7 +2528,7 @@ end
|
||||
--- Function to save an object to a file
|
||||
-- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems.
|
||||
-- @param #string Filename The name of the file. Existing file will be overwritten.
|
||||
-- @param #table Data The LUA data structure to save. This will be e.g. a table of text lines with an \\n at the end of each line.
|
||||
-- @param #string Data The data structure to save. This will be e.g. a string of text lines with an \\n at the end of each line.
|
||||
-- @return #boolean outcome True if saving is possible, else false.
|
||||
function UTILS.SaveToFile(Path,Filename,Data)
|
||||
-- Thanks to @FunkyFranky
|
||||
|
||||
@@ -63,6 +63,11 @@
|
||||
-- To be able to distinguish easily in your code the difference between a AIRBASE API call and a DCS Airbase API call,
|
||||
-- the first letter of the method is also capitalized. So, by example, the DCS Airbase method DCSWrapper.Airbase#Airbase.getName()
|
||||
-- is implemented in the AIRBASE class as @{#AIRBASE.GetName}().
|
||||
--
|
||||
-- ## Note on the "H" heli pads in the Syria map:
|
||||
--
|
||||
-- As of the time of writing (Oct 2024, DCS DCS 2.9.8.1107), these 143 objects have the **same name and object ID**, which makes them unusable in Moose, e.g. you cannot find a specific one for spawning etc.
|
||||
-- Waiting for Ugra and ED to fix this issue.
|
||||
--
|
||||
-- @field #AIRBASE AIRBASE
|
||||
AIRBASE = {
|
||||
@@ -248,6 +253,9 @@ AIRBASE.Nevada = {
|
||||
-- * AIRBASE.Normandy.Villacoublay
|
||||
-- * AIRBASE.Normandy.Vrigny
|
||||
-- * AIRBASE.Normandy.West_Malling
|
||||
-- * AIRBASE.Normandy.Eastchurch
|
||||
-- * AIRBASE.Normandy.Headcorn
|
||||
-- * AIRBASE.Normandy.Hawkinge
|
||||
--
|
||||
-- @field Normandy
|
||||
AIRBASE.Normandy = {
|
||||
@@ -330,6 +338,9 @@ AIRBASE.Normandy = {
|
||||
["Villacoublay"] = "Villacoublay",
|
||||
["Vrigny"] = "Vrigny",
|
||||
["West_Malling"] = "West Malling",
|
||||
["Eastchurch"] = "Eastchurch",
|
||||
["Headcorn"] = "Headcorn",
|
||||
["Hawkinge"] = "Hawkinge",
|
||||
}
|
||||
|
||||
--- Airbases of the Persion Gulf Map:
|
||||
@@ -450,6 +461,7 @@ AIRBASE.TheChannel = {
|
||||
-- * AIRBASE.Syria.Gaziantep
|
||||
-- * AIRBASE.Syria.Gazipasa
|
||||
-- * AIRBASE.Syria.Gecitkale
|
||||
-- * AIRBASE.Syria.H
|
||||
-- * AIRBASE.Syria.H3
|
||||
-- * AIRBASE.Syria.H3_Northwest
|
||||
-- * AIRBASE.Syria.H3_Southwest
|
||||
@@ -497,6 +509,10 @@ AIRBASE.TheChannel = {
|
||||
-- * AIRBASE.Syria.Tha_lah
|
||||
-- * AIRBASE.Syria.Tiyas
|
||||
-- * AIRBASE.Syria.Wujah_Al_Hajar
|
||||
-- * AIRBASE.Syria.Ben_Gurion
|
||||
-- * AIRBASE.Syria.Hatzor
|
||||
-- * AIRBASE.Syria.Palmashim
|
||||
-- * AIRBASE.Syria.Tel_Nof
|
||||
--
|
||||
--@field Syria
|
||||
AIRBASE.Syria={
|
||||
@@ -518,6 +534,7 @@ AIRBASE.Syria={
|
||||
["Gaziantep"] = "Gaziantep",
|
||||
["Gazipasa"] = "Gazipasa",
|
||||
["Gecitkale"] = "Gecitkale",
|
||||
["H"] = "H",
|
||||
["H3"] = "H3",
|
||||
["H3_Northwest"] = "H3 Northwest",
|
||||
["H3_Southwest"] = "H3 Southwest",
|
||||
@@ -565,6 +582,10 @@ AIRBASE.Syria={
|
||||
["Tha_lah"] = "Tha'lah",
|
||||
["Tiyas"] = "Tiyas",
|
||||
["Wujah_Al_Hajar"] = "Wujah Al Hajar",
|
||||
["Ben_Gurion"] = "Ben Gurion",
|
||||
["Hatzor"] = "Hatzor",
|
||||
["Palmashim"] = "Palmashim",
|
||||
["Tel_Nof"] = "Tel Nof",
|
||||
}
|
||||
|
||||
--- Airbases of the Mariana Islands map:
|
||||
@@ -752,12 +773,14 @@ AIRBASE.Sinai = {
|
||||
--
|
||||
-- * AIRBASE.Kola.Banak
|
||||
-- * AIRBASE.Kola.Bodo
|
||||
-- * AIRBASE.Kola.Ivalo
|
||||
-- * AIRBASE.Kola.Jokkmokk
|
||||
-- * AIRBASE.Kola.Kalixfors
|
||||
-- * AIRBASE.Kola.Kallax
|
||||
-- * AIRBASE.Kola.Kemi_Tornio
|
||||
-- * AIRBASE.Kola.Kirkenes
|
||||
-- * AIRBASE.Kola.Kiruna
|
||||
-- * AIRBASE.Kola.Kuusamo
|
||||
-- * AIRBASE.Kola.Monchegorsk
|
||||
-- * AIRBASE.Kola.Murmansk_International
|
||||
-- * AIRBASE.Kola.Olenya
|
||||
@@ -766,25 +789,31 @@ AIRBASE.Sinai = {
|
||||
-- * AIRBASE.Kola.Severomorsk_3
|
||||
-- * AIRBASE.Kola.Vidsel
|
||||
-- * AIRBASE.Kola.Vuojarvi
|
||||
--
|
||||
-- * AIRBASE.Kola.Andoya
|
||||
-- * AIRBASE.Kola.Alakourtti
|
||||
--
|
||||
-- @field Kola
|
||||
AIRBASE.Kola = {
|
||||
["Banak"] = "Banak",
|
||||
["Bodo"] = "Bodo",
|
||||
["Ivalo"] = "Ivalo",
|
||||
["Jokkmokk"] = "Jokkmokk",
|
||||
["Kalixfors"] = "Kalixfors",
|
||||
["Kallax"] = "Kallax",
|
||||
["Kemi_Tornio"] = "Kemi Tornio",
|
||||
["Kirkenes"] = "Kirkenes",
|
||||
["Kiruna"] = "Kiruna",
|
||||
["Kuusamo"] = "Kuusamo",
|
||||
["Monchegorsk"] = "Monchegorsk",
|
||||
["Murmansk_International"] = "Murmansk International",
|
||||
["Olenya"] = "Olenya",
|
||||
["Rovaniemi"] = "Rovaniemi",
|
||||
["Severomorsk_1"] = "Severomorsk-1",
|
||||
["Severomorsk_3"] = "Severomorsk-3",
|
||||
["Vuojarvi"] = "Vuojarvi",
|
||||
["Kirkenes"] = "Kirkenes",
|
||||
["Kallax"] = "Kallax",
|
||||
["Vidsel"] = "Vidsel",
|
||||
["Vuojarvi"] = "Vuojarvi",
|
||||
["Andoya"] = "Andoya",
|
||||
["Alakourtti"] = "Alakourtti",
|
||||
}
|
||||
|
||||
--- Airbases of the Afghanistan map
|
||||
@@ -824,6 +853,39 @@ AIRBASE.Afghanistan = {
|
||||
["Tarinkot"] = "Tarinkot",
|
||||
}
|
||||
|
||||
--- Airbases of the Iraq map
|
||||
--
|
||||
-- * `AIRBASE.Iraq.Baghdad_International_Airport` Baghdad International Airport
|
||||
-- * `AIRBASE.Iraq.Sulaimaniyah_International_Airport` Sulaimaniyah International Airport
|
||||
-- * `AIRBASE.Iraq.Al_Sahra_Airport` Al-Sahra Airport
|
||||
-- * `AIRBASE.Iraq.Erbil_International_Airport` Erbil International Airport
|
||||
-- * `AIRBASE.Iraq.Al_Taji_Airport` Al-Taji Airport
|
||||
-- * `AIRBASE.Iraq.Al_Asad_Airbase` Al-Asad Airbase
|
||||
-- * `AIRBASE.Iraq.Al_Salam_Airbase` Al-Salam Airbase
|
||||
-- * `AIRBASE.Iraq.Balad_Airbase` Balad Airbase
|
||||
-- * `AIRBASE.Iraq.Kirkuk_International_Airport` Kirkuk International Airport
|
||||
-- * `AIRBASE.Iraq.Bashur_Airport` Bashur Airport
|
||||
-- * `AIRBASE.Iraq.Al_Taquddum_Airport` Al-Taquddum Airport
|
||||
-- * `AIRBASE.Iraq.Qayyarah_Airfield_West` Qayyarah Airfield West
|
||||
-- * `AIRBASE.Iraq.K1_Base` K1 Base
|
||||
--
|
||||
-- @field Iraq
|
||||
AIRBASE.Iraq = {
|
||||
["Baghdad_International_Airport"] = "Baghdad International Airport",
|
||||
["Sulaimaniyah_International_Airport"] = "Sulaimaniyah International Airport",
|
||||
["Al_Sahra_Airport"] = "Al-Sahra Airport",
|
||||
["Erbil_International_Airport"] = "Erbil International Airport",
|
||||
["Al_Taji_Airport"] = "Al-Taji Airport",
|
||||
["Al_Asad_Airbase"] = "Al-Asad Airbase",
|
||||
["Al_Salam_Airbase"] = "Al-Salam Airbase",
|
||||
["Balad_Airbase"] = "Balad Airbase",
|
||||
["Kirkuk_International_Airport"] = "Kirkuk International Airport",
|
||||
["Bashur_Airport"] = "Bashur Airport",
|
||||
["Al_Taquddum_Airport"] = "Al-Taquddum Airport",
|
||||
["Qayyarah_Airfield_West"] = "Qayyarah Airfield West",
|
||||
["K1_Base"] = "K1 Base",
|
||||
}
|
||||
|
||||
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
||||
-- @type AIRBASE.ParkingSpot
|
||||
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.
|
||||
@@ -926,7 +988,7 @@ function AIRBASE:Register(AirbaseName)
|
||||
|
||||
-- Debug info.
|
||||
--self:I({airbase=AirbaseName, descriptors=self.descriptors})
|
||||
|
||||
|
||||
-- Category.
|
||||
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
|
||||
|
||||
@@ -937,22 +999,22 @@ function AIRBASE:Register(AirbaseName)
|
||||
--end
|
||||
|
||||
-- Set category.
|
||||
if self.category==Airbase.Category.AIRDROME then
|
||||
self.isAirdrome=true
|
||||
elseif self.category==Airbase.Category.HELIPAD then
|
||||
if self.category==Airbase.Category.AIRDROME then
|
||||
self.isAirdrome=true
|
||||
elseif self.category==Airbase.Category.HELIPAD or self.descriptors.typeName=="FARP_SINGLE_01" then
|
||||
self.isHelipad=true
|
||||
elseif self.category==Airbase.Category.SHIP then
|
||||
self.isShip=true
|
||||
-- DCS bug: Oil rigs and gas platforms have category=2 (ship). Also they cannot be retrieved by coalition.getStaticObjects()
|
||||
if self.descriptors.typeName=="Oil rig" or self.descriptors.typeName=="Ga" then
|
||||
self.isHelipad=true
|
||||
elseif self.category==Airbase.Category.SHIP then
|
||||
self.isShip=true
|
||||
-- DCS bug: Oil rigs and gas platforms have category=2 (ship). Also they cannot be retrieved by coalition.getStaticObjects()
|
||||
if self.descriptors.typeName=="Oil rig" or self.descriptors.typeName=="Ga" then
|
||||
self.isHelipad=true
|
||||
self.isShip=false
|
||||
self.category=Airbase.Category.HELIPAD
|
||||
_DATABASE:AddStatic(AirbaseName)
|
||||
end
|
||||
else
|
||||
self:E("ERROR: Unknown airbase category!")
|
||||
self.isShip=false
|
||||
self.category=Airbase.Category.HELIPAD
|
||||
_DATABASE:AddStatic(AirbaseName)
|
||||
end
|
||||
else
|
||||
self:E("ERROR: Unknown airbase category!")
|
||||
end
|
||||
|
||||
-- Init Runways.
|
||||
self:_InitRunways()
|
||||
|
||||
@@ -902,7 +902,11 @@ function CONTROLLABLE:CommandEPLRS( SwitchOnOff, Delay )
|
||||
groupId = self:GetID(),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
--if self:IsGround() then
|
||||
--CommandEPLRS.params.groupId = self:GetID()
|
||||
--end
|
||||
|
||||
if Delay and Delay > 0 then
|
||||
SCHEDULER:New( nil, self.CommandEPLRS, { self, SwitchOnOff }, Delay )
|
||||
else
|
||||
@@ -937,7 +941,7 @@ function CONTROLLABLE:CommandSetUnlimitedFuel(OnOff, Delay)
|
||||
end
|
||||
|
||||
|
||||
--- Set radio frequency. See [DCS command EPLRS](https://wiki.hoggitworld.com/view/DCS_command_setFrequency)
|
||||
--- Set radio frequency. See [DCS command SetFrequency](https://wiki.hoggitworld.com/view/DCS_command_setFrequency)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Frequency Radio frequency in MHz.
|
||||
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
|
||||
@@ -956,7 +960,7 @@ function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Power, Delay )
|
||||
}
|
||||
|
||||
if Delay and Delay > 0 then
|
||||
SCHEDULER:New( nil, self.CommandSetFrequency, { self, Frequency, Modulation, Power } )
|
||||
SCHEDULER:New( nil, self.CommandSetFrequency, { self, Frequency, Modulation, Power },Delay )
|
||||
else
|
||||
self:SetCommand( CommandSetFrequency )
|
||||
end
|
||||
@@ -964,7 +968,7 @@ function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Power, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set radio frequency. See [DCS command EPLRS](https://wiki.hoggitworld.com/view/DCS_command_setFrequencyForUnit)
|
||||
--- [AIR] Set radio frequency. See [DCS command SetFrequencyForUnit](https://wiki.hoggitworld.com/view/DCS_command_setFrequencyForUnit)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Frequency Radio frequency in MHz.
|
||||
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
|
||||
@@ -983,7 +987,7 @@ function CONTROLLABLE:CommandSetFrequencyForUnit(Frequency,Modulation,Power,Unit
|
||||
},
|
||||
}
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil,self.CommandSetFrequencyForUnit,{self,Frequency,Modulation,Power,UnitID})
|
||||
SCHEDULER:New(nil,self.CommandSetFrequencyForUnit,{self,Frequency,Modulation,Power,UnitID},Delay)
|
||||
else
|
||||
self:SetCommand(CommandSetFrequencyForUnit)
|
||||
end
|
||||
@@ -1009,7 +1013,11 @@ function CONTROLLABLE:TaskEPLRS( SwitchOnOff, idx )
|
||||
groupId = self:GetID(),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
--if self:IsGround() then
|
||||
--CommandEPLRS.params.groupId = self:GetID()
|
||||
--end
|
||||
|
||||
return self:TaskWrappedAction( CommandEPLRS, idx or 1 )
|
||||
end
|
||||
|
||||
@@ -2997,7 +3005,7 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad
|
||||
if DCSControllable then
|
||||
|
||||
local DetectionVisual = (DetectVisual and DetectVisual == true) and Controller.Detection.VISUAL or nil
|
||||
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTICAL or nil
|
||||
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTIC or nil
|
||||
local DetectionRadar = (DetectRadar and DetectRadar == true) and Controller.Detection.RADAR or nil
|
||||
local DetectionIRST = (DetectIRST and DetectIRST == true) and Controller.Detection.IRST or nil
|
||||
local DetectionRWR = (DetectRWR and DetectRWR == true) and Controller.Detection.RWR or nil
|
||||
@@ -3031,26 +3039,27 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Check if a target is detected.
|
||||
--- Check if a DCS object (unit or static) is detected by the controllable.
|
||||
-- Note that after a target is detected it remains "detected" for a certain amount of time, even if the controllable cannot "see" the target any more with it's sensors.
|
||||
-- The optional parametes specify the detection methods that can be applied.
|
||||
--
|
||||
-- If **no** detection method is given, the detection will use **all** the available methods by default.
|
||||
-- If **at least one** detection method is specified, only the methods set to *true* will be used.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param DCS#Object DCSObject The DCS object that is checked.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #boolean DetectVisual (Optional) If *false*, do not include visually detected targets.
|
||||
-- @param #boolean DetectOptical (Optional) If *false*, do not include optically detected targets.
|
||||
-- @param #boolean DetectRadar (Optional) If *false*, do not include targets detected by radar.
|
||||
-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST.
|
||||
-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR.
|
||||
-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link.
|
||||
-- @return #boolean True if target is detected.
|
||||
-- @return #boolean True if target is visible by line of sight.
|
||||
-- @return #number Mission time when target was detected.
|
||||
-- @return #boolean True if target type is known.
|
||||
-- @return #boolean True if distance to target is known.
|
||||
-- @return DCS#Vec3 Last known position vector of the target.
|
||||
-- @return DCS#Vec3 Last known velocity vector of the target.
|
||||
-- @return #boolean `true` if target is detected.
|
||||
-- @return #boolean `true` if target is *currently* visible by line of sight. Target must be detected (first parameter returns `true`).
|
||||
-- @return #boolean `true` if target type is known. Target must be detected (first parameter returns `true`).
|
||||
-- @return #boolean `true` if distance to target is known. Target must be detected (first parameter returns `true`).
|
||||
-- @return #number Mission time in seconds when target was last detected. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
-- @return DCS#Vec3 Last known position vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
-- @return DCS#Vec3 Last known velocity vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK )
|
||||
self:F2( self.ControllableName )
|
||||
|
||||
@@ -3059,7 +3068,7 @@ function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical,
|
||||
if DCSControllable then
|
||||
|
||||
local DetectionVisual = (DetectVisual and DetectVisual == true) and Controller.Detection.VISUAL or nil
|
||||
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTICAL or nil
|
||||
local DetectionOptical = (DetectOptical and DetectOptical == true) and Controller.Detection.OPTIC or nil
|
||||
local DetectionRadar = (DetectRadar and DetectRadar == true) and Controller.Detection.RADAR or nil
|
||||
local DetectionIRST = (DetectIRST and DetectIRST == true) and Controller.Detection.IRST or nil
|
||||
local DetectionRWR = (DetectRWR and DetectRWR == true) and Controller.Detection.RWR or nil
|
||||
@@ -3067,10 +3076,10 @@ function CONTROLLABLE:IsTargetDetected( DCSObject, DetectVisual, DetectOptical,
|
||||
|
||||
local Controller = self:_GetController()
|
||||
|
||||
local TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity
|
||||
local TargetIsDetected, TargetIsVisible, TargetKnowType, TargetKnowDistance, TargetLastTime, TargetLastPos, TargetLastVelocity
|
||||
= Controller:isTargetDetected( DCSObject, DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK )
|
||||
|
||||
return TargetIsDetected, TargetIsVisible, TargetLastTime, TargetKnowType, TargetKnowDistance, TargetLastPos, TargetLastVelocity
|
||||
return TargetIsDetected, TargetIsVisible, TargetKnowType, TargetKnowDistance, TargetLastTime, TargetLastPos, TargetLastVelocity
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -3078,6 +3087,7 @@ end
|
||||
|
||||
--- Check if a certain UNIT is detected by the controllable.
|
||||
-- The optional parametes specify the detection methods that can be applied.
|
||||
--
|
||||
-- If **no** detection method is given, the detection will use **all** the available methods by default.
|
||||
-- If **at least one** detection method is specified, only the methods set to *true* will be used.
|
||||
-- @param #CONTROLLABLE self
|
||||
@@ -3088,13 +3098,13 @@ end
|
||||
-- @param #boolean DetectIRST (Optional) If *false*, do not include targets detected by IRST.
|
||||
-- @param #boolean DetectRWR (Optional) If *false*, do not include targets detected by RWR.
|
||||
-- @param #boolean DetectDLINK (Optional) If *false*, do not include targets detected by data link.
|
||||
-- @return #boolean True if target is detected.
|
||||
-- @return #boolean True if target is visible by line of sight.
|
||||
-- @return #number Mission time when target was detected.
|
||||
-- @return #boolean True if target type is known.
|
||||
-- @return #boolean True if distance to target is known.
|
||||
-- @return DCS#Vec3 Last known position vector of the target.
|
||||
-- @return DCS#Vec3 Last known velocity vector of the target.
|
||||
-- @return #boolean `true` if target is detected.
|
||||
-- @return #boolean `true` if target is *currently* visible by line of sight. Target must be detected (first parameter returns `true`).
|
||||
-- @return #boolean `true` if target type is known. Target must be detected (first parameter returns `true`).
|
||||
-- @return #boolean `true` if distance to target is known. Target must be detected (first parameter returns `true`).
|
||||
-- @return #number Mission time in seconds when target was last detected. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
-- @return DCS#Vec3 Last known position vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
-- @return DCS#Vec3 Last known velocity vector of the target. Only present if the target is currently not visible (second parameter returns `false`) otherwise `nil` is returned.
|
||||
function CONTROLLABLE:IsUnitDetected( Unit, DetectVisual, DetectOptical, DetectRadar, DetectIRST, DetectRWR, DetectDLINK )
|
||||
self:F2( self.ControllableName )
|
||||
|
||||
|
||||
@@ -458,7 +458,7 @@ function DYNAMICCARGO:_UpdatePosition()
|
||||
self:T(self.lid.." AGL: "..agl or -1)
|
||||
local isunloaded = true
|
||||
local client
|
||||
local playername
|
||||
local playername = self.Owner
|
||||
if count > 0 and (agl > 0 or self.testing) then
|
||||
self:T(self.lid.." Possible alive helos: "..count or -1)
|
||||
if agl ~= 0 or self.testing then
|
||||
@@ -470,6 +470,11 @@ function DYNAMICCARGO:_UpdatePosition()
|
||||
self.Owner = playername
|
||||
_DATABASE:CreateEventDynamicCargoUnloaded(self)
|
||||
end
|
||||
elseif count > 0 and agl == 0 then
|
||||
self:T(self.lid.." moved! LOADED -> UNLOADED by "..tostring(playername))
|
||||
self.CargoState = DYNAMICCARGO.State.UNLOADED
|
||||
self.Owner = playername
|
||||
_DATABASE:CreateEventDynamicCargoUnloaded(self)
|
||||
end
|
||||
end
|
||||
self.LastPosition = pos
|
||||
|
||||
@@ -360,7 +360,7 @@ end
|
||||
-- @return DCS#Group The DCS Group.
|
||||
function GROUP:GetDCSObject()
|
||||
|
||||
if (not self.LastCallDCSObject) or (self.LastCallDCSObject and timer.getTime() - self.LastCallDCSObject > 1) then
|
||||
--if (not self.LastCallDCSObject) or (self.LastCallDCSObject and timer.getTime() - self.LastCallDCSObject > 1) then
|
||||
|
||||
-- Get DCS group.
|
||||
local DCSGroup = Group.getByName( self.GroupName )
|
||||
@@ -369,14 +369,14 @@ function GROUP:GetDCSObject()
|
||||
self.LastCallDCSObject = timer.getTime()
|
||||
self.DCSObject = DCSGroup
|
||||
return DCSGroup
|
||||
else
|
||||
self.DCSObject = nil
|
||||
self.LastCallDCSObject = nil
|
||||
-- else
|
||||
-- self.DCSObject = nil
|
||||
-- self.LastCallDCSObject = nil
|
||||
end
|
||||
|
||||
else
|
||||
return self.DCSObject
|
||||
end
|
||||
--else
|
||||
--return self.DCSObject
|
||||
--end
|
||||
|
||||
--self:E(string.format("ERROR: Could not get DCS group object of group %s because DCS object could not be found!", tostring(self.GroupName)))
|
||||
return nil
|
||||
@@ -485,20 +485,24 @@ function GROUP:Destroy( GenerateEvent, delay )
|
||||
self:ScheduleOnce(delay, GROUP.Destroy, self, GenerateEvent)
|
||||
else
|
||||
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
--local DCSGroup = self:GetDCSObject()
|
||||
local DCSGroup = Group.getByName( self.GroupName )
|
||||
|
||||
if DCSGroup then
|
||||
for Index, UnitData in pairs( DCSGroup:getUnits() ) do
|
||||
if GenerateEvent and GenerateEvent == true then
|
||||
if self:IsAir() then
|
||||
self:CreateEventCrash( timer.getTime(), UnitData )
|
||||
--self:ScheduleOnce(1,self.CreateEventCrash,self,timer.getTime(),UnitData)
|
||||
else
|
||||
self:CreateEventDead( timer.getTime(), UnitData )
|
||||
--self:ScheduleOnce(1,self.CreateEventDead,self,timer.getTime(),UnitData)
|
||||
end
|
||||
elseif GenerateEvent == false then
|
||||
-- Do nothing!
|
||||
else
|
||||
self:CreateEventRemoveUnit( timer.getTime(), UnitData )
|
||||
--self:ScheduleOnce(1,self.CreateEventRemoveUnit,self,timer.getTime(),UnitData)
|
||||
end
|
||||
end
|
||||
USERFLAG:New( self:GetName() ):Set( 100 )
|
||||
@@ -1985,15 +1989,11 @@ end
|
||||
-- - @{#GROUP.InitHeight}: Set the height for the units in meters for the respawned group. (This is applicable for air units).
|
||||
-- - @{#GROUP.InitRandomizeHeading}: Randomize the headings for the units within the respawned group.
|
||||
-- - @{#GROUP.InitZone}: Set the respawn @{Core.Zone} for the respawned group.
|
||||
-- - @{#GROUP.InitRandomizeZones}: Randomize the respawn @{Core.Zone} between one of the @{Core.Zone}s given for the respawned group.
|
||||
-- - @{#GROUP.InitRandomizePositionZone}: Randomize the positions of the units of the respawned group within the @{Core.Zone}.
|
||||
-- - @{#GROUP.InitRandomizePositionRadius}: Randomize the positions of the units of the respawned group in a circle band.
|
||||
-- - @{#GROUP.InitRandomizeTemplates}: Randomize the Template for the respawned group.
|
||||
--
|
||||
--
|
||||
-- Notes:
|
||||
--
|
||||
-- - When InitZone or InitRandomizeZones is not used, the position of the respawned group will be its current position.
|
||||
-- - The current alive group will always be destroyed and respawned using the template definition.
|
||||
--
|
||||
-- @param Wrapper.Group#GROUP self
|
||||
@@ -2015,10 +2015,24 @@ function GROUP:Respawn( Template, Reset )
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
local function TransFormRoute(Template,OldPos,NewPos)
|
||||
if Template.route and Template.route.points then
|
||||
for _,_point in ipairs(Template.route.points) do
|
||||
--self:I(string.format("Point x = %f Point y = %f",_point.x,_point.y))
|
||||
_point.x = _point.x - OldPos.x + NewPos.x
|
||||
_point.y = _point.y - OldPos.y + NewPos.y
|
||||
--self:I(string.format("Point x = %f Point y = %f",_point.x,_point.y))
|
||||
end
|
||||
end
|
||||
return Template
|
||||
end
|
||||
|
||||
-- First check if group is alive.
|
||||
if self:IsAlive() then
|
||||
|
||||
|
||||
local OldPos = self:GetVec2()
|
||||
|
||||
-- Respawn zone.
|
||||
local Zone = self.InitRespawnZone -- Core.Zone#ZONE
|
||||
|
||||
@@ -2031,6 +2045,8 @@ function GROUP:Respawn( Template, Reset )
|
||||
-- X, Y
|
||||
Template.x = Vec3.x
|
||||
Template.y = Vec3.z
|
||||
|
||||
local NewPos = { x = Vec3.x, y = Vec3.z }
|
||||
|
||||
--Template.x = nil
|
||||
--Template.y = nil
|
||||
@@ -2085,11 +2101,13 @@ function GROUP:Respawn( Template, Reset )
|
||||
-- Set heading.
|
||||
Template.units[UnitID].heading = _Heading(self.InitRespawnHeading and self.InitRespawnHeading or GroupUnit:GetHeading())
|
||||
Template.units[UnitID].psi = -Template.units[UnitID].heading
|
||||
|
||||
|
||||
-- Debug.
|
||||
--self:F( { UnitID, Template.units[UnitID], Template.units[UnitID] } )
|
||||
end
|
||||
end
|
||||
|
||||
Template = TransFormRoute(Template,OldPos,NewPos)
|
||||
|
||||
elseif Reset==false then -- Reset=false or nil
|
||||
|
||||
@@ -2128,11 +2146,13 @@ function GROUP:Respawn( Template, Reset )
|
||||
|
||||
-- Heading
|
||||
Template.units[UnitID].heading = self.InitRespawnHeading and self.InitRespawnHeading or TemplateUnitData.heading
|
||||
|
||||
|
||||
-- Debug.
|
||||
--self:F( { UnitID, Template.units[UnitID], Template.units[UnitID] } )
|
||||
end
|
||||
|
||||
|
||||
Template = TransFormRoute(Template,OldPos,NewPos)
|
||||
|
||||
else
|
||||
|
||||
local units=self:GetUnits()
|
||||
@@ -2181,10 +2201,11 @@ function GROUP:Respawn( Template, Reset )
|
||||
-- Destroy old group. Dont trigger any dead/crash events since this is a respawn.
|
||||
self:Destroy(false)
|
||||
|
||||
--self:T({Template=Template})
|
||||
--UTILS.PrintTableToLog(Template)
|
||||
|
||||
-- Spawn new group.
|
||||
_DATABASE:Spawn(Template)
|
||||
self:ScheduleOnce(0.1,_DATABASE.Spawn,_DATABASE,Template)
|
||||
--_DATABASE:Spawn(Template)
|
||||
|
||||
-- Reset events.
|
||||
self:ResetEvents()
|
||||
@@ -2192,6 +2213,29 @@ function GROUP:Respawn( Template, Reset )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Respawn the @{Wrapper.Group} at a @{Core.Point#COORDINATE}.
|
||||
-- The method will setup the new group template according the Init(Respawn) settings provided for the group.
|
||||
-- These settings can be provided by calling the relevant Init...() methods of the Group prior.
|
||||
--
|
||||
-- - @{#GROUP.InitHeading}: Set the heading for the units in degrees within the respawned group.
|
||||
-- - @{#GROUP.InitHeight}: Set the height for the units in meters for the respawned group. (This is applicable for air units).
|
||||
-- - @{#GROUP.InitRandomizeHeading}: Randomize the headings for the units within the respawned group.
|
||||
-- - @{#GROUP.InitRandomizePositionZone}: Randomize the positions of the units of the respawned group within the @{Core.Zone}.
|
||||
-- - @{#GROUP.InitRandomizePositionRadius}: Randomize the positions of the units of the respawned group in a circle band.
|
||||
--
|
||||
-- Notes:
|
||||
--
|
||||
-- - When no coordinate is given, the position of the respawned group will be its current position.
|
||||
-- - The current alive group will always be destroyed first.
|
||||
-- - The new group will have all of its original units and health restored.
|
||||
--
|
||||
-- @param Wrapper.Group#GROUP self
|
||||
-- @param Core.Point#COORDINATE Coordinate Where to respawn the group. Can be handed as a @{Core.Zone#ZONE_BASE} object.
|
||||
-- @return Wrapper.Group#GROUP self
|
||||
function GROUP:Teleport(Coordinate)
|
||||
self:InitZone(Coordinate)
|
||||
return self:Respawn(nil,false)
|
||||
end
|
||||
|
||||
--- Respawn a group at an airbase.
|
||||
-- Note that the group has to be on parking spots at the airbase already in order for this to work.
|
||||
@@ -2333,8 +2377,11 @@ end
|
||||
-- @return #table The mission route defined by points.
|
||||
function GROUP:GetTaskRoute()
|
||||
--self:F2( self.GroupName )
|
||||
|
||||
return UTILS.DeepCopy( _DATABASE.Templates.Groups[self.GroupName].Template.route.points )
|
||||
if _DATABASE.Templates.Groups[self.GroupName].Template and _DATABASE.Templates.Groups[self.GroupName].Template.route and _DATABASE.Templates.Groups[self.GroupName].Template.route.points then
|
||||
return UTILS.DeepCopy( _DATABASE.Templates.Groups[self.GroupName].Template.route.points )
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
--- Return the route of a group by using the global _DATABASE object (an instance of @{Core.Database#DATABASE}).
|
||||
@@ -2926,8 +2973,10 @@ end
|
||||
-- @param #GROUP self
|
||||
-- @param #boolean ShortCallsign Return a shortened customized callsign, i.e. "Ghostrider 9" and not "Ghostrider 9 1"
|
||||
-- @param #boolean Keepnumber (Player only) Return customized callsign, incl optional numbers at the end, e.g. "Aerial 1-1#Ghostrider 109" results in "Ghostrider 109", if you want to e.g. use historical US Navy Callsigns
|
||||
-- @param #table CallsignTranslations Table to translate between DCS standard callsigns and bespoke ones. Overrides personal/parsed callsigns if set
|
||||
-- @param #table CallsignTranslations (Optional) Table to translate between DCS standard callsigns and bespoke ones. Overrides personal/parsed callsigns if set
|
||||
-- callsigns from playername or group name.
|
||||
-- @param #func CustomFunction (Optional) For player names only(!). If given, this function will return the callsign. Needs to take the groupname and the playername as first arguments.
|
||||
-- @param #arg ... (Optional) Comma separated arguments to add to the CustomFunction call after groupname and playername.
|
||||
-- @return #string Callsign
|
||||
-- @usage
|
||||
-- -- suppose there are three groups with one (client) unit each:
|
||||
@@ -2948,8 +2997,12 @@ end
|
||||
-- -- Apollo for Slot 2 or Apollo 403 if Keepnumber is set
|
||||
-- -- Apollo for Slot 3
|
||||
-- -- Bengal-4 for Slot 4
|
||||
|
||||
function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations)
|
||||
--
|
||||
-- -- Using a custom function (for player units **only**):
|
||||
-- -- Imagine your playernames are looking like so: "[Squadname] | Cpt Apple" and you only want to have the last word as callsign, i.e. "Apple" here. Then this custom function will return this:
|
||||
-- local callsign = mygroup:GetCustomCallSign(true,false,nil,function(groupname,playername) return string.match(playername,"([%a]+)$") end)
|
||||
--
|
||||
function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations,CustomFunction,...)
|
||||
--self:I("GetCustomCallSign")
|
||||
|
||||
local callsign = "Ghost 1"
|
||||
@@ -2963,7 +3016,14 @@ function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations)
|
||||
local callnumbermajor = string.char(string.byte(callnumber,1)) -- 9
|
||||
local callnumberminor = string.char(string.byte(callnumber,2)) -- 1
|
||||
local personalized = false
|
||||
|
||||
local playername = IsPlayer == true and self:GetPlayerName() or shortcallsign
|
||||
|
||||
if CustomFunction and IsPlayer then
|
||||
local arguments = arg or {}
|
||||
local callsign = CustomFunction(groupname,playername,unpack(arguments))
|
||||
return callsign
|
||||
end
|
||||
|
||||
-- prioritize bespoke callsigns over parsing, prefer parsing over default callsigns
|
||||
if CallsignTranslations and CallsignTranslations[callsignroot] then
|
||||
callsignroot = CallsignTranslations[callsignroot]
|
||||
@@ -2975,9 +3035,9 @@ function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations)
|
||||
shortcallsign = string.match(groupname,"#%s*([%a]+)") or "Ghost" -- Ghostrider
|
||||
end
|
||||
personalized = true
|
||||
elseif IsPlayer and string.find(self:GetPlayerName(),"|") then
|
||||
elseif IsPlayer and string.find(playername,"|") then
|
||||
-- personalized flight name in group naming
|
||||
shortcallsign = string.match(self:GetPlayerName(),"|%s*([%a]+)") or string.match(self:GetPlayerName(),"|%s*([%d]+)") or "Ghost" -- Ghostrider
|
||||
shortcallsign = string.match(playername,"|%s*([%a]+)") or string.match(self:GetPlayerName(),"|%s*([%d]+)") or "Ghost" -- Ghostrider
|
||||
personalized = true
|
||||
end
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ do
|
||||
-- @field #NET
|
||||
NET = {
|
||||
ClassName = "NET",
|
||||
Version = "0.1.3",
|
||||
Version = "0.1.4",
|
||||
BlockTime = 600,
|
||||
BlockedPilots = {},
|
||||
BlockedUCIDs = {},
|
||||
@@ -67,6 +67,9 @@ function NET:New()
|
||||
self.KnownPilots = {}
|
||||
self:SetBlockMessage()
|
||||
self:SetUnblockMessage()
|
||||
self.BlockedSides = {}
|
||||
self.BlockedSides[1] = false
|
||||
self.BlockedSides[2] = false
|
||||
|
||||
-- Start State.
|
||||
self:SetStartState("Stopped")
|
||||
@@ -160,11 +163,12 @@ end
|
||||
-- @param #string PlayerSlot
|
||||
-- @return #boolean IsBlocked
|
||||
function NET:IsAnyBlocked(UCID,Name,PlayerID,PlayerSide,PlayerSlot)
|
||||
self:T({UCID,Name,PlayerID,PlayerSide,PlayerSlot})
|
||||
local blocked = false
|
||||
local TNow = timer.getTime()
|
||||
-- UCID
|
||||
if UCID and self.BlockedUCIDs[UCID] and TNow < self.BlockedUCIDs[UCID] then
|
||||
return true
|
||||
blocked = true
|
||||
end
|
||||
-- ID/Name
|
||||
if PlayerID and not Name then
|
||||
@@ -172,16 +176,18 @@ function NET:IsAnyBlocked(UCID,Name,PlayerID,PlayerSide,PlayerSlot)
|
||||
end
|
||||
-- Name
|
||||
if Name and self.BlockedPilots[Name] and TNow < self.BlockedPilots[Name] then
|
||||
return true
|
||||
blocked = true
|
||||
end
|
||||
-- Side
|
||||
if PlayerSide and self.BlockedSides[PlayerSide] and TNow < self.BlockedSides[PlayerSide] then
|
||||
return true
|
||||
self:T({time = self.BlockedSides[PlayerSide]})
|
||||
if PlayerSide and type(self.BlockedSides[PlayerSide]) == "number" and TNow < self.BlockedSides[PlayerSide] then
|
||||
blocked = true
|
||||
end
|
||||
-- Slot
|
||||
if PlayerSlot and self.BlockedSlots[PlayerSlot] and TNow < self.BlockedSlots[PlayerSlot] then
|
||||
return true
|
||||
blocked = true
|
||||
end
|
||||
self:T("IsAnyBlocked: "..tostring(blocked))
|
||||
return blocked
|
||||
end
|
||||
|
||||
@@ -200,19 +206,27 @@ function NET:_EventHandler(EventData)
|
||||
local ucid = self:GetPlayerUCID(nil,name) or "none"
|
||||
local PlayerID = self:GetPlayerIDByName(name) or "none"
|
||||
local PlayerSide, PlayerSlot = self:GetSlot(data.IniUnit)
|
||||
if not PlayerSide then PlayerSide = EventData.IniCoalition end
|
||||
if not PlayerSlot then PlayerSlot = EventData.IniUnit:GetID() end
|
||||
local TNow = timer.getTime()
|
||||
|
||||
self:T(self.lid.."Event for: "..name.." | UCID: "..ucid)
|
||||
self:T(self.lid.."Event for: "..name.." | UCID: "..ucid .. " | ID/SIDE/SLOT "..PlayerID.."/"..PlayerSide.."/"..PlayerSlot)
|
||||
|
||||
-- Joining
|
||||
if data.id == EVENTS.PlayerEnterUnit or data.id == EVENTS.PlayerEnterAircraft then
|
||||
self:T(self.lid.."Pilot Joining: "..name.." | UCID: "..ucid.." | Event ID: "..data.id)
|
||||
-- Check for blockages
|
||||
local blocked = self:IsAnyBlocked(ucid,name,PlayerID,PlayerSide,PlayerSlot)
|
||||
|
||||
if blocked and PlayerID and tonumber(PlayerID) ~= 1 then
|
||||
if blocked and PlayerID then -- and tonumber(PlayerID) ~= 1 then
|
||||
self:T("Player blocked")
|
||||
-- block pilot
|
||||
local outcome = net.force_player_slot(tonumber(PlayerID), 0, '' )
|
||||
local outcome = net.force_player_slot(tonumber(PlayerID), PlayerSide, data.IniUnit:GetID() )
|
||||
self:T({Blocked_worked=outcome})
|
||||
if outcome == false then
|
||||
local unit = data.IniUnit
|
||||
local sched = TIMER:New(unit.Destroy,unit,3):Start(3)
|
||||
self:__PlayerBlocked(5,unit,name,1)
|
||||
end
|
||||
else
|
||||
local client = CLIENT:FindByPlayerName(name) or data.IniUnit
|
||||
if not self.KnownPilots[name] or (self.KnownPilots[name] and TNow-self.KnownPilots[name].timestamp > 3) then
|
||||
@@ -225,6 +239,7 @@ function NET:_EventHandler(EventData)
|
||||
slot = PlayerSlot,
|
||||
timestamp = TNow,
|
||||
}
|
||||
--UTILS.PrintTableToLog(self.KnownPilots[name])
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -350,11 +365,10 @@ end
|
||||
|
||||
--- Block a specific coalition side, does NOT automatically kick all players of that side or kick out joined players
|
||||
-- @param #NET self
|
||||
-- @param #number side The side to block - 1 : Red, 2 : Blue
|
||||
-- @param #number Side The side to block - 1 : Red, 2 : Blue
|
||||
-- @param #number Seconds Seconds (optional) Number of seconds the player has to wait before rejoining.
|
||||
-- @return #NET self
|
||||
function NET:BlockSide(Side,Seconds)
|
||||
self:T({Side,Seconds})
|
||||
local addon = Seconds or self.BlockTime
|
||||
if Side == 1 or Side == 2 then
|
||||
self.BlockedSides[Side] = timer.getTime()+addon
|
||||
@@ -367,10 +381,9 @@ end
|
||||
-- @param #number Seconds Seconds (optional) Number of seconds the player has to wait before rejoining.
|
||||
-- @return #NET self
|
||||
function NET:UnblockSide(Side,Seconds)
|
||||
self:T({Side,Seconds})
|
||||
local addon = Seconds or self.BlockTime
|
||||
if Side == 1 or Side == 2 then
|
||||
self.BlockedSides[Side] = nil
|
||||
self.BlockedSides[Side] = false
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -485,8 +498,11 @@ end
|
||||
-- @param Wrapper.Client#CLIENT Client The client
|
||||
-- @return #number PlayerID or nil
|
||||
function NET:GetPlayerIDFromClient(Client)
|
||||
self:T("GetPlayerIDFromClient")
|
||||
self:T({Client=Client})
|
||||
if Client then
|
||||
local name = Client:GetPlayerName()
|
||||
self:T({name=name})
|
||||
local id = self:GetPlayerIDByName(name)
|
||||
return id
|
||||
else
|
||||
@@ -682,16 +698,19 @@ end
|
||||
-- @return #number SideID i.e. 0 : spectators, 1 : Red, 2 : Blue
|
||||
-- @return #number SlotID
|
||||
function NET:GetSlot(Client)
|
||||
self:T("NET.GetSlot")
|
||||
local PlayerID = self:GetPlayerIDFromClient(Client)
|
||||
self:T("NET.GetSlot PlayerID = "..tostring(PlayerID))
|
||||
if PlayerID then
|
||||
local side,slot = net.get_slot(tonumber(PlayerID))
|
||||
self:T("NET.GetSlot side, slot = "..tostring(side)..","..tostring(slot))
|
||||
return side,slot
|
||||
else
|
||||
return nil,nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Force the slot for a specific client.
|
||||
--- Force the slot for a specific client. If this returns false, it didn't work via `net` (which is ALWAYS the case as of Nov 2024)!
|
||||
-- @param #NET self
|
||||
-- @param Wrapper.Client#CLIENT Client The client
|
||||
-- @param #number SideID i.e. 0 : spectators, 1 : Red, 2 : Blue
|
||||
@@ -699,19 +718,22 @@ end
|
||||
-- @return #boolean Success
|
||||
function NET:ForceSlot(Client,SideID,SlotID)
|
||||
local PlayerID = self:GetPlayerIDFromClient(Client)
|
||||
if PlayerID and tonumber(PlayerID) ~= 1 then
|
||||
return net.force_player_slot(tonumber(PlayerID), SideID, SlotID or '' )
|
||||
local SlotID = SlotID or Client:GetID()
|
||||
if PlayerID then -- and tonumber(PlayerID) ~= 1 then
|
||||
return net.force_player_slot(tonumber(PlayerID), SideID, SlotID )
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Force a client back to spectators.
|
||||
--- Force a client back to spectators. If this returns false, it didn't work via `net` (which is ALWAYS the case as of Nov 2024)!
|
||||
-- @param #NET self
|
||||
-- @param Wrapper.Client#CLIENT Client The client
|
||||
-- @return #boolean Succes
|
||||
function NET:ReturnToSpectators(Client)
|
||||
local outcome = self:ForceSlot(Client,0)
|
||||
-- workaround
|
||||
local sched = TIMER:New(Client.Destroy,Client,1):Start(1)
|
||||
return outcome
|
||||
end
|
||||
|
||||
@@ -781,7 +803,7 @@ function NET:onafterStatus(From,Event,To)
|
||||
local function HouseHold(tavolo)
|
||||
local TNow = timer.getTime()
|
||||
for _,entry in pairs (tavolo) do
|
||||
if entry >= TNow then entry = nil end
|
||||
if type(entry) == "number" and entry >= TNow then entry = false end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ function STATIC:Register( StaticName )
|
||||
if DCSStatic then
|
||||
local Life0 = DCSStatic:getLife() or 1
|
||||
self.Life0 = Life0
|
||||
else
|
||||
self:E(string.format("Static object %s does not exist!", tostring(self.StaticName)))
|
||||
end
|
||||
|
||||
return self
|
||||
|
||||
@@ -240,7 +240,9 @@ end
|
||||
-- @return DCS#Unit The DCS Group.
|
||||
function UNIT:GetDCSObject()
|
||||
|
||||
if (not self.LastCallDCSObject) or (self.LastCallDCSObject and timer.getTime() - self.LastCallDCSObject > 1) then
|
||||
-- FF: Added checks that DCSObject exists because otherwise there were problems when respawning the unit right after it was initially spawned (e.g. teleport in OPSGROUP).
|
||||
-- Got "Unit does not exit" after coalition.addGroup() when trying to access unit data because LastCallDCSObject<=1.
|
||||
if (not self.LastCallDCSObject) or (self.LastCallDCSObject and timer.getTime()-self.LastCallDCSObject>1) or (self.DCSObject==nil) or (self.DCSObject:isExist()==false) then
|
||||
|
||||
-- Get DCS group.
|
||||
local DCSUnit = Unit.getByName( self.UnitName )
|
||||
|
||||
@@ -385,24 +385,26 @@ function WEAPON:GetTarget()
|
||||
|
||||
--Target name
|
||||
local name=object:getName()
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Got Target Object %s, category=%d", object:getName(), category))
|
||||
|
||||
if category==Object.Category.UNIT then
|
||||
|
||||
target=UNIT:FindByName(name)
|
||||
|
||||
elseif category==Object.Category.STATIC then
|
||||
|
||||
target=STATIC:FindByName(name, false)
|
||||
|
||||
elseif category==Object.Category.SCENERY then
|
||||
self:E(self.lid..string.format("ERROR: Scenery target not implemented yet!"))
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: Object category=%d is not implemented yet!", category))
|
||||
|
||||
if name then
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Got Target Object %s, category=%d", name, category))
|
||||
|
||||
if category==Object.Category.UNIT then
|
||||
|
||||
target=UNIT:FindByName(name)
|
||||
|
||||
elseif category==Object.Category.STATIC then
|
||||
|
||||
target=STATIC:FindByName(name, false)
|
||||
|
||||
elseif category==Object.Category.SCENERY then
|
||||
self:E(self.lid..string.format("ERROR: Scenery target not implemented yet!"))
|
||||
else
|
||||
self:E(self.lid..string.format("ERROR: Object category=%d is not implemented yet!", category))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user