This commit is contained in:
nasgroup94 2025-10-25 12:39:54 -04:00
commit 2b2acbe244
10 changed files with 2426 additions and 1963 deletions

View File

@ -1934,6 +1934,21 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius, Offset)
return self
end
--- Updates the current location from a @{Wrapper.Group}.
-- @param #ZONE_UNIT self
-- @param Wrapper.Group#GROUP Group (optional) Update from this Unit, if nil, update from the UNIT this zone is based on.
-- @return self
function ZONE_UNIT:UpdateFromUnit(Unit)
if Unit and Unit:IsAlive() then
local vec2 = Unit:GetVec2()
self.LastVec2 = vec2
elseif self.ZoneUNIT and self.ZoneUNIT:IsAlive() then
local ZoneVec2 = self.ZoneUNIT:GetVec2()
self.LastVec2 = ZoneVec2
end
return self
end
--- Returns the current location of the @{Wrapper.Unit#UNIT}.
-- @param #ZONE_UNIT self
@ -2071,6 +2086,22 @@ function ZONE_GROUP:GetVec2()
return ZoneVec2
end
--- Updates the current location from a @{Wrapper.Group}.
-- @param #ZONE_GROUP self
-- @param Wrapper.Group#GROUP Group (optional) Update from this Group, if nil, update from the GROUP this zone is based on.
-- @return self
function ZONE_GROUP:UpdateFromGroup(Group)
if Group and Group:IsAlive() then
local vec2 = Group:GetVec2()
self.Vec2 = vec2
elseif self._.ZoneGROUP and self._.ZoneGROUP:IsAlive() then
local ZoneVec2 = self._.ZoneGROUP:GetVec2()
self.Vec2 = ZoneVec2
self._.ZoneVec2Cache = ZoneVec2
end
return self
end
--- Returns a random location within the zone of the @{Wrapper.Group}.
-- @param #ZONE_GROUP self
-- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location.

File diff suppressed because it is too large Load Diff

View File

@ -5498,15 +5498,15 @@ function AIRBOSS:_GetAircraftAoA( playerData )
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, 12.5 ) -- 11.67 --13.0 units -- VNAO Edit - Original value 13
elseif goshawk then -- These parameters tweaked by Circuit for new T45 flight model
elseif goshawk then
-- T-45C Goshawk parameters.
aoa.SLOW = 9.5 --8.00 -- 19
aoa.Slow = 9.25 --7.75 -- 18
aoa.OnSpeedMax = 9.0 --7.25 -- 17.5
aoa.OnSpeed = 8.5 --7.00 -- 17
aoa.OnSpeedMin = 8.25 --6.75 -- 16.5
aoa.Fast = 7.75 -- 6.25 -- 16
aoa.FAST = 7.5 -- 6.00 -- 15
aoa.SLOW = 8.00 -- 19
aoa.Slow = 7.75 -- 18
aoa.OnSpeedMax = 7.25 -- 17.5
aoa.OnSpeed = 7.00 -- 17
aoa.OnSpeedMin = 6.75 -- 16.5
aoa.Fast = 6.25 -- 16
aoa.FAST = 6.00 -- 15
elseif skyhawk then
-- 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!
@ -8150,11 +8150,7 @@ function AIRBOSS:_CheckPlayerStatus()
local playerData = _playerData -- #AIRBOSS.PlayerData
if playerData then
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET
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
-- Player unit.
local unit = playerData.unit
@ -8165,8 +8161,8 @@ function AIRBOSS:_CheckPlayerStatus()
-- TODO: This might cause problems if the CCA is set to be very small!
if unit:IsInZone( self.zoneCCA ) then
-- VNAO Edit - Added wrapped up call to LSO grading Hornet
if playerData.step==AIRBOSS.PatternStep.WAKE and hornet then-- VNAO Edit - Added
-- VNAO Edit - Added wrapped up call to LSO grading
if playerData.step==AIRBOSS.PatternStep.WAKE 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
@ -8182,32 +8178,6 @@ function AIRBOSS:_CheckPlayerStatus()
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
-- 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
@ -12260,7 +12230,7 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord )
-- 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 = self:GetHeadingIntoWind_old(vdeck) -- VNAO Edit: Using old heading into wind algorithm
local intowind = self:GetHeadingIntoWind_old(vdeck,magnetic) -- VNAO Edit: Using old heading into wind algorithm
return intowind, v
end

