Merge pull request #1627 from FlightControl-Master/FF/Ops

Ff/ops
This commit is contained in:
Frank
2021-11-14 23:31:03 +01:00
committed by GitHub
42 changed files with 24481 additions and 5959 deletions

View File

@@ -142,7 +142,7 @@ AIRBASE.Caucasus = {
-- * AIRBASE.Nevada.Pahute_Mesa_Airstrip
-- * AIRBASE.Nevada.Tonopah_Airport
-- * AIRBASE.Nevada.Tonopah_Test_Range_Airfield
--
--
-- @field Nevada
AIRBASE.Nevada = {
["Creech_AFB"] = "Creech AFB",
@@ -197,7 +197,7 @@ AIRBASE.Nevada = {
-- * AIRBASE.Normandy.Funtington
-- * AIRBASE.Normandy.Tangmere
-- * AIRBASE.Normandy.Ford_AF
--
--
-- @field Normandy
AIRBASE.Normandy = {
["Saint_Pierre_du_Mont"] = "Saint Pierre du Mont",
@@ -271,7 +271,7 @@ AIRBASE.Normandy = {
-- * AIRBASE.PersianGulf.Sirri_Island
-- * AIRBASE.PersianGulf.Tunb_Island_AFB
-- * AIRBASE.PersianGulf.Tunb_Kochak
--
--
-- @field PersianGulf
AIRBASE.PersianGulf = {
["Abu_Dhabi_International_Airport"] = "Abu Dhabi Intl",
@@ -473,6 +473,13 @@ AIRBASE.MarianaIslands={
-- @field #boolean Free This spot is currently free, i.e. there is no alive aircraft on it at the present moment.
-- @field #number TerminalID0 Unknown what this means. If you know, please tell us!
-- @field #number DistToRwy Distance to runway in meters. Currently bugged and giving the same number as the TerminalID.
-- @field #string AirbaseName Name of the airbase.
-- @field #number MarkerID Numerical ID of marker placed at parking spot.
-- @field Wrapper.Marker#MARKER Marker The marker on the F10 map.
-- @field #string ClientSpot Client unit sitting at this spot or *nil*.
-- @field #string Status Status of spot e.g. AIRBASE.SpotStatus.FREE.
-- @field #string OccupiedBy Name of the aircraft occupying the spot or "unknown". Can be *nil* if spot is not occupied.
-- @field #string ReservedBy Name of the aircraft for which this spot is reserved. Can be *nil* if spot is not reserved.
--- Terminal Types of parking spots. See also https://wiki.hoggitworld.com/view/DCS_func_getParking
--
@@ -507,6 +514,17 @@ AIRBASE.TerminalType = {
FighterAircraft=244,
}
--- Status of a parking spot.
-- @type AIRBASE.SpotStatus
-- @field #string FREE Spot is free.
-- @field #string OCCUPIED Spot is occupied.
-- @field #string RESERVED Spot is reserved.
AIRBASE.SpotStatus = {
FREE="Free",
OCCUPIED="Occupied",
RESERVED="Reserved",
}
--- Runway data.
-- @type AIRBASE.Runway
-- @field #number heading Heading of the runway in degrees.
@@ -537,6 +555,9 @@ function AIRBASE:Register(AirbaseName)
-- Get descriptors.
self.descriptors=self:GetDesc()
-- Debug info.
--self:I({airbase=AirbaseName, descriptors=self.descriptors})
-- Category.
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
@@ -553,13 +574,15 @@ function AIRBASE:Register(AirbaseName)
self.isShip=false
self.category=Airbase.Category.HELIPAD
_DATABASE:AddStatic(AirbaseName)
end
end
else
self:E("ERROR: Unknown airbase category!")
end
-- Init parking spots.
self:_InitParkingSpots()
-- Get 2D position vector.
local vec2=self:GetVec2()
-- Init coordinate.
@@ -1024,6 +1047,8 @@ function AIRBASE:GetParkingSpotsTable(termtype)
spot.Free=_isfree(_spot) -- updated
spot.TOAC=_spot.TO_AC -- updated
spot.AirbaseName=self.AirbaseName
spot.ClientSpot=nil --TODO
table.insert(spots, spot)
@@ -1060,6 +1085,8 @@ function AIRBASE:GetFreeParkingSpotsTable(termtype, allowTOAC)
spot.Free=true -- updated
spot.TOAC=_spot.TO_AC -- updated
spot.AirbaseName=self.AirbaseName
spot.ClientSpot=nil --TODO
table.insert(freespots, spot)
@@ -1141,7 +1168,7 @@ end
-- @param #table parkingdata (Optional) Parking spots data table. If not given it is automatically derived from the GetParkingSpotsTable() function.
-- @return #table Table of coordinates and terminal IDs of free parking spots. Each table entry has the elements .Coordinate and .TerminalID.
function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nspots, parkingdata)
-- Init default
scanradius=scanradius or 50
if scanunits==nil then
@@ -1197,7 +1224,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
az = 17 -- width
end
-- Number of spots we are looking for. Note that, e.g. grouping can require a number different from the group size!
local _nspots=nspots or group:GetSize()
@@ -1325,7 +1352,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
-- Retrun spots we found, even if there were not enough.
return validspots
end
--- Check black and white lists.
@@ -1344,7 +1371,7 @@ function AIRBASE:_CheckParkingLists(TerminalID)
end
end
-- Check if a whitelist was defined.
if self.parkingWhitelist and #self.parkingWhitelist>0 then
for _,terminalID in pairs(self.parkingWhitelist or {}) do
@@ -1454,7 +1481,7 @@ function AIRBASE:GetRunwayData(magvar, mark)
name==AIRBASE.PersianGulf.Abu_Dhabi_International_Airport or
name==AIRBASE.PersianGulf.Dubai_Intl or
name==AIRBASE.PersianGulf.Shiraz_International_Airport or
name==AIRBASE.PersianGulf.Kish_International_Airport or
name==AIRBASE.PersianGulf.Kish_International_Airport or
name==AIRBASE.MarianaIslands.Andersen_AFB then
-- 1-->4, 2-->3, 3-->2, 4-->1

View File

@@ -1407,7 +1407,7 @@ function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, E
DCSTask = {
id = 'Escort',
params = {
groupId = FollowControllable:GetID(),
groupId = FollowControllable and FollowControllable:GetID() or nil,
pos = Vec3,
lastWptIndexFlag = LastWaypointIndex and true or false,
lastWptIndex = LastWaypointIndex,
@@ -1437,11 +1437,11 @@ function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType, Alti
id = 'FireAtPoint',
params = {
point = Vec2,
x=Vec2.x,
y=Vec2.y,
x = Vec2.x,
y = Vec2.y,
zoneRadius = Radius,
radius = Radius,
expendQty = 100, -- dummy value
expendQty = 1, -- dummy value
expendQtyEnabled = false,
alt_type = ASL and 0 or 1
}
@@ -1460,7 +1460,8 @@ function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType, Alti
DCSTask.params.weaponType=WeaponType
end
--self:I(DCSTask)
--env.info("FF fireatpoint")
--BASE:I(DCSTask)
return DCSTask
end
@@ -2022,22 +2023,20 @@ do -- Patrol methods
end
--- Return a Misson task to follow a given route defined by Points.
--- Return a "Misson" task to follow a given route defined by Points.
-- @param #CONTROLLABLE self
-- @param #table Points A table of route points.
-- @return DCS#Task
-- @return DCS#Task DCS mission task. Has entries `.id="Mission"`, `params`, were params has entries `airborne` and `route`, which is a table of `points`.
function CONTROLLABLE:TaskRoute( Points )
self:F2( Points )
local DCSTask = {
id = 'Mission',
params = {
airborne = self:IsAir(),
airborne = self:IsAir(), -- This is important to make aircraft land without respawning them (which was a long standing DCS issue).
route = {points = Points},
},
}
self:T3( { DCSTask } )
return DCSTask
end

View File

@@ -310,8 +310,7 @@ end
--- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return DCS#Position The 3D position vectors of the POSITIONABLE.
-- @return #nil The POSITIONABLE is not existing or alive.
-- @return DCS#Position The 3D position vectors of the POSITIONABLE or #nil if the groups not existing or alive.
function GROUP:GetPositionVec3() -- Overridden from POSITIONABLE:GetPositionVec3()
self:F2( self.PositionableName )
@@ -339,9 +338,7 @@ end
-- If the first @{Wrapper.Unit} of the group is inactive, it will return false.
--
-- @param #GROUP self
-- @return #boolean true if the group is alive and active.
-- @return #boolean false if the group is alive but inactive.
-- @return #nil if the group does not exist anymore.
-- @return #boolean `true` if the group is alive *and* active, `false` if the group is alive but inactive or `#nil` if the group does not exist anymore.
function GROUP:IsAlive()
self:F2( self.GroupName )
@@ -363,8 +360,7 @@ end
--- Returns if the group is activated.
-- @param #GROUP self
-- @return #boolean true if group is activated.
-- @return #nil The group is not existing or alive.
-- @return #boolean `true` if group is activated or `#nil` The group is not existing or alive.
function GROUP:IsActive()
self:F2( self.GroupName )
@@ -412,7 +408,6 @@ function GROUP:Destroy( GenerateEvent, delay )
self:F2( self.GroupName )
if delay and delay>0 then
--SCHEDULER:New(nil, GROUP.Destroy, {self, GenerateEvent}, delay)
self:ScheduleOnce(delay, GROUP.Destroy, self, GenerateEvent)
else

View File

@@ -56,8 +56,7 @@ end
-- If the Identifiable is not alive, nil is returned.
-- If the Identifiable is alive, true is returned.
-- @param #IDENTIFIABLE self
-- @return #boolean true if Identifiable is alive.
-- @return #nil if the Identifiable is not existing or is not alive.
-- @return #boolean true if Identifiable is alive or `#nil` if the Identifiable is not existing or is not alive.
function IDENTIFIABLE:IsAlive()
self:F3( self.IdentifiableName )
@@ -77,11 +76,8 @@ end
--- Returns DCS Identifiable object name.
-- The function provides access to non-activated objects too.
-- @param #IDENTIFIABLE self
-- @return #string The name of the DCS Identifiable.
-- @return #nil The DCS Identifiable is not existing or alive.
-- @return #string The name of the DCS Identifiable or `#nil`.
function IDENTIFIABLE:GetName()
self:F2( self.IdentifiableName )
local IdentifiableName = self.IdentifiableName
return IdentifiableName
end
@@ -148,8 +144,7 @@ end
--- Returns coalition of the Identifiable.
-- @param #IDENTIFIABLE self
-- @return DCS#coalition.side The side of the coalition.
-- @return #nil The DCS Identifiable is not existing or alive.
-- @return DCS#coalition.side The side of the coalition or `#nil` The DCS Identifiable is not existing or alive.
function IDENTIFIABLE:GetCoalition()
self:F2( self.IdentifiableName )
@@ -190,8 +185,7 @@ end
--- Returns country of the Identifiable.
-- @param #IDENTIFIABLE self
-- @return DCS#country.id The country identifier.
-- @return #nil The DCS Identifiable is not existing or alive.
-- @return DCS#country.id The country identifier or `#nil` The DCS Identifiable is not existing or alive.
function IDENTIFIABLE:GetCountry()
self:F2( self.IdentifiableName )
@@ -222,8 +216,7 @@ end
--- Returns Identifiable descriptor. Descriptor type depends on Identifiable category.
-- @param #IDENTIFIABLE self
-- @return DCS#Object.Desc The Identifiable descriptor.
-- @return #nil The DCS Identifiable is not existing or alive.
-- @return DCS#Object.Desc The Identifiable descriptor or `#nil` The DCS Identifiable is not existing or alive.
function IDENTIFIABLE:GetDesc()
self:F2( self.IdentifiableName )
@@ -242,8 +235,7 @@ end
--- Check if the Object has the attribute.
-- @param #IDENTIFIABLE self
-- @param #string AttributeName The attribute name.
-- @return #boolean true if the attribute exists.
-- @return #nil The DCS Identifiable is not existing or alive.
-- @return #boolean true if the attribute exists or `#nil` The DCS Identifiable is not existing or alive.
function IDENTIFIABLE:HasAttribute( AttributeName )
self:F2( self.IdentifiableName )
@@ -266,8 +258,10 @@ function IDENTIFIABLE:GetCallsign()
return ''
end
--- Gets the threat level.
-- @param #IDENTIFIABLE self
-- @return #number Threat level.
-- @return #string Type.
function IDENTIFIABLE:GetThreatLevel()
return 0, "Scenery"
end

View File

@@ -1368,8 +1368,6 @@ do -- Cargo
return self.__.Cargo
end
--- Remove cargo.
-- @param #POSITIONABLE self
-- @param Core.Cargo#CARGO Cargo
@@ -1414,17 +1412,15 @@ do -- Cargo
return ItemCount
end
-- --- Get Cargo Bay Free Volume in m3.
-- -- @param #POSITIONABLE self
-- -- @return #number CargoBayFreeVolume
-- function POSITIONABLE:GetCargoBayFreeVolume()
-- local CargoVolume = 0
-- for CargoName, Cargo in pairs( self.__.Cargo ) do
-- CargoVolume = CargoVolume + Cargo:GetVolume()
-- end
-- return self.__.CargoBayVolumeLimit - CargoVolume
-- end
--
--- Get the number of infantry soldiers that can be embarked into an aircraft (airplane or helicopter).
-- Returns `nil` for ground or ship units.
-- @param #POSITIONABLE self
-- @return #number Descent number of soldiers that fit into the unit. Returns `#nil` for ground and ship units.
function POSITIONABLE:GetTroopCapacity()
local DCSunit=self:GetDCSObject() --DCS#Unit
local capacity=DCSunit:getDescentCapacity()
return capacity
end
--- Get Cargo Bay Free Weight in kg.
-- @param #POSITIONABLE self
@@ -1443,55 +1439,97 @@ do -- Cargo
return self.__.CargoBayWeightLimit - CargoWeight
end
-- --- Get Cargo Bay Volume Limit in m3.
-- -- @param #POSITIONABLE self
-- -- @param #number VolumeLimit
-- function POSITIONABLE:SetCargoBayVolumeLimit( VolumeLimit )
-- self.__.CargoBayVolumeLimit = VolumeLimit
-- end
--- Set Cargo Bay Weight Limit in kg.
-- @param #POSITIONABLE self
-- @param #number WeightLimit
-- @param #number WeightLimit (Optional) Weight limit in kg. If not given, the value is taken from the descriptors or hard coded.
function POSITIONABLE:SetCargoBayWeightLimit( WeightLimit )
if WeightLimit then
if WeightLimit then
---
-- User defined value
---
self.__.CargoBayWeightLimit = WeightLimit
elseif self.__.CargoBayWeightLimit~=nil then
-- Value already set ==> Do nothing!
else
-- If weightlimit is not provided, we will calculate it depending on the type of unit.
---
-- Weightlimit is not provided, we will calculate it depending on the type of unit.
---
-- Descriptors that contain the type name and for aircraft also weights.
local Desc = self:GetDesc()
self:F({Desc=Desc})
-- Unit type name.
local TypeName=Desc.typeName or "Unknown Type"
-- When an airplane or helicopter, we calculate the weightlimit based on the descriptor.
if self:IsAir() then
local Desc = self:GetDesc()
self:F({Desc=Desc})
-- Max takeoff weight if DCS descriptors have unrealstic values.
local Weights = {
["C-17A"] = 35000, --77519 cannot be used, because it loads way too much apcs and infantry.,
["C-130"] = 22000 --The real value cannot be used, because it loads way too much apcs and infantry.,
-- C-17A
-- Wiki says: max=265,352, empty=128,140, payload=77,516 (134 troops, 1 M1 Abrams tank, 2 M2 Bradley or 3 Stryker)
-- DCS says: max=265,350, empty=125,645, fuel=132,405 ==> Cargo Bay=7300 kg with a full fuel load (lot of fuel!) and 73300 with half a fuel load.
--["C-17A"] = 35000, --77519 cannot be used, because it loads way too much apcs and infantry.
-- C-130:
-- DCS says: max=79,380, empty=36,400, fuel=10,415 kg ==> Cargo Bay=32,565 kg with fuel load.
-- Wiki says: max=70,307, empty=34,382, payload=19,000 kg (92 passengers, 2-3 Humvees or 2 M113s), max takeoff weight 70,037 kg.
-- Here we say two M113s should be transported. Each one weights 11,253 kg according to DCS. So the cargo weight should be 23,000 kg with a full load of fuel.
-- This results in a max takeoff weight of 69,815 kg (23,000+10,415+36,400), which is very close to the Wiki value of 70,037 kg.
["C-130"] = 70000,
}
self.__.CargoBayWeightLimit = Weights[Desc.typeName] or ( Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) )
-- Max (takeoff) weight (empty+fuel+cargo weight).
local massMax= Desc.massMax or 0
-- Adjust value if set above.
local maxTakeoff=Weights[TypeName]
if maxTakeoff then
massMax=maxTakeoff
end
-- Empty weight.
local massEmpty=Desc.massEmpty or 0
-- Fuel. The descriptor provides the max fuel mass in kg. This needs to be multiplied by the relative fuel amount to calculate the actual fuel mass on board.
local massFuelMax=Desc.fuelMassMax or 0
local relFuel=math.max(self:GetFuel() or 1.0, 1.0) -- We take 1.0 as max in case of external fuel tanks.
local massFuel=massFuelMax*relFuel
-- Number of soldiers according to DCS function
--local troopcapacity=self:GetTroopCapacity() or 0
-- Calculate max cargo weight, which is the max (takeoff) weight minus the empty weight minus the actual fuel weight.
local CargoWeight=massMax-(massEmpty+massFuel)
-- Debug info.
self:T(string.format("Setting Cargo bay weight limit [%s]=%d kg (Mass max=%d, empty=%d, fuelMax=%d kg (rel=%.3f), fuel=%d kg", TypeName, CargoWeight, massMax, massEmpty, massFuelMax, relFuel, massFuel))
--self:T(string.format("Descent Troop Capacity=%d ==> %d kg (for 95 kg soldier)", troopcapacity, troopcapacity*95))
-- Set value.
self.__.CargoBayWeightLimit = CargoWeight
elseif self:IsShip() then
local Desc = self:GetDesc()
self:F({Desc=Desc})
-- Hard coded cargo weights in kg.
local Weights = {
["Type_071"] = 245000,
["LHA_Tarawa"] = 500000,
["Ropucha-class"] = 150000,
["Dry-cargo ship-1"] = 70000,
["Dry-cargo ship-2"] = 70000,
["Higgins_boat"] = 3700, -- Higgins Boat can load 3700 kg of general cargo or 36 men (source wikipedia).
["USS_Samuel_Chase"] = 25000, -- Let's say 25 tons for now. Wiki says 33 Higgins boats, which would be 264 tons (can't be right!) and/or 578 troops.
["LST_Mk2"] =2100000, -- Can carry 2100 tons according to wiki source!
["Type_071"] = 245000,
["LHA_Tarawa"] = 500000,
["Ropucha-class"] = 150000,
["Dry-cargo ship-1"] = 70000,
["Dry-cargo ship-2"] = 70000,
["Higgins_boat"] = 3700, -- Higgins Boat can load 3700 kg of general cargo or 36 men (source wikipedia).
["USS_Samuel_Chase"] = 25000, -- Let's say 25 tons for now. Wiki says 33 Higgins boats, which would be 264 tons (can't be right!) and/or 578 troops.
["LST_Mk2"] = 2100000, -- Can carry 2100 tons according to wiki source!
["speedboat"] = 500, -- 500 kg ~ 5 persons
["Seawise_Giant"] =261000000, -- Gross tonnage is 261,000 tonns.
}
self.__.CargoBayWeightLimit = ( Weights[Desc.typeName] or 50000 )
self.__.CargoBayWeightLimit = ( Weights[TypeName] or 50000 )
else
local Desc = self:GetDesc()
-- Hard coded number of soldiers.
local Weights = {
["AAV7"] = 25,
["Bedford_MWD"] = 8, -- new by kappa
@@ -1537,12 +1575,28 @@ do -- Cargo
["VAB_Mephisto"] = 8, -- new by Apple
}
local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 95
-- Assuming that each passenger weighs 95 kg on average.
local CargoBayWeightLimit = ( Weights[TypeName] or 0 ) * 95
self.__.CargoBayWeightLimit = CargoBayWeightLimit
end
end
self:F({CargoBayWeightLimit = self.__.CargoBayWeightLimit})
end
--- Get Cargo Bay Weight Limit in kg.
-- @param #POSITIONABLE self
-- @return #number Max cargo weight in kg.
function POSITIONABLE:GetCargoBayWeightLimit()
if self.__.CargoBayWeightLimit==nil then
self:SetCargoBayWeightLimit()
end
return self.__.CargoBayWeightLimit
end
end --- Cargo
--- Signal a flare at the position of the POSITIONABLE.

View File

@@ -524,6 +524,63 @@ function UNIT:IsTanker()
return tanker, system
end
--- Check if the unit can supply ammo. Currently, we have
--
-- * M 818
-- * Ural-375
-- * ZIL-135
--
-- This list needs to be extended, if DCS adds other units capable of supplying ammo.
--
-- @param #UNIT self
-- @return #boolean If `true`, unit can supply ammo.
function UNIT:IsAmmoSupply()
-- Type name is the only thing we can check. There is no attribute (Sep. 2021) which would tell us.
local typename=self:GetTypeName()
if typename=="M 818" then
-- Blue ammo truck.
return true
elseif typename=="Ural-375" then
-- Red ammo truck.
return true
elseif typename=="ZIL-135" then
-- Red ammo truck. Checked that it can also provide ammo.
return true
end
return false
end
--- Check if the unit can supply fuel. Currently, we have
--
-- * M978 HEMTT Tanker
-- * ATMZ-5
-- * ATMZ-10
-- * ATZ-5
--
-- This list needs to be extended, if DCS adds other units capable of supplying fuel.
--
-- @param #UNIT self
-- @return #boolean If `true`, unit can supply fuel.
function UNIT:IsFuelSupply()
-- Type name is the only thing we can check. There is no attribute (Sep. 2021) which would tell us.
local typename=self:GetTypeName()
if typename=="M978 HEMTT Tanker" then
return true
elseif typename=="ATMZ-5" then
return true
elseif typename=="ATMZ-10" then
return true
elseif typename=="ATZ-5" then
return true
end
return false
end
--- Returns the unit's group if it exist and nil otherwise.
-- @param Wrapper.Unit#UNIT self
@@ -999,7 +1056,7 @@ function UNIT:GetThreatLevel()
elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and
not Attributes["ATGM"] then ThreatLevel = 3
elseif Attributes["Old Tanks"] or Attributes["APC"] or Attributes["Artillery"] then ThreatLevel = 2
elseif Attributes["Infantry"] then ThreatLevel = 1
elseif Attributes["Infantry"] or Attributes["EWR"] then ThreatLevel = 1
end
ThreatText = ThreatLevels[ThreatLevel+1]