diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index 4f414ecfb..d80b65043 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -15,10 +15,12 @@ -- @type AIRWING -- @field #string ClassName Name of the class. -- @field #boolean Debug Debug mode. Messages to all about status. --- @field #string sid Class id string for output to DCS log file. --- @field #string carriername The name of the carrier unit. +-- @field #string wid Class id string for output to DCS log file. +-- @field #string warehousename The name of the warehouse unit/static. -- @field #table menu Table of menu items. -- @field #table squadrons Table of squadrons. +-- @field #table missionqueue Mission queue table. +-- @field #table missioncounter Running index counting the added missions. -- @extends Functional.Warehouse#WAREHOUSE --- Be surprised! @@ -34,57 +36,49 @@ -- @field #AIRWING AIRWING = { ClassName = "AIRWING", - sid = nil, - carriername = nil, + wid = nil, + warehousename = nil, menu = nil, squadrons = nil, - taskqueue = {}, + missionqueue = {}, + missioncounter = nil, } --- Squadron data. -- @type AIRWING.Squadron -- @field #string name Name of the squadron. -- @field #table assets Assets of the squadron. --- @field #table tasks Task(s) of the squadron. +-- @field #table capabilities Mission types that the squadron can do. -- @field #string livery Livery of the squadron. --- @field DCS#Coalition.Side coalition Coalition side. --- @field #number threadlevel Thread level of intruder. --- @field #string threadtext Thread text. --- @field #number category Group category. --- @field #string categoryname Group category name. --- @field #string typename Type name of group. -- @field #table menu The squadron menu entries. --- Squadron asset. -- @type AIRWING.SquadronAsset --- @field #boolean assigned Assigned to mission. +-- @field #AIRWING.Missiondata mission The assigned mission. +-- @field Ops.FlightGroup#FLIGHTGROUP flightgroup The flightgroup object. -- @extends Functional.Warehouse#WAREHOUSE.Assetitem ---- Mission types. --- @type AIRWING.MissionType --- @extends Ops.FlightGroup#FLIGHTGROUP.MissionType - --- Mission data. --- @type AIRWING.Mission --- @field #string type Mission type. +-- @type AIRWING.Missiondata -- @field #string squadname Name of the assigned squadron. -- @field #number nassets Number of required assets. --- @field #string status Mission status. -- @extends Ops.FlightGroup#FLIGHTGROUP.Mission --- AIRWING class version. -- @field #string version -AIRWING.version="0.0.5" +AIRWING.version="0.1.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO: Add squadrons to warehouse. +-- DONE: Add squadrons to warehouse. -- TODO: Make special request to transfer squadrons to anther airwing (or warehouse). -- TODO: Build mission queue. -- TODO: Find way to start missions. -- TODO: Check if missions are accomplished. +-- TODO: Paylods as assets. +-- TODO: Cargo as assets. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor @@ -111,7 +105,7 @@ function AIRWING:New(warehousename, airwingname) -- Set some string id for output to DCS.log file. - self.sid=string.format("AIRWING %s |", airwingname) + self.wid=string.format("AIRWING %s |", airwingname) -- Add FSM transitions. -- From State --> Event --> To State @@ -119,10 +113,7 @@ function AIRWING:New(warehousename, airwingname) self:AddTransition("*", "AddMission", "*") -- Add a new mission. - self:AddTransition("*", "RequestCAP", "*") -- Request CAP flight. - self:AddTransition("*", "RequestIntercept", "*") -- Request Intercept. - self:AddTransition("*", "RequestCAS", "*") -- Request CAS. - self:AddTransition("*", "RequestSEAD", "*") -- Request SEAD. + self:AddTransition("*", "RequestMission", "*") -- Request CAP flight. ------------------------ --- Pseudo Functions --- @@ -154,18 +145,6 @@ function AIRWING:New(warehousename, airwingname) -- @param #AIRWING self -- @param #number delay Delay in seconds. - - --- Triggers the FSM event "RequestCAP". - -- @function [parent=#AIRWING] RequestCAP - -- @param #AIRWING self - -- @param Core.Point#COORDINATE coordinate - -- @param #number altitude Altitude - -- @param #number leg Race track length. - -- @param #number heading Heading in degrees. - -- @param #number speed Speed in knots. - -- @param #AIRWING.Squadron squadron Explicitly request a specific squadron. - - -- Debug trace. if true then self.Debug=true @@ -245,11 +224,11 @@ end --- Check if there is a squadron that can execute a given mission type. Optionally, the number of required assets can be specified. -- @param #AIRWING self --- @param #AIRWING.Squaron Squadron The Squadron. +-- @param #AIRWING.Squadron Squadron The Squadron. -- @param #string MissionType Type of mission. -- @param #number Nassets Number of required assets for the mission. Use *nil* or 0 for none. Then only the general capability is checked. -- @return #boolean If true, Squadron can do that type of mission. Available assets are not checked. --- @return #number Number of available assets. +-- @return #number Number of available assets that dont have a mission assigned. function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets) local cando=false @@ -272,12 +251,12 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets) for _,_asset in pairs(Squadron.assets) do local asset=_asset --#AIRWING.SquadronAsset - -- TODO: Check if on mission etc. - if not asset.spawned then + -- Check if has already a mission assigned. + if asset.mission==nil then n=n+1 end - end + end end @@ -322,6 +301,49 @@ function AIRWING:CanMission(MissionType, Nassets) return Can, N end +--- Create a CAP mission. +-- @param #AIRWING self +-- @param #number Altitude Orbit altitude in feet. Default 10000 ft. +-- @param #number SpeedOrbit Orbit speed in knots. Default 350 kts. +-- @param #number Heading Heading in degrees. Default 270° (East to West). +-- @param #number Leg Length of race-track in NM. Default 10 NM. +-- @return #AIRWING.MissionCAP The CAP mission table. +function AIRWING:CreateMissionCAP(Altitude, SpeedOrbit, Heading, Leg) + + local mission={} --#AIRWING.Missiondata + + mission.type=FLIGHTGROUP.MissionType.CAP + mission.altitude=UTILS.FeetToMeters(Altitude or 10000) + mission.speedOrbit=UTILS.KnotsToMps(SpeedOrbit or 350) + mission.heading=Heading or 270 + mission.leg=UTILS.NMToMeters(Leg or 10) + + mission.waypoint=1 + + return mission +end + +--- Add mission to queue. +-- @param #AIRWING self +-- @param AIRWING.Missiondata Mission for this group. +-- @param Core.Zone#ZONE Zone The mission zone. +-- @param #number WaypointIndex The waypoint index. +-- @param #string ClockStart Time the mission is started, e.g. "05:00" for 5 am. If specified as a #number, it will be relative (in seconds) to the current mission time. Default is 5 seconds after mission was added. +-- @param #string ClockStop Time the mission is stopped, e.g. "13:00" for 1 pm. If mission could not be started at that time, it will be removed from the queue. If specified as a #number it will be relative (in seconds) to the current mission time. +-- @param #number Prio Priority of the mission, i.e. a number between 1 and 100. Default 50. +-- @param #string Name Mission name. Default "Aerial Refueling #00X", where "#00X" is a running mission counter index starting at "#001". +-- @return #AIRWING.Missiondata The mission table. +function AIRWING:AddMission(Mission, Zone, WaypointIndex, ClockStart, ClockStop, Prio, Name) + + -- TODO: need to check that this call increases the correct mission counter and adds it to the mission queue. + local mission=FLIGHTGROUP.AddMission(self, Zone, WaypointIndex, ClockStart, ClockStop, Prio, Name, Mission) + + -- Mission needs the correct MID. + mission.MID=self.missioncounter + + return mission +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Start & Status ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -334,7 +356,7 @@ function AIRWING:onafterStart(From, Event, To) self:GetParent(self).onafterStart(self, From, Event, To) -- Info. - self:I(self.sid..string.format("Starting AIRWING v%s %s (%s)", AIRWING.version, self.alias, self.warehousename)) + self:I(self.wid..string.format("Starting AIRWING v%s %s (%s)", AIRWING.version, self.alias, self.warehousename)) -- Add F10 radio menu. self:_SetMenuCoalition() @@ -356,7 +378,7 @@ function AIRWING:onafterAirwingStatus(From, Event, To) -- Info text. local text=string.format("State %s", fsmstate) - self:I(self.sid..text) + self:I(self.wid..text) local text="Squadrons:" for i,_squadron in pairs(self.squadrons) do @@ -387,16 +409,18 @@ function AIRWING:onafterAirwingStatus(From, Event, To) end end - self:I(self.sid..text) + self:I(self.wid..text) + -------------- + -- Mission --- + -------------- + + -- Get next mission. local mission=self:_GetNextMission() - + + -- Request mission execution. if mission then - - if mission.type==AIRWING.MissionType.CAP then - self:RequestCAP(coordinate,altitude,leg,heading,speed,squadron) - end - + self:RequestMission(mission) end self:__AirwingStatus(-30) @@ -408,7 +432,7 @@ end function AIRWING:_GetNextMission() -- Number of missions. - local Nmissions=#self.Qmissions + local Nmissions=#self.missionqueue -- Treat special cases. if Nmissions==0 then @@ -419,16 +443,17 @@ function AIRWING:_GetNextMission() local function _sort(a, b) local taskA=a --#AIRWING.Mission local taskB=b --#AIRWING.Mission + --TODO: probably sort by prio first and then by time as only missions for T>Tstart are executed. That would ensure that the highest prio mission is carried ot first! return (taskA.Tstart=mission.Tstart and self:CanMission(mission.type, mission.nassets) then @@ -498,10 +523,49 @@ end function AIRWING:onafterAddMission(From, Event, To, Mission) -- Add Mission to queue. - table.insert(self.Qmission, Mission) + table.insert(self.missionqueue, Mission) end +--- On after "RequestMission" event. +-- @param #AIRWING self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #AIRWING.Missiondata Mission The requested mission. +function AIRWING:onafterRequestMission(From, Event, To, Mission) + + --TODO: request descriptor/attribute for given mission type! AWACS, Tankers, Fighters. + --TODO: also check that mission prio is same as warehouse prio (small=high or the other way around). + self:AddRequest(self, WAREHOUSE.Descriptor.ATTRIBUTE, GROUP.Attribute.AIR_FIGHTER, Mission.nassets, nil, nil, Mission.prio, tostring(Mission.mid)) + +end + +--- On after "AssetSpawned" event triggered when an asset group is spawned into the cruel world. +-- @param #AIRWING self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Group#GROUP group The group spawned. +-- @param #AIRWING.SquadronAsset asset The asset that was spawned. +-- @param Functional.Warehouse#WAREHOUSE.Pendingitem request The request of the dead asset. +function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request) + + -- Call parent warehouse function first. + self:GetParent(self).onafterAssetSpawned(self, From, Event, To, group, asset, request) + + local mid=tonumber(request.assignment) + + -- Set mission. + asset.mission=self:GetMissionByID(mid) + + -- Create flightgroup. + asset.flightgroup=FLIGHTGROUP:New(group:GetName()) + + -- Add mission to flightgroup queue. + asset.flightgroup:AddMission(asset.mission) + +end --- On after "SelfRequest" event. -- @param #AIRWING self @@ -514,83 +578,24 @@ function AIRWING:onafterSelfRequest(From, Event, To, groupset, request) -- Call parent warehouse function first. self:GetParent(self).onafterSelfRequest(self, From, Event, To, groupset, request) + + local mid=tonumber(request.assignment) + + local mission=self:GetMissionByID(mid) for _,_asset in pairs(request.assets) do - local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem - local a=asset.cargobay + local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem end - if request.assignment==AIRWING.Task.CAP then - for _,_group in pairs(groupset:GetSet()) do - local group=_group --Wrapper.Group#GROUP + for _,_group in pairs(groupset:GetSet()) do + local group=_group --Wrapper.Group#GROUP - local fg=FLIGHTGROUP:New(group:GetName()) - - fg:AddMission(request.mission) - - --self:LaunchCAP(group, coordinate, altitude, leg, speed, heading) - end - end end - ---- Request CAP. --- @param #AIRWING self --- @param #string From --- @param #string Event --- @param #string To --- @param Core.Point#COORDINATE coordinate --- @param #number altitude Altitude --- @param #number leg Race track length. --- @param #number heading Heading in degrees. --- @param #number speed Speed in knots. --- @param #AIRWING.Squadron squadron Explicitly request a specific squadron. -function AIRWING:onafterRequestCAP(From, Event, To, coordinate, altitude, leg, heading, speed, squadron) - - local n=self:GetNumberOfAssets(WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, false) - - if n>0 then - - self:AddRequest(self, WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, 1, nil, nil, nil, AIRWING.Task.CAP) - - else - MESSAGE:New("No CAP planes currently available", 5, "AIRWING"):ToCoalition(self:GetCoalition()) - self:__RequestCAP(-30, coordinate, altitude, leg, heading, speed, squadron) - end - -end - ---- Launch a CAP flight. --- @param #AIRWING self --- @param Ops.FlightGroup#FLIGHTGROUP flightgroup Flight group. --- @param Core.Point#COORDINATE capcoord Coordinate of CAP. --- @param #number alt Altitude in feet. Default 20000 ft. --- @param #number leg Length of race track pattern leg. Default 15 NM. --- @param #number heading Heading of race track in degrees. Default 180° i.e. from North to South. --- @param #number speed Speed in knots. -function AIRWING:LaunchCAP(flightgroup, capcoord, alt, leg, heading, speed) - - alt=UTILS.FeetToMeters(alt or 20000) - - speed=speed or 350 - leg=leg or 15 - - -- Task orbit. - local taskOrbit=flightgroup.group:TaskOrbit(capcoord, alt, UTILS.KnotsToMps(speed+50), capcoord:Translate(UTILS.NMToMeters(leg), heading)) - - flightgroup:AddWaypointAir(capcoord, 2, speed) - flightgroup:AddTaskWaypoint(taskOrbit, 2, "Orbit", 50, 60*60) - - - --TODO: flightcontrol would start up the aircraft. - flightgroup:StartUncontrolled(5) - -end - --- Create a new task name. -- @param #AIRWING self -- @param #string task Task of type @{#AIRWING.Task}. @@ -604,77 +609,6 @@ function AIRWING:_NewTaskName(task) return taskname end - ---- Request Intercept. --- @param #AIRWING self --- @param #string From --- @param #string Event --- @param #string To --- @param Wrapper.Group#GROUP bandits Group of bandits to intercept. --- @param #AIRWING.Squadron squadron Explicitly request a specific squadron. -function AIRWING:onafterRequestIntercept(From, Event, To, bandits, squadron) - - local n=self:GetNumberOfAssets(WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, false) - - if n>0 then - - self:__AddRequest(1, self, WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, 1, nil, nil, nil, AIRWING.Task.INTERCEPT) - - function self:OnAfterSelfRequest(From,Event,To,Groupset,Request) - local request=Request --Functional.Warehouse#WAREHOUSE.Pendingitem - local groupset=Groupset --Core.Set#SET_GROUP - - if Request.assignment==AIRWING.Task.INTERCEPT then - - for _,_group in pairs(groupset:GetSet()) do - local group=_group --Wrapper.Group#GROUP - - self:LaunchIntercept(group) - end - - end - end - - else - MESSAGE:New("No INTERCEPT fighters currently available", 5, "AIRWING"):ToCoalition(self:GetCoalition()) - end - -end - - - ---- Launch a flight group to intercept an intruder. --- @param #AIRWING self --- @param Wrapper.Group#GROUP group Interceptor flight group. --- @param Wrapper.Group#GROUP bandits Bandit group. -function AIRWING:LaunchIntercept(group, bandit) - - -- Task orbit. - local tasks={} - - for _,unit in pairs(bandit:GetUnits()) do - tasks[#tasks+1]=group:TaskAttackUnit(unit) - end - - local speed=group:GetSpeedMax() - local altitude=bandit:GetAltitude() - - -- Create waypoints. - local wp={} - wp[1]=self:GetCoordinate():WaypointAirTakeOffParking() - wp[2]=self:GetCoordinate():SetAltitude(altitude):WaypointAirTurningPoint(COORDINATE.WaypointAltType.BARO, speed, {tasks}, "Intercept") - - -- Start uncontrolled group. - group:StartUncontrolled() - - --airboss:SetExcludeAI() - - -- Route group - group:Route(wp) - -end - - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Misc Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -761,7 +695,7 @@ function AIRWING:ReportSquadrons() end - self:I(self.sid..text) + self:I(self.wid..text) MESSAGE:New(text, 10, "AIRWING", true):ToCoalition(self:GetCoalition()) end diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 5c4d4783e..4defb19fa 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -305,13 +305,17 @@ FLIGHTGROUP.TaskType={ --- Mission types. -- @type FLIGHTGROUP.MissionType --- @param #string INTERCEPT Intercept task. --- @param #string CAP Combat Air Patrol task. --- @param #string BAI Battlefield Air Interdiction task. +-- @param #string INTERCEPT Intercept. +-- @param #string CAP Combat Air Patrol. +-- @param #string BAI Battlefield Air Interdiction. -- @param #string SEAD Suppression/destruction of enemy air defences. --- @param #string STRIKE Strike task. --- @param #string AWACS AWACS task. --- @param #string TANKER Tanker task. +-- @param #string STRIKE Strike mission. +-- @param #string AWACS AWACS mission. +-- @param #string TANKER Tanker mission. +-- @param #string RECON Recon mission. +-- @param #string TRANSPORT Transport mission. +-- @param #string FERRY Ferry flight mission. +-- @param #string ANTISHIP Anti-ship mission. FLIGHTGROUP.MissionType={ INTERCEPT="Intercept", CAP="CAP", @@ -323,18 +327,20 @@ FLIGHTGROUP.MissionType={ TANKER="Tanker", RECON="Recon", TRANSPORT="Transport", + FERRY="Ferry Flight", + ANTISHIP="Anti Ship" } --- Mission status. -- @type FLIGHTGROUP.MissionStatus -- @field #string SCHEDULED Mission is scheduled. --- @field #string EXECUTING Mission is being executed. -- @field #string ASSIGNED Mission was assigned. +-- @field #string EXECUTING Mission is being executed. -- @field #string ACCOMPLISHED Mission is accomplished. FLIGHTGROUP.MissionStatus={ SCHEDULED="scheduled", + ASSIGNED="assigned", EXECUTING="executing", - ASSIGNED="assigned", ACCOMPLISHED="accomplished", FAILED="failed", } @@ -364,7 +370,7 @@ FLIGHTGROUP.MissionStatus={ --- FLIGHTGROUP class version. -- @field #string version -FLIGHTGROUP.version="0.2.6" +FLIGHTGROUP.version="0.3.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -1119,12 +1125,14 @@ function FLIGHTGROUP:CreateMissionCAP(Altitude, SpeedOrbit, Heading, Leg) mission.heading=Heading or 270 mission.leg=UTILS.NMToMeters(Leg or 10) + mission.type="bla" + return mission end --- Add mission to queue. -- @param #FLIGHTGROUP self --- @param FLIGHTGROUP.Mission Mission for this group. +-- @param #FLIGHTGROUP.Mission Mission Mission for this group. -- @param Core.Zone#ZONE Zone The mission zone. -- @param #number WaypointIndex The waypoint index. -- @param #string ClockStart Time the mission is started, e.g. "05:00" for 5 am. If specified as a #number, it will be relative (in seconds) to the current mission time. Default is 5 seconds after mission was added. @@ -1189,7 +1197,8 @@ function FLIGHTGROUP:AddMission(Mission, Zone, WaypointIndex, ClockStart, ClockS table.insert(self.missionqueue, mission) local text=string.format("Added %s mission %s at zone %s. Starting at %s. Stopping at %s", mission.type, mission.name, mission.zone:GetName(), UTILS.SecondsToClock(mission.Tstart, true), mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "never") - self:I(self.lid..text) + --self:I(self.lid..text) + self:I(text) return mission end diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index 35b3d3dcf..1ce505428 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -73,7 +73,7 @@ function INTEL:New(DetectionSet) self.detectionset=DetectionSet -- Set some string id for output to DCS.log file. - self.lid=string.format("INTEL %s | ", self.squadronname) + self.lid=string.format("INTEL %s | ", "KGB") -- Start State. self:SetStartState("Stopped") @@ -219,8 +219,6 @@ function INTEL:_UpdateIntel() local detectedlost=self.detectedunits:GetSetComplement(DetectedSet) - - end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Ops/WingCommander.lua b/Moose Development/Moose/Ops/WingCommander.lua index 86a6633c1..2a38154c5 100644 --- a/Moose Development/Moose/Ops/WingCommander.lua +++ b/Moose Development/Moose/Ops/WingCommander.lua @@ -15,9 +15,8 @@ -- @type WINGCOMMANDER -- @field #string ClassName Name of the class. -- @field #boolean Debug Debug mode. Messages to all about status. --- @field #string sid Class id string for output to DCS log file. --- @field #string livery Livery of the squadron. --- @field #table flights Table of flight groups. +-- @field #string ,id Class id string for output to DCS log file. +-- @field #table airwings Table of airwings. -- @extends Core.Fsm#FSM --- Be surprised! @@ -38,10 +37,21 @@ WINGCOMMANDER = { airwings = {}, } ---- Flight group element. --- @type WINGCOMMANDER.Flight --- @field Ops.FlightGroup#FLIGHTGROUP flightgroup The flight group object. --- @field #string mission Mission assigned to the flight. +--- Mission capability. +-- @type WINGCOMMANDER.Capability +-- @field #string missiontype Mission Type. +-- @field #number Ntot Total number of assets for this task. +-- @field #number Navail Number of available assets +-- @field #number Nonmission Number of assets currently on mission. + +--- Mission resources. +-- @type WINGCOMMANDER.Recourses +-- @field #string missiontype Mission Type. +-- @field #number Ntot Total number of assets for this task. +-- @field #number Navail Number of available assets +-- @field #number Nonmission Number of assets currently on mission. + + --- WINGCOMMANDER class version. -- @field #string version @@ -52,7 +62,7 @@ WINGCOMMANDER.version="0.0.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO: Add tasks. --- TODO: +-- TODO: ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor @@ -72,10 +82,6 @@ function WINGCOMMANDER:New(AgentSet) -- Start State. self:SetStartState("Stopped") - - - -- TODO Tasks? - self.tasks=tasks or {} -- Add FSM transitions. -- From State --> Event --> To State @@ -138,6 +144,8 @@ end -- @return #WINGCOMMANDER self function WINGCOMMANDER:SetLivery(liveryname) self.livery=liveryname + + return self end @@ -161,7 +169,7 @@ function WINGCOMMANDER:onafterStart(From, Event, To) self:__SitRep(-1) end ---- On after "FlightStatus" event. +--- On after "Sitrep" event. -- @param #WINGCOMMANDER self -- @param Wrapper.Group#GROUP Group Flight group. -- @param #string From From state. @@ -172,8 +180,18 @@ function WINGCOMMANDER:onafterSitrep(From, Event, To) -- FSM state. local fsmstate=self:GetState() + + -- Short info. local text=string.format("No activities") + + + local capabilities=self:CheckResources() + + -- Number of assets total, on mission, available + -- Number of assets available of each mission type. + + self:I(self.sid..text) if DetectedGroupsUnknown then @@ -184,14 +202,37 @@ function WINGCOMMANDER:onafterSitrep(From, Event, To) if group and group:IsAlive() then local category=group:GetCategory() + local attribute=group:GetAttribute() + local threatlevel=group:GetThreatLevel() - if category==Group.Category.AIRPLANE or category==Group.Category.AIRPLANE then + if category==Group.Category.AIRPLANE or category==Group.Category.HELICOPTER then + + if capability.INTERCEPT.Navail>0 then + + --TODO: Something like get closest AIRWING or squadron? + -- Launch even from multiple airwings? Currently Navail is like this. + + end elseif category==Group.Category.GROUND then + --TODO: action depends on type + -- AA/SAM ==> SEAD + -- Tanks ==> + -- Artillery ==> + -- Infantry ==> + -- + + if attribute==GROUP.Attribute.GROUND_AAA or attribute==GROUP.Attribute.GROUND_SAM then + + --TODO: SEAD/DEAD + + end + + elseif category==Group.Category.SHIP then - + --TODO: ANTISHIP end @@ -211,17 +252,27 @@ end --- Check resources. -- @param #WINGCOMMANDER self +-- @return #table function WINGCOMMANDER:CheckResources() - - for _,_airwing in pairs(self.airwings) do - local airwing=_airwing --Ops.AirWing#AIRWING - - airwing:GetFlightsWhoCan() + local capabilities={} + + for _,MissionType in pairs(FLIGHTGROUP.MissionType) do + capabilities[MissionType]=0 + for _,_airwing in pairs(self.airwings) do + local airwing=_airwing --Ops.AirWing#AIRWING + + -- Get Number of assets that can do this type of missions. + local _,nassets=airwing:CanMission(MissionType) + + -- Add up airwing resources. + capabilities[MissionType]=capabilities[MissionType]+nassets + end end + return capabilities end diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 8330da417..82616e283 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -173,6 +173,62 @@ GROUPTEMPLATE.Takeoff = { [GROUP.Takeoff.Cold] = { "TakeOffParking", "From Parking Area" } } +--- Generalized group attributes. See [DCS attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes) on hoggit. +-- @type GROUP.Attribute +-- @field #string AIR_TRANSPORTPLANE Airplane with transport capability. This can be used to transport other assets. +-- @field #string AIR_AWACS Airborne Early Warning and Control System. +-- @field #string AIR_FIGHTER Fighter, interceptor, ... airplane. +-- @field #string AIR_BOMBER Aircraft which can be used for strategic bombing. +-- @field #string AIR_TANKER Airplane which can refuel other aircraft. +-- @field #string AIR_TRANSPORTHELO Helicopter with transport capability. This can be used to transport other assets. +-- @field #string AIR_ATTACKHELO Attack helicopter. +-- @field #string AIR_UAV Unpiloted Aerial Vehicle, e.g. drones. +-- @field #string AIR_OTHER Any airborne unit that does not fall into any other airborne category. +-- @field #string GROUND_APC Infantry carriers, in particular Amoured Personell Carrier. This can be used to transport other assets. +-- @field #string GROUND_TRUCK Unarmed ground vehicles, which has the DCS "Truck" attribute. +-- @field #string GROUND_INFANTRY Ground infantry assets. +-- @field #string GROUND_ARTILLERY Artillery assets. +-- @field #string GROUND_TANK Tanks (modern or old). +-- @field #string GROUND_TRAIN Trains. Not that trains are **not** yet properly implemented in DCS and cannot be used currently. +-- @field #string GROUND_EWR Early Warning Radar. +-- @field #string GROUND_AAA Anti-Aircraft Artillery. +-- @field #string GROUND_SAM Surface-to-Air Missile system or components. +-- @field #string GROUND_OTHER Any ground unit that does not fall into any other ground category. +-- @field #string NAVAL_AIRCRAFTCARRIER Aircraft carrier. +-- @field #string NAVAL_WARSHIP War ship, i.e. cruisers, destroyers, firgates and corvettes. +-- @field #string NAVAL_ARMEDSHIP Any armed ship that is not an aircraft carrier, a cruiser, destroyer, firgatte or corvette. +-- @field #string NAVAL_UNARMEDSHIP Any unarmed naval vessel. +-- @field #string NAVAL_OTHER Any naval unit that does not fall into any other naval category. +-- @field #string OTHER_UNKNOWN Anything that does not fall into any other category. +GROUP.Attribute = { + AIR_TRANSPORTPLANE="Air_TransportPlane", + AIR_AWACS="Air_AWACS", + AIR_FIGHTER="Air_Fighter", + AIR_BOMBER="Air_Bomber", + AIR_TANKER="Air_Tanker", + AIR_TRANSPORTHELO="Air_TransportHelo", + AIR_ATTACKHELO="Air_AttackHelo", + AIR_UAV="Air_UAV", + AIR_OTHER="Air_OtherAir", + GROUND_APC="Ground_APC", + GROUND_TRUCK="Ground_Truck", + GROUND_INFANTRY="Ground_Infantry", + GROUND_ARTILLERY="Ground_Artillery", + GROUND_TANK="Ground_Tank", + GROUND_TRAIN="Ground_Train", + GROUND_EWR="Ground_EWR", + GROUND_AAA="Ground_AAA", + GROUND_SAM="Ground_SAM", + GROUND_OTHER="Ground_OtherGround", + NAVAL_AIRCRAFTCARRIER="Naval_AircraftCarrier", + NAVAL_WARSHIP="Naval_WarShip", + NAVAL_ARMEDSHIP="Naval_ArmedShip", + NAVAL_UNARMEDSHIP="Naval_UnarmedShip", + NAVAL_OTHER="Naval_OtherNaval", + OTHER_UNKNOWN="Other_Unknown", +} + + --- Create a new GROUP from a given GroupTemplate as a parameter. -- Note that the GroupTemplate is NOT spawned into the mission. -- It is merely added to the @{Core.Database}. @@ -2114,6 +2170,117 @@ function GROUP:GetDCSDesc(n) return nil end + +--- Get the generalized attribute of a self. +-- Note that for a heterogenious self, the attribute is determined from the attribute of the first unit! +-- @param #GROUP self +-- @return #string Generalized attribute of the self. +function GROUP:GetAttribute() + + -- Default + local attribute=GROUP.Attribute.OTHER_UNKNOWN --#GROUP.Attribute + + if self then + + ----------- + --- Air --- + ----------- + -- Planes + local transportplane=self:HasAttribute("Transports") and self:HasAttribute("Planes") + local awacs=self:HasAttribute("AWACS") + local fighter=self:HasAttribute("Fighters") or self:HasAttribute("Interceptors") or self:HasAttribute("Multirole fighters") or (self:HasAttribute("Bombers") and not self:HasAttribute("Strategic bombers")) + local bomber=self:HasAttribute("Strategic bombers") + local tanker=self:HasAttribute("Tankers") + local uav=self:HasAttribute("UAVs") + -- Helicopters + local transporthelo=self:HasAttribute("Transport helicopters") + local attackhelicopter=self:HasAttribute("Attack helicopters") + + -------------- + --- Ground --- + -------------- + -- Ground + local apc=self:HasAttribute("Infantry carriers") + local truck=self:HasAttribute("Trucks") and self:GetCategory()==Group.Category.GROUND + local infantry=self:HasAttribute("Infantry") + local artillery=self:HasAttribute("Artillery") + local tank=self:HasAttribute("Old Tanks") or self:HasAttribute("Modern Tanks") + local aaa=self:HasAttribute("AAA") + local ewr=self:HasAttribute("EWR") + local sam=self:HasAttribute("SAM elements") and (not self:HasAttribute("AAA")) + -- Train + local train=self:GetCategory()==Group.Category.TRAIN + + ------------- + --- Naval --- + ------------- + -- Ships + local aircraftcarrier=self:HasAttribute("Aircraft Carriers") + local warship=self:HasAttribute("Heavy armed ships") + local armedship=self:HasAttribute("Armed ships") + local unarmedship=self:HasAttribute("Unarmed ships") + + + -- Define attribute. Order is important. + if transportplane then + attribute=GROUP.Attribute.AIR_TRANSPORTPLANE + elseif awacs then + attribute=GROUP.Attribute.AIR_AWACS + elseif fighter then + attribute=GROUP.Attribute.AIR_FIGHTER + elseif bomber then + attribute=GROUP.Attribute.AIR_BOMBER + elseif tanker then + attribute=GROUP.Attribute.AIR_TANKER + elseif transporthelo then + attribute=GROUP.Attribute.AIR_TRANSPORTHELO + elseif attackhelicopter then + attribute=GROUP.Attribute.AIR_ATTACKHELO + elseif uav then + attribute=GROUP.Attribute.AIR_UAV + elseif apc then + attribute=GROUP.Attribute.GROUND_APC + elseif infantry then + attribute=GROUP.Attribute.GROUND_INFANTRY + elseif artillery then + attribute=GROUP.Attribute.GROUND_ARTILLERY + elseif tank then + attribute=GROUP.Attribute.GROUND_TANK + elseif aaa then + attribute=GROUP.Attribute.GROUND_AAA + elseif ewr then + attribute=GROUP.Attribute.GROUND_EWR + elseif sam then + attribute=GROUP.Attribute.GROUND_SAM + elseif truck then + attribute=GROUP.Attribute.GROUND_TRUCK + elseif train then + attribute=GROUP.Attribute.GROUND_TRAIN + elseif aircraftcarrier then + attribute=GROUP.Attribute.NAVAL_AIRCRAFTCARRIER + elseif warship then + attribute=GROUP.Attribute.NAVAL_WARSHIP + elseif armedship then + attribute=GROUP.Attribute.NAVAL_ARMEDSHIP + elseif unarmedship then + attribute=GROUP.Attribute.NAVAL_UNARMEDSHIP + else + if self:IsGround() then + attribute=GROUP.Attribute.GROUND_OTHER + elseif self:IsShip() then + attribute=GROUP.Attribute.NAVAL_OTHER + elseif self:IsAir() then + attribute=GROUP.Attribute.AIR_OTHER + else + attribute=GROUP.Attribute.OTHER_UNKNOWN + end + end + end + + return attribute +end + + do -- Route methods --- (AIR) Return the Group to an @{Wrapper.Airbase#AIRBASE}.