View File

@ -1150,11 +1150,11 @@ function CSAR:_EventHandler(EventData)
local initdcscoord = nil
local initcoord = nil
if _event.id == EVENTS.Ejection then
if _event.id == EVENTS.Ejection and _event.TgtDCSUnit then
initdcscoord = _event.TgtDCSUnit:getPoint()
initcoord = COORDINATE:NewFromVec3(initdcscoord)
self:T({initdcscoord})
else
elseif _event.IniDCSUnit then
initdcscoord = _event.IniDCSUnit:getPoint()
initcoord = COORDINATE:NewFromVec3(initdcscoord)
self:T({initdcscoord})

View File

@ -25,7 +25,7 @@
-- @module Ops.CTLD
-- @image OPS_CTLD.jpg
-- Last Update July 2025
-- Last Update Oct 2025
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -147,6 +147,7 @@ CTLD_CARGO = {
Location = ZONE:New(Location)
end
self.Location = Location
self.NoMoveToZone = false
return self
end
@ -783,6 +784,7 @@ do
-- 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".
-- 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:
-- my_ctld:AddCratesCargo("Forward Ops Base",{"FOB"},CTLD_CARGO.Enum.FOB,4)
@ -1556,6 +1558,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
self.smokedistance = 2000
self.movetroopstowpzone = true
self.movetroopsdistance = 5000
self.returntroopstobase = true -- if set to false, troops would stay after deployment inside a load zone.
self.troopdropzoneradius = 100
self.VehicleMoveFormation = AI.Task.VehicleFormation.VEE
@ -3676,7 +3679,7 @@ function CTLD:_UnloadTroops(Group, Unit)
inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP)
end
if inzone then
droppingatbase = true
droppingatbase = self.returntroopstobase
end
-- check for hover unload
local hoverunload = self:IsCorrectHover(Unit) --if true we\'re hovering in parameters
@ -4513,7 +4516,8 @@ function CTLD:_RefreshF10Menus()
end
for _,cargoObj in pairs(self.Cargo_Crates) do
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
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@ -4524,7 +4528,8 @@ function CTLD:_RefreshF10Menus()
end
for _,cargoObj in pairs(self.Cargo_Statics) do
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
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@ -4536,7 +4541,8 @@ function CTLD:_RefreshF10Menus()
else
for _,cargoObj in pairs(self.Cargo_Crates) do
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
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@ -4547,7 +4553,8 @@ function CTLD:_RefreshF10Menus()
end
for _,cargoObj in pairs(self.Cargo_Statics) do
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
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@ -4559,14 +4566,15 @@ function CTLD:_RefreshF10Menus()
end
end
else
if self.usesubcats then
if self.usesubcats == true then
local subcatmenus = {}
for catName, _ in pairs(self.subcats) do
subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) -- fixed variable case
end
for _, cargoObj in pairs(self.Cargo_Crates) do
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
local stock = cargoObj:GetStock()
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@ -4575,7 +4583,8 @@ function CTLD:_RefreshF10Menus()
end
for _, cargoObj in pairs(self.Cargo_Statics) do
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
local stock = cargoObj:GetStock()
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@ -4585,7 +4594,8 @@ function CTLD:_RefreshF10Menus()
else
for _, cargoObj in pairs(self.Cargo_Crates) do
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
local stock = cargoObj:GetStock()
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@ -4594,7 +4604,8 @@ function CTLD:_RefreshF10Menus()
end
for _, cargoObj in pairs(self.Cargo_Statics) do
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
local stock = cargoObj:GetStock()
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@ -5134,7 +5145,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.SHIP)
end
if inzone then
droppingatbase = true
droppingatbase = self.returntroopstobase
end
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
@ -5426,6 +5437,52 @@ function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,Sub
return self
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.
-- @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".
@ -5670,8 +5727,14 @@ function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Ship
return self
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.color = Color or SMOKECOLOR.Red
ctldzone.name = Name or "NONE"
@ -5697,11 +5760,56 @@ function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Ship
ctldzone.shiplength = Shiplength or 100
ctldzone.shipwidth = Shipwidth or 10
end
self:AddZone(ctldzone)
if not exists then
self:AddZone(ctldzone)
end
return self
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.
-- 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.
@ -7443,8 +7551,11 @@ end
-- @return #CTLD self
function CTLD:onafterCratesBuild(From, Event, To, Group, Unit, Vehicle)
self:T({From, Event, To})
if self.movetroopstowpzone then
self:_MoveGroupToZone(Vehicle)
if self.movetroopstowpzone and Vehicle then
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
return self
end

