mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-07-19 09:15:12 +00:00
Compare commits
242 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 26fbae8672 | |||
| 5089e7df25 | |||
| 0c0d1cc794 | |||
| 21b968a9c6 | |||
| 704bb8668f | |||
| 763bfb4bb1 | |||
| 046bd37fd5 | |||
| fbf83b3aed | |||
| 22097987dc | |||
| 98d02d7532 | |||
| 7b44e7a3f6 | |||
| aa4cf37aed | |||
| caf2b4e736 | |||
| da516a0167 | |||
| 17d1cf673d | |||
| 1fcd70b0d0 | |||
| 832941494b | |||
| 0e82cb977e | |||
| e9237146a3 | |||
| b72899b500 | |||
| 2f39e38264 | |||
| db54672fbd | |||
| 30d9a7d703 | |||
| 5a088a740e | |||
| be220b6c1d | |||
| 645c4a4dbc | |||
| c2a630dabd | |||
| 07a14bc176 | |||
| 2047e818ef | |||
| 801b4f01b6 | |||
| 6058160160 | |||
| 479dfc28b9 | |||
| 8392788cdb | |||
| 4a1b23c52a | |||
| 55242edbde | |||
| 2c5d9f043e | |||
| 2b2acbe244 | |||
| 7d4e103660 | |||
| 86798ae9ea | |||
| 2830e6d199 | |||
| 8c07573f8f | |||
| f3af0262df | |||
| 0f270a6a35 | |||
| 8432f46e48 | |||
| faccee88e7 | |||
| e8246b3b90 | |||
| eb4e7b9281 | |||
| 1e2190a6cc | |||
| 1644c1dc5b | |||
| 5fc3798c42 | |||
| fae81cdb1b | |||
| dbae37f151 | |||
| f7d58a0b76 | |||
| 2e0d1fd90f | |||
| 69e6497655 | |||
| ef8c7c9084 | |||
| e4eaf72769 | |||
| 5138ced630 | |||
| 534f445f8c | |||
| b2cc3e5329 | |||
| efde321616 | |||
| 3a61581608 | |||
| 3a10f0b946 | |||
| 6dc6972bdb | |||
| 405235a59d | |||
| 9c148625e4 | |||
| a08d82a3d9 | |||
| 48b51f21de | |||
| 3260279cb7 | |||
| 1e60a0a32a | |||
| 146f869aaa | |||
| 0bd35727f4 | |||
| 5183fcc316 | |||
| bf7596521c | |||
| a85b6c960c | |||
| a1aebf0575 | |||
| 0f42218681 | |||
| 5404f9ef19 | |||
| 8a84be19df | |||
| fd4ea81e46 | |||
| 3df79aedb1 | |||
| 4141aa35ba | |||
| 6e45ee558e | |||
| db138be5f3 | |||
| 5ae6495e69 | |||
| 58f1bc5531 | |||
| 935b52c489 | |||
| aace98545a | |||
| f39236c8fd | |||
| 43b4a6834b | |||
| aa3978b04d | |||
| b51e758516 | |||
| 5be1832c09 | |||
| 362652ac6c | |||
| aec69884dc | |||
| 8fb4d4c7c6 | |||
| b5524b9a69 | |||
| ec0ff7afcd | |||
| d0cf68c2e2 | |||
| 3beb98a5e9 | |||
| dd83ebe0e2 | |||
| 6fdf3957bd | |||
| f3d586d455 | |||
| c2f0ce0fa2 | |||
| 354490d149 | |||
| c5b0be5d21 | |||
| 5e8676cf8a | |||
| f4264cd149 | |||
| 65d1c4187e | |||
| cda1432d04 | |||
| 09e5fca1a5 | |||
| e38d73df8b | |||
| 7df90b2d30 | |||
| a917ee8f1e | |||
| 44f3c776eb | |||
| 873879ff79 | |||
| 6c1907f7e0 | |||
| 42ecdd3b14 | |||
| 297164a0ee | |||
| 323f09b06c | |||
| e003b91bbe | |||
| f1636fc5a9 | |||
| db053398d2 | |||
| 417caf1b62 | |||
| cc76851614 | |||
| 27fe314c1e | |||
| 2c12cfe4fd | |||
| 9adf342dd8 | |||
| facac82130 | |||
| 3e095711f4 | |||
| ca1ddb4013 | |||
| 8169235d2f | |||
| 4553785918 | |||
| 78b3efcf00 | |||
| 67cb844550 | |||
| b9cf1e46af | |||
| 4a04d7cce7 | |||
| 35f15435a3 | |||
| 4c97d966a2 | |||
| 674c6eec81 | |||
| c75c3d8777 | |||
| 4fa63986dc | |||
| 029f7a3f5c | |||
| e9194c59f4 | |||
| c8d693c8e7 | |||
| 2341014882 | |||
| eb15fadcfe | |||
| 13fa8f373e | |||
| b318e8ae13 | |||
| 7e963bef41 | |||
| 933000ffc7 | |||
| 9b217e1c97 | |||
| 324f4944b4 | |||
| f735f1eb53 | |||
| 7149226283 | |||
| 4164a5288a | |||
| 1992276b07 | |||
| 21a7023b7b | |||
| f094716b73 | |||
| 4b1888a34d | |||
| b9be3aa7f8 | |||
| fd2dacaefb | |||
| cc60e85901 | |||
| f172f6efeb | |||
| b6b6686873 | |||
| 5e724e7a3f | |||
| 90f1d1df2a | |||
| a5726c0ed8 | |||
| 23ff128ac8 | |||
| 7d3fc1740a | |||
| b2a084d669 | |||
| 30203668e4 | |||
| ebecc70693 | |||
| 74712b6e27 | |||
| 40253ea8bb | |||
| 4e56078d2a | |||
| 4bbf20ca4e | |||
| a462c5a493 | |||
| 367014ebf3 | |||
| 326b20b08d | |||
| 11b0ce6275 | |||
| 03763e16d6 | |||
| c1e8ee12e0 | |||
| ac8cc408c1 | |||
| ada38fa3ea | |||
| 2ee0597d48 | |||
| 7ae4cdc8f1 | |||
| 8c92a578ed | |||
| 096f2caf9c | |||
| 0b37c909b3 | |||
| 1b18ae1597 | |||
| c9ac6d73e6 | |||
| 0e836973fd | |||
| be40d7be9a | |||
| f3b7740041 | |||
| 7d7488db6f | |||
| 4964cc2f2d | |||
| f0a4c5b008 | |||
| 1b6412821b | |||
| 926a0733e4 | |||
| da70f4ce6c | |||
| 727cb3276c | |||
| 33e63a4819 | |||
| 3543b2c79a | |||
| 4489efff94 | |||
| 6a4bddde99 | |||
| dc2511942c | |||
| f0c257c4a5 | |||
| 068d21612f | |||
| 773461aad9 | |||
| f9257b2b0d | |||
| 9e0f03a3cd | |||
| a467fabdc8 | |||
| a2ab84c45a | |||
| 9fd6729967 | |||
| f1d4f1753a | |||
| 6d9c3fd0aa | |||
| 28ae63bd8d | |||
| 42e7e3f94f | |||
| 6466c5e95e | |||
| 829f5af25f | |||
| 0d1147bac4 | |||
| 24b47b02e0 | |||
| 3cabc07d58 | |||
| b0546b1e60 | |||
| a988e67490 | |||
| 2594c5bbf0 | |||
| db70fa341c | |||
| 763e3852ac | |||
| 8ec86973c6 | |||
| eb2c6ac6f2 | |||
| cbcc893ce5 | |||
| 382b049c5f | |||
| a53763221c | |||
| b7bac28113 | |||
| a9edb16554 | |||
| 0aeb1fc6af | |||
| eeeeda4e5e | |||
| f5881eda53 | |||
| c1997d9f70 | |||
| bb1caa6642 | |||
| dd5ca93f26 |
@@ -577,13 +577,19 @@ do -- Zones and Pathlines
|
||||
-- For a rectangular polygon drawing, we have the width (y) and height (x).
|
||||
local w=objectData.width
|
||||
local h=objectData.height
|
||||
local rotation = UTILS.ToRadian(objectData.angle or 0)
|
||||
|
||||
-- Create points from center using with and height (width for y and height for x is a bit confusing, but this is how ED implemented it).
|
||||
local points={}
|
||||
points[1]={x=vec2.x-h/2, y=vec2.y+w/2} --Upper left
|
||||
points[2]={x=vec2.x+h/2, y=vec2.y+w/2} --Upper right
|
||||
points[3]={x=vec2.x+h/2, y=vec2.y-w/2} --Lower right
|
||||
points[4]={x=vec2.x-h/2, y=vec2.y-w/2} --Lower left
|
||||
local sinRot = math.sin(rotation)
|
||||
local cosRot = math.cos(rotation)
|
||||
local dx = h / 2
|
||||
local dy = w / 2
|
||||
|
||||
local points = {
|
||||
{ x = -dx * cosRot - (-dy * sinRot) + vec2.x, y = -dx * sinRot + (-dy * cosRot) + vec2.y },
|
||||
{ x = dx * cosRot - (-dy * sinRot) + vec2.x, y = dx * sinRot + (-dy * cosRot) + vec2.y },
|
||||
{ x = dx * cosRot - (dy * sinRot) + vec2.x, y = dx * sinRot + (dy * cosRot) + vec2.y },
|
||||
{ x = -dx * cosRot - (dy * sinRot) + vec2.x, y = -dx * sinRot + (dy * cosRot) + vec2.y },
|
||||
}
|
||||
|
||||
--local coord=COORDINATE:NewFromVec2(vec2):MarkToAll("MapX, MapY")
|
||||
|
||||
@@ -1112,7 +1118,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 +1127,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 +1388,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 +1400,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 +1412,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 +1705,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
|
||||
|
||||
@@ -1508,7 +1508,9 @@ function EVENT:onEvent( Event )
|
||||
else
|
||||
if Event.place:isExist() and Object.getCategory(Event.place) ~= Object.Category.SCENERY then
|
||||
Event.Place=AIRBASE:Find(Event.place)
|
||||
Event.PlaceName=Event.Place:GetName()
|
||||
if Event.Place then
|
||||
Event.PlaceName=Event.Place:GetName()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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()
|
||||
--
|
||||
|
||||
@@ -59,6 +59,10 @@ do -- COORDINATE
|
||||
-- * @{#COORDINATE.SmokeOrange}(): To smoke the point in orange.
|
||||
-- * @{#COORDINATE.SmokeWhite}(): To smoke the point in white.
|
||||
-- * @{#COORDINATE.SmokeGreen}(): To smoke the point in green.
|
||||
-- * @{#COORDINATE.SetSmokeOffsetDirection}(): To set an offset point direction for smoke.
|
||||
-- * @{#COORDINATE.SetSmokeOffsetDistance}(): To set an offset point distance for smoke.
|
||||
-- * @{#COORDINATE.SwitchSmokeOffsetOn}(): To set an offset point for smoke to on.
|
||||
-- * @{#COORDINATE.SwitchSmokeOffsetOff}(): To set an offset point for smoke to off.
|
||||
--
|
||||
-- ## 2.2) Flare
|
||||
--
|
||||
@@ -773,7 +777,9 @@ do -- COORDINATE
|
||||
-- @return DCS#Vec2 Vec2
|
||||
function COORDINATE:GetRandomVec2InRadius( OuterRadius, InnerRadius )
|
||||
self:F2( { OuterRadius, InnerRadius } )
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
local Theta = 2 * math.pi * math.random()
|
||||
local Radials = math.random() + math.random()
|
||||
if Radials > 1 then
|
||||
@@ -833,6 +839,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
|
||||
@@ -1611,6 +1637,7 @@ do -- COORDINATE
|
||||
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then
|
||||
RoutePoint.linkUnit = AirbaseID
|
||||
RoutePoint.helipadId = AirbaseID
|
||||
RoutePoint.airdromeId = airbase:IsAirdrome() and AirbaseID or nil
|
||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||
RoutePoint.airdromeId = AirbaseID
|
||||
else
|
||||
@@ -2124,21 +2151,32 @@ do -- COORDINATE
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @param #string Name (Optional) Name if you want to stop the smoke early (normal duration: 5mins)
|
||||
-- @param #boolean Offset (Optional) If true, offset the smokle a bit.
|
||||
-- @param #number Direction (Optional) If Offset is true this is the direction of the offset, 1-359 (degrees). Default random.
|
||||
-- @param #number Distance (Optional) If Offset is true this is the distance of the offset in meters. Default random 10-20.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name)
|
||||
self:F2( { SmokeColor, Name, Duration, Delay } )
|
||||
function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name, Offset,Direction,Distance)
|
||||
self:F2( { SmokeColor, Name, Duration, Delay, Offset } )
|
||||
|
||||
SmokeColor=SmokeColor or SMOKECOLOR.Green
|
||||
|
||||
if Delay and Delay>0 then
|
||||
self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name)
|
||||
self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name, Direction,Distance)
|
||||
else
|
||||
|
||||
-- Create a name which is used to stop the smoke manually
|
||||
self.firename = Name or "Smoke-"..math.random(1,100000)
|
||||
|
||||
-- Create smoke
|
||||
trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename )
|
||||
if Offset or self.SmokeOffset then
|
||||
local Angle = Direction or self:GetSmokeOffsetDirection()
|
||||
local Distance = Distance or self:GetSmokeOffsetDistance()
|
||||
local newpos = self:Translate(Distance,Angle,true,false)
|
||||
local newvec3 = newpos:GetVec3()
|
||||
trigger.action.smoke( newvec3, SmokeColor, self.firename )
|
||||
else
|
||||
trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename )
|
||||
end
|
||||
|
||||
-- Stop smoke
|
||||
if Duration and Duration>0 then
|
||||
@@ -2148,6 +2186,72 @@ do -- COORDINATE
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the offset direction when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number Direction in degrees.
|
||||
function COORDINATE:GetSmokeOffsetDirection()
|
||||
local direction = self.SmokeOffsetDirection or math.random(1,359)
|
||||
return direction
|
||||
end
|
||||
|
||||
--- Set the offset direction when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number Direction (Optional) This is the direction of the offset, 1-359 (degrees). Default random.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SetSmokeOffsetDirection(Direction)
|
||||
if self then
|
||||
self.SmokeOffsetDirection = Direction or math.random(1,359)
|
||||
return self
|
||||
else
|
||||
COORDINATE.SmokeOffsetDirection = Direction or math.random(1,359)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the offset distance when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number Distance Distance in meters.
|
||||
function COORDINATE:GetSmokeOffsetDistance()
|
||||
local distance = self.SmokeOffsetDistance or math.random(10,20)
|
||||
return distance
|
||||
end
|
||||
|
||||
--- Set the offset distance when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number Distance (Optional) This is the distance of the offset in meters. Default random 10-20.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SetSmokeOffsetDistance(Distance)
|
||||
if self then
|
||||
self.SmokeOffsetDistance = Distance or math.random(10,20)
|
||||
return self
|
||||
else
|
||||
COORDINATE.SmokeOffsetDistance = Distance or math.random(10,20)
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the offset on when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SwitchSmokeOffsetOn()
|
||||
if self then
|
||||
self.SmokeOffset = true
|
||||
return self
|
||||
else
|
||||
COORDINATE.SmokeOffset = true
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the offset off when using `COORDINATE:Smoke()`.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SwitchSmokeOffsetOff()
|
||||
if self then
|
||||
self.SmokeOffset = false
|
||||
return self
|
||||
else
|
||||
COORDINATE.SmokeOffset = false
|
||||
end
|
||||
end
|
||||
|
||||
--- Stops smoking the point in a color.
|
||||
-- @param #COORDINATE self
|
||||
@@ -3716,7 +3820,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 ) ) )
|
||||
|
||||
|
||||
+1323
-1363
File diff suppressed because it is too large
Load Diff
@@ -1049,6 +1049,23 @@ function SPAWN:InitSetUnitAbsolutePositions(Positions)
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Uses Disposition and other fallback logic to find better ground positions for ground units.
|
||||
--- NOTE: This is not a spawn randomizer.
|
||||
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area.
|
||||
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||
-- @param #SPAWN self
|
||||
-- @param #boolean OnOff Enable/disable the feature.
|
||||
-- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the units.
|
||||
-- @param #number Spacing (Optional) Minimum spacing between units in meters. Default is 5% of the search radius or 5 meters, whichever is larger.
|
||||
-- @return #SPAWN
|
||||
function SPAWN:InitValidateAndRepositionGroundUnits(OnOff, MaxRadius, Spacing)
|
||||
self.SpawnValidateAndRepositionGroundUnits = OnOff
|
||||
self.SpawnValidateAndRepositionGroundUnitsRadius = MaxRadius
|
||||
self.SpawnValidateAndRepositionGroundUnitsSpacing = Spacing
|
||||
return self
|
||||
end
|
||||
|
||||
--- This method is rather complicated to understand. But I'll try to explain.
|
||||
-- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor,
|
||||
-- but they will all follow the same Template route and have the same prefix name.
|
||||
@@ -1829,7 +1846,13 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
||||
if self.SpawnHiddenOnMap then
|
||||
SpawnTemplate.hidden=self.SpawnHiddenOnMap
|
||||
end
|
||||
|
||||
|
||||
if self.SpawnValidateAndRepositionGroundUnits then
|
||||
local units = SpawnTemplate.units
|
||||
local gPos = { x = SpawnTemplate.x, y = SpawnTemplate.y }
|
||||
UTILS.ValidateAndRepositionGroundUnits(units, gPos, self.SpawnValidateAndRepositionGroundUnitsRadius, self.SpawnValidateAndRepositionGroundUnitsSpacing)
|
||||
end
|
||||
|
||||
-- Set country, coalition and category.
|
||||
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
|
||||
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -373,6 +378,20 @@ function SPAWNSTATIC:InitLinkToUnit(Unit, OffsetX, OffsetY, OffsetAngle)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Uses Disposition and other fallback logic to find a better and valid ground spawn position.
|
||||
--- NOTE: This is not a spawn randomizer.
|
||||
--- It will try to a find clear ground location avoiding trees, water, roads, runways, map scenery, other statics and other units in the area.
|
||||
--- Uses the initial position if it's a valid location.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #boolean OnOff Enable/disable the feature.
|
||||
-- @param #number MaxRadius (Optional) Max radius to search for a valid ground location in meters. Default is 10 times the max radius of the static.
|
||||
-- @return #SPAWNSTATIC self
|
||||
function SPAWNSTATIC:InitValidateAndRepositionStatic(OnOff, MaxRadius)
|
||||
self.ValidateAndRepositionStatic = OnOff
|
||||
self.ValidateAndRepositionStaticMaxRadius = MaxRadius
|
||||
return self
|
||||
end
|
||||
|
||||
--- Allows to place a CallFunction hook when a new static spawns.
|
||||
-- The provided method will be called when a new group is spawned, including its given parameters.
|
||||
-- The first parameter of the SpawnFunction is the @{Wrapper.Static#STATIC} that was spawned.
|
||||
@@ -459,8 +478,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
|
||||
|
||||
@@ -538,6 +558,14 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
-- Add static to the game.
|
||||
local Static=nil --DCS#StaticObject
|
||||
|
||||
if self.ValidateAndRepositionStatic then
|
||||
local validPos = UTILS.ValidateAndRepositionStatic(CountryID, Template.category, Template.type, Template, Template.shape_name, self.ValidateAndRepositionStaticMaxRadius)
|
||||
if validPos then
|
||||
Template.x = validPos.x
|
||||
Template.y = validPos.y
|
||||
end
|
||||
end
|
||||
|
||||
if self.InitFarp then
|
||||
|
||||
local TemplateGroup={}
|
||||
@@ -549,6 +577,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 +591,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 +630,18 @@ 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
|
||||
end
|
||||
|
||||
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 )
|
||||
|
||||
return mystatic
|
||||
end
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
-- @field #table Table of any trigger zone properties from the ME. The key is the Name of the property, and the value is the property's Value.
|
||||
-- @field #number Surface Type of surface. Only determined at the center of the zone!
|
||||
-- @field #number Checktime Check every Checktime seconds, used for ZONE:Trigger()
|
||||
-- @field #boolean PartlyInside When called, a GROUP is considered inside as soon as any of its units enters the zone even if they are far apart.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
@@ -534,6 +535,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.
|
||||
@@ -599,6 +613,8 @@ end
|
||||
--
|
||||
-- -- Stop watching the zone after 1 hour
|
||||
-- triggerzone:__TriggerStop(3600)
|
||||
-- -- Call :SetPartlyInside() if you use SET_GROUP to count as inside when any of their units enters even when they are far apart.
|
||||
-- -- Make sure to call :SetPartlyInside() before :Trigger()!
|
||||
function ZONE_BASE:Trigger(Objects)
|
||||
--self:I("Added Zone Trigger")
|
||||
self:SetStartState("TriggerStopped")
|
||||
@@ -667,6 +683,16 @@ function ZONE_BASE:Trigger(Objects)
|
||||
|
||||
end
|
||||
|
||||
--- Toggle “partly-inside” handling for this zone. To be used before :Trigger().
|
||||
-- * Default:* flag is **false** until you call the method.
|
||||
-- * Call with no argument or with **true** → enable.
|
||||
-- * Call with **false** → disable again (handy if it was enabled before).
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return #ZONE_BASE self
|
||||
function ZONE_BASE:SetPartlyInside(state)
|
||||
self.PartlyInside = state or not ( state == false )
|
||||
return self
|
||||
end
|
||||
--- (Internal) Check the assigned objects for being in/out of the zone
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param #boolean fromstart If true, do the init of the objects
|
||||
@@ -705,7 +731,12 @@ function ZONE_BASE:_TriggerCheck(fromstart)
|
||||
obj.TriggerInZone[self.ZoneName] = false
|
||||
end
|
||||
-- is obj in zone?
|
||||
local inzone = self:IsCoordinateInZone(obj:GetCoordinate())
|
||||
local inzone
|
||||
if self.PartlyInside and obj.ClassName == "GROUP" then
|
||||
inzone = obj:IsAnyInZone(self) -- TRUE if any unit is inside
|
||||
else
|
||||
inzone = self:IsCoordinateInZone(obj:GetCoordinate()) -- original barycentre test
|
||||
end
|
||||
--self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone))
|
||||
if inzone and obj.TriggerInZone[self.ZoneName] then
|
||||
-- just count
|
||||
@@ -1149,15 +1180,13 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
||||
|
||||
local function EvaluateZone( ZoneObject )
|
||||
--if ZoneObject:isExist() then --FF: isExist always returns false for SCENERY objects since DCS 2.2 and still in DCS 2.5
|
||||
if ZoneObject then
|
||||
if ZoneObject and self:IsVec3InZone(ZoneObject:getPoint()) then
|
||||
|
||||
-- Get object category.
|
||||
local ObjectCategory = Object.getCategory(ZoneObject)
|
||||
|
||||
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then
|
||||
|
||||
local CoalitionDCSUnit = ZoneObject:getCoalition()
|
||||
|
||||
local Include = false
|
||||
if not UnitCategories then
|
||||
-- Anything found is included.
|
||||
@@ -1509,6 +1538,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.
|
||||
@@ -1520,6 +1569,10 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
||||
local Vec2 = self:GetVec2()
|
||||
local _inner = inner or 0
|
||||
local _outer = outer or self:GetRadius()
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
if surfacetypes and type(surfacetypes)~="table" then
|
||||
surfacetypes={surfacetypes}
|
||||
@@ -1881,6 +1934,21 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius, Offset)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Updates the current location from a @{Wrapper.Group}.
|
||||
-- @param #ZONE_UNIT self
|
||||
-- @param Wrapper.Group#GROUP Group (optional) Update from this Unit, if nil, update from the UNIT this zone is based on.
|
||||
-- @return self
|
||||
function ZONE_UNIT:UpdateFromUnit(Unit)
|
||||
if Unit and Unit:IsAlive() then
|
||||
local vec2 = Unit:GetVec2()
|
||||
self.LastVec2 = vec2
|
||||
elseif self.ZoneUNIT and self.ZoneUNIT:IsAlive() then
|
||||
local ZoneVec2 = self.ZoneUNIT:GetVec2()
|
||||
self.LastVec2 = ZoneVec2
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Returns the current location of the @{Wrapper.Unit#UNIT}.
|
||||
-- @param #ZONE_UNIT self
|
||||
@@ -2018,6 +2086,22 @@ function ZONE_GROUP:GetVec2()
|
||||
return ZoneVec2
|
||||
end
|
||||
|
||||
--- Updates the current location from a @{Wrapper.Group}.
|
||||
-- @param #ZONE_GROUP self
|
||||
-- @param Wrapper.Group#GROUP Group (optional) Update from this Group, if nil, update from the GROUP this zone is based on.
|
||||
-- @return self
|
||||
function ZONE_GROUP:UpdateFromGroup(Group)
|
||||
if Group and Group:IsAlive() then
|
||||
local vec2 = Group:GetVec2()
|
||||
self.Vec2 = vec2
|
||||
elseif self._.ZoneGROUP and self._.ZoneGROUP:IsAlive() then
|
||||
local ZoneVec2 = self._.ZoneGROUP:GetVec2()
|
||||
self.Vec2 = ZoneVec2
|
||||
self._.ZoneVec2Cache = ZoneVec2
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Returns a random location within the zone of the @{Wrapper.Group}.
|
||||
-- @param #ZONE_GROUP self
|
||||
-- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location.
|
||||
@@ -2487,6 +2571,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.
|
||||
@@ -2865,6 +2969,11 @@ end
|
||||
function ZONE_POLYGON_BASE:GetRandomVec2()
|
||||
-- make sure we assign weights to the triangles based on their surface area, otherwise
|
||||
-- we'll be more likely to generate random points in smaller triangles
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
local weights = {}
|
||||
for _, triangle in pairs(self._Triangles) do
|
||||
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
||||
@@ -3204,12 +3313,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()
|
||||
|
||||
@@ -3233,14 +3337,12 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
||||
|
||||
local function EvaluateZone( ZoneObject )
|
||||
|
||||
if ZoneObject then
|
||||
if ZoneObject and self:IsVec3InZone(ZoneObject:getPoint()) then
|
||||
|
||||
local ObjectCategory = Object.getCategory(ZoneObject)
|
||||
|
||||
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then
|
||||
|
||||
local CoalitionDCSUnit = ZoneObject:getCoalition()
|
||||
|
||||
local Include = false
|
||||
if not UnitCategories then
|
||||
-- Anything found is included.
|
||||
@@ -3272,7 +3374,7 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
||||
end
|
||||
|
||||
-- trying with box search
|
||||
if ObjectCategory == Object.Category.SCENERY and self:IsVec3InZone(ZoneObject:getPoint()) then
|
||||
if ObjectCategory == Object.Category.SCENERY then
|
||||
local SceneryType = ZoneObject:getTypeName()
|
||||
local SceneryName = ZoneObject:getName()
|
||||
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
-- @module Functional.Mantis
|
||||
-- @image Functional.Mantis.jpg
|
||||
--
|
||||
-- Last Update: May 2025
|
||||
-- Last Update: August 2025
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **MANTIS** class, extends Core.Base#BASE
|
||||
@@ -108,10 +108,15 @@
|
||||
-- * Patriot
|
||||
-- * Rapier
|
||||
-- * Roland
|
||||
-- * IRIS-T SLM
|
||||
-- * Pantsir S1
|
||||
-- * TOR M2
|
||||
-- * C-RAM
|
||||
-- * 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
|
||||
-- * Other Mods: Nike
|
||||
--
|
||||
-- * 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 +130,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 +280,7 @@
|
||||
MANTIS = {
|
||||
ClassName = "MANTIS",
|
||||
name = "mymantis",
|
||||
version = "0.9.34",
|
||||
SAM_Templates_Prefix = "",
|
||||
SAM_Group = nil,
|
||||
EWR_Templates_Prefix = "",
|
||||
@@ -382,15 +389,21 @@ MANTIS.SamData = {
|
||||
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
||||
["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Linebacker", Point="true" },
|
||||
["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" },
|
||||
["HEMTT_C-RAM_Phalanx"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" },
|
||||
["C-RAM"] = { 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" },
|
||||
["TAMIR IDFA"] = { Range=20, Blindspot=0.6, Height=12.3, Type="Short", Radar="IRON_DOME_LN" },
|
||||
["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" },
|
||||
["STUNNER IDFA"] = { Range=250, Blindspot=1, Height=45, Type="Long", Radar="DAVID_SLING_LN" },
|
||||
["NIKE"] = { Range=155, Blindspot=6, Height=30, Type="Long", Radar="HIPAR" },
|
||||
["Dog Ear"] = { Range=11, Blindspot=0, Height=9, Type="Point", Radar="Dog Ear", Point="true" },
|
||||
-- CH Added to DCS core 2.9.19.x
|
||||
["Pantsir S1"] = { Range=20, Blindspot=1.2, Height=15, Type="Point", Radar="PantsirS1" , Point="true" },
|
||||
["Tor M2"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2", Point="true" },
|
||||
["IRIS-T SLM"] = { Range=40, Blindspot=0.5, Height=20, Type="Medium", Radar="CH_IRIST_SLM" },
|
||||
}
|
||||
|
||||
--- SAM data HDS
|
||||
@@ -406,13 +419,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
|
||||
@@ -452,15 +469,15 @@ MANTIS.SamDataCH = {
|
||||
-- https://www.currenthill.com/
|
||||
-- group name MUST contain CHM to ID launcher type correctly!
|
||||
["2S38 CHM"] = { Range=6, Blindspot=0.1, Height=4.5, Type="Short", Radar="2S38" },
|
||||
["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Short", Radar="PantsirS1" },
|
||||
["PantsirS1 CHM"] = { Range=20, Blindspot=1.2, Height=15, Type="Point", Radar="PantsirS1", Point="true" },
|
||||
["PantsirS2 CHM"] = { Range=30, Blindspot=1.2, Height=18, Type="Medium", Radar="PantsirS2" },
|
||||
["PGL-625 CHM"] = { Range=10, Blindspot=1, Height=5, Type="Short", Radar="PGL_625" },
|
||||
["HQ-17A CHM"] = { Range=15, Blindspot=1.5, Height=10, Type="Short", Radar="HQ17A" },
|
||||
["M903PAC2 CHM"] = { Range=120, Blindspot=3, Height=24.5, Type="Long", Radar="MIM104_M903_PAC2" },
|
||||
["M903PAC3 CHM"] = { Range=160, Blindspot=1, Height=40, Type="Long", Radar="MIM104_M903_PAC3" },
|
||||
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2" },
|
||||
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
|
||||
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
|
||||
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2", Point="true" },
|
||||
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2K", Point="true" },
|
||||
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Point", Radar="TorM2M", Point="true" },
|
||||
["NASAMS3-AMRAAMER CHM"] = { Range=50, Blindspot=2, Height=35.7, Type="Medium", Radar="CH_NASAMS3_LN_AMRAAM_ER" },
|
||||
["NASAMS3-AIM9X2 CHM"] = { Range=20, Blindspot=0.2, Height=18, Type="Short", Radar="CH_NASAMS3_LN_AIM9X2" },
|
||||
["C-RAM CHM"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="CH_Centurion_C_RAM", Point="true" },
|
||||
@@ -680,9 +697,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 ---
|
||||
@@ -879,7 +893,11 @@ do
|
||||
self.AcceptZones = AcceptZones or {}
|
||||
self.RejectZones = RejectZones or {}
|
||||
self.ConflictZones = ConflictZones or {}
|
||||
if #self.AcceptZones > 0 or #self.RejectZones > 0 or #self.ConflictZones > 0 then
|
||||
self.AcceptZonesNo = UTILS.TableLength(self.AcceptZones)
|
||||
self.RejectZonesNo = UTILS.TableLength(self.RejectZones)
|
||||
self.ConflictZonesNo = UTILS.TableLength(self.ConflictZones)
|
||||
self:T(string.format("AcceptZonesNo = %d | RejectZonesNo = %d | ConflictZonesNo = %d",self.AcceptZonesNo,self.RejectZonesNo,self.ConflictZonesNo))
|
||||
if self.AcceptZonesNo > 0 or self.RejectZonesNo > 0 or self.ConflictZonesNo > 0 then
|
||||
self.usezones = true
|
||||
end
|
||||
return self
|
||||
@@ -1271,7 +1289,8 @@ do
|
||||
self:T(self.lid.."_CheckCoordinateInZones")
|
||||
local inzone = false
|
||||
-- acceptzones
|
||||
if #self.AcceptZones > 0 then
|
||||
self:T(string.format("AcceptZonesNo = %d | RejectZonesNo = %d | ConflictZonesNo = %d",self.AcceptZonesNo,self.RejectZonesNo,self.ConflictZonesNo))
|
||||
if self.AcceptZonesNo > 0 then
|
||||
for _,_zone in pairs(self.AcceptZones) do
|
||||
local zone = _zone -- Core.Zone#ZONE
|
||||
if zone:IsCoordinateInZone(coord) then
|
||||
@@ -1282,7 +1301,7 @@ do
|
||||
end
|
||||
end
|
||||
-- rejectzones
|
||||
if #self.RejectZones > 0 and inzone then -- maybe in accept zone, but check the overlaps
|
||||
if self.RejectZonesNo > 0 then
|
||||
for _,_zone in pairs(self.RejectZones) do
|
||||
local zone = _zone -- Core.Zone#ZONE
|
||||
if zone:IsCoordinateInZone(coord) then
|
||||
@@ -1293,7 +1312,7 @@ do
|
||||
end
|
||||
end
|
||||
-- conflictzones
|
||||
if #self.ConflictZones > 0 and not inzone then -- if not already accepted, might be in conflict zones
|
||||
if self.ConflictZonesNo > 0 then
|
||||
for _,_zone in pairs(self.ConflictZones) do
|
||||
local zone = _zone -- Core.Zone#ZONE
|
||||
if zone:IsCoordinateInZone(coord) then
|
||||
@@ -1359,6 +1378,7 @@ do
|
||||
end
|
||||
-- check accept/reject zones
|
||||
local zonecheck = true
|
||||
self:T("self.usezones = "..tostring(self.usezones))
|
||||
if self.usezones then
|
||||
-- DONE
|
||||
zonecheck = self:_CheckCoordinateInZones(coord)
|
||||
@@ -1798,7 +1818,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 +1850,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 +2130,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
|
||||
|
||||
+1420
-1302
File diff suppressed because it is too large
Load Diff
@@ -320,8 +320,10 @@ function SCORING:New( GameName, SavePath, AutoSave )
|
||||
|
||||
-- Create the CSV file.
|
||||
self.AutoSavePath = SavePath
|
||||
self.AutoSave = AutoSave or true
|
||||
self:OpenCSV( GameName )
|
||||
self.AutoSave = (AutoSave == nil or AutoSave == true) and true or false
|
||||
if self.AutoSavePath and self.AutoSave == true then
|
||||
self:OpenCSV( GameName )
|
||||
end
|
||||
|
||||
return self
|
||||
|
||||
@@ -985,6 +987,7 @@ function SCORING:_EventOnHit( Event )
|
||||
local TargetUnitCoalition = nil
|
||||
local TargetUnitCategory = nil
|
||||
local TargetUnitType = nil
|
||||
local TargetIsScenery = false
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
|
||||
@@ -1025,6 +1028,12 @@ function SCORING:_EventOnHit( Event )
|
||||
TargetCategory = Event.TgtCategory
|
||||
TargetType = Event.TgtTypeName
|
||||
|
||||
-- Scenery hit
|
||||
if (not TargetCategory) and TargetUNIT ~= nil and TargetUnit:IsInstanceOf("SCENERY") then
|
||||
TargetCategory = Unit.Category.STRUCTURE
|
||||
TargetIsScenery = true
|
||||
end
|
||||
|
||||
TargetUnitCoalition = _SCORINGCoalition[TargetCoalition]
|
||||
TargetUnitCategory = _SCORINGCategory[TargetCategory]
|
||||
TargetUnitType = TargetType
|
||||
@@ -1117,17 +1126,22 @@ function SCORING:_EventOnHit( Event )
|
||||
MESSAGE.Type.Update )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
else
|
||||
elseif TargetIsScenery ~= true then
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
||||
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Update )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
elseif TargetIsScenery == true then
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object." .. " Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Update )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
end
|
||||
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||
end
|
||||
else -- A scenery object was hit.
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.",
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit nothing special.",
|
||||
MESSAGE.Type.Update )
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
@@ -1923,7 +1937,7 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
|
||||
TargetUnitType = TargetUnitType or ""
|
||||
TargetUnitName = TargetUnitName or ""
|
||||
|
||||
if lfs and io and os and self.AutoSave then
|
||||
if lfs and io and os and self.AutoSave == true and self.CSVFile ~= nil then
|
||||
self.CSVFile:write(
|
||||
'"' .. self.GameName .. '"' .. ',' ..
|
||||
'"' .. self.RunTime .. '"' .. ',' ..
|
||||
|
||||
@@ -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.
|
||||
@@ -4247,6 +4247,16 @@ function WAREHOUSE:_AssetItemInfo(asset)
|
||||
self:T3({Template=asset.template})
|
||||
end
|
||||
|
||||
--- This function uses Disposition and other fallback logic to find better ground positions for ground units.
|
||||
--- NOTE: This is not a spawn randomizer.
|
||||
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table.
|
||||
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||
--- Uses UTILS.ValidateAndRepositionGroundUnits.
|
||||
-- @param #boolean Enabled Enable/disable the feature.
|
||||
function WAREHOUSE:SetValidateAndRepositionGroundUnits(Enabled)
|
||||
self.ValidateAndRepositionGroundUnits = Enabled
|
||||
end
|
||||
|
||||
--- On after "NewAsset" event. A new asset has been added to the warehouse stock.
|
||||
-- @param #WAREHOUSE self
|
||||
-- @param #string From From state.
|
||||
@@ -5965,6 +5975,10 @@ function WAREHOUSE:_SpawnAssetGroundNaval(alias, asset, request, spawnzone, late
|
||||
template.y = coord.z
|
||||
template.alt = coord.y
|
||||
|
||||
if self.ValidateAndRepositionGroundUnits then
|
||||
UTILS.ValidateAndRepositionGroundUnits(template.units)
|
||||
end
|
||||
|
||||
-- Spawn group.
|
||||
local group=_DATABASE:Spawn(template) --Wrapper.Group#GROUP
|
||||
|
||||
@@ -6893,7 +6907,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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1077
-166
File diff suppressed because it is too large
Load Diff
@@ -72,7 +72,7 @@ end
|
||||
|
||||
--- Checks if a point is contained within the circle.
|
||||
-- @param #table point The point to check
|
||||
-- @return #bool True if the point is contained, false otherwise
|
||||
-- @return #boolean True if the point is contained, false otherwise
|
||||
function CIRCLE:ContainsPoint(point)
|
||||
if ((point.x - self.CenterVec2.x) ^ 2 + (point.y - self.CenterVec2.y) ^ 2) ^ 0.5 <= self.Radius then
|
||||
return true
|
||||
@@ -226,6 +226,11 @@ end
|
||||
--- Returns a random Vec2 within the circle.
|
||||
-- @return #table The random Vec2
|
||||
function CIRCLE:GetRandomVec2()
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
local angle = math.random() * 2 * math.pi
|
||||
|
||||
local rx = math.random(0, self.Radius) * math.cos(angle) + self.CenterVec2.x
|
||||
@@ -237,6 +242,11 @@ end
|
||||
--- Returns a random Vec2 on the border of the circle.
|
||||
-- @return #table The random Vec2
|
||||
function CIRCLE:GetRandomVec2OnBorder()
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
local angle = math.random() * 2 * math.pi
|
||||
|
||||
local rx = self.Radius * math.cos(angle) + self.CenterVec2.x
|
||||
|
||||
@@ -352,6 +352,7 @@ end
|
||||
--- Returns a random Vec2 within the polygon. The Vec2 is weighted by the areas of the triangles that make up the polygon.
|
||||
-- @return #table The random Vec2
|
||||
function POLYGON:GetRandomVec2()
|
||||
|
||||
local weights = {}
|
||||
for _, triangle in pairs(self.Triangles) do
|
||||
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
||||
|
||||
@@ -73,6 +73,11 @@ end
|
||||
-- @param #table points The points of the triangle, or 3 other points if you're just using the TRIANGLE class without an object of it
|
||||
-- @return #table The random Vec2
|
||||
function TRIANGLE:GetRandomVec2(points)
|
||||
|
||||
math.random()
|
||||
math.random()
|
||||
math.random()
|
||||
|
||||
points = points or self.Points
|
||||
local pt = {math.random(), math.random()}
|
||||
table.sort(pt)
|
||||
|
||||
@@ -443,28 +443,32 @@ MSRS.Voices = {
|
||||
["en_AU_Standard_B"] = 'en-AU-Standard-B', -- [2] MALE
|
||||
["en_AU_Standard_C"] = 'en-AU-Standard-C', -- [3] FEMALE
|
||||
["en_AU_Standard_D"] = 'en-AU-Standard-D', -- [4] MALE
|
||||
["en_IN_Standard_A"] = 'en-IN-Standard-A', -- [5] FEMALE
|
||||
["en_IN_Standard_B"] = 'en-IN-Standard-B', -- [6] MALE
|
||||
["en_IN_Standard_C"] = 'en-IN-Standard-C', -- [7] MALE
|
||||
["en_IN_Standard_D"] = 'en-IN-Standard-D', -- [8] FEMALE
|
||||
-- IN
|
||||
["en_IN_Standard_A"] = 'en-IN-Standard-A', -- Female
|
||||
["en_IN_Standard_B"] = 'en-IN-Standard-B', -- Male
|
||||
["en_IN_Standard_C"] = 'en-IN-Standard-C', -- Male
|
||||
["en_IN_Standard_D"] = 'en-IN-Standard-D', -- Female
|
||||
["en_IN_Standard_E"] = 'en-IN-Standard-E', -- Female
|
||||
["en_IN_Standard_F"] = 'en-IN-Standard-F', -- Male
|
||||
-- 2025 changes
|
||||
["en_GB_Standard_A"] = 'en-GB-Standard-N', -- [9] FEMALE
|
||||
["en_GB_Standard_B"] = 'en-GB-Standard-O', -- [10] MALE
|
||||
["en_GB_Standard_C"] = 'en-GB-Standard-N', -- [11] FEMALE
|
||||
["en_GB_Standard_D"] = 'en-GB-Standard-O', -- [12] MALE
|
||||
["en_GB_Standard_F"] = 'en-GB-Standard-N', -- [13] FEMALE
|
||||
["en_GB_Standard_O"] = 'en-GB-Standard-O', -- [12] MALE
|
||||
["en_GB_Standard_N"] = 'en-GB-Standard-N', -- [13] FEMALE
|
||||
["en_US_Standard_A"] = 'en-US-Standard-A', -- [14] MALE
|
||||
["en_US_Standard_B"] = 'en-US-Standard-B', -- [15] MALE
|
||||
["en_US_Standard_C"] = 'en-US-Standard-C', -- [16] FEMALE
|
||||
["en_US_Standard_D"] = 'en-US-Standard-D', -- [17] MALE
|
||||
["en_US_Standard_E"] = 'en-US-Standard-E', -- [18] FEMALE
|
||||
["en_US_Standard_F"] = 'en-US-Standard-F', -- [19] FEMALE
|
||||
["en_US_Standard_G"] = 'en-US-Standard-G', -- [20] FEMALE
|
||||
["en_US_Standard_H"] = 'en-US-Standard-H', -- [21] FEMALE
|
||||
["en_US_Standard_I"] = 'en-US-Standard-I', -- [22] MALE
|
||||
["en_US_Standard_J"] = 'en-US-Standard-J', -- [23] MALE
|
||||
["en_GB_Standard_A"] = 'en-GB-Standard-A', -- Female
|
||||
["en_GB_Standard_B"] = 'en-GB-Standard-B', -- Male
|
||||
["en_GB_Standard_C"] = 'en-GB-Standard-C', -- Female
|
||||
["en_GB_Standard_D"] = 'en-GB-Standard-D', -- Male
|
||||
["en_GB_Standard_F"] = 'en-GB-Standard-F', -- Female
|
||||
["en_GB_Standard_N"] = 'en-GB-Standard-N', -- Female
|
||||
["en_GB_Standard_O"] = 'en-GB-Standard-O', -- Male
|
||||
-- US
|
||||
["en_US_Standard_A"] = 'en-US-Standard-A', -- Male
|
||||
["en_US_Standard_B"] = 'en-US-Standard-B', -- Male
|
||||
["en_US_Standard_C"] = 'en-US-Standard-C', -- Female
|
||||
["en_US_Standard_D"] = 'en-US-Standard-D', -- Male
|
||||
["en_US_Standard_E"] = 'en-US-Standard-E', -- Female
|
||||
["en_US_Standard_F"] = 'en-US-Standard-F', -- Female
|
||||
["en_US_Standard_G"] = 'en-US-Standard-G', -- Female
|
||||
["en_US_Standard_H"] = 'en-US-Standard-H', -- Female
|
||||
["en_US_Standard_I"] = 'en-US-Standard-I', -- Male
|
||||
["en_US_Standard_J"] = 'en-US-Standard-J', -- Male
|
||||
-- 2025 catalog changes
|
||||
["fr_FR_Standard_A"] = "fr-FR-Standard-F", -- Female
|
||||
["fr_FR_Standard_B"] = "fr-FR-Standard-G", -- Male
|
||||
@@ -474,14 +478,15 @@ MSRS.Voices = {
|
||||
["fr_FR_Standard_G"] = "fr-FR-Standard-G", -- Male
|
||||
["fr_FR_Standard_F"] = "fr-FR-Standard-F", -- Female
|
||||
-- 2025 catalog changes
|
||||
["de_DE_Standard_A"] = "de-DE-Standard-G", -- Female
|
||||
["de_DE_Standard_B"] = "de-DE-Standard-H", -- Male
|
||||
["de_DE_Standard_C"] = "de-DE-Standard-G", -- Female
|
||||
["de_DE_Standard_D"] = "de-DE-Standard-H", -- Male
|
||||
["de_DE_Standard_E"] = "de-DE-Standard-H", -- Male
|
||||
["de_DE_Standard_F"] = "de-DE-Standard-G", -- Female
|
||||
["de_DE_Standard_H"] = "de-DE-Standard-H", -- Male
|
||||
["de_DE_Standard_G"] = "de-DE-Standard-G", -- Female
|
||||
["de_DE_Standard_A"] = 'de-DE-Standard-A', -- Female
|
||||
["de_DE_Standard_B"] = 'de-DE-Standard-B', -- Male
|
||||
["de_DE_Standard_C"] = 'de-DE-Standard-C', -- Female
|
||||
["de_DE_Standard_D"] = 'de-DE-Standard-D', -- Male
|
||||
["de_DE_Standard_E"] = 'de-DE-Standard-E', -- Male
|
||||
["de_DE_Standard_F"] = 'de-DE-Standard-F', -- Female
|
||||
["de_DE_Standard_G"] = 'de-DE-Standard-G', -- Female
|
||||
["de_DE_Standard_H"] = 'de-DE-Standard-H', -- Male
|
||||
-- ES
|
||||
["es_ES_Standard_A"] = "es-ES-Standard-E", -- Female
|
||||
["es_ES_Standard_B"] = "es-ES-Standard-F", -- Male
|
||||
["es_ES_Standard_C"] = "es-ES-Standard-E", -- Female
|
||||
@@ -497,32 +502,36 @@ MSRS.Voices = {
|
||||
["it_IT_Standard_F"] = "it-IT-Standard-F", -- Male
|
||||
},
|
||||
Wavenet = {
|
||||
["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- [1] FEMALE
|
||||
["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- [2] MALE
|
||||
["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- [3] FEMALE
|
||||
["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- [4] MALE
|
||||
["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- [5] FEMALE
|
||||
["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- [6] MALE
|
||||
["en_IN_Wavenet_C"] = 'en-IN-Wavenet-C', -- [7] MALE
|
||||
["en_IN_Wavenet_D"] = 'en-IN-Wavenet-D', -- [8] FEMALE
|
||||
["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- Female
|
||||
["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- Male
|
||||
["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- Female
|
||||
["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- Male
|
||||
-- IN
|
||||
["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- Female
|
||||
["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- Male
|
||||
["en_IN_Wavenet_C"] = 'en-IN-Wavenet-C', -- Male
|
||||
["en_IN_Wavenet_D"] = 'en-IN-Wavenet-D', -- Female
|
||||
["en_IN_Wavenet_E"] = 'en-IN-Wavenet-E', -- Female
|
||||
["en_IN_Wavenet_F"] = 'en-IN-Wavenet-F', -- Male
|
||||
-- 2025 changes
|
||||
["en_GB_Wavenet_A"] = 'en-GB-Wavenet-N', -- [9] FEMALE
|
||||
["en_GB_Wavenet_B"] = 'en-GB-Wavenet-O', -- [10] MALE
|
||||
["en_GB_Wavenet_C"] = 'en-GB-Wavenet-N', -- [11] FEMALE
|
||||
["en_GB_Wavenet_D"] = 'en-GB-Wavenet-O', -- [12] MALE
|
||||
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||
["en_GB_Wavenet_A"] = 'en-GB-Wavenet-A', -- [9] FEMALE
|
||||
["en_GB_Wavenet_B"] = 'en-GB-Wavenet-B', -- [10] MALE
|
||||
["en_GB_Wavenet_C"] = 'en-GB-Wavenet-C', -- [11] FEMALE
|
||||
["en_GB_Wavenet_D"] = 'en-GB-Wavenet-D', -- [12] MALE
|
||||
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-F', -- [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_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
|
||||
["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- [18] FEMALE
|
||||
["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- [19] FEMALE
|
||||
["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- [20] FEMALE
|
||||
["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- [21] FEMALE
|
||||
["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- [22] MALE
|
||||
["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- [23] MALE
|
||||
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||
-- US
|
||||
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- Male
|
||||
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- Male
|
||||
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- Female
|
||||
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- Male
|
||||
["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- Female
|
||||
["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- Female
|
||||
["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- Female
|
||||
["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- Female
|
||||
["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- Male
|
||||
["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- Male
|
||||
-- 2025 catalog changes
|
||||
["fr_FR_Wavenet_A"] = "fr-FR-Wavenet-F", -- Female
|
||||
["fr_FR_Wavenet_B"] = "fr-FR-Wavenet-G", -- Male
|
||||
@@ -532,14 +541,15 @@ MSRS.Voices = {
|
||||
["fr_FR_Wavenet_G"] = "fr-FR-Wavenet-G", -- Male
|
||||
["fr_FR_Wavenet_F"] = "fr-FR-Wavenet-F", -- Female
|
||||
-- 2025 catalog changes
|
||||
["de_DE_Wavenet_A"] = "de-DE-Wavenet-G", -- Female
|
||||
["de_DE_Wavenet_B"] = "de-DE-Wavenet-H", -- Male
|
||||
["de_DE_Wavenet_C"] = "de-DE-Wavenet-G", -- Female
|
||||
["de_DE_Wavenet_D"] = "de-DE-Wavenet-H", -- Male
|
||||
["de_DE_Wavenet_E"] = "de-DE-Wavenet-H", -- Male
|
||||
["de_DE_Wavenet_F"] = "de-DE-Wavenet-G", -- Female
|
||||
["de_DE_Wavenet_H"] = "de-DE-Wavenet-H", -- Male
|
||||
["de_DE_Wavenet_G"] = "de-DE-Wavenet-G", -- Female
|
||||
["de_DE_Wavenet_A"] = 'de-DE-Wavenet-A', -- Female
|
||||
["de_DE_Wavenet_B"] = 'de-DE-Wavenet-B', -- Male
|
||||
["de_DE_Wavenet_C"] = 'de-DE-Wavenet-C', -- Female
|
||||
["de_DE_Wavenet_D"] = 'de-DE-Wavenet-D', -- Male
|
||||
["de_DE_Wavenet_E"] = 'de-DE-Wavenet-E', -- Male
|
||||
["de_DE_Wavenet_F"] = 'de-DE-Wavenet-F', -- Female
|
||||
["de_DE_Wavenet_G"] = 'de-DE-Wavenet-G', -- Female
|
||||
["de_DE_Wavenet_H"] = 'de-DE-Wavenet-H', -- Male
|
||||
-- ES
|
||||
["es_ES_Wavenet_B"] = "es-ES-Wavenet-E", -- Male
|
||||
["es_ES_Wavenet_C"] = "es-ES-Wavenet-F", -- Female
|
||||
["es_ES_Wavenet_D"] = "es-ES-Wavenet-E", -- Female
|
||||
@@ -553,6 +563,134 @@ MSRS.Voices = {
|
||||
["it_IT_Wavenet_E"] = "it-IT-Wavenet-E", -- Female
|
||||
["it_IT_Wavenet_F"] = "it-IT-Wavenet-F", -- Male
|
||||
} ,
|
||||
Chirp3HD = {
|
||||
["en_GB_Chirp3_HD_Aoede"] = 'en-GB-Chirp3-HD-Aoede', -- Female
|
||||
["en_GB_Chirp3_HD_Charon"] = 'en-GB-Chirp3-HD-Charon', -- Male
|
||||
["en_GB_Chirp3_HD_Fenrir"] = 'en-GB-Chirp3-HD-Fenrir', -- Male
|
||||
["en_GB_Chirp3_HD_Kore"] = 'en-GB-Chirp3-HD-Kore', -- Female
|
||||
["en_GB_Chirp3_HD_Leda"] = 'en-GB-Chirp3-HD-Leda', -- Female
|
||||
["en_GB_Chirp3_HD_Orus"] = 'en-GB-Chirp3-HD-Orus', -- Male
|
||||
["en_GB_Chirp3_HD_Puck"] = 'en-GB-Chirp3-HD-Puck', -- Male
|
||||
["en_GB_Chirp3_HD_Zephyr"] = 'en-GB-Chirp3-HD-Zephyr', -- Female
|
||||
--["de_DE_Chirp3_HD_Aoede"] = 'de-DE-Chirp3-HD-Aoede', -- Female (Datenfehler im Original)
|
||||
["en_US_Chirp3_HD_Charon"] = 'en-US-Chirp3-HD-Charon', -- Male
|
||||
["en_US_Chirp3_HD_Fenrir"] = 'en-US-Chirp3-HD-Fenrir', -- Male
|
||||
["en_US_Chirp3_HD_Kore"] = 'en-US-Chirp3-HD-Kore', -- Female
|
||||
["en_US_Chirp3_HD_Leda"] = 'en-US-Chirp3-HD-Leda', -- Female
|
||||
["en_US_Chirp3_HD_Orus"] = 'en-US-Chirp3-HD-Orus', -- Male
|
||||
["en_US_Chirp3_HD_Puck"] = 'en-US-Chirp3-HD-Puck', -- Male
|
||||
--["de_DE_Chirp3_HD_Zephyr"] = 'de-DE-Chirp3-HD-Zephyr', -- Female (Datenfehler im Original)
|
||||
-- DE
|
||||
["de_DE_Chirp3_HD_Aoede"] = 'de-DE-Chirp3-HD-Aoede', -- Female
|
||||
["de_DE_Chirp3_HD_Charon"] = 'de-DE-Chirp3-HD-Charon', -- Male
|
||||
["de_DE_Chirp3_HD_Fenrir"] = 'de-DE-Chirp3-HD-Fenrir', -- Male
|
||||
["de_DE_Chirp3_HD_Kore"] = 'de-DE-Chirp3-HD-Kore', -- Female
|
||||
["de_DE_Chirp3_HD_Leda"] = 'de-DE-Chirp3-HD-Leda', -- Female
|
||||
["de_DE_Chirp3_HD_Orus"] = 'de-DE-Chirp3-HD-Orus', -- Male
|
||||
["de_DE_Chirp3_HD_Puck"] = 'de-DE-Chirp3-HD-Puck', -- Male
|
||||
["de_DE_Chirp3_HD_Zephyr"] = 'de-DE-Chirp3-HD-Zephyr', -- Female
|
||||
-- AU
|
||||
["en_AU_Chirp3_HD_Aoede"] = 'en-AU-Chirp3-HD-Aoede', -- Female
|
||||
["en_AU_Chirp3_HD_Charon"] = 'en-AU-Chirp3-HD-Charon', -- Male
|
||||
["en_AU_Chirp3_HD_Fenrir"] = 'en-AU-Chirp3-HD-Fenrir', -- Male
|
||||
["en_AU_Chirp3_HD_Kore"] = 'en-AU-Chirp3-HD-Kore', -- Female
|
||||
["en_AU_Chirp3_HD_Leda"] = 'en-AU-Chirp3-HD-Leda', -- Female
|
||||
["en_AU_Chirp3_HD_Orus"] = 'en-AU-Chirp3-HD-Orus', -- Male
|
||||
["en_AU_Chirp3_HD_Puck"] = 'en-AU-Chirp3-HD-Puck', -- Male
|
||||
["en_AU_Chirp3_HD_Zephyr"] = 'en-AU-Chirp3-HD-Zephyr', -- Female
|
||||
-- IN
|
||||
["en_IN_Chirp3_HD_Aoede"] = 'en-IN-Chirp3-HD-Aoede', -- Female
|
||||
["en_IN_Chirp3_HD_Charon"] = 'en-IN-Chirp3-HD-Charon', -- Male
|
||||
["en_IN_Chirp3_HD_Fenrir"] = 'en-IN-Chirp3-HD-Fenrir', -- Male
|
||||
["en_IN_Chirp3_HD_Kore"] = 'en-IN-Chirp3-HD-Kore', -- Female
|
||||
["en_IN_Chirp3_HD_Leda"] = 'en-IN-Chirp3-HD-Leda', -- Female
|
||||
["en_IN_Chirp3_HD_Orus"] = 'en-IN-Chirp3-HD-Orus', -- Male
|
||||
},
|
||||
ChirpHD = {
|
||||
["en_US_Chirp_HD_D"] = 'en-US-Chirp-HD-D', -- Male
|
||||
["en_US_Chirp_HD_F"] = 'en-US-Chirp-HD-F', -- Female
|
||||
["en_US_Chirp_HD_O"] = 'en-US-Chirp-HD-O', -- Female
|
||||
-- DE
|
||||
["de_DE_Chirp_HD_D"] = 'de-DE-Chirp-HD-D', -- Male
|
||||
["de_DE_Chirp_HD_F"] = 'de-DE-Chirp-HD-F', -- Female
|
||||
["de_DE_Chirp_HD_O"] = 'de-DE-Chirp-HD-O', -- Female
|
||||
-- AU
|
||||
["en_AU_Chirp_HD_D"] = 'en-AU-Chirp-HD-D', -- Male
|
||||
["en_AU_Chirp_HD_F"] = 'en-AU-Chirp-HD-F', -- Female
|
||||
["en_AU_Chirp_HD_O"] = 'en-AU-Chirp-HD-O', -- Female
|
||||
-- IN
|
||||
["en_IN_Chirp_HD_D"] = 'en-IN-Chirp-HD-D', -- Male
|
||||
["en_IN_Chirp_HD_F"] = 'en-IN-Chirp-HD-F', -- Female
|
||||
["en_IN_Chirp_HD_O"] = 'en-IN-Chirp-HD-O', -- Female
|
||||
},
|
||||
},
|
||||
Neural2 = {
|
||||
["en_GB_Neural2_A"] = 'en-GB-Neural2-A', -- Female
|
||||
["en_GB_Neural2_B"] = 'en-GB-Neural2-B', -- Male
|
||||
["en_GB_Neural2_C"] = 'en-GB-Neural2-C', -- Female
|
||||
["en_GB_Neural2_D"] = 'en-GB-Neural2-D', -- Male
|
||||
["en_GB_Neural2_F"] = 'en-GB-Neural2-F', -- Female
|
||||
["en_GB_Neural2_N"] = 'en-GB-Neural2-N', -- Female
|
||||
["en_GB_Neural2_O"] = 'en-GB-Neural2-O', -- Male
|
||||
-- US
|
||||
["en_US_Neural2_A"] = 'en-US-Neural2-A', -- Male
|
||||
["en_US_Neural2_C"] = 'en-US-Neural2-C', -- Female
|
||||
["en_US_Neural2_D"] = 'en-US-Neural2-D', -- Male
|
||||
["en_US_Neural2_E"] = 'en-US-Neural2-E', -- Female
|
||||
["en_US_Neural2_F"] = 'en-US-Neural2-F', -- Female
|
||||
["en_US_Neural2_G"] = 'en-US-Neural2-G', -- Female
|
||||
["en_US_Neural2_H"] = 'en-US-Neural2-H', -- Female
|
||||
["en_US_Neural2_I"] = 'en-US-Neural2-I', -- Male
|
||||
["en_US_Neural2_J"] = 'en-US-Neural2-J', -- Male
|
||||
-- DE
|
||||
["de_DE_Neural2_G"] = 'de-DE-Neural2-G', -- Female
|
||||
["de_DE_Neural2_H"] = 'de-DE-Neural2-H', -- Male
|
||||
-- AU
|
||||
["en_AU_Neural2_A"] = 'en-AU-Neural2-A', -- Female
|
||||
["en_AU_Neural2_B"] = 'en-AU-Neural2-B', -- Male
|
||||
["en_AU_Neural2_C"] = 'en-AU-Neural2-C', -- Female
|
||||
["en_AU_Neural2_D"] = 'en-AU-Neural2-D', -- Male
|
||||
-- IN
|
||||
["en_IN_Neural2_A"] = 'en-IN-Neural2-A', -- Female
|
||||
["en_IN_Neural2_B"] = 'en-IN-Neural2-B', -- Male
|
||||
["en_IN_Neural2_C"] = 'en-IN-Neural2-C', -- Male
|
||||
["en_IN_Neural2_D"] = 'en-IN-Neural2-D', -- Female
|
||||
},
|
||||
News = {
|
||||
["en_GB_News_G"] = 'en-GB-News-G', -- Female
|
||||
["en_GB_News_H"] = 'en-GB-News-H', -- Female
|
||||
["en_GB_News_I"] = 'en-GB-News-I', -- Female
|
||||
["en_GB_News_J"] = 'en-GB-News-J', -- Male
|
||||
["en_GB_News_K"] = 'en-GB-News-K', -- Male
|
||||
["en_GB_News_L"] = 'en-GB-News-L', -- Male
|
||||
["en_GB_News_M"] = 'en-GB-News-M', -- Male
|
||||
-- US
|
||||
["en_US_News_K"] = 'en-US-News-K', -- Female
|
||||
["en_US_News_L"] = 'en-US-News-L', -- Female
|
||||
["en_US_News_N"] = 'en-US-News-N', -- Male
|
||||
-- AU
|
||||
["en_AU_News_E"] = 'en-AU-News-E', -- Female
|
||||
["en_AU_News_F"] = 'en-AU-News-F', -- Female
|
||||
["en_AU_News_G"] = 'en-AU-News-G', -- Male
|
||||
},
|
||||
Casual = {
|
||||
["en_US_Casual_K"] = 'en-US-Casual-K', -- Male
|
||||
},
|
||||
Polyglot = {
|
||||
["en_US_Polyglot_1"] = 'en-US-Polyglot-1', -- Male
|
||||
["de_DE_Polyglot_1"] = 'de-DE-Polyglot-1', -- Male
|
||||
["en_AU_Polyglot_1"] = 'en-AU-Polyglot-1', -- Male
|
||||
},
|
||||
Studio = {
|
||||
-- Englisch (UK) - Studio
|
||||
["en_GB_Studio_B"] = 'en-GB-Studio-B', -- Male
|
||||
["en_GB_Studio_C"] = 'en-GB-Studio-C', -- Female
|
||||
-- Englisch (USA) - Studio
|
||||
["en_US_Studio_O"] = 'en-US-Studio-O', -- Female
|
||||
["en_US_Studio_Q"] = 'en-US-Studio-Q', -- Male
|
||||
-- DE
|
||||
["de_DE_Studio_B"] = 'de-DE-Studio-B', -- Male
|
||||
["de_DE_Studio_C"] = 'de-DE-Studio-C', -- Female
|
||||
},
|
||||
}
|
||||
|
||||
@@ -632,7 +770,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 +905,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 +1955,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 +1975,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 +2043,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}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1586,12 +1586,12 @@ function UTILS.HdgDiff(h1, h2)
|
||||
return math.abs(delta)
|
||||
end
|
||||
|
||||
--- Returns the heading from one vec3 to another vec3.
|
||||
-- @param DCS#Vec3 a From vec3.
|
||||
-- @param DCS#Vec3 b To vec3.
|
||||
--- Returns the heading from one vec2/vec3 to another vec2/vec3.
|
||||
-- @param DCS#Vec3 a From Vec2 or Vec3.
|
||||
-- @param DCS#Vec3 b To Vec2 or Vec3.
|
||||
-- @return #number Heading in degrees.
|
||||
function UTILS.HdgTo(a, b)
|
||||
local dz=b.z-a.z
|
||||
local dz=(b.z or b.y) - (a.z or a.y)
|
||||
local dx=b.x-a.x
|
||||
local heading=math.deg(math.atan2(dz, dx))
|
||||
if heading < 0 then
|
||||
@@ -1913,6 +1913,13 @@ end
|
||||
function UTILS.GetReportingName(Typename)
|
||||
|
||||
local typename = string.lower(Typename)
|
||||
|
||||
-- special cases - Shark and Manstay have "A-50" in the name
|
||||
if string.find(typename,"ka-50",1,true) then
|
||||
return "Shark"
|
||||
elseif string.find(typename,"a-50",1,true) then
|
||||
return "Mainstay"
|
||||
end
|
||||
|
||||
for name, value in pairs(ENUMS.ReportingName.NATO) do
|
||||
local svalue = string.lower(value)
|
||||
@@ -2323,6 +2330,16 @@ function UTILS.IsLoadingDoorOpen( unit_name )
|
||||
return true
|
||||
end
|
||||
|
||||
if type_name == "UH-60L_DAP" and (unit:getDrawArgumentValue(401) == 1 or unit:getDrawArgumentValue(402) == 1) then
|
||||
BASE:T(unit_name .. " cargo door is open")
|
||||
return true
|
||||
end
|
||||
|
||||
if type_name == "UH-60L_DAP" and (unit:getDrawArgumentValue(38) > 0 or unit:getDrawArgumentValue(400) == 1 ) then
|
||||
BASE:T(unit_name .. " front door(s) are open")
|
||||
return true
|
||||
end
|
||||
|
||||
if type_name == "AH-64D_BLK_II" then
|
||||
BASE:T(unit_name .. " front door(s) are open")
|
||||
return true -- no doors on this one ;)
|
||||
@@ -4120,6 +4137,45 @@ function UTILS.LCGRandom()
|
||||
return UTILS.lcg.seed / UTILS.lcg.m
|
||||
end
|
||||
|
||||
--- Create a table of grid-points for n points.
|
||||
-- @param #number startVec2 Starting DCS#Vec2 map coordinate, e.g. `{x=63598575,y=-63598575}`
|
||||
-- @param #number n Number of points to generate.
|
||||
-- @param #number spacingX Horizonzal spacing (meters).
|
||||
-- @param #number spacingY Vertical spacing (meters).
|
||||
-- @return #table Grid Table of DCS#Vec2 entries.
|
||||
function UTILS.GenerateGridPoints(startVec2, n, spacingX, spacingY)
|
||||
local points = {}
|
||||
local gridSize = math.ceil(math.sqrt(n))
|
||||
local count = 0
|
||||
local n = n or 1
|
||||
local spacingX = spacingX or 100
|
||||
local spacingY = spacingY or 100
|
||||
local startX = startVec2.x or 100
|
||||
local startY = startVec2.y or 100
|
||||
|
||||
for row = 0, gridSize - 1 do
|
||||
for col = 0, gridSize - 1 do
|
||||
if count >= n then
|
||||
break
|
||||
end
|
||||
|
||||
local point = {
|
||||
x = startX + (col * spacingX),
|
||||
y = startY + (row * spacingY)
|
||||
}
|
||||
|
||||
table.insert(points, point)
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
if count >= n then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return points
|
||||
end
|
||||
|
||||
--- Spawns a new FARP of a defined type and coalition and functional statics (fuel depot, ammo storage, tent, windsock) around that FARP to make it operational.
|
||||
-- Adds vehicles from template if given. Fills the FARP warehouse with liquids and known materiels.
|
||||
-- References: [DCS Forum Topic](https://forum.dcs.world/topic/282989-farp-equipment-to-run-it)
|
||||
@@ -4136,9 +4192,42 @@ 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.
|
||||
-- @param #number NumberPads If given, spawn this number of pads.
|
||||
-- @param #number SpacingX For NumberPads > 1, space this many meters horizontally. Defaults to 100.
|
||||
-- @param #number SpacingY For NumberPads > 1, space this many meters vertically. Defaults to 100.
|
||||
-- @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,NumberPads,SpacingX,SpacingY)
|
||||
|
||||
local function PopulateStorage(Name,liquids,equip,airframes)
|
||||
local newWH = STORAGE:New(Name)
|
||||
if liquids and liquids > 0 then
|
||||
-- Storage fill-up
|
||||
newWH:SetLiquid(STORAGE.Liquid.DIESEL,liquids) -- kgs to tons
|
||||
newWH:SetLiquid(STORAGE.Liquid.GASOLINE,liquids)
|
||||
newWH:SetLiquid(STORAGE.Liquid.JETFUEL,liquids)
|
||||
newWH:SetLiquid(STORAGE.Liquid.MW50,liquids)
|
||||
end
|
||||
|
||||
if equip and equip > 0 then
|
||||
for cat,nitem in pairs(ENUMS.Storage.weapons) do
|
||||
for name,item in pairs(nitem) do
|
||||
newWH:SetItem(item,equip)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if airframes and airframes > 0 then
|
||||
for typename in pairs (CSAR.AircraftType) do
|
||||
newWH:SetItem(typename,airframes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Set Defaults
|
||||
local farplocation = Coordinate
|
||||
@@ -4152,18 +4241,81 @@ 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
|
||||
local Country = Country or (Coalition == coalition.side.BLUE and country.id.USA or country.id.RUSSIA)
|
||||
local ReturnObjects = {}
|
||||
|
||||
-- Spawn FARP
|
||||
local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP"
|
||||
newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS"
|
||||
newfarp:InitFARP(callsign,freq,mod)
|
||||
local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name)
|
||||
table.insert(ReturnObjects,spawnedfarp)
|
||||
-- many FARPs
|
||||
local NumberPads = NumberPads or 1
|
||||
local SpacingX = SpacingX or 100
|
||||
local SpacingY = SpacingY or 100
|
||||
local FarpVec2 = Coordinate:GetVec2()
|
||||
|
||||
if NumberPads > 1 then
|
||||
local Grid = UTILS.GenerateGridPoints(FarpVec2, NumberPads, SpacingX, SpacingY)
|
||||
local groupData = {
|
||||
["visible"] = true,
|
||||
["hidden"] = false,
|
||||
["units"] = {},
|
||||
["y"] = 0, -- Group center latitude
|
||||
["x"] = 0, -- Group center longitude
|
||||
["name"] = Name,
|
||||
}
|
||||
local unitData = {
|
||||
["category"] = "Heliports",
|
||||
["type"] = STypeName, -- FARP type
|
||||
["y"] = 0, -- Latitude coordinate (meters)
|
||||
["x"] = 0, -- Longitude coordinate (meters)
|
||||
["name"] = Name,
|
||||
["heading"] = 0, -- Heading in radians
|
||||
["heliport_modulation"] = mod, -- 0 = AM, 1 = FM
|
||||
["heliport_frequency"] = freq, -- Radio frequency in MHz
|
||||
["heliport_callsign_id"] = callsign, -- Callsign ID
|
||||
["dead"] = false,
|
||||
["shape_name"] = SShapeName,
|
||||
["dynamicSpawn"] = DynamicSpawns,
|
||||
["allowHotStart"] = HotStart,
|
||||
}
|
||||
for id,gridpoint in ipairs(Grid) do
|
||||
-- Spawn FARP
|
||||
local UnitTemplate = UTILS.DeepCopy(unitData)
|
||||
UnitTemplate.x = gridpoint.x
|
||||
UnitTemplate.y = gridpoint.y
|
||||
if id > 1 then UnitTemplate.name = Name.."-"..id end
|
||||
table.insert(groupData.units,UnitTemplate)
|
||||
if id==1 then
|
||||
groupData.x = gridpoint.x
|
||||
groupData.y = gridpoint.y
|
||||
end
|
||||
end
|
||||
--BASE:I("Spawning FARP")
|
||||
--UTILS.PrintTableToLog(groupData,1)
|
||||
local Static=coalition.addGroup(Country, -1, groupData)
|
||||
-- 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 = {
|
||||
id = EVENTS.Birth,
|
||||
time = timer.getTime(),
|
||||
initiator = Static
|
||||
}
|
||||
-- Create BIRTH event.
|
||||
world.onEvent(Event)
|
||||
|
||||
PopulateStorage(Name.."-1",liquids,equip,airframes)
|
||||
else
|
||||
-- Spawn FARP
|
||||
local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP"
|
||||
newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS"
|
||||
newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart)
|
||||
local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name)
|
||||
table.insert(ReturnObjects,spawnedfarp)
|
||||
|
||||
PopulateStorage(Name,liquids,equip,airframes)
|
||||
end
|
||||
|
||||
-- Spawn Objects
|
||||
local FARPStaticObjectsNato = {
|
||||
["FUEL"] = { TypeName = "FARP Fuel Depot", ShapeName = "GSM Rus", Category = "Fortifications"},
|
||||
@@ -4197,23 +4349,6 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
|
||||
table.insert(ReturnObjects,spawnedvehicle)
|
||||
end
|
||||
|
||||
local newWH = STORAGE:New(Name)
|
||||
if liquids and liquids > 0 then
|
||||
-- Storage fill-up
|
||||
newWH:SetLiquid(STORAGE.Liquid.DIESEL,liquids) -- kgs to tons
|
||||
newWH:SetLiquid(STORAGE.Liquid.GASOLINE,liquids)
|
||||
newWH:SetLiquid(STORAGE.Liquid.JETFUEL,liquids)
|
||||
newWH:SetLiquid(STORAGE.Liquid.MW50,liquids)
|
||||
end
|
||||
|
||||
if equip and equip > 0 then
|
||||
for cat,nitem in pairs(ENUMS.Storage.weapons) do
|
||||
for name,item in pairs(nitem) do
|
||||
newWH:SetItem(item,equip)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ADFName
|
||||
if ADF and type(ADF) == "number" then
|
||||
local ADFFreq = ADF*1000 -- KHz to Hz
|
||||
@@ -4224,7 +4359,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.
|
||||
@@ -4421,3 +4699,449 @@ 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 to all
|
||||
-- @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, 0: Left, 1: Center, 2: Right
|
||||
-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom
|
||||
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||
function UTILS.ShowPictureToAll(FilePath, 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(\"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||
end
|
||||
|
||||
--- Show a picture on the screen to Coalition
|
||||
-- @param #number Coalition Coalition ID, can be coalition.side.BLUE, coalition.side.RED or coalition.side.NEUTRAL
|
||||
-- @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, 0: Left, 1: Center, 2: Right
|
||||
-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom
|
||||
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||
function UTILS.ShowPictureToCoalition(Coalition, FilePath, 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
|
||||
|
||||
local coalName = string.lower(UTILS.GetCoalitionName(Coalition))
|
||||
|
||||
net.dostring_in("mission", string.format("a_out_picture_s(\"%s\", \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", coalName, FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||
end
|
||||
|
||||
--- Show a picture on the screen to Country
|
||||
-- @param #number Country Country ID, can be country.id.USA, country.id.RUSSIA, etc.
|
||||
-- @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, 0: Left, 1: Center, 2: Right
|
||||
-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom
|
||||
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||
function UTILS.ShowPictureToCountry(Country, FilePath, 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_c(%d, \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", Country, FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||
end
|
||||
|
||||
--- Show a picture on the screen to Group
|
||||
-- @param Wrapper.Group#GROUP Group Group to show the picture to
|
||||
-- @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, 0: Left, 1: Center, 2: Right
|
||||
-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom
|
||||
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||
function UTILS.ShowPictureToGroup(Group, FilePath, 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_g(%d, \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", Group:GetID(), FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||
end
|
||||
|
||||
--- Show a picture on the screen to Unit
|
||||
-- @param Wrapper.Unit#UNIT Unit Unit to show the picture to
|
||||
-- @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, 0: Left, 1: Center, 2: Right
|
||||
-- @param #number VerticalAlign Vertical alignment of the picture, 0: Top, 1: Center, 2: Bottom
|
||||
-- @param #number Size Size of the picture in percent, defaults to 100
|
||||
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||
function UTILS.ShowPictureToUnit(Unit, FilePath, 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_u(%d, \"%s\", %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", Unit:GetID(), FilePath, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
||||
end
|
||||
|
||||
--- Load a mission file. This will replace the current mission with the one given carrying along the online clients.
|
||||
-- @param #string FileName Mission filename
|
||||
function UTILS.LoadMission(FileName)
|
||||
net.dostring_in("mission", string.format("a_load_mission(\"%s\")", FileName))
|
||||
end
|
||||
|
||||
--- Set the mission briefing for a coalition.
|
||||
-- @param #number Coalition Briefing coalition ID, can be coalition.side.BLUE, coalition.side.RED or coalition.side.NEUTRAL
|
||||
-- @param #string Text Briefing text, can contain newlines, will be converted formatted properly for DCS
|
||||
-- @param #string Picture Picture file path, can be a file in the DEFAULT folder inside the .miz
|
||||
function UTILS.SetMissionBriefing(Coalition, Text, Picture)
|
||||
Text = Text or ""
|
||||
Text = Text:gsub("\n", "\\n")
|
||||
Picture = Picture or ""
|
||||
local coalName = string.lower(UTILS.GetCoalitionName(Coalition))
|
||||
net.dostring_in("mission", string.format("a_set_briefing(\"%s\", \"%s\", \"%s\")", coalName, Picture, Text))
|
||||
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
|
||||
|
||||
--- Show a helper gate for a unit.
|
||||
-- @param Wrapper.Unit#UNIT Unit The unit to show the gate for
|
||||
-- @param #number Flag Helper gate flag
|
||||
function UTILS.ShowHelperGateForUnit(Unit, Flag)
|
||||
net.dostring_in("mission",string.format("a_show_route_gates_for_unit(%d, \"%d\")", Unit:GetID(), Flag))
|
||||
end
|
||||
|
||||
--- Set the carrier illumination mode. -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY
|
||||
-- @param #number UnitID Carrier unit ID ( UNIT:GetID() )
|
||||
-- @param #number Mode Illumination mode, can be -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY
|
||||
function UTILS.SetCarrierIlluminationMode(UnitID, Mode)
|
||||
net.dostring_in("mission",string.format("a_set_carrier_illumination_mode(%d, %d)", UnitID, Mode))
|
||||
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
|
||||
|
||||
--- This function uses Disposition and other fallback logic to find better ground positions for ground units.
|
||||
--- NOTE: This is not a spawn randomizer.
|
||||
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table.
|
||||
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||
-- @param #table Positions A table of DCS#Vec2 or DCS#Vec3, can be a units table from the group template.
|
||||
-- @param DCS#Vec2 Anchor (Optional) DCS#Vec2 or DCS#Vec3 as anchor point to calculate offset of the units.
|
||||
-- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the units.
|
||||
-- @param #number Spacing (Optional) Minimum spacing between units in meters. Default is 5% of the search radius or 5 meters, whichever is larger.
|
||||
function UTILS.ValidateAndRepositionGroundUnits(Positions, Anchor, MaxRadius, Spacing)
|
||||
local units = Positions
|
||||
Anchor = Anchor or UTILS.GetCenterPoint(units)
|
||||
local gPos = { x = Anchor.x, y = Anchor.z or Anchor.y }
|
||||
local maxRadius = 0
|
||||
local unitCount = 0
|
||||
for _, unit in pairs(units) do
|
||||
local pos = { x = unit.x, y = unit.z or unit.y }
|
||||
local dist = UTILS.VecDist2D(pos, gPos)
|
||||
if dist > maxRadius then
|
||||
maxRadius = dist
|
||||
end
|
||||
unitCount = unitCount + 1
|
||||
end
|
||||
maxRadius = MaxRadius or math.max(maxRadius * 2, 10)
|
||||
local spacing = Spacing or math.max(maxRadius * 0.05, 5)
|
||||
if unitCount > 0 and maxRadius > 5 then
|
||||
local spots = UTILS.GetSimpleZones(UTILS.Vec2toVec3(gPos), maxRadius, spacing, 1000)
|
||||
if spots and #spots > 0 then
|
||||
local validSpots = {}
|
||||
for _, spot in pairs(spots) do -- Disposition sometimes returns points on roads, hence this filter.
|
||||
if land.getSurfaceType(spot) == land.SurfaceType.LAND then
|
||||
table.insert(validSpots, spot)
|
||||
end
|
||||
end
|
||||
spots = validSpots
|
||||
end
|
||||
|
||||
local step = spacing
|
||||
for _, unit in pairs(units) do
|
||||
local pos = { x = unit.x, y = unit.z or unit.y }
|
||||
local isOnLand = land.getSurfaceType(pos) == land.SurfaceType.LAND
|
||||
local isValid = false
|
||||
if spots and #spots > 0 then
|
||||
local si = 1
|
||||
local sid = 0
|
||||
local closestDist = 100000000
|
||||
local closestSpot
|
||||
for _, spot in pairs(spots) do
|
||||
local dist = UTILS.VecDist2D(pos, spot)
|
||||
if dist < closestDist then
|
||||
closestDist = dist
|
||||
closestSpot = spot
|
||||
sid = si
|
||||
end
|
||||
si = si + 1
|
||||
end
|
||||
if closestSpot then
|
||||
if closestDist >= spacing then
|
||||
pos = closestSpot
|
||||
end
|
||||
isValid = true
|
||||
table.remove(spots, sid)
|
||||
end
|
||||
end
|
||||
|
||||
-- Failsafe calculation
|
||||
if not isValid and not isOnLand then
|
||||
|
||||
local h = UTILS.HdgTo(pos, gPos)
|
||||
local retries = 0
|
||||
while not isValid and retries < 500 do
|
||||
|
||||
local dist = UTILS.VecDist2D(pos, gPos)
|
||||
pos = UTILS.Vec2Translate(pos, step, h)
|
||||
|
||||
local skip = false
|
||||
for _, unit2 in pairs(units) do
|
||||
if unit ~= unit2 then
|
||||
local pos2 = { x = unit2.x, y = unit2.z or unit2.y }
|
||||
local dist2 = UTILS.VecDist2D(pos, pos2)
|
||||
if dist2 < 12 then
|
||||
isValid = false
|
||||
skip = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not skip and dist > step and land.getSurfaceType(pos) == land.SurfaceType.LAND then
|
||||
isValid = true
|
||||
break
|
||||
elseif dist <= step then
|
||||
break
|
||||
end
|
||||
|
||||
retries = retries + 1
|
||||
end
|
||||
end
|
||||
|
||||
if isValid then
|
||||
unit.x = pos.x
|
||||
if unit.z then
|
||||
unit.z = pos.y
|
||||
else
|
||||
unit.y = pos.y
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- This function uses Disposition and other fallback logic to find better ground positions for statics.
|
||||
--- NOTE: This is not a spawn randomizer.
|
||||
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table.
|
||||
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||
-- @param #table Positions A table of DCS#Vec2 or DCS#Vec3, can be a units table from the group template.
|
||||
-- @param DCS#Vec2 Position DCS#Vec2 or DCS#Vec3 initial spawn location.
|
||||
-- @param #number MaxRadius (Optional) Max radius to search for valid ground locations in meters. Default is double the max radius of the static.
|
||||
-- @return DCS#Vec2 Initial Position if it's valid, else a valid spawn position. nil if no valid position found.
|
||||
function UTILS.ValidateAndRepositionStatic(Country, Category, Type, Position, ShapeName, MaxRadius)
|
||||
local coord = COORDINATE:NewFromVec2(Position)
|
||||
local st = SPAWNSTATIC:NewFromType(Type, Category, Country)
|
||||
if ShapeName then
|
||||
st:InitShape(ShapeName)
|
||||
end
|
||||
local sName = "s-"..timer.getTime().."-"..math.random(1,10000)
|
||||
local tempStatic = st:SpawnFromCoordinate(coord, 0, sName)
|
||||
if tempStatic then
|
||||
local sRadius = tempStatic:GetBoundingRadius(2) or 3
|
||||
tempStatic:Destroy()
|
||||
sRadius = sRadius * 0.5
|
||||
MaxRadius = MaxRadius or math.max(sRadius * 10, 100)
|
||||
local positions = UTILS.GetSimpleZones(coord:GetVec3(), MaxRadius, sRadius, 20)
|
||||
if positions and #positions > 0 then
|
||||
local closestSpot
|
||||
local closestDist = math.huge
|
||||
for _, spot in pairs(positions) do -- Disposition sometimes returns points on roads, hence this filter.
|
||||
if land.getSurfaceType(spot) == land.SurfaceType.LAND then
|
||||
local dist = UTILS.VecDist2D(Position, spot)
|
||||
if dist < closestDist then
|
||||
closestDist = dist
|
||||
closestSpot = spot
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if closestSpot then
|
||||
if closestDist >= sRadius then
|
||||
return closestSpot
|
||||
else
|
||||
return Position
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
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
|
||||
@@ -676,51 +703,56 @@ AIRBASE.SouthAtlantic={
|
||||
|
||||
--- Airbases of the Sinai map:
|
||||
--
|
||||
-- * AIRBASE.Sinai.Abu_Rudeis
|
||||
-- * AIRBASE.Sinai.Abu_Suwayr
|
||||
-- * AIRBASE.Sinai.Al_Bahr_al_Ahmar
|
||||
-- * AIRBASE.Sinai.Al_Ismailiyah
|
||||
-- * AIRBASE.Sinai.Al_Khatatbah
|
||||
-- * AIRBASE.Sinai.Al_Mansurah
|
||||
-- * AIRBASE.Sinai.Al_Rahmaniyah_Air_Base
|
||||
-- * AIRBASE.Sinai.As_Salihiyah
|
||||
-- * AIRBASE.Sinai.AzZaqaziq
|
||||
-- * AIRBASE.Sinai.Baluza
|
||||
-- * AIRBASE.Sinai.Ben_Gurion
|
||||
-- * AIRBASE.Sinai.Beni_Suef
|
||||
-- * AIRBASE.Sinai.Bilbeis_Air_Base
|
||||
-- * AIRBASE.Sinai.Bir_Hasanah
|
||||
-- * AIRBASE.Sinai.Birma_Air_Base
|
||||
-- * AIRBASE.Sinai.Borj_El_Arab_International_Airport
|
||||
-- * AIRBASE.Sinai.Cairo_International_Airport
|
||||
-- * AIRBASE.Sinai.Cairo_West
|
||||
-- * AIRBASE.Sinai.Difarsuwar_Airfield
|
||||
-- * AIRBASE.Sinai.El_Arish
|
||||
-- * AIRBASE.Sinai.El_Gora
|
||||
-- * AIRBASE.Sinai.El_Minya
|
||||
-- * AIRBASE.Sinai.Fayed
|
||||
-- * AIRBASE.Sinai.Gebel_El_Basur_Air_Base
|
||||
-- * AIRBASE.Sinai.Hatzerim
|
||||
-- * AIRBASE.Sinai.Hatzor
|
||||
-- * AIRBASE.Sinai.Hurghada_International_Airport
|
||||
-- * AIRBASE.Sinai.Inshas_Airbase
|
||||
-- * AIRBASE.Sinai.Jiyanklis_Air_Base
|
||||
-- * AIRBASE.Sinai.Kedem
|
||||
-- * AIRBASE.Sinai.Kibrit_Air_Base
|
||||
-- * AIRBASE.Sinai.Kom_Awshim
|
||||
-- * AIRBASE.Sinai.Melez
|
||||
-- * AIRBASE.Sinai.Nevatim
|
||||
-- * AIRBASE.Sinai.Ovda
|
||||
-- * AIRBASE.Sinai.Palmachim
|
||||
-- * AIRBASE.Sinai.Quwaysina
|
||||
-- * AIRBASE.Sinai.Ramon_Airbase
|
||||
-- * AIRBASE.Sinai.Ramon_International_Airport
|
||||
-- * AIRBASE.Sinai.Sde_Dov
|
||||
-- * AIRBASE.Sinai.Sharm_El_Sheikh_International_Airport
|
||||
-- * AIRBASE.Sinai.St_Catherine
|
||||
-- * AIRBASE.Sinai.Tel_Nof
|
||||
-- * AIRBASE.Sinai.Wadi_Abu_Rish
|
||||
-- * AIRBASE.Sinai.Wadi_al_Jandali
|
||||
-- * AIRBASE.SinaiMap.Abu_Rudeis
|
||||
-- * AIRBASE.SinaiMap.Abu_Suwayr
|
||||
-- * AIRBASE.SinaiMap.Al_Bahr_al_Ahmar
|
||||
-- * AIRBASE.SinaiMap.Al_Ismailiyah
|
||||
-- * AIRBASE.SinaiMap.Al_Khatatbah
|
||||
-- * AIRBASE.SinaiMap.Al_Mansurah
|
||||
-- * AIRBASE.SinaiMap.Al_Rahmaniyah_Air_Base
|
||||
-- * AIRBASE.SinaiMap.As_Salihiyah
|
||||
-- * AIRBASE.SinaiMap.AzZaqaziq
|
||||
-- * AIRBASE.SinaiMap.Baluza
|
||||
-- * AIRBASE.SinaiMap.Ben_Gurion
|
||||
-- * AIRBASE.SinaiMap.Beni_Suef
|
||||
-- * AIRBASE.SinaiMap.Bilbeis_Air_Base
|
||||
-- * AIRBASE.SinaiMap.Bir_Hasanah
|
||||
-- * AIRBASE.SinaiMap.Birma_Air_Base
|
||||
-- * AIRBASE.SinaiMap.Borg_El_Arab_International_Airport
|
||||
-- * AIRBASE.SinaiMap.Cairo_International_Airport
|
||||
-- * AIRBASE.SinaiMap.Cairo_West
|
||||
-- * AIRBASE.SinaiMap.Damascus_Intl
|
||||
-- * AIRBASE.SinaiMap.Difarsuwar_Airfield
|
||||
-- * AIRBASE.SinaiMap.El_Arish
|
||||
-- * AIRBASE.SinaiMap.El_Gora
|
||||
-- * AIRBASE.SinaiMap.El_Minya
|
||||
-- * AIRBASE.SinaiMap.Fayed
|
||||
-- * AIRBASE.SinaiMap.Gebel_El_Basur_Air_Base
|
||||
-- * AIRBASE.SinaiMap.Hatzerim
|
||||
-- * AIRBASE.SinaiMap.Hatzor
|
||||
-- * AIRBASE.SinaiMap.Hurghada_International_Airport
|
||||
-- * AIRBASE.SinaiMap.Inshas_Airbase
|
||||
-- * AIRBASE.SinaiMap.Jiyanklis_Air_Base
|
||||
-- * AIRBASE.SinaiMap.Kedem
|
||||
-- * AIRBASE.SinaiMap.Kibrit_Air_Base
|
||||
-- * AIRBASE.SinaiMap.Kom_Awshim
|
||||
-- * AIRBASE.SinaiMap.Melez
|
||||
-- * AIRBASE.SinaiMap.Mezzeh_Air_Base
|
||||
-- * AIRBASE.SinaiMap.Nevatim
|
||||
-- * AIRBASE.SinaiMap.Ovda
|
||||
-- * AIRBASE.SinaiMap.Palmachim
|
||||
-- * AIRBASE.SinaiMap.Quwaysina
|
||||
-- * AIRBASE.SinaiMap.Rafic_Hariri_Intl
|
||||
-- * AIRBASE.SinaiMap.Ramat_David
|
||||
-- * AIRBASE.SinaiMap.Ramon_Airbase
|
||||
-- * AIRBASE.SinaiMap.Ramon_International_Airport
|
||||
-- * AIRBASE.SinaiMap.Sde_Dov
|
||||
-- * AIRBASE.SinaiMap.Sharm_El_Sheikh_International_Airport
|
||||
-- * AIRBASE.SinaiMap.St_Catherine
|
||||
-- * AIRBASE.SinaiMap.Tabuk
|
||||
-- * AIRBASE.SinaiMap.Tel_Nof
|
||||
-- * AIRBASE.SinaiMap.Wadi_Abu_Rish
|
||||
-- * AIRBASE.SinaiMap.Wadi_al_Jandali
|
||||
--
|
||||
-- @field Sinai
|
||||
AIRBASE.Sinai = {
|
||||
@@ -739,9 +771,10 @@ AIRBASE.Sinai = {
|
||||
["Bilbeis_Air_Base"] = "Bilbeis Air Base",
|
||||
["Bir_Hasanah"] = "Bir Hasanah",
|
||||
["Birma_Air_Base"] = "Birma Air Base",
|
||||
["Borj_El_Arab_International_Airport"] = "Borj El Arab International Airport",
|
||||
["Borg_El_Arab_International_Airport"] = "Borg El Arab International Airport",
|
||||
["Cairo_International_Airport"] = "Cairo International Airport",
|
||||
["Cairo_West"] = "Cairo West",
|
||||
["Damascus_Intl"] = "Damascus Intl",
|
||||
["Difarsuwar_Airfield"] = "Difarsuwar Airfield",
|
||||
["El_Arish"] = "El Arish",
|
||||
["El_Gora"] = "El Gora",
|
||||
@@ -757,15 +790,19 @@ AIRBASE.Sinai = {
|
||||
["Kibrit_Air_Base"] = "Kibrit Air Base",
|
||||
["Kom_Awshim"] = "Kom Awshim",
|
||||
["Melez"] = "Melez",
|
||||
["Mezzeh_Air_Base"] = "Mezzeh Air Base",
|
||||
["Nevatim"] = "Nevatim",
|
||||
["Ovda"] = "Ovda",
|
||||
["Palmachim"] = "Palmachim",
|
||||
["Quwaysina"] = "Quwaysina",
|
||||
["Rafic_Hariri_Intl"] = "Rafic Hariri Intl",
|
||||
["Ramat_David"] = "Ramat David",
|
||||
["Ramon_Airbase"] = "Ramon Airbase",
|
||||
["Ramon_International_Airport"] = "Ramon International Airport",
|
||||
["Sde_Dov"] = "Sde Dov",
|
||||
["Sharm_El_Sheikh_International_Airport"] = "Sharm El Sheikh International Airport",
|
||||
["St_Catherine"] = "St Catherine",
|
||||
["Tabuk"] = "Tabuk",
|
||||
["Tel_Nof"] = "Tel Nof",
|
||||
["Wadi_Abu_Rish"] = "Wadi Abu Rish",
|
||||
["Wadi_al_Jandali"] = "Wadi al Jandali",
|
||||
@@ -830,6 +867,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
|
||||
@@ -890,37 +933,51 @@ AIRBASE.Afghanistan = {
|
||||
|
||||
--- Airbases of the Iraq map
|
||||
--
|
||||
-- * AIRBASE.Iraq.Baghdad_International_Airport
|
||||
-- * AIRBASE.Iraq.Sulaimaniyah_International_Airport
|
||||
-- * AIRBASE.Iraq.Al_Sahra_Airport
|
||||
-- * AIRBASE.Iraq.Erbil_International_Airpor
|
||||
-- * AIRBASE.Iraq.Al_Taji_Airport
|
||||
-- * AIRBASE.Iraq.Al_Asad_Airbase
|
||||
-- * AIRBASE.Iraq.Al_Kut_Airbase
|
||||
-- * AIRBASE.Iraq.Al_Sahra_Airport
|
||||
-- * AIRBASE.Iraq.Al_Salam_Airbase
|
||||
-- * AIRBASE.Iraq.Balad_Airbase
|
||||
-- * AIRBASE.Iraq.Kirkuk_International_Airport
|
||||
-- * AIRBASE.Iraq.Bashur_Airport
|
||||
-- * AIRBASE.Iraq.Al_Taji_Airport
|
||||
-- * AIRBASE.Iraq.Al_Taquddum_Airport
|
||||
-- * AIRBASE.Iraq.Qayyarah_Airfield_West
|
||||
-- * AIRBASE.Iraq.Baghdad_International_Airport
|
||||
-- * AIRBASE.Iraq.Balad_Airbase
|
||||
-- * AIRBASE.Iraq.Bashur_Airport
|
||||
-- * AIRBASE.Iraq.Erbil_International_Airport
|
||||
-- * AIRBASE.Iraq.Sulaimaniyah_International_Airport
|
||||
-- * AIRBASE.Iraq.H2_Airbase
|
||||
-- * AIRBASE.Iraq.H3_Main_Airbase
|
||||
-- * AIRBASE.Iraq.H3_Northwest_Airbase
|
||||
-- * AIRBASE.Iraq.H3_Southwest_Airbase
|
||||
-- * AIRBASE.Iraq.K1_Base
|
||||
-- * AIRBASE.Iraq.Kirkuk_International_Airport
|
||||
-- * AIRBASE.Iraq.Mosul_International_Airport
|
||||
-- * AIRBASE.Iraq.Qayyarah_Airfield_West
|
||||
-- * AIRBASE.Iraq.Sulaimaniyah_International_Airport
|
||||
--
|
||||
-- @field Iraq
|
||||
AIRBASE.Iraq = {
|
||||
["Baghdad_International_Airport"] = "Baghdad International Airport",
|
||||
["Sulaimaniyah_International_Airport"] = "Sulaimaniyah International Airport",
|
||||
["Al_Sahra_Airport"] = "Al-Sahra Airport",
|
||||
["Erbil_International_Airport"] = "Erbil International Airport",
|
||||
["Al_Taji_Airport"] = "Al-Taji Airport",
|
||||
["Al_Asad_Airbase"] = "Al-Asad Airbase",
|
||||
["Al_Kut_Airport"] = "Al-Kut Airport",
|
||||
["Al_Sahra_Airport"] = "Al-Sahra Airport",
|
||||
["Al_Salam_Airbase"] = "Al-Salam Airbase",
|
||||
["Balad_Airbase"] = "Balad Airbase",
|
||||
["Kirkuk_International_Airport"] = "Kirkuk International Airport",
|
||||
["Bashur_Airport"] = "Bashur Airport",
|
||||
["Al_Taji_Airport"] = "Al-Taji Airport",
|
||||
["Al_Taquddum_Airport"] = "Al-Taquddum Airport",
|
||||
["Qayyarah_Airfield_West"] = "Qayyarah Airfield West",
|
||||
["Baghdad_International_Airport"] = "Baghdad International Airport",
|
||||
["Balad_Airbase"] = "Balad Airbase",
|
||||
["Bashur_Airport"] = "Bashur Airport",
|
||||
["Erbil_International_Airport"] = "Erbil International Airport",
|
||||
["H2_Airbase"] = "H-2 Airbase",
|
||||
["H3_Main_Airbase"] = "H-3 Main Airbase",
|
||||
["H3_Northwest_Airbase"] = "H-3 Northwest Airbase",
|
||||
["H3_Southwest_Airbase"] = "H-3 Southwest Airbase",
|
||||
["K1_Base"] = "K1 Base",
|
||||
["Kirkuk_International_Airport"] = "Kirkuk International Airport",
|
||||
["Mosul_International_Airport"] = "Mosul International Airport",
|
||||
["Qayyarah_Airfield_West"] = "Qayyarah Airfield West",
|
||||
["Sulaimaniyah_International_Airport"] = "Sulaimaniyah International Airport",
|
||||
}
|
||||
|
||||
|
||||
--- Airbases of the Germany Cold War map
|
||||
-- * AIRBASE.GermanyCW.Airracing_Frankfurt
|
||||
-- * AIRBASE.GermanyCW.Airracing_Frankfurt
|
||||
@@ -1434,7 +1491,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
|
||||
@@ -1517,6 +1574,17 @@ end
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Get the true airbase center as seen in the ME. The position returned by the dcs object is is wrong and often at the start of the runway.
|
||||
-- @return DCS#Vec2 The center of the true center of the airbase if it contains runways, otherwise the default DCS object position.
|
||||
function AIRBASE:GetVec2()
|
||||
local runways = self:GetRunways()
|
||||
if runways and #runways > 0 then
|
||||
return runways[1].center:GetVec2()
|
||||
end
|
||||
return self:GetCoordinate():GetVec2()
|
||||
end
|
||||
|
||||
--- Get the category of this airbase. This is only a debug function because DCS 2.9 incorrectly returns heliports as airdromes.
|
||||
-- @param #AIRBASE self
|
||||
function AIRBASE:_GetCategory()
|
||||
@@ -2601,6 +2669,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 +2982,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 +2998,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',
|
||||
@@ -2846,7 +2855,7 @@ do -- Route methods
|
||||
-- @param Core.Zone#ZONE Zone The zone where to route to.
|
||||
-- @param #boolean Randomize Defines whether to target point gets randomized within the Zone.
|
||||
-- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h.
|
||||
-- @param Core.Base#FORMATION Formation The formation string.
|
||||
-- @param DCS#FORMATION Formation The formation string.
|
||||
function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation )
|
||||
self:F2( Zone )
|
||||
|
||||
@@ -2906,7 +2915,7 @@ do -- Route methods
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param DCS#Vec2 Vec2 The Vec2 where to route to.
|
||||
-- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h.
|
||||
-- @param Core.Base#FORMATION Formation The formation string.
|
||||
-- @param DCS#FORMATION Formation The formation string.
|
||||
function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
@@ -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
|
||||
@@ -4134,7 +4163,7 @@ function CONTROLLABLE:OptionRestrictBurner( RestrictBurner )
|
||||
|
||||
end
|
||||
|
||||
--- Sets Controllable Option for A2A attack range for AIR FIGHTER units.
|
||||
--- [AIR] Sets Controllable Option for A2A attack range for AIR FIGHTER units.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number range Defines the range
|
||||
-- @return #CONTROLLABLE self
|
||||
@@ -4159,6 +4188,66 @@ function CONTROLLABLE:OptionAAAttackRange( range )
|
||||
return nil
|
||||
end
|
||||
|
||||
--- [GROUND/AAA] Sets Controllable Option for Ground AAA minimum firing height.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number meters The minimum height in meters.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionAAAMinFiringHeightMeters(meters)
|
||||
self:F2( { self.ControllableName } )
|
||||
local meters = meters or 20
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
if Controller then
|
||||
if self:IsGround() then
|
||||
self:SetOption(27, meters)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--- [GROUND/AAA] Sets Controllable Option for Ground AAA maximum firing height.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number meters The maximum height in meters.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionAAAMaxFiringHeightMeters(meters)
|
||||
self:F2( { self.ControllableName } )
|
||||
local meters = meters or 1000
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
if Controller then
|
||||
if self:IsGround() then
|
||||
self:SetOption(29, meters)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--- [GROUND/AAA] Sets Controllable Option for Ground AAA minimum firing height.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number feet The minimum height in feet.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionAAAMinFiringHeightFeet(feet)
|
||||
self:F2( { self.ControllableName } )
|
||||
local feet = feet or 60
|
||||
return self:OptionAAAMinFiringHeightMeters(UTILS.FeetToMeters(feet))
|
||||
end
|
||||
|
||||
--- [GROUND/AAA] Sets Controllable Option for Ground AAA maximum firing height.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number feet The maximum height in feet.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionAAAMaxFiringHeightfeet(feet)
|
||||
self:F2( { self.ControllableName } )
|
||||
local feet = feet or 3000
|
||||
return self:OptionAAAMaxFiringHeightMeters(UTILS.FeetToMeters(feet))
|
||||
end
|
||||
|
||||
--- Defines the range at which a GROUND unit/group is allowed to use its weapons automatically.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #number EngageRange Engage range limit in percent (a number between 0 and 100). Default 100.
|
||||
@@ -4183,6 +4272,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`
|
||||
|
||||
@@ -108,6 +108,9 @@ DYNAMICCARGO.State = {
|
||||
-- @type DYNAMICCARGO.AircraftTypes
|
||||
DYNAMICCARGO.AircraftTypes = {
|
||||
["CH-47Fbl1"] = "CH-47Fbl1",
|
||||
["Mi-8MTV2"] = "Mi-8MTV2",
|
||||
["Mi-8MT"] = "Mi-8MT",
|
||||
["C-130J-30"] = "C-130J-30",
|
||||
}
|
||||
|
||||
--- Helo types possible.
|
||||
@@ -120,17 +123,36 @@ DYNAMICCARGO.AircraftDimensions = {
|
||||
["length"] = 11,
|
||||
["ropelength"] = 30,
|
||||
},
|
||||
["Mi-8MTV2"] = {
|
||||
["width"] = 6,
|
||||
["height"] = 6,
|
||||
["length"] = 15,
|
||||
["ropelength"] = 30,
|
||||
},
|
||||
["Mi-8MT"] = {
|
||||
["width"] = 6,
|
||||
["height"] = 6,
|
||||
["length"] = 15,
|
||||
["ropelength"] = 30,
|
||||
},
|
||||
["C-130J-30"] = {
|
||||
["width"] = 4,
|
||||
["height"] = 12,
|
||||
["length"] = 35,
|
||||
["ropelength"] = 0,
|
||||
},
|
||||
}
|
||||
|
||||
--- DYNAMICCARGO class version.
|
||||
-- @field #string version
|
||||
DYNAMICCARGO.version="0.0.7"
|
||||
DYNAMICCARGO.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot...
|
||||
-- DONE: Added Mi-8 type and dimensions
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@@ -512,7 +534,10 @@ function DYNAMICCARGO:_UpdatePosition()
|
||||
---------------
|
||||
-- REMOVED Cargo
|
||||
---------------
|
||||
if self.timer and self.timer:IsRunning() then self.timer:Stop() end
|
||||
if self.timer and self.timer:IsRunning() then
|
||||
self.timer:Stop()
|
||||
self.timer=nil
|
||||
end
|
||||
self:T(self.lid.." dead! " ..self.CargoState.."-> REMOVED")
|
||||
self.CargoState = DYNAMICCARGO.State.REMOVED
|
||||
_DATABASE:CreateEventDynamicCargoRemoved(self)
|
||||
@@ -520,6 +545,24 @@ function DYNAMICCARGO:_UpdatePosition()
|
||||
return self
|
||||
end
|
||||
|
||||
--- [USER] Destroy a DYNAMICCARGO object.
|
||||
-- @param #DYNAMICCARGO self
|
||||
-- @param #boolean GenerateEvent Set to false to remove an item silently. Defaults to true.
|
||||
-- @return #boolean Return Returns nil if the object could not be found, else returns true.
|
||||
function DYNAMICCARGO:Destroy(GenerateEvent)
|
||||
local DCSObject = self:GetDCSObject()
|
||||
if DCSObject then
|
||||
local GenerateEvent = (GenerateEvent ~= nil and GenerateEvent == false) and false or true
|
||||
if GenerateEvent and GenerateEvent == true then
|
||||
self:CreateEventDead( timer.getTime(), DCSObject )
|
||||
end
|
||||
DCSObject:destroy()
|
||||
self:_UpdatePosition()
|
||||
return true
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--- [Internal] Track helos for loaded/unloaded decision making.
|
||||
-- @param Wrapper.Client#CLIENT client
|
||||
-- @return #boolean IsIn
|
||||
|
||||
@@ -230,6 +230,8 @@ GROUP.Attribute = {
|
||||
GROUND_EWR="Ground_EWR",
|
||||
GROUND_AAA="Ground_AAA",
|
||||
GROUND_SAM="Ground_SAM",
|
||||
GROUND_SHORAD="Ground_SHORAD",
|
||||
GROUND_BALLISTICMISSILE="Ground_BallisticMissile",
|
||||
GROUND_OTHER="Ground_OtherGround",
|
||||
NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier",
|
||||
NAVAL_WARSHIP="Naval_WarShip",
|
||||
@@ -1056,9 +1058,12 @@ function GROUP:GetTypeName()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local GroupTypeName = DCSGroup:getUnit(1):getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return( GroupTypeName )
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local GroupTypeName = unit:getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return( GroupTypeName )
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -1073,9 +1078,12 @@ function GROUP:GetNatoReportingName()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local GroupTypeName = DCSGroup:getUnit(1):getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return UTILS.GetReportingName(GroupTypeName)
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local GroupTypeName = unit:getTypeName()
|
||||
--self:T3( GroupTypeName )
|
||||
return UTILS.GetReportingName(GroupTypeName)
|
||||
end
|
||||
end
|
||||
|
||||
return "Bogey"
|
||||
@@ -1091,9 +1099,12 @@ function GROUP:GetPlayerName()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local PlayerName = DCSGroup:getUnit(1):getPlayerName()
|
||||
--self:T3( PlayerName )
|
||||
return( PlayerName )
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local PlayerName = unit:getPlayerName()
|
||||
--self:T3( PlayerName )
|
||||
return( PlayerName )
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -1109,9 +1120,12 @@ function GROUP:GetCallsign()
|
||||
local DCSGroup = self:GetDCSObject()
|
||||
|
||||
if DCSGroup then
|
||||
local GroupCallSign = DCSGroup:getUnit(1):getCallsign()
|
||||
--self:T3( GroupCallSign )
|
||||
return GroupCallSign
|
||||
local unit = DCSGroup:getUnit(1)
|
||||
if unit then
|
||||
local GroupCallSign = unit:getCallsign()
|
||||
--self:T3( GroupCallSign )
|
||||
return GroupCallSign
|
||||
end
|
||||
end
|
||||
|
||||
BASE:E( { "Cannot GetCallsign", Positionable = self, Alive = self:IsAlive() } )
|
||||
@@ -2230,6 +2244,10 @@ function GROUP:Respawn( Template, Reset )
|
||||
|
||||
--UTILS.PrintTableToLog(Template)
|
||||
|
||||
if self.ValidateAndRepositionGroundUnits then
|
||||
UTILS.ValidateAndRepositionGroundUnits(Template.units)
|
||||
end
|
||||
|
||||
-- Spawn new group.
|
||||
self:ScheduleOnce(0.1,_DATABASE.Spawn,_DATABASE,Template)
|
||||
--_DATABASE:Spawn(Template)
|
||||
@@ -2638,6 +2656,8 @@ function GROUP:GetAttribute()
|
||||
local artillery=self:HasAttribute("Artillery")
|
||||
local tank=self:HasAttribute("Old Tanks") or self:HasAttribute("Modern Tanks") or self:HasAttribute("Tanks")
|
||||
local aaa=self:HasAttribute("AAA") and (not self:HasAttribute("SAM elements"))
|
||||
local ballisticMissile=artillery and self:HasAttribute("SS_missile")
|
||||
local shorad=self:HasAttribute("SR SAM")
|
||||
local ewr=self:HasAttribute("EWR")
|
||||
local ifv=self:HasAttribute("IFV")
|
||||
local sam=self:HasAttribute("SAM elements") or self:HasAttribute("Optical Tracker")
|
||||
@@ -2679,6 +2699,8 @@ function GROUP:GetAttribute()
|
||||
attribute=GROUP.Attribute.GROUND_SAM
|
||||
elseif aaa then
|
||||
attribute=GROUP.Attribute.GROUND_AAA
|
||||
elseif artillery and ballisticMissile then
|
||||
attribute=GROUP.Attribute.GROUND_BALLISTICMISSILE
|
||||
elseif artillery then
|
||||
attribute=GROUP.Attribute.GROUND_ARTILLERY
|
||||
elseif tank then
|
||||
@@ -3191,3 +3213,60 @@ function GROUP:IsAAA()
|
||||
end
|
||||
return isAAA
|
||||
end
|
||||
|
||||
--- This function uses Disposition and other fallback logic to find better ground positions for ground units.
|
||||
--- NOTE: This is not a spawn randomizer.
|
||||
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table.
|
||||
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||
--- Uses UTILS.ValidateAndRepositionGroundUnits.
|
||||
-- @param #GROUP self
|
||||
-- @param #boolean Enabled Enable/disable the feature.
|
||||
function GROUP:SetValidateAndRepositionGroundUnits(Enabled)
|
||||
self.ValidateAndRepositionGroundUnits = Enabled
|
||||
end
|
||||
|
||||
|
||||
--- Get the bounding box of the group combining UNIT:GetBoundingBox() units.
|
||||
-- @param #GROUP self
|
||||
-- @return DCS#Box3 The bounding box of the GROUP.
|
||||
-- @return #nil The GROUP does not have any alive units.
|
||||
function GROUP:GetBoundingBox()
|
||||
local bbox = { min = { x = math.huge, y = math.huge, z = math.huge },
|
||||
max = { x = -math.huge, y = -math.huge, z = -math.huge }
|
||||
}
|
||||
|
||||
local Units = self:GetUnits() or {}
|
||||
if #Units == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
for _, unit in pairs(Units) do
|
||||
if unit and unit:IsAlive() then
|
||||
local ubox = unit:GetBoundingBox()
|
||||
|
||||
if ubox then
|
||||
if ubox.min.x < bbox.min.x then
|
||||
bbox.min.x = ubox.min.x
|
||||
end
|
||||
if ubox.min.y < bbox.min.y then
|
||||
bbox.min.y = ubox.min.y
|
||||
end
|
||||
if ubox.min.z < bbox.min.z then
|
||||
bbox.min.z = ubox.min.z
|
||||
end
|
||||
|
||||
if ubox.max.x > bbox.max.x then
|
||||
bbox.max.x = ubox.max.x
|
||||
end
|
||||
if ubox.max.y > bbox.max.y then
|
||||
bbox.max.y = ubox.max.y
|
||||
end
|
||||
if ubox.max.z > bbox.max.z then
|
||||
bbox.max.z = ubox.max.z
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return bbox
|
||||
end
|
||||
|
||||
@@ -170,6 +170,27 @@ function IDENTIFIABLE:GetCoalition()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns true if identifiable is of RED coalition.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return #boolean If the identifiable is red.
|
||||
function IDENTIFIABLE:IsRed()
|
||||
return self:GetCoalition() == coalition.side.RED
|
||||
end
|
||||
|
||||
--- Returns true if identifiable is of BLUE coalition.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return #boolean If the identifiable is blue.
|
||||
function IDENTIFIABLE:IsBlue()
|
||||
return self:GetCoalition() == coalition.side.BLUE
|
||||
end
|
||||
|
||||
--- Returns true if identifiable is of NEUTRAL coalition.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return #boolean If the identifiable is neutral.
|
||||
function IDENTIFIABLE:IsNeutral()
|
||||
return self:GetCoalition() == coalition.side.NEUTRAL
|
||||
end
|
||||
|
||||
--- Returns the name of the coalition of the Identifiable.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return #string The name of the coalition.
|
||||
|
||||
@@ -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() } )
|
||||
@@ -359,15 +361,17 @@ function POSITIONABLE:GetCoord()
|
||||
-- Get the current position.
|
||||
local PositionableVec3 = self:GetVec3()
|
||||
|
||||
if self.coordinate then
|
||||
-- Update COORDINATE from 3D vector.
|
||||
self.coordinate:UpdateFromVec3( PositionableVec3 )
|
||||
else
|
||||
-- New COORDINATE.
|
||||
self.coordinate = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||
end
|
||||
if PositionableVec3 then
|
||||
if self.coordinate then
|
||||
-- Update COORDINATE from 3D vector.
|
||||
self.coordinate:UpdateFromVec3( PositionableVec3 )
|
||||
else
|
||||
-- New COORDINATE.
|
||||
self.coordinate = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||
end
|
||||
|
||||
return self.coordinate
|
||||
return self.coordinate
|
||||
end
|
||||
end
|
||||
|
||||
-- Error message.
|
||||
@@ -388,13 +392,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.
|
||||
@@ -1861,6 +1865,7 @@ do -- Cargo
|
||||
["HL_DSHK"] = 6*POSITIONABLE.DefaultInfantryWeight,
|
||||
["CCKW_353"] = 16*POSITIONABLE.DefaultInfantryWeight, --GMC CCKW 2½-ton 6×6 truck, estimating 16 soldiers,
|
||||
["MaxxPro_MRAP"] = 7*POSITIONABLE.DefaultInfantryWeight,
|
||||
["Sd_Kfz_251"] = 10*POSITIONABLE.DefaultInfantryWeight,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ function STATIC:Register( StaticName )
|
||||
else
|
||||
self:E(string.format("Static object %s does not exist!", tostring(self.StaticName)))
|
||||
end
|
||||
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -86,6 +89,30 @@ function STATIC:GetLife()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get the position of the STATIC even if it is not alive.
|
||||
-- @param #STATIC self
|
||||
-- @return DCS#Vec2 The 2D point vector of the POSITIONABLE.
|
||||
-- @return #nil The position was not cached.
|
||||
function STATIC:GetVec2Cached()
|
||||
local vec2 = self:GetVec2()
|
||||
if not vec2 and self._vec3 then
|
||||
vec2 = {x = self._vec3.x, y = self._vec3.z }
|
||||
end
|
||||
return vec2
|
||||
end
|
||||
|
||||
--- Get the position of the STATIC even if it is not alive.
|
||||
-- @param #STATIC self
|
||||
-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE.
|
||||
-- @return #nil The position was not cached.
|
||||
function STATIC:GetVec3Cached()
|
||||
local vec3 = self:GetVec3()
|
||||
if not vec3 and self._vec3 then
|
||||
vec3 = self._vec3
|
||||
end
|
||||
return vec3
|
||||
end
|
||||
|
||||
--- Finds a STATIC from the _DATABASE using a DCSStatic object.
|
||||
-- @param #STATIC self
|
||||
-- @param DCS#StaticObject DCSStatic An existing DCS Static object reference.
|
||||
@@ -232,6 +259,8 @@ function STATIC:SpawnAt(Coordinate, Heading, Delay)
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName)
|
||||
|
||||
SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName )
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
end
|
||||
|
||||
@@ -255,6 +284,8 @@ function STATIC:ReSpawn(CountryID, Delay)
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, CountryID)
|
||||
|
||||
SpawnStatic:Spawn(nil, self.StaticName)
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
end
|
||||
|
||||
@@ -278,6 +309,8 @@ function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, self:GetCountry())
|
||||
|
||||
SpawnStatic:SpawnFromCoordinate(Coordinate, Heading, self.StaticName)
|
||||
-- Cache position
|
||||
self._vec3 = self:GetVec3()
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -753,7 +753,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E("File for Liquids could not be found: "..tostring(Path).."\\"..tostring(Filename"_Liquids.csv"))
|
||||
self:E("File for Liquids could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Liquids.csv")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -773,7 +773,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E("File for Aircraft could not be found: "..tostring(Path).."\\"..tostring(Filename"_Aircraft.csv"))
|
||||
self:E("File for Aircraft could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Aircraft.csv")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -805,7 +805,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E("File for Weapons could not be found: "..tostring(Path).."\\"..tostring(Filename"_Weapons.csv"))
|
||||
self:E("File for Weapons could not be found: "..tostring(Path).."\\"..tostring(Filename).."_Weapons.csv")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -377,6 +377,10 @@ function UNIT:ReSpawnAt(Coordinate, Heading)
|
||||
|
||||
--self:T( SpawnGroupTemplate )
|
||||
|
||||
if self.ValidateAndRepositionGroundUnits then
|
||||
UTILS.ValidateAndRepositionGroundUnits(SpawnGroupTemplate.units)
|
||||
end
|
||||
|
||||
_DATABASE:Spawn(SpawnGroupTemplate)
|
||||
end
|
||||
|
||||
@@ -1924,3 +1928,28 @@ 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
|
||||
|
||||
--- Set the carrier illumination mode. -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY
|
||||
-- @param #UNIT self
|
||||
-- @param #number Mode Illumination mode, can be -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY
|
||||
function UNIT:SetCarrierIlluminationMode(Mode)
|
||||
UTILS.SetCarrierIlluminationMode(self:GetID(), Mode)
|
||||
end
|
||||
|
||||
--- This function uses Disposition and other fallback logic to find better ground positions for ground units.
|
||||
--- NOTE: This is not a spawn randomizer.
|
||||
--- It will try to find clear ground locations avoiding trees, water, roads, runways, map scenery, statics and other units in the area and modifies the provided positions table.
|
||||
--- Maintains the original layout and unit positions as close as possible by searching for the next closest valid position to each unit.
|
||||
--- Uses UTILS.ValidateAndRepositionGroundUnits.
|
||||
-- @param #UNIT self
|
||||
-- @param #boolean Enabled Enable/disable the feature.
|
||||
function UNIT:SetValidateAndRepositionGroundUnits(Enabled)
|
||||
self.ValidateAndRepositionGroundUnits = Enabled
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user