- Laser
This commit is contained in:
Frank 2020-10-18 00:02:48 +02:00
parent 187093fa5a
commit 277eb2d09f
6 changed files with 596 additions and 110 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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 threatlevel<level then
level=threatlevel
threat=unit
end
end
end
return threat, level
end
--- Get MOOSE GROUP object.
-- @param #OPSGROUP self
-- @return Wrapper.Group#GROUP Moose group object.
@ -999,6 +1085,13 @@ function OPSGROUP:HasPassedFinalWaypoint()
return self.passedfinalwp
end
--- Check if the group is currently rearming.
-- @param #OPSGROUP self
-- @return #boolean If true, group is rearming.
function OPSGROUP:IsRearming()
return self:Is("Rearming")
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Waypoint Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -1736,7 +1829,6 @@ function OPSGROUP:CountRemainingTasks()
Ntot=Ntot+1
if task.type==OPSGROUP.TaskType.WAYPOINT then
--TODO: maybe check that waypoint was not already passed?
Nwp=Nwp+1
elseif task.type==OPSGROUP.TaskType.SCHEDULED then
Nsched=Nsched+1
@ -1833,7 +1925,7 @@ function OPSGROUP:GetTaskByID(id, status)
return nil
end
--- On after TaskExecute event.
--- On after "TaskExecute" event.
-- @param #OPSGROUP self
-- @param #string From From state.
-- @param #string Event Event.
@ -2868,6 +2960,173 @@ function OPSGROUP:onafterLeaveZone(From, Event, To, Zone)
self.inzones:Remove(zonename, true)
end
--- On after "LaserOn" event.
-- @param #OPSGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Point#COORDINATE Target Target Coordinate. Target can also be any POSITIONABLE from which we can obtain its coordinates.
function OPSGROUP:onafterLaserOn(From, Event, To, Target)
-- Assume we got a coordinate.
local coord=Target
-- Check if we have a POSITIONABLE.
if Target:IsInstanceOf("POSITIONABLE") then
local target=Target --Wrapper.Positionable#POSITIONABLE
if target:IsAlive() then
self.spot.Target=Target
coord=Target:GetCoordinate()
else
self:E("WARNING: LASER target is not alive!")
return
end
end
-- Set coordinate.
self.spot.Coordinate=coord
-- Get the first element alive.
local element=self:GetElementAlive()
if element then
-- Debug message.
self:T(self.lid.."Switching LASER on")
-- Start timer that calls the update twice per sec.
self.spot.timer:Start(nil, 0.5)
-- Set element.
self.spot.element=element
-- Get DCS unit.
local DCSunit=self.spot.element.unit:GetDCSObject()
-- Vec3.
self.spot.vec3=coord:GetVec3()
-- Height offset.
local offsetY=element.height
-- Create laser and IR beams.
self.spot.Laser=Spot.createLaser(DCSunit, {x=0, y=offsetY, z=0}, self.spot.vec3, self.spot.Code or 1688)
self.spot.IR=Spot.createInfraRed(DCSunit, {x=0, y=offsetY, z=0}, self.spot.vec3)
-- Laser is on.
self.spot.On=true
end
end
--- On after "LaserOff" event.
-- @param #OPSGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function OPSGROUP:onafterLaserOff(From, Event, To)
-- Debug message.
self:T(self.lid.."Switching LASER off")
-- "Destroy" the laser beam.
self.spot.Laser:destroy()
self.spot.IR:destroy()
-- Set to nil.
self.spot.Laser=nil
self.spot.IR=nil
-- Laser is off.
self.spot.On=false
end
--- On after "LaserCode" event. Changes the LASER code.
-- @param #OPSGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #number Code Laser code. Default is 1688.
function OPSGROUP:onafterLaserCode(From, Event, To, Code)
-- Default is 1688.
self.spot.Code=Code or 1688
-- Debug message.
self:T(self.lid..string.format("Setting LASER Code to %d", self.spot.Code))
if self.spot.On then
-- Debug info.
self:T(self.lid..string.format("Updating LASER Code to %d", self.spot.Code))
-- Set LASER code.
self.spot.Laser:setCode(self.spot.Code)
end
end
--- Update laser point.
-- @param #OPSGROUP self
function OPSGROUP:_UpdateLaser()
-- Firstly, check if laser is on.
if self.spot.On then
---
-- LASER is ON
--´-
-- Check if we have a POSITIONABLE to lase.
if self.spot.Target then
---
-- Lasing a possibly moving target
---
if self.spot.Target:IsAlive() then
-- Get current target position.
local vec3=self.spot.Target:GetVec3()
-- Calculate distance
local dist=UTILS.VecDist3D(vec3, self.spot.vec3)
-- Update laser if target moved more than one meter.
if dist>1 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]<value then
-- At least one type of ammunition is less than when spawned.
return false
end
end
return true
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -3469,16 +3750,25 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
-- Remove detour waypoint.
opsgroup:RemoveWaypointByID(uid)
-- Trigger event.
opsgroup:DetourReached()
if waypoint.detour==0 then
opsgroup:FullStop()
elseif waypoint.detour==1 then
opsgroup:Cruise()
if opsgroup:IsRearming() then
-- Trigger Rearming event.
opsgroup:Rearming()
else
opsgroup:E("ERROR: waypoint.detour should be 0 or 1")
-- Trigger DetourReached event.
opsgroup:DetourReached()
if waypoint.detour==0 then
opsgroup:FullStop()
elseif waypoint.detour==1 then
opsgroup:Cruise()
else
opsgroup:E("ERROR: waypoint.detour should be 0 or 1")
end
end
else
@ -4510,6 +4800,23 @@ function OPSGROUP:GetElementByName(unitname)
return nil
end
--- Get the first element of a group, which is alive.
-- @param #OPSGROUP self
-- @return #OPSGROUP.Element The element or `#nil` if no element is alive any more.
function OPSGROUP:GetElementAlive()
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
if element.status~=OPSGROUP.ElementStatus.DEAD then
if element.unit and element.unit:IsAlive() then
return element
end
end
end
return nil
end
--- Get number of elements alive.
-- @param #OPSGROUP self
-- @param #string status (Optional) Only count number, which are in a special status.
@ -4813,6 +5120,26 @@ function OPSGROUP:_CheckStuck()
end
--- Get coordinate from an object.
-- @param #OPSGROUP self
-- @param Wrapper.Object#OBJECT Object The object.
-- @return Core.Point#COORDINATE The coordinate of the object.
function OPSGROUP:_CoordinateFromObject(Object)
if Object:IsInstanceOf("COORDINATE") then
return Object
else
if Object:IsInstanceOf("POSITIONABLE") or Object:IsInstanceOf("ZONE_BASE") then
self:T(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE or ZONE. Trying to get coordinate")
return Object:GetCoordinate()
else
self:E(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE or ZONE!")
end
end
return nil
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------