mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-16 07:56:35 +00:00
Compare commits
233 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 30cf1f5713 | |||
| 33f7a7084c | |||
| 07a14bc176 | |||
| 8ca9474c1c | |||
| 2047e818ef | |||
| 801b4f01b6 | |||
| 37a5f68339 | |||
| 6058160160 | |||
| 479dfc28b9 | |||
| b28e66fe6d | |||
| 8392788cdb | |||
| 4a1b23c52a | |||
| 1965e24860 | |||
| 55242edbde | |||
| 2c5d9f043e | |||
| 2b2acbe244 | |||
| 7d4e103660 | |||
| 3da6187782 | |||
| 0bd79d518f | |||
| 86798ae9ea | |||
| dfc63de745 | |||
| 2830e6d199 | |||
| 8c07573f8f | |||
| f3af0262df | |||
| d7841b47a5 | |||
| 0f270a6a35 | |||
| 92db68c36b | |||
| 8432f46e48 | |||
| faccee88e7 | |||
| e8246b3b90 | |||
| eb4e7b9281 | |||
| e91bcdfe5e | |||
| 1f1a068d45 | |||
| a57c0a8c7d | |||
| 1e2190a6cc | |||
| 1644c1dc5b | |||
| 5fc3798c42 | |||
| 512c3c57e9 | |||
| 3a95e75c2d | |||
| fae81cdb1b | |||
| dbae37f151 | |||
| f7d58a0b76 | |||
| 08fb458aa4 | |||
| 2e0d1fd90f | |||
| 3694e9649d | |||
| 2c79fa6492 | |||
| 69e6497655 | |||
| aca713b8d9 | |||
| ef8c7c9084 | |||
| e4eaf72769 | |||
| 5138ced630 | |||
| 534f445f8c | |||
| a2da4f0e77 | |||
| b2cc3e5329 | |||
| efde321616 | |||
| 3a61581608 | |||
| 3a10f0b946 | |||
| 6dc6972bdb | |||
| 5910c9502a | |||
| 405235a59d | |||
| bd8ac9551c | |||
| 9c148625e4 | |||
| a08d82a3d9 | |||
| 48b51f21de | |||
| c850ea10f5 | |||
| 3260279cb7 | |||
| 2fcef1f277 | |||
| 1e60a0a32a | |||
| 7707522ce5 | |||
| 91e26adc6a | |||
| 146f869aaa | |||
| dc863be38a | |||
| 0bd35727f4 | |||
| 5183fcc316 | |||
| bf7596521c | |||
| a85b6c960c | |||
| 8cb91477cf | |||
| a8a69fdbca | |||
| a1aebf0575 | |||
| 0f42218681 | |||
| 5404f9ef19 | |||
| 8a84be19df | |||
| fd4ea81e46 | |||
| 025bd3237c | |||
| 3df79aedb1 | |||
| 4141aa35ba | |||
| 6e45ee558e | |||
| e867ce4c73 | |||
| db138be5f3 | |||
| 5ae6495e69 | |||
| d8281b0103 | |||
| 58f1bc5531 | |||
| 935b52c489 | |||
| aace98545a | |||
| f39236c8fd | |||
| 43b4a6834b | |||
| aa3978b04d | |||
| b51e758516 | |||
| 4a870d0183 | |||
| 5be1832c09 | |||
| 362652ac6c | |||
| aec69884dc | |||
| 47ddc64239 | |||
| 2a32be40f6 | |||
| 8fb4d4c7c6 | |||
| b17748cfeb | |||
| b5524b9a69 | |||
| ec0ff7afcd | |||
| c761d5020b | |||
| d0cf68c2e2 | |||
| 3beb98a5e9 | |||
| dd83ebe0e2 | |||
| 6fdf3957bd | |||
| 608fa1ca6c | |||
| f3d586d455 | |||
| c2f0ce0fa2 | |||
| 8535c39c2c | |||
| da8f023f5b | |||
| 354490d149 | |||
| c5b0be5d21 | |||
| 7123562f85 | |||
| 6301f5a939 | |||
| 5e8676cf8a | |||
| b320ba597a | |||
| 12d16f355b | |||
| f4264cd149 | |||
| 65d1c4187e | |||
| 58b169cb03 | |||
| 04fcb985fe | |||
| 5414adc8d8 | |||
| 95210366e9 | |||
| f73dc6c3be | |||
| 74383e3111 | |||
| 3f8954d21d | |||
| ebf393c58b | |||
| cda1432d04 | |||
| 09e5fca1a5 | |||
| 9c3c27f809 | |||
| 03275938e7 | |||
| a90e321a91 | |||
| e38d73df8b | |||
| 7df90b2d30 | |||
| e531f12f94 | |||
| a917ee8f1e | |||
| 44f3c776eb | |||
| 5d3f5dac1e | |||
| 873879ff79 | |||
| 2f46a63041 | |||
| 6c1907f7e0 | |||
| f43dd389e2 | |||
| 42ecdd3b14 | |||
| 297164a0ee | |||
| 323f09b06c | |||
| e003b91bbe | |||
| efb1d79e77 | |||
| ee23daa651 | |||
| e590701c01 | |||
| 9f1777ca9b | |||
| f1636fc5a9 | |||
| db053398d2 | |||
| 527c4d0de4 | |||
| 2479147fd9 | |||
| 7b7a8c1bab | |||
| 417caf1b62 | |||
| 2ff630d394 | |||
| b6d725920a | |||
| cc76851614 | |||
| c30d517a00 | |||
| 27fe314c1e | |||
| 2c12cfe4fd | |||
| 9adf342dd8 | |||
| facac82130 | |||
| c96249906e | |||
| 3e095711f4 | |||
| ca1ddb4013 | |||
| 8169235d2f | |||
| 0a56624657 | |||
| 4553785918 | |||
| 78b3efcf00 | |||
| 67cb844550 | |||
| 1b169f007c | |||
| 8efcad123c | |||
| b9cf1e46af | |||
| 47409b11cb | |||
| 4a04d7cce7 | |||
| 5ef6383c63 | |||
| 35f15435a3 | |||
| 38dcd04334 | |||
| b32a8a2899 | |||
| 8cac4dbf9e | |||
| ef2bec72a1 | |||
| 03c3a20b1b | |||
| 4c97d966a2 | |||
| f075c02db5 | |||
| 32e61a7a09 | |||
| 674c6eec81 | |||
| da535eaddc | |||
| c75c3d8777 | |||
| 4fa63986dc | |||
| 029f7a3f5c | |||
| eb6eba25f3 | |||
| e9194c59f4 | |||
| c8d693c8e7 | |||
| 72d8b29699 | |||
| 2341014882 | |||
| eb15fadcfe | |||
| 1e7203320f | |||
| e3b587aa95 | |||
| 13fa8f373e | |||
| c3dc055fb2 | |||
| 4e024f7173 | |||
| 1248006f3d | |||
| b318e8ae13 | |||
| 1af4d44ca5 | |||
| 7e963bef41 | |||
| 933000ffc7 | |||
| 9b217e1c97 | |||
| 324f4944b4 | |||
| b9d738c1ad | |||
| f735f1eb53 | |||
| 7149226283 | |||
| 4164a5288a | |||
| 1992276b07 | |||
| 21a7023b7b | |||
| bd054b26c0 | |||
| f094716b73 | |||
| b3100d2f5e | |||
| 4b1888a34d | |||
| f4cd214823 | |||
| b9be3aa7f8 | |||
| bb6db2b7f8 | |||
| fd2dacaefb | |||
| cc60e85901 |
@@ -20,7 +20,7 @@
|
|||||||
--
|
--
|
||||||
-- @module Core.ClientMenu
|
-- @module Core.ClientMenu
|
||||||
-- @image Core_Menu.JPG
|
-- @image Core_Menu.JPG
|
||||||
-- last change: Jan 2025
|
-- last change: Sept 2025
|
||||||
|
|
||||||
-- TODO
|
-- TODO
|
||||||
----------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------
|
||||||
@@ -417,7 +417,7 @@ end
|
|||||||
CLIENTMENUMANAGER = {
|
CLIENTMENUMANAGER = {
|
||||||
ClassName = "CLIENTMENUMANAGER",
|
ClassName = "CLIENTMENUMANAGER",
|
||||||
lid = "",
|
lid = "",
|
||||||
version = "0.1.6",
|
version = "0.1.7",
|
||||||
name = nil,
|
name = nil,
|
||||||
clientset = nil,
|
clientset = nil,
|
||||||
menutree = {},
|
menutree = {},
|
||||||
@@ -806,6 +806,16 @@ function CLIENTMENUMANAGER:ResetMenuComplete()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Remove the entry and all entries below the given entry from the client's F10 menus.
|
||||||
|
-- @param #CLIENTMENUMANAGER self
|
||||||
|
-- @param #CLIENTMENU Entry The entry to remove
|
||||||
|
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client.
|
||||||
|
-- @return #CLIENTMENUMANAGER self
|
||||||
|
function CLIENTMENUMANAGER:DeleteEntry(Entry,Client)
|
||||||
|
self:T(self.lid.."DeleteEntry")
|
||||||
|
return self:DeleteF10Entry(Entry,Client)
|
||||||
|
end
|
||||||
|
|
||||||
--- Remove the entry and all entries below the given entry from the client's F10 menus.
|
--- Remove the entry and all entries below the given entry from the client's F10 menus.
|
||||||
-- @param #CLIENTMENUMANAGER self
|
-- @param #CLIENTMENUMANAGER self
|
||||||
-- @param #CLIENTMENU Entry The entry to remove
|
-- @param #CLIENTMENU Entry The entry to remove
|
||||||
|
|||||||
@@ -577,13 +577,19 @@ do -- Zones and Pathlines
|
|||||||
-- For a rectangular polygon drawing, we have the width (y) and height (x).
|
-- For a rectangular polygon drawing, we have the width (y) and height (x).
|
||||||
local w=objectData.width
|
local w=objectData.width
|
||||||
local h=objectData.height
|
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 sinRot = math.sin(rotation)
|
||||||
local points={}
|
local cosRot = math.cos(rotation)
|
||||||
points[1]={x=vec2.x-h/2, y=vec2.y+w/2} --Upper left
|
local dx = h / 2
|
||||||
points[2]={x=vec2.x+h/2, y=vec2.y+w/2} --Upper right
|
local dy = w / 2
|
||||||
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 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")
|
--local coord=COORDINATE:NewFromVec2(vec2):MarkToAll("MapX, MapY")
|
||||||
|
|
||||||
|
|||||||
@@ -1508,7 +1508,9 @@ function EVENT:onEvent( Event )
|
|||||||
else
|
else
|
||||||
if Event.place:isExist() and Object.getCategory(Event.place) ~= Object.Category.SCENERY then
|
if Event.place:isExist() and Object.getCategory(Event.place) ~= Object.Category.SCENERY then
|
||||||
Event.Place=AIRBASE:Find(Event.place)
|
Event.Place=AIRBASE:Find(Event.place)
|
||||||
Event.PlaceName=Event.Place:GetName()
|
if Event.Place then
|
||||||
|
Event.PlaceName=Event.Place:GetName()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -777,7 +777,9 @@ do -- COORDINATE
|
|||||||
-- @return DCS#Vec2 Vec2
|
-- @return DCS#Vec2 Vec2
|
||||||
function COORDINATE:GetRandomVec2InRadius( OuterRadius, InnerRadius )
|
function COORDINATE:GetRandomVec2InRadius( OuterRadius, InnerRadius )
|
||||||
self:F2( { OuterRadius, InnerRadius } )
|
self:F2( { OuterRadius, InnerRadius } )
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
local Theta = 2 * math.pi * math.random()
|
local Theta = 2 * math.pi * math.random()
|
||||||
local Radials = math.random() + math.random()
|
local Radials = math.random() + math.random()
|
||||||
if Radials > 1 then
|
if Radials > 1 then
|
||||||
@@ -1635,6 +1637,7 @@ do -- COORDINATE
|
|||||||
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then
|
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then
|
||||||
RoutePoint.linkUnit = AirbaseID
|
RoutePoint.linkUnit = AirbaseID
|
||||||
RoutePoint.helipadId = AirbaseID
|
RoutePoint.helipadId = AirbaseID
|
||||||
|
RoutePoint.airdromeId = airbase:IsAirdrome() and AirbaseID or nil
|
||||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||||
RoutePoint.airdromeId = AirbaseID
|
RoutePoint.airdromeId = AirbaseID
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -4691,8 +4691,8 @@ do -- SET_CLIENT
|
|||||||
-- @param #SET_CLIENT self
|
-- @param #SET_CLIENT self
|
||||||
-- @return #SET_CLIENT self
|
-- @return #SET_CLIENT self
|
||||||
function SET_CLIENT:HandleCASlots()
|
function SET_CLIENT:HandleCASlots()
|
||||||
self:HandleEvent(EVENTS.PlayerEnterUnit,SET_CLIENT._EventPlayerEnterUnit)
|
self:HandleEvent(EVENTS.PlayerEnterUnit,self._EventPlayerEnterUnit)
|
||||||
self:HandleEvent(EVENTS.PlayerLeaveUnit,SET_CLIENT._EventPlayerLeaveUnit)
|
--self:HandleEvent(EVENTS.PlayerLeaveUnit,self._EventPlayerLeaveUnit) -- Already set in :FilterStart()
|
||||||
self:FilterFunction(function(client) if client and client:IsAlive() and client:IsGround() then return true else return false end end)
|
self:FilterFunction(function(client) if client and client:IsAlive() and client:IsGround() then return true else return false end end)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -6691,6 +6691,8 @@ do -- SET_ZONE
|
|||||||
--
|
--
|
||||||
-- -- Stop watching after 1 hour
|
-- -- Stop watching after 1 hour
|
||||||
-- zoneset:__TriggerStop(3600)
|
-- zoneset:__TriggerStop(3600)
|
||||||
|
-- -- Call :SetPartlyInside() on any zone (or SET_ZONE) if you want GROUPs to count as inside when any of their units enters even if they are far apart.
|
||||||
|
-- -- Make sure to call :SetPartlyInside() before :Trigger()!.
|
||||||
function SET_ZONE:Trigger(Objects)
|
function SET_ZONE:Trigger(Objects)
|
||||||
--self:I("Added Set_Zone Trigger")
|
--self:I("Added Set_Zone Trigger")
|
||||||
self:AddTransition("*","TriggerStart","TriggerRunning")
|
self:AddTransition("*","TriggerStart","TriggerRunning")
|
||||||
@@ -6741,6 +6743,20 @@ do -- SET_ZONE
|
|||||||
-- @param Core.Zone#ZONE_BASE Zone The zone left.
|
-- @param Core.Zone#ZONE_BASE Zone The zone left.
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Toggle “partly-inside” handling for every zone in the set when those zones are used with :Trigger().
|
||||||
|
-- * Call with no argument or **true** → enable for all.
|
||||||
|
-- * Call with **false** → disable again (handy if it was enabled before).
|
||||||
|
-- @param #SET_ZONE self
|
||||||
|
-- @return #SET_ZONE self
|
||||||
|
function SET_ZONE:SetPartlyInside(state)
|
||||||
|
for _,Zone in pairs(self.Set) do
|
||||||
|
if Zone.SetPartlyInside then
|
||||||
|
Zone:SetPartlyInside(state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- (Internal) Check the assigned objects for being in/out of the zone
|
--- (Internal) Check the assigned objects for being in/out of the zone
|
||||||
-- @param #SET_ZONE self
|
-- @param #SET_ZONE self
|
||||||
-- @param #boolean fromstart If true, do the init of the objects
|
-- @param #boolean fromstart If true, do the init of the objects
|
||||||
@@ -6776,8 +6792,13 @@ do -- SET_ZONE
|
|||||||
-- has not been tagged previously - wasn't in set!
|
-- has not been tagged previously - wasn't in set!
|
||||||
obj.TriggerInZone[_zone.ZoneName] = false
|
obj.TriggerInZone[_zone.ZoneName] = false
|
||||||
end
|
end
|
||||||
-- is obj in zone?
|
-- is obj in this zone?
|
||||||
local inzone = _zone:IsCoordinateInZone(obj:GetCoordinate())
|
local inzone
|
||||||
|
if _zone.PartlyInside and obj.ClassName == "GROUP" then
|
||||||
|
inzone = obj:IsAnyInZone(_zone) -- TRUE as soon as any unit is inside
|
||||||
|
else
|
||||||
|
inzone = _zone:IsCoordinateInZone(obj:GetCoordinate()) -- original centroid test
|
||||||
|
end
|
||||||
--self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone))
|
--self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone))
|
||||||
if inzone and not obj.TriggerInZone[_zone.ZoneName] then
|
if inzone and not obj.TriggerInZone[_zone.ZoneName] then
|
||||||
-- wasn't in zone before
|
-- wasn't in zone before
|
||||||
@@ -7844,6 +7865,28 @@ do -- SET_OPSGROUP
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Iterate the SET_OPSGROUP and count how many GROUPs and UNITs are alive.
|
||||||
|
-- @param #SET_GROUP self
|
||||||
|
-- @return #number The number of GROUPs alive.
|
||||||
|
-- @return #number The number of UNITs alive.
|
||||||
|
function SET_OPSGROUP:CountAlive()
|
||||||
|
local CountG = 0
|
||||||
|
local CountU = 0
|
||||||
|
|
||||||
|
local Set = self:GetSet()
|
||||||
|
|
||||||
|
for GroupID, GroupData in pairs( Set ) do -- For each GROUP in SET_GROUP
|
||||||
|
if GroupData and GroupData:IsAlive() then
|
||||||
|
CountG = CountG + 1
|
||||||
|
-- Count Units.
|
||||||
|
CountU = CountU + GroupData:GetGroup():CountAliveUnits()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return CountG, CountU
|
||||||
|
end
|
||||||
|
|
||||||
--- Finds an OPSGROUP based on the group name.
|
--- Finds an OPSGROUP based on the group name.
|
||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #string GroupName Name of the group.
|
-- @param #string GroupName Name of the group.
|
||||||
|
|||||||
@@ -1049,6 +1049,23 @@ function SPAWN:InitSetUnitAbsolutePositions(Positions)
|
|||||||
return self
|
return self
|
||||||
end
|
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 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,
|
-- 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.
|
-- but they will all follow the same Template route and have the same prefix name.
|
||||||
@@ -1830,6 +1847,12 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
|||||||
SpawnTemplate.hidden=self.SpawnHiddenOnMap
|
SpawnTemplate.hidden=self.SpawnHiddenOnMap
|
||||||
end
|
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.
|
-- Set country, coalition and category.
|
||||||
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
|
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
|
||||||
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
|
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
|
||||||
|
|||||||
@@ -378,6 +378,20 @@ function SPAWNSTATIC:InitLinkToUnit(Unit, OffsetX, OffsetY, OffsetAngle)
|
|||||||
return self
|
return self
|
||||||
end
|
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.
|
--- 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 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.
|
-- The first parameter of the SpawnFunction is the @{Wrapper.Static#STATIC} that was spawned.
|
||||||
@@ -544,6 +558,14 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
-- Add static to the game.
|
-- Add static to the game.
|
||||||
local Static=nil --DCS#StaticObject
|
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
|
if self.InitFarp then
|
||||||
|
|
||||||
local TemplateGroup={}
|
local TemplateGroup={}
|
||||||
@@ -611,16 +633,15 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
|
|
||||||
if self.StaticCopyFrom ~= nil then
|
if self.StaticCopyFrom ~= nil then
|
||||||
mystatic.StaticCopyFrom = self.StaticCopyFrom
|
mystatic.StaticCopyFrom = self.StaticCopyFrom
|
||||||
if not _DATABASE.Templates.Statics[Template.name] then
|
|
||||||
local TemplateGroup={}
|
|
||||||
TemplateGroup.units={}
|
|
||||||
TemplateGroup.units[1]=Template
|
|
||||||
TemplateGroup.x=Template.x
|
|
||||||
TemplateGroup.y=Template.y
|
|
||||||
TemplateGroup.name=Template.name
|
|
||||||
_DATABASE:_RegisterStaticTemplate( TemplateGroup, self.CoalitionID, self.CategoryID, CountryID )
|
|
||||||
end
|
|
||||||
end
|
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
|
return mystatic
|
||||||
end
|
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 #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 Surface Type of surface. Only determined at the center of the zone!
|
||||||
-- @field #number Checktime Check every Checktime seconds, used for ZONE:Trigger()
|
-- @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
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
@@ -612,6 +613,8 @@ end
|
|||||||
--
|
--
|
||||||
-- -- Stop watching the zone after 1 hour
|
-- -- Stop watching the zone after 1 hour
|
||||||
-- triggerzone:__TriggerStop(3600)
|
-- 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)
|
function ZONE_BASE:Trigger(Objects)
|
||||||
--self:I("Added Zone Trigger")
|
--self:I("Added Zone Trigger")
|
||||||
self:SetStartState("TriggerStopped")
|
self:SetStartState("TriggerStopped")
|
||||||
@@ -680,6 +683,16 @@ function ZONE_BASE:Trigger(Objects)
|
|||||||
|
|
||||||
end
|
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
|
--- (Internal) Check the assigned objects for being in/out of the zone
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @param #boolean fromstart If true, do the init of the objects
|
-- @param #boolean fromstart If true, do the init of the objects
|
||||||
@@ -718,7 +731,12 @@ function ZONE_BASE:_TriggerCheck(fromstart)
|
|||||||
obj.TriggerInZone[self.ZoneName] = false
|
obj.TriggerInZone[self.ZoneName] = false
|
||||||
end
|
end
|
||||||
-- is obj in zone?
|
-- 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))
|
--self:I("Object "..obj:GetName().." is in zone: "..tostring(inzone))
|
||||||
if inzone and obj.TriggerInZone[self.ZoneName] then
|
if inzone and obj.TriggerInZone[self.ZoneName] then
|
||||||
-- just count
|
-- just count
|
||||||
@@ -1162,15 +1180,13 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
|||||||
|
|
||||||
local function EvaluateZone( ZoneObject )
|
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: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.
|
-- Get object category.
|
||||||
local ObjectCategory = Object.getCategory(ZoneObject)
|
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
|
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
|
local Include = false
|
||||||
if not UnitCategories then
|
if not UnitCategories then
|
||||||
-- Anything found is included.
|
-- Anything found is included.
|
||||||
@@ -1554,6 +1570,10 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
|||||||
local _inner = inner or 0
|
local _inner = inner or 0
|
||||||
local _outer = outer or self:GetRadius()
|
local _outer = outer or self:GetRadius()
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
if surfacetypes and type(surfacetypes)~="table" then
|
if surfacetypes and type(surfacetypes)~="table" then
|
||||||
surfacetypes={surfacetypes}
|
surfacetypes={surfacetypes}
|
||||||
end
|
end
|
||||||
@@ -1914,6 +1934,21 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius, Offset)
|
|||||||
return self
|
return self
|
||||||
end
|
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}.
|
--- Returns the current location of the @{Wrapper.Unit#UNIT}.
|
||||||
-- @param #ZONE_UNIT self
|
-- @param #ZONE_UNIT self
|
||||||
@@ -2051,6 +2086,22 @@ function ZONE_GROUP:GetVec2()
|
|||||||
return ZoneVec2
|
return ZoneVec2
|
||||||
end
|
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}.
|
--- Returns a random location within the zone of the @{Wrapper.Group}.
|
||||||
-- @param #ZONE_GROUP self
|
-- @param #ZONE_GROUP self
|
||||||
-- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location.
|
-- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location.
|
||||||
@@ -2918,6 +2969,11 @@ end
|
|||||||
function ZONE_POLYGON_BASE:GetRandomVec2()
|
function ZONE_POLYGON_BASE:GetRandomVec2()
|
||||||
-- make sure we assign weights to the triangles based on their surface area, otherwise
|
-- 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
|
-- we'll be more likely to generate random points in smaller triangles
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
local weights = {}
|
local weights = {}
|
||||||
for _, triangle in pairs(self._Triangles) do
|
for _, triangle in pairs(self._Triangles) do
|
||||||
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
||||||
@@ -3281,14 +3337,12 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
|||||||
|
|
||||||
local function EvaluateZone( ZoneObject )
|
local function EvaluateZone( ZoneObject )
|
||||||
|
|
||||||
if ZoneObject then
|
if ZoneObject and self:IsVec3InZone(ZoneObject:getPoint()) then
|
||||||
|
|
||||||
local ObjectCategory = Object.getCategory(ZoneObject)
|
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
|
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
|
local Include = false
|
||||||
if not UnitCategories then
|
if not UnitCategories then
|
||||||
-- Anything found is included.
|
-- Anything found is included.
|
||||||
@@ -3320,7 +3374,7 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- trying with box search
|
-- 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 SceneryType = ZoneObject:getTypeName()
|
||||||
local SceneryName = ZoneObject:getName()
|
local SceneryName = ZoneObject:getName()
|
||||||
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
|
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
-- @module Functional.Mantis
|
-- @module Functional.Mantis
|
||||||
-- @image Functional.Mantis.jpg
|
-- @image Functional.Mantis.jpg
|
||||||
--
|
--
|
||||||
-- Last Update: July 2025
|
-- Last Update: August 2025
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **MANTIS** class, extends Core.Base#BASE
|
--- **MANTIS** class, extends Core.Base#BASE
|
||||||
@@ -108,10 +108,15 @@
|
|||||||
-- * Patriot
|
-- * Patriot
|
||||||
-- * Rapier
|
-- * Rapier
|
||||||
-- * Roland
|
-- * Roland
|
||||||
|
-- * IRIS-T SLM
|
||||||
|
-- * Pantsir S1
|
||||||
|
-- * TOR M2
|
||||||
|
-- * C-RAM
|
||||||
-- * Silkworm (though strictly speaking this is a surface to ship missile)
|
-- * 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
|
-- * 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 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, SAMP/T Block 1, SAMP/T Block 1INT, SAMP/T Block2
|
-- * 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
|
-- * 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"
|
-- **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"
|
||||||
@@ -275,7 +280,7 @@
|
|||||||
MANTIS = {
|
MANTIS = {
|
||||||
ClassName = "MANTIS",
|
ClassName = "MANTIS",
|
||||||
name = "mymantis",
|
name = "mymantis",
|
||||||
version = "0.9.32",
|
version = "0.9.34",
|
||||||
SAM_Templates_Prefix = "",
|
SAM_Templates_Prefix = "",
|
||||||
SAM_Group = nil,
|
SAM_Group = nil,
|
||||||
EWR_Templates_Prefix = "",
|
EWR_Templates_Prefix = "",
|
||||||
@@ -384,7 +389,7 @@ MANTIS.SamData = {
|
|||||||
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
||||||
["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Linebacker", Point="true" },
|
["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" },
|
["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
|
-- units from HDS Mod, multi launcher options is tricky
|
||||||
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"},
|
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"},
|
||||||
["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17" },
|
["SA-17"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17" },
|
||||||
@@ -393,6 +398,12 @@ MANTIS.SamData = {
|
|||||||
["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
["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" },
|
["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
|
--- SAM data HDS
|
||||||
@@ -458,15 +469,15 @@ MANTIS.SamDataCH = {
|
|||||||
-- https://www.currenthill.com/
|
-- https://www.currenthill.com/
|
||||||
-- group name MUST contain CHM to ID launcher type correctly!
|
-- group name MUST contain CHM to ID launcher type correctly!
|
||||||
["2S38 CHM"] = { Range=6, Blindspot=0.1, Height=4.5, Type="Short", Radar="2S38" },
|
["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" },
|
["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" },
|
["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" },
|
["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" },
|
["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" },
|
["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" },
|
["TorM2 CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2", Point="true" },
|
||||||
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Short", Radar="TorM2K" },
|
["TorM2K CHM"] = { Range=12, Blindspot=1, Height=10, Type="Point", Radar="TorM2K", Point="true" },
|
||||||
["TorM2M CHM"] = { Range=16, Blindspot=1, Height=10, Type="Short", Radar="TorM2M" },
|
["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-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" },
|
["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" },
|
["C-RAM CHM"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="CH_Centurion_C_RAM", Point="true" },
|
||||||
@@ -882,7 +893,11 @@ do
|
|||||||
self.AcceptZones = AcceptZones or {}
|
self.AcceptZones = AcceptZones or {}
|
||||||
self.RejectZones = RejectZones or {}
|
self.RejectZones = RejectZones or {}
|
||||||
self.ConflictZones = ConflictZones 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
|
self.usezones = true
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -1274,7 +1289,8 @@ do
|
|||||||
self:T(self.lid.."_CheckCoordinateInZones")
|
self:T(self.lid.."_CheckCoordinateInZones")
|
||||||
local inzone = false
|
local inzone = false
|
||||||
-- acceptzones
|
-- 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
|
for _,_zone in pairs(self.AcceptZones) do
|
||||||
local zone = _zone -- Core.Zone#ZONE
|
local zone = _zone -- Core.Zone#ZONE
|
||||||
if zone:IsCoordinateInZone(coord) then
|
if zone:IsCoordinateInZone(coord) then
|
||||||
@@ -1285,7 +1301,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- rejectzones
|
-- 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
|
for _,_zone in pairs(self.RejectZones) do
|
||||||
local zone = _zone -- Core.Zone#ZONE
|
local zone = _zone -- Core.Zone#ZONE
|
||||||
if zone:IsCoordinateInZone(coord) then
|
if zone:IsCoordinateInZone(coord) then
|
||||||
@@ -1296,7 +1312,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- conflictzones
|
-- 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
|
for _,_zone in pairs(self.ConflictZones) do
|
||||||
local zone = _zone -- Core.Zone#ZONE
|
local zone = _zone -- Core.Zone#ZONE
|
||||||
if zone:IsCoordinateInZone(coord) then
|
if zone:IsCoordinateInZone(coord) then
|
||||||
@@ -1362,6 +1378,7 @@ do
|
|||||||
end
|
end
|
||||||
-- check accept/reject zones
|
-- check accept/reject zones
|
||||||
local zonecheck = true
|
local zonecheck = true
|
||||||
|
self:T("self.usezones = "..tostring(self.usezones))
|
||||||
if self.usezones then
|
if self.usezones then
|
||||||
-- DONE
|
-- DONE
|
||||||
zonecheck = self:_CheckCoordinateInZones(coord)
|
zonecheck = self:_CheckCoordinateInZones(coord)
|
||||||
|
|||||||
@@ -320,8 +320,10 @@ function SCORING:New( GameName, SavePath, AutoSave )
|
|||||||
|
|
||||||
-- Create the CSV file.
|
-- Create the CSV file.
|
||||||
self.AutoSavePath = SavePath
|
self.AutoSavePath = SavePath
|
||||||
self.AutoSave = AutoSave or true
|
self.AutoSave = (AutoSave == nil or AutoSave == true) and true or false
|
||||||
self:OpenCSV( GameName )
|
if self.AutoSavePath and self.AutoSave == true then
|
||||||
|
self:OpenCSV( GameName )
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -985,6 +987,7 @@ function SCORING:_EventOnHit( Event )
|
|||||||
local TargetUnitCoalition = nil
|
local TargetUnitCoalition = nil
|
||||||
local TargetUnitCategory = nil
|
local TargetUnitCategory = nil
|
||||||
local TargetUnitType = nil
|
local TargetUnitType = nil
|
||||||
|
local TargetIsScenery = false
|
||||||
|
|
||||||
if Event.IniDCSUnit then
|
if Event.IniDCSUnit then
|
||||||
|
|
||||||
@@ -1025,6 +1028,12 @@ function SCORING:_EventOnHit( Event )
|
|||||||
TargetCategory = Event.TgtCategory
|
TargetCategory = Event.TgtCategory
|
||||||
TargetType = Event.TgtTypeName
|
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]
|
TargetUnitCoalition = _SCORINGCoalition[TargetCoalition]
|
||||||
TargetUnitCategory = _SCORINGCategory[TargetCategory]
|
TargetUnitCategory = _SCORINGCategory[TargetCategory]
|
||||||
TargetUnitType = TargetType
|
TargetUnitType = TargetType
|
||||||
@@ -1117,17 +1126,22 @@ function SCORING:_EventOnHit( Event )
|
|||||||
MESSAGE.Type.Update )
|
MESSAGE.Type.Update )
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
: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. " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
||||||
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Update )
|
MESSAGE.Type.Update )
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
: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
|
end
|
||||||
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
end
|
end
|
||||||
else -- A scenery object was hit.
|
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 )
|
MESSAGE.Type.Update )
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
@@ -1923,7 +1937,7 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
|
|||||||
TargetUnitType = TargetUnitType or ""
|
TargetUnitType = TargetUnitType or ""
|
||||||
TargetUnitName = TargetUnitName 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.CSVFile:write(
|
||||||
'"' .. self.GameName .. '"' .. ',' ..
|
'"' .. self.GameName .. '"' .. ',' ..
|
||||||
'"' .. self.RunTime .. '"' .. ',' ..
|
'"' .. self.RunTime .. '"' .. ',' ..
|
||||||
|
|||||||
@@ -30,10 +30,10 @@
|
|||||||
---- #-- Author : **applevangelist ** (Optimized by AI)
|
---- #-- Author : **applevangelist ** (Optimized by AI)
|
||||||
|
|
||||||
---
|
---
|
||||||
-- - @module Functional.Tiresias
|
-- @module Functional.Tiresias
|
||||||
-- - @image Functional.Tiresias.jpg
|
-- @image Functional.Tiresias.jpg
|
||||||
|
|
||||||
--- Last Update: Dec 2023 (Optimized July 2025)
|
--- Last Update: Oct 2025
|
||||||
|
|
||||||
--- **TIRESIAS** class, extends Core.Base#BASE
|
--- **TIRESIAS** class, extends Core.Base#BASE
|
||||||
-- @type TIRESIAS
|
-- @type TIRESIAS
|
||||||
@@ -55,6 +55,7 @@
|
|||||||
-- @field #boolean SwitchAAA
|
-- @field #boolean SwitchAAA
|
||||||
-- @field #string lid
|
-- @field #string lid
|
||||||
-- @field #table _cached_zones
|
-- @field #table _cached_zones
|
||||||
|
-- @field #table _cached_groupsets
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -103,8 +104,8 @@
|
|||||||
-- @field #TIRESIAS
|
-- @field #TIRESIAS
|
||||||
TIRESIAS = {
|
TIRESIAS = {
|
||||||
ClassName = "TIRESIAS",
|
ClassName = "TIRESIAS",
|
||||||
debug = true,
|
debug = false,
|
||||||
version = " 0.0.6-OPT" ,
|
version = " 0.0.8" ,
|
||||||
Interval = 20,
|
Interval = 20,
|
||||||
GroundSet = nil,
|
GroundSet = nil,
|
||||||
VehicleSet = nil,
|
VehicleSet = nil,
|
||||||
@@ -116,6 +117,7 @@ TIRESIAS = {
|
|||||||
PlaneSwitchRange = 25, -- NM
|
PlaneSwitchRange = 25, -- NM
|
||||||
SwitchAAA = true,
|
SwitchAAA = true,
|
||||||
_cached_zones = {}, -- Cache for zone objects
|
_cached_zones = {}, -- Cache for zone objects
|
||||||
|
_cached_groupsets = {}, -- Cache for group_set objects
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -138,7 +140,7 @@ function TIRESIAS:New()
|
|||||||
self:AddTransition("*", "Status", "*") -- TIRESIAS status update.
|
self:AddTransition("*", "Status", "*") -- TIRESIAS status update.
|
||||||
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
||||||
|
|
||||||
self.ExceptionSet = nil --SET_GROUP:New():Clear(false)
|
self.ExceptionSet = SET_GROUP:New() --:Clear(false)
|
||||||
self._cached_zones = {} -- Initialize zone cache
|
self._cached_zones = {} -- Initialize zone cache
|
||||||
|
|
||||||
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
|
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
|
||||||
@@ -222,10 +224,10 @@ function TIRESIAS:AddExceptionSet(Set)
|
|||||||
|
|
||||||
Set:ForEachGroupAlive(
|
Set:ForEachGroupAlive(
|
||||||
function(grp)
|
function(grp)
|
||||||
local inAAASet = self.AAASet:IsIncludeObject(grp)
|
--local inAAASet = self.AAASet:IsIncludeObject(grp)
|
||||||
local inVehSet = self.VehicleSet:IsIncludeObject(grp)
|
--local inVehSet = self.VehicleSet:IsIncludeObject(grp)
|
||||||
local inSAMSet = self.SAMSet:IsIncludeObject(grp)
|
--local inSAMSet = self.SAMSet:IsIncludeObject(grp)
|
||||||
if grp:IsGround() and (not grp.Tiresias) and (not inAAASet) and (not inVehSet) and (not inSAMSet) then
|
if grp:IsGround() and (not grp.Tiresias) then --and (not inAAASet) and (not inVehSet) and (not inSAMSet) then
|
||||||
grp.Tiresias = exception_data
|
grp.Tiresias = exception_data
|
||||||
exceptions:AddGroup(grp, true)
|
exceptions:AddGroup(grp, true)
|
||||||
BASE:T(" TIRESIAS: Added exception group: " .. grp:GetName())
|
BASE:T(" TIRESIAS: Added exception group: " .. grp:GetName())
|
||||||
@@ -417,7 +419,8 @@ function TIRESIAS:_SwitchOnGroups(group, radius)
|
|||||||
-- Use cached zones to reduce object creation
|
-- Use cached zones to reduce object creation
|
||||||
local group_name = group:GetName()
|
local group_name = group:GetName()
|
||||||
local cache_key = group_name .. " _" .. radius
|
local cache_key = group_name .. " _" .. radius
|
||||||
local zone = self._cached_zones[cache_key]
|
local zone = self._cached_zones[cache_key] -- Core.Zone#ZONE_RADIUS
|
||||||
|
--local ground = self._cached_groupsets[cache_key] -- Core.Set#SET_GROUP
|
||||||
|
|
||||||
if not zone then
|
if not zone then
|
||||||
zone = ZONE_GROUP:New(" Zone-" .. group_name, group, UTILS.NMToMeters(radius))
|
zone = ZONE_GROUP:New(" Zone-" .. group_name, group, UTILS.NMToMeters(radius))
|
||||||
@@ -427,7 +430,15 @@ function TIRESIAS:_SwitchOnGroups(group, radius)
|
|||||||
zone:UpdateFromGroup(group)
|
zone:UpdateFromGroup(group)
|
||||||
end
|
end
|
||||||
|
|
||||||
local ground = SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce()
|
--if not ground then
|
||||||
|
--ground = SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce()
|
||||||
|
--self._cached_groupsets[cache_key] = ground
|
||||||
|
--else
|
||||||
|
--ground:FilterZones({zone},true):FilterOnce()
|
||||||
|
zone:Scan({Object.Category.UNIT},{Unit.Category.GROUND_UNIT})
|
||||||
|
local ground = zone:GetScannedSetGroup()
|
||||||
|
--end
|
||||||
|
|
||||||
local count = ground:CountAlive()
|
local count = ground:CountAlive()
|
||||||
|
|
||||||
if self.debug then
|
if self.debug then
|
||||||
|
|||||||
@@ -4247,6 +4247,16 @@ function WAREHOUSE:_AssetItemInfo(asset)
|
|||||||
self:T3({Template=asset.template})
|
self:T3({Template=asset.template})
|
||||||
end
|
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.
|
--- On after "NewAsset" event. A new asset has been added to the warehouse stock.
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
@@ -5965,6 +5975,10 @@ function WAREHOUSE:_SpawnAssetGroundNaval(alias, asset, request, spawnzone, late
|
|||||||
template.y = coord.z
|
template.y = coord.z
|
||||||
template.alt = coord.y
|
template.alt = coord.y
|
||||||
|
|
||||||
|
if self.ValidateAndRepositionGroundUnits then
|
||||||
|
UTILS.ValidateAndRepositionGroundUnits(template.units)
|
||||||
|
end
|
||||||
|
|
||||||
-- Spawn group.
|
-- Spawn group.
|
||||||
local group=_DATABASE:Spawn(template) --Wrapper.Group#GROUP
|
local group=_DATABASE:Spawn(template) --Wrapper.Group#GROUP
|
||||||
|
|
||||||
|
|||||||
@@ -159,6 +159,8 @@ AIRWING = {
|
|||||||
-- @field #number refuelsystem Refueling system type: `0=Unit.RefuelingSystem.BOOM_AND_RECEPTACLE`, `1=Unit.RefuelingSystem.PROBE_AND_DROGUE`.
|
-- @field #number refuelsystem Refueling system type: `0=Unit.RefuelingSystem.BOOM_AND_RECEPTACLE`, `1=Unit.RefuelingSystem.PROBE_AND_DROGUE`.
|
||||||
-- @field #number noccupied Number of flights on this patrol point.
|
-- @field #number noccupied Number of flights on this patrol point.
|
||||||
-- @field Wrapper.Marker#MARKER marker F10 marker.
|
-- @field Wrapper.Marker#MARKER marker F10 marker.
|
||||||
|
-- @field #boolean IsZonePoint flag for using a (moving) zone as point for patrol etc.
|
||||||
|
-- @field Core.Zone#ZONE_BASE patrolzone in case Patrol coordinate was handed as zone, store here.
|
||||||
|
|
||||||
--- Patrol zone.
|
--- Patrol zone.
|
||||||
-- @type AIRWING.PatrolZone
|
-- @type AIRWING.PatrolZone
|
||||||
@@ -187,13 +189,14 @@ AIRWING = {
|
|||||||
|
|
||||||
--- AIRWING class version.
|
--- AIRWING class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
AIRWING.version="0.9.6"
|
AIRWING.version="0.9.7"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: Check that airbase has enough parking spots if a request is BIG.
|
-- TODO: Check that airbase has enough parking spots if a request is BIG.
|
||||||
|
-- DONE: Allow (moving) zones as base for patrol points.
|
||||||
-- DONE: Spawn in air ==> Needs WAREHOUSE update.
|
-- DONE: Spawn in air ==> Needs WAREHOUSE update.
|
||||||
-- DONE: Spawn hot.
|
-- DONE: Spawn hot.
|
||||||
-- DONE: Make special request to transfer squadrons to anther airwing (or warehouse).
|
-- DONE: Make special request to transfer squadrons to anther airwing (or warehouse).
|
||||||
@@ -807,13 +810,22 @@ function AIRWING:_PatrolPointMarkerText(point)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Update marker of the patrol point.
|
--- Update marker of the patrol point.
|
||||||
|
-- @param #AIRWING self
|
||||||
-- @param #AIRWING.PatrolData point Patrol point table.
|
-- @param #AIRWING.PatrolData point Patrol point table.
|
||||||
function AIRWING:UpdatePatrolPointMarker(point)
|
function AIRWING:UpdatePatrolPointMarker(point)
|
||||||
if self.markpoints then -- sometimes there's a direct call from #OPSGROUP
|
|
||||||
|
if self and self.markpoints then -- sometimes there's a direct call from #OPSGROUP
|
||||||
local text=string.format("%s Occupied=%d\nheading=%03d, leg=%d NM, alt=%d ft, speed=%d kts",
|
local text=string.format("%s Occupied=%d\nheading=%03d, leg=%d NM, alt=%d ft, speed=%d kts",
|
||||||
point.type, point.noccupied, point.heading, point.leg, point.altitude, point.speed)
|
point.type, point.noccupied, point.heading, point.leg, point.altitude, point.speed)
|
||||||
|
|
||||||
point.marker:UpdateText(text, 1)
|
if point.IsZonePoint and point.IsZonePoint == true and point.patrolzone then
|
||||||
|
-- update position
|
||||||
|
local Coordinate = point.patrolzone:GetCoordinate()
|
||||||
|
point.marker:UpdateCoordinate(Coordinate)
|
||||||
|
point.marker:UpdateText(text, 1.5)
|
||||||
|
else
|
||||||
|
point.marker:UpdateText(text, 1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -821,7 +833,7 @@ end
|
|||||||
--- Create a new generic patrol point.
|
--- Create a new generic patrol point.
|
||||||
-- @param #AIRWING self
|
-- @param #AIRWING self
|
||||||
-- @param #string Type Patrol point type, e.g. "CAP" or "AWACS". Default "Unknown".
|
-- @param #string Type Patrol point type, e.g. "CAP" or "AWACS". Default "Unknown".
|
||||||
-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Default 10-15 NM away from the location of the airwing.
|
-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Default 10-15 NM away from the location of the airwing. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone).
|
||||||
-- @param #number Altitude Orbit altitude in feet. Default random between Angels 10 and 20.
|
-- @param #number Altitude Orbit altitude in feet. Default random between Angels 10 and 20.
|
||||||
-- @param #number Heading Heading in degrees. Default random (0, 360] degrees.
|
-- @param #number Heading Heading in degrees. Default random (0, 360] degrees.
|
||||||
-- @param #number LegLength Length of race-track orbit in NM. Default 15 NM.
|
-- @param #number LegLength Length of race-track orbit in NM. Default 15 NM.
|
||||||
@@ -830,14 +842,16 @@ end
|
|||||||
-- @return #AIRWING.PatrolData Patrol point table.
|
-- @return #AIRWING.PatrolData Patrol point table.
|
||||||
function AIRWING:NewPatrolPoint(Type, Coordinate, Altitude, Speed, Heading, LegLength, RefuelSystem)
|
function AIRWING:NewPatrolPoint(Type, Coordinate, Altitude, Speed, Heading, LegLength, RefuelSystem)
|
||||||
|
|
||||||
-- Check if a zone was passed instead of a coordinate.
|
|
||||||
if Coordinate and Coordinate:IsInstanceOf("ZONE_BASE") then
|
|
||||||
Coordinate=Coordinate:GetCoordinate()
|
|
||||||
end
|
|
||||||
|
|
||||||
local patrolpoint={} --#AIRWING.PatrolData
|
local patrolpoint={} --#AIRWING.PatrolData
|
||||||
patrolpoint.type=Type or "Unknown"
|
patrolpoint.type=Type or "Unknown"
|
||||||
patrolpoint.coord=Coordinate or self:GetCoordinate():Translate(UTILS.NMToMeters(math.random(10, 15)), math.random(360))
|
patrolpoint.coord=Coordinate or self:GetCoordinate():Translate(UTILS.NMToMeters(math.random(10, 15)), math.random(360))
|
||||||
|
if Coordinate and Coordinate:IsInstanceOf("ZONE_BASE") then
|
||||||
|
patrolpoint.IsZonePoint = true
|
||||||
|
patrolpoint.patrolzone = Coordinate
|
||||||
|
patrolpoint.coord = patrolpoint.patrolzone:GetCoordinate()
|
||||||
|
else
|
||||||
|
patrolpoint.IsZonePoint = false
|
||||||
|
end
|
||||||
patrolpoint.heading=Heading or math.random(360)
|
patrolpoint.heading=Heading or math.random(360)
|
||||||
patrolpoint.leg=LegLength or 15
|
patrolpoint.leg=LegLength or 15
|
||||||
patrolpoint.altitude=Altitude or math.random(10,20)*1000
|
patrolpoint.altitude=Altitude or math.random(10,20)*1000
|
||||||
@@ -847,7 +861,7 @@ function AIRWING:NewPatrolPoint(Type, Coordinate, Altitude, Speed, Heading, LegL
|
|||||||
|
|
||||||
if self.markpoints then
|
if self.markpoints then
|
||||||
patrolpoint.marker=MARKER:New(Coordinate, "New Patrol Point"):ToAll()
|
patrolpoint.marker=MARKER:New(Coordinate, "New Patrol Point"):ToAll()
|
||||||
AIRWING.UpdatePatrolPointMarker(patrolpoint)
|
self:UpdatePatrolPointMarker(patrolpoint)
|
||||||
end
|
end
|
||||||
|
|
||||||
return patrolpoint
|
return patrolpoint
|
||||||
@@ -855,7 +869,7 @@ end
|
|||||||
|
|
||||||
--- Add a patrol Point for CAP missions.
|
--- Add a patrol Point for CAP missions.
|
||||||
-- @param #AIRWING self
|
-- @param #AIRWING self
|
||||||
-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point.
|
-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone).
|
||||||
-- @param #number Altitude Orbit altitude in feet.
|
-- @param #number Altitude Orbit altitude in feet.
|
||||||
-- @param #number Speed Orbit speed in knots.
|
-- @param #number Speed Orbit speed in knots.
|
||||||
-- @param #number Heading Heading in degrees.
|
-- @param #number Heading Heading in degrees.
|
||||||
@@ -872,7 +886,7 @@ end
|
|||||||
|
|
||||||
--- Add a patrol Point for RECON missions.
|
--- Add a patrol Point for RECON missions.
|
||||||
-- @param #AIRWING self
|
-- @param #AIRWING self
|
||||||
-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point.
|
-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone).
|
||||||
-- @param #number Altitude Orbit altitude in feet.
|
-- @param #number Altitude Orbit altitude in feet.
|
||||||
-- @param #number Speed Orbit speed in knots.
|
-- @param #number Speed Orbit speed in knots.
|
||||||
-- @param #number Heading Heading in degrees.
|
-- @param #number Heading Heading in degrees.
|
||||||
@@ -889,7 +903,7 @@ end
|
|||||||
|
|
||||||
--- Add a patrol Point for TANKER missions.
|
--- Add a patrol Point for TANKER missions.
|
||||||
-- @param #AIRWING self
|
-- @param #AIRWING self
|
||||||
-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point.
|
-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone).
|
||||||
-- @param #number Altitude Orbit altitude in feet.
|
-- @param #number Altitude Orbit altitude in feet.
|
||||||
-- @param #number Speed Orbit speed in knots.
|
-- @param #number Speed Orbit speed in knots.
|
||||||
-- @param #number Heading Heading in degrees.
|
-- @param #number Heading Heading in degrees.
|
||||||
@@ -907,7 +921,7 @@ end
|
|||||||
|
|
||||||
--- Add a patrol Point for AWACS missions.
|
--- Add a patrol Point for AWACS missions.
|
||||||
-- @param #AIRWING self
|
-- @param #AIRWING self
|
||||||
-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point.
|
-- @param Core.Point#COORDINATE Coordinate Coordinate of the patrol point. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone).
|
||||||
-- @param #number Altitude Orbit altitude in feet.
|
-- @param #number Altitude Orbit altitude in feet.
|
||||||
-- @param #number Speed Orbit speed in knots.
|
-- @param #number Speed Orbit speed in knots.
|
||||||
-- @param #number Heading Heading in degrees.
|
-- @param #number Heading Heading in degrees.
|
||||||
@@ -1176,6 +1190,10 @@ function AIRWING:_GetPatrolData(PatrolPoints, RefuelSystem)
|
|||||||
|
|
||||||
for _,_patrolpoint in pairs(PatrolPoints) do
|
for _,_patrolpoint in pairs(PatrolPoints) do
|
||||||
local patrolpoint=_patrolpoint --#AIRWING.PatrolData
|
local patrolpoint=_patrolpoint --#AIRWING.PatrolData
|
||||||
|
if patrolpoint.IsZonePoint and patrolpoint.IsZonePoint == true and patrolpoint.patrolzone then
|
||||||
|
-- update
|
||||||
|
patrolpoint.coord = patrolpoint.patrolzone:GetCoordinate()
|
||||||
|
end
|
||||||
if (RefuelSystem and patrolpoint.refuelsystem and RefuelSystem==patrolpoint.refuelsystem) or RefuelSystem==nil or patrolpoint.refuelsystem==nil then
|
if (RefuelSystem and patrolpoint.refuelsystem and RefuelSystem==patrolpoint.refuelsystem) or RefuelSystem==nil or patrolpoint.refuelsystem==nil then
|
||||||
return patrolpoint
|
return patrolpoint
|
||||||
end
|
end
|
||||||
@@ -1235,7 +1253,7 @@ function AIRWING:CheckCAP()
|
|||||||
|
|
||||||
patrol.noccupied=patrol.noccupied+1
|
patrol.noccupied=patrol.noccupied+1
|
||||||
|
|
||||||
if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end
|
if self.markpoints then self:UpdatePatrolPointMarker(patrol) end
|
||||||
|
|
||||||
self:AddMission(missionCAP)
|
self:AddMission(missionCAP)
|
||||||
|
|
||||||
@@ -1287,7 +1305,7 @@ function AIRWING:CheckRECON()
|
|||||||
|
|
||||||
patrol.noccupied=patrol.noccupied+1
|
patrol.noccupied=patrol.noccupied+1
|
||||||
|
|
||||||
if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end
|
if self.markpoints then self:UpdatePatrolPointMarker(patrol) end
|
||||||
|
|
||||||
self:AddMission(missionRECON)
|
self:AddMission(missionRECON)
|
||||||
|
|
||||||
@@ -1332,7 +1350,7 @@ function AIRWING:CheckTANKER()
|
|||||||
|
|
||||||
patrol.noccupied=patrol.noccupied+1
|
patrol.noccupied=patrol.noccupied+1
|
||||||
|
|
||||||
if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end
|
if self.markpoints then self:UpdatePatrolPointMarker(patrol) end
|
||||||
|
|
||||||
self:AddMission(mission)
|
self:AddMission(mission)
|
||||||
|
|
||||||
@@ -1351,7 +1369,7 @@ function AIRWING:CheckTANKER()
|
|||||||
|
|
||||||
patrol.noccupied=patrol.noccupied+1
|
patrol.noccupied=patrol.noccupied+1
|
||||||
|
|
||||||
if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end
|
if self.markpoints then self:UpdatePatrolPointMarker(patrol) end
|
||||||
|
|
||||||
self:AddMission(mission)
|
self:AddMission(mission)
|
||||||
|
|
||||||
@@ -1389,7 +1407,7 @@ function AIRWING:CheckAWACS()
|
|||||||
|
|
||||||
patrol.noccupied=patrol.noccupied+1
|
patrol.noccupied=patrol.noccupied+1
|
||||||
|
|
||||||
if self.markpoints then AIRWING.UpdatePatrolPointMarker(patrol) end
|
if self.markpoints then self:UpdatePatrolPointMarker(patrol) end
|
||||||
|
|
||||||
self:AddMission(mission)
|
self:AddMission(mission)
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,8 @@
|
|||||||
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_\(LHA-6\)) (LHA-6)
|
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_\(LHA-6\)) (LHA-6)
|
||||||
-- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61)
|
-- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61)
|
||||||
-- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_\(L02\)) (L02)
|
-- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_\(L02\)) (L02)
|
||||||
|
-- * BONHOMMERICHARD [VWV Mod]
|
||||||
|
-- * ENTERPRISE66 [VWV Mod]
|
||||||
--
|
--
|
||||||
-- **Supported Aircraft:**
|
-- **Supported Aircraft:**
|
||||||
--
|
--
|
||||||
@@ -1317,6 +1319,10 @@ AIRBOSS.AircraftCarrier={
|
|||||||
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module]
|
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module]
|
||||||
-- @field #string VINSON USS Carl Vinson (CVN-70) [Deprecated!]
|
-- @field #string VINSON USS Carl Vinson (CVN-70) [Deprecated!]
|
||||||
-- @field #string ESSEX Essex class carrier (e.g. USS Yorktown (CV-10)) [Magnitude 3 Carrier Module]
|
-- @field #string ESSEX Essex class carrier (e.g. USS Yorktown (CV-10)) [Magnitude 3 Carrier Module]
|
||||||
|
-- @field #string BONHOMMERICHARD USS Bon Homme Richard carrier [VWV Mod]
|
||||||
|
-- @field #string ESSEXSCB125 Generic Essex class carrier with angled deck (SCB-125 upgrade) [VWV Mod]
|
||||||
|
-- @field #string ENTERPRISE66 USS Enterprise in the 1966 configuration [VWV Mod]
|
||||||
|
-- @field #string ENTERPRISEMODERN USS Enterprise in a modern configuration [Derived VWV Mod]
|
||||||
-- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier]
|
-- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier]
|
||||||
-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier]
|
-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier]
|
||||||
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
|
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
|
||||||
@@ -1331,8 +1337,12 @@ AIRBOSS.CarrierType = {
|
|||||||
TRUMAN = "CVN_75",
|
TRUMAN = "CVN_75",
|
||||||
STENNIS = "Stennis",
|
STENNIS = "Stennis",
|
||||||
FORRESTAL = "Forrestal",
|
FORRESTAL = "Forrestal",
|
||||||
|
ENTERPRISE66 = "USS Enterprise 1966",
|
||||||
|
ENTERPRISEMODERN = "cvn-65",
|
||||||
VINSON = "VINSON",
|
VINSON = "VINSON",
|
||||||
ESSEX = "Essex",
|
ESSEX = "Essex",
|
||||||
|
BONHOMMERICHARD = "USS Bon Homme Richard",
|
||||||
|
ESSEXSCB125 = "essex_scb125",
|
||||||
HERMES = "HERMES81",
|
HERMES = "HERMES81",
|
||||||
INVINCIBLE = "hms_invincible",
|
INVINCIBLE = "hms_invincible",
|
||||||
TARAWA = "LHA_Tarawa",
|
TARAWA = "LHA_Tarawa",
|
||||||
@@ -1756,7 +1766,7 @@ AIRBOSS.MenuF10Root = nil
|
|||||||
|
|
||||||
--- Airboss class version.
|
--- Airboss class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
AIRBOSS.version = "1.4.1"
|
AIRBOSS.version = "1.4.2"
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -2019,11 +2029,19 @@ function AIRBOSS:New( carriername, alias )
|
|||||||
self:_InitNimitz()
|
self:_InitNimitz()
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.FORRESTAL then
|
elseif self.carriertype == AIRBOSS.CarrierType.FORRESTAL then
|
||||||
self:_InitForrestal()
|
self:_InitForrestal()
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.ENTERPRISE66 then
|
||||||
|
self:_InitEnterprise()
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.ENTERPRISEMODERN then
|
||||||
|
self:_InitEnterprise()
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.VINSON then
|
elseif self.carriertype == AIRBOSS.CarrierType.VINSON then
|
||||||
-- Carl Vinson is legacy now.
|
-- Carl Vinson is legacy now.
|
||||||
self:_InitStennis()
|
self:_InitStennis()
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.ESSEX then
|
elseif self.carriertype == AIRBOSS.CarrierType.ESSEX then
|
||||||
self:_InitEssex()
|
self:_InitEssex()
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.BONHOMMERICHARD then
|
||||||
|
self:_InitBonHommeRichard()
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.ESSEXSCB125 then
|
||||||
|
self:_InitEssexSCB125()
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.HERMES then
|
elseif self.carriertype == AIRBOSS.CarrierType.HERMES then
|
||||||
-- Hermes parameters.
|
-- Hermes parameters.
|
||||||
self:_InitHermes()
|
self:_InitHermes()
|
||||||
@@ -2412,6 +2430,16 @@ end
|
|||||||
-- USER API Functions
|
-- USER API Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Set the carrier illumination mode.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #number Mode Options are: -2: OFF, -1: AUTO, 0: NAVIGATION, 1: AC LAUNCH, 2: AC RECOVERY
|
||||||
|
-- @return #AIRBOSS self
|
||||||
|
function AIRBOSS:SetCarrierIllumination(Mode)
|
||||||
|
self.carrier:SetCarrierIlluminationMode(Mode)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set welcome messages for players.
|
--- Set welcome messages for players.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #boolean Switch If true, display welcome message to player.
|
-- @param #boolean Switch If true, display welcome message to player.
|
||||||
@@ -3100,8 +3128,8 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum
|
|||||||
self.SRS:SetCulture(Culture or "en-US")
|
self.SRS:SetCulture(Culture or "en-US")
|
||||||
--self.SRS:SetFrequencies(Frequencies)
|
--self.SRS:SetFrequencies(Frequencies)
|
||||||
self.SRS:SetGender(Gender or "male")
|
self.SRS:SetGender(Gender or "male")
|
||||||
self.SRS:SetPath(PathToSRS)
|
--self.SRS:SetPath(PathToSRS)
|
||||||
self.SRS:SetPort(Port or 5002)
|
self.SRS:SetPort(Port or MSRS.port or 5002)
|
||||||
self.SRS:SetLabel(self.AirbossRadio.alias or "AIRBOSS")
|
self.SRS:SetLabel(self.AirbossRadio.alias or "AIRBOSS")
|
||||||
self.SRS:SetCoordinate(self.carrier:GetCoordinate())
|
self.SRS:SetCoordinate(self.carrier:GetCoordinate())
|
||||||
self.SRS:SetVolume(Volume or 1)
|
self.SRS:SetVolume(Volume or 1)
|
||||||
@@ -3112,7 +3140,10 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum
|
|||||||
if Voice then
|
if Voice then
|
||||||
self.SRS:SetVoice(Voice)
|
self.SRS:SetVoice(Voice)
|
||||||
end
|
end
|
||||||
self.SRS:SetVolume(Volume or 1.0)
|
if (not Voice) and self.SRS and self.SRS:GetProvider() == MSRS.Provider.GOOGLE then
|
||||||
|
self.SRS.voice = MSRS.poptions["gcloud"].voice or MSRS.Voices.Google.Standard.en_US_Standard_B
|
||||||
|
end
|
||||||
|
--self.SRS:SetVolume(Volume or 1.0)
|
||||||
-- SRSQUEUE
|
-- SRSQUEUE
|
||||||
self.SRSQ = MSRSQUEUE:New("AIRBOSS")
|
self.SRSQ = MSRSQUEUE:New("AIRBOSS")
|
||||||
self.SRSQ:SetTransmitOnlyWithPlayers(true)
|
self.SRSQ:SetTransmitOnlyWithPlayers(true)
|
||||||
@@ -4643,6 +4674,26 @@ function AIRBOSS:_InitForrestal()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Init parameters for Enterprise carrier.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
function AIRBOSS:_InitEnterprise()
|
||||||
|
-- Using Forrestal as template
|
||||||
|
self:_InitForrestal()
|
||||||
|
|
||||||
|
self.carrierparam.sterndist = -164.30
|
||||||
|
self.carrierparam.deckheight = 19.52
|
||||||
|
|
||||||
|
self.carrierparam.totlength = 335
|
||||||
|
self.carrierparam.rwylength = 223
|
||||||
|
|
||||||
|
-- Wires.
|
||||||
|
self.carrierparam.wire1 = 57.7
|
||||||
|
self.carrierparam.wire2 = 69.6
|
||||||
|
self.carrierparam.wire3 = 79.5
|
||||||
|
self.carrierparam.wire4 = 90.0
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Init parameters for Essec class carriers.
|
--- Init parameters for Essec class carriers.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
function AIRBOSS:_InitEssex()
|
function AIRBOSS:_InitEssex()
|
||||||
@@ -4688,6 +4739,35 @@ function AIRBOSS:_InitEssex()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Init parameters for CVA-31 Bon Homme Richard carriers.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
function AIRBOSS:_InitBonHommeRichard()
|
||||||
|
-- Init Essex as default
|
||||||
|
self:_InitEssex()
|
||||||
|
|
||||||
|
self.carrierparam.deckheight = 16.95
|
||||||
|
|
||||||
|
-- Landing runway.
|
||||||
|
-- from BHR EssexRunwayAndRoutes.lua
|
||||||
|
self.carrierparam.rwyangle = -11.4
|
||||||
|
self.carrierparam.rwylength = 97
|
||||||
|
self.carrierparam.rwywidth = 20
|
||||||
|
|
||||||
|
-- Wires.
|
||||||
|
self.carrierparam.wire1 = 40.4 -- Distance from stern to first wire. Original from Frank - 42
|
||||||
|
self.carrierparam.wire2 = 45
|
||||||
|
self.carrierparam.wire3 = 51
|
||||||
|
self.carrierparam.wire4 = 58.1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Init parameters for Generic Essex SC125 class carriers.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
function AIRBOSS:_InitEssexSCB125()
|
||||||
|
-- Init Bon Homme Richard as default
|
||||||
|
self:_InitBonHommeRichard()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Init parameters for R12 HMS Hermes carrier.
|
--- Init parameters for R12 HMS Hermes carrier.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
function AIRBOSS:_InitHermes()
|
function AIRBOSS:_InitHermes()
|
||||||
@@ -5418,15 +5498,11 @@ function AIRBOSS:_GetAircraftAoA( playerData )
|
|||||||
aoa.OnSpeedMin = self:_AoAUnit2Deg( playerData, 14.0 ) -- 14.17 --14.5 units -- VNAO Edit - Original value 14.5
|
aoa.OnSpeedMin = self:_AoAUnit2Deg( playerData, 14.0 ) -- 14.17 --14.5 units -- VNAO Edit - Original value 14.5
|
||||||
aoa.Fast = self:_AoAUnit2Deg( playerData, 13.5 ) -- 13.33 --14.0 units -- VNAO Edit - Original value 14
|
aoa.Fast = self:_AoAUnit2Deg( playerData, 13.5 ) -- 13.33 --14.0 units -- VNAO Edit - Original value 14
|
||||||
aoa.FAST = self:_AoAUnit2Deg( playerData, 12.5 ) -- 11.67 --13.0 units -- VNAO Edit - Original value 13
|
aoa.FAST = self:_AoAUnit2Deg( playerData, 12.5 ) -- 11.67 --13.0 units -- VNAO Edit - Original value 13
|
||||||
elseif goshawk then
|
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET
|
||||||
-- T-45C Goshawk parameters.
|
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
|
||||||
aoa.SLOW = 8.00 -- 19
|
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
|
||||||
aoa.Slow = 7.75 -- 18
|
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER
|
||||||
aoa.OnSpeedMax = 7.25 -- 17.5
|
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
||||||
aoa.OnSpeed = 7.00 -- 17
|
|
||||||
aoa.OnSpeedMin = 6.75 -- 16.5
|
|
||||||
aoa.Fast = 6.25 -- 16
|
|
||||||
aoa.FAST = 6.00 -- 15
|
|
||||||
elseif skyhawk then
|
elseif skyhawk then
|
||||||
-- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390
|
-- A-4E-C Skyhawk parameters from https://forums.eagle.ru/showpost.php?p=3703467&postcount=390
|
||||||
-- Note that these are arbitrary UNITS and not degrees. We need a conversion formula!
|
-- Note that these are arbitrary UNITS and not degrees. We need a conversion formula!
|
||||||
@@ -6870,6 +6946,9 @@ function AIRBOSS:_AddMarshalGroup( flight, stack )
|
|||||||
-- Convert to clock string.
|
-- Convert to clock string.
|
||||||
local Ccharlie = UTILS.SecondsToClock( flight.Tcharlie )
|
local Ccharlie = UTILS.SecondsToClock( flight.Tcharlie )
|
||||||
|
|
||||||
|
-- Make sure brc is never above 360
|
||||||
|
brc = brc % 360
|
||||||
|
|
||||||
-- Combined marshal call.
|
-- Combined marshal call.
|
||||||
self:_MarshalCallArrived( flight.onboard, flight.case, brc, alt, Ccharlie, P )
|
self:_MarshalCallArrived( flight.onboard, flight.case, brc, alt, Ccharlie, P )
|
||||||
|
|
||||||
@@ -7523,7 +7602,7 @@ function AIRBOSS:_InitPlayer( playerData, step )
|
|||||||
playerData.landed = false
|
playerData.landed = false
|
||||||
playerData.Tlso = timer.getTime()
|
playerData.Tlso = timer.getTime()
|
||||||
playerData.Tgroove = nil
|
playerData.Tgroove = nil
|
||||||
playerData.TIG0 = nil
|
playerData.TIG0 = 0 --changed to prevent errors in script when player is not in correct spot
|
||||||
playerData.wire = nil
|
playerData.wire = nil
|
||||||
playerData.flag = -100
|
playerData.flag = -100
|
||||||
playerData.debriefschedulerID = nil
|
playerData.debriefschedulerID = nil
|
||||||
@@ -8062,8 +8141,7 @@ end
|
|||||||
--- Check current player status.
|
--- Check current player status.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
function AIRBOSS:_CheckPlayerStatus()
|
function AIRBOSS:_CheckPlayerStatus()
|
||||||
|
-- Loop over all players.
|
||||||
-- Loop over all players.
|
|
||||||
for _playerName, _playerData in pairs( self.players ) do
|
for _playerName, _playerData in pairs( self.players ) do
|
||||||
local playerData = _playerData -- #AIRBOSS.PlayerData
|
local playerData = _playerData -- #AIRBOSS.PlayerData
|
||||||
|
|
||||||
@@ -8079,8 +8157,14 @@ function AIRBOSS:_CheckPlayerStatus()
|
|||||||
-- TODO: This might cause problems if the CCA is set to be very small!
|
-- TODO: This might cause problems if the CCA is set to be very small!
|
||||||
if unit:IsInZone( self.zoneCCA ) then
|
if unit:IsInZone( self.zoneCCA ) then
|
||||||
|
|
||||||
-- VNAO Edit - Added wrapped up call to LSO grading
|
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET
|
||||||
if playerData.step==AIRBOSS.PatternStep.WAKE then-- VNAO Edit - Added
|
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
|
||||||
|
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
|
||||||
|
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER
|
||||||
|
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
||||||
|
|
||||||
|
-- VNAO Edit - Added wrapped up call to LSO grading Hornet
|
||||||
|
if playerData.step==AIRBOSS.PatternStep.WAKE and hornet then-- VNAO Edit - Added
|
||||||
if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added
|
if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added
|
||||||
playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added
|
playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added
|
||||||
elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added
|
elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added
|
||||||
@@ -8104,6 +8188,30 @@ function AIRBOSS:_CheckPlayerStatus()
|
|||||||
end -- VNAO Edit - Added
|
end -- VNAO Edit - Added
|
||||||
end-- VNAO Edit - Added
|
end-- VNAO Edit - Added
|
||||||
|
|
||||||
|
-- VNAO Edit - Added wrapped up call to LSO grading Tomcat
|
||||||
|
if playerData.step==AIRBOSS.PatternStep.WAKE and tomcat then-- VNAO Edit - Added
|
||||||
|
if math.abs(playerData.unit:GetRoll())>35 and math.abs(playerData.unit:GetRoll())<=40 then-- VNAO Edit - Added
|
||||||
|
playerData.wrappedUpAtWakeLittle = true -- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetRoll()) >40 and math.abs(playerData.unit:GetRoll())<=45 then-- VNAO Edit - Added
|
||||||
|
playerData.wrappedUpAtWakeFull = true-- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetRoll()) >45 then-- VNAO Edit - Added
|
||||||
|
playerData.wrappedUpAtWakeUnderline = true -- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetRoll()) <12 and math.abs(playerData.unit:GetRoll()) >=5 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments
|
||||||
|
playerData.AAatWakeLittle = true -- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetRoll()) <5 and math.abs(playerData.unit:GetRoll()) >=2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments
|
||||||
|
playerData.AAatWakeFull = true -- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetRoll()) <2 then -- VNAO Edit - Added a new AA comment based on discussion with Lipps today, and going to replace the AA at the X with the original LUL comments
|
||||||
|
playerData.AAatWakeUnderline = true -- VNAO Edit - Added
|
||||||
|
else -- VNAO Edit - Added
|
||||||
|
end -- VNAO Edit - Added
|
||||||
|
|
||||||
|
if math.abs(playerData.unit:GetAoA())>= 15 then -- VNAO Edit - Added
|
||||||
|
playerData.AFU = true -- VNAO Edit - Added
|
||||||
|
elseif math.abs(playerData.unit:GetAoA())<= 5 then -- VNAO Edit - Added
|
||||||
|
playerData.AFU = true -- VNAO Edit - Added
|
||||||
|
else -- VNAO Edit - Added
|
||||||
|
end -- VNAO Edit - Added
|
||||||
|
end-- VNAO Edit - Added
|
||||||
|
|
||||||
-- Display aircraft attitude and other parameters as message text.
|
-- Display aircraft attitude and other parameters as message text.
|
||||||
if playerData.attitudemonitor then
|
if playerData.attitudemonitor then
|
||||||
@@ -9564,7 +9672,7 @@ end
|
|||||||
--- Break entry for case I/II recoveries.
|
--- Break entry for case I/II recoveries.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #AIRBOSS.PlayerData playerData Player data table.
|
-- @param #AIRBOSS.PlayerData playerData Player data table.
|
||||||
function AIRBOSS:_BreakEntry( playerData ) --Adam Edits begin 7/24/23
|
function AIRBOSS:_BreakEntry( playerData )
|
||||||
|
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||||
local X, Z = self:_GetDistances( playerData.unit )
|
local X, Z = self:_GetDistances( playerData.unit )
|
||||||
@@ -9575,111 +9683,16 @@ function AIRBOSS:_BreakEntry( playerData ) --Adam Edits begin 7/24/23
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local stern = self:_GetSternCoord()
|
|
||||||
local coord = playerData.unit:GetCoordinate()
|
|
||||||
local dist = coord:Get2DDistance( stern )
|
|
||||||
|
|
||||||
--adam edits
|
|
||||||
local playerCallsign = playerData.unit:GetCallsign()
|
|
||||||
--trigger.action.outText(' Hornet is hook down on pre-break entry for testing hook argument ', 5)
|
|
||||||
--trigger.action.outText(' Hornet callsign is '..playerCallsign, 5)
|
|
||||||
local playerName = playerData.name
|
|
||||||
local unit = playerData.unit
|
|
||||||
|
|
||||||
--local playerName = unit:GetName()
|
|
||||||
--trigger.action.outText(' Hornet name is '..playerName, 5)
|
|
||||||
local unitClient = Unit.getByName(unit:GetName())
|
|
||||||
local hookArgument = unitClient:getDrawArgumentValue(25)
|
|
||||||
local hookArgument_Tomcat = unitClient:getDrawArgumentValue(1305)
|
|
||||||
local speedMPS = playerData.unit:GetVelocityMPS()
|
|
||||||
local speedKTS = UTILS.MpsToKnots( speedMPS )
|
|
||||||
local player_alt = playerData.unit:GetAltitude()
|
|
||||||
|
|
||||||
player_alt_feet = player_alt * 3.28
|
|
||||||
player_alt_feet = player_alt_feet/10
|
|
||||||
player_alt_feet = math.floor(player_alt_feet)*10
|
|
||||||
|
|
||||||
local player_velocity_round = speedKTS * 1.00
|
|
||||||
player_velocity_round = player_velocity_round/10
|
|
||||||
player_velocity_round = math.floor(player_velocity_round)*10
|
|
||||||
|
|
||||||
local player_alt_feet = player_alt * 3.28
|
|
||||||
player_alt_feet = player_alt_feet/10
|
|
||||||
player_alt_feet = math.floor(player_alt_feet)*10
|
|
||||||
|
|
||||||
local Play_SH_Sound = USERSOUND:New( "Airboss Soundfiles/GreatBallsOfFire.ogg" )
|
|
||||||
local Play_666SH_Sound = USERSOUND:New( "Airboss Soundfiles/Runninwiththedevil.ogg" )
|
|
||||||
local playerType = playerData.actype
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if dist <1000 and clientSHBFlag == false then
|
|
||||||
|
|
||||||
if speedKTS > 450 and speedKTS < 590 then
|
|
||||||
if player_alt_feet < 1500 then
|
|
||||||
if hookArgument > 0 or hookArgument_Tomcat > 0 then
|
|
||||||
--trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = true
|
|
||||||
trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType, 10)
|
|
||||||
local sh_message_to_discord = ('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
|
|
||||||
HypeMan.sendBotMessage(sh_message_to_discord)
|
|
||||||
Play_SH_Sound:ToAll()
|
|
||||||
clientSHBFlag = true
|
|
||||||
else
|
|
||||||
--trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = false
|
|
||||||
end
|
|
||||||
-- Next step: Early Break.
|
|
||||||
else
|
|
||||||
end
|
|
||||||
elseif speedKTS > 589 then
|
|
||||||
if player_alt_feet < 625 and player_alt_feet >575 then --SHB 666
|
|
||||||
if hookArgument > 0 or hookArgument_Tomcat > 0 then
|
|
||||||
--trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = true
|
|
||||||
trigger.action.outText(playerName..' performing a 666 Sierra Hotel Break in a '..playerType, 10)
|
|
||||||
local sh_message_to_discord = ('**'..playerName..' is performing a 666 Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
|
|
||||||
HypeMan.sendBotMessage(sh_message_to_discord)
|
|
||||||
Play_666SH_Sound:ToAll()
|
|
||||||
clientSHBFlag = true
|
|
||||||
else
|
|
||||||
--trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = false
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if hookArgument > 0 or hookArgument_Tomcat > 0 then
|
|
||||||
--trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = true
|
|
||||||
trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType, 10)
|
|
||||||
local sh_message_to_discord = ('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
|
|
||||||
HypeMan.sendBotMessage(sh_message_to_discord)
|
|
||||||
Play_SH_Sound:ToAll()
|
|
||||||
clientSHBFlag = true
|
|
||||||
else
|
|
||||||
--trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5)
|
|
||||||
playerData.shb = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
--trigger.action.outText(' Hornet is less than 400 kts so not SHB.... ', 5)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
--trigger.action.outText(' ******TEST OF of Break Entry and distance to CVN is: '..dist, 5)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- Check if we are in front of the boat (diffX > 0).
|
-- Check if we are in front of the boat (diffX > 0).
|
||||||
if self:_CheckLimits( X, Z, self.BreakEntry ) then
|
if self:_CheckLimits( X, Z, self.BreakEntry ) then
|
||||||
--trigger.action.outText(' 2 - Hornet is hook down on break entry for testing hook argument ', 5)
|
|
||||||
|
|
||||||
-- Hint for player about altitude, AoA etc.
|
-- Hint for player about altitude, AoA etc.
|
||||||
self:_PlayerHint( playerData )
|
self:_PlayerHint( playerData )
|
||||||
|
-- Next step: Early Break.
|
||||||
self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.EARLYBREAK )
|
self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.EARLYBREAK )
|
||||||
clientSHBFlag = false
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end--Adam Edits end 7/24/23
|
end
|
||||||
|
|
||||||
--- Break.
|
--- Break.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
@@ -10281,19 +10294,19 @@ function AIRBOSS:_Groove( playerData )
|
|||||||
if rho >= RAR and rho <= RIM then
|
if rho >= RAR and rho <= RIM then
|
||||||
if gd.LUE > 0.22 and lineupError < -0.22 then
|
if gd.LUE > 0.22 and lineupError < -0.22 then
|
||||||
env.info " Drift Right across centre ==> DR-"
|
env.info " Drift Right across centre ==> DR-"
|
||||||
gd.Drift = " DR"
|
gd.Drift = "DR"
|
||||||
self:T( self.lid .. string.format( "Got Drift Right across centre step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
|
self:T( self.lid .. string.format( "Got Drift Right across centre step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
|
||||||
elseif gd.LUE < -0.22 and lineupError > 0.22 then
|
elseif gd.LUE < -0.22 and lineupError > 0.22 then
|
||||||
env.info " Drift Left ==> DL-"
|
env.info " Drift Left ==> DL-"
|
||||||
gd.Drift = " DL"
|
gd.Drift = "DL"
|
||||||
self:T( self.lid .. string.format( "Got Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
|
self:T( self.lid .. string.format( "Got Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
|
||||||
elseif gd.LUE > 0.13 and lineupError < -0.14 then
|
elseif gd.LUE > 0.13 and lineupError < -0.14 then
|
||||||
env.info " Little Drift Right across centre ==> (DR-)"
|
env.info " Little Drift Right across centre ==> (DR-)"
|
||||||
gd.Drift = " (DR)"
|
gd.Drift = "(DR)"
|
||||||
self:T( self.lid .. string.format( "Got Little Drift Right across centre at step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
|
self:T( self.lid .. string.format( "Got Little Drift Right across centre at step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
|
||||||
elseif gd.LUE < -0.13 and lineupError > 0.14 then
|
elseif gd.LUE < -0.13 and lineupError > 0.14 then
|
||||||
env.info " Little Drift Left across centre ==> (DL-)"
|
env.info " Little Drift Left across centre ==> (DL-)"
|
||||||
gd.Drift = " (DL)"
|
gd.Drift = "(DL)"
|
||||||
self:E( self.lid .. string.format( "Got Little Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
|
self:E( self.lid .. string.format( "Got Little Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -11971,10 +11984,12 @@ function AIRBOSS:GetHeading( magnetic )
|
|||||||
hdg = hdg - self.magvar
|
hdg = hdg - self.magvar
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Adjust negative values.
|
-- -- Adjust negative values.
|
||||||
if hdg < 0 then
|
-- if hdg < 0 then
|
||||||
hdg = hdg + 360
|
-- hdg = hdg + 360
|
||||||
end
|
-- end
|
||||||
|
|
||||||
|
hdg = hdg % 360 -- using this to replace the above function to prevent negative values and BRC higher than 360
|
||||||
|
|
||||||
return hdg
|
return hdg
|
||||||
end
|
end
|
||||||
@@ -12240,8 +12255,8 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord )
|
|||||||
local magvar= magnetic and self.magvar or 0
|
local magvar= magnetic and self.magvar or 0
|
||||||
|
|
||||||
-- Ship heading so cross wind is min for the given wind.
|
-- Ship heading so cross wind is min for the given wind.
|
||||||
-- local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 -- VNAO Edit: Using old heading into wind algorithm
|
local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360
|
||||||
local intowind = self:GetHeadingIntoWind_old(vdeck) -- VNAO Edit: Using old heading into wind algorithm
|
|
||||||
|
|
||||||
return intowind, v
|
return intowind, v
|
||||||
end
|
end
|
||||||
@@ -12671,7 +12686,7 @@ function AIRBOSS:_LSOgrade( playerData )
|
|||||||
local TIG = ""
|
local TIG = ""
|
||||||
-- Analyse flight data and convert to LSO text.
|
-- Analyse flight data and convert to LSO text.
|
||||||
if playerData.Tgroove and playerData.Tgroove <= 360 and playerData.case < 3 then --Circuit Added
|
if playerData.Tgroove and playerData.Tgroove <= 360 and playerData.case < 3 then --Circuit Added
|
||||||
TIG = self:_EvalGrooveTime( playerData ) --Circuit Added
|
TIG = self:_EvalGrooveTime( playerData ) or "N/A" --Circuit Added
|
||||||
end --Circuit Added
|
end --Circuit Added
|
||||||
local GXX, nXX = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.XX )
|
local GXX, nXX = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.XX )
|
||||||
local GIM, nIM = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.IM )
|
local GIM, nIM = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.IM )
|
||||||
@@ -12694,6 +12709,7 @@ function AIRBOSS:_LSOgrade( playerData )
|
|||||||
local nS=count(G, '%(')
|
local nS=count(G, '%(')
|
||||||
local nN=N-nS-nL
|
local nN=N-nS-nL
|
||||||
|
|
||||||
|
if TIG=="_OK_" then nL = nL -1 end --Circuit added to prevent grade deduction for perfect groove
|
||||||
|
|
||||||
-- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn.
|
-- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn.
|
||||||
local Tgroove=playerData.Tgroove
|
local Tgroove=playerData.Tgroove
|
||||||
@@ -12723,7 +12739,6 @@ function AIRBOSS:_LSOgrade( playerData )
|
|||||||
else
|
else
|
||||||
|
|
||||||
if vtol then
|
if vtol then
|
||||||
|
|
||||||
-- Add AV-8B Harrier devation allowances due to lower groundspeed and 3x conventional groove time, this allows to maintain LSO tolerances while respecting the deviations are not unsafe.--Pene testing
|
-- Add AV-8B Harrier devation allowances due to lower groundspeed and 3x conventional groove time, this allows to maintain LSO tolerances while respecting the deviations are not unsafe.--Pene testing
|
||||||
-- Large devaitions still result in a No Grade, A Unicorn still requires a clean pass with no deviation.
|
-- Large devaitions still result in a No Grade, A Unicorn still requires a clean pass with no deviation.
|
||||||
|
|
||||||
@@ -12865,16 +12880,21 @@ function AIRBOSS:_LSOgrade( playerData )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- VNAO EDIT: Subtract 1pt from overall grade if it is a 1 wire. If it's already a 1pt pass, ignore.
|
-- -- VNAO EDIT: Subtract 1pt from overall grade if it is a 1 wire. If it's already a 1pt pass, ignore.
|
||||||
if playerData.wire == 1 and points > 1 then -- VNAO EDIT: added
|
-- if playerData.wire == 1 and points > 1 then -- VNAO EDIT: added
|
||||||
if points == 4 then -- VNAO EDIT: added
|
-- if points == 4 then -- VNAO EDIT: added
|
||||||
points = 3 -- VNAO EDIT: added
|
-- points = 3 -- VNAO EDIT: added
|
||||||
grade = "(OK)" -- VNAO EDIT: added
|
-- grade = "(OK)" -- VNAO EDIT: added
|
||||||
elseif points == 3 then -- VNAO EDIT: added
|
-- elseif points == 3 then -- VNAO EDIT: added
|
||||||
points = 2 -- VNAO EDIT: added
|
-- points = 2 -- VNAO EDIT: added
|
||||||
grade = "--" -- VNAO EDIT: added
|
-- grade = "--" -- VNAO EDIT: added
|
||||||
end -- VNAO EDIT: added
|
-- end -- VNAO EDIT: added
|
||||||
end -- VNAO EDIT: added
|
-- end -- VNAO EDIT: added
|
||||||
|
|
||||||
|
-- Circuit edit only take points awary from a 1 wire if there are more than 4 other deviations
|
||||||
|
if playerData.wire == 1 and points >= 3 and N > 4 then
|
||||||
|
points = points -1
|
||||||
|
end
|
||||||
|
|
||||||
env.info("Returning: " .. grade .. " " .. points .. " " .. G)
|
env.info("Returning: " .. grade .. " " .. points .. " " .. G)
|
||||||
|
|
||||||
@@ -12950,6 +12970,7 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep )
|
|||||||
|
|
||||||
-- Speed via AoA. Depends on aircraft type.
|
-- Speed via AoA. Depends on aircraft type.
|
||||||
local S = nil
|
local S = nil
|
||||||
|
local A = nil --circuit moved this line to be seen outside of this scope
|
||||||
if step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Added To avoid getting an AOA or GS grade in the wires... let's just check left or right in the wires
|
if step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Added To avoid getting an AOA or GS grade in the wires... let's just check left or right in the wires
|
||||||
if AIRBOSS.PatternStep.GROOVE_AR and playerData.waveoff == true and playerData.owo == true then -- VNAO Edit - Added
|
if AIRBOSS.PatternStep.GROOVE_AR and playerData.waveoff == true and playerData.owo == true then -- VNAO Edit - Added
|
||||||
-- env.info('Adam MOOSE Edit -AR and waved off so do not add AOA or GS errors to comments ') -- VNAO Edit - Added
|
-- env.info('Adam MOOSE Edit -AR and waved off so do not add AOA or GS errors to comments ') -- VNAO Edit - Added
|
||||||
@@ -12970,7 +12991,7 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Glideslope/altitude. Good [-0.3, 0.4] asymmetric!
|
-- Glideslope/altitude. Good [-0.3, 0.4] asymmetric!
|
||||||
local A = nil
|
|
||||||
if GSE > self.gle.HIGH then
|
if GSE > self.gle.HIGH then
|
||||||
A = underline( "H" )
|
A = underline( "H" )
|
||||||
elseif GSE > self.gle.High then
|
elseif GSE > self.gle.High then
|
||||||
|
|||||||
@@ -1321,13 +1321,19 @@ end
|
|||||||
-- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`.
|
-- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`.
|
||||||
-- @param #number Speed Orbit indicated airspeed in knots at the set altitude ASL. Default 350 KIAS.
|
-- @param #number Speed Orbit indicated airspeed in knots at the set altitude ASL. Default 350 KIAS.
|
||||||
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
-- @param #number Heading Heading of race-track pattern in degrees. Default 270 (East to West).
|
||||||
-- @param #number Leg Length of race-track in NM. Default 10 NM.
|
-- @param #number Leg Length of race-track in NM. Default 10 NM. Set to 0 for a simple circular orbit.
|
||||||
-- @param #number RefuelSystem Refueling system (0=boom, 1=probe). This info is *only* for AIRWINGs so they launch the right tanker type.
|
-- @param #number RefuelSystem Refueling system (0=boom, 1=probe). This info is *only* for AIRWINGs so they launch the right tanker type.
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
function AUFTRAG:NewTANKER(Coordinate, Altitude, Speed, Heading, Leg, RefuelSystem)
|
function AUFTRAG:NewTANKER(Coordinate, Altitude, Speed, Heading, Leg, RefuelSystem)
|
||||||
|
|
||||||
|
local mission
|
||||||
|
if Leg == 0 then
|
||||||
|
mission=AUFTRAG:NewORBIT_CIRCLE(Coordinate,Altitude,Speed)
|
||||||
|
else
|
||||||
|
mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate,Altitude,Speed,Heading,Leg)
|
||||||
|
end
|
||||||
-- Create ORBIT first.
|
-- Create ORBIT first.
|
||||||
local mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg)
|
--local mission=AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg)
|
||||||
|
|
||||||
-- Mission type TANKER.
|
-- Mission type TANKER.
|
||||||
mission.type=AUFTRAG.Type.TANKER
|
mission.type=AUFTRAG.Type.TANKER
|
||||||
@@ -1727,7 +1733,7 @@ function AUFTRAG:NewSEADInZone(TargetZone, Altitude, TargetTypes, Duration)
|
|||||||
|
|
||||||
local mission=AUFTRAG:New(AUFTRAG.Type.SEAD)
|
local mission=AUFTRAG:New(AUFTRAG.Type.SEAD)
|
||||||
|
|
||||||
mission:_TargetFromObject(TargetZone)
|
--mission:_TargetFromObject(TargetZone)
|
||||||
|
|
||||||
-- DCS Task options:
|
-- DCS Task options:
|
||||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
||||||
@@ -2318,8 +2324,9 @@ end
|
|||||||
-- @param #number Speed Speed in knots.
|
-- @param #number Speed Speed in knots.
|
||||||
-- @param #number Altitude Altitude in feet. Only for airborne units. Default 2000 feet ASL.
|
-- @param #number Altitude Altitude in feet. Only for airborne units. Default 2000 feet ASL.
|
||||||
-- @param #string Formation Formation used by ground units during patrol. Default "Off Road".
|
-- @param #string Formation Formation used by ground units during patrol. Default "Off Road".
|
||||||
|
-- @param #number StayInZoneTime Stay this many seconds in the zone when done, only then drive back.
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation)
|
function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation, StayInZoneTime)
|
||||||
|
|
||||||
local mission=AUFTRAG:New(AUFTRAG.Type.CAPTUREZONE)
|
local mission=AUFTRAG:New(AUFTRAG.Type.CAPTUREZONE)
|
||||||
|
|
||||||
@@ -2333,6 +2340,7 @@ function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation)
|
|||||||
mission.optionROE=ENUMS.ROE.ReturnFire
|
mission.optionROE=ENUMS.ROE.ReturnFire
|
||||||
mission.optionROT=ENUMS.ROT.PassiveDefense
|
mission.optionROT=ENUMS.ROT.PassiveDefense
|
||||||
mission.optionAlarm=ENUMS.AlarmState.Auto
|
mission.optionAlarm=ENUMS.AlarmState.Auto
|
||||||
|
mission.StayInZoneTime = StayInZoneTime
|
||||||
|
|
||||||
mission.missionFraction=0.1
|
mission.missionFraction=0.1
|
||||||
mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or nil
|
mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or nil
|
||||||
@@ -4010,6 +4018,23 @@ function AUFTRAG:IsOver()
|
|||||||
return over
|
return over
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if mission is repeatable.
|
||||||
|
-- @param #AUFTRAG self
|
||||||
|
-- @return #boolean If true, mission is repeatable.
|
||||||
|
function AUFTRAG:IsRepeatable()
|
||||||
|
local repeatmeS=self.repeatedSuccess<self.NrepeatSuccess or self.repeated<self.Nrepeat
|
||||||
|
local repeatmeF=self.repeatedFailure<self.NrepeatFailure or self.repeated<self.Nrepeat
|
||||||
|
if repeatmeS==true or repeatmeF==true then return true else return false end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if mission is NOT repeatable.
|
||||||
|
-- @param #AUFTRAG self
|
||||||
|
-- @return #boolean If true, mission is NOT repeatable.
|
||||||
|
function AUFTRAG:IsNotRepeatable()
|
||||||
|
return not self:IsRepeatable()
|
||||||
|
end
|
||||||
|
|
||||||
--- Check if mission is NOT over.
|
--- Check if mission is NOT over.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @return #boolean If true, mission is NOT over yet.
|
-- @return #boolean If true, mission is NOT over yet.
|
||||||
|
|||||||
@@ -509,7 +509,7 @@ do
|
|||||||
-- @field #AWACS
|
-- @field #AWACS
|
||||||
AWACS = {
|
AWACS = {
|
||||||
ClassName = "AWACS", -- #string
|
ClassName = "AWACS", -- #string
|
||||||
version = "0.2.72", -- #string
|
version = "0.2.73", -- #string
|
||||||
lid = "", -- #string
|
lid = "", -- #string
|
||||||
coalition = coalition.side.BLUE, -- #number
|
coalition = coalition.side.BLUE, -- #number
|
||||||
coalitiontxt = "blue", -- #string
|
coalitiontxt = "blue", -- #string
|
||||||
@@ -1596,6 +1596,16 @@ function AWACS:SetLocale(Locale)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Set own coordinate for BullsEye.
|
||||||
|
-- @param #AWACS self
|
||||||
|
-- @param Core.Point#COORDINATE
|
||||||
|
-- @return #AWACS self
|
||||||
|
function AWACS:SetBullsCoordinate(Coordinate)
|
||||||
|
self:T(self.lid.."SetBullsCoordinate")
|
||||||
|
self.AOCoordinate = Coordinate
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [User] Set the max mission range flights can be away from their home base.
|
--- [User] Set the max mission range flights can be away from their home base.
|
||||||
-- @param #AWACS self
|
-- @param #AWACS self
|
||||||
-- @param #number NM Distance in nautical miles
|
-- @param #number NM Distance in nautical miles
|
||||||
@@ -2021,7 +2031,9 @@ function AWACS:SetAdditionalZone(Zone, Draw)
|
|||||||
self.BorderZone = Zone
|
self.BorderZone = Zone
|
||||||
if self.debug then
|
if self.debug then
|
||||||
Zone:DrawZone(self.coalition,{1,0.64,0},1,{1,0.64,0},0.2,1,true)
|
Zone:DrawZone(self.coalition,{1,0.64,0},1,{1,0.64,0},0.2,1,true)
|
||||||
MARKER:New(Zone:GetCoordinate(),"Defensive Zone"):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
MARKER:New(Zone:GetCoordinate(),"Defensive Zone"):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
elseif Draw then
|
elseif Draw then
|
||||||
Zone:DrawZone(self.coalition,{1,0.64,0},1,{1,0.64,0},0.2,1,true)
|
Zone:DrawZone(self.coalition,{1,0.64,0},1,{1,0.64,0},0.2,1,true)
|
||||||
end
|
end
|
||||||
@@ -2041,7 +2053,9 @@ function AWACS:SetRejectionZone(Zone,Draw)
|
|||||||
--MARKER:New(Zone:GetCoordinate(),"Rejection Zone"):ToAll()
|
--MARKER:New(Zone:GetCoordinate(),"Rejection Zone"):ToAll()
|
||||||
elseif self.debug then
|
elseif self.debug then
|
||||||
Zone:DrawZone(self.coalition,{1,0.64,0},1,{1,0.64,0},0.2,1,true)
|
Zone:DrawZone(self.coalition,{1,0.64,0},1,{1,0.64,0},0.2,1,true)
|
||||||
MARKER:New(Zone:GetCoordinate(),"Rejection Zone"):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
MARKER:New(Zone:GetCoordinate(),"Rejection Zone"):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -4094,10 +4108,14 @@ function AWACS:_CreateAnchorStackFromMarker(Name,Coord)
|
|||||||
if self.debug then
|
if self.debug then
|
||||||
AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true)
|
AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true)
|
||||||
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
||||||
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
||||||
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.AnchorStacks:Push(AnchorStackOne,newname)
|
self.AnchorStacks:Push(AnchorStackOne,newname)
|
||||||
@@ -4140,10 +4158,14 @@ function AWACS:_CreateAnchorStack()
|
|||||||
--self.AnchorStacks:Flush()
|
--self.AnchorStacks:Flush()
|
||||||
AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true)
|
AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true)
|
||||||
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
||||||
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
||||||
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
self.AnchorStacks:Push(AnchorStackOne,newname)
|
self.AnchorStacks:Push(AnchorStackOne,newname)
|
||||||
else
|
else
|
||||||
@@ -4167,10 +4189,14 @@ function AWACS:_CreateAnchorStack()
|
|||||||
if self.debug then
|
if self.debug then
|
||||||
AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true)
|
AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true)
|
||||||
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
||||||
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
||||||
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
self.AnchorStacks:Push(AnchorStackOne,newname)
|
self.AnchorStacks:Push(AnchorStackOne,newname)
|
||||||
end
|
end
|
||||||
@@ -5102,10 +5128,14 @@ function AWACS:AddCAPAirWing(AirWing,Zone)
|
|||||||
if self.debug then
|
if self.debug then
|
||||||
AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true)
|
AnchorStackOne.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true)
|
||||||
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
||||||
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
local stationtag = string.format("Station: %s\nCoordinate: %s",newname,self.StationZone:GetCoordinate():ToStringLLDDM())
|
||||||
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
AnchorStackOne.AnchorMarker=MARKER:New(AnchorStackOne.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
self.AnchorStacks:Push(AnchorStackOne,newname)
|
self.AnchorStacks:Push(AnchorStackOne,newname)
|
||||||
AirWing.HasOwnStation = true
|
AirWing.HasOwnStation = true
|
||||||
@@ -5948,23 +5978,35 @@ function AWACS:onafterStart(From, Event, To)
|
|||||||
self.OpsZone:DrawZone(self.coalition,{1,0,0},1,{1,0,0},0.2,5,true)
|
self.OpsZone:DrawZone(self.coalition,{1,0,0},1,{1,0,0},0.2,5,true)
|
||||||
local AOCoordString = self.AOCoordinate:ToStringLLDDM()
|
local AOCoordString = self.AOCoordinate:ToStringLLDDM()
|
||||||
local Rocktag = string.format("FEZ: %s\nBulls Coordinate: %s",self.AOName,AOCoordString)
|
local Rocktag = string.format("FEZ: %s\nBulls Coordinate: %s",self.AOName,AOCoordString)
|
||||||
MARKER:New(self.AOCoordinate,Rocktag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
MARKER:New(self.AOCoordinate,Rocktag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
self.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true)
|
self.StationZone:DrawZone(self.coalition,{0,0,1},1,{0,0,1},0.2,5,true)
|
||||||
local stationtag = string.format("Station: %s\nCoordinate: %s",self.StationZoneName,self.StationZone:GetCoordinate():ToStringLLDDM())
|
local stationtag = string.format("Station: %s\nCoordinate: %s",self.StationZoneName,self.StationZone:GetCoordinate():ToStringLLDDM())
|
||||||
if not self.GCI then
|
if not self.GCI then
|
||||||
MARKER:New(self.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
MARKER:New(self.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
self.OrbitZone:DrawZone(self.coalition,{0,1,0},1,{0,1,0},0.2,5,true)
|
self.OrbitZone:DrawZone(self.coalition,{0,1,0},1,{0,1,0},0.2,5,true)
|
||||||
MARKER:New(self.OrbitZone:GetCoordinate(),"AIC Orbit Zone"):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
MARKER:New(self.OrbitZone:GetCoordinate(),"AIC Orbit Zone"):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local AOCoordString = self.AOCoordinate:ToStringLLDDM()
|
local AOCoordString = self.AOCoordinate:ToStringLLDDM()
|
||||||
local Rocktag = string.format("FEZ: %s\nBulls Coordinate: %s",self.AOName,AOCoordString)
|
local Rocktag = string.format("FEZ: %s\nBulls Coordinate: %s",self.AOName,AOCoordString)
|
||||||
MARKER:New(self.AOCoordinate,Rocktag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
MARKER:New(self.AOCoordinate,Rocktag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
if not self.GCI then
|
if not self.GCI then
|
||||||
MARKER:New(self.OrbitZone:GetCoordinate(),"AIC Orbit Zone"):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
MARKER:New(self.OrbitZone:GetCoordinate(),"AIC Orbit Zone"):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
local stationtag = string.format("Station: %s\nCoordinate: %s",self.StationZoneName,self.StationZone:GetCoordinate():ToStringLLDDM())
|
local stationtag = string.format("Station: %s\nCoordinate: %s",self.StationZoneName,self.StationZone:GetCoordinate():ToStringLLDDM())
|
||||||
MARKER:New(self.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
if self.AllowMarkers then
|
||||||
|
MARKER:New(self.StationZone:GetCoordinate(),stationtag):ToCoalition(self.coalition)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.GCI then
|
if not self.GCI then
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@
|
|||||||
-- @module Ops.CTLD
|
-- @module Ops.CTLD
|
||||||
-- @image OPS_CTLD.jpg
|
-- @image OPS_CTLD.jpg
|
||||||
|
|
||||||
-- Last Update July 2025
|
-- Last Update Oct 2025
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -147,6 +147,7 @@ CTLD_CARGO = {
|
|||||||
Location = ZONE:New(Location)
|
Location = ZONE:New(Location)
|
||||||
end
|
end
|
||||||
self.Location = Location
|
self.Location = Location
|
||||||
|
self.NoMoveToZone = false
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -783,6 +784,7 @@ do
|
|||||||
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10)
|
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10)
|
||||||
-- -- additionally, you can limit **where** the stock is available (one location only!) - this one is available in a zone called "Vehicle Store".
|
-- -- additionally, you can limit **where** the stock is available (one location only!) - this one is available in a zone called "Vehicle Store".
|
||||||
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10,nil,nil,"Vehicle Store")
|
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10,nil,nil,"Vehicle Store")
|
||||||
|
-- -- Tip: if you want the spawned/built group NOT to move to a MOVE zone, replace AddCratesCargo with AddCratesCargoNoMove (same parameters).
|
||||||
--
|
--
|
||||||
-- -- add infantry unit called "Forward Ops Base" using template "FOB", of type FOB, size 4, i.e. needs four crates to be build:
|
-- -- add infantry unit called "Forward Ops Base" using template "FOB", of type FOB, size 4, i.e. needs four crates to be build:
|
||||||
-- my_ctld:AddCratesCargo("Forward Ops Base",{"FOB"},CTLD_CARGO.Enum.FOB,4)
|
-- my_ctld:AddCratesCargo("Forward Ops Base",{"FOB"},CTLD_CARGO.Enum.FOB,4)
|
||||||
@@ -867,6 +869,8 @@ do
|
|||||||
-- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook
|
-- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook
|
||||||
-- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew.
|
-- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew.
|
||||||
-- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack. it will be a 1 step solution.
|
-- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack. it will be a 1 step solution.
|
||||||
|
-- my_ctld.VehicleMoveFormation = AI.Task.VehicleFormation.VEE -- When a group moves to a MOVE zone, then it takes this formation. Can be a table of formations, which are then randomly chosen. Defaults to "Vee".
|
||||||
|
-- my_ctld.validateAndRepositionUnits = false -- Uses Disposition and other logic to find better ground positions for ground units avoiding trees, water, roads, runways, map scenery, statics and other units in the area. (Default is false)
|
||||||
--
|
--
|
||||||
-- ## 2.1 CH-47 Chinook support
|
-- ## 2.1 CH-47 Chinook support
|
||||||
--
|
--
|
||||||
@@ -1294,6 +1298,7 @@ CTLD = {
|
|||||||
LoadedGroupsTable = {},
|
LoadedGroupsTable = {},
|
||||||
keeploadtable = true,
|
keeploadtable = true,
|
||||||
allowCATransport = false,
|
allowCATransport = false,
|
||||||
|
VehicleMoveFormation = AI.Task.VehicleFormation.VEE,
|
||||||
}
|
}
|
||||||
|
|
||||||
------------------------------
|
------------------------------
|
||||||
@@ -1393,6 +1398,7 @@ CTLD.UnitTypeCapabilities = {
|
|||||||
["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000}, -- 19t cargo, 64 paratroopers.
|
["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000}, -- 19t cargo, 64 paratroopers.
|
||||||
--Actually it's longer, but the center coord is off-center of the model.
|
--Actually it's longer, but the center coord is off-center of the model.
|
||||||
["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
|
["UH-60L_DAP"] = {type="UH-60L_DAP", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 16, cargoweightlimit = 500}, -- UH-60L DAP is an attack helo but can do limited CSAR and CTLD
|
||||||
["MH-60R"] = {type="MH-60R", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
["MH-60R"] = {type="MH-60R", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
["SH-60B"] = {type="SH-60B", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
["SH-60B"] = {type="SH-60B", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
|
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
|
||||||
@@ -1414,7 +1420,7 @@ CTLD.FixedWingTypes = {
|
|||||||
|
|
||||||
--- CTLD class version.
|
--- CTLD class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CTLD.version="1.3.36"
|
CTLD.version="1.3.38"
|
||||||
|
|
||||||
--- Instantiate a new CTLD.
|
--- Instantiate a new CTLD.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
@@ -1552,8 +1558,11 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
|||||||
self.smokedistance = 2000
|
self.smokedistance = 2000
|
||||||
self.movetroopstowpzone = true
|
self.movetroopstowpzone = true
|
||||||
self.movetroopsdistance = 5000
|
self.movetroopsdistance = 5000
|
||||||
|
self.returntroopstobase = true -- if set to false, troops would stay after deployment inside a load zone.
|
||||||
self.troopdropzoneradius = 100
|
self.troopdropzoneradius = 100
|
||||||
|
|
||||||
|
self.VehicleMoveFormation = AI.Task.VehicleFormation.VEE
|
||||||
|
|
||||||
-- added support Hercules Mod
|
-- added support Hercules Mod
|
||||||
self.enableHercules = false -- deprecated
|
self.enableHercules = false -- deprecated
|
||||||
self.enableFixedWing = false
|
self.enableFixedWing = false
|
||||||
@@ -1561,6 +1570,8 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
|||||||
self.FixedMaxAngels = 2000 -- for troop/cargo drop via chute
|
self.FixedMaxAngels = 2000 -- for troop/cargo drop via chute
|
||||||
self.FixedMaxSpeed = 77 -- 280 kph or 150kn eq 77 mps
|
self.FixedMaxSpeed = 77 -- 280 kph or 150kn eq 77 mps
|
||||||
|
|
||||||
|
self.validateAndRepositionUnits = false -- 280 kph or 150kn eq 77 mps
|
||||||
|
|
||||||
-- message suppression
|
-- message suppression
|
||||||
self.suppressmessages = false
|
self.suppressmessages = false
|
||||||
|
|
||||||
@@ -3321,6 +3332,7 @@ function CTLD:_LoadCratesNearby(Group, Unit)
|
|||||||
self:_RefreshLoadCratesMenu(Group, Unit)
|
self:_RefreshLoadCratesMenu(Group, Unit)
|
||||||
-- clean up real world crates
|
-- clean up real world crates
|
||||||
self:_CleanupTrackedCrates(crateidsloaded)
|
self:_CleanupTrackedCrates(crateidsloaded)
|
||||||
|
self:__CratesPickedUp(1, Group, Unit, loaded.Cargo)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -3667,7 +3679,7 @@ function CTLD:_UnloadTroops(Group, Unit)
|
|||||||
inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP)
|
inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP)
|
||||||
end
|
end
|
||||||
if inzone then
|
if inzone then
|
||||||
droppingatbase = true
|
droppingatbase = self.returntroopstobase
|
||||||
end
|
end
|
||||||
-- check for hover unload
|
-- check for hover unload
|
||||||
local hoverunload = self:IsCorrectHover(Unit) --if true we\'re hovering in parameters
|
local hoverunload = self:IsCorrectHover(Unit) --if true we\'re hovering in parameters
|
||||||
@@ -3731,6 +3743,7 @@ function CTLD:_UnloadTroops(Group, Unit)
|
|||||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||||
:InitDelayOff()
|
:InitDelayOff()
|
||||||
:InitSetUnitAbsolutePositions(Positions)
|
:InitSetUnitAbsolutePositions(Positions)
|
||||||
|
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||||
:SpawnFromVec2(randomcoord:GetVec2())
|
:SpawnFromVec2(randomcoord:GetVec2())
|
||||||
self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter],type)
|
self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter],type)
|
||||||
@@ -4177,11 +4190,13 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,Mult
|
|||||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||||
--:InitRandomizeUnits(true,20,2)
|
--:InitRandomizeUnits(true,20,2)
|
||||||
:InitDelayOff()
|
:InitDelayOff()
|
||||||
|
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||||
:SpawnFromVec2(randomcoord)
|
:SpawnFromVec2(randomcoord)
|
||||||
else -- don't random position of e.g. SAM units build as FOB
|
else -- don't random position of e.g. SAM units build as FOB
|
||||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||||
:InitDelayOff()
|
:InitDelayOff()
|
||||||
|
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||||
:SpawnFromVec2(randomcoord)
|
:SpawnFromVec2(randomcoord)
|
||||||
end
|
end
|
||||||
@@ -4197,6 +4212,17 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,Mult
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (Internal) Function to get a vehicle formation for a moving group
|
||||||
|
-- @param #CTLD self
|
||||||
|
-- @return #string Formation
|
||||||
|
function CTLD:_GetVehicleFormation()
|
||||||
|
local VehicleMoveFormation = self.VehicleMoveFormation or AI.Task.VehicleFormation.VEE
|
||||||
|
if type(self.VehicleMoveFormation)=="table" then
|
||||||
|
VehicleMoveFormation = self.VehicleMoveFormation[math.random(1,#self.VehicleMoveFormation)]
|
||||||
|
end
|
||||||
|
return VehicleMoveFormation
|
||||||
|
end
|
||||||
|
|
||||||
--- (Internal) Function to move group to WP zone.
|
--- (Internal) Function to move group to WP zone.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @param Wrapper.Group#GROUP Group The Group to move.
|
-- @param Wrapper.Group#GROUP Group The Group to move.
|
||||||
@@ -4211,18 +4237,20 @@ function CTLD:_MoveGroupToZone(Group)
|
|||||||
-- yes, we can ;)
|
-- yes, we can ;)
|
||||||
local groupname = Group:GetName()
|
local groupname = Group:GetName()
|
||||||
local zonecoord = zone:GetRandomCoordinate(20,125) -- Core.Point#COORDINATE
|
local zonecoord = zone:GetRandomCoordinate(20,125) -- Core.Point#COORDINATE
|
||||||
local coordinate = zonecoord:GetVec2()
|
local formation = self:_GetVehicleFormation()
|
||||||
|
--local coordinate = zonecoord:GetVec2()
|
||||||
Group:SetAIOn()
|
Group:SetAIOn()
|
||||||
Group:OptionAlarmStateAuto()
|
Group:OptionAlarmStateAuto()
|
||||||
Group:OptionDisperseOnAttack(30)
|
Group:OptionDisperseOnAttack(30)
|
||||||
Group:OptionROEOpenFirePossible()
|
Group:OptionROEOpenFire()
|
||||||
Group:RouteToVec2(coordinate,5)
|
Group:RouteGroundTo(zonecoord,25,formation)
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Housekeeping - Cleanup crates when build
|
--- (Internal) Housekeeping - Cleanup crates when build
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
|
--
|
||||||
-- @param #table Crates Table of #CTLD_CARGO objects near the unit.
|
-- @param #table Crates Table of #CTLD_CARGO objects near the unit.
|
||||||
-- @param #CTLD.Buildable Build Table build object.
|
-- @param #CTLD.Buildable Build Table build object.
|
||||||
-- @param #number Number Number of objects in Crates (found) to limit search.
|
-- @param #number Number Number of objects in Crates (found) to limit search.
|
||||||
@@ -4488,7 +4516,8 @@ function CTLD:_RefreshF10Menus()
|
|||||||
end
|
end
|
||||||
for _,cargoObj in pairs(self.Cargo_Crates) do
|
for _,cargoObj in pairs(self.Cargo_Crates) do
|
||||||
if not cargoObj.DontShowInMenu then
|
if not cargoObj.DontShowInMenu then
|
||||||
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
local needed = cargoObj:GetCratesNeeded() or 1
|
||||||
|
local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
if cargoObj.Location then txt = txt.."[R]" end
|
||||||
local stock = cargoObj:GetStock()
|
local stock = cargoObj:GetStock()
|
||||||
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
||||||
@@ -4499,7 +4528,8 @@ function CTLD:_RefreshF10Menus()
|
|||||||
end
|
end
|
||||||
for _,cargoObj in pairs(self.Cargo_Statics) do
|
for _,cargoObj in pairs(self.Cargo_Statics) do
|
||||||
if not cargoObj.DontShowInMenu then
|
if not cargoObj.DontShowInMenu then
|
||||||
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
local needed = cargoObj:GetCratesNeeded() or 1
|
||||||
|
local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
if cargoObj.Location then txt = txt.."[R]" end
|
||||||
local stock = cargoObj:GetStock()
|
local stock = cargoObj:GetStock()
|
||||||
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
||||||
@@ -4511,7 +4541,8 @@ function CTLD:_RefreshF10Menus()
|
|||||||
else
|
else
|
||||||
for _,cargoObj in pairs(self.Cargo_Crates) do
|
for _,cargoObj in pairs(self.Cargo_Crates) do
|
||||||
if not cargoObj.DontShowInMenu then
|
if not cargoObj.DontShowInMenu then
|
||||||
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
local needed = cargoObj:GetCratesNeeded() or 1
|
||||||
|
local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
if cargoObj.Location then txt = txt.."[R]" end
|
||||||
local stock = cargoObj:GetStock()
|
local stock = cargoObj:GetStock()
|
||||||
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
||||||
@@ -4522,7 +4553,8 @@ function CTLD:_RefreshF10Menus()
|
|||||||
end
|
end
|
||||||
for _,cargoObj in pairs(self.Cargo_Statics) do
|
for _,cargoObj in pairs(self.Cargo_Statics) do
|
||||||
if not cargoObj.DontShowInMenu then
|
if not cargoObj.DontShowInMenu then
|
||||||
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
local needed = cargoObj:GetCratesNeeded() or 1
|
||||||
|
local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
if cargoObj.Location then txt = txt.."[R]" end
|
||||||
local stock = cargoObj:GetStock()
|
local stock = cargoObj:GetStock()
|
||||||
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
||||||
@@ -4534,14 +4566,15 @@ function CTLD:_RefreshF10Menus()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if self.usesubcats then
|
if self.usesubcats == true then
|
||||||
local subcatmenus = {}
|
local subcatmenus = {}
|
||||||
for catName, _ in pairs(self.subcats) do
|
for catName, _ in pairs(self.subcats) do
|
||||||
subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) -- fixed variable case
|
subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) -- fixed variable case
|
||||||
end
|
end
|
||||||
for _, cargoObj in pairs(self.Cargo_Crates) do
|
for _, cargoObj in pairs(self.Cargo_Crates) do
|
||||||
if not cargoObj.DontShowInMenu then
|
if not cargoObj.DontShowInMenu then
|
||||||
local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0)
|
local needed = cargoObj:GetCratesNeeded() or 1
|
||||||
|
local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0)
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
if cargoObj.Location then txt = txt.."[R]" end
|
||||||
local stock = cargoObj:GetStock()
|
local stock = cargoObj:GetStock()
|
||||||
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
||||||
@@ -4550,7 +4583,8 @@ function CTLD:_RefreshF10Menus()
|
|||||||
end
|
end
|
||||||
for _, cargoObj in pairs(self.Cargo_Statics) do
|
for _, cargoObj in pairs(self.Cargo_Statics) do
|
||||||
if not cargoObj.DontShowInMenu then
|
if not cargoObj.DontShowInMenu then
|
||||||
local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0)
|
local needed = cargoObj:GetCratesNeeded() or 1
|
||||||
|
local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0)
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
if cargoObj.Location then txt = txt.."[R]" end
|
||||||
local stock = cargoObj:GetStock()
|
local stock = cargoObj:GetStock()
|
||||||
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
||||||
@@ -4560,7 +4594,8 @@ function CTLD:_RefreshF10Menus()
|
|||||||
else
|
else
|
||||||
for _, cargoObj in pairs(self.Cargo_Crates) do
|
for _, cargoObj in pairs(self.Cargo_Crates) do
|
||||||
if not cargoObj.DontShowInMenu then
|
if not cargoObj.DontShowInMenu then
|
||||||
local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0)
|
local needed = cargoObj:GetCratesNeeded() or 1
|
||||||
|
local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0)
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
if cargoObj.Location then txt = txt.."[R]" end
|
||||||
local stock = cargoObj:GetStock()
|
local stock = cargoObj:GetStock()
|
||||||
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
||||||
@@ -4569,7 +4604,8 @@ function CTLD:_RefreshF10Menus()
|
|||||||
end
|
end
|
||||||
for _, cargoObj in pairs(self.Cargo_Statics) do
|
for _, cargoObj in pairs(self.Cargo_Statics) do
|
||||||
if not cargoObj.DontShowInMenu then
|
if not cargoObj.DontShowInMenu then
|
||||||
local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0)
|
local needed = cargoObj:GetCratesNeeded() or 1
|
||||||
|
local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0)
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
if cargoObj.Location then txt = txt.."[R]" end
|
||||||
local stock = cargoObj:GetStock()
|
local stock = cargoObj:GetStock()
|
||||||
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
||||||
@@ -5109,7 +5145,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
|
|||||||
inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.SHIP)
|
inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.SHIP)
|
||||||
end
|
end
|
||||||
if inzone then
|
if inzone then
|
||||||
droppingatbase = true
|
droppingatbase = self.returntroopstobase
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
|
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
|
||||||
@@ -5194,6 +5230,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
|
|||||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template, alias)
|
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template, alias)
|
||||||
:InitDelayOff()
|
:InitDelayOff()
|
||||||
:InitSetUnitAbsolutePositions(Positions)
|
:InitSetUnitAbsolutePositions(Positions)
|
||||||
|
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||||
:SpawnFromVec2(randomcoord:GetVec2())
|
:SpawnFromVec2(randomcoord:GetVec2())
|
||||||
self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter], cType)
|
self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter], cType)
|
||||||
@@ -5400,6 +5437,52 @@ function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,Sub
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Identical to AddCratesCargo, but registers the cargo so the spawned/built group does not move to MOVE zones.
|
||||||
|
--- User function - Add *generic* crate-type loadable as cargo. This type will create crates that need to be loaded, moved, dropped and built.
|
||||||
|
-- @param #CTLD self
|
||||||
|
-- @param #string Name Unique name of this type of cargo. E.g. "Humvee".
|
||||||
|
-- @param #table Templates Table of #string names of late activated Wrapper.Group#GROUP building this cargo.
|
||||||
|
-- @param #CTLD_CARGO.Enum Type Type of cargo. I.e. VEHICLE or FOB. VEHICLE will move to destination zones when dropped/build, FOB stays put.
|
||||||
|
-- @param #number NoCrates Number of crates needed to build this cargo.
|
||||||
|
-- @param #number PerCrateMass Mass in kg of each crate
|
||||||
|
-- @param #number Stock Number of buildable groups in stock. Nil for unlimited.
|
||||||
|
-- @param #string SubCategory Name of sub-category (optional).
|
||||||
|
-- @param #boolean DontShowInMenu (optional) If set to "true" this won't show up in the menu.
|
||||||
|
-- @param Core.Zone#ZONE Location (optional) If set, the cargo item is **only** available here. Can be a #ZONE object or the name of a zone as #string.
|
||||||
|
-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH58D"}.
|
||||||
|
-- @param #string Category Static category name (optional). If set, spawn cargo crate with an alternate category type, e.g. "Cargos".
|
||||||
|
-- @param #string TypeName Static type name (optional). If set, spawn cargo crate with an alternate type shape, e.g. "iso_container".
|
||||||
|
-- @param #string ShapeName Static shape name (optional). If set, spawn cargo crate with an alternate type sub-shape, e.g. "iso_container_cargo".
|
||||||
|
-- @return #CTLD self
|
||||||
|
function CTLD:AddCratesCargoNoMove(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location,UnitTypes,Category,TypeName,ShapeName)
|
||||||
|
self:T(self.lid .. " AddCratesCargoNoMove")
|
||||||
|
if not self:_CheckTemplates(Templates) then
|
||||||
|
self:E(self.lid .. "Crates Cargo for " .. Name .. " has missing template(s)!" )
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
self.CargoCounter = self.CargoCounter + 1
|
||||||
|
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
|
||||||
|
cargo.NoMoveToZone = true
|
||||||
|
if UnitTypes then
|
||||||
|
cargo:AddUnitTypeName(UnitTypes)
|
||||||
|
end
|
||||||
|
cargo:SetStaticTypeAndShape("Cargos",self.basetype)
|
||||||
|
if TypeName then
|
||||||
|
cargo:SetStaticTypeAndShape(Category,TypeName,ShapeName)
|
||||||
|
end
|
||||||
|
table.insert(self.Cargo_Crates,cargo)
|
||||||
|
self.templateToCargoName = self.templateToCargoName or {}
|
||||||
|
if type(Templates)=="table" then
|
||||||
|
for _,t in pairs(Templates) do self.templateToCargoName[t] = Name end
|
||||||
|
else
|
||||||
|
self.templateToCargoName[Templates] = Name
|
||||||
|
end
|
||||||
|
self.nomovetozone_names = self.nomovetozone_names or {}
|
||||||
|
self.nomovetozone_names[Name] = true
|
||||||
|
if SubCategory and self.usesubcats ~= true then self.usesubcats=true end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- User function - Add *generic* static-type loadable as cargo. This type will create cargo that needs to be loaded, moved and dropped.
|
--- User function - Add *generic* static-type loadable as cargo. This type will create cargo that needs to be loaded, moved and dropped.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @param #string Name Unique name of this type of cargo as set in the mission editor (note: UNIT name!), e.g. "Ammunition-1".
|
-- @param #string Name Unique name of this type of cargo as set in the mission editor (note: UNIT name!), e.g. "Ammunition-1".
|
||||||
@@ -5645,7 +5728,13 @@ function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Ship
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local ctldzone = {} -- #CTLD.CargoZone
|
local exists = true
|
||||||
|
local ctldzone = self:GetCTLDZone(Name, Type) -- #CTLD.CargoZone
|
||||||
|
if not ctldzone then
|
||||||
|
exists = false
|
||||||
|
ctldzone = {}
|
||||||
|
end
|
||||||
|
|
||||||
ctldzone.active = Active or false
|
ctldzone.active = Active or false
|
||||||
ctldzone.color = Color or SMOKECOLOR.Red
|
ctldzone.color = Color or SMOKECOLOR.Red
|
||||||
ctldzone.name = Name or "NONE"
|
ctldzone.name = Name or "NONE"
|
||||||
@@ -5672,10 +5761,55 @@ function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Ship
|
|||||||
ctldzone.shipwidth = Shipwidth or 10
|
ctldzone.shipwidth = Shipwidth or 10
|
||||||
end
|
end
|
||||||
|
|
||||||
self:AddZone(ctldzone)
|
if not exists then
|
||||||
|
self:AddZone(ctldzone)
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- User function - find #CTLD.CargoZone zone by name.
|
||||||
|
-- @param #CTLD self
|
||||||
|
-- @param #string Name Name of this zone.
|
||||||
|
-- @param #string Type Type of this zone, #CTLD.CargoZoneType
|
||||||
|
-- @return #CTLD.CargoZone self
|
||||||
|
function CTLD:GetCTLDZone(Name, Type)
|
||||||
|
|
||||||
|
if Type == CTLD.CargoZoneType.LOAD then
|
||||||
|
for _, z in pairs(self.pickupZones) do
|
||||||
|
if z.name == Name then
|
||||||
|
return z
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif Type == CTLD.CargoZoneType.DROP then
|
||||||
|
for _, z in pairs(self.dropOffZones) do
|
||||||
|
if z.name == Name then
|
||||||
|
return z
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif Type == CTLD.CargoZoneType.SHIP then
|
||||||
|
for _, z in pairs(self.shipZones) do
|
||||||
|
if z.name == Name then
|
||||||
|
return z
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif Type == CTLD.CargoZoneType.BEACON then
|
||||||
|
for _, z in pairs(self.droppedBeacons) do
|
||||||
|
if z.name == Name then
|
||||||
|
return z
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for _, z in pairs(self.wpZones) do
|
||||||
|
if z.name == Name then
|
||||||
|
return z
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- User function - Creates and adds a #CTLD.CargoZone zone for this CTLD instance from an Airbase or FARP name.
|
--- User function - Creates and adds a #CTLD.CargoZone zone for this CTLD instance from an Airbase or FARP name.
|
||||||
-- Zones of type LOAD: Players load crates and troops here.
|
-- Zones of type LOAD: Players load crates and troops here.
|
||||||
-- Zones of type DROP: Players can drop crates here. Note that troops can be unloaded anywhere.
|
-- Zones of type DROP: Players can drop crates here. Note that troops can be unloaded anywhere.
|
||||||
@@ -6906,6 +7040,7 @@ end
|
|||||||
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
||||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||||
:InitRandomizeUnits(randompositions,20,2)
|
:InitRandomizeUnits(randompositions,20,2)
|
||||||
|
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||||
:InitDelayOff()
|
:InitDelayOff()
|
||||||
:OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp)
|
:OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp)
|
||||||
:SpawnFromVec2(randomcoord)
|
:SpawnFromVec2(randomcoord)
|
||||||
@@ -7059,12 +7194,14 @@ end
|
|||||||
if canmove then
|
if canmove then
|
||||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||||
:InitRandomizeUnits(true,20,2)
|
:InitRandomizeUnits(true,20,2)
|
||||||
|
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||||
:InitDelayOff()
|
:InitDelayOff()
|
||||||
:OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp)
|
:OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp)
|
||||||
:SpawnFromVec2(randomcoord)
|
:SpawnFromVec2(randomcoord)
|
||||||
else -- don't random position of e.g. SAM units build as FOB
|
else -- don't random position of e.g. SAM units build as FOB
|
||||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||||
:InitDelayOff()
|
:InitDelayOff()
|
||||||
|
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||||
:OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp)
|
:OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp)
|
||||||
:SpawnFromVec2(randomcoord)
|
:SpawnFromVec2(randomcoord)
|
||||||
end
|
end
|
||||||
@@ -7134,6 +7271,16 @@ end
|
|||||||
local filepath = self.filepath
|
local filepath = self.filepath
|
||||||
self:__Save(interval,filepath,filename)
|
self:__Save(interval,filepath,filename)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if type(self.VehicleMoveFormation) == "table" then
|
||||||
|
local Formations = {}
|
||||||
|
for _,_formation in pairs(self.VehicleMoveFormation) do
|
||||||
|
table.insert(Formations,_formation)
|
||||||
|
end
|
||||||
|
self.VehicleMoveFormation = nil
|
||||||
|
self.VehicleMoveFormation = Formations
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -7404,8 +7551,11 @@ end
|
|||||||
-- @return #CTLD self
|
-- @return #CTLD self
|
||||||
function CTLD:onafterCratesBuild(From, Event, To, Group, Unit, Vehicle)
|
function CTLD:onafterCratesBuild(From, Event, To, Group, Unit, Vehicle)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
if self.movetroopstowpzone then
|
if self.movetroopstowpzone and Vehicle then
|
||||||
self:_MoveGroupToZone(Vehicle)
|
local cg = self:GetGenericCargoObjectFromGroupName(Vehicle:GetName())
|
||||||
|
if not (cg and (cg.NoMoveToZone or (self.nomovetozone_names and self.nomovetozone_names[cg:GetName()]))) then
|
||||||
|
self:_MoveGroupToZone(Vehicle)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ COHORT = {
|
|||||||
|
|
||||||
--- COHORT class version.
|
--- COHORT class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
COHORT.version="0.3.6"
|
COHORT.version="0.3.7"
|
||||||
|
|
||||||
--- Global variable to store the unique(!) cohort names
|
--- Global variable to store the unique(!) cohort names
|
||||||
_COHORTNAMES={}
|
_COHORTNAMES={}
|
||||||
@@ -100,6 +100,7 @@ _COHORTNAMES={}
|
|||||||
-- DONE: Create FLOTILLA class.
|
-- DONE: Create FLOTILLA class.
|
||||||
-- DONE: Added check for properties.
|
-- DONE: Added check for properties.
|
||||||
-- DONE: Make general so that PLATOON and SQUADRON can inherit this class.
|
-- DONE: Make general so that PLATOON and SQUADRON can inherit this class.
|
||||||
|
-- DONE: Better setting of call signs.
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Constructor
|
-- Constructor
|
||||||
@@ -515,10 +516,12 @@ end
|
|||||||
-- @param #COHORT self
|
-- @param #COHORT self
|
||||||
-- @param #number Callsign Callsign from CALLSIGN.Aircraft, e.g. "Chevy" for CALLSIGN.Aircraft.CHEVY.
|
-- @param #number Callsign Callsign from CALLSIGN.Aircraft, e.g. "Chevy" for CALLSIGN.Aircraft.CHEVY.
|
||||||
-- @param #number Index Callsign index, Chevy-**1**.
|
-- @param #number Index Callsign index, Chevy-**1**.
|
||||||
|
-- @param #string CallsignString (optional) Set this for tasks like TANKER, AWACS or KIOWA and the like, which have special names. E.g. "Darkstar" or "Roughneck".
|
||||||
-- @return #COHORT self
|
-- @return #COHORT self
|
||||||
function COHORT:SetCallsign(Callsign, Index)
|
function COHORT:SetCallsign(Callsign, Index, CallsignString)
|
||||||
self.callsignName=Callsign
|
self.callsignName=Callsign
|
||||||
self.callsignIndex=Index
|
self.callsignIndex=Index
|
||||||
|
self.callsignClearName=CallsignString
|
||||||
self.callsign={}
|
self.callsign={}
|
||||||
self.callsign.NumberSquad=Callsign
|
self.callsign.NumberSquad=Callsign
|
||||||
self.callsign.NumberGroup=Index
|
self.callsign.NumberGroup=Index
|
||||||
@@ -679,7 +682,16 @@ end
|
|||||||
function COHORT:GetCallsign(Asset)
|
function COHORT:GetCallsign(Asset)
|
||||||
|
|
||||||
if self.callsignName then
|
if self.callsignName then
|
||||||
|
--[[
|
||||||
|
["callsign"] =
|
||||||
|
{
|
||||||
|
[2] = 1,
|
||||||
|
["name"] = "Darkstar11",
|
||||||
|
[3] = 1,
|
||||||
|
[1] = 5,
|
||||||
|
[4] = "Darkstar11",
|
||||||
|
}, -- end of ["callsign"]
|
||||||
|
]]
|
||||||
Asset.callsign={}
|
Asset.callsign={}
|
||||||
|
|
||||||
for i=1,Asset.nunits do
|
for i=1,Asset.nunits do
|
||||||
@@ -695,12 +707,16 @@ function COHORT:GetCallsign(Asset)
|
|||||||
else
|
else
|
||||||
self.callsigncounter=self.callsigncounter+1
|
self.callsigncounter=self.callsigncounter+1
|
||||||
end
|
end
|
||||||
|
callsign["name"] = self.callsignClearName or UTILS.GetCallsignName(self.callsignName) or "None"
|
||||||
|
callsign["name"] = string.format("%s%d%d",callsign["name"],callsign[2],callsign[3])
|
||||||
|
callsign[4] = callsign["name"]
|
||||||
|
|
||||||
Asset.callsign[i]=callsign
|
Asset.callsign[i]=callsign
|
||||||
|
|
||||||
self:T3({callsign=callsign})
|
self:T3({callsign=callsign})
|
||||||
|
|
||||||
--TODO: there is also a table entry .name, which is a string.
|
--DONE: there is also a table entry .name, which is a string.
|
||||||
|
--UTILS.PrintTableToLog(callsign)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
-- Easy CAP/GCI Class, based on OPS classes
|
-- Easy CAP/GCI Class, based on OPS classes
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
-- Documentation
|
--
|
||||||
|
-- ## Documentation:
|
||||||
--
|
--
|
||||||
-- https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Ops.EasyGCICAP.html
|
-- https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Ops.EasyGCICAP.html
|
||||||
--
|
--
|
||||||
|
-- ## Example Missions:
|
||||||
|
--
|
||||||
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Ops/EasyGCICAP).
|
||||||
|
--
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
-- Date: September 2023
|
-- Date: September 2023
|
||||||
-- Last Update: July 2024
|
-- Last Update: Aug 2025
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--
|
--
|
||||||
--- **Ops** - Easy GCI & CAP Manager
|
--- **Ops** - Easy GCI & CAP Manager
|
||||||
@@ -71,6 +76,10 @@
|
|||||||
-- @field #boolean DespawnAfterHolding
|
-- @field #boolean DespawnAfterHolding
|
||||||
-- @field #list<Ops.Auftrag#AUFTRAG> ListOfAuftrag
|
-- @field #list<Ops.Auftrag#AUFTRAG> ListOfAuftrag
|
||||||
-- @field #string defaulttakeofftype Take off type
|
-- @field #string defaulttakeofftype Take off type
|
||||||
|
-- @field #number FuelLowThreshold
|
||||||
|
-- @field #number FuelCriticalThreshold
|
||||||
|
-- @field #boolean showpatrolpointmarks
|
||||||
|
-- @field #table EngageTargetTypes
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown.
|
--- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown.
|
||||||
@@ -226,6 +235,10 @@ EASYGCICAP = {
|
|||||||
DespawnAfterHolding = true,
|
DespawnAfterHolding = true,
|
||||||
ListOfAuftrag = {},
|
ListOfAuftrag = {},
|
||||||
defaulttakeofftype = "hot",
|
defaulttakeofftype = "hot",
|
||||||
|
FuelLowThreshold = 25,
|
||||||
|
FuelCriticalThreshold = 10,
|
||||||
|
showpatrolpointmarks = false,
|
||||||
|
EngageTargetTypes = {"Air"},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Internal Squadron data type
|
--- Internal Squadron data type
|
||||||
@@ -258,10 +271,11 @@ EASYGCICAP = {
|
|||||||
-- @field #number Speed
|
-- @field #number Speed
|
||||||
-- @field #number Heading
|
-- @field #number Heading
|
||||||
-- @field #number LegLength
|
-- @field #number LegLength
|
||||||
|
-- @field Core.Zone#ZONE_BASE Zone
|
||||||
|
|
||||||
--- EASYGCICAP class version.
|
--- EASYGCICAP class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
EASYGCICAP.version="0.1.23"
|
EASYGCICAP.version="0.1.30"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -315,6 +329,10 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
|||||||
self.DespawnAfterHolding = true
|
self.DespawnAfterHolding = true
|
||||||
self.ListOfAuftrag = {}
|
self.ListOfAuftrag = {}
|
||||||
self.defaulttakeofftype = "hot"
|
self.defaulttakeofftype = "hot"
|
||||||
|
self.FuelLowThreshold = 25
|
||||||
|
self.FuelCriticalThreshold = 10
|
||||||
|
self.showpatrolpointmarks = false
|
||||||
|
self.EngageTargetTypes = {"Air"}
|
||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("EASYGCICAP %s | ", self.alias)
|
self.lid=string.format("EASYGCICAP %s | ", self.alias)
|
||||||
@@ -339,6 +357,63 @@ end
|
|||||||
-- Functions
|
-- Functions
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Get a specific managed AirWing by name
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param #string AirbaseName Airbase name of the home of this wing.
|
||||||
|
-- @return Ops.AirWing#AIRWING Airwing or nil if not found
|
||||||
|
function EASYGCICAP:GetAirwing(AirbaseName)
|
||||||
|
self:T(self.lid.."GetAirwing")
|
||||||
|
if self.wings[AirbaseName] then
|
||||||
|
return self.wings[AirbaseName][1]
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a table of all managed AirWings
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @return #table Table of Ops.AirWing#AIRWING Airwings
|
||||||
|
function EASYGCICAP:GetAirwingTable()
|
||||||
|
self:T(self.lid.."GetAirwingTable")
|
||||||
|
local Wingtable = {}
|
||||||
|
for _,_object in pairs(self.wings or {}) do
|
||||||
|
table.insert(Wingtable,_object[1])
|
||||||
|
end
|
||||||
|
return Wingtable
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set "fuel low" threshold for CAP and INTERCEPT flights.
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param #number Percent RTB if fuel at this percent. Values: 1..100, defaults to 25.
|
||||||
|
-- @return #EASYGCICAP self
|
||||||
|
function EASYGCICAP:SetFuelLow(Percent)
|
||||||
|
self:T(self.lid.."SetFuelLow")
|
||||||
|
self.FuelLowThreshold = Percent or 25
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set markers on the map for Patrol Points.
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param #boolean onoff Set to true to switch markers on.
|
||||||
|
-- @return #EASYGCICAP self
|
||||||
|
function EASYGCICAP:ShowPatrolPointMarkers(onoff)
|
||||||
|
if onoff then
|
||||||
|
self.showpatrolpointmarks = true
|
||||||
|
else
|
||||||
|
self.showpatrolpointmarks = false
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set "fuel critical" threshold for CAP and INTERCEPT flights.
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param #number Percent RTB if fuel at this percent. Values: 1..100, defaults to 10.
|
||||||
|
-- @return #EASYGCICAP self
|
||||||
|
function EASYGCICAP:SetFuelCritical(Percent)
|
||||||
|
self:T(self.lid.."SetFuelCritical")
|
||||||
|
self.FuelCriticalThreshold = Percent or 10
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set CAP formation.
|
--- Set CAP formation.
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #number Formation Formation to fly, defaults to ENUMS.Formation.FixedWing.FingerFour.Group
|
-- @param #number Formation Formation to fly, defaults to ENUMS.Formation.FixedWing.FingerFour.Group
|
||||||
@@ -359,7 +434,7 @@ function EASYGCICAP:SetTankerAndAWACSInvisible(Switch)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Count alive missions in our internal stack.
|
--- (internal) Count alive missions in our internal stack.
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @return #number count
|
-- @return #number count
|
||||||
function EASYGCICAP:_CountAliveAuftrags()
|
function EASYGCICAP:_CountAliveAuftrags()
|
||||||
@@ -536,6 +611,17 @@ function EASYGCICAP:SetCapStartTimeVariation(Start, End)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set which target types CAP flights will prefer to engage, defaults to {"Air"}
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param #table types Table of comma separated #string entries, defaults to {"Air"} (everything that flies and is not a weapon). Useful other options are e.g. {"Bombers"}, {"Fighters"},
|
||||||
|
-- or {"Helicopters"} or combinations like {"Bombers", "Fighters", "UAVs"}. See [Hoggit Wiki](https://wiki.hoggitworld.com/view/DCS_enum_attributes).
|
||||||
|
-- @return #EASYGCICAP self
|
||||||
|
function EASYGCICAP:SetCAPEngageTargetTypes(types)
|
||||||
|
self.EngageTargetTypes = types or {"Air"}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Add an AirWing to the manager
|
--- Add an AirWing to the manager
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #string Airbasename
|
-- @param #string Airbasename
|
||||||
@@ -583,7 +669,7 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
local DespawnAfterHolding = self.DespawnAfterHolding
|
local DespawnAfterHolding = self.DespawnAfterHolding
|
||||||
|
|
||||||
-- Check STATIC name
|
-- Check STATIC name
|
||||||
local check = STATIC:FindByName(Airbasename,false)
|
local check = STATIC:FindByName(Airbasename,false) or UNIT:FindByName(Airbasename)
|
||||||
if check == nil then
|
if check == nil then
|
||||||
MESSAGE:New(self.lid.."There's no warehouse static on the map (wrong naming?) for airbase "..tostring(Airbasename).."!",30,"CHECK"):ToAllIf(self.debug):ToLog()
|
MESSAGE:New(self.lid.."There's no warehouse static on the map (wrong naming?) for airbase "..tostring(Airbasename).."!",30,"CHECK"):ToAllIf(self.debug):ToLog()
|
||||||
return
|
return
|
||||||
@@ -599,6 +685,10 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
CAP_Wing:SetNumberCAP(self.capgrouping)
|
CAP_Wing:SetNumberCAP(self.capgrouping)
|
||||||
CAP_Wing:SetCapCloseRaceTrack(true)
|
CAP_Wing:SetCapCloseRaceTrack(true)
|
||||||
|
|
||||||
|
if self.showpatrolpointmarks then
|
||||||
|
CAP_Wing:ShowPatrolPointMarkers(true)
|
||||||
|
end
|
||||||
|
|
||||||
if self.capOptionVaryStartTime then
|
if self.capOptionVaryStartTime then
|
||||||
CAP_Wing:SetCapStartTimeVariation(self.capOptionVaryStartTime,self.capOptionVaryEndTime)
|
CAP_Wing:SetCapStartTimeVariation(self.capOptionVaryStartTime,self.capOptionVaryEndTime)
|
||||||
end
|
end
|
||||||
@@ -628,6 +718,9 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
local engagerange = self.engagerange
|
local engagerange = self.engagerange
|
||||||
local GoZoneSet = self.GoZoneSet
|
local GoZoneSet = self.GoZoneSet
|
||||||
local NoGoZoneSet = self.NoGoZoneSet
|
local NoGoZoneSet = self.NoGoZoneSet
|
||||||
|
local FuelLow = self.FuelLowThreshold or 25
|
||||||
|
local FuelCritical = self.FuelCriticalThreshold or 10
|
||||||
|
local EngageTypes = self.EngageTargetTypes or {"Air"}
|
||||||
|
|
||||||
function CAP_Wing:onbeforeFlightOnMission(From, Event, To, Flightgroup, Mission)
|
function CAP_Wing:onbeforeFlightOnMission(From, Event, To, Flightgroup, Mission)
|
||||||
local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP
|
local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP
|
||||||
@@ -639,10 +732,15 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
flightgroup:SetDestinationbase(AIRBASE:FindByName(Airbasename))
|
flightgroup:SetDestinationbase(AIRBASE:FindByName(Airbasename))
|
||||||
flightgroup:GetGroup():CommandEPLRS(true,5)
|
flightgroup:GetGroup():CommandEPLRS(true,5)
|
||||||
flightgroup:GetGroup():SetOptionRadarUsingForContinousSearch()
|
flightgroup:GetGroup():SetOptionRadarUsingForContinousSearch()
|
||||||
|
flightgroup:GetGroup():SetOptionLandingOverheadBreak()
|
||||||
if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then
|
if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then
|
||||||
flightgroup:SetDetection(true)
|
flightgroup:SetDetection(true)
|
||||||
flightgroup:SetEngageDetectedOn(engagerange,{"Air"},GoZoneSet,NoGoZoneSet)
|
flightgroup:SetEngageDetectedOn(engagerange,EngageTypes,GoZoneSet,NoGoZoneSet)
|
||||||
flightgroup:SetOutOfAAMRTB()
|
flightgroup:SetOutOfAAMRTB()
|
||||||
|
flightgroup:SetFuelLowRTB(true)
|
||||||
|
flightgroup:SetFuelLowThreshold(FuelLow)
|
||||||
|
flightgroup:SetFuelCriticalRTB(true)
|
||||||
|
flightgroup:SetFuelCriticalThreshold(FuelCritical)
|
||||||
if CapFormation then
|
if CapFormation then
|
||||||
flightgroup:GetGroup():SetOption(AI.Option.Air.id.FORMATION,CapFormation)
|
flightgroup:GetGroup():SetOption(AI.Option.Air.id.FORMATION,CapFormation)
|
||||||
end
|
end
|
||||||
@@ -681,24 +779,30 @@ end
|
|||||||
--- Add a CAP patrol point to a Wing
|
--- Add a CAP patrol point to a Wing
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #string AirbaseName Name of the Wing's airbase
|
-- @param #string AirbaseName Name of the Wing's airbase
|
||||||
-- @param Core.Point#COORDINATE Coordinate.
|
-- @param Core.Point#COORDINATE Coordinate. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone).
|
||||||
-- @param #number Altitude Defaults to 25000 feet ASL.
|
-- @param #number Altitude Defaults to 25000 feet ASL.
|
||||||
-- @param #number Speed Defaults to 300 knots TAS.
|
-- @param #number Speed Defaults to 300 knots TAS.
|
||||||
-- @param #number Heading Defaults to 90 degrees (East).
|
-- @param #number Heading Defaults to 90 degrees (East).
|
||||||
-- @param #number LegLength Defaults to 15 NM.
|
-- @param #number LegLength Defaults to 15 NM.
|
||||||
-- @return #EASYGCICAP self
|
-- @return #EASYGCICAP self
|
||||||
function EASYGCICAP:AddPatrolPointCAP(AirbaseName,Coordinate,Altitude,Speed,Heading,LegLength)
|
function EASYGCICAP:AddPatrolPointCAP(AirbaseName,Coordinate,Altitude,Speed,Heading,LegLength)
|
||||||
self:T(self.lid.."AddPatrolPointCAP "..Coordinate:ToStringLLDDM())
|
self:T(self.lid.."AddPatrolPointCAP")--..Coordinate:ToStringLLDDM())
|
||||||
|
local coordinate = Coordinate
|
||||||
local EntryCAP = {} -- #EASYGCICAP.CapPoint
|
local EntryCAP = {} -- #EASYGCICAP.CapPoint
|
||||||
|
if Coordinate:IsInstanceOf("ZONE_BASE") then
|
||||||
|
-- adjust coordinate and get the coordinate from the zone
|
||||||
|
coordinate = Coordinate:GetCoordinate()
|
||||||
|
EntryCAP.Zone = Coordinate
|
||||||
|
end
|
||||||
EntryCAP.AirbaseName = AirbaseName
|
EntryCAP.AirbaseName = AirbaseName
|
||||||
EntryCAP.Coordinate = Coordinate
|
EntryCAP.Coordinate = coordinate
|
||||||
EntryCAP.Altitude = Altitude or 25000
|
EntryCAP.Altitude = Altitude or 25000
|
||||||
EntryCAP.Speed = Speed or 300
|
EntryCAP.Speed = Speed or 300
|
||||||
EntryCAP.Heading = Heading or 90
|
EntryCAP.Heading = Heading or 90
|
||||||
EntryCAP.LegLength = LegLength or 15
|
EntryCAP.LegLength = LegLength or 15
|
||||||
self.ManagedCP[#self.ManagedCP+1] = EntryCAP
|
self.ManagedCP[#self.ManagedCP+1] = EntryCAP
|
||||||
if self.debug then
|
if self.debug then
|
||||||
local mark = MARKER:New(Coordinate,self.lid.."Patrol Point"):ToAll()
|
local mark = MARKER:New(coordinate,self.lid.."Patrol Point"):ToAll()
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -706,7 +810,7 @@ end
|
|||||||
--- Add a RECON patrol point to a Wing
|
--- Add a RECON patrol point to a Wing
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #string AirbaseName Name of the Wing's airbase
|
-- @param #string AirbaseName Name of the Wing's airbase
|
||||||
-- @param Core.Point#COORDINATE Coordinate.
|
-- @param Core.Point#COORDINATE Coordinate. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone).
|
||||||
-- @param #number Altitude Defaults to 25000 feet.
|
-- @param #number Altitude Defaults to 25000 feet.
|
||||||
-- @param #number Speed Defaults to 300 knots.
|
-- @param #number Speed Defaults to 300 knots.
|
||||||
-- @param #number Heading Defaults to 90 degrees (East).
|
-- @param #number Heading Defaults to 90 degrees (East).
|
||||||
@@ -731,7 +835,7 @@ end
|
|||||||
--- Add a TANKER patrol point to a Wing
|
--- Add a TANKER patrol point to a Wing
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #string AirbaseName Name of the Wing's airbase
|
-- @param #string AirbaseName Name of the Wing's airbase
|
||||||
-- @param Core.Point#COORDINATE Coordinate.
|
-- @param Core.Point#COORDINATE Coordinate. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone).
|
||||||
-- @param #number Altitude Defaults to 25000 feet.
|
-- @param #number Altitude Defaults to 25000 feet.
|
||||||
-- @param #number Speed Defaults to 300 knots.
|
-- @param #number Speed Defaults to 300 knots.
|
||||||
-- @param #number Heading Defaults to 90 degrees (East).
|
-- @param #number Heading Defaults to 90 degrees (East).
|
||||||
@@ -756,7 +860,7 @@ end
|
|||||||
--- Add an AWACS patrol point to a Wing
|
--- Add an AWACS patrol point to a Wing
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #string AirbaseName Name of the Wing's airbase
|
-- @param #string AirbaseName Name of the Wing's airbase
|
||||||
-- @param Core.Point#COORDINATE Coordinate.
|
-- @param Core.Point#COORDINATE Coordinate. Can be handed as a Core.Zone#ZONE object (e.g. in case you want the point to align with a moving zone).
|
||||||
-- @param #number Altitude Defaults to 25000 feet.
|
-- @param #number Altitude Defaults to 25000 feet.
|
||||||
-- @param #number Speed Defaults to 300 knots.
|
-- @param #number Speed Defaults to 300 knots.
|
||||||
-- @param #number Heading Defaults to 90 degrees (East).
|
-- @param #number Heading Defaults to 90 degrees (East).
|
||||||
@@ -844,7 +948,12 @@ function EASYGCICAP:_SetCAPPatrolPoints()
|
|||||||
local Speed = data.Speed
|
local Speed = data.Speed
|
||||||
local Heading = data.Heading
|
local Heading = data.Heading
|
||||||
local LegLength = data.LegLength
|
local LegLength = data.LegLength
|
||||||
Wing:AddPatrolPointCAP(Coordinate,Altitude,Speed,Heading,LegLength)
|
local Zone = _data.Zone
|
||||||
|
if Zone then
|
||||||
|
Wing:AddPatrolPointCAP(Zone,Altitude,Speed,Heading,LegLength)
|
||||||
|
else
|
||||||
|
Wing:AddPatrolPointCAP(Coordinate,Altitude,Speed,Heading,LegLength)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -910,7 +1019,7 @@ end
|
|||||||
-- @param #string SquadName Squadron name - must be unique!
|
-- @param #string SquadName Squadron name - must be unique!
|
||||||
-- @param #string AirbaseName Name of the airbase the airwing resides on, e.g. AIRBASE.Caucasus.Kutaisi
|
-- @param #string AirbaseName Name of the airbase the airwing resides on, e.g. AIRBASE.Caucasus.Kutaisi
|
||||||
-- @param #number AirFrames Number of available airframes, e.g. 20.
|
-- @param #number AirFrames Number of available airframes, e.g. 20.
|
||||||
-- @param #string Skill(optional) Skill level, e.g. AI.Skill.AVERAGE
|
-- @param #string Skill (optional) Skill level, e.g. AI.Skill.AVERAGE
|
||||||
-- @param #string Modex (optional) Modex to be used,e.g. 402.
|
-- @param #string Modex (optional) Modex to be used,e.g. 402.
|
||||||
-- @param #string Livery (optional) Livery name to be used.
|
-- @param #string Livery (optional) Livery name to be used.
|
||||||
-- @return #EASYGCICAP self
|
-- @return #EASYGCICAP self
|
||||||
@@ -1115,7 +1224,9 @@ function EASYGCICAP:_AddTankerSquadron(TemplateName, SquadName, AirbaseName, Air
|
|||||||
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
Squadron_One:SetSkill(Skill or AI.Skill.AVERAGE)
|
||||||
Squadron_One:SetMissionRange(self.missionrange)
|
Squadron_One:SetMissionRange(self.missionrange)
|
||||||
Squadron_One:SetRadio(Frequency,Modulation)
|
Squadron_One:SetRadio(Frequency,Modulation)
|
||||||
Squadron_One:AddTacanChannel(TACAN,TACAN)
|
if TACAN then
|
||||||
|
Squadron_One:AddTacanChannel(TACAN,TACAN)
|
||||||
|
end
|
||||||
|
|
||||||
local wing = self.wings[AirbaseName][1] -- Ops.Airwing#AIRWING
|
local wing = self.wings[AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
|
|
||||||
@@ -1199,19 +1310,19 @@ end
|
|||||||
-- @return #boolean assigned
|
-- @return #boolean assigned
|
||||||
-- @return #number leftover
|
-- @return #number leftover
|
||||||
function EASYGCICAP:_TryAssignIntercept(ReadyFlightGroups,InterceptAuftrag,Group,WingSize)
|
function EASYGCICAP:_TryAssignIntercept(ReadyFlightGroups,InterceptAuftrag,Group,WingSize)
|
||||||
self:I("_TryAssignIntercept for size "..WingSize or 1)
|
self:T("_TryAssignIntercept for size "..WingSize or 1)
|
||||||
local assigned = false
|
local assigned = false
|
||||||
local wingsize = WingSize or 1
|
local wingsize = WingSize or 1
|
||||||
local mindist = 0
|
local mindist = 0
|
||||||
local disttable = {}
|
local disttable = {}
|
||||||
if Group and Group:IsAlive() then
|
if Group and Group:IsAlive() then
|
||||||
local gcoord = Group:GetCoordinate() or COORDINATE:New(0,0,0)
|
local gcoord = Group:GetCoordinate() or COORDINATE:New(0,0,0)
|
||||||
self:I(self.lid..string.format("Assignment for %s",Group:GetName()))
|
self:T(self.lid..string.format("Assignment for %s",Group:GetName()))
|
||||||
for _name,_FG in pairs(ReadyFlightGroups or {}) do
|
for _name,_FG in pairs(ReadyFlightGroups or {}) do
|
||||||
local FG = _FG -- Ops.FlightGroup#FLIGHTGROUP
|
local FG = _FG -- Ops.FlightGroup#FLIGHTGROUP
|
||||||
local fcoord = FG:GetCoordinate()
|
local fcoord = FG:GetCoordinate()
|
||||||
local dist = math.floor(UTILS.Round(fcoord:Get2DDistance(gcoord)/1000,1))
|
local dist = math.floor(UTILS.Round(fcoord:Get2DDistance(gcoord)/1000,1))
|
||||||
self:I(self.lid..string.format("FG %s Distance %dkm",_name,dist))
|
self:T(self.lid..string.format("FG %s Distance %dkm",_name,dist))
|
||||||
disttable[#disttable+1] = { FG=FG, dist=dist}
|
disttable[#disttable+1] = { FG=FG, dist=dist}
|
||||||
if dist>mindist then mindist=dist end
|
if dist>mindist then mindist=dist end
|
||||||
end
|
end
|
||||||
@@ -1228,7 +1339,7 @@ function EASYGCICAP:_TryAssignIntercept(ReadyFlightGroups,InterceptAuftrag,Group
|
|||||||
local cm = FG:GetMissionCurrent()
|
local cm = FG:GetMissionCurrent()
|
||||||
if cm then cm:Cancel() end
|
if cm then cm:Cancel() end
|
||||||
wingsize = wingsize - 1
|
wingsize = wingsize - 1
|
||||||
self:I(self.lid..string.format("Assigned to FG %s Distance %dkm",FG:GetName(),_entry.dist))
|
self:T(self.lid..string.format("Assigned to FG %s Distance %dkm",FG:GetName(),_entry.dist))
|
||||||
if wingsize == 0 then
|
if wingsize == 0 then
|
||||||
assigned = true
|
assigned = true
|
||||||
break
|
break
|
||||||
@@ -1258,7 +1369,7 @@ function EASYGCICAP:_AssignIntercept(Cluster)
|
|||||||
local conflictzoneset = self.ConflictZoneSet
|
local conflictzoneset = self.ConflictZoneSet
|
||||||
local ReadyFlightGroups = self.ReadyFlightGroups
|
local ReadyFlightGroups = self.ReadyFlightGroups
|
||||||
|
|
||||||
-- Aircraft?
|
-- Aircraft?
|
||||||
if Cluster.ctype ~= INTEL.Ctype.AIRCRAFT then return end
|
if Cluster.ctype ~= INTEL.Ctype.AIRCRAFT then return end
|
||||||
-- Threatlevel 0..10
|
-- Threatlevel 0..10
|
||||||
local contact = self.Intel:GetHighestThreatContact(Cluster)
|
local contact = self.Intel:GetHighestThreatContact(Cluster)
|
||||||
@@ -1303,6 +1414,10 @@ function EASYGCICAP:_AssignIntercept(Cluster)
|
|||||||
local data = _data -- #EASYGCICAP.CapPoint
|
local data = _data -- #EASYGCICAP.CapPoint
|
||||||
local name = data.AirbaseName
|
local name = data.AirbaseName
|
||||||
local zonecoord = data.Coordinate
|
local zonecoord = data.Coordinate
|
||||||
|
if data.Zone then
|
||||||
|
-- refresh coordinate in case we have a (moving) zone
|
||||||
|
zonecoord = data.Zone:GetCoordinate()
|
||||||
|
end
|
||||||
local airwing = wings[name][1]
|
local airwing = wings[name][1]
|
||||||
local coa = AIRBASE:FindByName(name):GetCoalition()
|
local coa = AIRBASE:FindByName(name):GetCoalition()
|
||||||
local samecoalitionab = coa == self.coalition and true or false
|
local samecoalitionab = coa == self.coalition and true or false
|
||||||
@@ -1404,7 +1519,7 @@ function EASYGCICAP:_StartIntel()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
-- FSM Functions
|
-- TODO FSM Functions
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
|
|
||||||
--- (Internal) FSM Function onafterStart
|
--- (Internal) FSM Function onafterStart
|
||||||
@@ -1500,7 +1615,7 @@ function EASYGCICAP:onafterStatus(From,Event,To)
|
|||||||
local engage = FG:IsEngaging()
|
local engage = FG:IsEngaging()
|
||||||
local hasmissiles = FG:IsOutOfMissiles() == nil and true or false
|
local hasmissiles = FG:IsOutOfMissiles() == nil and true or false
|
||||||
local ready = hasmissiles and FG:IsFuelGood() and FG:IsAirborne()
|
local ready = hasmissiles and FG:IsFuelGood() and FG:IsAirborne()
|
||||||
--self:I(string.format("Flightgroup %s Engaging = %s Ready = %s",tostring(name),tostring(engage),tostring(ready)))
|
--self:T(string.format("Flightgroup %s Engaging = %s Ready = %s",tostring(name),tostring(engage),tostring(ready)))
|
||||||
if ready then
|
if ready then
|
||||||
self.ReadyFlightGroups[name] = FG
|
self.ReadyFlightGroups[name] = FG
|
||||||
end
|
end
|
||||||
@@ -1535,5 +1650,8 @@ end
|
|||||||
function EASYGCICAP:onafterStop(From,Event,To)
|
function EASYGCICAP:onafterStop(From,Event,To)
|
||||||
self:T({From,Event,To})
|
self:T({From,Event,To})
|
||||||
self.Intel:Stop()
|
self.Intel:Stop()
|
||||||
|
for _,_wing in pairs(self.wings or {}) do
|
||||||
|
_wing:Stop()
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2464,7 +2464,7 @@ end
|
|||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Payer Menu
|
-- Player Menu
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Create player menu.
|
--- Create player menu.
|
||||||
|
|||||||
@@ -4667,10 +4667,12 @@ function FLIGHTGROUP:GetParking(airbase)
|
|||||||
local coords={}
|
local coords={}
|
||||||
for clientname, client in pairs(clients) do
|
for clientname, client in pairs(clients) do
|
||||||
local template=_DATABASE:GetGroupTemplateFromUnitName(clientname)
|
local template=_DATABASE:GetGroupTemplateFromUnitName(clientname)
|
||||||
local units=template.units
|
if template then
|
||||||
for i,unit in pairs(units) do
|
local units=template.units
|
||||||
local coord=COORDINATE:New(unit.x, unit.alt, unit.y)
|
for i,unit in pairs(units) do
|
||||||
coords[unit.name]=coord
|
local coord=COORDINATE:New(unit.x, unit.alt, unit.y)
|
||||||
|
coords[unit.name]=coord
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return coords
|
return coords
|
||||||
@@ -5027,7 +5029,7 @@ function FLIGHTGROUP:_UpdateMenu(delay)
|
|||||||
|
|
||||||
-- Message to group.
|
-- Message to group.
|
||||||
MESSAGE:New(text, 5):ToGroup(self.group)
|
MESSAGE:New(text, 5):ToGroup(self.group)
|
||||||
self:I(self.lid..text)
|
self:T(self.lid..text)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get current position of player.
|
-- Get current position of player.
|
||||||
|
|||||||
@@ -662,6 +662,15 @@ function LEGION:CheckMissionQueue()
|
|||||||
if mission:IsNotOver() and mission:IsReadyToCancel() then
|
if mission:IsNotOver() and mission:IsReadyToCancel() then
|
||||||
mission:Cancel()
|
mission:Cancel()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Housekeeping
|
||||||
|
local TNow = timer.getTime()
|
||||||
|
if mission:IsOver() and mission:IsNotRepeatable() and mission.DeletionTimstamp == nil then
|
||||||
|
mission.DeletionTimstamp = TNow
|
||||||
|
end
|
||||||
|
if mission.DeletionTimstamp ~= nil and TNow - mission.DeletionTimstamp > 1800 then
|
||||||
|
mission = nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check that runway is operational and that carrier is not recovering.
|
-- Check that runway is operational and that carrier is not recovering.
|
||||||
@@ -761,7 +770,7 @@ function LEGION:CheckMissionQueue()
|
|||||||
-- Reduce number of reinforcements.
|
-- Reduce number of reinforcements.
|
||||||
if reinforce then
|
if reinforce then
|
||||||
mission.reinforce=mission.reinforce-#assets
|
mission.reinforce=mission.reinforce-#assets
|
||||||
self:I(self.lid..string.format("Reinforced with N=%d Nreinforce=%d", #assets, mission.reinforce))
|
self:T(self.lid..string.format("Reinforced with N=%d Nreinforce=%d", #assets, mission.reinforce))
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -1823,6 +1832,7 @@ function LEGION:_CreateFlightGroup(asset)
|
|||||||
---
|
---
|
||||||
|
|
||||||
opsgroup=ARMYGROUP:New(asset.spawngroupname)
|
opsgroup=ARMYGROUP:New(asset.spawngroupname)
|
||||||
|
opsgroup:SetValidateAndRepositionGroundUnits(self.ValidateAndRepositionGroundUnits)
|
||||||
|
|
||||||
elseif self:IsFleet() then
|
elseif self:IsFleet() then
|
||||||
|
|
||||||
|
|||||||
@@ -4631,7 +4631,12 @@ function OPSGROUP:_UpdateTask(Task, Mission)
|
|||||||
self:T(self.lid..string.format("Zone %s captured ==> Task DONE!", zoneCurr:GetName()))
|
self:T(self.lid..string.format("Zone %s captured ==> Task DONE!", zoneCurr:GetName()))
|
||||||
|
|
||||||
-- Task done.
|
-- Task done.
|
||||||
self:TaskDone(Task)
|
if Task.StayInZoneTime then
|
||||||
|
local stay = Task.StayInZoneTime
|
||||||
|
self:__TaskDone(stay,Task)
|
||||||
|
else
|
||||||
|
self:TaskDone(Task)
|
||||||
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
-- Current zone NOT captured yet ==> Find Target
|
-- Current zone NOT captured yet ==> Find Target
|
||||||
@@ -5730,7 +5735,7 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission)
|
|||||||
-- Decrease patrol data.
|
-- Decrease patrol data.
|
||||||
if Mission.patroldata then
|
if Mission.patroldata then
|
||||||
Mission.patroldata.noccupied=Mission.patroldata.noccupied-1
|
Mission.patroldata.noccupied=Mission.patroldata.noccupied-1
|
||||||
AIRWING.UpdatePatrolPointMarker(Mission.patroldata)
|
AIRWING.UpdatePatrolPointMarker(self,Mission.patroldata)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Switch auto engage detected off. This IGNORES that engage detected had been activated for the group!
|
-- Switch auto engage detected off. This IGNORES that engage detected had been activated for the group!
|
||||||
@@ -7534,7 +7539,7 @@ end
|
|||||||
function OPSGROUP:onafterElementDead(From, Event, To, Element)
|
function OPSGROUP:onafterElementDead(From, Event, To, Element)
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:I(self.lid..string.format("Element dead %s at t=%.3f", Element.name, timer.getTime()))
|
self:T(self.lid..string.format("Element dead %s at t=%.3f", Element.name, timer.getTime()))
|
||||||
|
|
||||||
-- Set element status.
|
-- Set element status.
|
||||||
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD)
|
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD)
|
||||||
@@ -7847,8 +7852,13 @@ function OPSGROUP:_Spawn(Delay, Template)
|
|||||||
-- Debug output.
|
-- Debug output.
|
||||||
self:T2({Template=Template})
|
self:T2({Template=Template})
|
||||||
|
|
||||||
|
if self:IsArmygroup() and self.ValidateAndRepositionGroundUnits then
|
||||||
|
UTILS.ValidateAndRepositionGroundUnits(Template.units)
|
||||||
|
end
|
||||||
|
|
||||||
-- Spawn new group.
|
-- Spawn new group.
|
||||||
self.group=_DATABASE:Spawn(Template)
|
self.group=_DATABASE:Spawn(Template)
|
||||||
|
self.group:SetValidateAndRepositionGroundUnits(self.ValidateAndRepositionGroundUnits)
|
||||||
--local countryID=self.group:GetCountry()
|
--local countryID=self.group:GetCountry()
|
||||||
--local categoryID=self.group:GetCategory()
|
--local categoryID=self.group:GetCategory()
|
||||||
--local dcsgroup=coalition.addGroup(countryID, categoryID, Template)
|
--local dcsgroup=coalition.addGroup(countryID, categoryID, Template)
|
||||||
@@ -8085,7 +8095,7 @@ function OPSGROUP:onafterStop(From, Event, To)
|
|||||||
_DATABASE.FLIGHTGROUPS[self.groupname]=nil
|
_DATABASE.FLIGHTGROUPS[self.groupname]=nil
|
||||||
|
|
||||||
-- Debug output.
|
-- Debug output.
|
||||||
self:I(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from _DATABASE")
|
self:T(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from _DATABASE")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "OutOfAmmo" event.
|
--- On after "OutOfAmmo" event.
|
||||||
@@ -13955,6 +13965,15 @@ function OPSGROUP:_GetDetectedTarget()
|
|||||||
return targetgroup, targetdist
|
return targetgroup, targetdist
|
||||||
end
|
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 OPSGROUP:SetValidateAndRepositionGroundUnits(Enabled)
|
||||||
|
self.ValidateAndRepositionGroundUnits = Enabled
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
-- @module Ops.PlayerTask
|
-- @module Ops.PlayerTask
|
||||||
-- @image OPS_PlayerTask.jpg
|
-- @image OPS_PlayerTask.jpg
|
||||||
-- @date Last Update May 2025
|
-- @date Last Update Oct 2025
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -59,6 +59,8 @@ do
|
|||||||
-- @field #string FinalState
|
-- @field #string FinalState
|
||||||
-- @field #string TypeName
|
-- @field #string TypeName
|
||||||
-- @field #number PreviousCount
|
-- @field #number PreviousCount
|
||||||
|
-- @field #boolean CanSmoke
|
||||||
|
-- @field #boolean ShowThreatDetails
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
@@ -94,11 +96,13 @@ PLAYERTASK = {
|
|||||||
NextTaskFailure = {},
|
NextTaskFailure = {},
|
||||||
FinalState = "none",
|
FinalState = "none",
|
||||||
PreviousCount = 0,
|
PreviousCount = 0,
|
||||||
|
CanSmoke = true,
|
||||||
|
ShowThreatDetails = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- PLAYERTASK class version.
|
--- PLAYERTASK class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
PLAYERTASK.version="0.1.27"
|
PLAYERTASK.version="0.1.29"
|
||||||
|
|
||||||
--- Generic task condition.
|
--- Generic task condition.
|
||||||
-- @type PLAYERTASK.Condition
|
-- @type PLAYERTASK.Condition
|
||||||
@@ -231,6 +235,7 @@ function PLAYERTASK:New(Type, Target, Repeat, Times, TTSType)
|
|||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
|
-- @param #boolen Silent If true, suppress message output on cancel.
|
||||||
|
|
||||||
--- On After "Planned" event. Task has been planned.
|
--- On After "Planned" event. Task has been planned.
|
||||||
-- @function [parent=#PLAYERTASK] OnAfterPilotPlanned
|
-- @function [parent=#PLAYERTASK] OnAfterPilotPlanned
|
||||||
@@ -387,6 +392,14 @@ function PLAYERTASK:_CheckCaptureOpsZoneSuccess(OpsZone, CaptureSquadGroupNamePr
|
|||||||
return OpsZone:GetOwner() == Coalition and isClientInZone and isCaptureGroupInZone
|
return OpsZone:GetOwner() == Coalition and isClientInZone and isCaptureGroupInZone
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Override this function in order to implement custom logic if a player can join a task or not.
|
||||||
|
-- @param #PLAYERTASK self
|
||||||
|
-- @param Wrapper.Group#GROUP Group
|
||||||
|
-- @param Wrapper.Client#CLIENT Client
|
||||||
|
-- @return #boolean Outcome True if player can join the task, false if not
|
||||||
|
function PLAYERTASK:CanJoinTask(Group, Client)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
--- [Internal] Add a PLAYERTASKCONTROLLER for this task
|
--- [Internal] Add a PLAYERTASKCONTROLLER for this task
|
||||||
-- @param #PLAYERTASK self
|
-- @param #PLAYERTASK self
|
||||||
@@ -460,6 +473,26 @@ function PLAYERTASK:SetSubType(Type)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [USER] Set if a task can have a smoke marker.
|
||||||
|
-- @param #PLAYERTASK self
|
||||||
|
-- @param #boolean OnOff If true (default) it can be smoke, false if not.
|
||||||
|
-- @return #PLAYERTASK self
|
||||||
|
function PLAYERTASK:SetCanSmoke(OnOff)
|
||||||
|
self:T(self.lid.."AddSSetCanSmokeubType")
|
||||||
|
self.CanSmoke = OnOff
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [USER] Set if a task can show threat details.
|
||||||
|
-- @param #PLAYERTASK self
|
||||||
|
-- @param #boolean OnOff If true (default) it can be shown, false if not.
|
||||||
|
-- @return #PLAYERTASK self
|
||||||
|
function PLAYERTASK:SetShowThreatDetails(OnOff)
|
||||||
|
self:T(self.lid.."SetShowThreatDetails")
|
||||||
|
self.ShowThreatDetails = OnOff
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [USER] Get task sub type description from this task.
|
--- [USER] Get task sub type description from this task.
|
||||||
-- @param #PLAYERTASK self
|
-- @param #PLAYERTASK self
|
||||||
-- @return #string Type or nil
|
-- @return #string Type or nil
|
||||||
@@ -1165,11 +1198,12 @@ end
|
|||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
|
-- @param #boolean Silent
|
||||||
-- @return #PLAYERTASK self
|
-- @return #PLAYERTASK self
|
||||||
function PLAYERTASK:onafterCancel(From, Event, To)
|
function PLAYERTASK:onafterCancel(From, Event, To, Silent)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
if self.TaskController then
|
if self.TaskController then
|
||||||
self.TaskController:__TaskCancelled(-1,self)
|
self.TaskController:__TaskCancelled(-1,self, Silent)
|
||||||
end
|
end
|
||||||
self.timestamp = timer.getAbsTime()
|
self.timestamp = timer.getAbsTime()
|
||||||
self.FinalState = "Cancelled"
|
self.FinalState = "Cancelled"
|
||||||
@@ -1227,7 +1261,10 @@ function PLAYERTASK:onafterFailed(From, Event, To)
|
|||||||
self.TargetMarker:Remove()
|
self.TargetMarker:Remove()
|
||||||
end
|
end
|
||||||
self.FinalState = "Failed"
|
self.FinalState = "Failed"
|
||||||
self:__Done(-1)
|
if self.TaskController then
|
||||||
|
self.TaskController:__TaskFailed(-1,self)
|
||||||
|
end
|
||||||
|
self:__Done(-1.5)
|
||||||
end
|
end
|
||||||
if self.TaskController.Scoring then
|
if self.TaskController.Scoring then
|
||||||
local clients,count = self:GetClientObjects()
|
local clients,count = self:GetClientObjects()
|
||||||
@@ -1595,7 +1632,7 @@ do
|
|||||||
--
|
--
|
||||||
-- The event is triggered when a task was cancelled manually. Use @{#PLAYERTASKCONTROLLER.OnAfterTaskCancelled}()` to link into this event:
|
-- The event is triggered when a task was cancelled manually. Use @{#PLAYERTASKCONTROLLER.OnAfterTaskCancelled}()` to link into this event:
|
||||||
--
|
--
|
||||||
-- function taskmanager:OnAfterTaskCancelled(From, Event, To, Task)
|
-- function taskmanager:OnAfterTaskCancelled(From, Event, To, Task, Silent)
|
||||||
-- ... your code here ...
|
-- ... your code here ...
|
||||||
-- end
|
-- end
|
||||||
--
|
--
|
||||||
@@ -1759,12 +1796,15 @@ PLAYERTASKCONTROLLER.Messages = {
|
|||||||
THREATMEDIUM = "medium",
|
THREATMEDIUM = "medium",
|
||||||
THREATLOW = "low",
|
THREATLOW = "low",
|
||||||
THREATTEXT = "%s\nThreat: %s\nTargets left: %d\nCoord: %s",
|
THREATTEXT = "%s\nThreat: %s\nTargets left: %d\nCoord: %s",
|
||||||
|
NOTHREATTEXT = "%s\nNo target information available.",
|
||||||
ELEVATION = "\nTarget Elevation: %s %s",
|
ELEVATION = "\nTarget Elevation: %s %s",
|
||||||
METER = "meter",
|
METER = "meter",
|
||||||
FEET = "feet",
|
FEET = "feet",
|
||||||
THREATTEXTTTS = "%s, %s. Target information for %s. Threat level %s. Targets left %d. Target location %s.",
|
THREATTEXTTTS = "%s, %s. Target information for %s. Threat level %s. Targets left %d. Target location %s.",
|
||||||
|
NOTHREATTEXTTTS = "%s, %s. No target information available.",
|
||||||
MARKTASK = "%s, %s, copy, task %03d location marked on map!",
|
MARKTASK = "%s, %s, copy, task %03d location marked on map!",
|
||||||
SMOKETASK = "%s, %s, copy, task %03d location smoked!",
|
SMOKETASK = "%s, %s, copy, task %03d location smoked!",
|
||||||
|
NOSMOKETASK = "%s, %s, negative, task %03d location cannot be smoked!",
|
||||||
FLARETASK = "%s, %s, copy, task %03d location illuminated!",
|
FLARETASK = "%s, %s, copy, task %03d location illuminated!",
|
||||||
ABORTTASK = "All stations, %s, %s has aborted %s task %03d!",
|
ABORTTASK = "All stations, %s, %s has aborted %s task %03d!",
|
||||||
UNKNOWN = "Unknown",
|
UNKNOWN = "Unknown",
|
||||||
@@ -1843,12 +1883,15 @@ PLAYERTASKCONTROLLER.Messages = {
|
|||||||
THREATMEDIUM = "mittel",
|
THREATMEDIUM = "mittel",
|
||||||
THREATLOW = "niedrig",
|
THREATLOW = "niedrig",
|
||||||
THREATTEXT = "%s\nGefahrstufe: %s\nZiele: %d\nKoord: %s",
|
THREATTEXT = "%s\nGefahrstufe: %s\nZiele: %d\nKoord: %s",
|
||||||
|
NOTHREATTEXT = "%s\nKeine Zielinformation verfügbar.",
|
||||||
ELEVATION = "\nZiel Höhe: %s %s",
|
ELEVATION = "\nZiel Höhe: %s %s",
|
||||||
METER = "Meter",
|
METER = "Meter",
|
||||||
FEET = "Fuss",
|
FEET = "Fuss",
|
||||||
THREATTEXTTTS = "%s, %s. Zielinformation zu %s. Gefahrstufe %s. Ziele %d. Zielposition %s.",
|
THREATTEXTTTS = "%s, %s. Zielinformation zu %s. Gefahrstufe %s. Ziele %d. Zielposition %s.",
|
||||||
|
NOTHREATTEXTTTS = "%s, %s. Keine Zielinformation verfügbar.",
|
||||||
MARKTASK = "%s, %s, verstanden, Zielposition %03d auf der Karte markiert!",
|
MARKTASK = "%s, %s, verstanden, Zielposition %03d auf der Karte markiert!",
|
||||||
SMOKETASK = "%s, %s, verstanden, Zielposition %03d mit Rauch markiert!",
|
SMOKETASK = "%s, %s, verstanden, Zielposition %03d mit Rauch markiert!",
|
||||||
|
NOSMOKETASK = "%s, %s, negativ, Zielposition %03d kann nicht markiert werden!",
|
||||||
FLARETASK = "%s, %s, verstanden, Zielposition %03d beleuchtet!",
|
FLARETASK = "%s, %s, verstanden, Zielposition %03d beleuchtet!",
|
||||||
ABORTTASK = "%s, an alle, %s hat Auftrag %s %03d abgebrochen!",
|
ABORTTASK = "%s, an alle, %s hat Auftrag %s %03d abgebrochen!",
|
||||||
UNKNOWN = "Unbekannt",
|
UNKNOWN = "Unbekannt",
|
||||||
@@ -1909,7 +1952,7 @@ PLAYERTASKCONTROLLER.Messages = {
|
|||||||
|
|
||||||
--- PLAYERTASK class version.
|
--- PLAYERTASK class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
PLAYERTASKCONTROLLER.version="0.1.70"
|
PLAYERTASKCONTROLLER.version="0.1.71"
|
||||||
|
|
||||||
--- Create and run a new TASKCONTROLLER instance.
|
--- Create and run a new TASKCONTROLLER instance.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
@@ -2050,6 +2093,7 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter)
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Ops.PlayerTask#PLAYERTASK Task
|
-- @param Ops.PlayerTask#PLAYERTASK Task
|
||||||
|
-- @param #boolean Silent If true suppress message output.
|
||||||
|
|
||||||
--- On After "TaskFailed" event. Task has failed.
|
--- On After "TaskFailed" event. Task has failed.
|
||||||
-- @function [parent=#PLAYERTASKCONTROLLER] OnAfterTaskFailed
|
-- @function [parent=#PLAYERTASKCONTROLLER] OnAfterTaskFailed
|
||||||
@@ -2730,11 +2774,12 @@ end
|
|||||||
|
|
||||||
--- [User] Manually cancel a specific task
|
--- [User] Manually cancel a specific task
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param Ops.PlayerTask#PLAYERTASK Task The task to be cancelled
|
-- @param Ops.PlayerTask#PLAYERTASK Task The task to be cancelled.
|
||||||
|
-- @param #boolean Silent If true suppress message output.
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
-- @return #PLAYERTASKCONTROLLER self
|
||||||
function PLAYERTASKCONTROLLER:CancelTask(Task)
|
function PLAYERTASKCONTROLLER:CancelTask(Task,Silent)
|
||||||
self:T(self.lid.."CancelTask")
|
self:T(self.lid.."CancelTask")
|
||||||
Task:__Cancel(-1)
|
Task:__Cancel(-1,Silent)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3530,6 +3575,16 @@ function PLAYERTASKCONTROLLER:AddPlayerTaskToQueue(PlayerTask,Silent,TaskFilter)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Override this function in order to implement custom logic if a player can join a task or not.
|
||||||
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
|
-- @param Ops.PlayerTask#PLAYERTASK Task
|
||||||
|
-- @param Wrapper.Group#GROUP Group
|
||||||
|
-- @param Wrapper.Client#CLIENT Client
|
||||||
|
-- @return #boolean Outcome True if player can join the task, false if not
|
||||||
|
function PLAYERTASKCONTROLLER:CanJoinTask(Task, Group, Client)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
--- [Internal] Join a player to a task
|
--- [Internal] Join a player to a task
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param Ops.PlayerTask#PLAYERTASK Task
|
-- @param Ops.PlayerTask#PLAYERTASK Task
|
||||||
@@ -3540,6 +3595,15 @@ end
|
|||||||
function PLAYERTASKCONTROLLER:_JoinTask(Task, Force, Group, Client)
|
function PLAYERTASKCONTROLLER:_JoinTask(Task, Force, Group, Client)
|
||||||
self:T({Force, Group, Client})
|
self:T({Force, Group, Client})
|
||||||
self:T(self.lid.."_JoinTask")
|
self:T(self.lid.."_JoinTask")
|
||||||
|
|
||||||
|
if not self:CanJoinTask(Task, Group, Client) then
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
if not Task:CanJoinTask(Group, Client) then
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
local force = false
|
local force = false
|
||||||
if type(Force) == "boolean" then
|
if type(Force) == "boolean" then
|
||||||
force = Force
|
force = Force
|
||||||
@@ -3704,6 +3768,7 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
|||||||
local Elevation = Coordinate:GetLandHeight() or 0 -- meters
|
local Elevation = Coordinate:GetLandHeight() or 0 -- meters
|
||||||
local CoordText = ""
|
local CoordText = ""
|
||||||
local CoordTextLLDM = nil
|
local CoordTextLLDM = nil
|
||||||
|
local ShowThreatInfo = task.ShowThreatDetails
|
||||||
local LasingDrone = self:_FindLasingDroneForTaskID(task.PlayerTaskNr)
|
local LasingDrone = self:_FindLasingDroneForTaskID(task.PlayerTaskNr)
|
||||||
if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A then
|
if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A then
|
||||||
CoordText = Coordinate:ToStringA2G(Client,nil,self.ShowMagnetic)
|
CoordText = Coordinate:ToStringA2G(Client,nil,self.ShowMagnetic)
|
||||||
@@ -3727,7 +3792,12 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
|||||||
local clientlist, clientcount = task:GetClients()
|
local clientlist, clientcount = task:GetClients()
|
||||||
local ThreatGraph = "[" .. string.rep( "■", ThreatLevel ) .. string.rep( "□", 10 - ThreatLevel ) .. "]: "..ThreatLevel
|
local ThreatGraph = "[" .. string.rep( "■", ThreatLevel ) .. string.rep( "□", 10 - ThreatLevel ) .. "]: "..ThreatLevel
|
||||||
local ThreatLocaleText = self.gettext:GetEntry("THREATTEXT",self.locale)
|
local ThreatLocaleText = self.gettext:GetEntry("THREATTEXT",self.locale)
|
||||||
text = string.format(ThreatLocaleText, taskname, ThreatGraph, targets, CoordText)
|
if ShowThreatInfo == true then
|
||||||
|
text = string.format(ThreatLocaleText, taskname, ThreatGraph, targets, CoordText)
|
||||||
|
else
|
||||||
|
ThreatLocaleText = self.gettext:GetEntry("NOTHREATTEXT",self.locale)
|
||||||
|
text = string.format(ThreatLocaleText, taskname)
|
||||||
|
end
|
||||||
local settings = _DATABASE:GetPlayerSettings(playername) or _SETTINGS -- Core.Settings#SETTINGS
|
local settings = _DATABASE:GetPlayerSettings(playername) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
local elevationmeasure = self.gettext:GetEntry("FEET",self.locale)
|
local elevationmeasure = self.gettext:GetEntry("FEET",self.locale)
|
||||||
if settings:IsMetric() then
|
if settings:IsMetric() then
|
||||||
@@ -3850,9 +3920,19 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
|||||||
end
|
end
|
||||||
--self:I(self.lid.." | ".. CoordText)
|
--self:I(self.lid.." | ".. CoordText)
|
||||||
end
|
end
|
||||||
|
local ttstext
|
||||||
local ThreatLocaleTextTTS = self.gettext:GetEntry("THREATTEXTTTS",self.locale)
|
local ThreatLocaleTextTTS = self.gettext:GetEntry("THREATTEXTTTS",self.locale)
|
||||||
local ttstext = string.format(ThreatLocaleTextTTS,ttsplayername,self.MenuName or self.Name,ttstaskname,ThreatLevelText, targets, CoordText)
|
-- THREATTEXT = "%s\nThreat: %s\nTargets left: %d\nCoord: %s",
|
||||||
|
-- THREATTEXTTTS = "%s, %s. Target information for %s. Threat level %s. Targets left %d. Target location %s.",
|
||||||
|
if ShowThreatInfo == true then
|
||||||
|
ttstext = string.format(ThreatLocaleTextTTS,ttsplayername,self.MenuName or self.Name,ttstaskname,ThreatLevelText, targets, CoordText)
|
||||||
|
else
|
||||||
|
ThreatLocaleTextTTS = self.gettext:GetEntry("NOTHREATTEXTTTS",self.locale)
|
||||||
|
ttstext = string.format(ThreatLocaleTextTTS,ttsplayername,self.MenuName or self.Name)
|
||||||
|
end
|
||||||
|
|
||||||
-- POINTERTARGETLASINGTTS = ". Pointer over target and lasing."
|
-- POINTERTARGETLASINGTTS = ". Pointer over target and lasing."
|
||||||
|
|
||||||
if task.Type == AUFTRAG.Type.PRECISIONBOMBING and self.precisionbombing then
|
if task.Type == AUFTRAG.Type.PRECISIONBOMBING and self.precisionbombing then
|
||||||
if LasingDrone and LasingDrone.playertask.inreach and LasingDrone:IsLasing() then
|
if LasingDrone and LasingDrone.playertask.inreach and LasingDrone:IsLasing() then
|
||||||
local lasingtext = self.gettext:GetEntry("POINTERTARGETLASINGTTS",self.locale)
|
local lasingtext = self.gettext:GetEntry("POINTERTARGETLASINGTTS",self.locale)
|
||||||
@@ -3921,15 +4001,25 @@ function PLAYERTASKCONTROLLER:_SmokeTask(Group, Client)
|
|||||||
local text = ""
|
local text = ""
|
||||||
if self.TasksPerPlayer:HasUniqueID(playername) then
|
if self.TasksPerPlayer:HasUniqueID(playername) then
|
||||||
local task = self.TasksPerPlayer:ReadByID(playername) -- Ops.PlayerTask#PLAYERTASK
|
local task = self.TasksPerPlayer:ReadByID(playername) -- Ops.PlayerTask#PLAYERTASK
|
||||||
task:SmokeTarget()
|
if task.CanSmoke == true then
|
||||||
local textmark = self.gettext:GetEntry("SMOKETASK",self.locale)
|
task:SmokeTarget()
|
||||||
text = string.format(textmark, ttsplayername, self.MenuName or self.Name, task.PlayerTaskNr)
|
local textmark = self.gettext:GetEntry("SMOKETASK",self.locale)
|
||||||
self:T(self.lid..text)
|
text = string.format(textmark, ttsplayername, self.MenuName or self.Name, task.PlayerTaskNr)
|
||||||
--local m=MESSAGE:New(text,"10","Tasking"):ToAll()
|
self:T(self.lid..text)
|
||||||
if self.UseSRS then
|
--local m=MESSAGE:New(text,"10","Tasking"):ToAll()
|
||||||
self.SRSQueue:NewTransmission(text,nil,self.SRS,nil,2)
|
if self.UseSRS then
|
||||||
|
self.SRSQueue:NewTransmission(text,nil,self.SRS,nil,2)
|
||||||
|
end
|
||||||
|
self:__TaskTargetSmoked(5,task)
|
||||||
|
else
|
||||||
|
local textmark = self.gettext:GetEntry("NOSMOKETASK",self.locale)
|
||||||
|
text = string.format(textmark, ttsplayername, self.MenuName or self.Name, task.PlayerTaskNr)
|
||||||
|
self:T(self.lid..text)
|
||||||
|
--local m=MESSAGE:New(text,"10","Tasking"):ToAll()
|
||||||
|
if self.UseSRS then
|
||||||
|
self.SRSQueue:NewTransmission(text,nil,self.SRS,nil,2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
self:__TaskTargetSmoked(5,task)
|
|
||||||
else
|
else
|
||||||
text = self.gettext:GetEntry("NOACTIVETASK",self.locale)
|
text = self.gettext:GetEntry("NOACTIVETASK",self.locale)
|
||||||
end
|
end
|
||||||
@@ -4763,22 +4853,27 @@ end
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Ops.PlayerTask#PLAYERTASK Task
|
-- @param Ops.PlayerTask#PLAYERTASK Task
|
||||||
|
-- @param #boolean Silent If true, suppress message output on cancel.
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
-- @return #PLAYERTASKCONTROLLER self
|
||||||
function PLAYERTASKCONTROLLER:onafterTaskCancelled(From, Event, To, Task)
|
function PLAYERTASKCONTROLLER:onafterTaskCancelled(From, Event, To, Task, Silent)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
self:T(self.lid.."TaskCancelled")
|
self:T(self.lid.."TaskCancelled")
|
||||||
local canceltxt = self.gettext:GetEntry("TASKCANCELLED",self.locale)
|
if Silent ~= true then
|
||||||
local canceltxttts = self.gettext:GetEntry("TASKCANCELLEDTTS",self.locale)
|
local canceltxt = self.gettext:GetEntry("TASKCANCELLED",self.locale)
|
||||||
local taskname = string.format(canceltxt, Task.PlayerTaskNr, tostring(Task.Type))
|
local canceltxttts = self.gettext:GetEntry("TASKCANCELLEDTTS",self.locale)
|
||||||
if not self.NoScreenOutput then
|
local taskname = string.format(canceltxt, Task.PlayerTaskNr, tostring(Task.Type))
|
||||||
self:_SendMessageToClients(taskname,15)
|
|
||||||
--local m = MESSAGE:New(taskname,15,"Tasking"):ToCoalition(self.Coalition)
|
|
||||||
end
|
|
||||||
if self.UseSRS then
|
|
||||||
taskname = string.format(canceltxttts, self.MenuName or self.Name, Task.PlayerTaskNr, tostring(Task.TTSType))
|
|
||||||
self.SRSQueue:NewTransmission(taskname,nil,self.SRS,nil,2)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
if self.NoScreenOutput ~= true then
|
||||||
|
self:_SendMessageToClients(taskname,15)
|
||||||
|
--local m = MESSAGE:New(taskname,15,"Tasking"):ToCoalition(self.Coalition)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.UseSRS then
|
||||||
|
taskname = string.format(canceltxttts, self.MenuName or self.Name, Task.PlayerTaskNr, tostring(Task.TTSType))
|
||||||
|
self.SRSQueue:NewTransmission(taskname,nil,self.SRS,nil,2)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
local clients=Task:GetClientObjects()
|
local clients=Task:GetClientObjects()
|
||||||
for _,client in pairs(clients) do
|
for _,client in pairs(clients) do
|
||||||
self:_RemoveMenuEntriesForTask(Task,client)
|
self:_RemoveMenuEntriesForTask(Task,client)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ end
|
|||||||
|
|
||||||
--- Checks if a point is contained within the circle.
|
--- Checks if a point is contained within the circle.
|
||||||
-- @param #table point The point to check
|
-- @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)
|
function CIRCLE:ContainsPoint(point)
|
||||||
if ((point.x - self.CenterVec2.x) ^ 2 + (point.y - self.CenterVec2.y) ^ 2) ^ 0.5 <= self.Radius then
|
if ((point.x - self.CenterVec2.x) ^ 2 + (point.y - self.CenterVec2.y) ^ 2) ^ 0.5 <= self.Radius then
|
||||||
return true
|
return true
|
||||||
@@ -226,6 +226,11 @@ end
|
|||||||
--- Returns a random Vec2 within the circle.
|
--- Returns a random Vec2 within the circle.
|
||||||
-- @return #table The random Vec2
|
-- @return #table The random Vec2
|
||||||
function CIRCLE:GetRandomVec2()
|
function CIRCLE:GetRandomVec2()
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
local angle = math.random() * 2 * math.pi
|
local angle = math.random() * 2 * math.pi
|
||||||
|
|
||||||
local rx = math.random(0, self.Radius) * math.cos(angle) + self.CenterVec2.x
|
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.
|
--- Returns a random Vec2 on the border of the circle.
|
||||||
-- @return #table The random Vec2
|
-- @return #table The random Vec2
|
||||||
function CIRCLE:GetRandomVec2OnBorder()
|
function CIRCLE:GetRandomVec2OnBorder()
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
local angle = math.random() * 2 * math.pi
|
local angle = math.random() * 2 * math.pi
|
||||||
|
|
||||||
local rx = self.Radius * math.cos(angle) + self.CenterVec2.x
|
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.
|
--- 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
|
-- @return #table The random Vec2
|
||||||
function POLYGON:GetRandomVec2()
|
function POLYGON:GetRandomVec2()
|
||||||
|
|
||||||
local weights = {}
|
local weights = {}
|
||||||
for _, triangle in pairs(self.Triangles) do
|
for _, triangle in pairs(self.Triangles) do
|
||||||
weights[triangle] = triangle.SurfaceArea / self.SurfaceArea
|
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
|
-- @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
|
-- @return #table The random Vec2
|
||||||
function TRIANGLE:GetRandomVec2(points)
|
function TRIANGLE:GetRandomVec2(points)
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
points = points or self.Points
|
points = points or self.Points
|
||||||
local pt = {math.random(), math.random()}
|
local pt = {math.random(), math.random()}
|
||||||
table.sort(pt)
|
table.sort(pt)
|
||||||
|
|||||||
@@ -443,28 +443,32 @@ MSRS.Voices = {
|
|||||||
["en_AU_Standard_B"] = 'en-AU-Standard-B', -- [2] MALE
|
["en_AU_Standard_B"] = 'en-AU-Standard-B', -- [2] MALE
|
||||||
["en_AU_Standard_C"] = 'en-AU-Standard-C', -- [3] FEMALE
|
["en_AU_Standard_C"] = 'en-AU-Standard-C', -- [3] FEMALE
|
||||||
["en_AU_Standard_D"] = 'en-AU-Standard-D', -- [4] MALE
|
["en_AU_Standard_D"] = 'en-AU-Standard-D', -- [4] MALE
|
||||||
["en_IN_Standard_A"] = 'en-IN-Standard-A', -- [5] FEMALE
|
-- IN
|
||||||
["en_IN_Standard_B"] = 'en-IN-Standard-B', -- [6] MALE
|
["en_IN_Standard_A"] = 'en-IN-Standard-A', -- Female
|
||||||
["en_IN_Standard_C"] = 'en-IN-Standard-C', -- [7] MALE
|
["en_IN_Standard_B"] = 'en-IN-Standard-B', -- Male
|
||||||
["en_IN_Standard_D"] = 'en-IN-Standard-D', -- [8] FEMALE
|
["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
|
-- 2025 changes
|
||||||
["en_GB_Standard_A"] = 'en-GB-Standard-N', -- [9] FEMALE
|
["en_GB_Standard_A"] = 'en-GB-Standard-A', -- Female
|
||||||
["en_GB_Standard_B"] = 'en-GB-Standard-O', -- [10] MALE
|
["en_GB_Standard_B"] = 'en-GB-Standard-B', -- Male
|
||||||
["en_GB_Standard_C"] = 'en-GB-Standard-N', -- [11] FEMALE
|
["en_GB_Standard_C"] = 'en-GB-Standard-C', -- Female
|
||||||
["en_GB_Standard_D"] = 'en-GB-Standard-O', -- [12] MALE
|
["en_GB_Standard_D"] = 'en-GB-Standard-D', -- Male
|
||||||
["en_GB_Standard_F"] = 'en-GB-Standard-N', -- [13] FEMALE
|
["en_GB_Standard_F"] = 'en-GB-Standard-F', -- Female
|
||||||
["en_GB_Standard_O"] = 'en-GB-Standard-O', -- [12] MALE
|
["en_GB_Standard_N"] = 'en-GB-Standard-N', -- Female
|
||||||
["en_GB_Standard_N"] = 'en-GB-Standard-N', -- [13] FEMALE
|
["en_GB_Standard_O"] = 'en-GB-Standard-O', -- Male
|
||||||
["en_US_Standard_A"] = 'en-US-Standard-A', -- [14] MALE
|
-- US
|
||||||
["en_US_Standard_B"] = 'en-US-Standard-B', -- [15] MALE
|
["en_US_Standard_A"] = 'en-US-Standard-A', -- Male
|
||||||
["en_US_Standard_C"] = 'en-US-Standard-C', -- [16] FEMALE
|
["en_US_Standard_B"] = 'en-US-Standard-B', -- Male
|
||||||
["en_US_Standard_D"] = 'en-US-Standard-D', -- [17] MALE
|
["en_US_Standard_C"] = 'en-US-Standard-C', -- Female
|
||||||
["en_US_Standard_E"] = 'en-US-Standard-E', -- [18] FEMALE
|
["en_US_Standard_D"] = 'en-US-Standard-D', -- Male
|
||||||
["en_US_Standard_F"] = 'en-US-Standard-F', -- [19] FEMALE
|
["en_US_Standard_E"] = 'en-US-Standard-E', -- Female
|
||||||
["en_US_Standard_G"] = 'en-US-Standard-G', -- [20] FEMALE
|
["en_US_Standard_F"] = 'en-US-Standard-F', -- Female
|
||||||
["en_US_Standard_H"] = 'en-US-Standard-H', -- [21] FEMALE
|
["en_US_Standard_G"] = 'en-US-Standard-G', -- Female
|
||||||
["en_US_Standard_I"] = 'en-US-Standard-I', -- [22] MALE
|
["en_US_Standard_H"] = 'en-US-Standard-H', -- Female
|
||||||
["en_US_Standard_J"] = 'en-US-Standard-J', -- [23] MALE
|
["en_US_Standard_I"] = 'en-US-Standard-I', -- Male
|
||||||
|
["en_US_Standard_J"] = 'en-US-Standard-J', -- Male
|
||||||
-- 2025 catalog changes
|
-- 2025 catalog changes
|
||||||
["fr_FR_Standard_A"] = "fr-FR-Standard-F", -- Female
|
["fr_FR_Standard_A"] = "fr-FR-Standard-F", -- Female
|
||||||
["fr_FR_Standard_B"] = "fr-FR-Standard-G", -- Male
|
["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_G"] = "fr-FR-Standard-G", -- Male
|
||||||
["fr_FR_Standard_F"] = "fr-FR-Standard-F", -- Female
|
["fr_FR_Standard_F"] = "fr-FR-Standard-F", -- Female
|
||||||
-- 2025 catalog changes
|
-- 2025 catalog changes
|
||||||
["de_DE_Standard_A"] = "de-DE-Standard-G", -- Female
|
["de_DE_Standard_A"] = 'de-DE-Standard-A', -- Female
|
||||||
["de_DE_Standard_B"] = "de-DE-Standard-H", -- Male
|
["de_DE_Standard_B"] = 'de-DE-Standard-B', -- Male
|
||||||
["de_DE_Standard_C"] = "de-DE-Standard-G", -- Female
|
["de_DE_Standard_C"] = 'de-DE-Standard-C', -- Female
|
||||||
["de_DE_Standard_D"] = "de-DE-Standard-H", -- Male
|
["de_DE_Standard_D"] = 'de-DE-Standard-D', -- Male
|
||||||
["de_DE_Standard_E"] = "de-DE-Standard-H", -- Male
|
["de_DE_Standard_E"] = 'de-DE-Standard-E', -- Male
|
||||||
["de_DE_Standard_F"] = "de-DE-Standard-G", -- Female
|
["de_DE_Standard_F"] = 'de-DE-Standard-F', -- Female
|
||||||
["de_DE_Standard_H"] = "de-DE-Standard-H", -- Male
|
["de_DE_Standard_G"] = 'de-DE-Standard-G', -- 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_A"] = "es-ES-Standard-E", -- Female
|
||||||
["es_ES_Standard_B"] = "es-ES-Standard-F", -- Male
|
["es_ES_Standard_B"] = "es-ES-Standard-F", -- Male
|
||||||
["es_ES_Standard_C"] = "es-ES-Standard-E", -- Female
|
["es_ES_Standard_C"] = "es-ES-Standard-E", -- Female
|
||||||
@@ -497,32 +502,36 @@ MSRS.Voices = {
|
|||||||
["it_IT_Standard_F"] = "it-IT-Standard-F", -- Male
|
["it_IT_Standard_F"] = "it-IT-Standard-F", -- Male
|
||||||
},
|
},
|
||||||
Wavenet = {
|
Wavenet = {
|
||||||
["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- [1] FEMALE
|
["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- Female
|
||||||
["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- [2] MALE
|
["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- Male
|
||||||
["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- [3] FEMALE
|
["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- Female
|
||||||
["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- [4] MALE
|
["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- Male
|
||||||
["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- [5] FEMALE
|
-- IN
|
||||||
["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- [6] MALE
|
["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- Female
|
||||||
["en_IN_Wavenet_C"] = 'en-IN-Wavenet-C', -- [7] MALE
|
["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- Male
|
||||||
["en_IN_Wavenet_D"] = 'en-IN-Wavenet-D', -- [8] FEMALE
|
["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
|
-- 2025 changes
|
||||||
["en_GB_Wavenet_A"] = 'en-GB-Wavenet-N', -- [9] FEMALE
|
["en_GB_Wavenet_A"] = 'en-GB-Wavenet-A', -- [9] FEMALE
|
||||||
["en_GB_Wavenet_B"] = 'en-GB-Wavenet-O', -- [10] MALE
|
["en_GB_Wavenet_B"] = 'en-GB-Wavenet-B', -- [10] MALE
|
||||||
["en_GB_Wavenet_C"] = 'en-GB-Wavenet-N', -- [11] FEMALE
|
["en_GB_Wavenet_C"] = 'en-GB-Wavenet-C', -- [11] FEMALE
|
||||||
["en_GB_Wavenet_D"] = 'en-GB-Wavenet-O', -- [12] MALE
|
["en_GB_Wavenet_D"] = 'en-GB-Wavenet-D', -- [12] MALE
|
||||||
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-F', -- [13] FEMALE
|
||||||
["en_GB_Wavenet_O"] = 'en-GB-Wavenet-O', -- [12] MALE
|
["en_GB_Wavenet_O"] = 'en-GB-Wavenet-O', -- [12] MALE
|
||||||
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||||
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- [14] MALE
|
-- US
|
||||||
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE
|
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- Male
|
||||||
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE
|
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- Male
|
||||||
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE
|
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- Female
|
||||||
["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- [18] FEMALE
|
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- Male
|
||||||
["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- [19] FEMALE
|
["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- Female
|
||||||
["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- [20] FEMALE
|
["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- Female
|
||||||
["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- [21] FEMALE
|
["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- Female
|
||||||
["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- [22] MALE
|
["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- Female
|
||||||
["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- [23] MALE
|
["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- Male
|
||||||
|
["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- Male
|
||||||
-- 2025 catalog changes
|
-- 2025 catalog changes
|
||||||
["fr_FR_Wavenet_A"] = "fr-FR-Wavenet-F", -- Female
|
["fr_FR_Wavenet_A"] = "fr-FR-Wavenet-F", -- Female
|
||||||
["fr_FR_Wavenet_B"] = "fr-FR-Wavenet-G", -- Male
|
["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_G"] = "fr-FR-Wavenet-G", -- Male
|
||||||
["fr_FR_Wavenet_F"] = "fr-FR-Wavenet-F", -- Female
|
["fr_FR_Wavenet_F"] = "fr-FR-Wavenet-F", -- Female
|
||||||
-- 2025 catalog changes
|
-- 2025 catalog changes
|
||||||
["de_DE_Wavenet_A"] = "de-DE-Wavenet-G", -- Female
|
["de_DE_Wavenet_A"] = 'de-DE-Wavenet-A', -- Female
|
||||||
["de_DE_Wavenet_B"] = "de-DE-Wavenet-H", -- Male
|
["de_DE_Wavenet_B"] = 'de-DE-Wavenet-B', -- Male
|
||||||
["de_DE_Wavenet_C"] = "de-DE-Wavenet-G", -- Female
|
["de_DE_Wavenet_C"] = 'de-DE-Wavenet-C', -- Female
|
||||||
["de_DE_Wavenet_D"] = "de-DE-Wavenet-H", -- Male
|
["de_DE_Wavenet_D"] = 'de-DE-Wavenet-D', -- Male
|
||||||
["de_DE_Wavenet_E"] = "de-DE-Wavenet-H", -- Male
|
["de_DE_Wavenet_E"] = 'de-DE-Wavenet-E', -- Male
|
||||||
["de_DE_Wavenet_F"] = "de-DE-Wavenet-G", -- Female
|
["de_DE_Wavenet_F"] = 'de-DE-Wavenet-F', -- Female
|
||||||
["de_DE_Wavenet_H"] = "de-DE-Wavenet-H", -- Male
|
["de_DE_Wavenet_G"] = 'de-DE-Wavenet-G', -- 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_B"] = "es-ES-Wavenet-E", -- Male
|
||||||
["es_ES_Wavenet_C"] = "es-ES-Wavenet-F", -- Female
|
["es_ES_Wavenet_C"] = "es-ES-Wavenet-F", -- Female
|
||||||
["es_ES_Wavenet_D"] = "es-ES-Wavenet-E", -- 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_E"] = "it-IT-Wavenet-E", -- Female
|
||||||
["it_IT_Wavenet_F"] = "it-IT-Wavenet-F", -- Male
|
["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
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -606,6 +606,7 @@ ENUMS.Storage = {
|
|||||||
OH58 = {}, -- Kiowa specifics
|
OH58 = {}, -- Kiowa specifics
|
||||||
UH1H = {}, -- Huey specifics
|
UH1H = {}, -- Huey specifics
|
||||||
AH64D = {}, -- Huey specifics
|
AH64D = {}, -- Huey specifics
|
||||||
|
UH60L = {}, -- Blackhawk specifics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1315,6 +1316,26 @@ ENUMS.Storage.weapons.UH1H.M134_MiniGun_Right_Door = {4,15,46,175}
|
|||||||
ENUMS.Storage.weapons.UH1H.M60_MG_Right_Door = {4,15,46,177}
|
ENUMS.Storage.weapons.UH1H.M60_MG_Right_Door = {4,15,46,177}
|
||||||
ENUMS.Storage.weapons.UH1H.M134_MiniGun_Left_Door = {4,15,46,174}
|
ENUMS.Storage.weapons.UH1H.M134_MiniGun_Left_Door = {4,15,46,174}
|
||||||
ENUMS.Storage.weapons.UH1H.M60_MG_Left_Door = {4,15,46,176}
|
ENUMS.Storage.weapons.UH1H.M60_MG_Left_Door = {4,15,46,176}
|
||||||
|
-- UH-60L
|
||||||
|
ENUMS.Storage.weapons.UH60L.M151_HYDRA = {4, 7, 33, 147} -- 2.75" Hydra, UnGd Rkts M151, HE
|
||||||
|
ENUMS.Storage.weapons.UH60L.M156_HYDRA = {4, 7, 33, 148} -- 2.75" Hydra, UnGd Rkts M156, Wht Phos
|
||||||
|
ENUMS.Storage.weapons.UH60L.M229_HYDRA = {4, 7, 33, 148} -- 2.75" Hydra, UnGd Rkts M229, HE
|
||||||
|
ENUMS.Storage.weapons.UH60L.M257_HYDRA = {4, 7, 33, 151} -- 2.75" Hydra, UnGd Rkts M257, Para Illum
|
||||||
|
ENUMS.Storage.weapons.UH60L.M259_HYDRA = {4, 7, 33, 151} -- 2.75" Hydra, UnGd Rkts M259, Smoke Marker
|
||||||
|
ENUMS.Storage.weapons.UH60L.M274_HYDRA = {4, 7, 33, 150} -- 2.75" Hydra, UnGd Rkts M274, Practice Smk
|
||||||
|
ENUMS.Storage.weapons.UH60L.M134_DOOR_GUN = {4, 15, 46, 3031}
|
||||||
|
ENUMS.Storage.weapons.UH60L.M3M = {4, 15, 46, 2496}
|
||||||
|
ENUMS.Storage.weapons.UH60L.M3M_DOOR_GUN = {4, 15, 46, 3032}
|
||||||
|
ENUMS.Storage.weapons.UH60L.M60_DOOR_GUN = {4, 15, 46, 3033}
|
||||||
|
ENUMS.Storage.weapons.UH60L.FUEL_TANK_200 = {1,3,43,3023}
|
||||||
|
ENUMS.Storage.weapons.UH60L.FUEL_TANK_230 = {1,3,43,3024}
|
||||||
|
ENUMS.Storage.weapons.UH60L.FUEL_TANK_450 = {1,3,43,3025}
|
||||||
|
ENUMS.Storage.weapons.UH60L.FUEL_TANK_DUAL_AUX = {1,3,43,3026}
|
||||||
|
ENUMS.Storage.weapons.UH60L.CARGO_SEAT_REAR_ROW = {1,3,43,3030}
|
||||||
|
ENUMS.Storage.weapons.UH60L.CARGO_SEAT_THREE_ROWS = {1,3,43,3029}
|
||||||
|
ENUMS.Storage.weapons.UH60L.EMPTY_GUNNER_SEAT_1 = {1,3,43,3027}
|
||||||
|
ENUMS.Storage.weapons.UH60L.EMPTY_GUNNER_SEAT_2 = {1,3,43,3028}
|
||||||
|
|
||||||
-- Kiowa
|
-- Kiowa
|
||||||
ENUMS.Storage.weapons.OH58.FIM92 = {4,4,7,449}
|
ENUMS.Storage.weapons.OH58.FIM92 = {4,4,7,449}
|
||||||
ENUMS.Storage.weapons.OH58.MG_M3P100 = {4,15,46,2611}
|
ENUMS.Storage.weapons.OH58.MG_M3P100 = {4,15,46,2611}
|
||||||
|
|||||||
@@ -1586,12 +1586,12 @@ function UTILS.HdgDiff(h1, h2)
|
|||||||
return math.abs(delta)
|
return math.abs(delta)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the heading from one vec3 to another vec3.
|
--- Returns the heading from one vec2/vec3 to another vec2/vec3.
|
||||||
-- @param DCS#Vec3 a From vec3.
|
-- @param DCS#Vec3 a From Vec2 or Vec3.
|
||||||
-- @param DCS#Vec3 b To vec3.
|
-- @param DCS#Vec3 b To Vec2 or Vec3.
|
||||||
-- @return #number Heading in degrees.
|
-- @return #number Heading in degrees.
|
||||||
function UTILS.HdgTo(a, b)
|
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 dx=b.x-a.x
|
||||||
local heading=math.deg(math.atan2(dz, dx))
|
local heading=math.deg(math.atan2(dz, dx))
|
||||||
if heading < 0 then
|
if heading < 0 then
|
||||||
@@ -2330,6 +2330,16 @@ function UTILS.IsLoadingDoorOpen( unit_name )
|
|||||||
return true
|
return true
|
||||||
end
|
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
|
if type_name == "AH-64D_BLK_II" then
|
||||||
BASE:T(unit_name .. " front door(s) are open")
|
BASE:T(unit_name .. " front door(s) are open")
|
||||||
return true -- no doors on this one ;)
|
return true -- no doors on this one ;)
|
||||||
@@ -4127,6 +4137,45 @@ function UTILS.LCGRandom()
|
|||||||
return UTILS.lcg.seed / UTILS.lcg.m
|
return UTILS.lcg.seed / UTILS.lcg.m
|
||||||
end
|
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.
|
--- 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.
|
-- 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)
|
-- References: [DCS Forum Topic](https://forum.dcs.world/topic/282989-farp-equipment-to-run-it)
|
||||||
@@ -4147,10 +4196,38 @@ end
|
|||||||
-- @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 #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 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 #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 #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.
|
-- @return #string ADFBeaconName Name of the ADF beacon, to be able to remove/stop it later.
|
||||||
-- @return #number MarkerID ID of the F10 Text, to be able to remove it later.
|
-- @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)
|
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
|
-- Set Defaults
|
||||||
local farplocation = Coordinate
|
local farplocation = Coordinate
|
||||||
@@ -4171,12 +4248,74 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
|
|||||||
local Country = Country or (Coalition == coalition.side.BLUE and country.id.USA or country.id.RUSSIA)
|
local Country = Country or (Coalition == coalition.side.BLUE and country.id.USA or country.id.RUSSIA)
|
||||||
local ReturnObjects = {}
|
local ReturnObjects = {}
|
||||||
|
|
||||||
-- Spawn FARP
|
-- many FARPs
|
||||||
local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP"
|
local NumberPads = NumberPads or 1
|
||||||
newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS"
|
local SpacingX = SpacingX or 100
|
||||||
newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart)
|
local SpacingY = SpacingY or 100
|
||||||
local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name)
|
local FarpVec2 = Coordinate:GetVec2()
|
||||||
table.insert(ReturnObjects,spawnedfarp)
|
|
||||||
|
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
|
-- Spawn Objects
|
||||||
local FARPStaticObjectsNato = {
|
local FARPStaticObjectsNato = {
|
||||||
["FUEL"] = { TypeName = "FARP Fuel Depot", ShapeName = "GSM Rus", Category = "Fortifications"},
|
["FUEL"] = { TypeName = "FARP Fuel Depot", ShapeName = "GSM Rus", Category = "Fortifications"},
|
||||||
@@ -4210,29 +4349,6 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
|
|||||||
table.insert(ReturnObjects,spawnedvehicle)
|
table.insert(ReturnObjects,spawnedvehicle)
|
||||||
end
|
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
|
|
||||||
|
|
||||||
if airframes and airframes > 0 then
|
|
||||||
for typename in pairs (CSAR.AircraftType) do
|
|
||||||
newWH:SetItem(typename,airframes)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local ADFName
|
local ADFName
|
||||||
if ADF and type(ADF) == "number" then
|
if ADF and type(ADF) == "number" then
|
||||||
local ADFFreq = ADF*1000 -- KHz to Hz
|
local ADFFreq = ADF*1000 -- KHz to Hz
|
||||||
@@ -4598,16 +4714,16 @@ function UTILS.DoStringIn(State,DoString)
|
|||||||
return net.dostring_in(State,DoString)
|
return net.dostring_in(State,DoString)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Show a picture on the screen
|
--- Show a picture on the screen to all
|
||||||
-- @param #string FileName File name of the picture
|
-- @param #string FileName File name of the picture
|
||||||
-- @param #number Duration Duration in seconds, defaults to 10
|
-- @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 #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 StartDelay Delay in seconds before showing the picture, defaults to 0
|
||||||
-- @param #number HorizontalAlign Horizontal alignment of the picture, defaults to 1 (left), can be 0 (center) or 2 (right)
|
-- @param #number HorizontalAlign Horizontal alignment of the picture, 0: Left, 1: Center, 2: Right
|
||||||
-- @param #number VerticalAlign Vertical alignment of the picture, defaults to 1 (top), can be 0 (center) or 2 (bottom)
|
-- @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 Size Size of the picture in percent, defaults to 100
|
||||||
-- @param #number SizeUnits Size units, defaults to 0 (percent), can be 1 (pixels)
|
-- @param #number SizeUnits Size units, 0 for % of original picture size, and 1 for % of window size
|
||||||
function UTILS.ShowPicture(FileName, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)
|
function UTILS.ShowPictureToAll(FilePath, Duration, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits)
|
||||||
ClearView = ClearView or false
|
ClearView = ClearView or false
|
||||||
StartDelay = StartDelay or 0
|
StartDelay = StartDelay or 0
|
||||||
HorizontalAlign = HorizontalAlign or 1
|
HorizontalAlign = HorizontalAlign or 1
|
||||||
@@ -4617,16 +4733,142 @@ function UTILS.ShowPicture(FileName, Duration, ClearView, StartDelay, Horizontal
|
|||||||
|
|
||||||
if ClearView then ClearView = "true" else ClearView = "false" end
|
if ClearView then ClearView = "true" else ClearView = "false" end
|
||||||
|
|
||||||
net.dostring_in("mission", string.format("a_out_picture(getValueResourceByKey(\"%s\"), %d, %s, %d, \"%d\", \"%d\", %d, \"%d\")", FileName, Duration or 10, ClearView, StartDelay, HorizontalAlign, VerticalAlign, Size, SizeUnits))
|
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
|
end
|
||||||
|
|
||||||
--- Show a helper gate at a DCS#Vec3 position
|
--- Show a helper gate at a DCS#Vec3 position
|
||||||
-- @param DCS#Vec3 pos The position
|
-- @param DCS#Vec3 pos The position
|
||||||
-- @param number heading Heading in degrees, can be 0..359 degrees
|
-- @param #number heading Heading in degrees, can be 0..359 degrees
|
||||||
function UTILS.ShowHelperGate(pos, heading)
|
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)))
|
net.dostring_in("mission",string.format("a_show_helper_gate(%s, %s, %s, %f)", pos.x, pos.y, pos.z, math.rad(heading)))
|
||||||
end
|
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
|
--- Shell a zone, zone must ME created
|
||||||
-- @param #string name The name of the ME created zone
|
-- @param #string name The name of the ME created zone
|
||||||
-- @param #number power Equals kg of TNT, e.g. 75
|
-- @param #number power Equals kg of TNT, e.g. 75
|
||||||
@@ -4745,3 +4987,161 @@ function UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2)
|
|||||||
|
|
||||||
return {x=qx, y=qy}
|
return {x=qx, y=qy}
|
||||||
end
|
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
|
||||||
|
|||||||
@@ -703,51 +703,56 @@ AIRBASE.SouthAtlantic={
|
|||||||
|
|
||||||
--- Airbases of the Sinai map:
|
--- Airbases of the Sinai map:
|
||||||
--
|
--
|
||||||
-- * AIRBASE.Sinai.Abu_Rudeis
|
-- * AIRBASE.SinaiMap.Abu_Rudeis
|
||||||
-- * AIRBASE.Sinai.Abu_Suwayr
|
-- * AIRBASE.SinaiMap.Abu_Suwayr
|
||||||
-- * AIRBASE.Sinai.Al_Bahr_al_Ahmar
|
-- * AIRBASE.SinaiMap.Al_Bahr_al_Ahmar
|
||||||
-- * AIRBASE.Sinai.Al_Ismailiyah
|
-- * AIRBASE.SinaiMap.Al_Ismailiyah
|
||||||
-- * AIRBASE.Sinai.Al_Khatatbah
|
-- * AIRBASE.SinaiMap.Al_Khatatbah
|
||||||
-- * AIRBASE.Sinai.Al_Mansurah
|
-- * AIRBASE.SinaiMap.Al_Mansurah
|
||||||
-- * AIRBASE.Sinai.Al_Rahmaniyah_Air_Base
|
-- * AIRBASE.SinaiMap.Al_Rahmaniyah_Air_Base
|
||||||
-- * AIRBASE.Sinai.As_Salihiyah
|
-- * AIRBASE.SinaiMap.As_Salihiyah
|
||||||
-- * AIRBASE.Sinai.AzZaqaziq
|
-- * AIRBASE.SinaiMap.AzZaqaziq
|
||||||
-- * AIRBASE.Sinai.Baluza
|
-- * AIRBASE.SinaiMap.Baluza
|
||||||
-- * AIRBASE.Sinai.Ben_Gurion
|
-- * AIRBASE.SinaiMap.Ben_Gurion
|
||||||
-- * AIRBASE.Sinai.Beni_Suef
|
-- * AIRBASE.SinaiMap.Beni_Suef
|
||||||
-- * AIRBASE.Sinai.Bilbeis_Air_Base
|
-- * AIRBASE.SinaiMap.Bilbeis_Air_Base
|
||||||
-- * AIRBASE.Sinai.Bir_Hasanah
|
-- * AIRBASE.SinaiMap.Bir_Hasanah
|
||||||
-- * AIRBASE.Sinai.Birma_Air_Base
|
-- * AIRBASE.SinaiMap.Birma_Air_Base
|
||||||
-- * AIRBASE.Sinai.Borg_El_Arab_International_Airport
|
-- * AIRBASE.SinaiMap.Borg_El_Arab_International_Airport
|
||||||
-- * AIRBASE.Sinai.Cairo_International_Airport
|
-- * AIRBASE.SinaiMap.Cairo_International_Airport
|
||||||
-- * AIRBASE.Sinai.Cairo_West
|
-- * AIRBASE.SinaiMap.Cairo_West
|
||||||
-- * AIRBASE.Sinai.Difarsuwar_Airfield
|
-- * AIRBASE.SinaiMap.Damascus_Intl
|
||||||
-- * AIRBASE.Sinai.El_Arish
|
-- * AIRBASE.SinaiMap.Difarsuwar_Airfield
|
||||||
-- * AIRBASE.Sinai.El_Gora
|
-- * AIRBASE.SinaiMap.El_Arish
|
||||||
-- * AIRBASE.Sinai.El_Minya
|
-- * AIRBASE.SinaiMap.El_Gora
|
||||||
-- * AIRBASE.Sinai.Fayed
|
-- * AIRBASE.SinaiMap.El_Minya
|
||||||
-- * AIRBASE.Sinai.Gebel_El_Basur_Air_Base
|
-- * AIRBASE.SinaiMap.Fayed
|
||||||
-- * AIRBASE.Sinai.Hatzerim
|
-- * AIRBASE.SinaiMap.Gebel_El_Basur_Air_Base
|
||||||
-- * AIRBASE.Sinai.Hatzor
|
-- * AIRBASE.SinaiMap.Hatzerim
|
||||||
-- * AIRBASE.Sinai.Hurghada_International_Airport
|
-- * AIRBASE.SinaiMap.Hatzor
|
||||||
-- * AIRBASE.Sinai.Inshas_Airbase
|
-- * AIRBASE.SinaiMap.Hurghada_International_Airport
|
||||||
-- * AIRBASE.Sinai.Jiyanklis_Air_Base
|
-- * AIRBASE.SinaiMap.Inshas_Airbase
|
||||||
-- * AIRBASE.Sinai.Kedem
|
-- * AIRBASE.SinaiMap.Jiyanklis_Air_Base
|
||||||
-- * AIRBASE.Sinai.Kibrit_Air_Base
|
-- * AIRBASE.SinaiMap.Kedem
|
||||||
-- * AIRBASE.Sinai.Kom_Awshim
|
-- * AIRBASE.SinaiMap.Kibrit_Air_Base
|
||||||
-- * AIRBASE.Sinai.Melez
|
-- * AIRBASE.SinaiMap.Kom_Awshim
|
||||||
-- * AIRBASE.Sinai.Nevatim
|
-- * AIRBASE.SinaiMap.Melez
|
||||||
-- * AIRBASE.Sinai.Ovda
|
-- * AIRBASE.SinaiMap.Mezzeh_Air_Base
|
||||||
-- * AIRBASE.Sinai.Palmachim
|
-- * AIRBASE.SinaiMap.Nevatim
|
||||||
-- * AIRBASE.Sinai.Quwaysina
|
-- * AIRBASE.SinaiMap.Ovda
|
||||||
-- * AIRBASE.Sinai.Ramon_Airbase
|
-- * AIRBASE.SinaiMap.Palmachim
|
||||||
-- * AIRBASE.Sinai.Ramon_International_Airport
|
-- * AIRBASE.SinaiMap.Quwaysina
|
||||||
-- * AIRBASE.Sinai.Sde_Dov
|
-- * AIRBASE.SinaiMap.Rafic_Hariri_Intl
|
||||||
-- * AIRBASE.Sinai.Sharm_El_Sheikh_International_Airport
|
-- * AIRBASE.SinaiMap.Ramat_David
|
||||||
-- * AIRBASE.Sinai.St_Catherine
|
-- * AIRBASE.SinaiMap.Ramon_Airbase
|
||||||
-- * AIRBASE.Sinai.Tel_Nof
|
-- * AIRBASE.SinaiMap.Ramon_International_Airport
|
||||||
-- * AIRBASE.Sinai.Wadi_Abu_Rish
|
-- * AIRBASE.SinaiMap.Sde_Dov
|
||||||
-- * AIRBASE.Sinai.Wadi_al_Jandali
|
-- * 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
|
-- @field Sinai
|
||||||
AIRBASE.Sinai = {
|
AIRBASE.Sinai = {
|
||||||
@@ -769,6 +774,7 @@ AIRBASE.Sinai = {
|
|||||||
["Borg_El_Arab_International_Airport"] = "Borg El Arab International Airport",
|
["Borg_El_Arab_International_Airport"] = "Borg El Arab International Airport",
|
||||||
["Cairo_International_Airport"] = "Cairo International Airport",
|
["Cairo_International_Airport"] = "Cairo International Airport",
|
||||||
["Cairo_West"] = "Cairo West",
|
["Cairo_West"] = "Cairo West",
|
||||||
|
["Damascus_Intl"] = "Damascus Intl",
|
||||||
["Difarsuwar_Airfield"] = "Difarsuwar Airfield",
|
["Difarsuwar_Airfield"] = "Difarsuwar Airfield",
|
||||||
["El_Arish"] = "El Arish",
|
["El_Arish"] = "El Arish",
|
||||||
["El_Gora"] = "El Gora",
|
["El_Gora"] = "El Gora",
|
||||||
@@ -784,15 +790,19 @@ AIRBASE.Sinai = {
|
|||||||
["Kibrit_Air_Base"] = "Kibrit Air Base",
|
["Kibrit_Air_Base"] = "Kibrit Air Base",
|
||||||
["Kom_Awshim"] = "Kom Awshim",
|
["Kom_Awshim"] = "Kom Awshim",
|
||||||
["Melez"] = "Melez",
|
["Melez"] = "Melez",
|
||||||
|
["Mezzeh_Air_Base"] = "Mezzeh Air Base",
|
||||||
["Nevatim"] = "Nevatim",
|
["Nevatim"] = "Nevatim",
|
||||||
["Ovda"] = "Ovda",
|
["Ovda"] = "Ovda",
|
||||||
["Palmachim"] = "Palmachim",
|
["Palmachim"] = "Palmachim",
|
||||||
["Quwaysina"] = "Quwaysina",
|
["Quwaysina"] = "Quwaysina",
|
||||||
|
["Rafic_Hariri_Intl"] = "Rafic Hariri Intl",
|
||||||
|
["Ramat_David"] = "Ramat David",
|
||||||
["Ramon_Airbase"] = "Ramon Airbase",
|
["Ramon_Airbase"] = "Ramon Airbase",
|
||||||
["Ramon_International_Airport"] = "Ramon International Airport",
|
["Ramon_International_Airport"] = "Ramon International Airport",
|
||||||
["Sde_Dov"] = "Sde Dov",
|
["Sde_Dov"] = "Sde Dov",
|
||||||
["Sharm_El_Sheikh_International_Airport"] = "Sharm El Sheikh International Airport",
|
["Sharm_El_Sheikh_International_Airport"] = "Sharm El Sheikh International Airport",
|
||||||
["St_Catherine"] = "St Catherine",
|
["St_Catherine"] = "St Catherine",
|
||||||
|
["Tabuk"] = "Tabuk",
|
||||||
["Tel_Nof"] = "Tel Nof",
|
["Tel_Nof"] = "Tel Nof",
|
||||||
["Wadi_Abu_Rish"] = "Wadi Abu Rish",
|
["Wadi_Abu_Rish"] = "Wadi Abu Rish",
|
||||||
["Wadi_al_Jandali"] = "Wadi al Jandali",
|
["Wadi_al_Jandali"] = "Wadi al Jandali",
|
||||||
@@ -923,37 +933,51 @@ AIRBASE.Afghanistan = {
|
|||||||
|
|
||||||
--- Airbases of the Iraq map
|
--- 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_Asad_Airbase
|
||||||
|
-- * AIRBASE.Iraq.Al_Kut_Airbase
|
||||||
|
-- * AIRBASE.Iraq.Al_Sahra_Airport
|
||||||
-- * AIRBASE.Iraq.Al_Salam_Airbase
|
-- * AIRBASE.Iraq.Al_Salam_Airbase
|
||||||
-- * AIRBASE.Iraq.Balad_Airbase
|
-- * AIRBASE.Iraq.Al_Taji_Airport
|
||||||
-- * AIRBASE.Iraq.Kirkuk_International_Airport
|
|
||||||
-- * AIRBASE.Iraq.Bashur_Airport
|
|
||||||
-- * AIRBASE.Iraq.Al_Taquddum_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.K1_Base
|
||||||
|
-- * AIRBASE.Iraq.Kirkuk_International_Airport
|
||||||
|
-- * AIRBASE.Iraq.Mosul_International_Airport
|
||||||
|
-- * AIRBASE.Iraq.Qayyarah_Airfield_West
|
||||||
|
-- * AIRBASE.Iraq.Sulaimaniyah_International_Airport
|
||||||
--
|
--
|
||||||
-- @field Iraq
|
-- @field Iraq
|
||||||
AIRBASE.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_Asad_Airbase"] = "Al-Asad Airbase",
|
||||||
|
["Al_Kut_Airport"] = "Al-Kut Airport",
|
||||||
|
["Al_Sahra_Airport"] = "Al-Sahra Airport",
|
||||||
["Al_Salam_Airbase"] = "Al-Salam Airbase",
|
["Al_Salam_Airbase"] = "Al-Salam Airbase",
|
||||||
["Balad_Airbase"] = "Balad Airbase",
|
["Al_Taji_Airport"] = "Al-Taji Airport",
|
||||||
["Kirkuk_International_Airport"] = "Kirkuk International Airport",
|
|
||||||
["Bashur_Airport"] = "Bashur Airport",
|
|
||||||
["Al_Taquddum_Airport"] = "Al-Taquddum 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",
|
["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
|
--- Airbases of the Germany Cold War map
|
||||||
-- * AIRBASE.GermanyCW.Airracing_Frankfurt
|
-- * AIRBASE.GermanyCW.Airracing_Frankfurt
|
||||||
-- * AIRBASE.GermanyCW.Airracing_Frankfurt
|
-- * AIRBASE.GermanyCW.Airracing_Frankfurt
|
||||||
@@ -1550,6 +1574,17 @@ end
|
|||||||
return self
|
return self
|
||||||
end
|
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.
|
--- Get the category of this airbase. This is only a debug function because DCS 2.9 incorrectly returns heliports as airdromes.
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
function AIRBASE:_GetCategory()
|
function AIRBASE:_GetCategory()
|
||||||
|
|||||||
@@ -4163,7 +4163,7 @@ function CONTROLLABLE:OptionRestrictBurner( RestrictBurner )
|
|||||||
|
|
||||||
end
|
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 #CONTROLLABLE self
|
||||||
-- @param #number range Defines the range
|
-- @param #number range Defines the range
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
@@ -4188,6 +4188,66 @@ function CONTROLLABLE:OptionAAAttackRange( range )
|
|||||||
return nil
|
return nil
|
||||||
end
|
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.
|
--- Defines the range at which a GROUND unit/group is allowed to use its weapons automatically.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number EngageRange Engage range limit in percent (a number between 0 and 100). Default 100.
|
-- @param #number EngageRange Engage range limit in percent (a number between 0 and 100). Default 100.
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ DYNAMICCARGO.State = {
|
|||||||
-- @type DYNAMICCARGO.AircraftTypes
|
-- @type DYNAMICCARGO.AircraftTypes
|
||||||
DYNAMICCARGO.AircraftTypes = {
|
DYNAMICCARGO.AircraftTypes = {
|
||||||
["CH-47Fbl1"] = "CH-47Fbl1",
|
["CH-47Fbl1"] = "CH-47Fbl1",
|
||||||
|
["Mi-8MTV2"] = "CH-47Fbl1",
|
||||||
|
["Mi-8MT"] = "CH-47Fbl1",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Helo types possible.
|
--- Helo types possible.
|
||||||
@@ -120,17 +122,30 @@ DYNAMICCARGO.AircraftDimensions = {
|
|||||||
["length"] = 11,
|
["length"] = 11,
|
||||||
["ropelength"] = 30,
|
["ropelength"] = 30,
|
||||||
},
|
},
|
||||||
|
["Mi-8MTV2"] = {
|
||||||
|
["width"] = 6,
|
||||||
|
["height"] = 6,
|
||||||
|
["length"] = 15,
|
||||||
|
["ropelength"] = 30,
|
||||||
|
},
|
||||||
|
["Mi-8MT"] = {
|
||||||
|
["width"] = 6,
|
||||||
|
["height"] = 6,
|
||||||
|
["length"] = 15,
|
||||||
|
["ropelength"] = 30,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- DYNAMICCARGO class version.
|
--- DYNAMICCARGO class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
DYNAMICCARGO.version="0.0.7"
|
DYNAMICCARGO.version="0.0.9"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: A lot...
|
-- TODO: A lot...
|
||||||
|
-- DONE: Added Mi-8 type and dimensions
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Constructor
|
-- Constructor
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ GROUP.Attribute = {
|
|||||||
GROUND_AAA="Ground_AAA",
|
GROUND_AAA="Ground_AAA",
|
||||||
GROUND_SAM="Ground_SAM",
|
GROUND_SAM="Ground_SAM",
|
||||||
GROUND_SHORAD="Ground_SHORAD",
|
GROUND_SHORAD="Ground_SHORAD",
|
||||||
|
GROUND_BALLISTICMISSILE="Ground_BallisticMissile",
|
||||||
GROUND_OTHER="Ground_OtherGround",
|
GROUND_OTHER="Ground_OtherGround",
|
||||||
NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier",
|
NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier",
|
||||||
NAVAL_WARSHIP="Naval_WarShip",
|
NAVAL_WARSHIP="Naval_WarShip",
|
||||||
@@ -2231,6 +2232,10 @@ function GROUP:Respawn( Template, Reset )
|
|||||||
|
|
||||||
--UTILS.PrintTableToLog(Template)
|
--UTILS.PrintTableToLog(Template)
|
||||||
|
|
||||||
|
if self.ValidateAndRepositionGroundUnits then
|
||||||
|
UTILS.ValidateAndRepositionGroundUnits(Template.units)
|
||||||
|
end
|
||||||
|
|
||||||
-- Spawn new group.
|
-- Spawn new group.
|
||||||
self:ScheduleOnce(0.1,_DATABASE.Spawn,_DATABASE,Template)
|
self:ScheduleOnce(0.1,_DATABASE.Spawn,_DATABASE,Template)
|
||||||
--_DATABASE:Spawn(Template)
|
--_DATABASE:Spawn(Template)
|
||||||
@@ -2639,6 +2644,8 @@ function GROUP:GetAttribute()
|
|||||||
local artillery=self:HasAttribute("Artillery")
|
local artillery=self:HasAttribute("Artillery")
|
||||||
local tank=self:HasAttribute("Old Tanks") or self:HasAttribute("Modern Tanks") or self:HasAttribute("Tanks")
|
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 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 ewr=self:HasAttribute("EWR")
|
||||||
local ifv=self:HasAttribute("IFV")
|
local ifv=self:HasAttribute("IFV")
|
||||||
local sam=self:HasAttribute("SAM elements") or self:HasAttribute("Optical Tracker")
|
local sam=self:HasAttribute("SAM elements") or self:HasAttribute("Optical Tracker")
|
||||||
@@ -2680,6 +2687,8 @@ function GROUP:GetAttribute()
|
|||||||
attribute=GROUP.Attribute.GROUND_SAM
|
attribute=GROUP.Attribute.GROUND_SAM
|
||||||
elseif aaa then
|
elseif aaa then
|
||||||
attribute=GROUP.Attribute.GROUND_AAA
|
attribute=GROUP.Attribute.GROUND_AAA
|
||||||
|
elseif artillery and ballisticMissile then
|
||||||
|
attribute=GROUP.Attribute.GROUND_BALLISTICMISSILE
|
||||||
elseif artillery then
|
elseif artillery then
|
||||||
attribute=GROUP.Attribute.GROUND_ARTILLERY
|
attribute=GROUP.Attribute.GROUND_ARTILLERY
|
||||||
elseif tank then
|
elseif tank then
|
||||||
@@ -3192,3 +3201,60 @@ function GROUP:IsAAA()
|
|||||||
end
|
end
|
||||||
return isAAA
|
return isAAA
|
||||||
end
|
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
|
||||||
|
|||||||
@@ -361,15 +361,17 @@ function POSITIONABLE:GetCoord()
|
|||||||
-- Get the current position.
|
-- Get the current position.
|
||||||
local PositionableVec3 = self:GetVec3()
|
local PositionableVec3 = self:GetVec3()
|
||||||
|
|
||||||
if self.coordinate then
|
if PositionableVec3 then
|
||||||
-- Update COORDINATE from 3D vector.
|
if self.coordinate then
|
||||||
self.coordinate:UpdateFromVec3( PositionableVec3 )
|
-- Update COORDINATE from 3D vector.
|
||||||
else
|
self.coordinate:UpdateFromVec3( PositionableVec3 )
|
||||||
-- New COORDINATE.
|
else
|
||||||
self.coordinate = COORDINATE:NewFromVec3( PositionableVec3 )
|
-- New COORDINATE.
|
||||||
end
|
self.coordinate = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||||
|
end
|
||||||
|
|
||||||
return self.coordinate
|
return self.coordinate
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Error message.
|
-- Error message.
|
||||||
@@ -1863,6 +1865,7 @@ do -- Cargo
|
|||||||
["HL_DSHK"] = 6*POSITIONABLE.DefaultInfantryWeight,
|
["HL_DSHK"] = 6*POSITIONABLE.DefaultInfantryWeight,
|
||||||
["CCKW_353"] = 16*POSITIONABLE.DefaultInfantryWeight, --GMC CCKW 2½-ton 6×6 truck, estimating 16 soldiers,
|
["CCKW_353"] = 16*POSITIONABLE.DefaultInfantryWeight, --GMC CCKW 2½-ton 6×6 truck, estimating 16 soldiers,
|
||||||
["MaxxPro_MRAP"] = 7*POSITIONABLE.DefaultInfantryWeight,
|
["MaxxPro_MRAP"] = 7*POSITIONABLE.DefaultInfantryWeight,
|
||||||
|
["Sd_Kfz_251"] = 10*POSITIONABLE.DefaultInfantryWeight,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -753,7 +753,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -773,7 +773,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -805,7 +805,7 @@ function STORAGE:LoadFromFile(Path,Filename)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -377,6 +377,10 @@ function UNIT:ReSpawnAt(Coordinate, Heading)
|
|||||||
|
|
||||||
--self:T( SpawnGroupTemplate )
|
--self:T( SpawnGroupTemplate )
|
||||||
|
|
||||||
|
if self.ValidateAndRepositionGroundUnits then
|
||||||
|
UTILS.ValidateAndRepositionGroundUnits(SpawnGroupTemplate.units)
|
||||||
|
end
|
||||||
|
|
||||||
_DATABASE:Spawn(SpawnGroupTemplate)
|
_DATABASE:Spawn(SpawnGroupTemplate)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1931,3 +1935,21 @@ end
|
|||||||
function UNIT:SetLife(Percent)
|
function UNIT:SetLife(Percent)
|
||||||
net.dostring_in("mission",string.format("a_unit_set_life_percentage(%d, %f)", self:GetID(), Percent))
|
net.dostring_in("mission",string.format("a_unit_set_life_percentage(%d, %f)", self:GetID(), Percent))
|
||||||
end
|
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