This commit is contained in:
Frank
2020-03-10 00:44:50 +01:00
parent 781ebc7a42
commit a477fc78bc
6 changed files with 196 additions and 78 deletions
@@ -1608,6 +1608,8 @@ WAREHOUSE = {
-- @field #boolean spawned If true, asset was spawned into the cruel world. If false, it is still in stock. -- @field #boolean spawned If true, asset was spawned into the cruel world. If false, it is still in stock.
-- @field #string spawngroupname Name of the spawned group. -- @field #string spawngroupname Name of the spawned group.
-- @field #boolean iscargo If true, asset is cargo. If false asset is transport. Nil if in stock. -- @field #boolean iscargo If true, asset is cargo. If false asset is transport. Nil if in stock.
-- @field #number rid The request ID of this asset.
-- @field #boolean arrived If true, asset arrived at its destination.
--- Item of the warehouse queue table. --- Item of the warehouse queue table.
-- @type WAREHOUSE.Queueitem -- @type WAREHOUSE.Queueitem
@@ -3747,12 +3749,6 @@ function WAREHOUSE:onafterAddAsset(From, Event, To, group, ngroups, forceattribu
if asset~=nil then if asset~=nil then
self:_DebugMessage(string.format("Warehouse %s: Adding KNOWN asset uid=%d with attribute=%s to stock.", self.alias, asset.uid, asset.attribute), 5) self:_DebugMessage(string.format("Warehouse %s: Adding KNOWN asset uid=%d with attribute=%s to stock.", self.alias, asset.uid, asset.attribute), 5)
-- Asset now belongs to this warehouse. Set warehouse ID.
asset.wid=self.uid
-- No request associated with this asset.
asset.rid=nil
-- Set livery. -- Set livery.
if liveries then if liveries then
if type(liveries)=="table" then if type(liveries)=="table" then
@@ -3765,9 +3761,16 @@ function WAREHOUSE:onafterAddAsset(From, Event, To, group, ngroups, forceattribu
-- Set skill. -- Set skill.
asset.skill=skill or asset.skill asset.skill=skill or asset.skill
-- Asset now belongs to this warehouse. Set warehouse ID.
asset.wid=self.uid
-- No request associated with this asset.
asset.rid=nil
-- Asset is not spawned. -- Asset is not spawned.
asset.spawned=false asset.spawned=false
asset.iscargo=nil asset.iscargo=nil
asset.arrived=nil
-- Add asset to stock. -- Add asset to stock.
table.insert(self.stock, asset) table.insert(self.stock, asset)
@@ -4259,6 +4262,7 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request)
-- Asset is transport. -- Asset is transport.
_assetitem.spawned=false _assetitem.spawned=false
_assetitem.iscargo=false _assetitem.iscargo=false
_assetitem.arrived=false
local spawngroup=nil --Wrapper.Group#GROUP local spawngroup=nil --Wrapper.Group#GROUP
@@ -4675,6 +4679,28 @@ function WAREHOUSE:onafterUnloaded(From, Event, To, group)
end end
end end
--- On before "Arrived" event. Triggered when a group has arrived at its destination warehouse.
-- @param #WAREHOUSE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Group#GROUP group The group that was delivered.
function WAREHOUSE:onbeforeArrived(From, Event, To, group)
local asset=self:FindAssetInDB(group)
if asset then
if asset.arrived==true then
-- Asset already arrived (e.g. if multiple units trigger the event via landing).
return false
else
asset.arrived=true --ensure this is not called again from the same asset group.
return true
end
end
end
--- On after "Arrived" event. Triggered when a group has arrived at its destination warehouse. --- On after "Arrived" event. Triggered when a group has arrived at its destination warehouse.
-- The routine should be called by the warehouse sending this asset and not by the receiving warehouse. -- The routine should be called by the warehouse sending this asset and not by the receiving warehouse.
-- It is checked if this asset is cargo (or self propelled) or transport. If it is cargo it is put into the stock of receiving warehouse. -- It is checked if this asset is cargo (or self propelled) or transport. If it is cargo it is put into the stock of receiving warehouse.
@@ -4718,7 +4744,8 @@ function WAREHOUSE:onafterArrived(From, Event, To, group)
end end
-- Increase number of cargo delivered and transports home. -- Increase number of cargo delivered and transports home.
local istransport=warehouse:_GroupIsTransport(group,request) --local istransport=warehouse:_GroupIsTransport(group,request)
if istransport==true then if istransport==true then
request.ntransporthome=request.ntransporthome+1 request.ntransporthome=request.ntransporthome+1
request.transportgroupset:Remove(group:GetName(), true) request.transportgroupset:Remove(group:GetName(), true)
@@ -5613,10 +5640,11 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
unit.payload=asset.payload.pylons unit.payload=asset.payload.pylons
env.info("FF payload") env.info("FF payload")
self:I({playload=unit.payload}) self:I({playload=unit.payload})
self:I(asset)
else else
env.info("FF No payload for asset!") env.info("FF No payload for asset!")
end end
env.info("FF Asset info")
self:I(asset)
end end
@@ -5916,7 +5944,7 @@ end
-- @param Wrapper.Group#GROUP group The group that arrived. -- @param Wrapper.Group#GROUP group The group that arrived.
-- @param #number n Waypoint passed. -- @param #number n Waypoint passed.
-- @param #number N Final waypoint. -- @param #number N Final waypoint.
function WAREHOUSE:_PassingWaypoint(group,n,N) function WAREHOUSE:_PassingWaypoint(group, n, N)
self:T(self.lid..string.format("Group %s passing waypoint %d of %d!", tostring(group:GetName()), n, N)) self:T(self.lid..string.format("Group %s passing waypoint %d of %d!", tostring(group:GetName()), n, N))
-- Final waypoint reached. -- Final waypoint reached.
@@ -6910,7 +6938,7 @@ function WAREHOUSE:_CheckRequestNow(request)
if not _enough then if not _enough then
local text=string.format("Warehouse %s: Request ID=%d denied! Not enough (cargo) assets currently available.", self.alias, request.uid) local text=string.format("Warehouse %s: Request ID=%d denied! Not enough (cargo) assets currently available.", self.alias, request.uid)
self:_InfoMessage(text, 5) self:_InfoMessage(text, 5)
text=string.format("Enough=%s, #_assets=%d, _nassets=%d, request.nasset=%s", tostring(_enough), #_assets,_nassets, tostring(request.nasset)) text=string.format("Enough=%s, #assets=%d, nassets=%d, request.nasset=%s", tostring(_enough), #_assets,_nassets, tostring(request.nasset))
self:T(self.lid..text) self:T(self.lid..text)
return false return false
end end
@@ -7830,18 +7858,15 @@ function WAREHOUSE:_FilterStock(stock, descriptor, attribute, nmax, mobile)
-- Count total number in stock. -- Count total number in stock.
local ntot=0 local ntot=0
for _,_asset in ipairs(stock) do for _,_rasset in pairs(attribute) do
local asset=_asset --#WAREHOUSE.Assetitem local rasset=_rasset --#WAREHOUSE.Assetitem
for _,_asset in ipairs(stock) do
for _,_rasset in pairs(attribute) do local asset=_asset --#WAREHOUSE.Assetitem
local rasset=_rasset --#WAREHOUSE.Assetitem
if rasset.uid==asset.uid then if rasset.uid==asset.uid then
table.insert(filtered, asset) table.insert(filtered, asset)
break
end end
end end
end end
return filtered, #filtered, #filtered>=#attribute return filtered, #filtered, #filtered>=#attribute
+35 -21
View File
@@ -479,6 +479,10 @@ function AIRWING:onafterStatus(From, Event, To)
--self:CheckAWACS() --self:CheckAWACS()
-- TODO: count payloads, count squadrons, count missions
local text=string.format("Status %s: missions=%d, payloads=%d, squads=%d", fsmstate, #self.missionqueue, #self.payloads, #self.squadrons)
self:I(self.lid..text)
------------------ ------------------
-- Mission Info -- -- Mission Info --
------------------ ------------------
@@ -514,21 +518,14 @@ function AIRWING:onafterStatus(From, Event, To)
missiontext=string.format(" [%s (%s): status=%s]", mission.type, mission.name, mission.status) missiontext=string.format(" [%s (%s): status=%s]", mission.type, mission.name, mission.status)
end end
text=text..string.format("\n -[%d] %s*%d: spawned=%s, mission=%s%s", j, typename, asset.nunits, spawned, tostring(self:IsAssetOnMission(asset)), missiontext) text=text..string.format("\n -[%d] %s*%d \"%s\": spawned=%s, mission=%s%s", j, typename, asset.nunits, asset.spawngroupname, spawned, tostring(self:IsAssetOnMission(asset)), missiontext)
local payload=asset.payload and table.concat(asset.payload.missiontypes, ", ") or "None"
local payload=asset.payload text=text.." payload="..payload
if payload then
text=text.." payload "..table.concat(payload.missiontypes, ", ")
else
text=text.." NO payload!"
end
end end
end end
self:I(self.lid..text) self:I(self.lid..text)
-------------- --------------
-- Mission --- -- Mission ---
-------------- --------------
@@ -652,13 +649,12 @@ function AIRWING:_GetNextMission()
-- Get payload for the asset. -- Get payload for the asset.
asset.payload=self:FetchPayloadFromStock(asset.unittype, mission.type) asset.payload=self:FetchPayloadFromStock(asset.unittype, mission.type)
env.info("FF asset payload for mission "..mission.type) -- Should not happen as we just checked!
self:I(asset.payload)
if not asset.payload then if not asset.payload then
self:E(self.lid.."ERROR: No payload for asset! This should not happen!") self:E(self.lid.."ERROR: No payload for asset! This should not happen!")
end end
-- Add asset to mission.
mission:AddAsset(asset) mission:AddAsset(asset)
end end
@@ -763,6 +759,17 @@ function AIRWING:onafterMissionRequest(From, Event, To, Mission)
-- Add request to airwing warehouse. -- Add request to airwing warehouse.
if #Assetlist>0 then if #Assetlist>0 then
--local text=string.format("Requesting assets for mission %s:", Mission.name)
for i,_asset in pairs(Assetlist) do
local asset=_asset --#AIRWING.SquadronAsset
-- Set asset to requested! Important so that new requests do not use this asset!
asset.requested=true
--text=text..string.format("\n[%d] %s spawned=%s type=%s payload=%s", i, asset.spawngroupname, tostring(asset.spawned), asset.unittype, asset.payload and table.concat(asset.payload.missiontypes, ", ") or "no payload!")
end
--self:I(self.lid..text)
-- Add request to airwing warehouse. -- Add request to airwing warehouse.
-- TODO: better Assignment string. -- TODO: better Assignment string.
self:AddRequest(self, WAREHOUSE.Descriptor.ASSETLIST, Assetlist, #Assetlist, nil, nil, Mission.prio, tostring(Mission.auftragsnummer)) self:AddRequest(self, WAREHOUSE.Descriptor.ASSETLIST, Assetlist, #Assetlist, nil, nil, Mission.prio, tostring(Mission.auftragsnummer))
@@ -874,6 +881,9 @@ function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request)
-- Create a flight group. -- Create a flight group.
asset.flightgroup=self:_CreateFlightGroup(asset) asset.flightgroup=self:_CreateFlightGroup(asset)
-- Not requested any more.
asset.requested=nil
-- Get Mission (if any). -- Get Mission (if any).
local mission=self:GetMissionByID(request.assignment) local mission=self:GetMissionByID(request.assignment)
@@ -1051,7 +1061,7 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets)
-- Check if the payload of this asset is compatible with the mission. -- Check if the payload of this asset is compatible with the mission.
if self:CheckMissionType(MissionType, asset.payload.missiontypes) then if self:CheckMissionType(MissionType, asset.payload.missiontypes) then
-- TODO: Check if asset actually has weapons left. Difficult! -- TODO: Check if asset actually has weapons left. Difficult!
table.insert(assets, asset) --table.insert(assets, asset)
end end
end end
@@ -1065,15 +1075,19 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets)
if asset.spawned then if asset.spawned then
-- This asset is already spawned. Let's check if it has the right payload. -- This asset is already spawned. Let's check if it has the right payload.
if self:CheckMissionType(MissionType, asset.payload.missiontypes) then if self:CheckMissionType(MissionType, asset.payload.missiontypes) then
table.insert(assets, asset) --table.insert(assets, asset)
end end
else else
-- Check if we got a payload and reserve it for this asset. if not asset.requested then
local payload=self:FetchPayloadFromStock(asset.unittype, MissionType)
if payload then -- Check if we got a payload and reserve it for this asset.
asset.payload=payload local payload=self:FetchPayloadFromStock(asset.unittype, MissionType)
table.insert(assets, asset) if payload then
asset.payload=payload
table.insert(assets, asset)
end
end end
end end
@@ -1215,7 +1229,7 @@ function AIRWING:CanMission(MissionType, Nassets)
for _,_asset in pairs(Assets) do for _,_asset in pairs(Assets) do
local asset=_asset --#AIRWING.SquadronAsset local asset=_asset --#AIRWING.SquadronAsset
-- Only unspawned payloads are returned. -- Only unspawned payloads are returned.
if not asset.spawned then if not asset.spawned and not asset.requested then
self:ReturnPayloadFromAsset(asset) self:ReturnPayloadFromAsset(asset)
end end
end end
+30 -18
View File
@@ -62,6 +62,8 @@
-- @field #number requestID The ID of the queued warehouse request. Necessary to cancel the request if the mission was cancelled before the request is processed. -- @field #number requestID The ID of the queued warehouse request. Necessary to cancel the request if the mission was cancelled before the request is processed.
-- @field #boolean cancelContactLost If true, cancel mission if the contact is lost. -- @field #boolean cancelContactLost If true, cancel mission if the contact is lost.
-- --
-- @field #number missionAltitude Mission altitude in meters.
--
-- @field #number optionROE ROE. -- @field #number optionROE ROE.
-- @field #number optionROT ROT. -- @field #number optionROT ROT.
-- @field #number optionCM Counter measures. -- @field #number optionCM Counter measures.
@@ -108,23 +110,23 @@ _AUFTRAGSNR=0
--- Mission types. --- Mission types.
-- @type AUFTRAG.Type -- @type AUFTRAG.Type
-- @param #string ANTISHIP Anti-ship mission. -- @field #string ANTISHIP Anti-ship mission.
-- @param #string AWACS AWACS mission. -- @field #string AWACS AWACS mission.
-- @param #string BAI Battlefield Air Interdiction. -- @field #string BAI Battlefield Air Interdiction.
-- @param #string BOMBING Bombing mission. -- @field #string BOMBING Bombing mission.
-- @param #string CAP Combat Air Patrol. -- @field #string CAP Combat Air Patrol.
-- @param #string CAS Close Air Support. -- @field #string CAS Close Air Support.
-- @param #string ESCORT Escort mission. -- @field #string ESCORT Escort mission.
-- @param #string FACA Forward AirController airborne mission. -- @field #string FACA Forward AirController airborne mission.
-- @param #string FERRY Ferry flight mission. -- @field #string FERRY Ferry flight mission.
-- @param #string INTERCEPT Intercept mission. -- @field #string INTERCEPT Intercept mission.
-- @param #string ORBIT Orbit mission. -- @field #string ORBIT Orbit mission.
-- @param #string PATROL Similar to CAP but no auto engage targets. -- @field #string PATROL Similar to CAP but no auto engage targets.
-- @param #string RECON Recon mission. -- @field #string RECON Recon mission.
-- @param #string SEAD Suppression/destruction of enemy air defences. -- @field #string SEAD Suppression/destruction of enemy air defences.
-- @param #string STRIKE Strike mission. -- @field #string STRIKE Strike mission.
-- @param #string TANKER Tanker mission. -- @field #string TANKER Tanker mission.
-- @param #string TRANSPORT Transport mission. -- @field #string TRANSPORT Transport mission.
AUFTRAG.Type={ AUFTRAG.Type={
ANTISHIP="Anti Ship", ANTISHIP="Anti Ship",
AWACS="AWACS", AWACS="AWACS",
@@ -212,9 +214,10 @@ AUFTRAG.version="0.0.5"
-- TODO: Mission ROE and ROT -- TODO: Mission ROE and ROT
-- TODO: Mission formation, etc. -- TODO: Mission formation, etc.
-- TODO: FSM events. -- DONE: FSM events.
-- TODO: F10 marker functions that are updated on Status event. -- TODO: F10 marker functions that are updated on Status event.
-- TODO: Evaluate mission result ==> SUCCESS/FAILURE -- TODO: Evaluate mission result ==> SUCCESS/FAILURE
-- TODO: NewAUTO() NewA2G NewA2A
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor -- Constructor
@@ -542,6 +545,15 @@ function AUFTRAG:SetWeaponType(WeaponType)
return self return self
end end
--- Set mission altitude.
-- @param #AUFTRAG self
-- @param #string Altitude Altitude in feet.
-- @return #AUFTRAG self
function AUFTRAG:SetMissionAltitude(Altitude)
self.missionAltitude=UTILS.FeetToMeters(Altitude)
return self
end
--- Set Rules of Engagement for this mission. --- Set Rules of Engagement for this mission.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param #number roe ROE -- @param #number roe ROE
+7 -2
View File
@@ -2518,7 +2518,7 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE airbase The airbase to hold at. -- @param Wrapper.Airbase#AIRBASE airbase The airbase to hold at.
-- @param #number SpeedTo Speed used for traveling from current position to holding point in knots. Default 350 kts. -- @param #number SpeedTo Speed used for traveling from current position to holding point in knots. Default 75% of max speed.
-- @param #number SpeedHold Holding speed in knots. Default 250 kts. -- @param #number SpeedHold Holding speed in knots. Default 250 kts.
-- @param #number SpeedLand Landing speed in knots. Default 170 kts. -- @param #number SpeedLand Landing speed in knots. Default 170 kts.
function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, SpeedLand) function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, SpeedLand)
@@ -2526,7 +2526,7 @@ function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, Sp
self:I(self.lid..string.format("RTB: event=%s: %s --> %s", Event, From, To)) self:I(self.lid..string.format("RTB: event=%s: %s --> %s", Event, From, To))
-- Defaults: -- Defaults:
SpeedTo=SpeedTo or 350 SpeedTo=SpeedTo or UTILS.KmphToKnots(self.speedmax*0.75)
SpeedHold=SpeedHold or 250 SpeedHold=SpeedHold or 250
SpeedLand=SpeedLand or 170 SpeedLand=SpeedLand or 170
@@ -3327,6 +3327,11 @@ function FLIGHTGROUP:RouteToMission(mission, delay)
local flightcoord=self.group:GetCoordinate() local flightcoord=self.group:GetCoordinate()
local waypointcoord=flightcoord:GetIntermediateCoordinate(targetcoord, 0.5) local waypointcoord=flightcoord:GetIntermediateCoordinate(targetcoord, 0.5)
-- Set altitude of mission waypoint.
if mission.missionAltitude then
waypointcoord.y=mission.missionAltitude
end
-- Add waypoint. -- Add waypoint.
self:AddWaypointAir(waypointcoord, nextwaypoint, self.speedmax*0.8, false) self:AddWaypointAir(waypointcoord, nextwaypoint, self.speedmax*0.8, false)
+59 -11
View File
@@ -17,7 +17,7 @@
-- @field #boolean Debug Debug mode. Messages to all about status. -- @field #boolean Debug Debug mode. Messages to all about status.
-- @field #string lid Class id string for output to DCS log file. -- @field #string lid Class id string for output to DCS log file.
-- @field #number coalition Coalition side number, e.g. coalition.side.RED. -- @field #number coalition Coalition side number, e.g. coalition.side.RED.
-- @field #table filter Category filters. -- @field #table filterCategory Category filters.
-- @field Core.Set#SET_ZONE acceptzoneset Set of accept zones. If defined, only contacts in these zones are considered. -- @field Core.Set#SET_ZONE acceptzoneset Set of accept zones. If defined, only contacts in these zones are considered.
-- @field Core.Set#SET_ZONE rejectzoneset Set of reject zones. Contacts in these zones are not considered. -- @field Core.Set#SET_ZONE rejectzoneset Set of reject zones. Contacts in these zones are not considered.
-- @field #table Contacts Table of detected items. -- @field #table Contacts Table of detected items.
@@ -41,7 +41,7 @@ INTEL = {
ClassName = "INTEL", ClassName = "INTEL",
Debug = nil, Debug = nil,
lid = nil, lid = nil,
filter = nil, filterCategory = {},
detectionset = nil, detectionset = nil,
Contacts = {}, Contacts = {},
ContactsLost = {}, ContactsLost = {},
@@ -202,6 +202,32 @@ function INTEL:SetForgetTime(TimeInterval)
return self return self
end end
--- Filter group categories. Valid categories are:
--
-- * Group.Category.AIRPLANE
-- * Group.Category.HELICOPTER
-- * Group.Category.GROUND
-- * Group.Category.SHIP
-- * Group.Category.TRAIN
--
-- @param #INTEL self
-- @param #table Categories Filter categories, e.g. {Group.Category.AIRPLANE, Group.Category.HELICOPTER}.
-- @return #INTEL self
function INTEL:SetFilterCategory(Categories)
if type(Categories)~="table" then
Categories={Categories}
end
self.filterCategory=Categories
local text="Filter categories: "
for _,category in pairs(self.filterCategory) do
text=text..string.format("%d,", category)
end
self:I(self.lid..text)
return self
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status -- Start & Status
@@ -294,22 +320,44 @@ function INTEL:UpdateIntel()
local unit=_unit --Wrapper.Unit#UNIT local unit=_unit --Wrapper.Unit#UNIT
-- Check if unit is in any of the accept zones. -- Check if unit is in any of the accept zones.
local inzone=false if self.acceptzoneset:Count()>0 then
for _,_zone in pairs(self.acceptzoneset.Set) do local inzone=false
local zone=_zone --Core.Zone#ZONE for _,_zone in pairs(self.acceptzoneset.Set) do
if unit:IsInZone(zone) then local zone=_zone --Core.Zone#ZONE
inzone=true if unit:IsInZone(zone) then
break inzone=true
break
end
end
-- Unit is not in accept zone ==> remove!
if not inzone then
table.insert(remove, unit:GetName())
end end
end end
-- Unit is not in accept zone ==> remove! -- Filter unit categories.
if not inzone then if #self.filterCategory>0 then
table.insert(remove, unit:GetName()) local unitcategory=unit:GetCategory()
local keepit=false
for _,filtercategory in pairs(self.filterCategory) do
if unitcategory==filtercategory then
keepit=true
break
end
end
if not keepit then
self:I(self.lid..string.format("Removing unit %s category=%d", unit:GetName(), unit:GetCategory()))
table.insert(remove, unit:GetName())
end
end end
end end
-- Remove filtered units. -- Remove filtered units.
for _,unitname in pairs(remove) do
DetectedSet:Remove(unitname, true)
end
--DetectedSet:RemoveUnitsByName(remove) --DetectedSet:RemoveUnitsByName(remove)
-- Create detected contacts. -- Create detected contacts.
+14
View File
@@ -756,6 +756,20 @@ function UNIT:GetDamageRelative()
return 1 return 1
end end
--- Returns the category of the #UNIT.
-- @param #UNIT self
-- @return #number Unit category.
function UNIT:GetCategory()
self:F3( self.UnitName )
local DCSUnit = self:GetDCSObject()
if DCSUnit then
return DCSUnit:getDesc().category
end
return nil
end
--- Returns the category name of the #UNIT. --- Returns the category name of the #UNIT.
-- @param #UNIT self -- @param #UNIT self
-- @return #string Category name = Helicopter, Airplane, Ground Unit, Ship -- @return #string Category name = Helicopter, Airplane, Ground Unit, Ship