From 929f99d527d4c538697282347f185e522198cf76 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 28 Feb 2020 16:47:24 +0100 Subject: [PATCH] Ops --- Moose Development/Moose/Ops/AirWing.lua | 78 ++--- Moose Development/Moose/Ops/Auftrag.lua | 218 +++++++++---- Moose Development/Moose/Ops/FlightGroup.lua | 304 +++++++++--------- Moose Development/Moose/Ops/WingCommander.lua | 11 +- 4 files changed, 335 insertions(+), 276 deletions(-) diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index dd0e18f90..0810d426b 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -39,10 +39,9 @@ AIRWING = { Debug = false, lid = nil, menu = nil, - squadrons = nil, + squadrons = {}, missionqueue = {}, payloads = {}, - payloadcounter = nil, } --- Squadron data. @@ -84,7 +83,7 @@ AIRWING.version="0.1.2" -- DONE: Build mission queue. -- DONE: Find way to start missions. -- TODO: Check if missions are accomplished. --- TODO: Paylods as assets. +-- TODO: Payloads as resources. -- TODO: Spawn in air or hot. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -106,11 +105,6 @@ function AIRWING:New(warehousename, airwingname) return nil end - -- Squadrons. - self.squadrons={} - - self.payloadcounter=0 - -- Set some string id for output to DCS.log file. self.lid=string.format("AIRWING %s | ", self.alias) @@ -333,7 +327,10 @@ function AIRWING:AddMission(Mission, Nassets, WaypointCoordinate) Mission.waypointindex=nil -- Set status to scheduled. - Mission.status=AUFTRAG.Status.SCHEDULED + Mission.status=AUFTRAG.Status.QUEUED + + -- Todo call FSM event. + --Mission:Queue() -- Add mission to queue. table.insert(self.missionqueue, Mission) @@ -457,8 +454,7 @@ function AIRWING:_GetNextMission() local function _sort(a, b) local taskA=a --Ops.Auftrag#AUFTRAG local taskB=b --Ops.Auftrag#AUFTRAG - --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 out first! - return (taskA.Tstart=mission.Tstart then + if mission.status==AUFTRAG.Status.QUEUED and time>=mission.Tstart then -- Check if airwing can do the mission and gather required assets. local can, assets=self:CanMission(mission.type, mission.nassets) @@ -485,12 +481,13 @@ function AIRWING:_GetNextMission() --self:_OptimizeAssetSelection(assets, mission) -- TODO: check that mission.assets table is clean. - mission.assets=mission.assets or {} + mission.assets={} -- Assign assets to mission. for i=1,mission.nassets do local asset=assets[i] --#AIRWING.SquadronAsset + -- Get payload for the asset. asset.payload=self:FetchPayloadFromStock(asset.unittype, mission.type) if not asset.payload then @@ -619,7 +616,7 @@ function AIRWING:onafterMissionRequest(From, Event, To, Mission) -- Need to dived to set into spawned and instock assets and handle the other -- Assets to be requested - local areq={} + local Assetlist={} for _,_asset in pairs(Mission.assets) do local asset=_asset --#AIRWING.SquadronAsset @@ -628,20 +625,20 @@ function AIRWING:onafterMissionRequest(From, Event, To, Mission) if asset.flightgroup then --TODO: cancel current mission if there is any! - asset.flightgroup:AddMission(asset.mission, asset.mission.waypointcoord, asset.mission.waypointindex) + asset.flightgroup:AddMission(Mission, Mission.waypointcoord, Mission.waypointindex) else --TODO: create flightgroup. should already be there actually! end else -- These assets need to be requested and spawned. - table.insert(areq, asset) + table.insert(Assetlist, asset) end end -- Add request to airwing warehouse. - if #areq>0 then - self:AddRequest(self, WAREHOUSE.Descriptor.ASSETLIST, areq, #areq, nil, nil, Mission.prio, tostring(Mission.auftragsnummer)) + if #Assetlist>0 then + self:AddRequest(self, WAREHOUSE.Descriptor.ASSETLIST, Assetlist, #Assetlist, nil, nil, Mission.prio, tostring(Mission.auftragsnummer)) end end @@ -654,18 +651,17 @@ end -- @param Functional.Warehouse#WAREHOUSE.Queueitem Request Information table of the request. function AIRWING:onafterRequest(From, Event, To, Request) - -- Modify the cargo assets. + -- Assets local assets=Request.cargoassets + -- Get Mission local Mission=self:GetMissionByID(Request.assignment) if Mission and assets then for _,_asset in pairs(assets) do - local asset=_asset --#AIRWING.SquadronAsset - - --asset.payload=Mission.payload - + local asset=_asset --#AIRWING.SquadronAsset + -- This would be the place to modify the asset table before the asset is spawned. end end @@ -696,13 +692,9 @@ function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request) -- Add mission to flightgroup queue. if mission then - - -- Set mission. - -- TODO: This should not be necessary! - asset.mission=mission - + -- Add mission to flightgroup queue. - asset.flightgroup:AddMission(asset.mission, asset.mission.waypointcoord, asset.mission.waypointindex) + asset.flightgroup:AddMission(mission, mission.waypointcoord, mission.waypointindex) end end @@ -718,20 +710,16 @@ 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) + -- Get Mission + local mission=self:GetMissionByID(request.assignment) for _,_asset in pairs(request.assets) do - local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem + local asset=_asset --#AIRWING.SquadronAsset end - - + for _,_group in pairs(groupset:GetSet()) do - local group=_group --Wrapper.Group#GROUP - + local group=_group --Wrapper.Group#GROUP end end @@ -805,7 +793,6 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets) if not gotit then -- This squad cannot do this mission. - env.info("100") cando=false else @@ -814,13 +801,17 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets) -- Check if has already any missions in the queue. if self:IsAssetOnMission(asset) then - env.info("200") + + --- + -- This asset is already on a mission + --- + --TODO: This only checks if it has an ORBIT mission. It could have others as well! if self:IsAssetOnMission(asset, AUFTRAG.Type.ORBIT) then - env.info("300") + -- Check if the payload of this asset is compatible with the mission. if self:CheckMissionType(MissionType, asset.payload.missiontypes) then - -- TODO: check if asset actually has weapons left! + -- TODO: Check if asset actually has weapons left. Difficult! table.insert(assets, asset) end @@ -831,7 +822,7 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets) --- -- This asset as no current mission --- - env.info("400") + if asset.spawned then -- This asset is already spawned. Let's check if it has the right payload. if self:CheckMissionType(MissionType, asset.payload.missiontypes) then @@ -856,7 +847,6 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets) -- Check if required assets are present. if Nassets and Nassets > #assets then cando=false - env.info("500") end return cando, assets diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index ed21f2f1c..ef37d530f 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -21,30 +21,45 @@ -- @field #string type Mission type. -- @field #string status Mission status. -- @field #string name Mission name. --- @field #number mid Mission ID. -- @field #number prio Mission priority. -- @field #number Tstart Mission start time in seconds. -- @field #number Tstop Mission stop time in seconds. -- @field #number duration Mission duration in seconds. +-- @field #number marker F10 map marker ID. -- @field #table DCStask DCS task structure. +-- -- @field Core.Point#COORDINATE waypointcoord Coordinate of the waypoint task. -- @field #number waypointindex Waypoint number at which the task is executed. -- @field Ops.FlightGroup#FLIGHTGROUP.Task waypointtask Waypoint task. --- @field #number marker F10 map marker ID. +-- -- @field Core.Point#COORDINATE orbitCoord Coordinate where to orbit. -- @field #number orbitSpeed Orbit speed in m/s. -- @field #number orbitHeading Orbit heading in degrees. -- @field #number orbitLeg Length of orbit leg in meters. --- @field Core.Zone#ZONE_RADIUS zoneEngage *Circular* engagement zone. --- @field #table typeTargets Table of target types that are engaged in the engagement zone. --- @field Core.Point#COORDINATE coordTarget Coordinate of target location. --- @field Core.Set#SET_GROUP groupsetTargets Set of target groups to attack. --- @field #string squadname Name of the assigned squadron. --- @field #table assets Assets assigned for this mission. --- @field #number nassets Number of required assets. +-- +-- @field Core.Zone#ZONE_RADIUS engageZone *Circular* engagement zone. +-- @field #table engageTargetTypes Table of target types that are engaged in the engagement zone. +-- @field Core.Point#COORDINATE engageCoord Coordinate of target location. +-- @field Core.Set#SET_GROUP engageTargetGroupset Set of target groups to attack. +-- @field Core.Set#SET_GROUP engageTargetUnitset Set of target units to attack. +-- @field #number engageAltitude Engagement altitude in meters. +-- @field #number engageDirection Engagement direction in degrees. +-- @field #number engageQuantity Number of times a target is engaged. +-- @field #number engageWeaponType Weapon type used. +-- @field #number engageWeaponExpend How many weapons are used. +-- @field #boolean engageAsGroup Group attack. +-- @field #number engageMaxDistance Max engage distance. +-- +-- @field Wrapper.Group#GROUP escortGroup The group to be escorted. +-- @field DCS#Vec3 escortVec3 The 3D offset vector from the escorted group to the escort group. +-- +-- @field #string squadname Name of the assigned Airwing squadron. +-- @field #table assets Airwing Assets assigned for this mission. +-- @field #number nassets Number of required assets by the Airwing. +-- -- @extends Core.Fsm#FSM ---- *To invent an airplane is nothing. To build one is something. To fly is everything.* -- Otto Lilienthal +--- *A warrior's mission is to foster the success of others.* --- Morihei Ueshiba -- -- === -- @@ -55,7 +70,7 @@ -- # Events -- -- --- # Tasking +-- # Missions -- -- -- # Examples @@ -116,32 +131,31 @@ AUFTRAG.Type={ --- Mission status. -- @type AUFTRAG.Status -- @field #string PLANNED Mission is at the early planning stage. --- @field #string SCHEDULED Mission is scheduled in a queue waiting to be assigned. +-- @field #string QUEUED Mission is queued at an airwing. -- @field #string ASSIGNED Mission was assigned to somebody. +-- @field #string SCHEDULED Mission is scheduled in a FLIGHGROUP queue waiting to be started. -- @field #string STARTED Mission started but is not executed yet. -- @field #string EXECUTING Mission is being executed. -- @field #string DONE Mission is over. --- @field #string ANY The ANY "*" state. AUFTRAG.Status={ PLANNED="planned", - SCHEDULED="scheduled", + QUEUED="queued", ASSIGNED="assigned", + SCHEDULED="scheduled", STARTED="started", EXECUTING="executing", DONE="done", - ANY="Any", } --- AUFTRAG class version. -- @field #string version -AUFTRAG.version="0.0.1" +AUFTRAG.version="0.0.2" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO: A lot -- TODO: Mission ROE and ROT -- TODO: Mission formation, etc. -- TODO: FSM events. @@ -170,22 +184,33 @@ function AUFTRAG:New(Type) self.name=string.format("Auftrag #%d", self.auftragsnummer) + self.prio=50 + self.lid=string.format("Auftrag #%d %s | ", self.auftragsnummer, self.type) self:SetStartState(self.status) - --[[ - self:AddTransition(AUFTRAG.Status.PLANNED, "Start", AUFTRAG.Status.STARTED) -- Mission has started. - self:AddTransition(AUFTRAG.Status., "Start", AUFTRAG.Status.STARTED) -- Mission has started. - self:AddTransition("*", "Done", "*") -- Mission is over. - self:AddTransition(AUFTRAG.Status.ANY, "Update", AUFTRAG.Status.ANY) -- Mission is updated with latest data. - self:AddTransition("*", "Abort", "*") -- Mission is aborted. - ]] + -- PLANNED --> (QUEUED) --> (ASSIGNED) --> SCHEDULED --> STARTED --> EXECUTING --> DONE + self:AddTransition(AUFTRAG.Status.PLANNED, "Queue", AUFTRAG.Status.QUEUED) -- + self:AddTransition(AUFTRAG.Status.QUEUED, "Assign", AUFTRAG.Status.ASSIGNED) -- + self:AddTransition(AUFTRAG.Status.ASSIGNED, "Schedule", AUFTRAG.Status.SCHEDULED) -- + self:AddTransition(AUFTRAG.Status.PLANNED, "Schedule", AUFTRAG.Status.SCHEDULED) -- From planned directly to scheduled. + self:AddTransition(AUFTRAG.Status.SCHEDULED, "Start", AUFTRAG.Status.STARTED) -- + self:AddTransition(AUFTRAG.Status.STARTED, "Execute", AUFTRAG.Status.EXECUTING) -- + self:AddTransition(AUFTRAG.Status.EXECUTING, "Done", AUFTRAG.Status.DONE) -- + self:AddTransition("*", "Cancel", "Cancelled") + self:AddTransition("*", "Accomplished", "Success") + self:AddTransition("*", "Failed", "Failure") + return self end ---- Create a new AUFTRAG object and start the FSM. +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Create Missions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Create an ORBIT mission. -- @param #AUFTRAG self -- @param Core.Point#COORDINATE Coordinate Where to orbit. Altitude is also taken from the coordinate. -- @param #number Speed Orbit speed in knots. Default 350 kts. @@ -229,8 +254,8 @@ function AUFTRAG:NewCAP(OrbitCoordinate, OrbitSpeed, Heading, Leg, ZoneCAP, Targ -- CAP paramters. mission.type=AUFTRAG.Type.CAP - mission.zoneEngage=ZoneCAP or ZONE_RADIUS:New("CAP Zone", OrbitCoordinate:GetVec2(), mission.orbitLeg) - mission.typeTargets=TargetTypes or {"Air"} + mission.engageZone=ZoneCAP or ZONE_RADIUS:New("CAP Zone", OrbitCoordinate:GetVec2(), mission.orbitLeg) + mission.engageTargetTypes=TargetTypes or {"Air"} mission.DCStask=mission:GetDCSMissionTask() @@ -260,8 +285,8 @@ function AUFTRAG:NewCAS(OrbitCoordinate, OrbitSpeed, Heading, Leg, ZoneCAS, Targ -- CAS paramters. mission.type=AUFTRAG.Type.CAS - mission.zoneEngage=ZoneCAS or ZONE_RADIUS:New("CAS Zone", OrbitCoordinate:GetVec2(), Leg) - mission.typeTargets=TargetTypes or {"Helicopters", "Ground Units", "Light armed ships"} + mission.engageZone=ZoneCAS or ZONE_RADIUS:New("CAS Zone", OrbitCoordinate:GetVec2(), Leg) + mission.engageTargetTypes=TargetTypes or {"Helicopters", "Ground Units", "Light armed ships"} mission.DCStask=mission:GetDCSMissionTask() @@ -273,14 +298,14 @@ end --- Create a STRIKE mission. Flight will attack a specified coordinate. -- @param #AUFTRAG self -- @param Core.Point#COORDINATE Coordinate Target Coordinate. --- @param #number Altitude Attack altitude in feet. Default 1000. +-- @param #number Altitude Engage altitude in feet. Default 1000. -- @return #AUFTRAG self function AUFTRAG:NewSTRIKE(TargetCoordinate, Altitude) local mission=AUFTRAG:New(AUFTRAG.Type.STRIKE) - mission.coordTarget=TargetCoordinate - mission.altitude=UTILS.FeetToMeters(Altitude or 1000) + mission.engageCoord=TargetCoordinate + mission.engageAltitude=UTILS.FeetToMeters(Altitude or 1000) mission.DCStask=mission:GetDCSMissionTask() @@ -300,8 +325,8 @@ function AUFTRAG:NewINTERCEPT(TargetGroupSet) local mission=AUFTRAG:New(AUFTRAG.Type.INTERCEPT) - mission.groupsetTargets=TargetGroupSet - mission.groupsetTargets:FilterDeads():FilterCrashes() + mission.engageTargetGroupset=TargetGroupSet + mission.engageTargetGroupset:FilterDeads():FilterCrashes() mission.DCStask=mission:GetDCSMissionTask() @@ -321,8 +346,8 @@ function AUFTRAG:NewBAI(TargetGroupSet) local mission=AUFTRAG:New(AUFTRAG.Type.BAI) - mission.groupsetTargets=TargetGroupSet - mission.groupsetTargets:FilterDeads():FilterCrashes() + mission.engageTargetGroupset=TargetGroupSet + mission.engageTargetGroupset:FilterDeads():FilterCrashes() mission.DCStask=mission:GetDCSMissionTask() @@ -371,7 +396,7 @@ end --- Set mission priority. -- @param #AUFTRAG self --- @param #number Prio Priority 1=high, 100=low. Default 50 +-- @param #number Prio Priority 1=high, 100=low. Default 50. -- @return #AUFTRAG self function AUFTRAG:SetPriority(Prio) self.prio=Prio or 50 @@ -387,6 +412,25 @@ function AUFTRAG:SetName(Name) return self end +--- Set weapon type used for the engagement. +-- @param #AUFTRAG self +-- @param #number WeaponType Weapon type. Default is ENUMS.WeaponFlag.Auto +-- @return #AUFTRAG self +function AUFTRAG:SetWeaponType(WeaponType) + + self.engageWeaponType=WeaponType or ENUMS.WeaponFlag.Auto + + -- Update the DCS task parameter. + self.DCStask=self:GetDCSMissionTask() + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- FSM Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Misc Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -397,29 +441,30 @@ end function AUFTRAG:CountMissionTargets() local N=0 - if self.groupsetTargets then - local n=self.groupsetTargets:CountAlive() + if self.engageTargetGroupset then + local n=self.engageTargetGroupset:CountAlive() N=N+n end - if self.unitsetTargets then - local n=self.unitsetTargets:CountAlive() + if self.engageTargetUnitset then + local n=self.engageTargetUnitset:CountAlive() N=N+n end return N end ---- Count alive mission targets. +--- Get coordinate of target. First unit/group of the set is used. -- @param #AUFTRAG self -- @param Core.Point#COORDINATE The target coordinate or nil. function AUFTRAG:GetTargetCoordinate() - if self.groupsetTargets then - local group=self.groupsetTargets:GetFirst() --Wrapper.Group#GROUP + if self.engageTargetGroupset then + + local group=self.engageTargetGroupset:GetFirst() --Wrapper.Group#GROUP return group:GetCoordinate() - elseif self.unitsetTargets then - local unit=self.unitsetTargets:GetFirst() --Wraper.Unit#UNIT + elseif self.engageTargetUnitset then + local unit=self.engageTargetUnitset:GetFirst() --Wrapper.Unit#UNIT return unit:GetCoordinate() end @@ -440,13 +485,22 @@ function AUFTRAG:GetDCSMissionTask() -- ANTISHIP Mission -- ---------------------- - local DCStask=CONTROLLABLE.TaskAttackUnit(nil, AttackUnit, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType) + for _,_unit in pairs(self.engageTargetUnitset:GetSet()) do + local TargetUnit=_unit + + local DCStask=CONTROLLABLE.TaskAttackUnit(nil, TargetUnit, self.engageAltitude, self.WeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType) + + end elseif self.type==AUFTRAG.Type.AWACS then ------------------- -- AWACS Mission -- ------------------- + + local DCStask=CONTROLLABLE.EnRouteTaskAWACS(nil) + + table.insert(DCStasks, DCStask) elseif self.type==AUFTRAG.Type.BAI then @@ -454,10 +508,10 @@ function AUFTRAG:GetDCSMissionTask() -- BAI Mission -- ----------------- - for _,_group in pairs(self.groupsetTargets:GetSet()) do + for _,_group in pairs(self.engageTargetGroupset:GetSet()) do local TargetGroup=_group - local DCStask=CONTROLLABLE.TaskAttackGroup(nil, TargetGroup, ENUMS.WeaponFlag.Auto, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit) + local DCStask=CONTROLLABLE.TaskAttackGroup(nil, TargetGroup, self.engageWeaponType, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude) table.insert(DCStasks, DCStask) end @@ -468,18 +522,19 @@ function AUFTRAG:GetDCSMissionTask() -- BOMBING Mission -- --------------------- + local Vec2=self.engageCoord:GetVec2() + + local DCStask=CONTROLLABLE.TaskBombing(self,Vec2, self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, Divebomb) + + table.insert(DCStasks, DCStask) + elseif self.type==AUFTRAG.Type.CAP then ----------------- -- CAP Mission -- ----------------- - local CoordRaceTrack=self.orbitCoord:Translate(self.orbitLeg, self.orbitHeading, true) - - local DCStask=CONTROLLABLE.TaskOrbit(nil, self.orbitCoord, self.orbitCoord.y, self.orbitSpeed, CoordRaceTrack) - - -- TODO! Could be added in the same task! - self:AddTaskEnrouteEngageTargetsInZone(self.zoneEngage, self.typeTargets, self.prio) + local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(self.engageZone:GetVec2(), self.engageZone:GetRadius(), self.engageTargetTypes, Priority) table.insert(DCStasks, DCStask) @@ -489,11 +544,7 @@ function AUFTRAG:GetDCSMissionTask() -- CAS Mission -- ----------------- - local CoordRaceTrack=self.orbitCoord:Translate(self.orbitLeg, self.orbitHeading, true) - - local DCStask=CONTROLLABLE.TaskOrbit(nil, self.orbitCoord, self.orbitCoord.y, self.orbitSpeed, CoordRaceTrack) - - self:AddTaskEnrouteEngageTargetsInZone(self.zoneEngage, self.typeTargets, self.prio) + local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(self.engageZone:GetVec2(), self.engageZone:GetRadius(), self.engageTargetTypes, Priority) table.insert(DCStasks, DCStask) @@ -503,7 +554,9 @@ function AUFTRAG:GetDCSMissionTask() -- ESCORT Mission -- -------------------- - local DCStask=CONTROLLABLE.TaskEscort(nil, FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes) + local DCStask=CONTROLLABLE.TaskEscort(nil, self.escortGroup, self.escortVec3, LastWaypointIndex, self.engageMaxDistance, self.engageTargetTypes) + + table.insert(DCStasks, DCStask) elseif self.type==AUFTRAG.Type.FACA then @@ -511,7 +564,9 @@ function AUFTRAG:GetDCSMissionTask() -- FAC Mission -- ----------------- - local DCStask=CONTROLLABLE.TaskFAC_AttackGroup(nil, AttackGroup, WeaponType, Designation, Datalink) + local DCStask=CONTROLLABLE.TaskFAC_AttackGroup(nil, self.engageAsGroup, self.engageWeaponType, Designation, Datalink) + + table.insert(DCStasks, DCStask) elseif self.type==AUFTRAG.Type.FERRY then @@ -525,10 +580,10 @@ function AUFTRAG:GetDCSMissionTask() -- INTERCEPT Mission -- ----------------------- - for _,group in pairs(self.groupsetTargets:GetSet()) do + for _,group in pairs(self.engageTargetGroupset:GetSet()) do local TargetGroup=group --Wrapper.Group#GROUP - local DCStask=CONTROLLABLE.TaskAttackGroup(nil, TargetGroup, ENUMS.WeaponFlag.Auto, WeaponExpend, AttackQty, Direction, Altitude, AttackQtyLimit) + local DCStask=CONTROLLABLE.TaskAttackGroup(nil, TargetGroup, self.engageWeaponType, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude) table.insert(DCStasks, DCStask) end @@ -538,12 +593,8 @@ function AUFTRAG:GetDCSMissionTask() ------------------- -- ORBIT Mission -- ------------------- - - local CoordRaceTrack=self.orbitCoord:Translate(self.orbitLeg, self.orbitHeading, true) - local DCStask=CONTROLLABLE.TaskOrbit(nil, self.orbitCoord, self.orbitCoord.y, self.orbitSpeed, CoordRaceTrack) - - table.insert(DCStasks, DCStask) + -- Done below as also other mission types use the orbit task. elseif self.type==AUFTRAG.Type.RECON then @@ -557,9 +608,9 @@ function AUFTRAG:GetDCSMissionTask() -- STIKE Mission -- ------------------- - local Vec2=self.coordtarget:GetVec2() + local Vec2=self.engageCoord:GetVec2() - local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, self.altitude, WeaponType) + local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, Vec2, self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType) table.insert(DCStasks, DCStask) @@ -568,13 +619,38 @@ function AUFTRAG:GetDCSMissionTask() -------------------- -- TANKER Mission -- -------------------- + + local DCStask=CONTROLLABLE.EnRouteTaskTanker(nil) + + table.insert(DCStasks, DCStask) elseif self.type==AUFTRAG.Type.TRANSPORT then + + ----------------------- + -- TRANSPORT Mission -- + ----------------------- else self:E(self.lid..string.format("ERROR: Unknown mission task!")) return nil end + + + -- Set ORBIT task. Also applies to other missions: AWACS, TANKER, CAP, CAS. + if self.type==AUFTRAG.Type.ORBIT or self.type==AUFTRAG.Type.CAP or self.type==AUFTRAG.Type.CAS or self.type==AUFTRAG.Type.AWACS or self.type==AUFTRAG.Type.TANKER then + + ------------------- + -- ORBIT Mission -- + ------------------- + + local CoordRaceTrack=self.orbitCoord:Translate(self.orbitLeg, self.orbitHeading, true) + + local DCStask=CONTROLLABLE.TaskOrbit(nil, self.orbitCoord, self.orbitCoord.y, self.orbitSpeed, CoordRaceTrack) + + table.insert(DCStasks, DCStask) + + end + if #DCStasks==1 then return DCStasks[1] diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index fbdcf4577..22de998ae 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -32,7 +32,7 @@ -- @field #table taskenroute Enroute task of the group. -- @field #table taskpaused Paused tasks. -- @field #table missionqueue Queue of missions. --- @field Ops.Auftrag#AUFTRAG currentmission The mission currently assigned or executed. +-- @field #number currentmission The ID (auftragsnummer) of the currently assigned AUFTRAG. -- @field Core.Set#SET_UNIT detectedunits Set of detected units. -- @field Wrapper.Airbase#AIRBASE homebase The home base of the flight group. -- @field Wrapper.Airbase#AIRBASE destbase The destination base of the flight group. @@ -329,7 +329,7 @@ FLIGHTGROUP.version="0.3.2" -- DONE: Fuel threshhold ==> RTB. -- TODO: ROE, Afterburner restrict. -- TODO: Add EPLRS, TACAN. --- TODO: Respawn? With correct loadout, fuelstate. +-- NOGO: Respawn? With correct loadout, fuelstate. Solved in DCS 2.5.6 -- TODO: Damage? -- TODO: shot events? -- TODO: Marks to add waypoints/tasks on-the-fly. @@ -426,12 +426,12 @@ function FLIGHTGROUP:New(groupname, autostart) self:AddTransition("*", "TaskDone", "*") -- Task is over. self:AddTransition("*", "MissionStart", "*") -- Mission is started. - self:AddTransition("*", "MissionUpdate", "*") -- Mission is updated with latest data. + self:AddTransition("*", "MissionExecute", "*") -- Mission execution began. self:AddTransition("*", "MissionCancel", "*") -- Cancel current mission. self:AddTransition("*", "MissionDone", "*") -- Mission is over. - self:AddTransition("Airborne", "EngageTarget", "Engaging") -- Pause current task. - self:AddTransition("Engaging", "Disengage", "Airborne") -- Pause current task. + self:AddTransition("Airborne", "EngageTargets", "Engaging") -- Engage targets. + self:AddTransition("Engaging", "Disengage", "Airborne") -- Engagement over. self:AddTransition("*", "ElementSpawned", "*") -- An element was spawned. self:AddTransition("*", "ElementParking", "*") -- An element is parking. @@ -1333,7 +1333,8 @@ function FLIGHTGROUP:onafterFlightStatus(From, Event, To) --- -- Current mission name. - local mymission=self.currentmission and self.currentmission.name or "N/A" + local Mission=self:GetMissionByID(self.currentmission) + local mymission=Mission and Mission.name or "none" -- Current status. local text=string.format("Missions=%d Current: %s", #self.missionqueue, mymission) @@ -1462,16 +1463,8 @@ function FLIGHTGROUP:_GetNextTask() return nil end - -- Sort results table wrt times they have already been engaged. - local function _sort(a, b) - local taskA=a --#FLIGHTGROUP.Task - local taskB=b --#FLIGHTGROUP.Task - --TODO: better sort by prio first as only tasks which are due are considered to be executed! - return (taskA.time0 then @@ -2778,13 +2775,8 @@ function FLIGHTGROUP:GetTasksWaypoint(n) -- Tasks table. local tasks={} - -- Sort results table wrt times they have already been engaged. - local function _sort(a, b) - local taskA=a --#FLIGHTGROUP.Task - local taskB=b --#FLIGHTGROUP.Task - return (taskA.time Mission Done! - if self.currentmission and self.currentmission.waypointtask and self.currentmission.waypointtask.id==Task.id then - self:MissionDone(self.currentmission) + local Mission=self:GetMissionByTaskID(Task.id) + if Mission then + self:MissionDone(Mission) end -- Update route. This is necessary because of the route task being overwritten. But we want to fly to the remaining waypoints. @@ -3004,38 +3015,6 @@ function FLIGHTGROUP:onafterTaskDone(From, Event, To, Task) end ---- Function called when a task is executed. ---@param Wrapper.Group#GROUP group Group that reached the holding zone. ---@param #FLIGHTGROUP flightgroup Flight group. ---@param #FLIGHTGROUP.Task task Task. -function FLIGHTGROUP._TaskExecute(group, flightgroup, task) - - -- Debug message. - local text=string.format("_TaskExecute %s", task.description) - flightgroup:I(flightgroup.lid..text) - - -- Set current task to nil so that the next in line can be executed. - if flightgroup then - flightgroup:TaskExecute(task) - end -end - ---- Function called when a task is done. ---@param Wrapper.Group#GROUP group Group that reached the holding zone. ---@param #FLIGHTGROUP flightgroup Flight group. ---@param #FLIGHTGROUP.Task task Task. -function FLIGHTGROUP._TaskDone(group, flightgroup, task) - - -- Debug message. - local text=string.format("_TaskDone %s", task.description) - flightgroup:I(flightgroup.lid..text) - - -- Set current task to nil so that the next in line can be executed. - if flightgroup then - flightgroup:TaskDone(task) - end -end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Mission functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -3084,19 +3063,31 @@ function FLIGHTGROUP:onafterMissionStart(From, Event, To, Mission) MESSAGE:New(text, 120, "DEBUG"):ToAllIf(true) -- Set current mission. - self.currentmission=Mission - - -- Set Tstarted time stamp. - self.currentmission.Tstarted=timer.getAbsTime() - + self.currentmission=Mission.auftragsnummer + -- Set mission status. - self.currentmission.status=AUFTRAG.Status.STARTED + Mission.status=AUFTRAG.Status.STARTED -- Route flight to mission zone. self:RouteToMission(Mission, 5) end +--- On after "MissionExecute" event. Mission execution began. +-- @param #FLIGHTGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Ops.Auftrag#AUFTRAG Mission The mission table. +function FLIGHTGROUP:onafterMissionExecute(From, Event, To, Mission) + + local text=string.format("Executing Mission %s", tostring(Mission.name)) + MESSAGE:New(text, 120, "DEBUG"):ToAllIf(true) + + Mission.status=AUFTRAG.Status.EXECUTING + +end + --- On after "MissionCancel" event. Cancels the current mission. -- @param #FLIGHTGROUP self -- @param #string From From state. @@ -3105,11 +3096,13 @@ end function FLIGHTGROUP:onafterMissionCancel(From, Event, To) if self.currentmission then - - local task=self.currentmission.waypointtask - + + -- Cancelling the mission is actually cancelling the current task. self:TaskCancel() + else + + end end @@ -3136,20 +3129,6 @@ function FLIGHTGROUP:onafterMissionDone(From, Event, To, Mission) end ---- On after "MissionUpdate" event. --- @param #FLIGHTGROUP self --- @param #string From From state. --- @param #string Event Event. --- @param #string To To state. --- @param Ops.Auftrag#AUFTRAG Mission -function FLIGHTGROUP:onafterMissionUpdate(From, Event, To, Mission) - - if Mission.groupsetTarget then - - end - -end - --- Route group to mission. -- @param #FLIGHTGROUP self -- @param Ops.Auftrag#AUFTRAG mission The mission table. @@ -3179,9 +3158,41 @@ function FLIGHTGROUP:RouteToMission(mission, delay) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Route functions +-- Special Task Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Function called when a task is executed. +--@param Wrapper.Group#GROUP group Group that reached the holding zone. +--@param #FLIGHTGROUP flightgroup Flight group. +--@param #FLIGHTGROUP.Task task Task. +function FLIGHTGROUP._TaskExecute(group, flightgroup, task) + + -- Debug message. + local text=string.format("_TaskExecute %s", task.description) + flightgroup:I(flightgroup.lid..text) + + -- Set current task to nil so that the next in line can be executed. + if flightgroup then + flightgroup:TaskExecute(task) + end +end + +--- Function called when a task is done. +--@param Wrapper.Group#GROUP group Group that reached the holding zone. +--@param #FLIGHTGROUP flightgroup Flight group. +--@param #FLIGHTGROUP.Task task Task. +function FLIGHTGROUP._TaskDone(group, flightgroup, task) + + -- Debug message. + local text=string.format("_TaskDone %s", task.description) + flightgroup:I(flightgroup.lid..text) + + -- Set current task to nil so that the next in line can be executed. + if flightgroup then + flightgroup:TaskDone(task) + end +end + --- Function called when a group is passing a waypoint. --@param Wrapper.Group#GROUP group Group that passed the waypoint --@param #FLIGHTGROUP flightgroup Flightgroup object. @@ -3191,48 +3202,24 @@ function FLIGHTGROUP._PassingWaypoint(group, flightgroup, i) local final=#flightgroup.waypoints or 1 -- Debug message. - local text=string.format("Group %s passing waypoint %d of %d.", group:GetName(), i, final) - env.info(text) - - -- Debug smoke and marker. - if flightgroup.Debug then - local pos=group:GetCoordinate() - --pos:SmokeRed() - --local MarkerID=pos:MarkToAll(string.format("Group %s reached waypoint %d", group:GetName(), i)) - end - - -- Debug message. + local text=string.format("Group passing waypoint %d of %d.", group:GetName(), i, final) flightgroup:T3(flightgroup.lid..text) -- Set current waypoint. flightgroup.currentwp=i - -- Passing Waypoint event. + -- Trigger PassingWaypoint event. flightgroup:PassingWaypoint(i, final) - -- If final waypoint reached. - if i==final then - - if flightgroup.destbase then - flightgroup:__RTB(-10) - elseif flightgroup.destzone then - flightgroup:__RTZ(-10) - end - - end - end --- Function called when flight has reached the holding point. -- @param Wrapper.Group#GROUP group Group object. -- @param #FLIGHTGROUP flightgroup Flight group object. function FLIGHTGROUP._ReachedHolding(group, flightgroup) - flightgroup:T(flightgroup.lid..string.format("Group %s reached holding point", group:GetName())) - - if flightgroup.Debug then - group:GetCoordinate():MarkToAll("Holding Point Reached") - end - + flightgroup:T(flightgroup.lid..string.format("Group reached holding point")) + + -- Trigger Holding event. flightgroup:__Holding(-1) end @@ -3244,49 +3231,10 @@ function FLIGHTGROUP._DestinationOverhead(group, flightgroup, destination) -- Tell the flight to hold. -- WARNING: This needs to be delayed or we get a CTD! - flightgroup:__Hold(-1, destination) + flightgroup:__RTB(-1, destination) end - ---- Route flight group to orbit. --- @param #FLIGHTGROUP self --- @param Core.Point#COORDINATE CoordOrbit Orbit coordinate. --- @param #number Speed Speed in km/h. Default 60% of max group speed. --- @param #number Altitude Altitude in meters. Default 10,000 ft. --- @param Core.Point#COORDINATE CoordRaceTrack (Optional) Race track coordinate. -function FLIGHTGROUP:RouteOrbit(CoordOrbit, Speed, Altitude, CoordRaceTrack) - - -- If speed is not given take 80% of max speed. - Speed=Speed or self.group:GetSpeedMax()*0.6 - - -- Altitude. - local altitude=Altitude or UTILS.FeetToMeters(10000) - - -- Waypoints. - local wp={} - - -- Current coordinate. - wp[1]=self.group:GetCoordinate():SetAltitude(altitude):WaypointAirTurningPoint(nil, Speed, {}, "Current") - - -- Orbit - wp[2]=CoordOrbit:SetAltitude(altitude):WaypointAirTurningPoint(nil, Speed, {}, "Orbit") - - - local TaskOrbit=self.group:TaskOrbit(CoordOrbit, altitude, Speed, CoordRaceTrack) - local TaskRoute=self.group:TaskRoute(wp) - - --local TaskCondi=self.group:TaskCondition(time,userFlag,userFlagValue,condition,duration,lastWayPoint) - - local TaskCombo=self.group:TaskControlled(TaskRoute, TaskOrbit) - - self:SetTask(TaskCombo, 1) - - -- Route the group or this will not work. - --self.group:Route(wp, 1) -end - - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Misc functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -3689,6 +3637,48 @@ function FLIGHTGROUP:GetTaskByID(id, status) return nil end +--- Get mission by its id (auftragsnummer). +-- @param #FLIGHTGROUP self +-- @param #number id Mission id (auftragsnummer). +-- @return Ops.Auftrag#AUFTRAG The mission. +function FLIGHTGROUP:GetMissionByID(id) + + if not id then + return nil + end + + for _,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + + if mission.auftragsnummer==id then + return mission + end + + end + + return nil +end + +--- Get mission by its task id. +-- @param #FLIGHTGROUP self +-- @param #number taskid The id of the (waypoint) task of the mission. +-- @return Ops.Auftrag#AUFTRAG The mission. +function FLIGHTGROUP:GetMissionByTaskID(taskid) + + for _,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + + local task=mission.waypointtask + + if task and task.id and task.id==taskid then + return mission + end + + end + + return nil +end + --- Get next waypoint of the flight group. -- @param #FLIGHTGROUP self diff --git a/Moose Development/Moose/Ops/WingCommander.lua b/Moose Development/Moose/Ops/WingCommander.lua index f184e981e..2866f89e7 100644 --- a/Moose Development/Moose/Ops/WingCommander.lua +++ b/Moose Development/Moose/Ops/WingCommander.lua @@ -137,12 +137,15 @@ end -- User functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Set livery. +--- Add an airwing to the wingcommander. -- @param #WINGCOMMANDER self --- @param #string liveryname Name of the livery. +-- @param Ops.AirWing#AIRWING Airwing The airwing to add. -- @return #WINGCOMMANDER self -function WINGCOMMANDER:SetLivery(liveryname) - self.livery=liveryname +function WINGCOMMANDER:AddAirwing(Airwing) + + --table.insert(self.airwings, Airwing) + + self.airwings[Airwing.alias]=Airwing return self end