From 15d7c36d8f0476bc57e36e0714992f69ad664630 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 17 Jun 2019 23:50:03 +0200 Subject: [PATCH] CVW --- Moose Development/Moose/Modules.lua | 1 + Moose Development/Moose/Ops/Airboss.lua | 2 +- .../Moose/Ops/CarrierAirWing.lua | 536 ++++++++++++++++++ Moose Development/Moose/Ops/Skipper.lua | 247 ++------ 4 files changed, 579 insertions(+), 207 deletions(-) create mode 100644 Moose Development/Moose/Ops/CarrierAirWing.lua diff --git a/Moose Development/Moose/Modules.lua b/Moose Development/Moose/Modules.lua index fb1f44800..7a946024f 100644 --- a/Moose Development/Moose/Modules.lua +++ b/Moose Development/Moose/Modules.lua @@ -69,6 +69,7 @@ __Moose.Include( 'Scripts/Moose/Ops/RecoveryTanker.lua' ) __Moose.Include( 'Scripts/Moose/Ops/RescueHelo.lua' ) __Moose.Include( 'Scripts/Moose/Ops/FlightControl.lua' ) __Moose.Include( 'Scripts/Moose/Ops/Skipper.lua' ) +__Moose.Include( 'Scripts/Moose/Ops/CarrierAirWing.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Balancer.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Air.lua' ) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 0764f2490..385016112 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -13588,7 +13588,7 @@ function AIRBOSS._PassingWaypoint(group, airboss, i, final) -- If final waypoint reached, do route all over again. if i==final and final>1 and airboss.adinfinitum then - airboss:_PatrolRoute(i) + airboss:_PatrolRoute() end end diff --git a/Moose Development/Moose/Ops/CarrierAirWing.lua b/Moose Development/Moose/Ops/CarrierAirWing.lua new file mode 100644 index 000000000..650efc951 --- /dev/null +++ b/Moose Development/Moose/Ops/CarrierAirWing.lua @@ -0,0 +1,536 @@ +--- **CVW** - (R2.5) - Carrier Air Wing (CVW) Warehouse. +-- +-- **Main Features:** +-- +-- * Nice stuff. +-- +-- === +-- +-- ### Author: **funkyfranky** +-- @module Ops.CVW +-- @image OPS_CarrierAirWing.png + + +--- CVW class. +-- @type CVW +-- @field #string ClassName Name of the class. +-- @field #boolean Debug Debug mode. Messages to all about status. +-- @field #string cid Class id string for output to DCS log file. +-- @field #string carriername The name of the carrier unit. +-- @field Wrapper.Group#GROUP group The carrier strike group. +-- @field #table menu Table of menu items. +-- @extends Functional.Warehouse#WAREHOUSE + +--- Be surprised! +-- +-- === +-- +-- ![Banner Image](..\Presentations\CarrierAirWing\CVW_Main.jpg) +-- +-- # The CVW Concept +-- +-- +-- +-- @field #CVW +CVW = { + ClassName = "CVW", + sid = nil, + carriername = nil, + group = nil, + menu = nil, +} + +--- Squadron +-- @type CVW.Squadron +-- @field Wrapper.Group#GROUP group Intruder group object. +-- @field #string groupname Name of the intruder group. +-- @field #number time0 Abs. mission time first detected inside CCA. +-- @field #number dist0 Distance first detected inside CCA. +-- @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 defence menu entries. + +--- FlightControl class version. +-- @field #string version +CVW.version="0.0.1" + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- TODO list +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +-- TODO: A lot! + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Constructor +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Create a new CVW class object for a specific aircraft carrier unit. +-- @param #CVW self +-- @param #string carriername Name of the carrier. +-- @param #string alias Skipper alias. +-- @return #CVW self +function CVW:New(carriername, alias) + + -- Inherit everything from WAREHOUSE class. + local self=BASE:Inherit(self, WAREHOUSE:New(carriername, alias)) -- #CVW + + if not self.carrier then + BASE:E(string.format("ERROR: Could not find carrier %s!", carriername)) + return nil + end + + self.carriername=carriername + + self.group=self.carrier:GetGroup() + + + -- Set some string id for output to DCS.log file. + self.sid=string.format("CVW %s |", self.carriername) + + -- Add FSM transitions. + -- From State --> Event --> To State + self:AddTransition("*", "AirwingStatus", "*") -- Skipper status update. + self:AddTransition("*", "RequestCAP", "*") -- New intruder detected. + + ------------------------ + --- Pseudo Functions --- + ------------------------ + + --- Triggers the FSM event "Start". Starts the CVW. Initializes parameters and starts event handlers. + -- @function [parent=#CVW] Start + -- @param #CVW self + + --- Triggers the FSM event "Start" after a delay. Starts the CVW. Initializes parameters and starts event handlers. + -- @function [parent=#CVW] __Start + -- @param #CVW self + -- @param #number delay Delay in seconds. + + --- Triggers the FSM event "Stop". Stops the CVW and all its event handlers. + -- @param #CVW self + + --- Triggers the FSM event "Stop" after a delay. Stops the CVW and all its event handlers. + -- @function [parent=#CVW] __Stop + -- @param #CVW self + -- @param #number delay Delay in seconds. + + --- Triggers the FSM event "SkipperStatus". + -- @function [parent=#CVW] SkipperStatus + -- @param #CVW self + + --- Triggers the FSM event "SkipperStatus" after a delay. + -- @function [parent=#CVW] __SkipperStatus + -- @param #CVW self + -- @param #number delay Delay in seconds. + + + -- Debug trace. + if true then + self.Debug=true + BASE:TraceOnOff(true) + BASE:TraceClass(self.ClassName) + BASE:TraceLevel(1) + end + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- User Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Optimized F10 radio menu for a single carrier. The menu entries will be stored directly under F10 Other/Skipper/ and not F10 Other/Skipper/"Carrier Alias"/. +-- **WARNING**: If you use this with two CVW objects/carriers, the radio menu will be screwed up! +-- @param #CVW self +-- @param #boolean switch If true or nil single menu is enabled. If false, menu is for multiple carriers in the mission. +-- @return #CVW self +function CVW:SetMenuSingleCarrier(switch) + if switch==true or switch==nil then + self.menusingle=true + else + self.menusingle=false + end + return self +end + +--- Add squadron +-- @param #CVW self +-- @param #string name Name of the squadron, e.g. VFA-37. +-- @return #CVW self +function CVW:AddSquadron(name) + + local squadron={} --#CVW.Squadron + + squadron.name=name + squadron.assets={} + + table.insert(self.squadrons, squadron) +end + +--- Add squadron +-- @param #CVW self +-- @param #string groupname Name of the template group. +-- @return #CVW self +function CVW:AddFlightToSquadron(squadron, flightgroup, ngroups, livery) + + self:AddAsset(flightgroup, ngroups, nil, nil, nil, nil, nil, {livery}, squadron.name) + + function self:OnAfterNewAsset(From,Event,To,asset,assignment) + if assignment==squadron.name then + table.insert(squadron.assets, asset) + end + end + +end + +--- Get squadron by name +-- @param #CVW self +-- @param #string name Name of the squadron, e.g. VFA-37. +-- @return #CVW self +function CVW:GetSquadron(name) + + for _,_squadron in pairs(self.squadrons) do + if _squadron.name==name then + return _squadron + end + end + + return nil +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Status +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Start CVW FSM. Handle events. +-- @param #CVW self +function CVW:onafterStart(From, Event, To) + + -- Start parent Warehouse. + self:GetParent(self).onafterStart(self, From, Event, To) + + -- Info. + self:I(self.sid..string.format("Starting CVW v%s for carrier %s on map %s.", CVW.version, self.carriername, self.theatre)) + + -- Add F10 radio menu. + self:_SetMenuCoalition() + + -- Init status updates. + self:__AirwingStatus(-1) +end + +--- Update status. +-- @param #CVW self +function CVW:onafterSkipperStatus(From, Event, To) + + local fsmstate=self:GetState() + + -- Check zone for flights inbound. + self:_CheckIntruder() + + -- Info text. + local text=string.format("State %s", fsmstate) + self:I(self.sid..text) + + self:__AirwingStatus(-30) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- FSM Events +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Update status. +-- @param #CVW self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @param #CVW.Squadon squadron +-- @param Core.Point#COORDINATE coordinate +function CVW:onafterRequestCAP(From, Event, To, squadron, coordinate) + + + self:__AddRequest(1, self, WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, 1, nil, nil, nil, "CAP") + + function self:OnAfterSelfRequest(From,Event,To,Groupset,Request) + + if Request.assignment=="CAP" then + + end + end + +end + + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Misc Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Menu Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Patrol carrier. +-- @param #CVW self +-- @return #CVW self +function CVW:_SetMenuCoalition() + + -- Get coalition. + local Coalition=self:GetCoalition() + + -- Init menu table. + self.menu=self.menu or {} + + -- Init menu coalition table. + self.menu[Coalition]=self.menu[Coalition] or {} + + -- Shortcut. + local menu=self.menu[Coalition] + + if self.menusingle then + -- F10/Skipper/... + if not menu.Skipper then + menu.Skipper=MENU_COALITION:New(Coalition, "Skipper") + end + else + -- F10/Skipper//... + if not menu.Root then + menu.Root=MENU_COALITION:New(Coalition, "Skipper") + end + menu.Skipper=MENU_COALITION:New(Coalition, self.alias, menu.Root) + end + + ------------------- + -- Squadron Menu -- + ------------------- + + menu.Squadron= MENU_COALITION:New(Coalition, "Squadrons", menu.Skipper) + + + ------------------ + -- Defence Menu -- + ------------------ + + menu.Defence = MENU_COALITION:New(Coalition, "Defence", menu.Skipper) + menu.Defence_SetROE = MENU_COALITION:New(Coalition, "Set ROE", menu.Defence) + menu.Defence_SetROE_Hold = MENU_COALITION_COMMAND:New(Coalition, "Weapon Hold", menu.Defence_SetROE, self._SetROE, self, "Hold") + menu.Defence_SetROE_Free = MENU_COALITION_COMMAND:New(Coalition, "Weapon Free", menu.Defence_SetROE, self._SetROE, self, "Free") + menu.Defence_SetROE_Return = MENU_COALITION_COMMAND:New(Coalition, "Return Fire", menu.Defence_SetROE, self._SetROE, self, "Return") + + menu.Defence_Intruders = MENU_COALITION:New(Coalition, "Intruders", menu.Defence) + menu.Defence_Ammo = MENU_COALITION_COMMAND:New(Coalition, "Report Ammo", menu.Defence, self.arty.GetAmmo, self.arty, true) + menu.Defence_IntruderR = MENU_COALITION_COMMAND:New(Coalition, "Report Intruders", menu.Defence, self._ListIntruders, self) + menu.Defence_LaunchCAP = MENU_COALITION_COMMAND:New(Coalition, "Lauch CAP", menu.Defence, self.LaunchCAP, self) + + -------------------- + -- Warehouse Menu -- + -------------------- + + if self.warehouse then + menu.Warehouse=MENU_COALITION:New(Coalition, "Warehouse", menu.Skipper) + menu.Warehouse_Assets = MENU_COALITION_COMMAND:New(Coalition, "Reports On/Off", menu.Warehouse, self.WarehouseReportsToggle, self) + menu.Warehouse_Assets = MENU_COALITION_COMMAND:New(Coalition, "Report Assets", menu.Warehouse, self.ReportWarehouseStock, self) + end + +end + + +--- Add sub menu for this intruder. +-- @param #CVW self +-- @param #CVW.Squadron squadron The squadron data. +function CVW:_AddSquadonMenu(squadron) + + local Coalition=self:GetCoalition() + + local root=self.menu[Coalition].Squadrons + + local menu=MENU_COALITION:New(Coalition, squadron.name, root) + + if intruder.category==Group.Category.GROUND then + MENU_COALITION_COMMAND:New(Coalition, "Engage Shells", menu, self.EngageArty, self, intruder, ARTY.WeaponType.Cannon) + MENU_COALITION_COMMAND:New(Coalition, "Engage Cruise M", menu, self.EngageArty, self, intruder, ARTY.WeaponType.CruiseMissile) + elseif intruder.category==Group.Category.SHIP then + MENU_COALITION_COMMAND:New(Coalition, "Engage", menu, self.EngageArty, self, intruder) + elseif intruder.category==Group.Category.AIRPLANE or intruder.category==Group.Category.HELICOPTER then + MENU_COALITION_COMMAND:New(Coalition, "Engage A2A", menu, self.LaunchIntercept, self, intruder) + end + + -- Set menu. + intruder.menu=menu + +end + + +--- Warehouse reports on/off. +-- @param #CVW self +function CVW:WarehouseReportsToggle() + self.warehouse.Report=not self.warehouse.Report + MESSAGE:New(string.format("Warehouse reports are now %s", tostring(self.warehouse.Report)), 10, "CVW", true):ToCoalition(self:GetCoalition()) +end + + +--- Report warehouse stock. +-- @param #CVW self +function CVW:ReportWarehouseStock() + local text=self.warehouse:_GetStockAssetsText(false) + MESSAGE:New(text, 10, "CVW", true):ToCoalition(self:GetCoalition()) +end + +--- Launch a Intercept flight. +-- @param #CVW self +-- @param #CVW.Intruder intruder Intruder group. +function CVW:LaunchIntercept(intruder) + + -- Get number of aircraft. + local n=self:GetNumberOfAssets(WAREHOUSE.Descriptor.ASSIGNMENT, "Intercept", false) + + if n>0 then + + self.warehouse:AddRequest(self.warehouse, WAREHOUSE.Descriptor.ASSIGNMENT, "Intercept", 1, nil, nil, nil, "Intercept") + + local capcoord=intruder.group:GetCoordinate() + + capcoord:MarkToAll("Intruder coord") + + function self.warehouse.OnAfterSelfRequest(warehouse, From, Event, To, Groupset, Request) + local request=Request --Functional.Warehouse#WAREHOUSE.Pendingitem + local groupset=Groupset --Core.Set#SET_GROUP + + for _,_group in pairs(groupset:GetSet()) do + local group=_group --Wrapper.Group#GROUP + + if request.assignment=="Intercept" then + + -- Task orbit. + local tasks={} + + for _,unit in pairs(intruder.group:GetUnits()) do + tasks[#tasks+1]=group:TaskAttackUnit(unit) + end + + local speed=group:GetSpeedMax() + local altitude=intruder.group:GetAltitude() + + -- Create waypoints. + local wp={} + wp[1]=self:GetCoordinate():WaypointAirTakeOffParking() + wp[2]=self:GetCoordinate():SetAltitude(altitude):WaypointAirTurningPoint(COORDINATE.WaypointAltType.BARO, speed, {tasks}, "Attack Intruder") + + -- Start uncontrolled group. + group:StartUncontrolled() + + --airboss:SetExcludeAI() + + -- Route group + group:Route(wp) + end + + end + + end + + else + MESSAGE:New("No INTERCEPT fighters currently available", 5, "CVW"):ToCoalition(self:GetCoalition()) + end +end + + +--- Launch a CAP flight. +-- @param #CVW self +function CVW:LaunchCAP() + + local n=self:GetNumberOfAssets(WAREHOUSE.Descriptor.ASSIGNMENT, "CAP", false) + + if n>0 then + + self:AddRequest(self, WAREHOUSE.Descriptor.ATTRIBUTE, WAREHOUSE.Attribute.AIR_FIGHTER, 1, nil, nil, nil, "CAP") + + local capcoord=self.zoneCCA:GetRandomCoordinate(self.zoneCCA:GetRadius()/2) + + capcoord:MarkToAll("CAP coord") + + function self:OnAfterSelfRequest(From, Event, To, Groupset, Request) + local request=Request --Functional.Warehouse#WAREHOUSE.Pendingitem + local groupset=Groupset --Core.Set#SET_GROUP + + for _,_group in pairs(groupset:GetSet()) do + local group=_group --Wrapper.Group#GROUP + + if request.assignment=="CAP" then + + local alt=UTILS.FeetToMeters(20000) + + -- Task orbit. + local taskOrbit=group:TaskOrbit(capcoord, alt, UTILS.KnotsToMps(400), capcoord:Translate(UTILS.NMToMeters(15), 0)) + + local wp={} + wp[1]=self:GetCoordinate():WaypointAirTakeOffParking() + wp[2]=self:GetCoordinate():SetAltitude(alt):WaypointAirTurningPoint(COORDINATE.WaypointAltType.BARO, UTILS.KnotsToKmph(350), {taskOrbit}, "CAP") + + -- Start uncontrolled group. + group:StartUncontrolled() + + --airboss:SetExcludeAI() + + -- Route group. + group:Route(wp) + end + end + end + + else + MESSAGE:New("No CAP fighters currently available", 5, "CVW"):ToCoalition(self:GetCoalition()) + end +end + +--- Sort intruders table. +-- @param #CVW self +function CVW:_SortIntruders() + + -- Sort potential section members wrt to distance to lead. + local function _sort(_a,_b) + local a=_a --#CVW.Intruder + local b=_b --#CVW.Intruder + return a.threadlevel>b.threadlevel + end + + table.sort(self.intruders, _sort) +end + +--- Add sub menu for this intruder. +-- @param #CVW self +-- @param #CVW.Intruder intruder The intruder data. +-- @param #boolean removed If true, an intruder was removed. If false or nil, a new intruder was added. +function CVW:_UpdateIntruderMenu() + + for _,_intruder in ipairs(self.intruders) do + local intruder=_intruder --#CVW.Intruder + self:_AddIntruderMenu(intruder) + end + +end + + + +--- Remove sub menu for this intruder. +-- @param #CVW self +-- @param #CVW.Intruder intruder The intruder data. +function CVW:_RemoveIntruderMenu(intruder) + + if intruder.menu then + local menu=intruder.menu --Core.Menu#MENU_COALITION + + menu:Remove() + + intruder.menu=nil + end + +end + + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Ops/Skipper.lua b/Moose Development/Moose/Ops/Skipper.lua index a15a5f43a..131199e2d 100644 --- a/Moose Development/Moose/Ops/Skipper.lua +++ b/Moose Development/Moose/Ops/Skipper.lua @@ -113,34 +113,9 @@ function SKIPPER:New(carriername, alias) -- Set some string id for output to DCS.log file. self.sid=string.format("SKIPPER %s |", self.carriername) - - --[[ - - -- Current map. - self.theatre=env.mission.theatre - - -- 30 NM zone around the airbase. - self.zoneCCA=ZONE_UNIT:New("CCA", self.carrier, UTILS.NMToMeters(50)) - - -- Initialize ME waypoints. - self:_InitWaypoints() - - -- Current waypoint. - self.currentwp=1 - - -- Patrol route. - self:_PatrolRoute() - - -- Start State. - self:SetStartState("Stopped") - - --]] -- Add FSM transitions. -- From State --> Event --> To State - --self:AddTransition("Stopped", "Start", "Running") -- Start FSM. - --self:AddTransition("*", "Status", "*") -- Update status. - self:AddTransition("*", "SkipperStatus", "*") -- Skipper status update. self:AddTransition("*", "IntruderAlert", "*") -- New intruder detected. @@ -165,12 +140,12 @@ function SKIPPER:New(carriername, alias) -- @param #SKIPPER self -- @param #number delay Delay in seconds. - --- Triggers the FSM event "Status". - -- @function [parent=#SKIPPER] Status + --- Triggers the FSM event "SkipperStatus". + -- @function [parent=#SKIPPER] SkipperStatus -- @param #SKIPPER self - --- Triggers the FSM event "Status" after a delay. - -- @function [parent=#SKIPPER] __Status + --- Triggers the FSM event "SkipperStatus" after a delay. + -- @function [parent=#SKIPPER] __SkipperStatus -- @param #SKIPPER self -- @param #number delay Delay in seconds. @@ -199,7 +174,7 @@ function SKIPPER:New(carriername, alias) self.Debug=true BASE:TraceOnOff(true) BASE:TraceClass(self.ClassName) - BASE:TraceLevel(3) + BASE:TraceLevel(1) self.arty:GetAmmo(true) end @@ -293,9 +268,6 @@ end -- @param #SKIPPER self function SKIPPER:onafterSkipperStatus(From, Event, To) - -- Get State of parent airboss. - --self:GetParent(self).onafterStatus(self, From, Event, To) - local fsmstate=self:GetState() -- Check zone for flights inbound. @@ -375,7 +347,11 @@ function SKIPPER:_CheckIntruder() -- Intruder is gone! if not gotit then + + -- Remove from table. table.remove(self.intruders, i) + + -- Menu update required. updateintrudermenu=true end @@ -410,12 +386,10 @@ function SKIPPER:_CheckIntruder() -- Add intruder to list. table.insert(self.intruders, intruder) - -- Add menu. - --self:_AddIntruderMenu(intruder) - -- Trigger alert! self:IntruderAlert(intruder) + -- Menu update required. updateintrudermenu=true end end @@ -433,148 +407,6 @@ end -- Misc Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---[[ - ---- Patrol carrier. --- @param #SKIPPER self --- @return #SKIPPER self -function SKIPPER:_InitWaypoints() - - -- Waypoints of group. - local Waypoints=self.group:GetTemplateRoutePoints() - - -- Init array. - self.waypoints={} - - -- Set waypoint table. - for i,point in ipairs(Waypoints) do - - -- Coordinate of the waypoint - local coord=COORDINATE:New(point.x, point.alt, point.y) - - -- Set velocity of the coordinate. - coord:SetVelocity(point.speed) - - -- Add to table. - table.insert(self.waypoints, coord) - - -- Debug info. - if self.Debug then - coord:MarkToAll(string.format("Carrier Waypoint %d, Speed=%.1f knots", i, UTILS.MpsToKnots(point.speed))) - end - - end - - return self -end - - - ---- Patrol carrier. --- @param #SKIPPER self --- @param #number n Next waypoint number. --- @return #SKIPPER self -function SKIPPER:_PatrolRoute(n) - - -- Get next waypoint coordinate and number. - local nextWP, N=self:_GetNextWaypoint() - - -- Default resume is to next waypoint. - n=n or N - - -- Get carrier group. - local CarrierGroup=self.group - - -- Waypoints table. - local Waypoints={} - - -- Create a waypoint from the current coordinate. - local wp=self:GetCoordinate():WaypointGround(CarrierGroup:GetVelocityKMH()) - - -- Add current position as first waypoint. - table.insert(Waypoints, wp) - - -- Loop over waypoints. - for i=n,#self.waypoints do - local coord=self.waypoints[i] --Core.Point#COORDINATE - - -- Create a waypoint from the coordinate. - local wp=coord:WaypointGround(UTILS.MpsToKmph(coord.Velocity)) - - -- Passing waypoint taskfunction - local TaskPassingWP=CarrierGroup:TaskFunction("SKIPPER._PassingWaypoint", self, i, #self.waypoints) - - -- Call task function when carrier arrives at waypoint. - CarrierGroup:SetTaskWaypoint(wp, TaskPassingWP) - - -- - table.insert(Waypoints, wp) - end - - -- Route carrier group. - CarrierGroup:Route(Waypoints) - - return self -end - ---- Function called when a group is passing a waypoint. ---@param Wrapper.Group#GROUP group Group that passed the waypoint. ---@param #SKIPPER skipper skipper object. ---@param #number i Waypoint number that has been reached. ---@param #number final Final waypoint number. -function SKIPPER._PassingWaypoint(group, skipper, i, final) - - -- Debug message. - local text=string.format("Group %s passing waypoint %d of %d.", group:GetName(), i, final) - - -- Debug smoke and marker. - if skipper.Debug and false then - local pos=group:GetCoordinate() - pos:SmokeRed() - local MarkerID=pos:MarkToAll(string.format("Group %s reached waypoint %d", group:GetName(), i)) - end - - -- Debug message. - MESSAGE:New(text,10):ToAllIf(skipper.Debug) - skipper:T(skipper.lid..text) - - -- Set current waypoint. - skipper.currentwp=i - - -- Passing Waypoint event. - --skipper:PassingWaypoint(i) - - -- If final waypoint reached, do route all over again. - if i==final and final>1 and skipper.adinfinitum then - skipper:_PatrolRoute(i) - end -end - ---- Get next waypoint of the carrier. --- @param #SKIPPER self --- @return Core.Point#COORDINATE Coordinate of the next waypoint. --- @return #number Number of waypoint. -function SKIPPER:_GetNextWaypoint() - - -- Next waypoint. - local Nextwp=nil - if self.currentwp==#self.waypoints then - Nextwp=1 - else - Nextwp=self.currentwp+1 - end - - -- Debug output - local text=string.format("Current WP=%d/%d, next WP=%d", self.currentwp, #self.waypoints, Nextwp) - self:T2(self.lid..text) - - -- Next waypoint. - local nextwp=self.waypoints[Nextwp] --Core.Point#COORDINATE - - return nextwp,Nextwp -end - -]] ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Menu Functions @@ -647,6 +479,7 @@ function SKIPPER:_SetMenuCoalition() menu.CaseI = MENU_COALITION_COMMAND:New(Coalition, "Start CASE I", menu.Recovery, self._StartCaseX, self, 1) menu.CaseII = MENU_COALITION_COMMAND:New(Coalition, "Start CASE II", menu.Recovery, self._StartCaseX, self, 2) menu.CaseIII = MENU_COALITION_COMMAND:New(Coalition, "Start CASE III", menu.Recovery, self._StartCaseX, self, 3) + menu.Rstop = MENU_COALITION_COMMAND:New(Coalition, "Pause/Unpause", menu.Recovery, self._Rpause, self) menu.Rstop = MENU_COALITION_COMMAND:New(Coalition, "Stop Recovery", menu.Recovery, self._Rstop, self) @@ -692,6 +525,18 @@ function SKIPPER:ReportWarehouseStock() MESSAGE:New(text, 10, "SKIPPER", true):ToCoalition(self:GetCoalition()) end +--- Handle self requests from carrier warehouse. +-- @param #SKIPPER self +-- @param Functional.Warehouse#WAREHOUSE warehouse The (carrier) warehouse object. +-- @param Core.Set#SET_GROUP groupset Group set. +-- @param Functional.Warehouse#WAREHOUSE.Pendingitem request Request. +function SKIPPER:_SelfRequest(warehouse, groupset, request) + + local assignment=request.assignment + + env.info(string.format("FF warehouse self request assignment %s", tostring(assignment))) + +end --- Launch a Intercept flight. -- @param #SKIPPER self @@ -709,7 +554,6 @@ function SKIPPER:LaunchIntercept(intruder) capcoord:MarkToAll("Intruder coord") - --[[ function self.warehouse.OnAfterSelfRequest(warehouse, From, Event, To, Groupset, Request) local request=Request --Functional.Warehouse#WAREHOUSE.Pendingitem local groupset=Groupset --Core.Set#SET_GROUP @@ -721,7 +565,10 @@ function SKIPPER:LaunchIntercept(intruder) -- Task orbit. local tasks={} - local taskAttack=group:TaskAttackUnit(intruder.group:GetUnit(1)) + + for _,unit in pairs(intruder.group:GetUnits()) do + tasks[#tasks+1]=group:TaskAttackUnit(unit) + end local speed=group:GetSpeedMax() local altitude=intruder.group:GetAltitude() @@ -729,38 +576,26 @@ function SKIPPER:LaunchIntercept(intruder) -- Create waypoints. local wp={} wp[1]=self:GetCoordinate():WaypointAirTakeOffParking() - wp[2]=self:GetCoordinate():SetAltitude(altitude):WaypointAirTurningPoint(COORDINATE.WaypointAltType.BARO, speed, {taskAttack}, "Attack Intruder") + wp[2]=self:GetCoordinate():SetAltitude(altitude):WaypointAirTurningPoint(COORDINATE.WaypointAltType.BARO, speed, {tasks}, "Attack Intruder") + -- Start uncontrolled group. group:StartUncontrolled() --airboss:SetExcludeAI() - group:Route(wp) + -- Route group + group:Route(wp) end end end - ]] else MESSAGE:New("No INTERCEPT fighters currently available", 5, "SKIPPER"):ToCoalition(self:GetCoalition()) end end ---- Handle self requests from carrier warehouse. --- @param #SKIPPER self --- @param Functional.Warehouse#WAREHOUSE warehouse The (carrier) warehouse object. --- @param Core.Set#SET_GROUP groupset Group set. --- @param Functional.Warehouse#WAREHOUSE.Pendingitem request Request. -function SKIPPER:_SelfRequest(warehouse, groupset, request) - - local assignment=request.assignment - - env.info(string.format("FF warehouse self request assignment %s", tostring(assignment))) - -end - --- Launch a CAP flight. -- @param #SKIPPER self @@ -777,34 +612,34 @@ function SKIPPER:LaunchCAP() capcoord:MarkToAll("CAP coord") - - --[[ function self.warehouse.OnAfterSelfRequest(warehouse, From, Event, To, Groupset, Request) local request=Request --Functional.Warehouse#WAREHOUSE.Pendingitem local groupset=Groupset --Core.Set#SET_GROUP - + for _,_group in pairs(groupset:GetSet()) do local group=_group --Wrapper.Group#GROUP - + if request.assignment=="CAP" then + local alt=UTILS.FeetToMeters(20000) + -- Task orbit. - local taskOrbit=group:TaskOrbit(capcoord, UTILS.FeetToMeters(20000), UTILS.KnotsToMps(400), capcoord:Translate(UTILS.NMToMeters(15), 0)) + local taskOrbit=group:TaskOrbit(capcoord, alt, UTILS.KnotsToMps(400), capcoord:Translate(UTILS.NMToMeters(15), 0)) local wp={} wp[1]=self:GetCoordinate():WaypointAirTakeOffParking() - wp[2]=self:GetCoordinate():WaypointAirTurningPoint("Baro", UTILS.KnotsToKph(350), {taskOrbit}, "CAP") + wp[2]=self:GetCoordinate():SetAltitude(alt):WaypointAirTurningPoint(COORDINATE.WaypointAltType.BARO, UTILS.KnotsToKmph(350), {taskOrbit}, "CAP") + -- Start uncontrolled group. group:StartUncontrolled() --airboss:SetExcludeAI() - group:Route(wp) + -- Route group. + group:Route(wp) end - - end + end end - ]] else MESSAGE:New("No CAP fighters currently available", 5, "SKIPPER"):ToCoalition(self:GetCoalition())