File diff suppressed because it is too large Load Diff

View File

@ -2330,6 +2330,16 @@ function UTILS.IsLoadingDoorOpen( unit_name )
return true
end
if type_name == "UH-60L_DAP" and (unit:getDrawArgumentValue(401) == 1 or unit:getDrawArgumentValue(402) == 1) then
BASE:T(unit_name .. " cargo door is open")
return true
end
if type_name == "UH-60L_DAP" and (unit:getDrawArgumentValue(38) > 0 or unit:getDrawArgumentValue(400) == 1 ) then
BASE:T(unit_name .. " front door(s) are open")
return true
end
if type_name == "AH-64D_BLK_II" then
BASE:T(unit_name .. " front door(s) are open")
return true -- no doors on this one ;)
@ -4127,6 +4137,45 @@ function UTILS.LCGRandom()
return UTILS.lcg.seed / UTILS.lcg.m
end
--- Create a table of grid-points for n points.
-- @param #number startVec2 Starting DCS#Vec2 map coordinate, e.g. `{x=63598575,y=-63598575}`
-- @param #number n Number of points to generate.
-- @param #number spacingX Horizonzal spacing (meters).
-- @param #number spacingY Vertical spacing (meters).
-- @return #table Grid Table of DCS#Vec2 entries.
function UTILS.GenerateGridPoints(startVec2, n, spacingX, spacingY)
local points = {}
local gridSize = math.ceil(math.sqrt(n))
local count = 0
local n = n or 1
local spacingX = spacingX or 100
local spacingY = spacingY or 100
local startX = startVec2.x or 100
local startY = startVec2.y or 100
for row = 0, gridSize - 1 do
for col = 0, gridSize - 1 do
if count >= n then
break
end
local point = {
x = startX + (col * spacingX),
y = startY + (row * spacingY)
}
table.insert(points, point)
count = count + 1
end
if count >= n then
break
end
end
return points
end
--- Spawns a new FARP of a defined type and coalition and functional statics (fuel depot, ammo storage, tent, windsock) around that FARP to make it operational.
-- Adds vehicles from template if given. Fills the FARP warehouse with liquids and known materiels.
-- References: [DCS Forum Topic](https://forum.dcs.world/topic/282989-farp-equipment-to-run-it)
@ -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 #boolean DynamicSpawns If true, allow Dynamic Spawns from this FARP.
-- @param #boolean HotStart If true and DynamicSpawns is true, allow hot starts for Dynamic Spawns from this FARP.
-- @param #number NumberPads If given, spawn this number of pads.
-- @param #number SpacingX For NumberPads > 1, space this many meters horizontally. Defaults to 100.
-- @param #number SpacingY For NumberPads > 1, space this many meters vertically. Defaults to 100.
-- @return #list<Wrapper.Static#STATIC> Table of spawned objects and vehicle object (if given).
-- @return #string ADFBeaconName Name of the ADF beacon, to be able to remove/stop it later.
-- @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
local farplocation = Coordinate
@ -4171,12 +4248,84 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
local Country = Country or (Coalition == coalition.side.BLUE and country.id.USA or country.id.RUSSIA)
local ReturnObjects = {}
-- Spawn FARP
local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP"
newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS"
newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart)
local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name)
table.insert(ReturnObjects,spawnedfarp)
-- many FARPs
local NumberPads = NumberPads or 1
local SpacingX = SpacingX or 100
local SpacingY = SpacingY or 100
local FarpVec2 = Coordinate:GetVec2()
if NumberPads > 1 then
local Grid = UTILS.GenerateGridPoints(FarpVec2, NumberPads, SpacingX, SpacingY)
local groupData = {
["visible"] = true,
["hidden"] = false,
["units"] = {},
["y"] = 0, -- Group center latitude
["x"] = 0, -- Group center longitude
["name"] = Name,
}
local unitData = {
["category"] = "Heliports",
["type"] = STypeName, -- FARP type
["y"] = 0, -- Latitude coordinate (meters)
["x"] = 0, -- Longitude coordinate (meters)
["name"] = Name,
["heading"] = 0, -- Heading in radians
["heliport_modulation"] = mod, -- 0 = AM, 1 = FM
["heliport_frequency"] = freq, -- Radio frequency in MHz
["heliport_callsign_id"] = callsign, -- Callsign ID
["dead"] = false,
["shape_name"] = SShapeName,
["dynamicSpawn"] = DynamicSpawns,
["allowHotStart"] = HotStart,
}
for id,gridpoint in ipairs(Grid) do
-- Spawn FARP
--[[
local location = COORDINATE:NewFromVec2(gridpoint)
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(location,0,Name.."-"..id)
table.insert(ReturnObjects,spawnedfarp)
PopulateStorage(Name.."-"..id,liquids,equip,airframes)
--]]
local UnitTemplate = UTILS.DeepCopy(unitData)
UnitTemplate.x = gridpoint.x
UnitTemplate.y = gridpoint.y
UnitTemplate.name = Name.."-"..id
table.insert(groupData.units,UnitTemplate)
if id==1 then
groupData.x = gridpoint.x
groupData.y = gridpoint.y
end
end
--BASE:I("Spawning FARP")
--UTILS.PrintTableToLog(groupData,1)
local Static=coalition.addGroup(Country, -1, groupData)
-- Currently DCS >= 2.8 does not trigger birth events if FARPS are spawned!
-- We create such an event. The airbase is registered in Core.Event
local Event = {
id = EVENTS.Birth,
time = timer.getTime(),
initiator = Static
}
-- Create BIRTH event.
world.onEvent(Event)
PopulateStorage(Name.."-1",liquids,equip,airframes)
else
-- Spawn FARP
local newfarp = SPAWNSTATIC:NewFromType(STypeName,"Heliports",Country) -- "Invisible FARP" "FARP"
newfarp:InitShape(SShapeName) -- "invisiblefarp" "FARPS"
newfarp:InitFARP(callsign,freq,mod,DynamicSpawns,HotStart)
local spawnedfarp = newfarp:SpawnFromCoordinate(farplocation,0,Name)
table.insert(ReturnObjects,spawnedfarp)
PopulateStorage(Name,liquids,equip,airframes)
end
-- Spawn Objects
local FARPStaticObjectsNato = {
["FUEL"] = { TypeName = "FARP Fuel Depot", ShapeName = "GSM Rus", Category = "Fortifications"},
@ -4210,29 +4359,6 @@ function UTILS.SpawnFARPAndFunctionalStatics(Name,Coordinate,FARPType,Coalition,
table.insert(ReturnObjects,spawnedvehicle)
end
local newWH = STORAGE:New(Name)
if liquids and liquids > 0 then
-- Storage fill-up
newWH:SetLiquid(STORAGE.Liquid.DIESEL,liquids) -- kgs to tons
newWH:SetLiquid(STORAGE.Liquid.GASOLINE,liquids)
newWH:SetLiquid(STORAGE.Liquid.JETFUEL,liquids)
newWH:SetLiquid(STORAGE.Liquid.MW50,liquids)
end
if equip and equip > 0 then
for cat,nitem in pairs(ENUMS.Storage.weapons) do
for name,item in pairs(nitem) do
newWH:SetItem(item,equip)
end
end
end
if airframes and airframes > 0 then
for typename in pairs (CSAR.AircraftType) do
newWH:SetItem(typename,airframes)
end
end
local ADFName
if ADF and type(ADF) == "number" then
local ADFFreq = ADF*1000 -- KHz to Hz

View File

@ -1574,6 +1574,17 @@ end
return self
end
--- Get the true airbase center as seen in the ME. The position returned by the dcs object is is wrong and often at the start of the runway.
-- @return DCS#Vec2 The center of the true center of the airbase if it contains runways, otherwise the default DCS object position.
function AIRBASE:GetVec2()
local runways = self:GetRunways()
if runways and #runways > 0 then
return runways[1].center:GetVec2()
end
return self:GetCoordinate():GetVec2()
end
--- Get the category of this airbase. This is only a debug function because DCS 2.9 incorrectly returns heliports as airdromes.
-- @param #AIRBASE self
function AIRBASE:_GetCategory()

View File

@ -4163,7 +4163,7 @@ function CONTROLLABLE:OptionRestrictBurner( RestrictBurner )
end
--- Sets Controllable Option for A2A attack range for AIR FIGHTER units.
--- [AIR] Sets Controllable Option for A2A attack range for AIR FIGHTER units.
-- @param #CONTROLLABLE self
-- @param #number range Defines the range
-- @return #CONTROLLABLE self
@ -4188,6 +4188,66 @@ function CONTROLLABLE:OptionAAAttackRange( range )
return nil
end
--- [GROUND/AAA] Sets Controllable Option for Ground AAA minimum firing height.
-- @param #CONTROLLABLE self
-- @param #number meters The minimum height in meters.
-- @return #CONTROLLABLE self
function CONTROLLABLE:OptionAAAMinFiringHeightMeters(meters)
self:F2( { self.ControllableName } )
local meters = meters or 20
local DCSControllable = self:GetDCSObject()
if DCSControllable then
local Controller = self:_GetController()
if Controller then
if self:IsGround() then
self:SetOption(27, meters)
end
end
return self
end
return nil
end
--- [GROUND/AAA] Sets Controllable Option for Ground AAA maximum firing height.
-- @param #CONTROLLABLE self
-- @param #number meters The maximum height in meters.
-- @return #CONTROLLABLE self
function CONTROLLABLE:OptionAAAMaxFiringHeightMeters(meters)
self:F2( { self.ControllableName } )
local meters = meters or 1000
local DCSControllable = self:GetDCSObject()
if DCSControllable then
local Controller = self:_GetController()
if Controller then
if self:IsGround() then
self:SetOption(29, meters)
end
end
return self
end
return nil
end
--- [GROUND/AAA] Sets Controllable Option for Ground AAA minimum firing height.
-- @param #CONTROLLABLE self
-- @param #number feet The minimum height in feet.
-- @return #CONTROLLABLE self
function CONTROLLABLE:OptionAAAMinFiringHeightFeet(feet)
self:F2( { self.ControllableName } )
local feet = feet or 60
return self:OptionAAAMinFiringHeightMeters(UTILS.FeetToMeters(feet))
end
--- [GROUND/AAA] Sets Controllable Option for Ground AAA maximum firing height.
-- @param #CONTROLLABLE self
-- @param #number feet The maximum height in feet.
-- @return #CONTROLLABLE self
function CONTROLLABLE:OptionAAAMaxFiringHeightfeet(feet)
self:F2( { self.ControllableName } )
local feet = feet or 3000
return self:OptionAAAMaxFiringHeightMeters(UTILS.FeetToMeters(feet))
end
--- Defines the range at which a GROUND unit/group is allowed to use its weapons automatically.
-- @param #CONTROLLABLE self
-- @param #number EngageRange Engage range limit in percent (a number between 0 and 100). Default 100.

View File

@ -108,6 +108,8 @@ DYNAMICCARGO.State = {
-- @type DYNAMICCARGO.AircraftTypes
DYNAMICCARGO.AircraftTypes = {
["CH-47Fbl1"] = "CH-47Fbl1",
["Mi-8MTV2"] = "CH-47Fbl1",
["Mi-8MT"] = "CH-47Fbl1",
}
--- Helo types possible.
@ -120,17 +122,30 @@ DYNAMICCARGO.AircraftDimensions = {
["length"] = 11,
["ropelength"] = 30,
},
["Mi-8MTV2"] = {
["width"] = 6,
["height"] = 6,
["length"] = 15,
["ropelength"] = 30,
},
["Mi-8MT"] = {
["width"] = 6,
["height"] = 6,
["length"] = 15,
["ropelength"] = 30,
},
}
--- DYNAMICCARGO class version.
-- @field #string version
DYNAMICCARGO.version="0.0.7"
DYNAMICCARGO.version="0.0.9"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot...
-- DONE: Added Mi-8 type and dimensions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor