From 277eb2d09fcf1428621c711880dc0fb4b5f784ab Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 18 Oct 2020 00:02:48 +0200 Subject: [PATCH] Ops - Laser --- Moose Development/Moose/DCS.lua | 59 ++++ Moose Development/Moose/Ops/ArmyGroup.lua | 186 ++++++---- Moose Development/Moose/Ops/Auftrag.lua | 24 +- Moose Development/Moose/Ops/FlightGroup.lua | 28 +- Moose Development/Moose/Ops/NavyGroup.lua | 42 ++- Moose Development/Moose/Ops/OpsGroup.lua | 367 ++++++++++++++++++-- 6 files changed, 596 insertions(+), 110 deletions(-) diff --git a/Moose Development/Moose/DCS.lua b/Moose Development/Moose/DCS.lua index 15c73c29a..2d190d215 100644 --- a/Moose Development/Moose/DCS.lua +++ b/Moose Development/Moose/DCS.lua @@ -736,7 +736,66 @@ do -- Airbase end -- Airbase +do -- Spot + --- [DCS Class Spot](https://wiki.hoggitworld.com/view/DCS_Class_Spot) + -- Represents a spot from laser or IR-pointer. + -- @type Spot + -- @field #Spot.Category Category enum that stores spot categories. + + --- Enum that stores spot categories. + -- @type Spot.Category + -- @field #string INFRA_RED + -- @field #string LASER + + + --- Creates a laser ray emanating from the given object to a point in 3d space. + -- @function [parent=#Spot] createLaser + -- @param DCS#Object Source The source object of the laser. + -- @param DCS#Vec3 LocalRef An optional 3D offset for the source. + -- @param DCS#Vec3 Vec3 Target coordinate where the ray is pointing at. + -- @param #number LaserCode Any 4 digit number between 1111 and 1788. + -- @return #Spot + + --- Creates an infrared ray emanating from the given object to a point in 3d space. Can be seen with night vision goggles. + -- @function [parent=#Spot] createInfraRed + -- @param DCS#Object Source Source position of the IR ray. + -- @param DCS#Vec3 LocalRef An optional 3D offset for the source. + -- @param DCS#Vec3 Vec3 Target coordinate where the ray is pointing at. + -- @return #Spot + + --- Returns a vec3 table of the x, y, and z coordinates for the position of the given object in 3D space. Coordinates are dependent on the position of the maps origin. + -- @function [parent=#Spot] getPoint + -- @param #Spot self + -- @return DCS#Vec3 Point in 3D, where the beam is pointing at. + + --- Sets the destination point from which the source of the spot is drawn toward. + -- @function [parent=#Spot] setPoint + -- @param #Spot self + -- @param DCS#Vec3 Vec3 Point in 3D, where the beam is pointing at. + + --- Returns the number that is used to define the laser code for which laser designation can track. + -- @function [parent=#Spot] getCode + -- @param #Spot self + -- @return #number Code The laser code used. + + --- Sets the number that is used to define the laser code for which laser designation can track. + -- @function [parent=#Spot] setCode + -- @param #Spot self + -- @param #number Code The laser code. Default value is 1688. + + --- Destroys the spot. + -- @function [parent=#Spot] destroy + -- @param #Spot self + + --- Gets the category of the spot (laser or IR). + -- @function [parent=#Spot] getCategory + -- @param #Spot self + -- @return #string Category. + + Spot = {} --#Spot + +end -- Spot do -- Controller --- Controller is an object that performs A.I.-routines. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C. diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index f32dca574..a366d7a79 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -1,21 +1,29 @@ --- **Ops** - Enhanced Ground Group. -- --- **Main Features:** +-- ## Main Features: -- --- * Dynamically add and remove waypoints. --- * Convenient checks when the group enters or leaves a zone. --- * Sophisticated task queueing system. --- * Compatible with AUFTRAG class. --- * Easy change of ROE, alarm state, formation and other settings. --- * Many additional events that the mission designer can hook into. +-- * Patrol waypoints *ad infinitum* +-- * Easy change of ROE and alarm state, formation and other settings +-- * Dynamically add and remove waypoints +-- * Sophisticated task queueing system (know when DCS tasks start and end) +-- * Convenient checks when the group enters or leaves a zone +-- * Detection events for new, known and lost units +-- * Simple LASER and IR-pointer setup +-- * Compatible with AUFTRAG class +-- * Many additional events that the mission designer can hook into -- --- **Example Missions:** +-- === +-- +-- ## Example Missions: -- -- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Armygroup). -- -- === -- -- ### Author: **funkyfranky** +-- +-- == +-- -- @module Ops.ArmyGroup -- @image OPS_ArmyGroup.png @@ -46,7 +54,12 @@ ARMYGROUP = { --- Army group element. -- @type ARMYGROUP.Element -- @field #string name Name of the element, i.e. the unit. +-- @field Wrapper.Unit#UNIT unit The UNIT object. +-- @field #string status The element status. -- @field #string typename Type name. +-- @field #number length Length of element in meters. +-- @field #number width Width of element in meters. +-- @field #number height Height of element in meters. --- Army Group version. -- @field #string version @@ -85,10 +98,7 @@ function ARMYGROUP:New(Group) -- From State --> Event --> To State self:AddTransition("*", "FullStop", "Holding") -- Hold position. self:AddTransition("*", "Cruise", "Cruising") -- Cruise along the given route of waypoints. - - self:AddTransition("*", "Rearm", "Rearming") -- Group is send to a coordinate and waits until ammo is refilled. - self:AddTransition("Rearming", "Rearmed", "Cruising") -- Group was rearmed. - + self:AddTransition("*", "Detour", "OnDetour") -- Make a detour to a coordinate and resume route afterwards. self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate. @@ -178,6 +188,8 @@ end -- @return Ops.OpsGroup#OPSGROUP.Task The task table. function ARMYGROUP:AddTaskFireAtPoint(Coordinate, Clock, Radius, Nshots, WeaponType, Prio) + Coordinate=self:_CoordinateFromObject(Coordinate) + local DCStask=CONTROLLABLE.TaskFireAtPoint(nil, Coordinate:GetVec2(), Radius, Nshots, WeaponType) local task=self:AddTask(DCStask, Clock, nil, Prio) @@ -196,6 +208,8 @@ end -- @return Ops.OpsGroup#OPSGROUP.Task The task table. function ARMYGROUP:AddTaskWaypointFireAtPoint(Coordinate, Waypoint, Radius, Nshots, WeaponType, Prio) + Coordinate=self:_CoordinateFromObject(Coordinate) + Waypoint=Waypoint or self:GetWaypointNext() local DCStask=CONTROLLABLE.TaskFireAtPoint(nil, Coordinate:GetVec2(), Radius, Nshots, WeaponType) @@ -243,13 +257,6 @@ function ARMYGROUP:IsOnDetour() return self:Is("OnDetour") end ---- Check if the group is currently rearming. --- @param #ARMYGROUP self --- @return #boolean If true, group is rearming. -function ARMYGROUP:IsRearming() - return self:Is("Rearming") -end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Status ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -286,12 +293,24 @@ function ARMYGROUP:onafterStatus(From, Event, To) if self.detectionOn then self:_CheckDetectedUnits() end - - -- Update position etc. - self:_UpdatePosition() - -- Check if group got stuck. - self:_CheckStuck() + if self:IsRearming() then + + local rearmed=self:_CheckAmmoFull() + + if rearmed then + self:Rearmed() + end + + else + + -- Update position etc. + self:_UpdatePosition() + + -- Check if group got stuck. + self:_CheckStuck() + + end if self.verbose>=1 then @@ -303,7 +322,7 @@ function ARMYGROUP:onafterStatus(From, Event, To) local alarm=self:GetAlarmstate() local speed=UTILS.MpsToKnots(self.velocity) local speedEx=UTILS.MpsToKnots(self:GetExpectedSpeed()) - local formation=self.option.Formation + local formation=self.option.Formation or "unknown" -- Info text. local text=string.format("%s: Wp=%d/%d-->%d Speed=%.1f (%d) Heading=%03d ROE=%d Alarm=%d Formation=%s Tasks=%d Missions=%d", @@ -382,7 +401,11 @@ function ARMYGROUP:onafterSpawned(From, Event, To) end -- Update route. - self:Cruise(nil, self.option.Formation or self.optionDefault.Formation) + if #self.waypoints>1 then + self:Cruise(nil, self.option.Formation or self.optionDefault.Formation) + else + self:FullStop() + end end @@ -549,6 +572,35 @@ function ARMYGROUP:onafterRearm(From, Event, To, Coordinate, Formation) end +--- On after "Rearming" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARMYGROUP:onafterRearming(From, Event, To) + + -- Get current position. + local pos=self:GetCoordinate() + + -- Create a new waypoint. + local wp=pos:WaypointGround(0) + + -- Create new route consisting of only this position ==> Stop! + self:Route({wp}) + +end + +--- On after "Rearmed" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARMYGROUP:onafterRearmed(From, Event, To) + + self:_CheckGroupDone(1) + +end + --- On after "DetourReached" event. -- @param #ARMYGROUP self -- @param #string From From state. @@ -709,6 +761,8 @@ end -- @return Ops.OpsGroup#OPSGROUP.Waypoint Waypoint table. function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute) + local coordinate=self:_CoordinateFromObject(Coordinate) + -- Set waypoint index. local wpnumber=self:GetWaypointIndexAfterID(AfterWaypointWithID) @@ -721,7 +775,7 @@ function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation Speed=Speed or self:GetSpeedCruise() -- Create a Naval waypoint. - local wp=Coordinate:WaypointGround(UTILS.KnotsToKmph(Speed), Formation) + local wp=coordinate:WaypointGround(UTILS.KnotsToKmph(Speed), Formation) -- Create waypoint data table. local waypoint=self:_CreateWaypoint(wp) @@ -730,9 +784,9 @@ function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation self:_AddWaypoint(waypoint, wpnumber) -- Get closest point to road. - waypoint.roadcoord=Coordinate:GetClosestPointToRoad(false) + waypoint.roadcoord=coordinate:GetClosestPointToRoad(false) if waypoint.roadcoord then - waypoint.roaddist=Coordinate:Get2DDistance(waypoint.roadcoord) + waypoint.roaddist=coordinate:Get2DDistance(waypoint.roadcoord) else waypoint.roaddist=1000*1000 --1000 km. end @@ -805,51 +859,61 @@ function ARMYGROUP:_InitGroup() for _,_unit in pairs(units) do local unit=_unit --Wrapper.Unit#UNIT + + -- TODO: this is wrong when grouping is used! + local unittemplate=unit:GetTemplate() local element={} --#ARMYGROUP.Element element.name=unit:GetName() - element.typename=unit:GetTypeName() + element.unit=unit element.status=OPSGROUP.ElementStatus.INUTERO - element.unit=unit + element.typename=unit:GetTypeName() + element.skill=unittemplate.skill or "Unknown" + element.ai=true + element.category=element.unit:GetUnitCategory() + element.categoryname=element.unit:GetCategoryName() + element.size, element.length, element.height, element.width=unit:GetObjectSize() + element.ammo0=self:GetAmmoUnit(unit, false) + + -- Debug text. + local text=string.format("Adding element %s: status=%s, skill=%s, category=%s (%d), size: %.1f (L=%.1f H=%.1f W=%.1f)", + element.name, element.status, element.skill, element.categoryname, element.category, element.size, element.length, element.height, element.width) + self:I(self.lid..text) + + -- Add element to table. table.insert(self.elements, element) - self:GetAmmoUnit(unit, false) + -- Get Descriptors. + self.descriptors=self.descriptors or unit:GetDesc() - if unit:IsAlive() then + -- Set type name. + self.actype=self.actype or unit:GetTypeName() + + if unit:IsAlive() then + -- Trigger spawned event. self:ElementSpawned(element) end end - -- Get first unit. This is used to extract other parameters. - local unit=self.group:GetUnit(1) - - if unit then - - self.descriptors=unit:GetDesc() - - self.actype=unit:GetTypeName() - - -- Debug info. - if self.verbose>=1 then - local text=string.format("Initialized Army Group %s:\n", self.groupname) - text=text..string.format("Unit type = %s\n", self.actype) - text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedMax)) - text=text..string.format("Speed cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise)) - text=text..string.format("Elements = %d\n", #self.elements) - text=text..string.format("Waypoints = %d\n", #self.waypoints) - text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radio.On)) - text=text..string.format("Ammo = %d (G=%d/R=%d/M=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Missiles) - text=text..string.format("FSM state = %s\n", self:GetState()) - text=text..string.format("Is alive = %s\n", tostring(self:IsAlive())) - text=text..string.format("LateActivate = %s\n", tostring(self:IsLateActivated())) - self:I(self.lid..text) - end - - -- Init done. - self.groupinitialized=true - + -- Debug info. + if self.verbose>=1 then + local text=string.format("Initialized Army Group %s:\n", self.groupname) + text=text..string.format("Unit type = %s\n", self.actype) + text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedMax)) + text=text..string.format("Speed cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise)) + text=text..string.format("Elements = %d\n", #self.elements) + text=text..string.format("Waypoints = %d\n", #self.waypoints) + text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radio.On)) + text=text..string.format("Ammo = %d (G=%d/R=%d/M=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Missiles) + text=text..string.format("FSM state = %s\n", self:GetState()) + text=text..string.format("Is alive = %s\n", tostring(self:IsAlive())) + text=text..string.format("LateActivate = %s\n", tostring(self:IsLateActivated())) + self:I(self.lid..text) end + + -- Init done. + self.groupinitialized=true return self end diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index b6c030455..54d186a09 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1,18 +1,26 @@ --- **Ops** - Auftrag (mission) for Ops. -- --- **Main Features:** +-- ## Main Features: -- --- * Simplifies defining and executing DCS tasks. --- * Additional useful events. --- * Set mission start/stop times. --- * Set mission priority and urgency (can cancel running missions). +-- * Simplifies defining and executing DCS tasks +-- * Additional useful events +-- * Set mission start/stop times +-- * Set mission priority and urgency (can cancel running missions) -- * Specific mission options for ROE, ROT, formation, etc. --- * Interface to FLIGHTGROUP, NAVYGROUP, ARMYGROUP, AIRWING, WINGCOMMANDER and CHIEF classes. --- * FSM events when a mission is done, successful or failed. --- +-- * Compatible with FLIGHTGROUP, NAVYGROUP, ARMYGROUP, AIRWING, WINGCOMMANDER and CHIEF classes +-- * FSM events when a mission is done, successful or failed +-- -- === -- +-- ## Example Missions: +-- +-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Auftrag). +-- +-- === +-- -- ### Author: **funkyfranky** +-- +-- === -- @module Ops.Auftrag -- @image OPS_Auftrag.png diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index f7d394d96..dc73d37e2 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -1,16 +1,30 @@ --- **Ops** - Enhanced Airborne Group. -- --- **Main Features:** +-- ## Main Features: -- --- * Monitor flight status of elements and/or the entire group. --- * Monitor fuel and ammo status. --- * Conveniently set radio freqencies, TACAN, ROE etc. --- * Sophisticated task queueing system. --- * Many additional events for each element and the whole group. +-- * Monitor flight status of elements and/or the entire group +-- * Monitor fuel and ammo status +-- * Conveniently set radio freqencies, TACAN, ROE etc +-- * Order helos to land at specifc coordinates +-- * Dynamically add and remove waypoints +-- * Sophisticated task queueing system (know when DCS tasks start and end) +-- * Convenient checks when the group enters or leaves a zone +-- * Detection events for new, known and lost units +-- * Simple LASER and IR-pointer setup +-- * Compatible with AUFTRAG class +-- * Many additional events that the mission designer can hook into -- -- === -- +-- ## Example Missions: +-- +-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Flightgroup). +-- +-- === +-- -- ### Author: **funkyfranky** +-- +-- === -- @module Ops.FlightGroup -- @image OPS_FlightGroup.png @@ -186,6 +200,7 @@ FLIGHTGROUP.version="0.6.0" -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- TODO: VTOL aircraft. -- TODO: Use new UnitLost event instead of crash/dead. -- TODO: Options EPLRS, Afterburner restrict etc. -- DONE: Add TACAN beacon. @@ -2729,6 +2744,7 @@ function FLIGHTGROUP:AddElementByName(unitname) element.ai=true end + -- Debug text. local text=string.format("Adding element %s: status=%s, skill=%s, modex=%s, fuelmass=%.1f (%d), category=%d, categoryname=%s, callsign=%s, ai=%s", element.name, element.status, element.skill, element.modex, element.fuelmass, element.fuelrel*100, element.category, element.categoryname, element.callsign, tostring(element.ai)) self:T(self.lid..text) diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index e180ae53f..dd0fb65a9 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -1,25 +1,33 @@ --- **Ops** - Enhanced Naval Group. -- --- **Main Features:** +-- ## Main Features: -- --- * Dynamically add and remove waypoints. --- * Let the group steam into the wind. --- * Command a full stop. --- * Automatic pathfinding, e.g. around islands. --- * Collision warning, if group is heading towards a land mass. --- * Let a submarine dive and surface. --- * Sophisticated task queueing system. --- * Compatible with AUFTRAG class. --- * Convenient checks when the group enters or leaves a zone. --- * Many additional events that the mission designer can hook into. +-- * Let the group steam into the wind +-- * Command a full stop +-- * Patrol waypoints *ad infinitum* +-- * Collision warning, if group is heading towards a land mass +-- * Automatic pathfinding, e.g. around islands +-- * Let a submarine dive and surface +-- * Manage TACAN and ICLS beacons +-- * Dynamically add and remove waypoints +-- * Sophisticated task queueing system (know when DCS tasks start and end) +-- * Convenient checks when the group enters or leaves a zone +-- * Detection events for new, known and lost units +-- * Simple LASER and IR-pointer setup +-- * Compatible with AUFTRAG class +-- * Many additional events that the mission designer can hook into -- --- **Example Missions:** +-- === +-- +-- ## Example Missions: -- -- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Navygroup) -- -- === -- -- ### Author: **funkyfranky** +-- +-- === -- @module Ops.NavyGroup -- @image OPS_NavyGroup.png @@ -655,7 +663,11 @@ function NAVYGROUP:onafterSpawned(From, Event, To) end -- Update route. - self:Cruise() + if #self.waypoints>1 then + self:Cruise() + else + self:FullStop() + end end @@ -1124,10 +1136,10 @@ function NAVYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Depth, Up -- Check if a coordinate was given or at least a positionable. if not Coordinate:IsInstanceOf("COORDINATE") then if Coordinate:IsInstanceOf("POSITIONABLE") or Coordinate:IsInstanceOf("ZONE_BASE") then - self:T(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE. Trying to get coordinate") + self:T(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE or ZONE. Trying to get coordinate") Coordinate=Coordinate:GetCoordinate() else - self:E(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE!") + self:E(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE or ZONE!") return nil end end diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 4b3c44d41..7a9828e81 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -1,10 +1,12 @@ ---- **Ops** - Generic group enhancement functions. +--- **Ops** - Generic group enhancement. -- --- This class is **not** meant to be used itself by the end user. +-- This class is **not** meant to be used itself by the end user. It contains common functionalities of derived classes for air, ground and sea. -- -- === -- -- ### Author: **funkyfranky** +-- +-- === -- @module Ops.OpsGroup -- @image OPS_OpsGroup.png @@ -83,6 +85,8 @@ -- @field #OPSGROUP.Callsign callsign Current callsign settings. -- @field #OPSGROUP.Callsign callsignDefault Default callsign settings. -- +-- @field #OPSGROUP.Spot spot Laser and IR spot. +-- -- @extends Core.Fsm#FSM --- *A small group of determined and like-minded people can change the course of history.* --- Mahatma Gandhi @@ -136,6 +140,17 @@ OPSGROUP = { Ndestroyed = 0, } + +--- OPS group element. +-- @type OPSGROUP.Element +-- @field #string name Name of the element, i.e. the unit. +-- @field Wrapper.Unit#UNIT unit The UNIT object. +-- @field #string status The element status. +-- @field #string typename Type name. +-- @field #number length Length of element in meters. +-- @field #number width Width of element in meters. +-- @field #number height Height of element in meters. + --- Status of group element. -- @type OPSGROUP.ElementStatus -- @field #string INUTERO Element was not spawned yet or its status is unknown so far. @@ -236,7 +251,6 @@ OPSGROUP.TaskType={ -- @field #boolean EPLRS data link. -- @field #boolean Disperse Disperse under fire. - --- Weapon range data. -- @type OPSGROUP.WeaponData -- @field #number BitType Type of weapon. @@ -244,6 +258,16 @@ OPSGROUP.TaskType={ -- @field #number RangeMax Max range in meters. -- @field #number ReloadTime Time to reload in seconds. +--- Laser and IR spot data. +-- @type OPSGROUP.Spot +-- @field DCS#Spot Laser Laser spot. +-- @field DCS#Spot IR Infra-red spot. +-- @field #number Code Laser code. +-- @field Wrapper.Positionable#POSITIONABLE Target The target. +-- @field Core.Point#COORDINATE Coordinate where the spot is pointing. +-- @field #boolean On If true, the laser is on. +-- @field Core.Timer#TIMER timer Spot timer. + --- Ammo data. -- @type OPSGROUP.Ammo -- @field #number Total Total amount of ammo. @@ -281,13 +305,14 @@ OPSGROUP.TaskType={ --- NavyGroup version. -- @field #string version -OPSGROUP.version="0.5.0" +OPSGROUP.version="0.6.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO: Implement common functions. +-- TODO: Suppression of fire. +-- TODO: Add pseudo function. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor @@ -320,6 +345,12 @@ function OPSGROUP:New(Group) -- Init inzone set. self.inzones=SET_ZONE:New() + -- Laser. + self.spot={} + self.spot.On=false + self.spot.timer=TIMER:New(OPSGROUP._UpdateLaser, self) + self:SetLaser() + -- Init task counter. self.taskcurrent=0 self.taskcounter=0 @@ -356,6 +387,14 @@ function OPSGROUP:New(Group) self:AddTransition("*", "EnterZone", "*") -- Group entered a certain zone. self:AddTransition("*", "LeaveZone", "*") -- Group leaves a certain zone. + self:AddTransition("*", "Rearm", "Rearming") -- Group is send to a coordinate and waits until ammo is refilled. + self:AddTransition("Rearming", "Rearming", "Rearming") -- Group has arrived at the rearming coodinate and is waiting to be fully rearmed. + self:AddTransition("Rearming", "Rearmed", "Cruising") -- Group was rearmed. + + self:AddTransition("*", "LaserOn", "*") -- Turn laser on. + self:AddTransition("*", "LaserOff", "*") -- Turn laser off. + self:AddTransition("*", "LaserCode", "*") -- Switch laser code. + self:AddTransition("*", "TaskExecute", "*") -- Group will execute a task. self:AddTransition("*", "TaskPause", "*") -- Pause current task. Not implemented yet! self:AddTransition("*", "TaskCancel", "*") -- Cancel current task. @@ -457,6 +496,19 @@ function OPSGROUP:SetDetection(Switch) return self end +--- Set detection on or off. +-- If detection is on, detected targets of the group will be evaluated and FSM events triggered. +-- @param #OPSGROUP self +-- @param #number Code Laser code. Default 1688. +-- @param #boolean IROff If true, then dont switch on the additional IR pointer. +-- @param #number UpdateTime Time interval in seconds the beam gets up for moving targets. Default every 0.5 sec. +-- @return #OPSGROUP self +function OPSGROUP:SetLaser(Code, IROff, UpdateTime) + self.spot.Code=Code or 1688 + self.spot.IRoff=IROff + return self +end + --- Define a SET of zones that trigger and event if the group enters or leaves any of the zones. -- @param #OPSGROUP self -- @param Core.Set#SET_ZONE CheckZonesSet Set of zones. @@ -502,9 +554,9 @@ function OPSGROUP:AddWeaponRange(RangeMin, RangeMax, BitType) return self end ---- +--- Get weapon data. -- @param #OPSGROUP self --- @param #number BitType +-- @param #number BitType Type of weapon. -- @return #OPSGROUP.WeaponData Weapon range data. function OPSGROUP:GetWeaponData(BitType) @@ -518,7 +570,6 @@ function OPSGROUP:GetWeaponData(BitType) end - --- Get set of detected units. -- @param #OPSGROUP self -- @return Core.Set#SET_UNIT Set of detected units. @@ -526,6 +577,41 @@ function OPSGROUP:GetDetectedUnits() return self.detectedunits end +--- Get highest detected threat. Detection must be turned on. The threat level is a number between 0 and 10, where 0 is the lowest, e.g. unarmed units. +-- @param #OPSGROUP self +-- @param #number ThreatLevelMin Only consider threats with level greater or equal to this number. Default 1 (so unarmed units wont be considered). +-- @param #number ThreatLevelMax Only consider threats with level smaller or queal to this number. Default 10. +-- @return Wrapper.Unit#UNIT Highest threat unit detected by the group or `nil` if no threat is currently detected. +-- @return #number Threat level. +function OPSGROUP:GetThreat(ThreatLevelMin, ThreatLevelMax) + + ThreatLevelMin=ThreatLevelMin or 1 + ThreatLevelMax=ThreatLevelMax or 10 + + local threat=nil --Wrapper.Unit#UNIT + local level=0 + for _,_unit in pairs(self.detectedunits:GetSet()) do + local unit=_unit --Wrapper.Unit#UNIT + + -- Get threatlevel of unit. + local threatlevel=unit:GetThreatLevel() + + -- Check if withing threasholds. + if threatlevel>=ThreatLevelMin and threatlevel<=ThreatLevelMax then + + if threatlevel1 then + + -- Store current position. + self.spot.vec3=vec3 + + -- Update beam coordinate. + self.spot.Coordinate:UpdateFromVec3(vec3) + + -- Set the new laser target point. + self.spot.Laser:setPoint(vec3) + self.spot.IR:setPoint(vec3) + + end + + else + + -- Switch laser off. + self:T(self.lid.."Target is not alive any more ==> switching LASER off") + self:LaserOff() + + end + + end + + end + +end + --- On after "ElementDestroyed" event. -- @param #OPSGROUP self @@ -2902,9 +3161,22 @@ end -- @param #OPSGROUP.Element Element The flight group element. function OPSGROUP:onafterElementDead(From, Event, To, Element) self:T(self.lid..string.format("Element dead %s", Element.name)) - + -- Set element status. self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD) + + -- Check if element was lasing and if so, switch to another unit alive to lase. + if self.spot.On and self.spot.element.name==Element.name then + + -- Switch laser off. + self:LaserOff() + + -- If there is another element alive, switch laser on again. + if self:GetNelements()>0 then + self:__LaserOn(-1, self.spot.Target or self.spot.Coordinate) + end + end + end --- On after "Dead" event. @@ -3172,10 +3444,19 @@ end -- @return #boolean If true, ammo is full. function OPSGROUP:_CheckAmmoFull() - for _,_ammo in pairs(self.ammo) do + -- Get current ammo. + local ammo=self:GetAmmoTot() + + for key,value in pairs(self.ammo) do + + if ammo[key]