mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge pull request #1362 from FlightControl-Master/FF/Ops
Ops Enhancements
This commit is contained in:
commit
bad8dc2220
@ -913,7 +913,7 @@ do -- FSM
|
||||
--- Check if FSM is in state.
|
||||
-- @param #FSM self
|
||||
-- @param #string State State name.
|
||||
-- @param #boolean If true, FSM is in this state.
|
||||
-- @return #boolean If true, FSM is in this state.
|
||||
function FSM:Is( State )
|
||||
return self.current == State
|
||||
end
|
||||
@ -921,7 +921,7 @@ do -- FSM
|
||||
--- Check if FSM is in state.
|
||||
-- @param #FSM self
|
||||
-- @param #string State State name.
|
||||
-- @param #boolean If true, FSM is in this state.
|
||||
-- @return #boolean If true, FSM is in this state.
|
||||
function FSM:is(state)
|
||||
return self.current == state
|
||||
end
|
||||
|
||||
@ -284,6 +284,12 @@ do -- COORDINATE
|
||||
return self
|
||||
end
|
||||
|
||||
--- Return the coordinates itself. Sounds stupid but can be useful for compatibility.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:GetCoordinate()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Return the coordinates of the COORDINATE in Vec3 format.
|
||||
-- @param #COORDINATE self
|
||||
@ -733,6 +739,13 @@ do -- COORDINATE
|
||||
return Velocity or 0
|
||||
end
|
||||
|
||||
--- Return the "name" of the COORDINATE. Obviously, a coordinate does not have a name like a unit, static or group. So here we take the MGRS coordinates of the position.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #string MGRS coordinates.
|
||||
function COORDINATE:GetName()
|
||||
local name=self:ToStringMGRS()
|
||||
return rname
|
||||
end
|
||||
|
||||
--- Return velocity text of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
-- @field #number dT Time interval between function calls in seconds.
|
||||
-- @field #number ncalls Counter of function calls.
|
||||
-- @field #number ncallsMax Max number of function calls. If reached, timer is stopped.
|
||||
-- @field #boolean isrunning If `true`, timer is running. Else it was not started yet or was stopped.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- *Better three hours too soon than a minute too late.* - William Shakespeare
|
||||
@ -111,7 +112,7 @@ _TIMERID=0
|
||||
|
||||
--- TIMER class version.
|
||||
-- @field #string version
|
||||
TIMER.version="0.1.0"
|
||||
TIMER.version="0.1.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -143,6 +144,9 @@ function TIMER:New(Function, ...)
|
||||
-- Number of function calls.
|
||||
self.ncalls=0
|
||||
|
||||
-- Not running yet.
|
||||
self.isrunning=false
|
||||
|
||||
-- Increase counter
|
||||
_TIMERID=_TIMERID+1
|
||||
|
||||
@ -186,6 +190,9 @@ function TIMER:Start(Tstart, dT, Duration)
|
||||
-- Set log id.
|
||||
self.lid=string.format("TIMER UID=%d/%d | ", self.uid, self.tid)
|
||||
|
||||
-- Is now running.
|
||||
self.isrunning=true
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Starting Timer in %.3f sec, dT=%s, Tstop=%s", self.Tstart-Tnow, tostring(self.dT), tostring(self.Tstop)))
|
||||
|
||||
@ -210,6 +217,9 @@ function TIMER:Stop(Delay)
|
||||
self:T(self.lid..string.format("Stopping timer by removing timer function after %d calls!", self.ncalls))
|
||||
timer.removeFunction(self.tid)
|
||||
|
||||
-- Not running any more.
|
||||
self.isrunning=false
|
||||
|
||||
-- Remove DB entry.
|
||||
--_TIMERDB[self.uid]=nil
|
||||
|
||||
@ -229,6 +239,13 @@ function TIMER:SetMaxFunctionCalls(Nmax)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Check if the timer has been started and was not stopped.
|
||||
-- @param #TIMER self
|
||||
-- @return #boolean If `true`, the timer is running.
|
||||
function TIMER:IsRunning()
|
||||
return self.isrunning
|
||||
end
|
||||
|
||||
--- Call timer function.
|
||||
-- @param #TIMER self
|
||||
-- @param #number time DCS model time in seconds.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -152,7 +152,7 @@ AIRWING = {
|
||||
|
||||
--- AIRWING class version.
|
||||
-- @field #string version
|
||||
AIRWING.version="0.5.0"
|
||||
AIRWING.version="0.5.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
@ -472,11 +472,19 @@ function AIRWING:FetchPayloadFromStock(UnitType, MissionType, Payloads)
|
||||
return nil
|
||||
elseif #payloads==1 then
|
||||
-- Only one payload anyway.
|
||||
return payloads[1]
|
||||
local payload=payloads[1] --#AIRWING.Payload
|
||||
if not payload.unlimited then
|
||||
payload.navail=payload.navail-1
|
||||
end
|
||||
return payload
|
||||
else
|
||||
-- Sort payloads.
|
||||
table.sort(payloads, sortpayloads)
|
||||
return payloads[1]
|
||||
local payload=payloads[1] --#AIRWING.Payload
|
||||
if not payload.unlimited then
|
||||
payload.navail=payload.navail-1
|
||||
end
|
||||
return payload
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -1,12 +1,29 @@
|
||||
--- **Ops** - Enhanced Ground Group.
|
||||
--
|
||||
-- **Main Features:**
|
||||
-- ## Main Features:
|
||||
--
|
||||
-- * Dynamically add and remove waypoints.
|
||||
-- * 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:
|
||||
--
|
||||
-- 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
|
||||
|
||||
@ -15,6 +32,7 @@
|
||||
-- @type ARMYGROUP
|
||||
-- @field #boolean adinfinitum Resume route at first waypoint when final waypoint is reached.
|
||||
-- @field #boolean formationPerma Formation that is used permanently and overrules waypoint formations.
|
||||
-- @field #boolean isMobile If true, group is mobile.
|
||||
-- @extends Ops.OpsGroup#OPSGROUP
|
||||
|
||||
--- *Your soul may belong to Jesus, but your ass belongs to the marines.* -- Eugene B. Sledge
|
||||
@ -36,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
|
||||
@ -46,7 +69,10 @@ ARMYGROUP.version="0.3.0"
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot.
|
||||
-- TODO: Suppression of fire.
|
||||
-- TODO: Check if group is mobile.
|
||||
-- TODO: F10 menu.
|
||||
-- DONE: Rearm. Specify a point where to go and wait until ammo is full.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@ -54,12 +80,12 @@ ARMYGROUP.version="0.3.0"
|
||||
|
||||
--- Create a new ARMYGROUP class object.
|
||||
-- @param #ARMYGROUP self
|
||||
-- @param #string GroupName Name of the group.
|
||||
-- @param Wrapper.Group#GROUP Group The group object. Can also be given by its group name as `#string`.
|
||||
-- @return #ARMYGROUP self
|
||||
function ARMYGROUP:New(GroupName)
|
||||
function ARMYGROUP:New(Group)
|
||||
|
||||
-- Inherit everything from FSM class.
|
||||
local self=BASE:Inherit(self, OPSGROUP:New(GroupName)) -- #ARMYGROUP
|
||||
local self=BASE:Inherit(self, OPSGROUP:New(Group)) -- #ARMYGROUP
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("ARMYGROUP %s | ", self.groupname)
|
||||
@ -73,11 +99,15 @@ function ARMYGROUP:New(GroupName)
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
self:AddTransition("*", "FullStop", "Holding") -- Hold position.
|
||||
self:AddTransition("*", "Cruise", "Cruising") -- Hold position.
|
||||
self:AddTransition("*", "Cruise", "Cruising") -- Cruise along the given route of waypoints.
|
||||
|
||||
self:AddTransition("*", "Detour", "OnDetour") -- Make a detour to a coordinate and resume route afterwards.
|
||||
self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate.
|
||||
|
||||
self:AddTransition("*", "Rearm", "Rearm") -- Group is send to a coordinate and waits until ammo is refilled.
|
||||
self:AddTransition("Rearm", "Rearming", "Rearming") -- Group has arrived at the rearming coodinate and is waiting to be fully rearmed.
|
||||
self:AddTransition("Rearming", "Rearmed", "Cruising") -- Group was rearmed.
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
------------------------
|
||||
@ -104,6 +134,8 @@ function ARMYGROUP:New(GroupName)
|
||||
self:HandleEvent(EVENTS.Dead, self.OnEventDead)
|
||||
self:HandleEvent(EVENTS.RemoveUnit, self.OnEventRemoveUnit)
|
||||
|
||||
--self:HandleEvent(EVENTS.Hit, self.OnEventHit)
|
||||
|
||||
-- Start the status monitoring.
|
||||
self:__Status(-1)
|
||||
|
||||
@ -164,6 +196,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)
|
||||
@ -182,6 +216,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)
|
||||
@ -224,7 +260,7 @@ end
|
||||
|
||||
--- Check if the group is currently on a detour.
|
||||
-- @param #ARMYGROUP self
|
||||
-- @return #boolean If true, group is on a detour
|
||||
-- @return #boolean If true, group is on a detour.
|
||||
function ARMYGROUP:IsOnDetour()
|
||||
return self:Is("OnDetour")
|
||||
end
|
||||
@ -266,6 +302,9 @@ function ARMYGROUP:onafterStatus(From, Event, To)
|
||||
self:_CheckDetectedUnits()
|
||||
end
|
||||
|
||||
-- Check ammo status.
|
||||
self:_CheckAmmoStatus()
|
||||
|
||||
-- Update position etc.
|
||||
self:_UpdatePosition()
|
||||
|
||||
@ -282,11 +321,11 @@ 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",
|
||||
fsmstate, self.currentwp, #self.waypoints, self:GetWaypointIndexNext(), speed, speedEx, self.heading, roe, alarm, formation, nTaskTot, nMissions)
|
||||
local text=string.format("%s [ROE-AS=%d-%d T/M=%d/%d]: Wp=%d/%d-->%d (final %s), Speed=%.1f (%d), Heading=%03d",
|
||||
fsmstate, roe, alarm, nTaskTot, nMissions, self.currentwp, #self.waypoints, self:GetWaypointIndexNext(), tostring(self.passedfinalwp), speed, speedEx, self.heading)
|
||||
self:I(self.lid..text)
|
||||
|
||||
end
|
||||
@ -340,7 +379,7 @@ function ARMYGROUP:onafterSpawned(From, Event, To)
|
||||
-- Update position.
|
||||
self:_UpdatePosition()
|
||||
|
||||
if self.ai then
|
||||
if self.isAI then
|
||||
|
||||
-- Set default ROE.
|
||||
self:SwitchROE(self.option.ROE)
|
||||
@ -358,10 +397,19 @@ function ARMYGROUP:onafterSpawned(From, Event, To)
|
||||
self:SetDefaultRadio(self.radio.Freq, self.radio.Modu, true)
|
||||
end
|
||||
|
||||
-- Formation
|
||||
if not self.option.Formation then
|
||||
self.option.Formation=self.optionDefault.Formation
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
@ -375,6 +423,10 @@ end
|
||||
-- @param #number Formation Formation of the group.
|
||||
function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation)
|
||||
|
||||
-- Debug info.
|
||||
local text=string.format("Update route n=%s, Speed=%s, Formation=%s", tostring(n), tostring(Speed), tostring(Formation))
|
||||
self:T(self.lid..text)
|
||||
|
||||
-- Update route from this waypoint number onwards.
|
||||
n=n or self:GetWaypointIndexNext(self.adinfinitum)
|
||||
|
||||
@ -451,9 +503,6 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation)
|
||||
local wp=_wp
|
||||
local text=string.format("WP #%d UID=%d type=%s: Speed=%d m/s, alt=%d m, Action=%s", i, wp.uid and wp.uid or 0, wp.type, wp.speed, wp.alt, wp.action)
|
||||
self:T(text)
|
||||
if false and wp.coordinate then
|
||||
wp.coordinate:MarkToAll(text)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -479,6 +528,43 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation)
|
||||
|
||||
end
|
||||
|
||||
--- On after "GotoWaypoint" event. Group will got to the given waypoint and execute its route from there.
|
||||
-- @param #ARMYGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #number UID The goto waypoint unique ID.
|
||||
-- @param #number Speed (Optional) Speed to waypoint in knots.
|
||||
-- @param #number Formation (Optional) Formation to waypoint.
|
||||
function ARMYGROUP:onafterGotoWaypoint(From, Event, To, UID, Speed, Formation)
|
||||
|
||||
local n=self:GetWaypointIndex(UID)
|
||||
|
||||
--env.info(string.format("FF AG Goto waypoint UID=%s Index=%s, Speed=%s, Formation=%s", tostring(UID), tostring(n), tostring(Speed), tostring(Formation)))
|
||||
|
||||
if n then
|
||||
|
||||
-- TODO: switch to re-enable waypoint tasks.
|
||||
if false then
|
||||
local tasks=self:GetTasksWaypoint(n)
|
||||
|
||||
for _,_task in pairs(tasks) do
|
||||
local task=_task --Ops.OpsGroup#OPSGROUP.Task
|
||||
task.status=OPSGROUP.TaskStatus.SCHEDULED
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Speed to waypoint.
|
||||
Speed=Speed or self:GetSpeedToWaypoint(n)
|
||||
|
||||
-- Update the route.
|
||||
self:UpdateRoute(n, Speed, Formation)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- On after "Detour" event.
|
||||
-- @param #ARMYGROUP self
|
||||
-- @param #string From From state.
|
||||
@ -508,6 +594,55 @@ function ARMYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Formation,
|
||||
|
||||
end
|
||||
|
||||
--- On after "Rearm" event.
|
||||
-- @param #ARMYGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param Core.Point#COORDINATE Coordinate Coordinate where to rearm.
|
||||
-- @param #number Formation Formation of the group.
|
||||
function ARMYGROUP:onafterRearm(From, Event, To, Coordinate, Formation)
|
||||
|
||||
-- ID of current waypoint.
|
||||
local uid=self:GetWaypointCurrent().uid
|
||||
|
||||
-- Add waypoint after current.
|
||||
local wp=self:AddWaypoint(Coordinate, nil, uid, Formation, true)
|
||||
|
||||
-- Set if we want to resume route after reaching the detour waypoint.
|
||||
wp.detour=0
|
||||
|
||||
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.
|
||||
@ -549,7 +684,7 @@ function ARMYGROUP:onafterCruise(From, Event, To, Speed, Formation)
|
||||
|
||||
end
|
||||
|
||||
--- On after Start event. Starts the ARMYGROUP FSM and event handlers.
|
||||
--- On after "Stop" event.
|
||||
-- @param #ARMYGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
@ -631,7 +766,7 @@ function ARMYGROUP:OnEventDead(EventData)
|
||||
|
||||
end
|
||||
|
||||
--- Event function handling the crash of a unit.
|
||||
--- Event function handling when a unit is removed from the game.
|
||||
-- @param #ARMYGROUP self
|
||||
-- @param Core.Event#EVENTDATA EventData Event data.
|
||||
function ARMYGROUP:OnEventRemoveUnit(EventData)
|
||||
@ -654,6 +789,22 @@ function ARMYGROUP:OnEventRemoveUnit(EventData)
|
||||
|
||||
end
|
||||
|
||||
--- Event function handling when a unit is hit.
|
||||
-- @param #ARMYGROUP self
|
||||
-- @param Core.Event#EVENTDATA EventData Event data.
|
||||
function ARMYGROUP:OnEventHit(EventData)
|
||||
|
||||
-- Check that this is the right group.
|
||||
if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then
|
||||
local unit=EventData.IniUnit
|
||||
local group=EventData.IniGroup
|
||||
local unitname=EventData.IniUnitName
|
||||
|
||||
-- TODO: suppression
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Routing
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -668,6 +819,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)
|
||||
|
||||
@ -680,7 +833,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)
|
||||
@ -689,15 +842,15 @@ 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
|
||||
|
||||
-- Debug info.
|
||||
self:I(self.lid..string.format("Adding waypoint UID=%d (index=%d), Speed=%.1f knots, Dist2Road=%d m, Action=%s", waypoint.uid, wpnumber, Speed, waypoint.roaddist, waypoint.action))
|
||||
self:T(self.lid..string.format("Adding waypoint UID=%d (index=%d), Speed=%.1f knots, Dist2Road=%d m, Action=%s", waypoint.uid, wpnumber, Speed, waypoint.roaddist, waypoint.action))
|
||||
|
||||
-- Update route.
|
||||
if Updateroute==nil or Updateroute==true then
|
||||
@ -726,8 +879,8 @@ function ARMYGROUP:_InitGroup()
|
||||
self.isNaval=false
|
||||
self.isGround=true
|
||||
|
||||
-- Ships are always AI.
|
||||
self.ai=true
|
||||
-- Ground are always AI.
|
||||
self.isAI=true
|
||||
|
||||
-- Is (template) group late activated.
|
||||
self.isLateActivated=self.template.lateActivation
|
||||
@ -765,51 +918,63 @@ 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.status=OPSGROUP.ElementStatus.INUTERO
|
||||
element.unit=unit
|
||||
element.status=OPSGROUP.ElementStatus.INUTERO
|
||||
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.
|
||||
if self.verbose>=2 then
|
||||
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)
|
||||
end
|
||||
|
||||
-- Add element to table.
|
||||
table.insert(self.elements, element)
|
||||
|
||||
self:GetAmmoUnit(unit, false)
|
||||
-- Get Descriptors.
|
||||
self.descriptors=self.descriptors or unit:GetDesc()
|
||||
|
||||
-- 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
|
||||
|
||||
|
||||
@ -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, AIRWING and WINGCOMMANDER 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
|
||||
|
||||
@ -1682,6 +1690,13 @@ function AUFTRAG:GetPriority()
|
||||
return self.prio
|
||||
end
|
||||
|
||||
--- Get casualties, i.e. number of units that died during this mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @return #number Number of dead units.
|
||||
function AUFTRAG:GetCasualties()
|
||||
return self.Ncasualties or 0
|
||||
end
|
||||
|
||||
--- Check if mission is "urgent".
|
||||
-- @param #AUFTRAG self
|
||||
-- @return #boolean If `true`, mission is "urgent".
|
||||
@ -1942,7 +1957,7 @@ function AUFTRAG:IsReadyToCancel()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-- Evaluate failure condition. One is enough.
|
||||
local failure=self:EvalConditionsAny(self.conditionFailure)
|
||||
|
||||
if failure then
|
||||
@ -1950,6 +1965,7 @@ function AUFTRAG:IsReadyToCancel()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Evaluate success consitions. One is enough.
|
||||
local success=self:EvalConditionsAny(self.conditionSuccess)
|
||||
|
||||
if success then
|
||||
|
||||
@ -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
|
||||
|
||||
@ -50,7 +64,7 @@
|
||||
--
|
||||
-- @extends Ops.OpsGroup#OPSGROUP
|
||||
|
||||
--- *To invent an airplane is nothing. To build one is something. To fly is everything.* -- Otto Lilienthal
|
||||
--- *To invent an airplane is nothing; to build one is something; to fly is everything.* -- Otto Lilienthal
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@ -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.
|
||||
@ -210,7 +225,7 @@ FLIGHTGROUP.version="0.6.0"
|
||||
|
||||
--- Create a new FLIGHTGROUP object and start the FSM.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param Wrapper.Group#GROUP group The group object. Can also be given as #string with the name of the group.
|
||||
-- @param Wrapper.Group#GROUP Group The group object. Can also be given by its group name as `#string`.
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:New(group)
|
||||
|
||||
@ -396,7 +411,7 @@ function FLIGHTGROUP:SetFlightControl(flightcontrol)
|
||||
table.insert(flightcontrol.flights, self)
|
||||
|
||||
-- Update flight's F10 menu.
|
||||
if self.ai==false then
|
||||
if self.isAI==false then
|
||||
self:_UpdateMenu(0.5)
|
||||
end
|
||||
|
||||
@ -705,7 +720,7 @@ end
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
---- Update status.
|
||||
-- @param #FLIHGTGROUP self
|
||||
-- @param #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:onbeforeStatus(From, Event, To)
|
||||
|
||||
-- First we check if elements are still alive. Could be that they were despawned without notice, e.g. when landing on a too small airbase.
|
||||
@ -1040,7 +1055,7 @@ function FLIGHTGROUP:OnEventEngineStartup(EventData)
|
||||
-- TODO: could be that this element is part of a human flight group.
|
||||
-- Problem: when player starts hot, the AI does too and starts to taxi immidiately :(
|
||||
-- when player starts cold, ?
|
||||
if self.ai then
|
||||
if self.isAI then
|
||||
self:ElementEngineOn(element)
|
||||
else
|
||||
if element.ai then
|
||||
@ -1447,7 +1462,7 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To)
|
||||
-- Update position.
|
||||
self:_UpdatePosition()
|
||||
|
||||
if self.ai then
|
||||
if self.isAI then
|
||||
|
||||
-- Set ROE.
|
||||
self:SwitchROE(self.option.ROE)
|
||||
@ -1522,7 +1537,7 @@ function FLIGHTGROUP:onafterParking(From, Event, To)
|
||||
self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.PARKING)
|
||||
|
||||
-- Update player menu.
|
||||
if not self.ai then
|
||||
if not self.isAI then
|
||||
self:_UpdateMenu(0.5)
|
||||
end
|
||||
|
||||
@ -1547,7 +1562,7 @@ function FLIGHTGROUP:onafterTaxiing(From, Event, To)
|
||||
if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then
|
||||
|
||||
-- Add AI flight to takeoff queue.
|
||||
if self.ai then
|
||||
if self.isAI then
|
||||
-- AI flights go directly to TAKEOFF as we don't know when they finished taxiing.
|
||||
self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.TAKEOFF)
|
||||
else
|
||||
@ -1586,7 +1601,7 @@ end
|
||||
function FLIGHTGROUP:onafterAirborne(From, Event, To)
|
||||
self:T(self.lid..string.format("Flight airborne"))
|
||||
|
||||
if self.ai then
|
||||
if self.isAI then
|
||||
self:_CheckGroupDone(1)
|
||||
else
|
||||
self:_UpdateMenu()
|
||||
@ -1737,7 +1752,7 @@ function FLIGHTGROUP:onbeforeUpdateRoute(From, Event, To, n)
|
||||
--end
|
||||
|
||||
-- Only AI flights.
|
||||
if not self.ai then
|
||||
if not self.isAI then
|
||||
allowed=false
|
||||
end
|
||||
|
||||
@ -1840,7 +1855,7 @@ end
|
||||
-- @param #number delay Delay in seconds.
|
||||
function FLIGHTGROUP:_CheckGroupDone(delay)
|
||||
|
||||
if self:IsAlive() and self.ai then
|
||||
if self:IsAlive() and self.isAI then
|
||||
|
||||
if delay and delay>0 then
|
||||
-- Delayed call.
|
||||
@ -2099,7 +2114,7 @@ function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, Sp
|
||||
|
||||
end
|
||||
|
||||
if self.ai then
|
||||
if self.isAI then
|
||||
|
||||
local routeto=false
|
||||
if fc or world.event.S_EVENT_KILL then
|
||||
@ -2279,7 +2294,7 @@ function FLIGHTGROUP:onafterHolding(From, Event, To)
|
||||
-- Set flight status to holding
|
||||
self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.HOLDING)
|
||||
|
||||
if not self.ai then
|
||||
if not self.isAI then
|
||||
self:_UpdateMenu()
|
||||
end
|
||||
|
||||
@ -2626,10 +2641,10 @@ function FLIGHTGROUP:_InitGroup()
|
||||
self.tacan=UTILS.DeepCopy(self.tacanDefault)
|
||||
|
||||
-- Is this purely AI?
|
||||
self.ai=not self:_IsHuman(group)
|
||||
self.isAI=not self:_IsHuman(group)
|
||||
|
||||
-- Create Menu.
|
||||
if not self.ai then
|
||||
if not self.isAI then
|
||||
self.menu=self.menu or {}
|
||||
self.menu.atc=self.menu.atc or {}
|
||||
self.menu.atc.root=self.menu.atc.root or MENU_GROUP:New(self.group, "ATC")
|
||||
@ -2665,7 +2680,7 @@ function FLIGHTGROUP:_InitGroup()
|
||||
text=text..string.format("Ceiling = %.1f feet\n", UTILS.MetersToFeet(self.ceiling))
|
||||
text=text..string.format("Tanker type = %s\n", tostring(self.tankertype))
|
||||
text=text..string.format("Refuel type = %s\n", tostring(self.refueltype))
|
||||
text=text..string.format("AI = %s\n", tostring(self.ai))
|
||||
text=text..string.format("AI = %s\n", tostring(self.isAI))
|
||||
text=text..string.format("Helicopter = %s\n", tostring(self.group:IsHelicopter()))
|
||||
text=text..string.format("Elements = %d\n", #self.elements)
|
||||
text=text..string.format("Waypoints = %d\n", #self.waypoints)
|
||||
@ -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)
|
||||
|
||||
@ -1,15 +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.
|
||||
-- * Let a submarine dive and surface.
|
||||
-- * 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:
|
||||
--
|
||||
-- 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
|
||||
|
||||
@ -19,6 +37,7 @@
|
||||
-- @field #boolean turning If true, group is currently turning.
|
||||
-- @field #NAVYGROUP.IntoWind intowind Into wind info.
|
||||
-- @field #table Qintowind Queue of "into wind" turns.
|
||||
-- @field #number intowindcounter Counter of into wind IDs.
|
||||
-- @field #number depth Ordered depth in meters.
|
||||
-- @field #boolean collisionwarning If true, collition warning.
|
||||
-- @field #boolean pathfindingOn If true, enable pathfining.
|
||||
@ -74,7 +93,9 @@ NAVYGROUP.version="0.5.0"
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Collision warning.
|
||||
-- TODO: Extend, shorten turn into wind windows
|
||||
-- TODO: Skipper menu.
|
||||
-- DONE: Collision warning.
|
||||
-- DONE: Detour, add temporary waypoint and resume route.
|
||||
-- DONE: Stop and resume route.
|
||||
-- DONE: Add waypoints.
|
||||
@ -109,7 +130,9 @@ function NAVYGROUP:New(GroupName)
|
||||
self:AddTransition("*", "Cruise", "Cruising") -- Hold position.
|
||||
|
||||
self:AddTransition("*", "TurnIntoWind", "IntoWind") -- Command the group to turn into the wind.
|
||||
self:AddTransition("*", "TurnIntoWindOver", "Cruising") -- Turn into wind is over.
|
||||
self:AddTransition("IntoWind", "TurnedIntoWind", "IntoWind") -- Group turned into wind.
|
||||
self:AddTransition("IntoWind", "TurnIntoWindStop", "IntoWind") -- Stop a turn into wind.
|
||||
self:AddTransition("IntoWind", "TurnIntoWindOver", "Cruising") -- Turn into wind is over.
|
||||
|
||||
self:AddTransition("*", "TurningStarted", "*") -- Group started turning.
|
||||
self:AddTransition("*", "TurningStopped", "*") -- Group stopped turning.
|
||||
@ -144,14 +167,6 @@ function NAVYGROUP:New(GroupName)
|
||||
-- Initialize the group.
|
||||
self:_InitGroup()
|
||||
|
||||
-- Debug trace.
|
||||
if false then
|
||||
self.Debug=true
|
||||
BASE:TraceOnOff(true)
|
||||
BASE:TraceClass(self.ClassName)
|
||||
BASE:TraceLevel(1)
|
||||
end
|
||||
|
||||
-- Handle events:
|
||||
self:HandleEvent(EVENTS.Birth, self.OnEventBirth)
|
||||
self:HandleEvent(EVENTS.Dead, self.OnEventDead)
|
||||
@ -272,7 +287,7 @@ function NAVYGROUP:AddTaskAttackGroup(TargetGroup, WeaponExpend, WeaponType, Clo
|
||||
return task
|
||||
end
|
||||
|
||||
--- Add aircraft recovery time window and recovery case.
|
||||
--- Create a turn into wind window. Note that this is not executed as it not added to the queue.
|
||||
-- @param #NAVYGROUP self
|
||||
-- @param #string starttime Start time, e.g. "8:00" for eight o'clock. Default now.
|
||||
-- @param #string stoptime Stop time, e.g. "9:00" for nine o'clock. Default 90 minutes after start time.
|
||||
@ -280,7 +295,7 @@ end
|
||||
-- @param #boolean uturn If true (or nil), carrier wil perform a U-turn and go back to where it came from before resuming its route to the next waypoint. If false, it will go directly to the next waypoint.
|
||||
-- @param #number offset Offset angle in degrees, e.g. to account for an angled runway. Default 0 deg.
|
||||
-- @return #NAVYGROUP.IntoWind Recovery window.
|
||||
function NAVYGROUP:CreateTurnIntoWind(starttime, stoptime, speed, uturn, offset)
|
||||
function NAVYGROUP:_CreateTurnIntoWind(starttime, stoptime, speed, uturn, offset)
|
||||
|
||||
-- Absolute mission time in seconds.
|
||||
local Tnow=timer.getAbsTime()
|
||||
@ -335,17 +350,17 @@ function NAVYGROUP:CreateTurnIntoWind(starttime, stoptime, speed, uturn, offset)
|
||||
return recovery
|
||||
end
|
||||
|
||||
--- Add aircraft recovery time window and recovery case.
|
||||
--- Add a time window, where the groups steams into the wind.
|
||||
-- @param #NAVYGROUP self
|
||||
-- @param #string starttime Start time, e.g. "8:00" for eight o'clock. Default now.
|
||||
-- @param #string stoptime Stop time, e.g. "9:00" for nine o'clock. Default 90 minutes after start time.
|
||||
-- @param #number speed Speed in knots during turn into wind leg.
|
||||
-- @param #boolean uturn If true (or nil), carrier wil perform a U-turn and go back to where it came from before resuming its route to the next waypoint. If false, it will go directly to the next waypoint.
|
||||
-- @param #boolean uturn If `true` (or `nil`), carrier wil perform a U-turn and go back to where it came from before resuming its route to the next waypoint. If false, it will go directly to the next waypoint.
|
||||
-- @param #number offset Offset angle in degrees, e.g. to account for an angled runway. Default 0 deg.
|
||||
-- @return #NAVYGROUP.IntoWind Recovery window.
|
||||
-- @return #NAVYGROUP.IntoWind Turn into window data table.
|
||||
function NAVYGROUP:AddTurnIntoWind(starttime, stoptime, speed, uturn, offset)
|
||||
|
||||
local recovery=self:CreateTurnIntoWind(starttime, stoptime, speed, uturn, offset)
|
||||
local recovery=self:_CreateTurnIntoWind(starttime, stoptime, speed, uturn, offset)
|
||||
|
||||
--TODO: check if window is overlapping with an other and if extend the window.
|
||||
|
||||
@ -355,6 +370,31 @@ function NAVYGROUP:AddTurnIntoWind(starttime, stoptime, speed, uturn, offset)
|
||||
return recovery
|
||||
end
|
||||
|
||||
--- Remove steam into wind window from queue. If the window is currently active, it is stopped first.
|
||||
-- @param #NAVYGROUP self
|
||||
-- @param #NAVYGROUP.IntoWind IntoWindData Turn into window data table.
|
||||
-- @return #NAVYGROUP self
|
||||
function NAVYGROUP:RemoveTurnIntoWind(IntoWindData)
|
||||
|
||||
-- Check if this is a window currently open.
|
||||
if self.intowind and self.intowind.Id==IntoWindData.Id then
|
||||
--env.info("FF stop in remove")
|
||||
self:TurnIntoWindStop()
|
||||
return
|
||||
end
|
||||
|
||||
for i,_tiw in pairs(self.Qintowind) do
|
||||
local tiw=_tiw --#NAVYGROUP.IntoWind
|
||||
if tiw.Id==IntoWindData.Id then
|
||||
--env.info("FF removing window "..tiw.Id)
|
||||
table.remove(self.Qintowind, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Check if the group is currently holding its positon.
|
||||
-- @param #NAVYGROUP self
|
||||
@ -527,6 +567,37 @@ function NAVYGROUP:onafterStatus(From, Event, To)
|
||||
|
||||
end
|
||||
|
||||
---
|
||||
-- Recovery Windows
|
||||
---
|
||||
|
||||
if self.verbose>=2 then
|
||||
|
||||
-- Debug output:
|
||||
local text=string.format(self.lid.."Turn into wind time windows:")
|
||||
|
||||
-- Handle case with no recoveries.
|
||||
if #self.Qintowind==0 then
|
||||
text=text.." none!"
|
||||
end
|
||||
|
||||
-- Loop over all slots.
|
||||
for i,_recovery in pairs(self.Qintowind) do
|
||||
local recovery=_recovery --#NAVYGROUP.IntoWind
|
||||
|
||||
-- Get start/stop clock strings.
|
||||
local Cstart=UTILS.SecondsToClock(recovery.Tstart)
|
||||
local Cstop=UTILS.SecondsToClock(recovery.Tstop)
|
||||
|
||||
-- Debug text.
|
||||
text=text..string.format("\n[%d] ID=%d Start=%s Stop=%s Open=%s Over=%s", i, recovery.Id, Cstart, Cstop, tostring(recovery.Open), tostring(recovery.Over))
|
||||
end
|
||||
|
||||
-- Debug output.
|
||||
self:I(self.lid..text)
|
||||
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- Tasks & Missions
|
||||
@ -568,7 +639,7 @@ function NAVYGROUP:onafterSpawned(From, Event, To)
|
||||
-- Update position.
|
||||
self:_UpdatePosition()
|
||||
|
||||
if self.ai then
|
||||
if self.isAI then
|
||||
|
||||
-- Set default ROE.
|
||||
self:SwitchROE(self.option.ROE)
|
||||
@ -592,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
|
||||
|
||||
@ -757,37 +832,84 @@ function NAVYGROUP:onafterTurnIntoWind(From, Event, To, IntoWind)
|
||||
|
||||
end
|
||||
|
||||
--- On before "TurnIntoWindStop" event.
|
||||
-- @param #NAVYGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
function NAVYGROUP:onbeforeTurnIntoWindStop(From, Event, To)
|
||||
|
||||
if self.intowind then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- On after "TurnIntoWindStop" event.
|
||||
-- @param #NAVYGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
function NAVYGROUP:onafterTurnIntoWindStop(From, Event, To)
|
||||
self:TurnIntoWindOver(self.intowind)
|
||||
end
|
||||
|
||||
--- On after "TurnIntoWindOver" event.
|
||||
-- @param #NAVYGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #number Duration Duration in seconds.
|
||||
-- @param #number Speed Speed in knots.
|
||||
-- @param #boolean Uturn Return to the place we came from.
|
||||
function NAVYGROUP:onafterTurnIntoWindOver(From, Event, To)
|
||||
-- @param #NAVYGROUP.IntoWind IntoWindData Data table.
|
||||
function NAVYGROUP:onafterTurnIntoWindOver(From, Event, To, IntoWindData)
|
||||
|
||||
-- Debug message.
|
||||
self:T2(self.lid.."Turn Into Wind Over!")
|
||||
if IntoWindData and self.intowind and IntoWindData.Id==self.intowind.Id then
|
||||
|
||||
self.intowind.Over=true
|
||||
self.intowind.Open=false
|
||||
-- Debug message.
|
||||
self:T2(self.lid.."Turn Into Wind Over!")
|
||||
|
||||
-- Remove additional waypoint.
|
||||
self:RemoveWaypointByID(self.intowind.waypoint.uid)
|
||||
-- Window over and not open anymore.
|
||||
self.intowind.Over=true
|
||||
self.intowind.Open=false
|
||||
|
||||
-- Remove additional waypoint.
|
||||
self:RemoveWaypointByID(self.intowind.waypoint.uid)
|
||||
|
||||
if self.intowind.Uturn then
|
||||
|
||||
---
|
||||
-- U-turn ==> Go to coordinate where we left the route.
|
||||
---
|
||||
|
||||
-- Detour to where we left the route.
|
||||
self:T(self.lid.."FF Turn Into Wind Over ==> Uturn!")
|
||||
self:Detour(self.intowind.Coordinate, self:GetSpeedCruise(), 0, true)
|
||||
|
||||
else
|
||||
|
||||
---
|
||||
-- Go directly to next waypoint.
|
||||
---
|
||||
|
||||
-- Next waypoint index and speed.
|
||||
local indx=self:GetWaypointIndexNext()
|
||||
local speed=self:GetWaypointSpeed(indx)
|
||||
|
||||
-- Update route.
|
||||
self:T(self.lid..string.format("FF Turn Into Wind Over ==> Next WP Index=%d at %.1f knots via update route!", indx, speed))
|
||||
self:__UpdateRoute(-1, indx, speed)
|
||||
|
||||
end
|
||||
|
||||
-- Set current window to nil.
|
||||
self.intowind=nil
|
||||
|
||||
-- Remove window from queue.
|
||||
self:RemoveTurnIntoWind(IntoWindData)
|
||||
|
||||
if self.intowind.Uturn then
|
||||
self:T(self.lid.."Turn Into Wind Over ==> Uturn!")
|
||||
self:Detour(self.intowind.Coordinate, self:GetSpeedCruise(), 0, true)
|
||||
else
|
||||
self:T(self.lid.."FF Turn Into Wind Over ==> Next WP!")
|
||||
local indx=self:GetWaypointIndexNext()
|
||||
local speed=self:GetWaypointSpeed(indx)
|
||||
self:__UpdateRoute(-1, indx, speed)
|
||||
end
|
||||
|
||||
self.intowind=nil
|
||||
|
||||
end
|
||||
|
||||
--- On after "FullStop" event.
|
||||
@ -874,6 +996,11 @@ end
|
||||
function NAVYGROUP:onafterTurningStopped(From, Event, To)
|
||||
self.turning=false
|
||||
self.collisionwarning=false
|
||||
|
||||
if self:IsSteamingIntoWind() then
|
||||
self:TurnedIntoWind()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- On after "CollisionWarning" event.
|
||||
@ -1009,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
|
||||
@ -1071,7 +1198,7 @@ function NAVYGROUP:_InitGroup()
|
||||
--self.isSubmarine=self.group:IsSubmarine()
|
||||
|
||||
-- Ships are always AI.
|
||||
self.ai=true
|
||||
self.isAI=true
|
||||
|
||||
-- Is (template) group late activated.
|
||||
self.isLateActivated=self.template.lateActivation
|
||||
@ -1111,51 +1238,64 @@ function NAVYGROUP:_InitGroup()
|
||||
for _,_unit in pairs(units) do
|
||||
local unit=_unit --Wrapper.Unit#UNIT
|
||||
|
||||
-- Get unit template.
|
||||
local unittemplate=unit:GetTemplate()
|
||||
|
||||
local element={} --#NAVYGROUP.Element
|
||||
element.name=unit:GetName()
|
||||
element.typename=unit:GetTypeName()
|
||||
element.status=OPSGROUP.ElementStatus.INUTERO
|
||||
element.unit=unit
|
||||
element.status=OPSGROUP.ElementStatus.INUTERO
|
||||
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.
|
||||
if self.verbose>=2 then
|
||||
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)
|
||||
end
|
||||
|
||||
-- Add element to table.
|
||||
table.insert(self.elements, element)
|
||||
|
||||
self:GetAmmoUnit(unit, false)
|
||||
-- Get Descriptors.
|
||||
self.descriptors=self.descriptors or unit:GetDesc()
|
||||
|
||||
-- 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 Navy 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/T=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Missiles, self.ammo.Torpedos)
|
||||
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 Navy 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/T=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Missiles, self.ammo.Torpedos)
|
||||
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
|
||||
|
||||
@ -1306,66 +1446,60 @@ function NAVYGROUP:_CheckTurnsIntoWind()
|
||||
|
||||
-- Get current abs time.
|
||||
local time=timer.getAbsTime()
|
||||
local Cnow=UTILS.SecondsToClock(time)
|
||||
|
||||
-- Debug output:
|
||||
local text=string.format(self.lid.."Recovery time windows:")
|
||||
|
||||
-- Handle case with no recoveries.
|
||||
if #self.Qintowind==0 then
|
||||
text=text.." none!"
|
||||
end
|
||||
|
||||
-- Sort windows wrt to start time.
|
||||
table.sort(self.Qintowind, function(a, b) return a.Tstart<b.Tstart end)
|
||||
|
||||
-- Loop over all slots.
|
||||
for _,_recovery in pairs(self.Qintowind) do
|
||||
local recovery=_recovery --#NAVYGROUP.IntoWind
|
||||
|
||||
-- Get start/stop clock strings.
|
||||
local Cstart=UTILS.SecondsToClock(recovery.Tstart)
|
||||
local Cstop=UTILS.SecondsToClock(recovery.Tstop)
|
||||
|
||||
-- Debug text.
|
||||
text=text..string.format("\n- Start=%s Stop=%s Open=%s Closed=%s", Cstart, Cstop, tostring(recovery.Open), tostring(recovery.Over))
|
||||
end
|
||||
|
||||
-- Debug output.
|
||||
self:T(self.lid..text)
|
||||
|
||||
|
||||
-- Loop over all slots.
|
||||
for _,_recovery in pairs(self.Qintowind) do
|
||||
local recovery=_recovery --#NAVYGROUP.IntoWind
|
||||
|
||||
if time>=recovery.Tstart and time<recovery.Tstop and not recovery.Open then
|
||||
self:TurnIntoWind(recovery)
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If into wind, check if over.
|
||||
if self.intowind then
|
||||
if timer.getAbsTime()>=self.intowind.Tstop then
|
||||
self:TurnIntoWindOver()
|
||||
|
||||
-- Check if time is over.
|
||||
if time>=self.intowind.Tstop then
|
||||
self:TurnIntoWindOver(self.intowind)
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
-- Get next window.
|
||||
local IntoWind=self:GetTurnIntoWindNext()
|
||||
|
||||
-- Start turn into wind.
|
||||
if IntoWind then
|
||||
self:TurnIntoWind(IntoWind)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Check queued turns into wind.
|
||||
--- Get the next turn into wind window, which is not yet running.
|
||||
-- @param #NAVYGROUP self
|
||||
-- @return #NAVYGROUP.IntoWind Next into wind data.
|
||||
function NAVYGROUP:GetNextTurnIntoWind()
|
||||
-- @return #NAVYGROUP.IntoWind Next into wind data. Could be `nil` if there is not next window.
|
||||
function NAVYGROUP:GetTurnIntoWindNext()
|
||||
|
||||
-- Loop over all windows.
|
||||
for _,_recovery in pairs(self.Qintowind) do
|
||||
local recovery=_recovery --#NAVYGROUP.IntoWind
|
||||
if #self.Qintowind>0 then
|
||||
|
||||
-- Get current abs time.
|
||||
local time=timer.getAbsTime()
|
||||
|
||||
-- Sort windows wrt to start time.
|
||||
table.sort(self.Qintowind, function(a, b) return a.Tstart<b.Tstart end)
|
||||
|
||||
-- Loop over all slots.
|
||||
for _,_recovery in pairs(self.Qintowind) do
|
||||
local recovery=_recovery --#NAVYGROUP.IntoWind
|
||||
|
||||
if time>=recovery.Tstart and time<recovery.Tstop and not (recovery.Open or recovery.Over) then
|
||||
return recovery
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get the turn into wind window, which is currently open.
|
||||
-- @param #NAVYGROUP self
|
||||
-- @return #NAVYGROUP.IntoWind Current into wind data. Could be `nil` if there is no window currenly open.
|
||||
function NAVYGROUP:GetTurnIntoWindCurrent()
|
||||
return self.intowind
|
||||
end
|
||||
|
||||
--- Get wind direction and speed at current position.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -2169,6 +2169,40 @@ function GROUP:GetThreatLevel()
|
||||
return threatlevelMax
|
||||
end
|
||||
|
||||
--- Get the unit in the group with the highest threat level, which is still alive.
|
||||
-- @param #GROUP self
|
||||
-- @return Wrapper.Unit#UNIT The most dangerous unit in the group.
|
||||
-- @return #number Threat level of the unit.
|
||||
function GROUP:GetHighestThreat()
|
||||
|
||||
-- Get units of the group.
|
||||
local units=self:GetUnits()
|
||||
|
||||
if units then
|
||||
|
||||
local threat=nil ; local maxtl=0
|
||||
for _,_unit in pairs(units or {}) do
|
||||
local unit=_unit --Wrapper.Unit#UNIT
|
||||
|
||||
if unit and unit:IsAlive() then
|
||||
|
||||
-- Threat level of group.
|
||||
local tl=unit:GetThreatLevel()
|
||||
|
||||
-- Check if greater the current threat.
|
||||
if tl>maxtl then
|
||||
maxtl=tl
|
||||
threat=unit
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return threat, maxtl
|
||||
end
|
||||
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
|
||||
--- Returns true if the first unit of the GROUP is in the air.
|
||||
-- @param Wrapper.Group#GROUP self
|
||||
|
||||
@ -492,8 +492,7 @@ end
|
||||
|
||||
--- Returns the unit's group if it exist and nil otherwise.
|
||||
-- @param Wrapper.Unit#UNIT self
|
||||
-- @return Wrapper.Group#GROUP The Group of the Unit.
|
||||
-- @return #nil The DCS Unit is not existing or alive.
|
||||
-- @return Wrapper.Group#GROUP The Group of the Unit or `nil` if the unit does not exist.
|
||||
function UNIT:GetGroup()
|
||||
self:F2( self.UnitName )
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user