mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
133 Commits
6c2cc37abe
...
2.9.13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9520782a04 | ||
|
|
f172f6efeb | ||
|
|
b6b6686873 | ||
|
|
5e724e7a3f | ||
|
|
90f1d1df2a | ||
|
|
a5726c0ed8 | ||
|
|
1860366986 | ||
|
|
9db1d38a15 | ||
|
|
04ceda693b | ||
|
|
23ff128ac8 | ||
|
|
3749142670 | ||
|
|
7d3fc1740a | ||
|
|
b2a084d669 | ||
|
|
30203668e4 | ||
|
|
ebecc70693 | ||
|
|
74712b6e27 | ||
|
|
40253ea8bb | ||
|
|
7279da7f09 | ||
|
|
31c40c96f2 | ||
|
|
7a833365ce | ||
|
|
4e56078d2a | ||
|
|
0ac156f2b5 | ||
|
|
4bbf20ca4e | ||
|
|
a462c5a493 | ||
|
|
179cb5f589 | ||
|
|
367014ebf3 | ||
|
|
9d8d0c2155 | ||
|
|
edfe91274d | ||
|
|
326b20b08d | ||
|
|
11b0ce6275 | ||
|
|
03763e16d6 | ||
|
|
c1e8ee12e0 | ||
|
|
ac8cc408c1 | ||
|
|
dad91cca8c | ||
|
|
2f9c384ac0 | ||
|
|
f23a2267cf | ||
|
|
ada38fa3ea | ||
|
|
2ee0597d48 | ||
|
|
b39a83ad6e | ||
|
|
7ae4cdc8f1 | ||
|
|
7d47227fab | ||
|
|
1f09b8fe0b | ||
|
|
8c92a578ed | ||
|
|
992f09d9ba | ||
|
|
096f2caf9c | ||
|
|
0b37c909b3 | ||
|
|
bdad38e707 | ||
|
|
1b18ae1597 | ||
|
|
8dcc3cbe8f | ||
|
|
aa8f3a824c | ||
|
|
b5a19528a1 | ||
|
|
bd20e8fc81 | ||
|
|
2f806801bc | ||
|
|
be006bd2bf | ||
|
|
18a08288ec | ||
|
|
c9ac6d73e6 | ||
|
|
f602455d1f | ||
|
|
d5c34a37b0 | ||
|
|
8a0e9a3400 | ||
|
|
0e836973fd | ||
|
|
1b57af88a0 | ||
|
|
be40d7be9a | ||
|
|
00de8d911c | ||
|
|
9df3fcfdf7 | ||
|
|
d675e34f37 | ||
|
|
2d96ba0f56 | ||
|
|
21c2bd1103 | ||
|
|
f3b7740041 | ||
|
|
7d7488db6f | ||
|
|
b9197d65d5 | ||
|
|
ec6f190b68 | ||
|
|
5e4f9f035b | ||
|
|
7b6bf7f39b | ||
|
|
2e8875dd2f | ||
|
|
4964cc2f2d | ||
|
|
f0a4c5b008 | ||
|
|
1b6412821b | ||
|
|
926a0733e4 | ||
|
|
124ebd3240 | ||
|
|
7728609165 | ||
|
|
da70f4ce6c | ||
|
|
69b3e9abad | ||
|
|
f9f77bfa7b | ||
|
|
429db73854 | ||
|
|
1e9c45c115 | ||
|
|
727cb3276c | ||
|
|
a68175448d | ||
|
|
33e63a4819 | ||
|
|
d7431478d1 | ||
|
|
3543b2c79a | ||
|
|
4489efff94 | ||
|
|
dcdea379ef | ||
|
|
6a4bddde99 | ||
|
|
2088359756 | ||
|
|
dc2511942c | ||
|
|
f0c257c4a5 | ||
|
|
068d21612f | ||
|
|
773461aad9 | ||
|
|
f9257b2b0d | ||
|
|
9e0f03a3cd | ||
|
|
0ab6a10ec4 | ||
|
|
73f393c542 | ||
|
|
a467fabdc8 | ||
|
|
a2ab84c45a | ||
|
|
7ec7228cb8 | ||
|
|
9fd6729967 | ||
|
|
f1d4f1753a | ||
|
|
1f268b3b5d | ||
|
|
6d9c3fd0aa | ||
|
|
28ae63bd8d | ||
|
|
42e7e3f94f | ||
|
|
4a5204aecb | ||
|
|
6466c5e95e | ||
|
|
829f5af25f | ||
|
|
0d1147bac4 | ||
|
|
24b47b02e0 | ||
|
|
10262fd30b | ||
|
|
3cabc07d58 | ||
|
|
b0546b1e60 | ||
|
|
a988e67490 | ||
|
|
fa951838d2 | ||
|
|
2594c5bbf0 | ||
|
|
db70fa341c | ||
|
|
763e3852ac | ||
|
|
66157d0596 | ||
|
|
8ec86973c6 | ||
|
|
eb2c6ac6f2 | ||
|
|
93a8d8bc2d | ||
|
|
cbcc893ce5 | ||
|
|
c19713949d | ||
|
|
54450935a1 | ||
|
|
d0f5712ca8 | ||
|
|
382b049c5f |
@@ -1112,7 +1112,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
||||
self:E("WARNING: Invalid STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||
else
|
||||
self.STNS[stn] = UnitTemplate.name
|
||||
self:I("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||
self:T("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||
end
|
||||
end
|
||||
if UnitTemplate.AddPropAircraft.SADL_TN then
|
||||
@@ -1121,7 +1121,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
||||
self:E("WARNING: Invalid SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||
else
|
||||
self.SADL[sadl] = UnitTemplate.name
|
||||
self:I("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||
self:T("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1382,7 +1382,7 @@ function DATABASE:GetCoalitionFromClientTemplate( ClientName )
|
||||
if self.Templates.ClientsByName[ClientName] then
|
||||
return self.Templates.ClientsByName[ClientName].CoalitionID
|
||||
end
|
||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1394,7 +1394,7 @@ function DATABASE:GetCategoryFromClientTemplate( ClientName )
|
||||
if self.Templates.ClientsByName[ClientName] then
|
||||
return self.Templates.ClientsByName[ClientName].CategoryID
|
||||
end
|
||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1406,7 +1406,7 @@ function DATABASE:GetCountryFromClientTemplate( ClientName )
|
||||
if self.Templates.ClientsByName[ClientName] then
|
||||
return self.Templates.ClientsByName[ClientName].CountryID
|
||||
end
|
||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1699,7 +1699,7 @@ function DATABASE:_EventOnBirth( Event )
|
||||
if PlayerName then
|
||||
|
||||
-- Debug info.
|
||||
self:I(string.format("Player '%s' joined unit '%s' of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniDCSGroupName)))
|
||||
self:I(string.format("Player '%s' joined unit '%s' (%s) of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniTypeName), tostring(Event.IniDCSGroupName)))
|
||||
|
||||
-- Add client in case it does not exist already.
|
||||
if client == nil or (client and client:CountPlayers() == 0) then
|
||||
|
||||
@@ -50,7 +50,7 @@ MARKEROPS_BASE = {
|
||||
ClassName = "MARKEROPS",
|
||||
Tag = "mytag",
|
||||
Keywords = {},
|
||||
version = "0.1.3",
|
||||
version = "0.1.4",
|
||||
debug = false,
|
||||
Casesensitive = true,
|
||||
}
|
||||
@@ -154,14 +154,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
self:E("Skipping onEvent. Event or Event.idx unknown.")
|
||||
return true
|
||||
end
|
||||
--position
|
||||
local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}
|
||||
local coord=COORDINATE:NewFromVec3(vec3)
|
||||
if self.debug then
|
||||
local coordtext = coord:ToStringLLDDM()
|
||||
local text = tostring(Event.text)
|
||||
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||
end
|
||||
|
||||
local coalition = Event.MarkCoalition
|
||||
-- decision
|
||||
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
||||
@@ -170,8 +163,14 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
local Eventtext = tostring(Event.text)
|
||||
if Eventtext~=nil then
|
||||
if self:_MatchTag(Eventtext) then
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z})
|
||||
if self.debug then
|
||||
local coordtext = coord:ToStringLLDDM()
|
||||
local text = tostring(Event.text)
|
||||
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||
end
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
end
|
||||
end
|
||||
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
||||
@@ -180,8 +179,14 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
local Eventtext = tostring(Event.text)
|
||||
if Eventtext~=nil then
|
||||
if self:_MatchTag(Eventtext) then
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z})
|
||||
if self.debug then
|
||||
local coordtext = coord:ToStringLLDDM()
|
||||
local text = tostring(Event.text)
|
||||
local m = MESSAGE:New(string.format("Mark changed at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||
end
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
end
|
||||
end
|
||||
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||
|
||||
@@ -452,7 +452,7 @@ end
|
||||
_MESSAGESRS = {}
|
||||
|
||||
--- Set up MESSAGE generally to allow Text-To-Speech via SRS and TTS functions. `SetMSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible.
|
||||
-- @param #string PathToSRS (optional) Path to SRS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone" or your configuration file setting.
|
||||
-- @param #string PathToSRS (optional) Path to SRS TTS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\ExternalAudio" or your configuration file setting.
|
||||
-- @param #number Port Port (optional) number of SRS, defaults to 5002 or your configuration file setting.
|
||||
-- @param #string PathToCredentials (optional) Path to credentials file for Google.
|
||||
-- @param #number Frequency Frequency in MHz. Can also be given as a #table of frequencies.
|
||||
@@ -468,13 +468,13 @@ _MESSAGESRS = {}
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||
--
|
||||
function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,Gender,Culture,Voice,Coalition,Volume,Label,Coordinate,Backend)
|
||||
|
||||
_MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
_MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
|
||||
_MESSAGESRS.frequency = Frequency or MSRS.frequencies or 243
|
||||
_MESSAGESRS.modulation = Modulation or MSRS.modulations or radio.modulation.AM
|
||||
@@ -535,7 +535,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||
--
|
||||
@@ -567,7 +567,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSBlue()
|
||||
--
|
||||
@@ -589,7 +589,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.RED)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.RED)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSRed()
|
||||
--
|
||||
@@ -611,7 +611,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.NEUTRAL)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.NEUTRAL)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSAll()
|
||||
--
|
||||
|
||||
@@ -837,6 +837,26 @@ do -- COORDINATE
|
||||
return land.getHeight( Vec2 )
|
||||
end
|
||||
|
||||
--- Returns a table of DCS#Vec3 points representing the terrain profile between two points.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Destination DCS#Vec3 Ending point of the profile.
|
||||
-- @return #table DCS#Vec3 table of the profile
|
||||
function COORDINATE:GetLandProfileVec3(Destination)
|
||||
return land.profile(self:GetVec3(), Destination)
|
||||
end
|
||||
|
||||
--- Returns a table of #COORDINATE representing the terrain profile between two points.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Destination #COORDINATE Ending coordinate of the profile.
|
||||
-- @return #table #COORDINATE table of the profile
|
||||
function COORDINATE:GetLandProfileCoordinates(Destination)
|
||||
local points = self:GetLandProfileVec3(Destination:GetVec3())
|
||||
local coords = {}
|
||||
for _, point in ipairs(points) do
|
||||
table.insert(coords, COORDINATE:NewFromVec3(point))
|
||||
end
|
||||
return coords
|
||||
end
|
||||
|
||||
--- Set the heading of the coordinate, if applicable.
|
||||
-- @param #COORDINATE self
|
||||
@@ -3797,7 +3817,26 @@ do -- COORDINATE
|
||||
function COORDINATE:GetRandomPointVec3InRadius( OuterRadius, InnerRadius )
|
||||
return COORDINATE:NewFromVec3( self:GetRandomVec3InRadius( OuterRadius, InnerRadius ) )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Search for clear zones in a given area. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #number SearchRadius Radius of the search area.
|
||||
-- @param #number PosRadius Required clear radius around each position.
|
||||
-- @param #number NumPositions Number of positions to find.
|
||||
-- @return #table A table of Core.Point#COORDINATE that are clear of map objects within the given PosRadius. nil if no positions are found.
|
||||
function COORDINATE:GetSimpleZones(SearchRadius, PosRadius, NumPositions)
|
||||
local clearPositions = UTILS.GetSimpleZones(self:GetVec3(), SearchRadius, PosRadius, NumPositions)
|
||||
if clearPositions and #clearPositions > 0 then
|
||||
local coords = {}
|
||||
for _, pos in pairs(clearPositions) do
|
||||
local coord = COORDINATE:NewFromVec2(pos)
|
||||
table.insert(coords, coord)
|
||||
end
|
||||
return coords
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do
|
||||
|
||||
@@ -175,7 +175,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
local Name = Info.name or "?"
|
||||
|
||||
local ErrorHandler = function( errmsg )
|
||||
env.info( "Error in timer function: " .. errmsg )
|
||||
env.info( "Error in timer function: " .. errmsg or "" )
|
||||
if BASE.Debug ~= nil then
|
||||
env.info( BASE.Debug.traceback() )
|
||||
end
|
||||
@@ -326,7 +326,7 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
||||
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
|
||||
|
||||
-- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing.
|
||||
if Schedule.ScheduleID then
|
||||
if Schedule and Schedule.ScheduleID then
|
||||
|
||||
self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
|
||||
|
||||
|
||||
@@ -958,7 +958,26 @@ do -- SET_BASE
|
||||
|
||||
return ObjectNames
|
||||
end
|
||||
|
||||
--- Get a *new* set table that only contains alive objects.
|
||||
-- @param #SET_BASE self
|
||||
-- @return #table Set table of alive objects.
|
||||
function SET_BASE:GetAliveSet()
|
||||
--self:F2()
|
||||
|
||||
local AliveSet = {}
|
||||
-- Clean the Set before returning with only the alive Objects.
|
||||
for ObjectName, Object in pairs( self.Set ) do
|
||||
if Object then
|
||||
if Object:IsAlive() then
|
||||
AliveSet[#AliveSet+1] = Object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return AliveSet or {}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do
|
||||
@@ -1125,25 +1144,25 @@ do
|
||||
|
||||
end
|
||||
|
||||
--- Get a *new* set that only contains alive groups.
|
||||
--- Get a *new* set table that only contains alive groups.
|
||||
-- @param #SET_GROUP self
|
||||
-- @return #SET_GROUP Set of alive groups.
|
||||
-- @return #table Set of alive groups.
|
||||
function SET_GROUP:GetAliveSet()
|
||||
--self:F2()
|
||||
|
||||
local AliveSet = SET_GROUP:New()
|
||||
|
||||
--local AliveSet = SET_GROUP:New()
|
||||
local AliveSet = {}
|
||||
-- Clean the Set before returning with only the alive Groups.
|
||||
for GroupName, GroupObject in pairs( self.Set ) do
|
||||
local GroupObject = GroupObject -- Wrapper.Group#GROUP
|
||||
if GroupObject then
|
||||
if GroupObject:IsAlive() then
|
||||
AliveSet:Add( GroupName, GroupObject )
|
||||
AliveSet[GroupName] = GroupObject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return AliveSet.Set or {}
|
||||
return AliveSet or {}
|
||||
end
|
||||
|
||||
--- Returns a report of of unit types.
|
||||
@@ -2595,18 +2614,16 @@ do -- SET_UNIT
|
||||
|
||||
--- Gets the alive set.
|
||||
-- @param #SET_UNIT self
|
||||
-- @return #table Table of SET objects
|
||||
-- @return #table Table of alive UNIT objects
|
||||
-- @return #SET_UNIT AliveSet
|
||||
function SET_UNIT:GetAliveSet()
|
||||
|
||||
local AliveSet = SET_UNIT:New()
|
||||
|
||||
-- Clean the Set before returning with only the alive Groups.
|
||||
for GroupName, GroupObject in pairs(self.Set) do
|
||||
local GroupObject=GroupObject --Wrapper.Client#CLIENT
|
||||
|
||||
for GroupName, GroupObject in pairs(self.Set) do
|
||||
if GroupObject and GroupObject:IsAlive() then
|
||||
AliveSet:Add(GroupName, GroupObject)
|
||||
AliveSet[GroupName] = GroupObject
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4784,18 +4801,16 @@ do -- SET_CLIENT
|
||||
-- @return #table Table of SET objects
|
||||
function SET_CLIENT:GetAliveSet()
|
||||
|
||||
local AliveSet = SET_CLIENT:New()
|
||||
local AliveSet = {}
|
||||
|
||||
-- Clean the Set before returning with only the alive Groups.
|
||||
for GroupName, GroupObject in pairs(self.Set) do
|
||||
local GroupObject=GroupObject --Wrapper.Client#CLIENT
|
||||
|
||||
for GroupName, GroupObject in pairs(self.Set) do
|
||||
if GroupObject and GroupObject:IsAlive() then
|
||||
AliveSet:Add(GroupName, GroupObject)
|
||||
AliveSet[GroupName] = GroupObject
|
||||
end
|
||||
end
|
||||
|
||||
return AliveSet.Set or {}
|
||||
return AliveSet or {}
|
||||
end
|
||||
|
||||
--- [User] Add a custom condition function.
|
||||
|
||||
@@ -149,6 +149,7 @@ function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
||||
self.CategoryID = CategoryID
|
||||
self.CoalitionID = CoalitionID
|
||||
self.SpawnIndex = 0
|
||||
self.StaticCopyFrom = SpawnTemplateName
|
||||
else
|
||||
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. tostring(SpawnTemplateName) .. "'" )
|
||||
end
|
||||
@@ -302,12 +303,16 @@ end
|
||||
-- @param #number CallsignID Callsign ID. Default 1 (="London").
|
||||
-- @param #number Frequency Frequency in MHz. Default 127.5 MHz.
|
||||
-- @param #number Modulation Modulation 0=AM, 1=FM.
|
||||
-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns
|
||||
-- @param #boolean DynamicHotStarts If true, and DynamicSpawns is true, then allow Dynamic Spawns with hot starts.
|
||||
-- @return #SPAWNSTATIC self
|
||||
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation)
|
||||
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation, DynamicSpawns,DynamicHotStarts)
|
||||
self.InitFarp=true
|
||||
self.InitFarpCallsignID=CallsignID or 1
|
||||
self.InitFarpFreq=Frequency or 127.5
|
||||
self.InitFarpModu=Modulation or 0
|
||||
self.InitFarpDynamicSpawns = DynamicSpawns
|
||||
self.InitFarpDynamicHotStarts = (DynamicSpawns == true and DynamicHotStarts == true) and true or nil
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -459,8 +464,9 @@ end
|
||||
function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName)
|
||||
|
||||
-- Spawn the new static at the center of the zone.
|
||||
local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
||||
|
||||
--local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
||||
local Static = self:SpawnFromCoordinate(Zone:GetCoordinate(), Heading, NewName)
|
||||
|
||||
return Static
|
||||
end
|
||||
|
||||
@@ -549,6 +555,13 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
TemplateGroup.x=Template.x
|
||||
TemplateGroup.y=Template.y
|
||||
TemplateGroup.name=Template.name
|
||||
|
||||
if self.InitFarpDynamicSpawns == true then
|
||||
TemplateGroup.units[1].dynamicSpawn = true
|
||||
if self.InitFarpDynamicHotStarts == true then
|
||||
TemplateGroup.units[1].allowHotStart = true
|
||||
end
|
||||
end
|
||||
|
||||
self:T("Spawning FARP")
|
||||
self:T({Template=Template})
|
||||
@@ -556,7 +569,8 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
|
||||
-- ED's dirty way to spawn FARPS.
|
||||
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
||||
|
||||
--Static=coalition.addStaticObject(CountryID, Template)
|
||||
|
||||
-- Currently DCS 2.8 does not trigger birth events if FARPS are spawned!
|
||||
-- We create such an event. The airbase is registered in Core.Event
|
||||
local Event = {
|
||||
@@ -594,6 +608,19 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
-- 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))
|
||||
end
|
||||
|
||||
|
||||
if self.StaticCopyFrom ~= nil then
|
||||
mystatic.StaticCopyFrom = self.StaticCopyFrom
|
||||
if not _DATABASE.Templates.Statics[Template.name] then
|
||||
local TemplateGroup={}
|
||||
TemplateGroup.units={}
|
||||
TemplateGroup.units[1]=Template
|
||||
TemplateGroup.x=Template.x
|
||||
TemplateGroup.y=Template.y
|
||||
TemplateGroup.name=Template.name
|
||||
_DATABASE:_RegisterStaticTemplate( TemplateGroup, self.CoalitionID, self.CategoryID, CountryID )
|
||||
end
|
||||
end
|
||||
|
||||
return mystatic
|
||||
end
|
||||
|
||||
@@ -534,6 +534,19 @@ function ZONE_BASE:GetZoneProbability()
|
||||
return self.ZoneProbability
|
||||
end
|
||||
|
||||
--- Get the coordinate on the radius of the zone nearest to Outsidecoordinate. Useto e.g. find an ingress point.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param Core.Point#COORDINATE Outsidecoordinate The coordinate outside of the zone from where to look.
|
||||
-- @return Core.Point#COORDINATE CoordinateOnRadius
|
||||
function ZONE_BASE:FindNearestCoordinateOnRadius(Outsidecoordinate)
|
||||
local Vec1 = self:GetVec2()
|
||||
local Radius = self:GetRadius()
|
||||
local Vec2 = Outsidecoordinate:GetVec2()
|
||||
local Point = UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2)
|
||||
local rc = COORDINATE:NewFromVec2(Point)
|
||||
return rc
|
||||
end
|
||||
|
||||
--- Get the zone taking into account the randomization probability of a zone to be selected.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return #ZONE_BASE The zone is selected taking into account the randomization probability factor.
|
||||
@@ -1509,6 +1522,26 @@ function ZONE_RADIUS:IsVec3InZone( Vec3 )
|
||||
return InZone
|
||||
end
|
||||
|
||||
--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number PosRadius Required clear radius around each position.
|
||||
-- @param #number NumPositions Number of positions to find.
|
||||
-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found.
|
||||
function ZONE_RADIUS:GetClearZonePositions(PosRadius, NumPositions)
|
||||
return UTILS.GetClearZonePositions(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
|
||||
--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200))
|
||||
-- @param #number NumPositions (Optional) Number of positions to find. (Default 50)
|
||||
-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found.
|
||||
-- @return #number Assigned radius for the found zones. nil if no clear positions are found.
|
||||
function ZONE_RADIUS:GetRandomClearZoneCoordinate(PosRadius, NumPositions)
|
||||
return UTILS.GetRandomClearZoneCoordinate(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
--- Returns a random Vec2 location within the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
||||
@@ -2487,6 +2520,26 @@ function ZONE_POLYGON_BASE:Flush()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @param #number PosRadius Required clear radius around each position.
|
||||
-- @param #number NumPositions Number of positions to find.
|
||||
-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found.
|
||||
function ZONE_POLYGON_BASE:GetClearZonePositions(PosRadius, NumPositions)
|
||||
return UTILS.GetClearZonePositions(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
|
||||
--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200))
|
||||
-- @param #number NumPositions (Optional) Number of positions to find. (Default 50)
|
||||
-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found.
|
||||
-- @return #number Assigned radius for the found zones. nil if no clear positions are found.
|
||||
function ZONE_POLYGON_BASE:GetRandomClearZoneCoordinate(PosRadius, NumPositions)
|
||||
return UTILS.GetRandomClearZoneCoordinate(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
--- Smokes the zone boundaries in a color.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @param #boolean UnBound If true, the tyres will be destroyed.
|
||||
@@ -3204,12 +3257,7 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
||||
|
||||
local vectors = self:GetBoundingSquare()
|
||||
|
||||
local minVec3 = {x=vectors.x1, y=0, z=vectors.y1}
|
||||
local maxVec3 = {x=vectors.x2, y=0, z=vectors.y2}
|
||||
|
||||
local minmarkcoord = COORDINATE:NewFromVec3(minVec3)
|
||||
local maxmarkcoord = COORDINATE:NewFromVec3(maxVec3)
|
||||
local ZoneRadius = minmarkcoord:Get2DDistance(maxmarkcoord)/2
|
||||
local ZoneRadius = UTILS.VecDist2D({x=vectors.x1, y=vectors.y1}, {x=vectors.x2, y=vectors.y2})/2
|
||||
-- self:I("Scan Radius:" ..ZoneRadius)
|
||||
local CenterVec3 = self:GetCoordinate():GetVec3()
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Applevangelist**
|
||||
-- Last Update Sept 2023
|
||||
-- Last Update July 2025
|
||||
--
|
||||
-- ===
|
||||
-- @module Functional.AICSAR
|
||||
@@ -57,6 +57,8 @@
|
||||
-- @field #number Speed Default speed setting for the helicopter FLIGHTGROUP is 100kn.
|
||||
-- @field #boolean UseEventEject In case Event LandingAfterEjection isn't working, use set this to true.
|
||||
-- @field #number Delay In case of UseEventEject wait this long until we spawn a landed pilot.
|
||||
-- @field #boolean UseRescueZone If true, use a rescue zone and not the max distance to FARP/MASH
|
||||
-- @field Core.Zone#ZONE_RADIUS RescueZone Use this zone as operational area for the AICSAR instance.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
@@ -153,10 +155,10 @@
|
||||
-- To set up AICSAR for SRS TTS output, add e.g. the following to your script:
|
||||
--
|
||||
-- -- setup for google TTS, radio 243 AM, SRS server port 5002 with a google standard-quality voice (google cloud account required)
|
||||
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",243,radio.modulation.AM,5002,MSRS.Voices.Google.Standard.en_US_Standard_D,"en-US","female","C:\\Program Files\\DCS-SimpleRadio-Standalone\\google.json")
|
||||
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",243,radio.modulation.AM,5002,MSRS.Voices.Google.Standard.en_US_Standard_D,"en-US","female","C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\google.json")
|
||||
--
|
||||
-- -- alternatively for MS Desktop TTS (voices need to be installed locally first!)
|
||||
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",243,radio.modulation.AM,5002,MSRS.Voices.Microsoft.Hazel,"en-GB","female")
|
||||
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",243,radio.modulation.AM,5002,MSRS.Voices.Microsoft.Hazel,"en-GB","female")
|
||||
--
|
||||
-- -- define a different voice for the downed pilot(s)
|
||||
-- my_aicsar:SetPilotTTSVoice(MSRS.Voices.Google.Standard.en_AU_Standard_D,"en-AU","male")
|
||||
@@ -177,7 +179,7 @@
|
||||
--
|
||||
-- Switch on radio transmissions via **either** SRS **or** "normal" DCS radio e.g. like so:
|
||||
--
|
||||
-- my_aicsar:SetSRSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",270,radio.modulation.AM,nil,5002)
|
||||
-- my_aicsar:SetSRSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",270,radio.modulation.AM,nil,5002)
|
||||
--
|
||||
-- or
|
||||
--
|
||||
@@ -191,7 +193,7 @@
|
||||
-- @field #AICSAR
|
||||
AICSAR = {
|
||||
ClassName = "AICSAR",
|
||||
version = "0.1.16",
|
||||
version = "0.1.18",
|
||||
lid = "",
|
||||
coalition = coalition.side.BLUE,
|
||||
template = "",
|
||||
@@ -236,6 +238,8 @@ AICSAR = {
|
||||
Altitude = 1500,
|
||||
UseEventEject = false,
|
||||
Delay = 100,
|
||||
UseRescueZone = false,
|
||||
RescueZone = nil,
|
||||
}
|
||||
|
||||
-- TODO Messages
|
||||
@@ -304,8 +308,9 @@ AICSAR.RadioLength = {
|
||||
-- @param #string Helotemplate Helicopter template name.
|
||||
-- @param Wrapper.Airbase#AIRBASE FARP FARP object or Airbase from where to start.
|
||||
-- @param Core.Zone#ZONE MASHZone Zone where to drop pilots after rescue.
|
||||
-- @param #number Helonumber Max number of alive Ai Helos at the same time. Defaults to three.
|
||||
-- @return #AICSAR self
|
||||
function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone)
|
||||
function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone,Helonumber)
|
||||
-- Inherit everything from FSM class.
|
||||
local self=BASE:Inherit(self, FSM:New())
|
||||
|
||||
@@ -373,7 +378,7 @@ function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone)
|
||||
|
||||
-- limit number of available helos at the same time
|
||||
self.limithelos = true
|
||||
self.helonumber = 3
|
||||
self.helonumber = Helonumber or 3
|
||||
|
||||
-- localization
|
||||
self:InitLocalization()
|
||||
@@ -524,10 +529,20 @@ function AICSAR:InitLocalization()
|
||||
return self
|
||||
end
|
||||
|
||||
--- [User] Use a defined zone as area of operation and not the distance to FARP.
|
||||
-- @param #AICSAR self
|
||||
-- @param Core.Zone#ZONE Zone The operational zone to use. Downed pilots in this area will be rescued. Can be any known #ZONE type.
|
||||
-- @return #AICSAR self
|
||||
function AICSAR:SetUsingRescueZone(Zone)
|
||||
self.UseRescueZone = true
|
||||
self.RescueZone = Zone
|
||||
return self
|
||||
end
|
||||
|
||||
--- [User] Switch sound output on and use SRS output for sound files.
|
||||
-- @param #AICSAR self
|
||||
-- @param #boolean OnOff Switch on (true) or off (false).
|
||||
-- @param #string Path Path to your SRS Server Component, e.g. "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone"
|
||||
-- @param #string Path Path to your SRS Server External Audio Component, e.g. "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\\\ExternalAudio"
|
||||
-- @param #number Frequency Defaults to 243 (guard)
|
||||
-- @param #number Modulation Radio modulation. Defaults to radio.modulation.AM
|
||||
-- @param #string SoundPath Where to find the audio files. Defaults to nil, i.e. add messages via "Sound to..." in the Mission Editor.
|
||||
@@ -538,7 +553,7 @@ function AICSAR:SetSRSRadio(OnOff,Path,Frequency,Modulation,SoundPath,Port)
|
||||
self.SRSRadio = OnOff and true
|
||||
self.SRSTTSRadio = false
|
||||
self.SRSFrequency = Frequency or 243
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
self.SRS:SetLabel("ACSR")
|
||||
self.SRS:SetCoalition(self.coalition)
|
||||
self.SRSModulation = Modulation or radio.modulation.AM
|
||||
@@ -556,7 +571,7 @@ end
|
||||
-- See `AICSAR:SetPilotTTSVoice()` and `AICSAR:SetOperatorTTSVoice()`
|
||||
-- @param #AICSAR self
|
||||
-- @param #boolean OnOff Switch on (true) or off (false).
|
||||
-- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone"
|
||||
-- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
-- @param #number Frequency (Optional) Defaults to 243 (guard)
|
||||
-- @param #number Modulation (Optional) Radio modulation. Defaults to radio.modulation.AM
|
||||
-- @param #number Port (Optional) Port of the SRS, defaults to 5002.
|
||||
@@ -570,7 +585,7 @@ function AICSAR:SetSRSTTSRadio(OnOff,Path,Frequency,Modulation,Port,Voice,Cultur
|
||||
self.SRSTTSRadio = OnOff and true
|
||||
self.SRSRadio = false
|
||||
self.SRSFrequency = Frequency or 243
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
self.SRSModulation = Modulation or radio.modulation.AM
|
||||
self.SRSPort = Port or MSRS.port or 5002
|
||||
if OnOff then
|
||||
@@ -693,7 +708,7 @@ function AICSAR:_EjectEventHandler(EventData)
|
||||
local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p)
|
||||
local _country = _event.initiator:getCountry()
|
||||
local _coalition = coalition.getCountryCoalition( _country )
|
||||
local data = UTILS.DeepCopy(EventData)
|
||||
--local data = UTILS.DeepCopy(EventData)
|
||||
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
|
||||
self:ScheduleOnce(self.Delay,self._DelayedSpawnPilot,self,_LandingPos,_coalition)
|
||||
end
|
||||
@@ -708,7 +723,14 @@ end
|
||||
-- @return #AICSAR self
|
||||
function AICSAR:_DelayedSpawnPilot(_LandingPos,_coalition)
|
||||
|
||||
local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate())
|
||||
local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate())
|
||||
if self.UseRescueZone == true and self.RescueZone ~= nil then
|
||||
if self.RescueZone:IsCoordinateInZone(_LandingPos) then
|
||||
distancetofarp = self.maxdistance - 10
|
||||
else
|
||||
distancetofarp = self.maxdistance + 10
|
||||
end
|
||||
end
|
||||
-- Mayday Message
|
||||
local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale)
|
||||
local text = ""
|
||||
@@ -795,7 +817,13 @@ function AICSAR:_EventHandler(EventData, FromEject)
|
||||
|
||||
-- DONE: add distance check
|
||||
local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate())
|
||||
|
||||
if self.UseRescueZone == true and self.RescueZone ~= nil then
|
||||
if self.RescueZone:IsCoordinateInZone(_LandingPos) then
|
||||
distancetofarp = self.maxdistance - 10
|
||||
else
|
||||
distancetofarp = self.maxdistance + 10
|
||||
end
|
||||
end
|
||||
-- Mayday Message
|
||||
local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale)
|
||||
local text = ""
|
||||
@@ -817,7 +845,6 @@ function AICSAR:_EventHandler(EventData, FromEject)
|
||||
if _coalition == self.coalition then
|
||||
if self.verbose then
|
||||
MESSAGE:New(msgtxt,15,"AICSAR"):ToCoalition(self.coalition)
|
||||
-- MESSAGE:New(msgtxt,15,"AICSAR"):ToLog()
|
||||
end
|
||||
if self.SRSRadio then
|
||||
local sound = SOUNDFILE:New(Soundfile,self.SRSSoundPath,Soundlength)
|
||||
@@ -869,6 +896,7 @@ function AICSAR:_GetFlight()
|
||||
:InitUnControlled(true)
|
||||
:OnSpawnGroup(
|
||||
function(Group)
|
||||
Group:OptionPreferVerticalLanding()
|
||||
self:__HeloOnDuty(1,Group)
|
||||
end
|
||||
)
|
||||
@@ -892,7 +920,7 @@ function AICSAR:_InitMission(Pilot,Index)
|
||||
--local pilotset = SET_GROUP:New()
|
||||
--pilotset:AddGroup(Pilot)
|
||||
|
||||
-- Cargo transport assignment.
|
||||
-- Cargo transport assignment.
|
||||
local opstransport=OPSTRANSPORT:New(Pilot, pickupzone, self.farpzone)
|
||||
--opstransport:SetVerbosity(3)
|
||||
|
||||
@@ -934,6 +962,10 @@ function AICSAR:_InitMission(Pilot,Index)
|
||||
helo:__UnloadingDone(5)
|
||||
end
|
||||
|
||||
function helo:OnAfterLandAtAirbase(From,Event,To,airbase)
|
||||
helo:Despawn(2)
|
||||
end
|
||||
|
||||
self.helos[Index] = helo
|
||||
|
||||
return self
|
||||
@@ -984,7 +1016,9 @@ function AICSAR:_CheckHelos()
|
||||
local name = helo:GetName()
|
||||
self:T("Helo group "..name.." in state "..state)
|
||||
if state == "Arrived" then
|
||||
helo:__Stop(5)
|
||||
--helo:__Stop(5)
|
||||
helo.OnAfterDead = nil
|
||||
helo:Despawn(35)
|
||||
self.helos[_index] = nil
|
||||
end
|
||||
else
|
||||
@@ -1025,7 +1059,7 @@ function AICSAR:_CheckQueue(OpsGroup)
|
||||
if self:_CheckInMashZone(_pilot) then
|
||||
self:T("Pilot" .. _pilot.GroupName .. " rescued!")
|
||||
if OpsGroup then
|
||||
OpsGroup:Despawn(10)
|
||||
--OpsGroup:Despawn(10)
|
||||
else
|
||||
_pilot:Destroy(true,10)
|
||||
end
|
||||
|
||||
@@ -105,7 +105,7 @@ AUTOLASE = {
|
||||
debug = false,
|
||||
smokemenu = true,
|
||||
RoundingPrecision = 0,
|
||||
increasegroundawareness = true,
|
||||
increasegroundawareness = false,
|
||||
MonitorFrequency = 30,
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ function AUTOLASE:New(RecceSet, Coalition, Alias, PilotSet)
|
||||
self.smokemenu = true
|
||||
self.threatmenu = true
|
||||
self.RoundingPrecision = 0
|
||||
self.increasegroundawareness = true
|
||||
self.increasegroundawareness = false
|
||||
self.MonitorFrequency = 30
|
||||
|
||||
self:EnableSmokeMenu({Angle=math.random(0,359),Distance=math.random(10,20)})
|
||||
@@ -493,7 +493,7 @@ end
|
||||
--- (User) Function enable sending messages via SRS.
|
||||
-- @param #AUTOLASE self
|
||||
-- @param #boolean OnOff Switch usage on and off
|
||||
-- @param #string Path Path to SRS directory, e.g. C:\\Program Files\\DCS-SimpleRadio-Standalone
|
||||
-- @param #string Path Path to SRS TTS directory, e.g. C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio
|
||||
-- @param #number Frequency Frequency to send, e.g. 243
|
||||
-- @param #number Modulation Modulation i.e. radio.modulation.AM or radio.modulation.FM
|
||||
-- @param #string Label (Optional) Short label to be used on the SRS Client Overlay
|
||||
@@ -508,7 +508,7 @@ end
|
||||
function AUTOLASE:SetUsingSRS(OnOff,Path,Frequency,Modulation,Label,Gender,Culture,Port,Voice,Volume,PathToGoogleKey)
|
||||
if OnOff then
|
||||
self.useSRS = true
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
self.SRSFreq = Frequency or 271
|
||||
self.SRSMod = Modulation or radio.modulation.AM
|
||||
self.Gender = Gender or MSRS.gender or "male"
|
||||
@@ -1020,7 +1020,7 @@ function AUTOLASE:_Prescient()
|
||||
self:T(self.lid.."Checking possibly visible STATICs for Recce "..unit:GetName())
|
||||
for _,_static in pairs(Statics) do -- DCS static object here
|
||||
local static = STATIC:Find(_static)
|
||||
if static and static:GetCoalition() ~= self.coalition then
|
||||
if static and static:GetCoalition() ~= self.coalition and static:GetCoordinate() then
|
||||
local IsLOS = position:IsLOS(static:GetCoordinate())
|
||||
if IsLOS then
|
||||
unit:KnowUnit(static,true,true)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
-- @module Functional.Mantis
|
||||
-- @image Functional.Mantis.jpg
|
||||
--
|
||||
-- Last Update: May 2025
|
||||
-- Last Update: July 2025
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **MANTIS** class, extends Core.Base#BASE
|
||||
@@ -111,7 +111,7 @@
|
||||
-- * Silkworm (though strictly speaking this is a surface to ship missile)
|
||||
-- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19
|
||||
-- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!)
|
||||
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2
|
||||
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2, SAMP/T Block 1, SAMP/T Block 1INT, SAMP/T Block2
|
||||
--
|
||||
-- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M
|
||||
-- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA"
|
||||
@@ -125,10 +125,11 @@
|
||||
-- * SA-2 (with V759 missile, e.g. "Red SAM SA-2 HDS")
|
||||
-- * SA-2 (with HQ-2 launcher, use HQ-2 in the group name, e.g. "Red SAM HQ-2" )
|
||||
-- * SA-3 (with V601P missile, e.g. "Red SAM SA-3 HDS")
|
||||
-- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS")
|
||||
-- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS")
|
||||
-- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS")
|
||||
-- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS")
|
||||
-- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS" with 5P85CE launcher)
|
||||
-- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS" with 5P85SE launcher)
|
||||
-- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS 2" for the 9A82 variant and "Red SAM SA-12 HDS 1" for the 9A83 variant)
|
||||
-- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS 2" for the 9A82ME variant and "Red SAM SA-23 HDS 1" for the 9A83ME variant)
|
||||
-- * SAMP/T (launcher dependent range, e.g. "Blue SAM SAMPT Block 1 HDS" for Block 1, "Blue SAM SAMPT Block 1INT HDS", "Blue SAM SAMPT Block 2 HDS")
|
||||
--
|
||||
-- The other HDS types work like the rest of the known SAM systems.
|
||||
--
|
||||
@@ -274,6 +275,7 @@
|
||||
MANTIS = {
|
||||
ClassName = "MANTIS",
|
||||
name = "mymantis",
|
||||
version = "0.9.32",
|
||||
SAM_Templates_Prefix = "",
|
||||
SAM_Group = nil,
|
||||
EWR_Templates_Prefix = "",
|
||||
@@ -385,7 +387,7 @@ MANTIS.SamData = {
|
||||
["HEMTT_C-RAM_Phalanx"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" },
|
||||
-- units from HDS Mod, multi launcher options is tricky
|
||||
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"},
|
||||
["SA-17"] = { Range=50, Blindspot=3, Height=30, Type="Medium", Radar="SA-17" },
|
||||
["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17" },
|
||||
["SA-20A"] = { Range=150, Blindspot=5, Height=27, Type="Long" , Radar="S-300PMU1"},
|
||||
["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"},
|
||||
["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
||||
@@ -406,13 +408,17 @@ MANTIS.SamDataHDS = {
|
||||
-- group name MUST contain HDS to ID launcher type correctly!
|
||||
["SA-2 HDS"] = { Range=56, Blindspot=7, Height=30, Type="Medium", Radar="V759" },
|
||||
["SA-3 HDS"] = { Range=20, Blindspot=6, Height=30, Type="Short", Radar="V-601P" },
|
||||
["SA-10C HDS 2"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85DE ln"}, -- V55RUD
|
||||
["SA-10C HDS 1"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD
|
||||
["SA-12 HDS 2"] = { Range=100, Blindspot=10, Height=25, Type="Long" , Radar="S-300V 9A82 l"},
|
||||
["SA-12 HDS 1"] = { Range=75, Blindspot=1, Height=25, Type="Long" , Radar="S-300V 9A83 l"},
|
||||
["SA-10B HDS"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD
|
||||
["SA-10C HDS"] = { Range=75, Blindspot=5, Height=25, Type="Long" , Radar="5P85SE ln"}, -- V55RUD
|
||||
["SA-17 HDS"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17 " },
|
||||
["SA-12 HDS 2"] = { Range=100, Blindspot=13, Height=30, Type="Long" , Radar="S-300V 9A82 l"},
|
||||
["SA-12 HDS 1"] = { Range=75, Blindspot=6, Height=25, Type="Long" , Radar="S-300V 9A83 l"},
|
||||
["SA-23 HDS 2"] = { Range=200, Blindspot=5, Height=37, Type="Long", Radar="S-300VM 9A82ME" },
|
||||
["SA-23 HDS 1"] = { Range=100, Blindspot=1, Height=50, Type="Long", Radar="S-300VM 9A83ME" },
|
||||
["HQ-2 HDS"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
||||
["SAMPT Block 1 HDS"] = { Range=120, Blindspot=1, Height=20, Type="long", Radar="SAMPT_MLT_Blk1" }, -- Block 1 Launcher
|
||||
["SAMPT Block 1INT HDS"] = { Range=150, Blindspot=1, Height=25, Type="long", Radar="SAMPT_MLT_Blk1NT" }, -- Block 1-INT Launcher
|
||||
["SAMPT Block 2 HDS"] = { Range=200, Blindspot=10, Height=70, Type="long", Radar="SAMPT_MLT_Blk2" }, -- Block 2 Launcher
|
||||
}
|
||||
|
||||
--- SAM data SMA
|
||||
@@ -680,9 +686,6 @@ do
|
||||
-- counter for SAM table updates
|
||||
self.checkcounter = 1
|
||||
|
||||
-- TODO Version
|
||||
-- @field #string version
|
||||
self.version="0.9.30"
|
||||
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||
|
||||
--- FSM Functions ---
|
||||
@@ -1798,7 +1801,7 @@ do
|
||||
if self.Shorad and self.Shorad.ActiveGroups and self.Shorad.ActiveGroups[name] then
|
||||
activeshorad = true
|
||||
end
|
||||
if IsInZone and not suppressed and not activeshorad then --check any target in zone and not currently managed by SEAD
|
||||
if IsInZone and (not suppressed) and (not activeshorad) then --check any target in zone and not currently managed by SEAD
|
||||
if samgroup:IsAlive() then
|
||||
-- switch on SAM
|
||||
local switch = false
|
||||
@@ -1830,7 +1833,7 @@ do
|
||||
-- link in to SHORAD if available
|
||||
-- DONE: Test integration fully
|
||||
if self.ShoradLink and (Distance < self.ShoradActDistance or Distance < blind ) then -- don't give SHORAD position away too early
|
||||
local Shorad = self.Shorad
|
||||
local Shorad = self.Shorad --Functional.Shorad#SHORAD
|
||||
local radius = self.checkradius
|
||||
local ontime = self.ShoradTime
|
||||
Shorad:WakeUpShorad(name, radius, ontime)
|
||||
@@ -2110,7 +2113,7 @@ do
|
||||
if self.debug and self.verbose then
|
||||
self:I(self.lid .. "Status Report")
|
||||
for _name,_state in pairs(self.SamStateTracker) do
|
||||
self:I(string.format("Site %s\tStatus %s",_name,_state))
|
||||
self:I(string.format("Site %s | Status %s",_name,_state))
|
||||
end
|
||||
end
|
||||
local interval = self.detectinterval * -1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3153,7 +3153,7 @@ end
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return Core.Point#COORDINATE The coordinate of the warehouse.
|
||||
function WAREHOUSE:GetCoordinate()
|
||||
return self.warehouse:GetCoordinate()
|
||||
return self.warehouse:GetCoord()
|
||||
end
|
||||
|
||||
--- Get 3D vector of warehouse static.
|
||||
@@ -6893,7 +6893,7 @@ function WAREHOUSE:_CheckConquered()
|
||||
for _,_unit in pairs(units) do
|
||||
local unit=_unit --Wrapper.Unit#UNIT
|
||||
|
||||
local distance=coord:Get2DDistance(unit:GetCoordinate())
|
||||
local distance=coord:Get2DDistance(unit:GetCoord())
|
||||
|
||||
-- Filter only alive groud units. Also check distance again, because the scan routine might give some larger distances.
|
||||
if unit:IsGround() and unit:IsAlive() and distance <= radius then
|
||||
|
||||
@@ -115,7 +115,6 @@ __Moose.Include( 'Ops\\Operation.lua' )
|
||||
__Moose.Include( 'Ops\\FlightControl.lua' )
|
||||
__Moose.Include( 'Ops\\PlayerRecce.lua' )
|
||||
__Moose.Include( 'Ops\\EasyGCICAP.lua' )
|
||||
__Moose.Include( 'Ops\\EasyA2G.lua' )
|
||||
|
||||
__Moose.Include( 'AI\\AI_Balancer.lua' )
|
||||
__Moose.Include( 'AI\\AI_Air.lua' )
|
||||
|
||||
@@ -974,6 +974,46 @@ function AIRWING:SetTakeoffAir()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft of the AirWing to land straight in.
|
||||
-- @param #AIRWING self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function AIRWING:SetLandingStraightIn()
|
||||
self.OptionLandingStraightIn = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft of the AirWing to land in pairs for groups > 1 aircraft.
|
||||
-- @param #AIRWING self
|
||||
-- @return #AIRWING self
|
||||
function AIRWING:SetLandingForcePair()
|
||||
self.OptionLandingForcePair = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft of the AirWing to NOT land in pairs.
|
||||
-- @param #AIRWING self
|
||||
-- @return #AIRWING self
|
||||
function AIRWING:SetLandingRestrictPair()
|
||||
self.OptionLandingRestrictPair = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft of the AirWing to land after overhead break.
|
||||
-- @param #AIRWING self
|
||||
-- @return #AIRWING self
|
||||
function AIRWING:SetLandingOverheadBreak()
|
||||
self.OptionLandingOverheadBreak = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Helicopter] Set the aircraft of the AirWing to prefer vertical takeoff and landing.
|
||||
-- @param #AIRWING self
|
||||
-- @return #AIRWING self
|
||||
function AIRWING:SetOptionPreferVerticalLanding()
|
||||
self.OptionPreferVerticalLanding = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set despawn after landing. Aircraft will be despawned after the landing event.
|
||||
-- Can help to avoid DCS AI taxiing issues.
|
||||
-- @param #AIRWING self
|
||||
@@ -1464,7 +1504,21 @@ function AIRWING:onafterFlightOnMission(From, Event, To, FlightGroup, Mission)
|
||||
self:T(self.lid..string.format("Group %s on %s mission %s", FlightGroup:GetName(), Mission:GetType(), Mission:GetName()))
|
||||
if self.UseConnectedOpsAwacs and self.ConnectedOpsAwacs then
|
||||
self.ConnectedOpsAwacs:__FlightOnMission(2,FlightGroup,Mission)
|
||||
end
|
||||
end
|
||||
-- Landing Options
|
||||
if self.OptionLandingForcePair then
|
||||
FlightGroup:SetOptionLandingForcePair()
|
||||
elseif self.OptionLandingOverheadBreak then
|
||||
FlightGroup:SetOptionLandingOverheadBreak()
|
||||
elseif self.OptionLandingRestrictPair then
|
||||
FlightGroup:SetOptionLandingRestrictPair()
|
||||
elseif self.OptionLandingStraightIn then
|
||||
FlightGroup:SetOptionLandingStraightIn()
|
||||
end
|
||||
-- Landing Options Helo
|
||||
if self.OptionPreferVerticalLanding then
|
||||
FlightGroup:SetOptionPreferVertical()
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -397,6 +397,7 @@ AUFTRAG = {
|
||||
conditionPush = {},
|
||||
conditionSuccessSet = false,
|
||||
conditionFailureSet = false,
|
||||
repeatDelay = 1,
|
||||
}
|
||||
|
||||
--- Global mission counter.
|
||||
@@ -1403,8 +1404,6 @@ function AUFTRAG:NewINTERCEPT(Target)
|
||||
end
|
||||
|
||||
--- **[AIR]** Create a CAP mission.
|
||||
-- Assinged groups are tasked to execute a CAP mission. This consists of a DCS orbit task combined with an enroute "search and engage in zone" task.
|
||||
-- **Note** that currently DCS only supports *circular* zones for the task.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Zone#ZONE_RADIUS ZoneCAP Circular CAP zone. Detected targets in this zone will be engaged.
|
||||
-- @param #number Altitude Altitude at which to orbit in feet. Default is 10,000 ft.
|
||||
@@ -1430,7 +1429,7 @@ function AUFTRAG:NewCAP(ZoneCAP, Altitude, Speed, Coordinate, Heading, Leg, Targ
|
||||
mission:_SetLogID()
|
||||
|
||||
-- DCS task parameters:
|
||||
mission.engageZone=ZoneCAP
|
||||
mission.engageZone=ZoneCAP or Coordinate
|
||||
mission.engageTargetTypes=TargetTypes or {"Air"}
|
||||
|
||||
-- Mission options:
|
||||
@@ -1717,6 +1716,42 @@ function AUFTRAG:NewSEAD(Target, Altitude)
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[AIR]** Create a SEAD in Zone mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Zone#ZONE TargetZone The target zone to attack.
|
||||
-- @param #number Altitude Engage altitude in feet. Default 25000 ft.
|
||||
-- @param #table TargetTypes Table of string of DCS known target types, defaults to {"Air Defence"}. See [DCS Target Attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes)
|
||||
-- @param #number Duration Engage this much time when the AUFTRAG starts executing.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewSEADInZone(TargetZone, Altitude, TargetTypes, Duration)
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.SEAD)
|
||||
|
||||
mission:_TargetFromObject(TargetZone)
|
||||
|
||||
-- DCS Task options:
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
||||
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
|
||||
mission.engageZone = TargetZone
|
||||
mission.engageTargetTypes = TargetTypes or {"Air Defence"}
|
||||
|
||||
-- Mission options:
|
||||
mission.missionTask=ENUMS.MissionTask.SEAD
|
||||
mission.missionAltitude=mission.engageAltitude
|
||||
mission.missionFraction=0.2
|
||||
mission.optionROE=ENUMS.ROE.OpenFire
|
||||
mission.optionROT=ENUMS.ROT.EvadeFire
|
||||
|
||||
mission.categories={AUFTRAG.Category.AIRCRAFT}
|
||||
|
||||
mission.DCStask=mission:GetDCSMissionTask()
|
||||
|
||||
mission:SetDuration(Duration or 1800)
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[AIR]** Create a STRIKE mission. Flight will attack the closest map object to the specified coordinate.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object.
|
||||
@@ -1754,8 +1789,9 @@ end
|
||||
-- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object.
|
||||
-- @param #number Altitude Engage altitude in feet. Default 25000 ft.
|
||||
-- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options.
|
||||
-- @param #boolean Divebomb If true, use a dive bombing attack approach.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewBOMBING(Target, Altitude, EngageWeaponType)
|
||||
function AUFTRAG:NewBOMBING(Target, Altitude, EngageWeaponType, Divebomb)
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.BOMBING)
|
||||
|
||||
@@ -1772,6 +1808,7 @@ function AUFTRAG:NewBOMBING(Target, Altitude, EngageWeaponType)
|
||||
mission.missionFraction=0.5
|
||||
mission.optionROE=ENUMS.ROE.OpenFire
|
||||
mission.optionROT=ENUMS.ROT.NoReaction -- No reaction is better.
|
||||
mission.optionDivebomb = Divebomb or nil
|
||||
|
||||
-- Evaluate result after 5 min. We might need time until the bombs have dropped and targets have been detroyed.
|
||||
mission.dTevaluate=5*60
|
||||
@@ -2968,6 +3005,16 @@ function AUFTRAG:SetRepeat(Nrepeat)
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- **[LEGION, COMMANDER, CHIEF]** Set the repeat delay in seconds after a mission is successful/failed. Only valid if the mission is handled by a LEGION (AIRWING, BRIGADE, FLEET) or higher level.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number Nrepeat Repeat delay in seconds. Default 1.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:SetRepeatDelay(RepeatDelay)
|
||||
self.repeatDelay = RepeatDelay
|
||||
return self
|
||||
end
|
||||
|
||||
--- **[LEGION, COMMANDER, CHIEF]** Set how many times the mission is repeated if it fails. Only valid if the mission is handled by a LEGION (AIRWING, BRIGADE, FLEET) or higher level.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number Nrepeat Number of repeats. Default 0.
|
||||
@@ -4767,6 +4814,8 @@ end
|
||||
-- @return #boolean If `true`, all groups are done with the mission.
|
||||
function AUFTRAG:CheckGroupsDone()
|
||||
|
||||
local fsmState = self:GetState()
|
||||
|
||||
-- Check status of all OPS groups.
|
||||
for groupname,data in pairs(self.groupdata) do
|
||||
local groupdata=data --#AUFTRAG.GroupData
|
||||
@@ -4824,6 +4873,11 @@ function AUFTRAG:CheckGroupsDone()
|
||||
self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] but count of alive OPSGROUP is zero. Mission DONE!", self.status, self:GetState()))
|
||||
return true
|
||||
end
|
||||
|
||||
if (self:IsStarted() or self:IsExecuting()) and (fsmState == AUFTRAG.Status.STARTED or fsmState == AUFTRAG.Status.EXECUTING) and self:CountOpsGroups()>0 then
|
||||
self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] and count of alive OPSGROUP > zero. Mission NOT DONE!", self.status, self:GetState()))
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
@@ -5162,7 +5216,7 @@ function AUFTRAG:onafterSuccess(From, Event, To)
|
||||
|
||||
-- Repeat mission.
|
||||
self:T(self.lid..string.format("Mission SUCCESS! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N))
|
||||
self:Repeat()
|
||||
self:__Repeat(self.repeatDelay)
|
||||
|
||||
else
|
||||
|
||||
@@ -5204,7 +5258,7 @@ function AUFTRAG:onafterFailed(From, Event, To)
|
||||
|
||||
-- Repeat mission.
|
||||
self:T(self.lid..string.format("Mission FAILED! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N))
|
||||
self:Repeat()
|
||||
self:__Repeat(self.repeatDelay)
|
||||
|
||||
else
|
||||
|
||||
@@ -6112,7 +6166,7 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
|
||||
local coords = self.engageTarget:GetCoordinates()
|
||||
for _, coord in pairs(coords) do
|
||||
local DCStask = CONTROLLABLE.TaskBombing(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType)
|
||||
local DCStask = CONTROLLABLE.TaskBombing(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, self.optionDivebomb)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
end
|
||||
@@ -6152,8 +6206,16 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
-----------------
|
||||
-- CAP Mission --
|
||||
-----------------
|
||||
|
||||
local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(nil, self.engageZone:GetVec2(), self.engageZone:GetRadius(), self.engageTargetTypes, Priority)
|
||||
|
||||
local Vec2 = self.engageZone:GetVec2()
|
||||
local Radius
|
||||
if self.engageZone:IsInstanceOf("COORDINATE") then
|
||||
Radius = UTILS.NMToMeters(20)
|
||||
else
|
||||
Radius = self.engageZone:GetRadius()
|
||||
end
|
||||
|
||||
local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(nil, Vec2, Radius, self.engageTargetTypes, Priority)
|
||||
|
||||
table.insert(self.enrouteTasks, DCStask)
|
||||
|
||||
@@ -6307,9 +6369,35 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
-- Add enroute task SEAD. Disabled that here because the group enganges everything on its route.
|
||||
--local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.TargetType)
|
||||
--table.insert(self.enrouteTasks, DCStask)
|
||||
|
||||
self:_GetDCSAttackTask(self.engageTarget, DCStasks)
|
||||
|
||||
|
||||
if self.engageZone then
|
||||
|
||||
--local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.engageTargetTypes)
|
||||
--table.insert(self.enrouteTasks, DCStask)
|
||||
self.engageZone:Scan({Object.Category.UNIT},{Unit.Category.GROUND_UNIT})
|
||||
local ScanUnitSet = self.engageZone:GetScannedSetUnit()
|
||||
local SeadUnitSet = SET_UNIT:New()
|
||||
for _,_unit in pairs (ScanUnitSet.Set) do
|
||||
local unit = _unit -- Wrapper.Unit#UNTI
|
||||
if unit and unit:IsAlive() and unit:HasSEAD() then
|
||||
self:T("Adding UNIT for SEAD: "..unit:GetName())
|
||||
local task = CONTROLLABLE.TaskAttackUnit(nil,unit,GroupAttack,AI.Task.WeaponExpend.ALL,1,Direction,self.engageAltitude,2956984318)
|
||||
table.insert(DCStasks, task)
|
||||
SeadUnitSet:AddUnit(unit)
|
||||
end
|
||||
end
|
||||
self.engageTarget = TARGET:New(SeadUnitSet)
|
||||
--local OrbitTask = CONTROLLABLE.TaskOrbitCircle(nil,self.engageAltitude,self.missionSpeed,self.engageZone:GetCoordinate())
|
||||
--local Point = self.engageZone:GetVec2()
|
||||
--local OrbitTask = CONTROLLABLE.TaskOrbitCircleAtVec2(nil,Point,self.engageAltitude,self.missionSpeed)
|
||||
--table.insert(DCStasks, OrbitTask)
|
||||
|
||||
else
|
||||
|
||||
self:_GetDCSAttackTask(self.engageTarget, DCStasks)
|
||||
|
||||
end
|
||||
|
||||
elseif self.type==AUFTRAG.Type.STRIKE then
|
||||
|
||||
--------------------
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **applevangelist**
|
||||
-- @date Last Update Jan 2025
|
||||
-- @date Last Update July 2025
|
||||
-- @module Ops.AWACS
|
||||
-- @image OPS_AWACS.jpg
|
||||
|
||||
@@ -237,7 +237,7 @@ do
|
||||
-- -- Callsign will be "Focus". We'll be a Angels 30, doing 300 knots, orbit leg to 88deg with a length of 25nm.
|
||||
-- testawacs:SetAwacsDetails(CALLSIGN.AWACS.Focus,1,30,300,88,25)
|
||||
-- -- Set up SRS on port 5010 - change the below to your path and port
|
||||
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone","female","en-GB",5010)
|
||||
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio","female","en-GB",5010)
|
||||
-- -- Add a "red" border we don't want to cross, set up in the mission editor with a late activated helo named "Red Border#ZONE_POLYGON"
|
||||
-- testawacs:SetRejectionZone(ZONE:FindByName("Red Border"))
|
||||
-- -- Our CAP flight will have the callsign "Ford", we want 4 AI planes, Time-On-Station is four hours, doing 300 kn IAS.
|
||||
@@ -255,7 +255,7 @@ do
|
||||
-- -- The CAP station zone is called "Fremont". We will be on 255 AM. Note the Orbit Zone is given as *nil* in the `New()`-Statement
|
||||
-- local testawacs = AWACS:New("GCI Senaki",AwacsAW,"blue",AIRBASE.Caucasus.Senaki_Kolkhi,nil,ZONE:FindByName("Rock"),"Fremont",255,radio.modulation.AM )
|
||||
-- -- Set up SRS on port 5010 - change the below to your path and port
|
||||
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone","female","en-GB",5010)
|
||||
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio","female","en-GB",5010)
|
||||
-- -- Add a "red" border we don't want to cross, set up in the mission editor with a late activated helo named "Red Border#ZONE_POLYGON"
|
||||
-- testawacs:SetRejectionZone(ZONE:FindByName("Red Border"))
|
||||
-- -- Our CAP flight will have the callsign "Ford", we want 4 AI planes, Time-On-Station is four hours, doing 300 kn IAS.
|
||||
@@ -509,7 +509,7 @@ do
|
||||
-- @field #AWACS
|
||||
AWACS = {
|
||||
ClassName = "AWACS", -- #string
|
||||
version = "0.2.71", -- #string
|
||||
version = "0.2.72", -- #string
|
||||
lid = "", -- #string
|
||||
coalition = coalition.side.BLUE, -- #number
|
||||
coalitiontxt = "blue", -- #string
|
||||
@@ -1123,7 +1123,7 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
||||
self.EscortMissionReplacement = {}
|
||||
|
||||
-- SRS
|
||||
self.PathToSRS = "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.PathToSRS = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
self.Gender = "female"
|
||||
self.Culture = "en-GB"
|
||||
self.Voice = nil
|
||||
@@ -1242,6 +1242,8 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
||||
self:AddTransition("*", "Intercept", "*")
|
||||
self:AddTransition("*", "InterceptSuccess", "*")
|
||||
self:AddTransition("*", "InterceptFailure", "*")
|
||||
self:AddTransition("*", "VIDSuccess", "*")
|
||||
self:AddTransition("*", "VIDFailure", "*")
|
||||
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
||||
|
||||
|
||||
@@ -1365,18 +1367,38 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
||||
-- @param #string To To state.
|
||||
|
||||
--- On After "InterceptSuccess" event. Intercept successful.
|
||||
-- @function [parent=#AWACS] OnAfterIntercept
|
||||
-- @function [parent=#AWACS] OnAfterInterceptSuccess
|
||||
-- @param #AWACS self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
|
||||
--- On After "InterceptFailure" event. Intercept failure.
|
||||
-- @function [parent=#AWACS] OnAfterIntercept
|
||||
-- @function [parent=#AWACS] OnAfterInterceptFailure
|
||||
-- @param #AWACS self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
|
||||
--- On After "VIDSuccess" event. Intercept successful.
|
||||
-- @function [parent=#AWACS] OnAfterVIDSuccess
|
||||
-- @param #AWACS self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #number GID Managed group ID (Player)
|
||||
-- @param Wrapper.Group#GROUP Group (Player) Group done the VID
|
||||
-- @param #AWACS.ManagedContact Contact The contact that was VID'd
|
||||
|
||||
--- On After "VIDFailure" event. Intercept failure.
|
||||
-- @function [parent=#AWACS] OnAfterVIDFailure
|
||||
-- @param #AWACS self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #number GID Managed group ID (Player)
|
||||
-- @param Wrapper.Group#GROUP Group (Player) Group done the VID
|
||||
-- @param #AWACS.ManagedContact Contact The contact that was VID'd
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -2091,7 +2113,7 @@ end
|
||||
|
||||
--- [User] Set AWACS SRS TTS details - see @{Sound.SRS} for details. `SetSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible.
|
||||
-- @param #AWACS self
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
-- @param #string Gender Defaults to "male"
|
||||
-- @param #string Culture Defaults to "en-US"
|
||||
-- @param #number Port Defaults to 5002
|
||||
@@ -2104,7 +2126,7 @@ end
|
||||
-- @return #AWACS self
|
||||
function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Backend)
|
||||
self:T(self.lid.."SetSRS")
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
self.Gender = Gender or MSRS.gender or "male"
|
||||
self.Culture = Culture or MSRS.culture or "en-US"
|
||||
self.Port = Port or MSRS.port or 5002
|
||||
@@ -3263,12 +3285,14 @@ function AWACS:_VID(Group,Declaration)
|
||||
local vidpos = self.gettext:GetEntry("VIDPOS",self.locale)
|
||||
text = string.format(vidpos,Callsign,self.callsigntxt, Declaration)
|
||||
self:T(text)
|
||||
self:__VIDSuccess(3,GID,group,cluster)
|
||||
else
|
||||
-- too far away
|
||||
self:T("Contact VID not close enough")
|
||||
local vidneg = self.gettext:GetEntry("VIDNEG",self.locale)
|
||||
text = string.format(vidneg,Callsign,self.callsigntxt)
|
||||
self:T(text)
|
||||
self:__VIDFailure(3,GID,group,cluster)
|
||||
end
|
||||
self:_NewRadioEntry(text,text,GID,Outcome,true,true,false,true)
|
||||
end
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
-- ## 2.2 SRS Features and Other Features
|
||||
--
|
||||
-- mycsar.useSRS = false -- Set true to use FF\'s SRS integration
|
||||
-- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!)
|
||||
-- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\ExternalAudio\\" -- adjust your own path in your SRS installation -- server(!)
|
||||
-- mycsar.SRSchannel = 300 -- radio channel
|
||||
-- mycsar.SRSModulation = radio.modulation.AM -- modulation
|
||||
-- mycsar.SRSport = 5002 -- and SRS Server port
|
||||
@@ -481,7 +481,7 @@ function CSAR:New(Coalition, Template, Alias)
|
||||
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
|
||||
-- needs SRS => 1.9.6 to work (works on the *server* side)
|
||||
self.useSRS = false -- Use FF\'s SRS integration
|
||||
self.SRSPath = "E:\\Program Files\\DCS-SimpleRadio-Standalone" -- adjust your own path in your server(!)
|
||||
self.SRSPath = "E:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" -- adjust your own path in your server(!)
|
||||
self.SRSchannel = 300 -- radio channel
|
||||
self.SRSModulation = radio.modulation.AM -- modulation
|
||||
self.SRSport = 5002 -- port
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
-- @module Ops.CTLD
|
||||
-- @image OPS_CTLD.jpg
|
||||
|
||||
-- Last Update May 2025
|
||||
-- Last Update July 2025
|
||||
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1414,7 +1414,7 @@ CTLD.FixedWingTypes = {
|
||||
|
||||
--- CTLD class version.
|
||||
-- @field #string version
|
||||
CTLD.version="1.3.34"
|
||||
CTLD.version="1.3.36"
|
||||
|
||||
--- Instantiate a new CTLD.
|
||||
-- @param #CTLD self
|
||||
@@ -1481,6 +1481,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
||||
self:AddTransition("*", "CratesRepaired", "*") -- CTLD repair event.
|
||||
self:AddTransition("*", "CratesBuildStarted", "*") -- CTLD build event.
|
||||
self:AddTransition("*", "CratesRepairStarted", "*") -- CTLD repair event.
|
||||
self:AddTransition("*", "CratesPacked", "*") -- CTLD repack event.
|
||||
self:AddTransition("*", "HelicopterLost", "*") -- CTLD lost event.
|
||||
self:AddTransition("*", "Load", "*") -- CTLD load event.
|
||||
self:AddTransition("*", "Loaded", "*") -- CTLD load event.
|
||||
@@ -1759,6 +1760,17 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
||||
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
||||
-- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB repaired.
|
||||
-- @return #CTLD self
|
||||
|
||||
--- FSM Function OnBeforeCratesPacked.
|
||||
-- @function [parent=#CTLD] OnBeforeCratesPacked
|
||||
-- @param #CTLD self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Group#GROUP Group Group Object.
|
||||
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
||||
-- @param #CTLD_CARGO Cargo Cargo crate that was repacked.
|
||||
-- @return #CTLD self
|
||||
|
||||
--- FSM Function OnBeforeTroopsRTB.
|
||||
-- @function [parent=#CTLD] OnBeforeTroopsRTB
|
||||
@@ -1846,6 +1858,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Group#GROUP Group Group Object.
|
||||
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
||||
-- @param CargoName The name of the cargo being built.
|
||||
-- @return #CTLD self
|
||||
|
||||
--- FSM Function OnAfterCratesRepairStarted. Info event that a repair has been started.
|
||||
@@ -1888,6 +1901,17 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
||||
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
||||
-- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB repaired.
|
||||
-- @return #CTLD self
|
||||
|
||||
--- FSM Function OnAfterCratesPacked.
|
||||
-- @function [parent=#CTLD] OnAfterCratesPacked
|
||||
-- @param #CTLD self
|
||||
-- @param #string From State.
|
||||
-- @param #string Event Trigger.
|
||||
-- @param #string To State.
|
||||
-- @param Wrapper.Group#GROUP Group Group Object.
|
||||
-- @param Wrapper.Unit#UNIT Unit Unit Object.
|
||||
-- @param #CTLD_CARGO Cargo Cargo crate that was repacked.
|
||||
-- @return #CTLD self
|
||||
|
||||
--- FSM Function OnAfterTroopsRTB.
|
||||
-- @function [parent=#CTLD] OnAfterTroopsRTB
|
||||
@@ -2075,6 +2099,9 @@ function CTLD:_EventHandler(EventData)
|
||||
local _group = event.IniGroup
|
||||
local _unit = event.IniUnit
|
||||
self:_RefreshLoadCratesMenu(_group, _unit)
|
||||
if self:IsFixedWing(_unit) and self.enableFixedWing then
|
||||
self:_RefreshDropCratesMenu(_group, _unit)
|
||||
end
|
||||
end
|
||||
elseif event.id == EVENTS.PlayerLeaveUnit or event.id == EVENTS.UnitLost then
|
||||
-- remove from pilot table
|
||||
@@ -2824,8 +2851,12 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack)
|
||||
if cratedistance > self.CrateDistance then cratedistance = self.CrateDistance end
|
||||
-- altered heading logic
|
||||
-- DONE: right standard deviation?
|
||||
rheading = UTILS.RandomGaussian(0,30,-90,90,100)
|
||||
rheading = math.fmod((heading + rheading), 360)
|
||||
if self:IsUnitInAir(Unit) and self:IsFixedWing(Unit) then
|
||||
rheading = math.random(20,60)
|
||||
else
|
||||
rheading = UTILS.RandomGaussian(0, 30, -90, 90, 100)
|
||||
end
|
||||
rheading=math.fmod((heading+rheading),360)
|
||||
cratecoord = position:Translate(cratedistance,rheading)
|
||||
else
|
||||
cratedistance = (row-1)*6
|
||||
@@ -3962,7 +3993,7 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop)
|
||||
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate(),MultiDrop)
|
||||
buildtimer:Start(self.buildtime)
|
||||
self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group)
|
||||
self:__CratesBuildStarted(1,Group,Unit)
|
||||
self:__CratesBuildStarted(1,Group,Unit,build.Name)
|
||||
self:_RefreshDropTroopsMenu(Group,Unit)
|
||||
else
|
||||
self:_BuildObjectFromCrates(Group,Unit,build,false,nil,MultiDrop)
|
||||
@@ -4004,6 +4035,7 @@ function CTLD:_PackCratesNearby(Group, Unit)
|
||||
_Group:Destroy() -- if a match is found destroy the Wrapper.Group#GROUP near the player
|
||||
self:_GetCrates(Group, Unit, _entry, nil, false, true) -- spawn the appropriate crates near the player
|
||||
self:_RefreshLoadCratesMenu(Group,Unit) -- call the refresher to show the crates in the menu
|
||||
self:__CratesPacked(1,Group,Unit,_entry)
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -4888,7 +4920,17 @@ function CTLD:_UnloadSingleCrateSet(Group, Unit, setIndex)
|
||||
cObj:SetWasDropped(true)
|
||||
cObj:SetHasMoved(true)
|
||||
end
|
||||
|
||||
local cname = crateObj:GetName() or "Unknown"
|
||||
local count = #chunk
|
||||
if needed > 1 then
|
||||
if count == needed then
|
||||
self:_SendMessage(string.format("Dropped %d %s.", 1, cname), 10, false, Group)
|
||||
else
|
||||
self:_SendMessage(string.format("Dropped %d/%d crate(s) of %s.", count, needed, cname), 15, false, Group)
|
||||
end
|
||||
else
|
||||
self:_SendMessage(string.format("Dropped %d %s(s).", count, cname), 10, false, Group)
|
||||
end
|
||||
-- Rebuild the cargo list to remove the dropped crates
|
||||
local loadedData = self.Loaded_Cargo[unitName]
|
||||
if loadedData and loadedData.Cargo then
|
||||
@@ -5007,8 +5049,10 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
|
||||
--------------------------------------------------------------------
|
||||
local mAll=MENU_GROUP:New(Group,"Drop ALL crates",dropCratesMenu)
|
||||
MENU_GROUP_COMMAND:New(Group,"Drop",mAll,self._UnloadCrates,self,Group,Unit)
|
||||
MENU_GROUP_COMMAND:New(Group,"Drop and build",mAll,self._DropAndBuild,self,Group,Unit)
|
||||
|
||||
if not ( self:IsUnitInAir(Unit) and self:IsFixedWing(Unit) ) then
|
||||
MENU_GROUP_COMMAND:New(Group,"Drop and build",mAll,self._DropAndBuild,self,Group,Unit)
|
||||
end
|
||||
|
||||
self.CrateGroupList=self.CrateGroupList or{}
|
||||
self.CrateGroupList[Unit:GetName()]={}
|
||||
|
||||
@@ -5029,7 +5073,9 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
|
||||
local setIndex=#self.CrateGroupList[Unit:GetName()]
|
||||
local mSet=MENU_GROUP:New(Group,label,dropCratesMenu)
|
||||
MENU_GROUP_COMMAND:New(Group,"Drop",mSet,self._UnloadSingleCrateSet,self,Group,Unit,setIndex)
|
||||
if not ( self:IsUnitInAir(Unit) and self:IsFixedWing(Unit) ) then
|
||||
MENU_GROUP_COMMAND:New(Group,"Drop and build",mSet,self._DropSingleAndBuild,self,Group,Unit,setIndex)
|
||||
end
|
||||
i=i+needed
|
||||
else
|
||||
local chunk={}
|
||||
@@ -5156,6 +5202,8 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
|
||||
foundCargo:SetWasDropped(true)
|
||||
if cType == CTLD_CARGO.Enum.ENGINEERS then
|
||||
self.Engineers = self.Engineers + 1
|
||||
local grpname = self.DroppedTroops[self.TroopCounter]:GetName()
|
||||
self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname)
|
||||
self:_SendMessage(string.format("Dropped Engineers %s into action!", name), 10, false, Group)
|
||||
else
|
||||
self:_SendMessage(string.format("Dropped Troops %s into action!", name), 10, false, Group)
|
||||
@@ -5971,16 +6019,22 @@ function CTLD:SmokeZoneNearBy(Unit, Flare)
|
||||
for index,cargozone in pairs(zones[i]) do
|
||||
local CZone = cargozone --#CTLD.CargoZone
|
||||
local zonename = CZone.name
|
||||
local zone = nil
|
||||
local zone = nil -- Core.Zone#ZONE_RADIUS
|
||||
local airbasezone = false
|
||||
if i == 4 then
|
||||
zone = UNIT:FindByName(zonename)
|
||||
else
|
||||
zone = ZONE:FindByName(zonename)
|
||||
if not zone then
|
||||
zone = AIRBASE:FindByName(zonename):GetZone()
|
||||
airbasezone = true
|
||||
end
|
||||
end
|
||||
local zonecoord = zone:GetCoordinate()
|
||||
-- Avoid smoke/flares on runways
|
||||
if (i==1 or 1==3) and airbasezone==true and zone:IsInstanceOf("ZONE_BASE") then
|
||||
zonecoord = zone:GetRandomCoordinate(inner,outer,{land.SurfaceType.LAND})
|
||||
end
|
||||
if zonecoord then
|
||||
local active = CZone.active
|
||||
local color = CZone.color
|
||||
|
||||
@@ -136,6 +136,7 @@ COMMANDER = {
|
||||
awacsZones = {},
|
||||
tankerZones = {},
|
||||
limitMission = {},
|
||||
maxMissionsAssignPerCycle = 1,
|
||||
}
|
||||
|
||||
--- COMMANDER class version.
|
||||
@@ -1535,6 +1536,8 @@ function COMMANDER:CheckMissionQueue()
|
||||
end
|
||||
end
|
||||
|
||||
local missionsAssigned = 0
|
||||
|
||||
-- Loop over missions in queue.
|
||||
for _,_mission in pairs(self.missionqueue) do
|
||||
local mission=_mission --Ops.Auftrag#AUFTRAG
|
||||
@@ -1594,9 +1597,12 @@ function COMMANDER:CheckMissionQueue()
|
||||
-- Recruited assets but no requested escort available. Unrecruit assets!
|
||||
LEGION.UnRecruitAssets(assets, mission)
|
||||
end
|
||||
|
||||
-- Only ONE mission is assigned.
|
||||
return
|
||||
|
||||
missionsAssigned = missionsAssigned + 1
|
||||
if missionsAssigned >= (self.maxMissionsAssignPerCycle or 1) then
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
@@ -1611,6 +1617,16 @@ function COMMANDER:CheckMissionQueue()
|
||||
|
||||
end
|
||||
|
||||
--- Set how many missions can be assigned in a single status iteration. (eg. This is useful for persistent missions where you need to load all AUFTRAGs on mission start and then change it back to default)
|
||||
--- Warning: Increasing this value will increase the number of missions started per iteration and thus may lead to performance issues if too many missions are started at once.
|
||||
-- @param #COMMANDER self
|
||||
-- @param #number Number of missions assigned per status iteration. Default is 1.
|
||||
-- @return #COMMANDER self.
|
||||
function COMMANDER:SetMaxMissionsAssignPerCycle(MaxMissionsAssignPerCycle)
|
||||
self.maxMissionsAssignPerCycle = MaxMissionsAssignPerCycle or 1
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get cohorts.
|
||||
-- @param #COMMANDER self
|
||||
-- @param #table Legions Special legions.
|
||||
@@ -1670,9 +1686,12 @@ function COMMANDER:_GetCohorts(Legions, Cohorts, Operation)
|
||||
for _,_legion in pairs(Legions or {}) do
|
||||
local legion=_legion --Ops.Legion#LEGION
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=true
|
||||
if legion:IsAirwing() then
|
||||
Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition()
|
||||
end
|
||||
|
||||
-- Legion has to be running.
|
||||
if legion:IsRunning() and Runway then
|
||||
|
||||
@@ -1703,9 +1722,12 @@ function COMMANDER:_GetCohorts(Legions, Cohorts, Operation)
|
||||
for _,_legion in pairs(self.legions) do
|
||||
local legion=_legion --Ops.Legion#LEGION
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=true
|
||||
if legion:IsAirwing() then
|
||||
Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition()
|
||||
end
|
||||
|
||||
-- Legion has to be running.
|
||||
if legion:IsRunning() and Runway then
|
||||
|
||||
|
||||
@@ -779,6 +779,61 @@ function FLIGHTGROUP:SetJettisonWeapons(Switch)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft to land straight in.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetOptionLandingStraightIn()
|
||||
self.OptionLandingStraightIn = true
|
||||
if self:GetGroup():IsAlive() then
|
||||
self:GetGroup():SetOptionLandingStraightIn()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft to land in pairs.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetOptionLandingForcePair()
|
||||
self.OptionLandingForcePair = true
|
||||
if self:GetGroup():IsAlive() then
|
||||
self:GetGroup():SetOptionLandingForcePair()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft to NOT land in pairs.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetOptionLandingRestrictPair()
|
||||
self.OptionLandingRestrictPair = true
|
||||
if self:GetGroup():IsAlive() then
|
||||
self:GetGroup():SetOptionLandingRestrictPair()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft to land after overhead break.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetOptionLandingOverheadBreak()
|
||||
self.OptionLandingOverheadBreak = true
|
||||
if self:GetGroup():IsAlive() then
|
||||
self:GetGroup():SetOptionLandingOverheadBreak()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [HELICOPTER] Set the aircraft to prefer takeoff and landing vertically.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetOptionPreferVertical()
|
||||
self.OptionPreferVertical = true
|
||||
if self:GetGroup():IsAlive() then
|
||||
self:GetGroup():OptionPreferVerticalLanding()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set if group is ready for taxi/takeoff if controlled by a `FLIGHTCONTROL`.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param #boolean ReadyTO If `true`, flight is ready for takeoff.
|
||||
@@ -3079,7 +3134,7 @@ function FLIGHTGROUP:onbeforeLandAtAirbase(From, Event, To, airbase)
|
||||
local Tsuspend=nil
|
||||
|
||||
if airbase==nil then
|
||||
self:T(self.lid.."ERROR: Airbase is nil in LandAtAirase() call!")
|
||||
self:T(self.lid.."ERROR: Airbase is nil in LandAtAirbase() call!")
|
||||
allowed=false
|
||||
end
|
||||
|
||||
@@ -4497,6 +4552,11 @@ function FLIGHTGROUP:GetParkingSpot(element, maxdist, airbase)
|
||||
-- Airbase.
|
||||
airbase=airbase or self:GetClosestAirbase()
|
||||
|
||||
if airbase == nil then
|
||||
self:T(self.lid.."No airbase found for element "..element.name)
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Parking table of airbase.
|
||||
local parking=airbase.parking --:GetParkingSpotsTable()
|
||||
|
||||
|
||||
@@ -2513,9 +2513,12 @@ function LEGION._GetCohorts(Legions, Cohorts, Operation, OpsQueue)
|
||||
for _,_legion in pairs(Legions or {}) do
|
||||
local legion=_legion --Ops.Legion#LEGION
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=true
|
||||
if legion:IsAirwing() then
|
||||
Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition()
|
||||
end
|
||||
|
||||
-- Legion has to be running.
|
||||
if legion:IsRunning() and Runway then
|
||||
|
||||
|
||||
@@ -1544,7 +1544,7 @@ end
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #number Frequency Frequency to be used. Can also be given as a table of multiple frequencies, e.g. 271 or {127,251}. There needs to be exactly the same number of modulations!
|
||||
-- @param #number Modulation Modulation to be used. Can also be given as a table of multiple modulations, e.g. radio.modulation.AM or {radio.modulation.FM,radio.modulation.AM}. There needs to be exactly the same number of frequencies!
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
-- @param #string Gender (Optional) Defaults to "male"
|
||||
-- @param #string Culture (Optional) Defaults to "en-US"
|
||||
-- @param #number Port (Optional) Defaults to 5002
|
||||
@@ -1556,7 +1556,7 @@ end
|
||||
-- @return #PLAYERRECCE self
|
||||
function PLAYERRECCE:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,Backend)
|
||||
self:T(self.lid.."SetSRS")
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" --
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" --
|
||||
self.Gender = Gender or MSRS.gender or "male" --
|
||||
self.Culture = Culture or MSRS.culture or "en-US" --
|
||||
self.Port = Port or MSRS.port or 5002 --
|
||||
|
||||
@@ -1440,9 +1440,9 @@ do
|
||||
-- taskmanager:AddRejectZone(ZONE:FindByName("RejectZone"))
|
||||
--
|
||||
-- -- Set up using SRS for messaging
|
||||
-- local hereSRSPath = "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
-- local hereSRSPath = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
-- local hereSRSPort = 5002
|
||||
-- -- local hereSRSGoogle = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourkey.json"
|
||||
-- -- local hereSRSGoogle = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\yourkey.json"
|
||||
-- taskmanager:SetSRS({130,255},{radio.modulation.AM,radio.modulation.AM},hereSRSPath,"female","en-GB",hereSRSPort,"Microsoft Hazel Desktop",0.7,hereSRSGoogle)
|
||||
--
|
||||
-- -- Controller will announce itself under these broadcast frequencies, handy to use cold-start frequencies here of your aircraft
|
||||
@@ -4606,7 +4606,7 @@ end
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @param #number Frequency Frequency to be used. Can also be given as a table of multiple frequencies, e.g. 271 or {127,251}. There needs to be exactly the same number of modulations!
|
||||
-- @param #number Modulation Modulation to be used. Can also be given as a table of multiple modulations, e.g. radio.modulation.AM or {radio.modulation.FM,radio.modulation.AM}. There needs to be exactly the same number of frequencies!
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
-- @param #string Gender (Optional) Defaults to "male"
|
||||
-- @param #string Culture (Optional) Defaults to "en-US"
|
||||
-- @param #number Port (Optional) Defaults to 5002
|
||||
@@ -4620,7 +4620,7 @@ end
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Coordinate,Backend)
|
||||
self:T(self.lid.."SetSRS")
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" --
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" --
|
||||
self.Gender = Gender or MSRS.gender or "male" --
|
||||
self.Culture = Culture or MSRS.culture or "en-US" --
|
||||
self.Port = Port or MSRS.port or 5002 --
|
||||
|
||||
@@ -513,7 +513,7 @@ MSRS.Voices = {
|
||||
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||
["en_GB_Wavenet_O"] = 'en-GB-Wavenet-O', -- [12] MALE
|
||||
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||
["en_US_Wavenet_A"] = 'en-US-Wavenet-N', -- [14] MALE
|
||||
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- [14] MALE
|
||||
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE
|
||||
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE
|
||||
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE
|
||||
@@ -632,7 +632,7 @@ end
|
||||
-- set the path to the exe file via @{#MSRS.SetPath}.
|
||||
--
|
||||
-- @param #MSRS self
|
||||
-- @param #string Path Path to SRS directory. Default `C:\\Program Files\\DCS-SimpleRadio-Standalone`.
|
||||
-- @param #string Path Path to SRS directory. Default `C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio`.
|
||||
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. Can also be given as a #table of multiple frequencies.
|
||||
-- @param #number Modulation Radio modulation: 0=AM (default), 1=FM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators. Can also be given as a #table of multiple modulations.
|
||||
-- @param #string Backend Backend used: `MSRS.Backend.SRSEXE` (default) or `MSRS.Backend.GRPC`.
|
||||
@@ -767,13 +767,13 @@ end
|
||||
|
||||
--- Set path to SRS install directory. More precisely, path to where the `DCS-SR-ExternalAudio.exe` is located.
|
||||
-- @param #MSRS self
|
||||
-- @param #string Path Path to the directory, where the sound file is located. Default is `C:\\Program Files\\DCS-SimpleRadio-Standalone`.
|
||||
-- @param #string Path Path to the directory, where the sound file is located. Default is `C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio`.
|
||||
-- @return #MSRS self
|
||||
function MSRS:SetPath(Path)
|
||||
self:F( {Path=Path} )
|
||||
|
||||
-- Set path.
|
||||
self.path=Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.path=Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
|
||||
-- Remove (back)slashes.
|
||||
local n=1 ; local nmax=1000
|
||||
@@ -1817,7 +1817,7 @@ end
|
||||
--
|
||||
-- -- Moose MSRS default Config
|
||||
-- MSRS_Config = {
|
||||
-- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone", -- Path to SRS install directory.
|
||||
-- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio", -- Path to SRS install directory.
|
||||
-- Port = 5002, -- Port of SRS server. Default 5002.
|
||||
-- Backend = "srsexe", -- Interface to SRS: "srsexe" or "grpc".
|
||||
-- Frequency = {127, 243}, -- Default frequences. Must be a table 1..n entries!
|
||||
@@ -1837,7 +1837,7 @@ end
|
||||
-- -- Google Cloud
|
||||
-- gcloud = {
|
||||
-- voice = "en-GB-Standard-A", -- The Google Cloud voice to use (see https://cloud.google.com/text-to-speech/docs/voices).
|
||||
-- credentials="C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourfilename.json", -- Full path to credentials JSON file (only for SRS-TTS.exe backend)
|
||||
-- credentials="C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\yourfilename.json", -- Full path to credentials JSON file (only for SRS-TTS.exe backend)
|
||||
-- key="Your access Key", -- Google API access key (only for DCS-gRPC backend)
|
||||
-- },
|
||||
-- -- Amazon Web Service
|
||||
@@ -1905,7 +1905,7 @@ function MSRS:LoadConfigFile(Path,Filename)
|
||||
|
||||
local Self = self or MSRS --#MSRS
|
||||
|
||||
Self.path = MSRS_Config.Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
Self.path = MSRS_Config.Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
Self.port = MSRS_Config.Port or 5002
|
||||
Self.backend = MSRS_Config.Backend or MSRS.Backend.SRSEXE
|
||||
Self.frequencies = MSRS_Config.Frequency or {127,243}
|
||||
|
||||
@@ -4143,9 +4143,14 @@ end
|
||||
-- @param #string VehicleTemplate, template name for additional vehicles. Can be nil for no additional vehicles.
|
||||
-- @param #number Liquids Tons of fuel to be added initially to the FARP. Defaults to 10 (tons). Set to 0 for no fill.
|
||||
-- @param #number Equipment Number of equipment items per known item to be added initially to the FARP. Defaults to 10 (items). Set to 0 for no fill.
|
||||
-- @param #number Airframes Number of helicopter airframes per known type in Ops.CSAR#CSAR.AircraftType to be added initially to the FARP. Set to 0 for no airframes.
|
||||
-- @param #string F10Text Text to display on F10 map if given. Handy to post things like the ADF beacon Frequency, Callsign and ATC Frequency.
|
||||
-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns from this FARP.
|
||||
-- @param #boolean HotStart If true and DynamicSpawns is true, allow hot starts for Dynamic Spawns from this FARP.
|
||||
-- @return #list<Wrapper.Static#STATIC> Table of spawned objects and vehicle object (if given).
|
||||
-- @return #string ADFBeaconName Name of the ADF beacon, to be able to remove/stop it later.
|
||||
function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment)
|
||||
-- @return #number MarkerID ID of the F10 Text, to be able to remove it later.
|
||||
function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,Country,CallSign,Frequency,Modulation,ADF,SpawnRadius,VehicleTemplate,Liquids,Equipment,Airframes,F10Text,DynamicSpawns,HotStart)
|
||||
|
||||
-- Set Defaults
|
||||
local farplocation = Coordinate
|
||||
@@ -4159,6 +4164,7 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
|
||||
local liquids = Liquids or 10
|
||||
liquids = liquids * 1000 -- tons to kg
|
||||
local equip = Equipment or 10
|
||||
local airframes = Airframes or 10
|
||||
local statictypes = ENUMS.FARPObjectTypeNamesAndShape[farptype] or {TypeName="FARP", ShapeName="FARPS"}
|
||||
local STypeName = statictypes.TypeName
|
||||
local SShapeName = statictypes.ShapeName
|
||||
@@ -4168,7 +4174,7 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
|
||||
-- Spawn FARP
|
||||
local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP"
|
||||
newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS"
|
||||
newfarp:InitFARP(callsign,freq,mod)
|
||||
newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart)
|
||||
local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name)
|
||||
table.insert(ReturnObjects,spawnedfarp)
|
||||
-- Spawn Objects
|
||||
@@ -4221,6 +4227,12 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
|
||||
end
|
||||
end
|
||||
|
||||
if airframes and airframes > 0 then
|
||||
for typename in pairs (CSAR.AircraftType) do
|
||||
newWH:SetItem(typename,airframes)
|
||||
end
|
||||
end
|
||||
|
||||
local ADFName
|
||||
if ADF and type(ADF) == "number" then
|
||||
local ADFFreq = ADF*1000 -- KHz to Hz
|
||||
@@ -4231,7 +4243,150 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
|
||||
trigger.action.radioTransmission(Sound, vec3, 0, true, ADFFreq, 250, ADFName)
|
||||
end
|
||||
|
||||
return ReturnObjects, ADFName
|
||||
local MarkerID = nil
|
||||
if F10Text then
|
||||
local Color = {0,0,1}
|
||||
if Coalition == coalition.side.RED then
|
||||
Color = {1,0,0}
|
||||
elseif Coalition == coalition.side.NEUTRAL then
|
||||
Color = {0,1,0}
|
||||
end
|
||||
local Alpha = 0.75
|
||||
local coordinate = Coordinate:Translate(600,0)
|
||||
MarkerID = coordinate:TextToAll(F10Text,Coalition,Color,1,{1,1,1},Alpha,14,true)
|
||||
end
|
||||
|
||||
return ReturnObjects, ADFName, MarkerID
|
||||
end
|
||||
|
||||
--- Spawn a MASH at a given coordinate, optionally, add an ADF Beacon.
|
||||
-- @param #string Name Unique Name of the Mash.
|
||||
-- @param Core.Point#COORDINATE Coordinate Coordinate where to spawn the MASH. Can be given as a Core.Zone#ZONE object, in this case we take the center coordinate.
|
||||
-- @param #number Country Country ID the MASH belongs to, e.g. country.id.USA or country.id.RUSSIA.
|
||||
-- @param #number ADF (Optional) ADF Frequency in kHz (Kilohertz), if given activate an ADF Beacon at the location of the MASH.
|
||||
-- @param #string Livery (Optional) The livery of the static CH-47, defaults to dark green.
|
||||
-- @param #boolean DeployHelo (Optional) If true, deploy the helicopter static.
|
||||
-- @param #number MASHRadio MASH Radio Frequency, defaults to 127.5.
|
||||
-- @param #number MASHRadioModulation MASH Radio Modulation, defaults to radio.modulation.AM.
|
||||
-- @param #number MASHCallsign Defaults to CALLSIGN.FARP.Berlin.
|
||||
-- @param #table Templates (Optional) You can hand in your own template table of numbered(!) entries. Each entry consist of a relative(!) x,y position and data of a
|
||||
-- static, shape_name is optional. Also, livery_id is optional, but is applied to the helicopter static only.
|
||||
-- @return #table Table of Wrapper.Static#STATIC objects that were spawned.
|
||||
-- @return #string ADFName Name of the ADF Beacon to remove it later.
|
||||
-- @usage
|
||||
-- -- MASH Template example, this one is the built in one used in the function:
|
||||
-- MASHTemplates = {
|
||||
-- [1]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=0.000000,y=0.000000,},
|
||||
-- [2]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=0.313533,y=8.778935,},
|
||||
-- [3]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=16.303737,y=20.379671,},
|
||||
-- [4]={category='Helicopters',type='CH-47Fbl1',shape_name='none',heading=0,x=-20.047735,y=-63.166179,livery_id = "us army dark green",},
|
||||
-- [5]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=26.650339,y=20.066138,},
|
||||
-- [6]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-25.432292,y=9.077099,},
|
||||
-- [7]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-12.717421,y=-3.216114,},
|
||||
-- [8]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-25.439281,y=-3.216114,},
|
||||
-- [9]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-12.717421,y=9.155603,},
|
||||
-- [10]={category='Fortifications',type='TACAN_beacon',shape_name='none',heading=0,x=-2.329847,y=-16.579903,},
|
||||
-- [11]={category='Fortifications',type='FARP Fuel Depot',shape_name='GSM Rus',heading=0,x=2.222011,y=4.487030,},
|
||||
-- [12]={category='Fortifications',type='APFC fuel',shape_name='M92_APFCfuel',heading=0,x=3.614927,y=0.367838,},
|
||||
-- [13]={category='Fortifications',type='Camouflage03',shape_name='M92_Camouflage03',heading=0,x=21.544148,y=21.998879,},
|
||||
-- [14]={category='Fortifications',type='Container_generator',shape_name='M92_Container_generator',heading=0,x=20.989192,y=37.314334,},
|
||||
-- [15]={category='Fortifications',type='FireExtinguisher02',shape_name='M92_FireExtinguisher02',heading=0,x=3.988003,y=8.362333,},
|
||||
-- [16]={category='Fortifications',type='FireExtinguisher02',shape_name='M92_FireExtinguisher02',heading=0,x=-3.953195,y=12.945844,},
|
||||
-- [17]={category='Fortifications',type='Windsock',shape_name='H-Windsock_RW',heading=0,x=-18.944173,y=-33.042196,},
|
||||
-- [18]={category='Fortifications',type='Tent04',shape_name='M92_Tent04',heading=0,x=21.220671,y=30.247529,},
|
||||
-- }
|
||||
--
|
||||
function UTILS.SpawnMASHStatics(Name,Coordinate,Country,ADF,Livery,DeployHelo,MASHRadio,MASHRadioModulation,MASHCallsign,Templates)
|
||||
|
||||
-- Basic objects table
|
||||
|
||||
local MASHTemplates = {
|
||||
[1]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=0.000000,y=0.000000,},
|
||||
[2]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=0.313533,y=8.778935,},
|
||||
[3]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=16.303737,y=20.379671,},
|
||||
[4]={category='Helicopters',type='CH-47Fbl1',shape_name='none',heading=0,x=-20.047735,y=-63.166179,livery_id = "us army dark green",},
|
||||
[5]={category='Infantry',type='Soldier M4',shape_name='none',heading=0,x=26.650339,y=20.066138,},
|
||||
[6]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-25.432292,y=9.077099,},
|
||||
[7]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-12.717421,y=-3.216114,},
|
||||
[8]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-25.439281,y=-3.216114,},
|
||||
[9]={category='Heliports',type='FARP_SINGLE_01',shape_name='FARP_SINGLE_01',heading=0,x=-12.717421,y=9.155603,},
|
||||
[10]={category='Fortifications',type='TACAN_beacon',shape_name='none',heading=0,x=-2.329847,y=-16.579903,},
|
||||
[11]={category='Fortifications',type='FARP Fuel Depot',shape_name='GSM Rus',heading=0,x=2.222011,y=4.487030,},
|
||||
[12]={category='Fortifications',type='APFC fuel',shape_name='M92_APFCfuel',heading=0,x=3.614927,y=0.367838,},
|
||||
[13]={category='Fortifications',type='Camouflage03',shape_name='M92_Camouflage03',heading=0,x=21.544148,y=21.998879,},
|
||||
[14]={category='Fortifications',type='Container_generator',shape_name='M92_Container_generator',heading=0,x=20.989192,y=37.314334,},
|
||||
[15]={category='Fortifications',type='FireExtinguisher02',shape_name='M92_FireExtinguisher02',heading=0,x=3.988003,y=8.362333,},
|
||||
[16]={category='Fortifications',type='FireExtinguisher02',shape_name='M92_FireExtinguisher02',heading=0,x=-3.953195,y=12.945844,},
|
||||
[17]={category='Fortifications',type='Windsock',shape_name='H-Windsock_RW',heading=0,x=-18.944173,y=-33.042196,},
|
||||
[18]={category='Fortifications',type='Tent04',shape_name='M92_Tent04',heading=0,x=21.220671,y=30.247529,},
|
||||
}
|
||||
|
||||
if Templates then MASHTemplates=Templates end
|
||||
|
||||
-- locals
|
||||
local name = Name or "Florence Nightingale"
|
||||
local positionVec2
|
||||
local positionVec3
|
||||
local ReturnStatics = {}
|
||||
local CountryID = Country or country.id.USA
|
||||
local livery = "us army dark green"
|
||||
local MASHRadio = MASHRadio or 127.5
|
||||
local MASHRadioModulation = MASHRadioModulation or radio.modulation.AM
|
||||
local MASHCallsign = MASHCallsign or CALLSIGN.FARP.Berlin
|
||||
|
||||
-- check for coordinate or zone
|
||||
if type(Coordinate) == "table" then
|
||||
if Coordinate:IsInstanceOf("COORDINATE") or Coordinate:IsInstanceOf("ZONE_BASE") then
|
||||
positionVec2 = Coordinate:GetVec2()
|
||||
positionVec3 = Coordinate:GetVec3()
|
||||
end
|
||||
else
|
||||
BASE:E("Spawn MASH - no ZONE or COORDINATE handed!")
|
||||
return
|
||||
end
|
||||
|
||||
-- position
|
||||
local BaseX = positionVec2.x
|
||||
local BaseY = positionVec2.y
|
||||
|
||||
-- Statics
|
||||
for id,object in pairs(MASHTemplates) do
|
||||
local NewName = string.format("%s#%3d",name,id)
|
||||
local vec2 = {x=BaseX+object.x,y=BaseY+object.y}
|
||||
local Coordinate=COORDINATE:NewFromVec2(vec2)
|
||||
local static = SPAWNSTATIC:NewFromType(object.type,object.category,CountryID)
|
||||
if object.shape_name and object.shape_name ~= "none" then
|
||||
static:InitShape(object.shape_name)
|
||||
end
|
||||
if object.category == "Helicopters" and DeployHelo == true then
|
||||
if object.livery_id ~= nil then
|
||||
livery = object.livery_id
|
||||
end
|
||||
static:InitLivery(livery)
|
||||
local newstatic = static:SpawnFromCoordinate(Coordinate,object.heading,NewName)
|
||||
table.insert(ReturnStatics,newstatic)
|
||||
elseif object.category == "Heliports" then
|
||||
static:InitFARP(MASHCallsign,MASHRadio,MASHRadioModulation,false,false)
|
||||
local newstatic = static:SpawnFromCoordinate(Coordinate,object.heading,NewName)
|
||||
table.insert(ReturnStatics,newstatic)
|
||||
elseif object.category ~= "Helicopters" and object.category ~= "Heliports" then
|
||||
local newstatic = static:SpawnFromCoordinate(Coordinate,object.heading,NewName)
|
||||
table.insert(ReturnStatics,newstatic)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Beacon
|
||||
local ADFName
|
||||
if ADF and type(ADF) == "number" then
|
||||
local ADFFreq = ADF*1000 -- KHz to Hz
|
||||
local Sound = "l10n/DEFAULT/beacon.ogg"
|
||||
ADFName = Name .. " ADF "..tostring(ADF).."KHz"
|
||||
--BASE:I(string.format("Adding MASH Beacon %d KHz Name %s",ADF,ADFName))
|
||||
trigger.action.radioTransmission(Sound, positionVec3, 0, true, ADFFreq, 250, ADFName)
|
||||
end
|
||||
|
||||
return ReturnStatics, ADFName
|
||||
end
|
||||
|
||||
--- Converts a Vec2 to a Vec3.
|
||||
@@ -4428,3 +4583,165 @@ end
|
||||
function UTILS.Weather.StopFogAnimation()
|
||||
return world.weather.setFogAnimation({})
|
||||
end
|
||||
|
||||
--- Find a ME created zone by its name
|
||||
function UTILS.GetEnvZone(name)
|
||||
for _,v in ipairs(env.mission.triggers.zones) do
|
||||
if v.name == name then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- net.dostring_in
|
||||
function UTILS.DoStringIn(State,DoString)
|
||||
return net.dostring_in(State,DoString)
|
||||
end
|
||||
|
||||
--- Show a picture on the screen
|
||||
-- @param #string FileName File name of the picture
|
||||
-- @param #number Duration Duration in seconds, defaults to 10
|
||||
-- @param #boolean ClearView If true, clears the view before showing the picture, defaults to false
|
||||
-- @param #number StartDelay Delay in seconds before showing the picture, defaults to 0
|
||||
-- @param #number HorizontalAlign Horizontal alignment of the picture, defaults to 1 (left), can be 0 (center) or 2 (right)
|
||||
-- @param #number VerticalAlign Vertical alignment of the picture, defaults to 1 (top), can be 0 (center) or 2 (bottom)
|
||||
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||
-- @param #number SizeUnits Size units, defaults to 0 (percent), can be 1 (pixels)
|
||||
function UTILS.ShowPicture(FileName, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)
|
||||
ClearView = ClearView or false
|
||||
StartDelay = StartDelay or 0
|
||||
HorizontalAlign = HorizontalAlign or 1
|
||||
VerticalAlign = VerticalAlign or 1
|
||||
Size = Size or 100
|
||||
SizeUnits = SizeUnits or 0
|
||||
|
||||
if ClearView then ClearView = "true" else ClearView = "false" end
|
||||
|
||||
net.dostring_in("mission", string.format("a_out_picture(getValueResourceByKey(\"%s\"), %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", FileName, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||
end
|
||||
|
||||
--- Show a helper gate at a DCS#Vec3 position
|
||||
-- @param DCS#Vec3 pos The position
|
||||
-- @param number heading Heading in degrees, can be 0..359 degrees
|
||||
function UTILS.ShowHelperGate(pos, heading)
|
||||
net.dostring_in("mission",string.format("a_show_helper_gate(%s, %s, %s, %f)", pos.x, pos.y, pos.z, math.rad(heading)))
|
||||
end
|
||||
|
||||
--- Shell a zone, zone must ME created
|
||||
-- @param #string name The name of the ME created zone
|
||||
-- @param #number power Equals kg of TNT, e.g. 75
|
||||
-- @param #count Number of shells simulated
|
||||
function UTILS.ShellZone(name, power, count)
|
||||
local z = UTILS.GetEnvZone(name)
|
||||
if z then
|
||||
net.dostring_in("mission",string.format("a_shelling_zone(%d, %d, %d)", z.zoneId, power, count))
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove objects from a zone, zone must ME created
|
||||
-- @param #string name The name of the ME created zone
|
||||
-- @param #number type Type of objects to remove can be 0:all, 1: trees, 2:objects
|
||||
function UTILS.RemoveObjects(name, type)
|
||||
local z = UTILS.GetEnvZone(name)
|
||||
if z then
|
||||
net.dostring_in("mission",string.format("a_remove_scene_objects(%d, %d)", z.zoneId, type))
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove scenery objects from a zone, zone must ME created
|
||||
-- @param #string name The name of the ME created zone
|
||||
-- @param #number level Level of removal
|
||||
function UTILS.DestroyScenery(name, level)
|
||||
local z = UTILS.GetEnvZone(name)
|
||||
if z then
|
||||
net.dostring_in("mission",string.format("a_scenery_destruction_zone(%d, %d)", z.zoneId, level))
|
||||
end
|
||||
end
|
||||
|
||||
--- Search for clear zones in a given area. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param DCS##Vec3 Center position vector for the search area.
|
||||
-- @param #number SearchRadius Radius of the search area.
|
||||
-- @param #number PosRadius Required clear radius around each position.
|
||||
-- @param #number NumPositions Number of positions to find.
|
||||
-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius.
|
||||
function UTILS.GetSimpleZones(Vec3, SearchRadius, PosRadius, NumPositions)
|
||||
return Disposition.getSimpleZones(Vec3, SearchRadius, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param Core.Zone#ZONE Zone to search.
|
||||
-- @param #number (Optional) PosRadius Required clear radius around each position. (Default is math.min(Radius/10, 200))
|
||||
-- @param #number (Optional) NumPositions Number of positions to find. (Default 50)
|
||||
-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found.
|
||||
function UTILS.GetClearZonePositions(Zone, PosRadius, NumPositions)
|
||||
local radius = PosRadius or math.min(Zone:GetRadius()/10, 200)
|
||||
local clearPositions = UTILS.GetSimpleZones(Zone:GetVec3(), Zone:GetRadius(), radius, NumPositions or 50)
|
||||
if clearPositions and #clearPositions > 0 then
|
||||
local validZones = {}
|
||||
for _, vec2 in pairs(clearPositions) do
|
||||
if Zone:IsVec2InZone(vec2) then
|
||||
table.insert(validZones, vec2)
|
||||
end
|
||||
end
|
||||
if #validZones > 0 then
|
||||
return validZones, radius
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param Core.Zone#ZONE Zone to search.
|
||||
-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200))
|
||||
-- @param #number NumPositions (Optional) Number of positions to find. (Default 50)
|
||||
-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found.
|
||||
-- @return #number Assigned radius for the found zones. nil if no clear positions are found.
|
||||
function UTILS.GetRandomClearZoneCoordinate(Zone, PosRadius, NumPositions)
|
||||
local clearPositions = UTILS.GetClearZonePositions(Zone, PosRadius, NumPositions)
|
||||
if clearPositions and #clearPositions > 0 then
|
||||
local randomPosition, radius = clearPositions[math.random(1, #clearPositions)]
|
||||
return COORDINATE:NewFromVec2(randomPosition), radius
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Find the point on the radius of a circle closest to a point outside of the radius.
|
||||
-- @param DCS#Vec2 Vec1 Simple Vec2 marking the middle of the circle.
|
||||
-- @param #number Radius The radius of the circle.
|
||||
-- @param DCS#Vec2 Vec2 Simple Vec2 marking the point outside of the circle.
|
||||
-- @return DCS#Vec2 Vec2 point on the radius.
|
||||
function UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2)
|
||||
local r = Radius
|
||||
local cx = Vec1.x or 1
|
||||
local cy = Vec1.y or 1
|
||||
local px = Vec2.x or 1
|
||||
local py = Vec2.y or 1
|
||||
|
||||
-- Berechne den Vektor vom Mittelpunkt zum externen Punkt
|
||||
local dx = px - cx
|
||||
local dy = py - cy
|
||||
|
||||
-- Berechne die Länge des Vektors
|
||||
local dist = math.sqrt(dx * dx + dy * dy)
|
||||
|
||||
-- Wenn der Punkt im Mittelpunkt liegt, wähle einen Punkt auf der X-Achse
|
||||
if dist == 0 then
|
||||
return {x=cx + r, y=cy}
|
||||
end
|
||||
|
||||
-- Normalisiere den Vektor (richtungsweise Vektor mit Länge 1)
|
||||
local norm_dx = dx / dist
|
||||
local norm_dy = dy / dist
|
||||
|
||||
-- Berechne den Punkt auf dem Rand des Kreises
|
||||
local qx = cx + r * norm_dx
|
||||
local qy = cy + r * norm_dy
|
||||
|
||||
local shift_factor = 1
|
||||
qx = qx + shift_factor * norm_dx
|
||||
qy = qy + shift_factor * norm_dy
|
||||
|
||||
return {x=qx, y=qy}
|
||||
end
|
||||
|
||||
@@ -449,7 +449,6 @@ AIRBASE.TheChannel = {
|
||||
-- * AIRBASE.Syria.Al_Dumayr
|
||||
-- * AIRBASE.Syria.Al_Qusayr
|
||||
-- * AIRBASE.Syria.Aleppo
|
||||
-- * AIRBASE.Syria.Amman
|
||||
-- * AIRBASE.Syria.An_Nasiriyah
|
||||
-- * AIRBASE.Syria.At_Tanf
|
||||
-- * AIRBASE.Syria.Bassel_Al_Assad
|
||||
@@ -511,7 +510,7 @@ AIRBASE.TheChannel = {
|
||||
-- * AIRBASE.Syria.Wujah_Al_Hajar
|
||||
-- * AIRBASE.Syria.Ben_Gurion
|
||||
-- * AIRBASE.Syria.Hatzor
|
||||
-- * AIRBASE.Syria.Palmashim
|
||||
-- * AIRBASE.Syria.Palmachim
|
||||
-- * AIRBASE.Syria.Tel_Nof
|
||||
-- * AIRBASE.Syria.Marka
|
||||
--
|
||||
@@ -523,7 +522,6 @@ AIRBASE.Syria={
|
||||
["Al_Dumayr"] = "Al-Dumayr",
|
||||
["Al_Qusayr"] = "Al Qusayr",
|
||||
["Aleppo"] = "Aleppo",
|
||||
["Amman"] = "Amman",
|
||||
["An_Nasiriyah"] = "An Nasiriyah",
|
||||
["At_Tanf"] = "At Tanf",
|
||||
["Bassel_Al_Assad"] = "Bassel Al-Assad",
|
||||
@@ -555,6 +553,7 @@ AIRBASE.Syria={
|
||||
["Kuweires"] = "Kuweires",
|
||||
["Lakatamia"] = "Lakatamia",
|
||||
["Larnaca"] = "Larnaca",
|
||||
["Marka"] = "Marka",
|
||||
["Marj_Ruhayyil"] = "Marj Ruhayyil",
|
||||
["Marj_as_Sultan_North"] = "Marj as Sultan North",
|
||||
["Marj_as_Sultan_South"] = "Marj as Sultan South",
|
||||
@@ -585,9 +584,8 @@ AIRBASE.Syria={
|
||||
["Wujah_Al_Hajar"] = "Wujah Al Hajar",
|
||||
["Ben_Gurion"] = "Ben Gurion",
|
||||
["Hatzor"] = "Hatzor",
|
||||
["Palmashim"] = "Palmashim",
|
||||
["Palmachim"] = "Palmachim",
|
||||
["Tel_Nof"] = "Tel Nof",
|
||||
["Marka"] = "Marka",
|
||||
}
|
||||
|
||||
--- Airbases of the Mariana Islands map:
|
||||
@@ -613,6 +611,35 @@ AIRBASE.MarianaIslands = {
|
||||
["Tinian_Intl"] = "Tinian Intl",
|
||||
}
|
||||
|
||||
--- Airbase of the Marianas WWII map
|
||||
--
|
||||
-- * AIRBASE.MarianaIslandsWWII.Agana
|
||||
-- * AIRBASE.MarianaIslandsWWII.Airfield_3
|
||||
-- * AIRBASE.MarianaIslandsWWII.Charon_Kanoa
|
||||
-- * AIRBASE.MarianaIslandsWWII.Gurguan_Point
|
||||
-- * AIRBASE.MarianaIslandsWWII.Isley
|
||||
-- * AIRBASE.MarianaIslandsWWII.Kagman
|
||||
-- * AIRBASE.MarianaIslandsWWII.Marpi
|
||||
-- * AIRBASE.MarianaIslandsWWII.Orote
|
||||
-- * AIRBASE.MarianaIslandsWWII.Pagan
|
||||
-- * AIRBASE.MarianaIslandsWWII.Rota
|
||||
-- * AIRBASE.MarianaIslandsWWII.Ushi
|
||||
-- @field AIRBASE.MarianaIslandsWWII
|
||||
AIRBASE.MarianaIslandsWWII =
|
||||
{
|
||||
["Agana"] = "Agana",
|
||||
["Airfield_3"] = "Airfield 3",
|
||||
["Charon_Kanoa"] = "Charon Kanoa",
|
||||
["Gurguan_Point"] = "Gurguan Point",
|
||||
["Isley"] = "Isley",
|
||||
["Kagman"] = "Kagman",
|
||||
["Marpi"] = "Marpi",
|
||||
["Orote"] = "Orote",
|
||||
["Pagan"] = "Pagan",
|
||||
["Rota"] = "Rota",
|
||||
["Ushi"] = "Ushi",
|
||||
}
|
||||
|
||||
--- Airbases of the South Atlantic map:
|
||||
--
|
||||
-- * AIRBASE.SouthAtlantic.Almirante_Schroeders
|
||||
@@ -830,6 +857,12 @@ AIRBASE.Kola = {
|
||||
["Enontekio"] = "Enontekio",
|
||||
["Evenes"] = "Evenes",
|
||||
["Hosio"] = "Hosio",
|
||||
["Kilpyavr"] = "Kilpyavr",
|
||||
["Afrikanda"] = "Afrikanda",
|
||||
["Kalevala"] = "Kalevala",
|
||||
["Koshka_Yavr"] = "Koshka Yavr",
|
||||
["Poduzhemye"] = "Poduzhemye",
|
||||
["Luostari_Pechenga"] = "Luostari Pechenga",
|
||||
}
|
||||
|
||||
--- Airbases of the Afghanistan map
|
||||
@@ -1434,7 +1467,7 @@ function AIRBASE:Register(AirbaseName)
|
||||
self.descriptors=self:GetDesc()
|
||||
|
||||
-- Debug info.
|
||||
--self:I({airbase=AirbaseName, descriptors=self.descriptors})
|
||||
--self:T({airbase=AirbaseName, descriptors=self.descriptors})
|
||||
|
||||
-- Category.
|
||||
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
|
||||
@@ -2601,6 +2634,7 @@ function AIRBASE:_InitRunways(IncludeInverse)
|
||||
|
||||
--runway.name=string.format("%02d", tonumber(name))
|
||||
runway.magheading=tonumber(runway.name)*10
|
||||
runway.idx=runway.magheading
|
||||
runway.heading=heading
|
||||
runway.width=width or 0
|
||||
runway.length=length or 0
|
||||
@@ -2913,6 +2947,7 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
||||
local runway={} --#AIRBASE.Runway
|
||||
runway.heading=hdg
|
||||
runway.idx=idx
|
||||
runway.magheading=idx
|
||||
runway.length=c1:Get2DDistance(c2)
|
||||
runway.position=c1
|
||||
runway.endpoint=c2
|
||||
@@ -2928,6 +2963,57 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
||||
-- Add runway.
|
||||
table.insert(runways, runway)
|
||||
|
||||
end
|
||||
|
||||
-- Look for identical (parallel) runways, e.g. 03L and 03R at Nellis.
|
||||
local rpairs={}
|
||||
for i,_ri in pairs(runways) do
|
||||
local ri=_ri --#AIRBASE.Runway
|
||||
for j,_rj in pairs(runways) do
|
||||
local rj=_rj --#AIRBASE.Runway
|
||||
if i<j then
|
||||
if ri.name==rj.name then
|
||||
rpairs[i]=j
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function isLeft(a, b, c)
|
||||
--return ((b.x - a.x)*(c.z - a.z) - (b.z - a.z)*(c.x - a.x)) > 0
|
||||
return ((b.z - a.z)*(c.x - a.x) - (b.x - a.x)*(c.z - a.z)) > 0
|
||||
end
|
||||
|
||||
for i,j in pairs(rpairs) do
|
||||
local ri=runways[i] --#AIRBASE.Runway
|
||||
local rj=runways[j] --#AIRBASE.Runway
|
||||
|
||||
-- Draw arrow.
|
||||
--ri.center:ArrowToAll(rj.center)
|
||||
|
||||
local c0=ri.position
|
||||
|
||||
-- Vector in the direction of the runway.
|
||||
local a=UTILS.VecTranslate(c0, 1000, ri.heading)
|
||||
|
||||
-- Vector from runway i to runway j.
|
||||
local b=UTILS.VecSubstract(rj.position, ri.position)
|
||||
b=UTILS.VecAdd(ri.position, b)
|
||||
|
||||
-- Check if rj is left of ri.
|
||||
local left=isLeft(c0, a, b)
|
||||
|
||||
--env.info(string.format("Found pair %s: i=%d, j=%d, left==%s", ri.name, i, j, tostring(left)))
|
||||
|
||||
if left then
|
||||
ri.isLeft=false
|
||||
rj.isLeft=true
|
||||
else
|
||||
ri.isLeft=true
|
||||
rj.isLeft=false
|
||||
end
|
||||
|
||||
--break
|
||||
end
|
||||
|
||||
return runways
|
||||
|
||||
@@ -168,16 +168,25 @@
|
||||
-- * @{#CONTROLLABLE.OptionAlarmStateGreen}
|
||||
-- * @{#CONTROLLABLE.OptionAlarmStateRed}
|
||||
--
|
||||
-- ## 5.4) Jettison weapons:
|
||||
-- ## 5.4) [AIR] Jettison weapons:
|
||||
--
|
||||
-- * @{#CONTROLLABLE.OptionAllowJettisonWeaponsOnThreat}
|
||||
-- * @{#CONTROLLABLE.OptionKeepWeaponsOnThreat}
|
||||
--
|
||||
-- ## 5.5) Air-2-Air missile attack range:
|
||||
-- ## 5.5) [AIR] Air-2-Air missile attack range:
|
||||
-- * @{#CONTROLLABLE.OptionAAAttackRange}(): Defines the usage of A2A missiles against possible targets.
|
||||
--
|
||||
-- # 6) [GROUND] IR Maker Beacons for GROUPs and UNITs
|
||||
-- * @{#CONTROLLABLE:NewIRMarker}(): Create a blinking IR Marker on a GROUP or UNIT.
|
||||
--
|
||||
-- # 7) [HELICOPTER] Units prefer vertical landing and takeoffs:
|
||||
-- * @{#CONTROLLABLE.OptionPreferVerticalLanding}(): Set aircraft to prefer vertical landing and takeoff.
|
||||
--
|
||||
-- # 8) [AIRCRAFT] Landing approach options
|
||||
-- * @{#CONTROLLABLE.SetOptionLandingStraightIn}(): Landing approach straight in.
|
||||
-- * @{#CONTROLLABLE.SetOptionLandingForcePair}(): Landing approach in pairs for groups > 1 unit.
|
||||
-- * @{#CONTROLLABLE.SetOptionLandingRestrictPair}(): Landing approach single.
|
||||
-- * @{#CONTROLLABLE.SetOptionLandingOverheadBreak}(): Landing approach overhead break.
|
||||
--
|
||||
-- @field #CONTROLLABLE
|
||||
CONTROLLABLE = {
|
||||
@@ -1432,7 +1441,7 @@ end
|
||||
-- @param #number Speed The speed [m/s] flying when holding the position.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:TaskOrbitCircleAtVec2( Point, Altitude, Speed )
|
||||
self:F2( { self.ControllableName, Point, Altitude, Speed } )
|
||||
--self:F2( { self.ControllableName, Point, Altitude, Speed } )
|
||||
|
||||
local DCSTask = {
|
||||
id = 'Orbit',
|
||||
@@ -3629,6 +3638,26 @@ function CONTROLLABLE:OptionROTPassiveDefense()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Helicopter - prefer vertical landing.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionPreferVerticalLanding()
|
||||
self:F2( { self.ControllableName } )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
|
||||
if self:IsAir() then
|
||||
Controller:setOption( AI.Option.Air.id.PREFER_VERTICAL, true )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Can the CONTROLLABLE evade on enemy fire?
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #boolean
|
||||
@@ -4183,6 +4212,50 @@ function CONTROLLABLE:OptionEngageRange( EngageRange )
|
||||
return nil
|
||||
end
|
||||
|
||||
--- [AIR] Set how the AI lands on an airfield. Here: Straight in.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:SetOptionLandingStraightIn()
|
||||
self:F2( { self.ControllableName } )
|
||||
if self:IsAir() then
|
||||
self:SetOption("36","0")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set how the AI lands on an airfield. Here: In pairs (if > 1 aircraft in group)
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:SetOptionLandingForcePair()
|
||||
self:F2( { self.ControllableName } )
|
||||
if self:IsAir() then
|
||||
self:SetOption("36","1")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set how the AI lands on an airfield. Here: No landing in pairs.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:SetOptionLandingRestrictPair()
|
||||
self:F2( { self.ControllableName } )
|
||||
if self:IsAir() then
|
||||
self:SetOption("36","2")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set how the AI lands on an airfield. Here: Overhead break.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:SetOptionLandingOverheadBreak()
|
||||
self:F2( { self.ControllableName } )
|
||||
if self:IsAir() then
|
||||
self:SetOption("36","3")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [AIR] Set how the AI uses the onboard radar.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number Option Options are: `NEVER = 0, FOR_ATTACK_ONLY = 1,FOR_SEARCH_IF_REQUIRED = 2, FOR_CONTINUOUS_SEARCH = 3`
|
||||
|
||||
@@ -230,6 +230,7 @@ GROUP.Attribute = {
|
||||
GROUND_EWR="Ground_EWR",
|
||||
GROUND_AAA="Ground_AAA",
|
||||
GROUND_SAM="Ground_SAM",
|
||||
GROUND_SHORAD="Ground_SHORAD",
|
||||
GROUND_OTHER="Ground_OtherGround",
|
||||
NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier",
|
||||
NAVAL_WARSHIP="Naval_WarShip",
|
||||
|
||||
@@ -246,18 +246,20 @@ end
|
||||
function POSITIONABLE:GetVec3()
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
if DCSPositionable then
|
||||
--local status, vec3 = pcall(
|
||||
-- function()
|
||||
-- local vec3 = DCSPositionable:getPoint()
|
||||
-- return vec3
|
||||
--end
|
||||
--)
|
||||
|
||||
local vec3 = DCSPositionable:getPoint()
|
||||
--if status then
|
||||
return vec3
|
||||
--else
|
||||
--self:E( { "Cannot get Vec3 from DCS Object", Positionable = self, Alive = self:IsAlive() } )
|
||||
--end
|
||||
|
||||
if not vec3 then
|
||||
local pos = DCSPositionable:getPosition()
|
||||
if pos and pos.p then
|
||||
vec3 = pos.p
|
||||
else
|
||||
self:E( { "Cannot get the position from DCS Object for GetVec3", Positionable = self, Alive = self:IsAlive() } )
|
||||
end
|
||||
end
|
||||
|
||||
return vec3
|
||||
|
||||
end
|
||||
-- ERROR!
|
||||
self:E( { "Cannot get the Positionable DCS Object for GetVec3", Positionable = self, Alive = self:IsAlive() } )
|
||||
@@ -388,13 +390,13 @@ function POSITIONABLE:GetCoordinate()
|
||||
|
||||
-- Get the current position.
|
||||
local PositionableVec3 = self:GetVec3()
|
||||
|
||||
local coord=COORDINATE:NewFromVec3(PositionableVec3)
|
||||
local heading = self:GetHeading()
|
||||
coord.Heading = heading
|
||||
-- Return a new coordiante object.
|
||||
return coord
|
||||
|
||||
if PositionableVec3 then
|
||||
local coord=COORDINATE:NewFromVec3(PositionableVec3)
|
||||
local heading = self:GetHeading()
|
||||
coord.Heading = heading
|
||||
-- Return a new coordiante object.
|
||||
return coord
|
||||
end
|
||||
end
|
||||
|
||||
-- Error message.
|
||||
|
||||
@@ -1924,3 +1924,10 @@ function UNIT:IsAAA()
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Set the relative life points of a UNIT object
|
||||
-- @param #UNIT self
|
||||
-- @param #number Percent Percent to set, can be 0..100.
|
||||
function UNIT:SetLife(Percent)
|
||||
net.dostring_in("mission",string.format("a_unit_set_life_percentage(%d, %f)", self:GetID(), Percent))
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user