Merge branch 'master' into develop

This commit is contained in:
Frank
2020-08-30 17:15:31 +02:00
23 changed files with 3089 additions and 2215 deletions
+352 -182
View File
@@ -15,6 +15,15 @@
--- @type AIRBASE
-- @field #string ClassName Name of the class, i.e. "AIRBASE".
-- @field #table CategoryName Names of airbase categories.
-- @field #string AirbaseName Name of the airbase.
-- @field #number AirbaseID Airbase ID.
-- @field #number category Airbase category.
-- @field #table descriptors DCS descriptors.
-- @field #boolean isAirdrome Airbase is an airdrome.
-- @field #boolean isHelipad Airbase is a helipad.
-- @field #boolean isShip Airbase is a ship.
-- @field #table parking Parking spot data.
-- @field #table parkingByID Parking spot data table with ID as key.
-- @field #number activerwyno Active runway number (forced).
-- @extends Wrapper.Positionable#POSITIONABLE
@@ -440,20 +449,52 @@ AIRBASE.TerminalType = {
-- @field Core.Point#COORDINATE position Position of runway start.
-- @field Core.Point#COORDINATE endpoint End point of runway.
-- Registration.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Registration
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new AIRBASE from DCSAirbase.
-- @param #AIRBASE self
-- @param #string AirbaseName The name of the airbase.
-- @return Wrapper.Airbase#AIRBASE
function AIRBASE:Register( AirbaseName )
-- @return #AIRBASE self
function AIRBASE:Register(AirbaseName)
-- Inherit everything from positionable.
local self=BASE:Inherit(self, POSITIONABLE:New(AirbaseName)) --#AIRBASE
-- Set airbase name.
self.AirbaseName=AirbaseName
-- Set airbase ID.
self.AirbaseID=self:GetID(true)
-- Get descriptors.
self.descriptors=self:GetDesc()
-- Category.
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
-- Set category.
if self.category==Airbase.Category.AIRDROME then
self.isAirdrome=true
elseif self.category==Airbase.Category.HELIPAD then
self.isHelipad=true
elseif self.category==Airbase.Category.SHIP then
self.isShip=true
else
self:E("ERROR: Unknown airbase category!")
end
self:_InitParkingSpots()
local self = BASE:Inherit( self, POSITIONABLE:New( AirbaseName ) ) --#AIRBASE
self.AirbaseName = AirbaseName
self.AirbaseID = self:GetID(true)
local vec2=self:GetVec2()
-- Init coordinate.
self:GetCoordinate()
if vec2 then
self.AirbaseZone = ZONE_RADIUS:New( AirbaseName, vec2, 2500 )
-- TODO: For ships we need a moving zone.
self.AirbaseZone=ZONE_RADIUS:New( AirbaseName, vec2, 2500 )
else
self:E(string.format("ERROR: Cound not get position Vec2 of airbase %s", AirbaseName))
end
@@ -461,7 +502,9 @@ function AIRBASE:Register( AirbaseName )
return self
end
-- Reference methods.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Reference methods
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Finds a AIRBASE from the _DATABASE using a DCSAirbase object.
-- @param #AIRBASE self
@@ -508,7 +551,9 @@ end
-- @param #AIRBASE self
-- @return DCS#Airbase DCS airbase object.
function AIRBASE:GetDCSObject()
local DCSAirbase = Airbase.getByName( self.AirbaseName )
-- Get the DCS object.
local DCSAirbase = Airbase.getByName(self.AirbaseName)
if DCSAirbase then
return DCSAirbase
@@ -533,7 +578,7 @@ function AIRBASE.GetAllAirbases(coalition, category)
local airbases={}
for _,_airbase in pairs(_DATABASE.AIRBASES) do
local airbase=_airbase --#AIRBASE
if (coalition~=nil and airbase:GetCoalition()==coalition) or coalition==nil then
if coalition==nil or airbase:GetCoalition()==coalition then
if category==nil or category==airbase:GetAirbaseCategory() then
table.insert(airbases, airbase)
end
@@ -543,6 +588,25 @@ function AIRBASE.GetAllAirbases(coalition, category)
return airbases
end
--- Get all airbase names of the current map. This includes ships and FARPS.
-- @param DCS#Coalition coalition (Optional) Return only airbases belonging to the specified coalition. By default, all airbases of the map are returned.
-- @param #number category (Optional) Return only airbases of a certain category, e.g. Airbase.Category.FARP
-- @return #table Table containing all airbase names of the current map.
function AIRBASE.GetAllAirbaseNames(coalition, category)
local airbases={}
for airbasename,_airbase in pairs(_DATABASE.AIRBASES) do
local airbase=_airbase --#AIRBASE
if coalition==nil or airbase:GetCoalition()==coalition then
if category==nil or category==airbase:GetAirbaseCategory() then
table.insert(airbases, airbasename)
end
end
end
return airbases
end
--- Get ID of the airbase.
-- @param #AIRBASE self
-- @param #boolean unique (Optional) If true, ships will get a negative sign as the unit ID might be the same as an airbase ID. Default off!
@@ -565,22 +629,6 @@ function AIRBASE:GetID(unique)
local airbaseCategory=self:GetAirbaseCategory()
--env.info(string.format("FF airbase=%s id=%s category=%s", tostring(AirbaseName), tostring(airbaseID), tostring(airbaseCategory)))
-- No way AFIK to get the DCS version. So we check if the event exists. That should tell us if we are on DCS 2.5.6 or prior to that.
--[[
if world.event.S_EVENT_KILL and world.event.S_EVENT_KILL>0 and airbaseCategory==Airbase.Category.AIRDROME then
-- We have to take the key value of this loop!
airbaseID=DCSAirbaseId
-- Now another quirk: for Caucasus, we need to add 11 to the key value to get the correct ID. See https://forums.eagle.ru/showpost.php?p=4210774&postcount=11
if UTILS.GetDCSMap()==DCSMAP.Caucasus then
airbaseID=airbaseID+11
end
end
]]
if AirbaseName==self.AirbaseName then
if airbaseCategory==Airbase.Category.SHIP or airbaseCategory==Airbase.Category.HELIPAD then
-- Ships get a negative sign as their unit number might be the same as the ID of another airbase.
@@ -598,6 +646,38 @@ function AIRBASE:GetID(unique)
end
--- Get category of airbase.
-- @param #AIRBASE self
-- @return #number Category of airbase from GetDesc().category.
function AIRBASE:GetAirbaseCategory()
return self.category
end
--- Check if airbase is an airdrome.
-- @param #AIRBASE self
-- @return #boolean If true, airbase is an airdrome.
function AIRBASE:IsAirdrome()
return self.isAirdrome
end
--- Check if airbase is a helipad.
-- @param #AIRBASE self
-- @return #boolean If true, airbase is a helipad.
function AIRBASE:IsHelipad()
return self.isHelipad
end
--- Check if airbase is a ship.
-- @param #AIRBASE self
-- @return #boolean If true, airbase is a ship.
function AIRBASE:IsShip()
return self.isShip
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Parking
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Returns a table of parking data for a given airbase. If the optional parameter *available* is true only available parking will be returned, otherwise all parking at the base is returned. Term types have the following enumerated values:
--
-- * 16 : Valid spawn points on runway
@@ -728,6 +808,58 @@ function AIRBASE:GetParkingSpotsCoordinates(termtype)
return spots
end
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
-- @param #AIRBASE self
-- @return#AIRBASE self
function AIRBASE:_InitParkingSpots()
-- Get parking data of all spots (free or occupied)
local parkingdata=self:GetParkingData(false)
-- Init table.
self.parking={}
self.parkingByID={}
self.NparkingTotal=0
self.NparkingTerminal={}
for _,terminalType in pairs(AIRBASE.TerminalType) do
self.NparkingTerminal[terminalType]=0
end
-- Put coordinates of parking spots into table.
for _,spot in pairs(parkingdata) do
-- New parking spot.
local park={} --#AIRBASE.ParkingSpot
park.Vec3=spot.vTerminalPos
park.Coordinate=COORDINATE:NewFromVec3(spot.vTerminalPos)
park.DistToRwy=spot.fDistToRW
park.Free=nil
park.TerminalID=spot.Term_Index
park.TerminalID0=spot.Term_Index_0
park.TerminalType=spot.Term_Type
park.TOAC=spot.TO_AC
for _,terminalType in pairs(AIRBASE.TerminalType) do
if self._CheckTerminalType(terminalType, park.TerminalType) then
self.NparkingTerminal[terminalType]=self.NparkingTerminal[terminalType]+1
end
end
self.parkingByID[park.TerminalID]=park
table.insert(self.parking, park)
end
return self
end
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
-- @param #AIRBASE self
-- @param #number TerminalID Terminal ID.
-- @return #AIRBASE.ParkingSpot Parking spot.
function AIRBASE:_GetParkingSpotByID(TerminalID)
return self.parkingByID[TerminalID]
end
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
-- @param #AIRBASE self
@@ -737,6 +869,7 @@ function AIRBASE:GetParkingSpotsTable(termtype)
-- Get parking data of all spots (free or occupied)
local parkingdata=self:GetParkingData(false)
-- Get parking data of all free spots.
local parkingfree=self:GetParkingData(true)
@@ -753,15 +886,18 @@ function AIRBASE:GetParkingSpotsTable(termtype)
-- Put coordinates of parking spots into table.
local spots={}
for _,_spot in pairs(parkingdata) do
if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) then
self:T2({_spot=_spot})
local _free=_isfree(_spot)
local _coord=COORDINATE:NewFromVec3(_spot.vTerminalPos)
table.insert(spots, {Coordinate=_coord, TerminalID=_spot.Term_Index, TerminalType=_spot.Term_Type, TOAC=_spot.TO_AC, Free=_free, TerminalID0=_spot.Term_Index_0, DistToRwy=_spot.fDistToRW})
end
end
self:T2({ spots = spots } )
if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) then
local spot=self:_GetParkingSpotByID(_spot.Term_Index)
spot.Free=_isfree(_spot) -- updated
spot.TOAC=_spot.TO_AC -- updated
table.insert(spots, spot)
end
end
return spots
end
@@ -781,8 +917,14 @@ function AIRBASE:GetFreeParkingSpotsTable(termtype, allowTOAC)
for _,_spot in pairs(parkingfree) do
if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) and _spot.Term_Index>0 then
if (allowTOAC and allowTOAC==true) or _spot.TO_AC==false then
local _coord=COORDINATE:NewFromVec3(_spot.vTerminalPos)
table.insert(freespots, {Coordinate=_coord, TerminalID=_spot.Term_Index, TerminalType=_spot.Term_Type, TOAC=_spot.TO_AC, Free=true, TerminalID0=_spot.Term_Index_0, DistToRwy=_spot.fDistToRW})
local spot=self:_GetParkingSpotByID(_spot.Term_Index)
spot.Free=true -- updated
spot.TOAC=_spot.TO_AC -- updated
table.insert(freespots, spot)
end
end
end
@@ -795,14 +937,10 @@ end
-- @param #number TerminalID The terminal ID of the parking spot.
-- @return #AIRBASE.ParkingSpot Table free parking spots. Table has the elements ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
function AIRBASE:GetParkingSpotData(TerminalID)
self:F({TerminalID=TerminalID})
-- Get parking data.
local parkingdata=self:GetParkingSpotsTable()
-- Debug output.
self:T2({parkingdata=parkingdata})
for _,_spot in pairs(parkingdata) do
local spot=_spot --#AIRBASE.ParkingSpot
self:T({TerminalID=spot.TerminalID,TerminalType=spot.TerminalType})
@@ -1041,99 +1179,6 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
return validspots
end
--- Function that checks if at leat one unit of a group has been spawned close to a spawn point on the runway.
-- @param #AIRBASE self
-- @param Wrapper.Group#GROUP group Group to be checked.
-- @param #number radius Radius around the spawn point to be checked. Default is 50 m.
-- @param #boolean despawn If true, the group is destroyed.
-- @return #boolean True if group is within radius around spawn points on runway.
function AIRBASE:CheckOnRunWay(group, radius, despawn)
-- Default radius.
radius=radius or 50
-- We only check at real airbases (not FARPS or ships).
if self:GetAirbaseCategory()~=Airbase.Category.AIRDROME then
return false
end
if group and group:IsAlive() then
-- Debug.
self:T(string.format("%s, checking if group %s is on runway?",self:GetName(), group:GetName()))
-- Get coordinates on runway.
local runwaypoints=self:GetParkingSpotsCoordinates(AIRBASE.TerminalType.Runway)
-- Mark runway spawn points.
--[[
for _i,_coord in pairs(runwaypoints) do
_coord:MarkToAll(string.format("runway %d",_i))
end
]]
-- Get units of group.
local units=group:GetUnits()
-- Loop over units.
for _,_unit in pairs(units) do
local unit=_unit --Wrapper.Unit#UNIT
-- Check if unit is alive and not in air.
if unit and unit:IsAlive() and not unit:InAir() then
self:T(string.format("%s, checking if unit %s is on runway?",self:GetName(), unit:GetName()))
-- Loop over runway spawn points.
for _i,_coord in pairs(runwaypoints) do
-- Distance between unit and spawn pos.
local dist=unit:GetCoordinate():Get2DDistance(_coord)
-- Mark unit spawn points for debugging.
--unit:GetCoordinate():MarkToAll(string.format("unit %s distance to rwy %d = %d",unit:GetName(),_i, dist))
-- Check if unit is withing radius.
if dist<radius then
self:E(string.format("%s, unit %s of group %s was spawned on runway #%d. Distance %.1f < radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn)))
--unit:FlareRed()
if despawn then
group:Destroy(true)
end
return true
else
self:T(string.format("%s, unit %s of group %s was NOT spawned on runway #%d. Distance %.1f > radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn)))
--unit:FlareGreen()
end
end
else
self:T(string.format("%s, checking if unit %s of group %s is on runway. Unit is NOT alive.",self:GetName(), unit:GetName(), group:GetName()))
end
end
else
self:T(string.format("%s, checking if group %s is on runway. Group is NOT alive.",self:GetName(), group:GetName()))
end
return false
end
--- Get category of airbase.
-- @param #AIRBASE self
-- @return #number Category of airbase from GetDesc().category.
function AIRBASE:GetAirbaseCategory()
local desc=self:GetDesc()
local category=Airbase.Category.AIRDROME
if desc and desc.category then
category=desc.category
else
self:E(string.format("ERROR: Cannot get category of airbase %s due to DCS 2.5.6 bug! Assuming it is an AIRDROME for now...", tostring(self.AirbaseName)))
end
return category
end
--- Helper function to check for the correct terminal type including "artificial" ones.
-- @param #number Term_Type Termial type from getParking routine.
-- @param #AIRBASE.TerminalType termtype Terminal type from AIRBASE.TerminalType enumerator.
@@ -1180,6 +1225,10 @@ function AIRBASE._CheckTerminalType(Term_Type, termtype)
return match
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Runway
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Get runways data. Only for airdromes!
-- @param #AIRBASE self
-- @param #number magvar (Optional) Magnetic variation in degrees.
@@ -1194,41 +1243,124 @@ function AIRBASE:GetRunwayData(magvar, mark)
return {}
end
-- Get spawn points on runway.
-- Get spawn points on runway. These can be used to determine the runway heading.
local runwaycoords=self:GetParkingSpotsCoordinates(AIRBASE.TerminalType.Runway)
-- Debug: For finding the numbers of the spawn points belonging to each runway.
if false then
for i,_coord in pairs(runwaycoords) do
local coord=_coord --Core.Point#COORDINATE
coord:Translate(100, 0):MarkToAll("Runway i="..i)
end
end
-- Magnetic declination.
magvar=magvar or UTILS.GetMagneticDeclination()
-- Number of runways.
local N=#runwaycoords
local dN=2
local ex=false
local N2=N/2
local exception=false
-- Airbase name.
local name=self:GetName()
-- Exceptions
if name==AIRBASE.Nevada.Jean_Airport or
name==AIRBASE.Nevada.Creech_AFB or
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 then
name==AIRBASE.PersianGulf.Kish_International_Airport
then
N=#runwaycoords/2
dN=1
ex=true
-- 1-->4, 2-->3, 3-->2, 4-->1
exception=1
elseif UTILS.GetDCSMap()==DCSMAP.Syria and N>=2 and
name~=AIRBASE.Syria.Minakh and
name~=AIRBASE.Syria.Damascus and
name~=AIRBASE.Syria.Khalkhalah and
name~=AIRBASE.Syria.Marj_Ruhayyil and
name~=AIRBASE.Syria.Beirut_Rafic_Hariri then
-- 1-->3, 2-->4, 3-->1, 4-->2
exception=2
end
local function f(i)
local j
if exception==1 then
j=N-(i+1) -- 1-->4, 2-->3
elseif exception==2 then
if i<=N2 then
j=i+N2 -- 1-->3, 2-->4
else
j=i-N2 -- 3-->1, 4-->3
end
else
if i%2==0 then
j=i-1 -- even 2-->1, 4-->3
else
j=i+1 -- odd 1-->2, 3-->4
end
end
-- Special case where there is no obvious order.
if name==AIRBASE.Syria.Beirut_Rafic_Hariri then
if i==1 then
j=3
elseif i==2 then
j=6
elseif i==3 then
j=1
elseif i==4 then
j=5
elseif i==5 then
j=4
elseif i==6 then
j=2
end
end
if name==AIRBASE.Syria.Ramat_David then
if i==1 then
j=4
elseif i==2 then
j=6
elseif i==3 then
j=5
elseif i==4 then
j=1
elseif i==5 then
j=3
elseif i==6 then
j=2
end
end
return j
end
for i=1,N,dN do
for i=1,N do
local j=i+1
if ex then
--j=N+i
j=#runwaycoords-i+1
end
-- Get the other spawn point coordinate.
local j=f(i)
-- Coordinates of the two runway points.
local c1=runwaycoords[i] --Core.Point#COORDINATES
local c2=runwaycoords[j] --Core.Point#COORDINATES
local c1=runwaycoords[i] --Core.Point#COORDINATE
local c2=runwaycoords[j] --Core.Point#COORDINATE
-- Heading of runway.
local hdg=c1:HeadingTo(c2)
@@ -1245,11 +1377,11 @@ function AIRBASE:GetRunwayData(magvar, mark)
runway.endpoint=c2
-- Debug info.
self:T(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m", self:GetName(), runway.idx, runway.heading, runway.length))
self:I(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m i=%d j=%d", self:GetName(), runway.idx, runway.heading, runway.length, i, j))
-- Debug mark
if mark then
runway.position:MarkToAll(string.format("Runway %s: true heading=%03d (magvar=%d), length=%d m", runway.idx, runway.heading, magvar, runway.length))
runway.position:MarkToAll(string.format("Runway %s: true heading=%03d (magvar=%d), length=%d m, i=%d, j=%d", runway.idx, runway.heading, magvar, runway.length, i, j))
end
-- Add runway.
@@ -1257,38 +1389,6 @@ function AIRBASE:GetRunwayData(magvar, mark)
end
-- Get inverse runways
local inverse={}
for _,_runway in pairs(runways) do
local r=_runway --#AIRBASE.Runway
local runway={} --#AIRBASE.Runway
runway.heading=r.heading-180
if runway.heading<0 then
runway.heading=runway.heading+360
end
runway.idx=string.format("%02d", math.max(0, UTILS.Round((runway.heading-magvar)/10, 0)))
runway.length=r.length
runway.position=r.endpoint
runway.endpoint=r.position
-- Debug info.
self:T(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m", self:GetName(), runway.idx, runway.heading, runway.length))
-- Debug mark
if mark then
runway.position:MarkToAll(string.format("Runway %s: true heading=%03d (magvar=%d), length=%d m", runway.idx, runway.heading, magvar, runway.length))
end
-- Add runway.
table.insert(inverse, runway)
end
-- Add inverse runway.
for _,runway in pairs(inverse) do
table.insert(runways, runway)
end
return runways
end
@@ -1358,3 +1458,73 @@ function AIRBASE:GetActiveRunway(magvar)
return runways[iact]
end
--- Function that checks if at leat one unit of a group has been spawned close to a spawn point on the runway.
-- @param #AIRBASE self
-- @param Wrapper.Group#GROUP group Group to be checked.
-- @param #number radius Radius around the spawn point to be checked. Default is 50 m.
-- @param #boolean despawn If true, the group is destroyed.
-- @return #boolean True if group is within radius around spawn points on runway.
function AIRBASE:CheckOnRunWay(group, radius, despawn)
-- Default radius.
radius=radius or 50
-- We only check at real airbases (not FARPS or ships).
if self:GetAirbaseCategory()~=Airbase.Category.AIRDROME then
return false
end
if group and group:IsAlive() then
-- Debug.
self:T(string.format("%s, checking if group %s is on runway?",self:GetName(), group:GetName()))
-- Get coordinates on runway.
local runwaypoints=self:GetParkingSpotsCoordinates(AIRBASE.TerminalType.Runway)
-- Get units of group.
local units=group:GetUnits()
-- Loop over units.
for _,_unit in pairs(units) do
local unit=_unit --Wrapper.Unit#UNIT
-- Check if unit is alive and not in air.
if unit and unit:IsAlive() and not unit:InAir() then
self:T(string.format("%s, checking if unit %s is on runway?",self:GetName(), unit:GetName()))
-- Loop over runway spawn points.
for _i,_coord in pairs(runwaypoints) do
-- Distance between unit and spawn pos.
local dist=unit:GetCoordinate():Get2DDistance(_coord)
-- Mark unit spawn points for debugging.
--unit:GetCoordinate():MarkToAll(string.format("unit %s distance to rwy %d = %d",unit:GetName(),_i, dist))
-- Check if unit is withing radius.
if dist<radius then
self:E(string.format("%s, unit %s of group %s was spawned on runway #%d. Distance %.1f < radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn)))
--unit:FlareRed()
if despawn then
group:Destroy(true)
end
return true
else
self:T(string.format("%s, unit %s of group %s was NOT spawned on runway #%d. Distance %.1f > radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn)))
--unit:FlareGreen()
end
end
else
self:T(string.format("%s, checking if unit %s of group %s is on runway. Unit is NOT alive.",self:GetName(), unit:GetName(), group:GetName()))
end
end
else
self:T(string.format("%s, checking if group %s is on runway. Group is NOT alive.",self:GetName(), group:GetName()))
end
return false
end
@@ -243,8 +243,7 @@ end
--- Returns the initial health.
-- @param #CONTROLLABLE self
-- @return #number The controllable health value (unit or group average).
-- @return #nil The controllable is not existing or alive.
-- @return #number The controllable health value (unit or group average) or `nil` if the controllable does not exist.
function CONTROLLABLE:GetLife0()
self:F2( self.ControllableName )
@@ -296,7 +295,6 @@ end
-- @return #nil The CONTROLLABLE is not existing or alive.
function CONTROLLABLE:GetFuel()
self:F( self.ControllableName )
return nil
end
@@ -1429,16 +1427,6 @@ end
-- @return DCS#Task The DCS task structure.
function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType )
-- FireAtPoint = {
-- id = 'FireAtPoint',
-- params = {
-- point = Vec2,
-- radius = Distance,
-- expendQty = number,
-- expendQtyEnabled = boolean,
-- }
-- }
local DCSTask = {
id = 'FireAtPoint',
params = {
@@ -1458,7 +1446,6 @@ function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType )
DCSTask.params.weaponType=WeaponType
end
self:T3( { DCSTask } )
return DCSTask
end
+71 -19
View File
@@ -261,7 +261,9 @@ end
-- @param #string GroupName The Group name
-- @return #GROUP self
function GROUP:Register( GroupName )
local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) -- #GROUP
self.GroupName = GroupName
self:SetEventPriority( 4 )
@@ -668,14 +670,15 @@ end
-- @param #number UnitNumber The number of the UNIT wrapper class to be returned.
-- @return Wrapper.Unit#UNIT The UNIT wrapper class.
function GROUP:GetUnit( UnitNumber )
self:F3( { self.GroupName, UnitNumber } )
local DCSGroup = self:GetDCSObject()
if DCSGroup then
local DCSUnit = DCSGroup:getUnit( UnitNumber )
local UnitFound = UNIT:Find( DCSGroup:getUnit( UnitNumber ) )
self:T2( UnitFound )
local UnitFound = UNIT:Find(DCSUnit)
return UnitFound
end
@@ -688,13 +691,11 @@ end
-- @param #number UnitNumber The number of the DCS Unit to be returned.
-- @return DCS#Unit The DCS Unit.
function GROUP:GetDCSUnit( UnitNumber )
self:F3( { self.GroupName, UnitNumber } )
local DCSGroup = self:GetDCSObject()
local DCSGroup=self:GetDCSObject()
if DCSGroup then
local DCSUnitFound = DCSGroup:getUnit( UnitNumber )
self:T3( DCSUnitFound )
local DCSUnitFound=DCSGroup:getUnit( UnitNumber )
return DCSUnitFound
end
@@ -706,14 +707,14 @@ end
-- @param #GROUP self
-- @return #number The DCS Group size.
function GROUP:GetSize()
self:F3( { self.GroupName } )
local DCSGroup = self:GetDCSObject()
if DCSGroup then
local GroupSize = DCSGroup:getSize()
if GroupSize then
self:T3( GroupSize )
return GroupSize
else
return 0
@@ -946,24 +947,29 @@ end
-- @param #GROUP self
-- @return DCS#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group.
function GROUP:GetVec2()
self:F2( self.GroupName )
local UnitPoint = self:GetUnit(1)
UnitPoint:GetVec2()
local GroupPointVec2 = UnitPoint:GetVec2()
self:T3( GroupPointVec2 )
return GroupPointVec2
local Unit=self:GetUnit(1)
if Unit then
return Unit:GetVec2()
end
end
--- Returns the current Vec3 vector of the first DCS Unit in the GROUP.
-- @param #GROUP self
-- @return DCS#Vec3 Current Vec3 of the first DCS Unit of the GROUP.
function GROUP:GetVec3()
self:F2( self.GroupName )
local GroupVec3 = self:GetUnit(1):GetVec3()
self:T3( GroupVec3 )
return GroupVec3
-- Get first unit.
local unit=self:GetUnit(1)
if unit then
return unit:GetVec3()
end
self:E("ERROR: Cannot get Vec3 of group "..tostring(self.GroupName))
return nil
end
--- Returns a POINT_VEC2 object indicating the point in 2D of the first UNIT of the GROUP within the mission.
@@ -1166,6 +1172,32 @@ end
do -- Is Zone methods
--- Check if any unit of a group is inside a @{Zone}.
-- @param #GROUP self
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
-- @return #boolean Returns true if at least one unit is inside the zone or false if no unit is inside.
function GROUP:IsInZone( Zone )
if self:IsAlive() then
for UnitID, UnitData in pairs(self:GetUnits()) do
local Unit = UnitData -- Wrapper.Unit#UNIT
if Zone:IsVec3InZone(Unit:GetVec3()) then
return true -- At least one unit is in the zone. That is enough.
else
-- This one is not but another could be.
end
end
return false
end
return nil
end
--- Returns true if all units of the group are within a @{Zone}.
-- @param #GROUP self
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
@@ -2100,6 +2132,7 @@ end
--- Calculate the maxium A2G threat level of the Group.
-- @param #GROUP self
-- @return #number Number between 0 and 10.
function GROUP:CalculateThreatLevelA2G()
local MaxThreatLevelA2G = 0
@@ -2115,6 +2148,25 @@ function GROUP:CalculateThreatLevelA2G()
return MaxThreatLevelA2G
end
--- Get threat level of the group.
-- @param #GROUP self
-- @return #number Max threat level (a number between 0 and 10).
function GROUP:GetThreatLevel()
local threatlevelMax = 0
for UnitName, UnitData in pairs(self:GetUnits()) do
local ThreatUnit = UnitData -- Wrapper.Unit#UNIT
local threatlevel = ThreatUnit:GetThreatLevel()
if threatlevel > threatlevelMax then
threatlevelMax=threatlevel
end
end
return threatlevelMax
end
--- Returns true if the first unit of the GROUP is in the air.
-- @param Wrapper.Group#GROUP self
-- @return #boolean true if in the first unit of the group is in the air or #nil if the GROUP is not existing or not alive.
+138 -138
View File
@@ -1,5 +1,5 @@
--- **Wrapper** - Markers On the F10 map.
--
--
-- **Main Features:**
--
-- * Convenient handling of markers via multiple user API functions.
@@ -8,7 +8,7 @@
-- * Retrieve data such as text and coordinate.
-- * Marker specific FSM events when a marker is added, removed or changed.
-- * Additional FSM events when marker text or position is changed.
--
--
-- ===
--
-- ### Author: **funkyfranky**
@@ -36,104 +36,104 @@
-- ![Banner Image](..\Presentations\MARKER\Marker_Main.jpg)
--
-- # The MARKER Class Idea
--
--
-- The MARKER class simplifies creating, updating and removing of markers on the F10 map.
--
--
-- # Create a Marker
--
--
-- -- Create a MARKER object at Batumi with a trivial text.
-- local Coordinate=AIRBASE:FindByName("Batumi"):GetCoordinate()
-- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield")
--
-- Now this does **not** show the marker yet. We still need to specifiy to whom it is shown. There are several options, i.e.
--
-- Now this does **not** show the marker yet. We still need to specifiy to whom it is shown. There are several options, i.e.
-- show the marker to everyone, to a speficic coaliton only, or only to a specific group.
--
--
-- ## For Everyone
--
--
-- If the marker should be visible to everyone, you can use the :ToAll() function.
--
-- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToAll()
--
--
-- ## For a Coaliton
--
--
-- If the maker should be visible to a specific coalition, you can use the :ToCoalition() function.
--
--
-- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToCoaliton(coaliton.side.BLUE)
--
--
-- ### To Blue Coaliton
--
--
-- ### To Red Coalition
--
--
-- This would show the marker only to the Blue coaliton.
--
--
-- ## For a Group
--
--
--
--
-- # Removing a Marker
--
--
--
--
-- # Updating a Marker
--
--
-- The marker text and coordinate can be updated easily as shown below.
--
--
-- However, note that **updateing involves to remove and recreate the marker if either text or its coordinate is changed**.
-- *This is a DCS scripting engine limitation.*
--
-- *This is a DCS scripting engine limitation.*
--
-- ## Update Text
--
--
-- If you created a marker "mymarker" as shown above, you can update the dispayed test by
--
--
-- mymarker:UpdateText("I am the new text at Batumi")
--
--
-- The update can also be delayed by, e.g. 90 seconds, using
--
--
-- mymarker:UpdateText("I am the new text at Batumi", 90)
--
--
-- ## Update Coordinate
--
--
-- If you created a marker "mymarker" as shown above, you can update its coordinate on the F10 map by
--
--
-- mymarker:UpdateCoordinate(NewCoordinate)
--
--
-- The update can also be delayed by, e.g. 60 seconds, using
--
--
-- mymarker:UpdateCoordinate(NewCoordinate, 60)
--
--
-- # Retrieve Data
--
--
-- The important data as the displayed text and the coordinate of the marker can be retrieved easily.
--
--
-- ## Text
--
--
-- local text=mymarker:GetText()
-- env.info("Marker Text = " .. text)
--
--
-- ## Coordinate
--
--
-- local Coordinate=mymarker:GetCoordinate()
-- env.info("Marker Coordinate LL DSM = " .. Coordinate:ToStringLLDMS())
--
--
--
--
-- # FSM Events
--
--
-- Moose creates addditonal events, so called FSM event, when markers are added, changed, removed, and text or the coordianteis updated.
--
--
-- These events can be captured and used for processing via OnAfter functions as shown below.
--
--
-- ## Added
--
--
-- ## Changed
--
--
-- ## Removed
--
--
-- ## TextUpdate
--
--
-- ## CoordUpdate
--
--
--
--
-- # Examples
--
--
--
--
-- @field #MARKER
MARKER = {
ClassName = "MARKER",
@@ -170,29 +170,29 @@ MARKER.version="0.1.0"
--- Create a new MARKER class object.
-- @param #MARKER self
-- @param Core.Point#COORDINATE Coordinate Coordinate where to place the marker.
-- @param #string Text Text displayed on the mark panel.
-- @param #string Text Text displayed on the mark panel.
-- @return #MARKER self
function MARKER:New(Coordinate, Text)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #MARKER
self.coordinate=Coordinate
self.text=Text
-- Defaults
self.readonly=false
self.message=""
-- New marker ID. This is not the one of the actual marker.
-- New marker ID. This is not the one of the actual marker.
_MARKERID=_MARKERID+1
self.myid=_MARKERID
-- Log ID.
self.lid=string.format("Marker #%d | ", self.myid)
-- Start State.
self:SetStartState("Invisible")
@@ -201,7 +201,7 @@ function MARKER:New(Coordinate, Text)
self:AddTransition("Invisible", "Added", "Visible") -- Marker was added.
self:AddTransition("Visible", "Removed", "Invisible") -- Marker was removed.
self:AddTransition("*", "Changed", "*") -- Marker was changed.
self:AddTransition("*", "TextUpdate", "*") -- Text updated.
self:AddTransition("*", "CoordUpdate", "*") -- Coordinates updated.
@@ -304,8 +304,8 @@ function MARKER:New(Coordinate, Text)
self:HandleEvent(EVENTS.MarkAdded)
self:HandleEvent(EVENTS.MarkRemoved)
self:HandleEvent(EVENTS.MarkChange)
return self
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -318,7 +318,7 @@ end
function MARKER:ReadOnly()
self.readonly=true
return self
end
@@ -329,7 +329,7 @@ end
function MARKER:Message(Text)
self.message=Text or ""
return self
end
@@ -349,14 +349,14 @@ function MARKER:ToAll(Delay)
self.togroup=nil
self.groupname=nil
self.groupid=nil
-- First remove an existing mark.
if self.shown then
self:Remove()
if self.shown then
self:Remove()
end
self.mid=UTILS.GetMarkID()
-- Call DCS function.
trigger.action.markToAll(self.mid, self.text, self.coordinate:GetVec3(), self.readonly, self.message)
@@ -377,25 +377,25 @@ function MARKER:ToCoalition(Coalition, Delay)
else
self.coalition=Coalition
self.tocoaliton=true
self.toall=false
self.togroup=false
self.groupname=nil
self.groupid=nil
-- First remove an existing mark.
if self.shown then
self:Remove()
if self.shown then
self:Remove()
end
self.mid=UTILS.GetMarkID()
-- Call DCS function.
trigger.action.markToCoalition(self.mid, self.text, self.coordinate:GetVec3(), self.coalition, self.readonly, self.message)
end
return self
end
@@ -440,36 +440,36 @@ function MARKER:ToGroup(Group, Delay)
-- Check if group exists.
if Group and Group:IsAlive()~=nil then
self.groupid=Group:GetID()
if self.groupid then
self.groupname=Group:GetName()
self.togroup=true
self.tocoaliton=nil
self.coalition=nil
self.toall=nil
-- First remove an existing mark.
if self.shown then
self:Remove()
if self.shown then
self:Remove()
end
self.mid=UTILS.GetMarkID()
-- Call DCS function.
trigger.action.markToGroup(self.mid, self.text, self.coordinate:GetVec3(), self.groupid, self.readonly, self.message)
end
else
--TODO: Warning!
--TODO: Warning!
end
end
return self
end
@@ -482,14 +482,14 @@ function MARKER:UpdateText(Text, Delay)
if Delay and Delay>0 then
self:ScheduleOnce(Delay, MARKER.UpdateText, self, Text)
else
else
self.text=tostring(Text)
self:Refresh()
self:TextUpdate(tostring(Text))
end
return self
@@ -504,14 +504,14 @@ function MARKER:UpdateCoordinate(Coordinate, Delay)
if Delay and Delay>0 then
self:ScheduleOnce(Delay, MARKER.UpdateCoordinate, self, Coordinate)
else
else
self.coordinate=Coordinate
self:Refresh()
self:CoordUpdate(Coordinate)
end
return self
@@ -525,26 +525,26 @@ function MARKER:Refresh(Delay)
if Delay and Delay>0 then
self:ScheduleOnce(Delay, MARKER.Refresh, self)
else
else
if self.toall then
self:ToAll()
elseif self.tocoaliton then
self:ToCoalition(self.coalition)
elseif self.togroup then
local group=GROUP:FindByName(self.groupname)
self:ToGroup(group)
else
self:E(self.lid.."ERROR: unknown To in :Refresh()!")
end
end
return self
@@ -564,9 +564,9 @@ function MARKER:Remove(Delay)
-- Call DCS function.
trigger.action.removeMark(self.mid)
end
end
return self
@@ -605,7 +605,7 @@ end
--- Check if marker is currently invisible on the F10 map.
-- @param #MARKER self
-- @return
-- @return
function MARKER:IsInvisible()
return self:Is("Invisible")
end
@@ -620,17 +620,17 @@ end
function MARKER:OnEventMarkAdded(EventData)
if EventData and EventData.MarkID then
local MarkID=EventData.MarkID
self:T3(self.lid..string.format("Captured event MarkAdded for Mark ID=%s", tostring(MarkID)))
if MarkID==self.mid then
self.shown=true
self:Added(EventData)
end
end
@@ -643,21 +643,21 @@ end
function MARKER:OnEventMarkRemoved(EventData)
if EventData and EventData.MarkID then
local MarkID=EventData.MarkID
self:T3(self.lid..string.format("Captured event MarkAdded for Mark ID=%s", tostring(MarkID)))
if MarkID==self.mid then
self.shown=false
self:Removed(EventData)
end
end
end
--- Event function when a MARKER changed.
@@ -666,17 +666,17 @@ end
function MARKER:OnEventMarkChange(EventData)
if EventData and EventData.MarkID then
local MarkID=EventData.MarkID
self:T3(self.lid..string.format("Captured event MarkChange for Mark ID=%s", tostring(MarkID)))
if MarkID==self.mid then
self:Changed(EventData)
self:TextChanged(tostring(EventData.MarkText))
end
end
@@ -696,7 +696,7 @@ end
function MARKER:onafterAdded(From, Event, To, EventData)
-- Debug info.
local text=string.format("Captured event MarkAdded for myself:\n")
local text=string.format("Captured event MarkAdded for myself:\n")
text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID))
text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition))
text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID))
@@ -716,7 +716,7 @@ end
function MARKER:onafterRemoved(From, Event, To, EventData)
-- Debug info.
local text=string.format("Captured event MarkRemoved for myself:\n")
local text=string.format("Captured event MarkRemoved for myself:\n")
text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID))
text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition))
text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID))
@@ -736,7 +736,7 @@ end
function MARKER:onafterChanged(From, Event, To, EventData)
-- Debug info.
local text=string.format("Captured event MarkChange for myself:\n")
local text=string.format("Captured event MarkChange for myself:\n")
text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID))
text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition))
text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID))
@@ -755,7 +755,7 @@ end
-- @param #string Text The updated text, displayed in the mark panel.
function MARKER:onafterTextUpdate(From, Event, To, Text)
self:I(self.lid..string.format("New Marker Text:\n%s", Text))
self:T(self.lid..string.format("New Marker Text:\n%s", Text))
end
@@ -767,8 +767,8 @@ end
-- @param Core.Point#COORDINATE Coordinate The updated coordinates.
function MARKER:onafterCoordUpdate(From, Event, To, Coordinate)
self:I(self.lid..string.format("New Marker Coordinate in LL DMS: %s", Coordinate:ToStringLLDMS()))
self:T(self.lid..string.format("New Marker Coordinate in LL DMS: %s", Coordinate:ToStringLLDMS()))
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+106 -51
View File
@@ -15,6 +15,8 @@
-- @extends Wrapper.Identifiable#IDENTIFIABLE
--- @type POSITIONABLE
-- @field Core.Point#COORDINATE coordinate Coordinate object.
-- @field Core.Point#POINT_VEC3 pointvec3 Point Vec3 object.
-- @extends Wrapper.Identifiable#IDENTIFIABLE
@@ -45,6 +47,8 @@
POSITIONABLE = {
ClassName = "POSITIONABLE",
PositionableName = "",
coordinate = nil,
pointvec3 = nil,
}
--- @field #POSITIONABLE.__
@@ -121,10 +125,17 @@ function POSITIONABLE:Destroy( GenerateEvent )
return nil
end
--- Returns the DCS object. Polymorphic for other classes like UNIT, STATIC, GROUP, AIRBASE.
-- @param #POSITIONABLE self
-- @return DCS#Object The DCS object.
function POSITIONABLE:GetDCSObject()
return nil
end
--- Returns a pos3 table of the objects current position and orientation in 3D space. X, Y, Z values are unit vectors defining the objects orientation.
-- Coordinates are dependent on the position of the maps origin.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return DCS#Position Table consisting of the point and orientation tables.
-- @return DCS#Position3 Table consisting of the point and orientation tables.
function POSITIONABLE:GetPosition()
self:F2( self.PositionableName )
@@ -215,27 +226,44 @@ function POSITIONABLE:GetPositionVec3()
return nil
end
--- Returns the @{DCS#Vec2} vector indicating the point in 2D of the POSITIONABLE within the mission.
--- Returns the @{DCS#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return DCS#Vec2 The 2D point vector of the POSITIONABLE.
-- @return #nil The POSITIONABLE is not existing or alive.
function POSITIONABLE:GetVec2()
self:F2( self.PositionableName )
-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE or `nil` if it is not existing or alive.
function POSITIONABLE:GetVec3()
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
local PositionableVec3 = DCSPositionable:getPosition().p
local PositionableVec2 = {}
PositionableVec2.x = PositionableVec3.x
PositionableVec2.y = PositionableVec3.z
self:T2( PositionableVec2 )
return PositionableVec2
local vec3=DCSPositionable:getPoint()
if vec3 then
return vec3
else
self:E("ERROR: Cannot get vec3!")
end
end
BASE:E( { "Cannot GetVec2", Positionable = self, Alive = self:IsAlive() } )
-- ERROR!
self:E( { "Cannot GetVec3", Positionable = self, Alive = self:IsAlive() } )
return nil
end
--- Returns the @{DCS#Vec2} vector indicating the point in 2D of the POSITIONABLE within the mission.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return DCS#Vec2 The 2D point vector of the POSITIONABLE or #nil if it is not existing or alive.
function POSITIONABLE:GetVec2()
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
local Vec3=DCSPositionable:getPoint() --DCS#Vec3
return {x=Vec3.x, y=Vec3.z}
end
self:E( { "Cannot GetVec2", Positionable = self, Alive = self:IsAlive() } )
return nil
end
@@ -258,7 +286,7 @@ function POSITIONABLE:GetPointVec2()
return PositionablePointVec2
end
BASE:E( { "Cannot GetPointVec2", Positionable = self, Alive = self:IsAlive() } )
self:E( { "Cannot GetPointVec2", Positionable = self, Alive = self:IsAlive() } )
return nil
end
@@ -268,17 +296,29 @@ end
-- @return Core.Point#POINT_VEC3 The 3D point vector of the POSITIONABLE.
-- @return #nil The POSITIONABLE is not existing or alive.
function POSITIONABLE:GetPointVec3()
self:F2( self.PositionableName )
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
local PositionableVec3 = self:GetPositionVec3()
local PositionablePointVec3 = POINT_VEC3:NewFromVec3( PositionableVec3 )
self:T2( PositionablePointVec3 )
return PositionablePointVec3
-- Get 3D vector.
local PositionableVec3 = self:GetPositionVec3()
if false and self.pointvec3 then
-- Update vector.
self.pointvec3.x=PositionableVec3.x
self.pointvec3.y=PositionableVec3.y
self.pointvec3.z=PositionableVec3.z
else
-- Create a new POINT_VEC3 object.
self.pointvec3=POINT_VEC3:NewFromVec3(PositionableVec3)
end
return self.pointvec3
end
BASE:E( { "Cannot GetPointVec3", Positionable = self, Alive = self:IsAlive() } )
@@ -289,27 +329,62 @@ end
--- Returns a COORDINATE object indicating the point in 3D of the POSITIONABLE within the mission.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return Core.Point#COORDINATE The COORDINATE of the POSITIONABLE.
function POSITIONABLE:GetCoordinate()
self:F2( self.PositionableName )
function POSITIONABLE:GetCoord()
-- Get DCS object.
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
local PositionableVec3 = self:GetPositionVec3()
local PositionableCoordinate = COORDINATE:NewFromVec3( PositionableVec3 )
PositionableCoordinate:SetHeading( self:GetHeading() )
PositionableCoordinate:SetVelocity( self:GetVelocityMPS() )
self:T2( PositionableCoordinate )
return PositionableCoordinate
-- Get the current position.
local Vec3 = self:GetVec3()
if self.coordinate then
-- Update vector.
self.coordinate.x=Vec3.x
self.coordinate.y=Vec3.y
self.coordinate.z=Vec3.z
else
-- New COORDINATE.
self.coordinate=COORDINATE:NewFromVec3(Vec3)
end
return self.coordinate
end
-- Error message.
BASE:E( { "Cannot GetCoordinate", Positionable = self, Alive = self:IsAlive() } )
return nil
end
--- Returns a COORDINATE object indicating the point in 3D of the POSITIONABLE within the mission.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return Core.Point#COORDINATE The COORDINATE of the POSITIONABLE.
function POSITIONABLE:GetCoordinate()
-- Get DCS object.
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
-- Get the current position.
local PositionableVec3 = self:GetVec3()
-- Return a new coordiante object.
return COORDINATE:NewFromVec3(PositionableVec3)
end
-- Error message.
self:E( { "Cannot GetCoordinate", Positionable = self, Alive = self:IsAlive() } )
return nil
end
--- Returns a COORDINATE object, which is offset with respect to the orientation of the POSITIONABLE.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @param #number x Offset in the direction "the nose" of the unit is pointing in meters. Default 0 m.
@@ -384,26 +459,6 @@ function POSITIONABLE:GetRandomVec3( Radius )
return nil
end
--- Returns the @{DCS#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE.
-- @return #nil The POSITIONABLE is not existing or alive.
function POSITIONABLE:GetVec3()
self:F2( self.PositionableName )
local DCSPositionable = self:GetDCSObject()
if DCSPositionable then
local PositionableVec3 = DCSPositionable:getPosition().p
self:T3( PositionableVec3 )
return PositionableVec3
end
BASE:E( { "Cannot GetVec3", Positionable = self, Alive = self:IsAlive() } )
return nil
end
--- Get the bounding box of the underlying POSITIONABLE DCS Object.
-- @param #POSITIONABLE self
@@ -1533,7 +1588,7 @@ end
--- Returns true if the unit is within a @{Zone}.
-- @param #STPOSITIONABLEATIC self
-- @param #POSITIONABLE self
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
-- @return #boolean Returns true if the unit is within the @{Core.Zone#ZONE_BASE}
function POSITIONABLE:IsInZone( Zone )