This commit is contained in:
Frank 2020-08-13 01:21:02 +02:00
parent fb6ebc42a5
commit cf65c2af15
5 changed files with 435 additions and 311 deletions

View File

@ -21,7 +21,7 @@
-- --
-- === -- ===
-- --
-- ![Banner Image](..\Presentations\ARMYGROUP\NavyGroup_Main.jpg) -- ![Banner Image](..\Presentations\ARMYGROUP\ArmyGroup_Main.jpg)
-- --
-- # The ARMYGROUP Concept -- # The ARMYGROUP Concept
-- --
@ -33,12 +33,12 @@ ARMYGROUP = {
formationPerma = nil, formationPerma = nil,
} }
--- Navy group element. --- Army group element.
-- @type ARMYGROUP.Element -- @type ARMYGROUP.Element
-- @field #string name Name of the element, i.e. the unit. -- @field #string name Name of the element, i.e. the unit.
-- @field #string typename Type name. -- @field #string typename Type name.
--- NavyGroup version. --- Army Group version.
-- @field #string version -- @field #string version
ARMYGROUP.version="0.0.1" ARMYGROUP.version="0.0.1"
@ -151,8 +151,7 @@ end
--- Get coordinate of the closest road. --- Get coordinate of the closest road.
-- @param #ARMYGROUP self -- @param #ARMYGROUP self
-- @param #boolean switch If true or nil, patrol until the end of time. If false, go along the waypoints once and stop. -- @return Core.Point#COORDINATE Coordinate of a road closest to the group.
-- @return #ARMYGROUP self
function ARMYGROUP:GetClosestRoad() function ARMYGROUP:GetClosestRoad()
return self:GetCoordinate():GetClosestPointToRoad() return self:GetCoordinate():GetClosestPointToRoad()
end end
@ -174,6 +173,24 @@ function ARMYGROUP:AddTaskFireAtPoint(Coordinate, Radius, Nshots, WeaponType, Cl
end end
--- Add a *waypoint* task.
-- @param #ARMYGROUP self
-- @param Core.Point#COORDINATE Coordinate Coordinate of the target.
-- @param Ops.OpsGroup#OPSGROUP.Waypoint Waypoint Where the task is executed. Default is next waypoint.
-- @param #number Radius Radius in meters. Default 100 m.
-- @param #number Nshots Number of shots to fire. Default 3.
-- @param #number WeaponType Type of weapon. Default auto.
-- @param #number Prio Priority of the task.
function ARMYGROUP:AddTaskWaypointFireAtPoint(Coordinate, Waypoint, Radius, Nshots, WeaponType, Prio)
Waypoint=Waypoint or self:GetWaypointNext()
local DCStask=CONTROLLABLE.TaskFireAtPoint(nil, Coordinate:GetVec2(), Radius, Nshots, WeaponType)
self:AddTaskWaypoint(DCStask, Waypoint, nil, Prio)
end
--- Add a *scheduled* task. --- Add a *scheduled* task.
-- @param #ARMYGROUP self -- @param #ARMYGROUP self
-- @param Wrapper.Group#GROUP TargetGroup Target group. -- @param Wrapper.Group#GROUP TargetGroup Target group.
@ -189,6 +206,8 @@ function ARMYGROUP:AddTaskAttackGroup(TargetGroup, WeaponExpend, WeaponType, Clo
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Status -- Status
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -251,60 +270,11 @@ function ARMYGROUP:onafterStatus(From, Event, To)
--- ---
-- Tasks -- Tasks & Missions
--- ---
-- Task queue. self:_PrintTaskAndMissionStatus()
if #self.taskqueue>0 and self.verbose>1 then
local text=string.format("Tasks #%d", #self.taskqueue)
for i,_task in pairs(self.taskqueue) do
local task=_task --Ops.OpsGroup#OPSGROUP.Task
local name=task.description
local taskid=task.dcstask.id or "unknown"
local status=task.status
local clock=UTILS.SecondsToClock(task.time, true)
local eta=task.time-timer.getAbsTime()
local started=task.timestamp and UTILS.SecondsToClock(task.timestamp, true) or "N/A"
local duration=-1
if task.duration then
duration=task.duration
if task.timestamp then
-- Time the task is running.
duration=task.duration-(timer.getAbsTime()-task.timestamp)
else
-- Time the task is supposed to run.
duration=task.duration
end
end
-- Output text for element.
if task.type==OPSGROUP.TaskType.SCHEDULED then
text=text..string.format("\n[%d] %s (%s): status=%s, scheduled=%s (%d sec), started=%s, duration=%d", i, taskid, name, status, clock, eta, started, duration)
elseif task.type==OPSGROUP.TaskType.WAYPOINT then
text=text..string.format("\n[%d] %s (%s): status=%s, waypoint=%d, started=%s, duration=%d, stopflag=%d", i, taskid, name, status, task.waypoint, started, duration, task.stopflag:Get())
end
end
self:I(self.lid..text)
end
---
-- Missions
---
-- Current mission name.
if self.verbose>0 then
local Mission=self:GetMissionByID(self.currentmission)
-- Current status.
local text=string.format("Missions %d, Current: %s", self:CountRemainingMissison(), Mission and Mission.name or "none")
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
local Cstart= UTILS.SecondsToClock(mission.Tstart, true)
local Cstop = mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "INF"
text=text..string.format("\n[%d] %s (%s) status=%s (%s), Time=%s-%s, prio=%d wp=%s targets=%d",
i, tostring(mission.name), mission.type, mission:GetGroupStatus(self), tostring(mission.status), Cstart, Cstop, mission.prio, tostring(mission:GetGroupWaypointIndex(self)), mission:CountMissionTargets())
end
self:I(self.lid..text)
end
self:__Status(-30) self:__Status(-30)
end end
@ -350,11 +320,29 @@ function ARMYGROUP:onafterSpawned(From, Event, To)
if self.ai then if self.ai then
-- Set default ROE option. -- Set default ROE.
if self.option.ROE then
self:SwitchROE(self.option.ROE) self:SwitchROE(self.option.ROE)
else
self:SwitchROE(ENUMS.ROE.ReturnFire)
end
-- Set default Alarm State option. -- Set default Alarm State.
if self.option.Alarm then
self:SwitchAlarmstate(self.option.Alarm) self:SwitchAlarmstate(self.option.Alarm)
else
self:SwitchAlarmstate(0)
end
-- Turn TACAN beacon on.
if self.tacan.On then
self:_SwitchTACAN(self.tacan)
end
-- Turn on the radio.
if self.radio.On then
self:SwitchRadio(self.radio.Freq, self.radio.Modu)
end
end end
@ -385,8 +373,11 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation)
-- Waypoints. -- Waypoints.
local waypoints={} local waypoints={}
-- Total number of waypoints
local N=#self.waypoints
-- Add remaining waypoints to route. -- Add remaining waypoints to route.
for i=n, #self.waypoints do for i=n, N do
-- Copy waypoint. -- Copy waypoint.
local wp=UTILS.DeepCopy(self.waypoints[i]) --Ops.OpsGroup#OPSGROUP.Waypoint local wp=UTILS.DeepCopy(self.waypoints[i]) --Ops.OpsGroup#OPSGROUP.Waypoint
@ -404,7 +395,9 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation)
end end
if self.formationPerma then if self.formationPerma then
--if self.formationPerma==ENUMS.Formation.Vehicle.OnRoad then
wp.action=self.formationPerma wp.action=self.formationPerma
--end
elseif Formation then elseif Formation then
wp.action=Formation wp.action=Formation
end end
@ -429,16 +422,26 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation)
end end
if wp.roaddist>100 and wp.action==ENUMS.Formation.Vehicle.OnRoad then
env.info("FF Adding ON road waypoint")
--wp.roadcoord:MarkToAll("Added Road waypoint")
if formation==ENUMS.Formation.Vehicle.OnRoad then -- Waypoint is actually off road!
wp.action=ENUMS.Formation.Vehicle.OffRoad
local wpnext=self:GetWaypointNext()
if wpnext.action~=ENUMS.Formation.Vehicle.OnRoad then
-- Add "On Road" waypoint in between.
local wproad=wp.roadcoord:WaypointGround(wp.speed, ENUMS.Formation.Vehicle.OnRoad)
table.insert(waypoints, wproad)
end end
--if wp.formation==ENUMS.Formation.Vehicle.OnRoad and wp.action~=ENUMS.Formation.Vehicle.OnRoad then --and not self.formationPerma~=ENUMS.Formation.Vehicle.OnRoad then
--[[
if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp.roaddist>100 then
env.info("FF Adding ON road waypoint")
local wproad=wp.roadcoord:WaypointGround(wp.speed, ENUMS.Formation.Vehicle.OnRoad)
table.insert(waypoints, wproad)
end end
]]
-- Debug info. -- Debug info.
self:I(string.format("WP %d %s: Speed=%d m/s, alt=%d m, Action=%s", i, wp.type, wp.speed, wp.alt, wp.action)) self:I(string.format("WP %d %s: Speed=%d m/s, alt=%d m, Action=%s", i, wp.type, wp.speed, wp.alt, wp.action))
@ -716,10 +719,24 @@ function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation
-- Get closest point to road. -- Get closest point to road.
waypoint.roadcoord=Coordinate:GetClosestPointToRoad(false) waypoint.roadcoord=Coordinate:GetClosestPointToRoad(false)
waypoint.roadist=Coordinate:Get2DDistance(waypoint.roadcoord) if waypoint.roadcoord then
waypoint.roaddist=Coordinate:Get2DDistance(waypoint.roadcoord)
else
waypoint.roaddist=1000*1000 --1000 km.
end
--[[
if waypoint.roaddist>100 and waypoint.action==ENUMS.Formation.Vehicle.OnRoad then
waypoint.formation=ENUMS.Formation.Vehicle.OnRoad
waypoint.action=ENUMS.Formation.Vehicle.OffRoad
else
waypoint.formation=waypoint.action
end
]]
-- Debug info. -- Debug info.
self:T(self.lid..string.format("Adding GROUND waypoint #%d, speed=%.1f knots. Last waypoint passed was #%s. Total waypoints #%d", wpnumber, Speed, self.currentwp, #self.waypoints)) 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))
-- Update route. -- Update route.
if Updateroute==nil or Updateroute==true then if Updateroute==nil or Updateroute==true then
@ -771,7 +788,7 @@ function ARMYGROUP:_InitGroup()
self.position=self:GetCoordinate() self.position=self:GetCoordinate()
-- Radio parameters from template. -- Radio parameters from template.
self.radioOn=false -- Radio is always OFF for ground. self.radio.On=false -- Radio is always OFF for ground.
self.radio.Freq=133 self.radio.Freq=133
self.radio.Modu=radio.modulation.AM self.radio.Modu=radio.modulation.AM
@ -810,13 +827,13 @@ function ARMYGROUP:_InitGroup()
self.actype=unit:GetTypeName() self.actype=unit:GetTypeName()
-- Debug info. -- Debug info.
local text=string.format("Initialized Navy Group %s:\n", self.groupname) local text=string.format("Initialized Army Group %s:\n", self.groupname)
text=text..string.format("AC type = %s\n", self.actype) text=text..string.format("AC type = %s\n", self.actype)
text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedmax)) 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("Speed cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise))
text=text..string.format("Elements = %d\n", #self.elements) text=text..string.format("Elements = %d\n", #self.elements)
text=text..string.format("Waypoints = %d\n", #self.waypoints) 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.radioOn)) 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("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("FSM state = %s\n", self:GetState())
text=text..string.format("Is alive = %s\n", tostring(self:IsAlive())) text=text..string.format("Is alive = %s\n", tostring(self:IsAlive()))

View File

@ -824,60 +824,10 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
end end
--- ---
-- Tasks -- Tasks & Missions
--- ---
-- Task queue. self:_PrintTaskAndMissionStatus()
if self.verbose>1 and #self.taskqueue>0 then
local text=string.format("Tasks #%d", #self.taskqueue)
for i,_task in pairs(self.taskqueue) do
local task=_task --Ops.OpsGroup#OPSGROUP.Task
local name=task.description
local taskid=task.dcstask.id or "unknown"
local status=task.status
local clock=UTILS.SecondsToClock(task.time, true)
local eta=task.time-timer.getAbsTime()
local started=task.timestamp and UTILS.SecondsToClock(task.timestamp, true) or "N/A"
local duration=-1
if task.duration then
duration=task.duration
if task.timestamp then
-- Time the task is running.
duration=task.duration-(timer.getAbsTime()-task.timestamp)
else
-- Time the task is supposed to run.
duration=task.duration
end
end
-- Output text for element.
if task.type==OPSGROUP.TaskType.SCHEDULED then
text=text..string.format("\n[%d] %s (%s): status=%s, scheduled=%s (%d sec), started=%s, duration=%d", i, taskid, name, status, clock, eta, started, duration)
elseif task.type==OPSGROUP.TaskType.WAYPOINT then
text=text..string.format("\n[%d] %s (%s): status=%s, waypoint=%d, started=%s, duration=%d, stopflag=%d", i, taskid, name, status, task.waypoint, started, duration, task.stopflag:Get())
end
end
self:I(self.lid..text)
end
---
-- Missions
---
-- Current mission name.
if self.verbose>0 then
local Mission=self:GetMissionByID(self.currentmission)
-- Current status.
local text=string.format("Missions %d, Current: %s", self:CountRemainingMissison(), Mission and Mission.name or "none")
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
local Cstart= UTILS.SecondsToClock(mission.Tstart, true)
local Cstop = mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "INF"
text=text..string.format("\n[%d] %s (%s) status=%s (%s), Time=%s-%s, prio=%d wp=%s targets=%d",
i, tostring(mission.name), mission.type, mission:GetGroupStatus(self), tostring(mission.status), Cstart, Cstop, mission.prio, tostring(mission:GetGroupWaypointIndex(self)), mission:CountMissionTargets())
end
self:I(self.lid..text)
end
--- ---
-- Fuel State -- Fuel State
@ -1415,27 +1365,28 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To)
if self.ai then if self.ai then
-- Set default ROE and ROT options. -- Set default ROE.
if self.option.ROE then
self:SwitchROE(self.option.ROE) self:SwitchROE(self.option.ROE)
else
self:SwitchROE(ENUMS.ROE.ReturnFire)
end
-- Set default ROT.
if self.option.ROT then
self:SwitchROT(self.option.ROT) self:SwitchROT(self.option.ROT)
else
self:SwitchROE(ENUMS.ROT.PassiveDefense)
end
-- Turn TACAN beacon on. -- Turn TACAN beacon on.
if self.tacanDefault then if self.tacan.On then
self:SwitchTACAN(self.tacanDefault.Channel, self.tacanDefault.Morse, self.tacanDefault.BeaconName, self.tacanDefault.Band) self:_SwitchTACAN(self.tacan)
end end
-- Turn on the radio. -- Turn on the radio.
if self.radioDefault then if self.radio.On then
self:SwitchRadio(self.radioDefault.Freq, self.radioDefault.Modu) self:SwitchRadio(self.radio.Freq, self.radio.Modu)
else
self:SetDefaultRadio(self.radio.Freq, self.radio.Modu)
end
-- Set callsign.
if self.callsignDefault then
self:SwitchCallsign(self.callsignDefault.NumberSquad, self.callsignDefault.NumberGroup)
else
self:SetDefaultCallsign(self.callsign.NumberSquad, self.callsign.NumberGroup)
end end
-- TODO: make this input. -- TODO: make this input.
@ -1444,7 +1395,6 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To)
self.group:SetOption(AI.Option.Air.id.RTB_ON_BINGO, false) self.group:SetOption(AI.Option.Air.id.RTB_ON_BINGO, false)
--self.group:SetOption(AI.Option.Air.id.RADAR_USING, AI.Option.Air.val.RADAR_USING.FOR_CONTINUOUS_SEARCH) --self.group:SetOption(AI.Option.Air.id.RADAR_USING, AI.Option.Air.val.RADAR_USING.FOR_CONTINUOUS_SEARCH)
-- Update route. -- Update route.
self:__UpdateRoute(-0.5) self:__UpdateRoute(-0.5)
@ -2554,7 +2504,7 @@ function FLIGHTGROUP:_InitGroup()
self.position=self:GetCoordinate() self.position=self:GetCoordinate()
-- Radio parameters from template. -- Radio parameters from template.
self.radioOn=self.template.communication self.radio.On=self.template.communication
self.radio.Freq=self.template.frequency self.radio.Freq=self.template.frequency
self.radio.Modu=self.template.modulation self.radio.Modu=self.template.modulation
@ -2614,7 +2564,7 @@ function FLIGHTGROUP:_InitGroup()
text=text..string.format("Helicopter = %s\n", tostring(self.group:IsHelicopter())) text=text..string.format("Helicopter = %s\n", tostring(self.group:IsHelicopter()))
text=text..string.format("Elements = %d\n", #self.elements) text=text..string.format("Elements = %d\n", #self.elements)
text=text..string.format("Waypoints = %d\n", #self.waypoints) 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.radioOn)) 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/B=%d/M=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Bombs, self.ammo.Missiles) text=text..string.format("Ammo = %d (G=%d/R=%d/B=%d/M=%d)\n", self.ammo.Total, self.ammo.Guns, self.ammo.Rockets, self.ammo.Bombs, self.ammo.Missiles)
text=text..string.format("FSM state = %s\n", self:GetState()) text=text..string.format("FSM state = %s\n", self:GetState())
text=text..string.format("Is alive = %s\n", tostring(self.group:IsAlive())) text=text..string.format("Is alive = %s\n", tostring(self.group:IsAlive()))

View File

@ -95,8 +95,8 @@ function NAVYGROUP:New(GroupName)
self.lid=string.format("NAVYGROUP %s | ", self.groupname) self.lid=string.format("NAVYGROUP %s | ", self.groupname)
-- Defaults -- Defaults
self:SetDefaultROE() --self:SetDefaultROE()
self:SetDefaultAlarmstate() --self:SetDefaultAlarmstate()
self:SetDetection() self:SetDetection()
self:SetPatrolAdInfinitum(true) self:SetPatrolAdInfinitum(true)
@ -205,6 +205,27 @@ function NAVYGROUP:AddTaskFireAtPoint(Coordinate, Radius, Nshots, WeaponType, Cl
return task return task
end end
--- Add a *waypoint* task.
-- @param #NAVYGROUP self
-- @param Core.Point#COORDINATE Coordinate Coordinate of the target.
-- @param Ops.OpsGroup#OPSGROUP.Waypoint Waypoint Where the task is executed. Default is next waypoint.
-- @param #number Radius Radius in meters. Default 100 m.
-- @param #number Nshots Number of shots to fire. Default 3.
-- @param #number WeaponType Type of weapon. Default auto.
-- @param #number Prio Priority of the task.
-- @return Ops.OpsGroup#OPSGROUP.Task The task table.
function NAVYGROUP:AddTaskWaypointFireAtPoint(Coordinate, Waypoint, Radius, Nshots, WeaponType, Prio)
Waypoint=Waypoint or self:GetWaypointNext()
local DCStask=CONTROLLABLE.TaskFireAtPoint(nil, Coordinate:GetVec2(), Radius, Nshots, WeaponType)
local task=self:AddTaskWaypoint(DCStask, Waypoint, nil, Prio)
return task
end
--- Add a *scheduled* task. --- Add a *scheduled* task.
-- @param #NAVYGROUP self -- @param #NAVYGROUP self
-- @param Wrapper.Group#GROUP TargetGroup Target group. -- @param Wrapper.Group#GROUP TargetGroup Target group.
@ -408,14 +429,16 @@ function NAVYGROUP:onafterStatus(From, Event, To)
-- Check free path ahead. -- Check free path ahead.
freepath=self:_CheckFreePath(freepath, 100) freepath=self:_CheckFreePath(freepath, 100)
if freepath<5000 then if freepath<5000 and not self.collisionwarning then
-- Issue a collision warning event.
self:CollisionWarning() self:CollisionWarning()
end end
if not self.ispathfinding then if not self.ispathfinding then
if freepath<5000 then if freepath<5000 then
--self.ispathfinding=self:_FindPathToNextWaypoint() self.ispathfinding=self:_FindPathToNextWaypoint()
end end
end end
@ -464,60 +487,10 @@ function NAVYGROUP:onafterStatus(From, Event, To)
--- ---
-- Tasks -- Tasks & Missions
--- ---
-- Task queue. self:_PrintTaskAndMissionStatus()
if self.verbose>-1 and #self.taskqueue>0 then
local text=string.format("Tasks #%d", #self.taskqueue)
for i,_task in pairs(self.taskqueue) do
local task=_task --Ops.OpsGroup#OPSGROUP.Task
local name=task.description
local taskid=task.dcstask.id or "unknown"
local status=task.status
local clock=UTILS.SecondsToClock(task.time, true)
local eta=task.time-timer.getAbsTime()
local started=task.timestamp and UTILS.SecondsToClock(task.timestamp, true) or "N/A"
local duration=-1
if task.duration then
duration=task.duration
if task.timestamp then
-- Time the task is running.
duration=task.duration-(timer.getAbsTime()-task.timestamp)
else
-- Time the task is supposed to run.
duration=task.duration
end
end
-- Output text for element.
if task.type==OPSGROUP.TaskType.SCHEDULED then
text=text..string.format("\n[%d] %s (%s): status=%s, scheduled=%s (%d sec), started=%s, duration=%d", i, taskid, name, status, clock, eta, started, duration)
elseif task.type==OPSGROUP.TaskType.WAYPOINT then
text=text..string.format("\n[%d] %s (%s): status=%s, waypoint=%d, started=%s, duration=%d, stopflag=%d", i, taskid, name, status, task.waypoint, started, duration, task.stopflag:Get())
end
end
self:I(self.lid..text)
end
---
-- Missions
---
-- Current mission name.
if self.verbose>0 then
local Mission=self:GetMissionByID(self.currentmission)
-- Current status.
local text=string.format("Missions %d, Current: %s", self:CountRemainingMissison(), Mission and Mission.name or "none")
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
local Cstart= UTILS.SecondsToClock(mission.Tstart, true)
local Cstop = mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "INF"
text=text..string.format("\n[%d] %s (%s) status=%s (%s), Time=%s-%s, prio=%d wp=%s targets=%d",
i, tostring(mission.name), mission.type, mission:GetGroupStatus(self), tostring(mission.status), Cstart, Cstop, mission.prio, tostring(mission:GetGroupWaypointIndex(self)), mission:CountMissionTargets())
end
self:I(self.lid..text)
end
-- Next status update in 30 seconds. -- Next status update in 30 seconds.
@ -566,26 +539,34 @@ function NAVYGROUP:onafterSpawned(From, Event, To)
if self.ai then if self.ai then
-- Set default ROE. -- Set default ROE.
if self.option.ROE then
self:SwitchROE(self.option.ROE) self:SwitchROE(self.option.ROE)
else
self:SwitchROE(ENUMS.ROE.ReturnFire)
end
-- Set default Alarm State. -- Set default Alarm State.
if self.option.Alarm then
self:SwitchAlarmstate(self.option.Alarm) self:SwitchAlarmstate(self.option.Alarm)
else
self:SwitchAlarmstate(0)
end
-- Turn TACAN beacon on. -- Turn TACAN beacon on.
if self.tacanDefault then if self.tacan.On then
self:SwitchTACAN(self.tacanDefault.Channel, self.tacanDefault.Morse, self.tacanDefault.BeaconName, self.tacanDefault.Band) self:_SwitchTACAN(self.tacan)
end end
-- Turn ICLS on. -- Turn ICLS on.
if self.iclsDefault then if self.icls.On then
self:SwitchICLS(self.iclsDefault.Channel, self.iclsDefault.Morse, self.iclsDefault.BeaconName) self:_SwitchICLS(self.icls)
end end
-- Turn on the radio. -- Turn on the radio.
if self.radioDefault then if self.radio.On then
self:SwitchRadio(self.radioDefault.Freq, self.radioDefault.Modu) self:SwitchRadio(self.radio.Freq, self.radio.Modu)
else else
self:SetDefaultRadio(self.radio.Freq, self.radio.Modu) self.radio.On=true -- Radio is always on for ships. If not set, it is default.
end end
end end
@ -776,7 +757,7 @@ function NAVYGROUP:onafterTurnIntoWind(From, Event, To, IntoWind)
IntoWind.waypoint=wptiw IntoWind.waypoint=wptiw
if IntoWind.Uturn then if IntoWind.Uturn and self.Debug then
IntoWind.Coordinate:MarkToAll("Return coord") IntoWind.Coordinate:MarkToAll("Return coord")
end end
@ -880,6 +861,34 @@ function NAVYGROUP:onafterSurface(From, Event, To, Speed)
end end
--- On after "TurningStarted" event.
-- @param #NAVYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function NAVYGROUP:onafterTurningStarted(From, Event, To)
self.turning=true
end
--- On after "TurningStarted" event.
-- @param #NAVYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function NAVYGROUP:onafterTurningStopped(From, Event, To)
self.turning=false
self.collisionwarning=false
end
--- On after "CollisionWarning" event.
-- @param #NAVYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function NAVYGROUP:onafterCollisionWarning(From, Event, To)
self.collisionwarning=true
end
--- On after "Dead" event. --- On after "Dead" event.
-- @param #NAVYGROUP self -- @param #NAVYGROUP self
-- @param #string From From state. -- @param #string From From state.
@ -1030,6 +1039,16 @@ end
-- @return Ops.OpsGroup#OPSGROUP.Waypoint Waypoint table. -- @return Ops.OpsGroup#OPSGROUP.Waypoint Waypoint table.
function NAVYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Depth, Updateroute) function NAVYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Depth, Updateroute)
if not Coordinate:IsInstanceOf("COORDINATE") then
if Coordinate:IsInstanceOf("POSITIONABLE") then
self:I(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE. Trying to get coordinate")
Coordinate=Coordinate:GetCoordinate()
else
self:E(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE!")
return nil
end
end
-- Set waypoint index. -- Set waypoint index.
local wpnumber=self:GetWaypointIndexAfterID(AfterWaypointWithID) local wpnumber=self:GetWaypointIndexAfterID(AfterWaypointWithID)
@ -1107,7 +1126,7 @@ function NAVYGROUP:_InitGroup()
self.position=self:GetCoordinate() self.position=self:GetCoordinate()
-- Radio parameters from template. -- Radio parameters from template.
self.radioOn=true -- Radio is always on for ships. self.radio.On=false -- Radio is always on for ships but we set it to false to check if it has been changed before spawn.
self.radio.Freq=tonumber(self.template.units[1].frequency)/1000000 self.radio.Freq=tonumber(self.template.units[1].frequency)/1000000
self.radio.Modu=tonumber(self.template.units[1].modulation) self.radio.Modu=tonumber(self.template.units[1].modulation)
@ -1152,7 +1171,7 @@ function NAVYGROUP:_InitGroup()
text=text..string.format("Speed cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise)) 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("Elements = %d\n", #self.elements)
text=text..string.format("Waypoints = %d\n", #self.waypoints) 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.radioOn)) 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("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("FSM state = %s\n", self:GetState())
text=text..string.format("Is alive = %s\n", tostring(self.group:IsAlive())) text=text..string.format("Is alive = %s\n", tostring(self.group:IsAlive()))
@ -1190,7 +1209,13 @@ function NAVYGROUP:_CheckFreePath(DistanceMax, dx)
return distance return distance
end end
local offsetY=1 -- Offset above sea level.
local offsetY=0.1
-- Current bug on Caucasus. LoS returns false.
if UTILS.GetDCSMap()==DCSMAP.Caucasus then
offsetY=5.01
end
-- Current coordinate. -- Current coordinate.
local coordinate=self:GetCoordinate():SetAltitude(offsetY, true) local coordinate=self:GetCoordinate():SetAltitude(offsetY, true)
@ -1199,7 +1224,7 @@ function NAVYGROUP:_CheckFreePath(DistanceMax, dx)
local heading=self:GetHeading() local heading=self:GetHeading()
-- Check from 500 meters in front. -- Check from 500 meters in front.
coordinate=coordinate:Translate(500, heading, true) --coordinate=coordinate:Translate(500, heading, true)
local function LoS(dist) local function LoS(dist)
local checkcoord=coordinate:Translate(dist, heading, true) local checkcoord=coordinate:Translate(dist, heading, true)
@ -1534,7 +1559,7 @@ function NAVYGROUP:_FindPathToNextWaypoint()
local delta=dist/10 local delta=dist/10
-- Create a grid of nodes. We only want nodes of surface type water. -- Create a grid of nodes. We only want nodes of surface type water.
astar:CreateGrid({land.SurfaceType.WATER}, boxwidth, spacex, delta, delta*2, false) astar:CreateGrid({land.SurfaceType.WATER}, boxwidth, spacex, delta, delta*2, self.Debug)
-- Valid neighbour nodes need to have line of sight. -- Valid neighbour nodes need to have line of sight.
astar:SetValidNeighbourLoS(400) astar:SetValidNeighbourLoS(400)

View File

@ -58,16 +58,13 @@
-- --
-- @field #OPSGROUP.Radio radio Current radio settings. -- @field #OPSGROUP.Radio radio Current radio settings.
-- @field #OPSGROUP.Radio radioDefault Default radio settings. -- @field #OPSGROUP.Radio radioDefault Default radio settings.
-- @field #boolean radioOn If true, radio is currently turned on.
-- @field Core.RadioQueue#RADIOQUEUE radioQueue Radio queue. -- @field Core.RadioQueue#RADIOQUEUE radioQueue Radio queue.
-- --
-- @field #OPSGROUP.Beacon tacan Current TACAN settings. -- @field #OPSGROUP.Beacon tacan Current TACAN settings.
-- @field #OPSGROUP.Beacon tacanDefault Default TACAN settings. -- @field #OPSGROUP.Beacon tacanDefault Default TACAN settings.
-- @field #boolean tacanOn If true, TACAN is currently active.
-- --
-- @field #OPSGROUP.Beacon icls Current ICLS settings. -- @field #OPSGROUP.Beacon icls Current ICLS settings.
-- @field #OPSGROUP.Beacon iclsDefault Default ICLS settings. -- @field #OPSGROUP.Beacon iclsDefault Default ICLS settings.
-- @field #boolean iclsOn If true, ICLS is currently active.
-- --
-- @field #OPSGROUP.Option option Current optional settings. -- @field #OPSGROUP.Option option Current optional settings.
-- @field #OPSGROUP.Option optionDefault Default option settings. -- @field #OPSGROUP.Option optionDefault Default option settings.
@ -202,11 +199,13 @@ OPSGROUP.TaskType={
-- @field #string Band Band "X" or "Y" for TACAN beacon. -- @field #string Band Band "X" or "Y" for TACAN beacon.
-- @field #string BeaconName Name of the unit acting as beacon. -- @field #string BeaconName Name of the unit acting as beacon.
-- @field Wrapper.Unit#UNIT BeaconUnit Unit object acting as beacon. -- @field Wrapper.Unit#UNIT BeaconUnit Unit object acting as beacon.
-- @field #boolean On If true, beacon is on, if false, beacon is turned off. If nil, has not been used yet.
--- Radio data. --- Radio data.
-- @type OPSGROUP.Radio -- @type OPSGROUP.Radio
-- @field #number Freq Frequency -- @field #number Freq Frequency
-- @field #number Modu Modulation. -- @field #number Modu Modulation.
-- @field #boolean On If true, radio is on, if false, radio is turned off. If nil, has not been used yet.
--- Callsign data. --- Callsign data.
-- @type OPSGROUP.Callsign -- @type OPSGROUP.Callsign
@ -255,7 +254,9 @@ OPSGROUP.TaskType={
-- @field #boolean astar If true, this waypint was found by A* pathfinding algorithm. -- @field #boolean astar If true, this waypint was found by A* pathfinding algorithm.
-- @field Core.Point#COORDINATE coordinate Waypoint coordinate. -- @field Core.Point#COORDINATE coordinate Waypoint coordinate.
-- @field Core.Point#COORDINATE roadcoord Closest point to road. -- @field Core.Point#COORDINATE roadcoord Closest point to road.
-- @field #number roaddist Distance to closest point on road.
-- @field Wrapper.Marker#MARKER marker Marker on the F10 map. -- @field Wrapper.Marker#MARKER marker Marker on the F10 map.
-- @field #string formation Ground formation. Similar to action but on/off road.
--- NavyGroup version. --- NavyGroup version.
-- @field #string version -- @field #string version
@ -864,6 +865,14 @@ end
--- Get unique ID of waypoint. --- Get unique ID of waypoint.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #OPSGROUP.Waypoint waypoint The waypoint data table.
-- @return #number Unique ID.
function OPSGROUP:GetWaypointUID(waypoint)
return waypoint.uid
end
--- Get unique ID of waypoint given its index.
-- @param #OPSGROUP self
-- @param #number indx Waypoint index. -- @param #number indx Waypoint index.
-- @return #number Unique ID. -- @return #number Unique ID.
function OPSGROUP:GetWaypointID(indx) function OPSGROUP:GetWaypointID(indx)
@ -1213,7 +1222,7 @@ function OPSGROUP:AddTaskWaypoint(task, Waypoint, description, prio, duration)
-- Task data structure. -- Task data structure.
local newtask={} --#OPSGROUP.Task local newtask={} --#OPSGROUP.Task
newtask.description=description newtask.description=description or string.format("Task #%d", self.taskcounter)
newtask.status=OPSGROUP.TaskStatus.SCHEDULED newtask.status=OPSGROUP.TaskStatus.SCHEDULED
newtask.dcstask=task newtask.dcstask=task
newtask.prio=prio or 50 newtask.prio=prio or 50
@ -2592,6 +2601,72 @@ function OPSGROUP:_CheckGroupDone(delay)
end end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Status Info Common to Air, Land and Sea
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Print info on mission and task status to DCS log file.
-- @param #OPSGROUP self
function OPSGROUP:_PrintTaskAndMissionStatus()
---
-- Tasks: verbose >= 2
---
-- Task queue.
if #self.taskqueue>0 and self.verbose>=2 then
local text=string.format("Tasks #%d", #self.taskqueue)
for i,_task in pairs(self.taskqueue) do
local task=_task --Ops.OpsGroup#OPSGROUP.Task
local name=task.description
local taskid=task.dcstask.id or "unknown"
local status=task.status
local clock=UTILS.SecondsToClock(task.time, true)
local eta=task.time-timer.getAbsTime()
local started=task.timestamp and UTILS.SecondsToClock(task.timestamp, true) or "N/A"
local duration=-1
if task.duration then
duration=task.duration
if task.timestamp then
-- Time the task is running.
duration=task.duration-(timer.getAbsTime()-task.timestamp)
else
-- Time the task is supposed to run.
duration=task.duration
end
end
-- Output text for element.
if task.type==OPSGROUP.TaskType.SCHEDULED then
text=text..string.format("\n[%d] %s (%s): status=%s, scheduled=%s (%d sec), started=%s, duration=%d", i, taskid, name, status, clock, eta, started, duration)
elseif task.type==OPSGROUP.TaskType.WAYPOINT then
text=text..string.format("\n[%d] %s (%s): status=%s, waypoint=%d, started=%s, duration=%d, stopflag=%d", i, taskid, name, status, task.waypoint, started, duration, task.stopflag:Get())
end
end
self:I(self.lid..text)
end
---
-- Missions: verbose>=1
---
-- Current mission name.
if self.verbose>0 then
local Mission=self:GetMissionByID(self.currentmission)
-- Current status.
local text=string.format("Missions %d, Current: %s", self:CountRemainingMissison(), Mission and Mission.name or "none")
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
local Cstart= UTILS.SecondsToClock(mission.Tstart, true)
local Cstop = mission.Tstop and UTILS.SecondsToClock(mission.Tstop, true) or "INF"
text=text..string.format("\n[%d] %s (%s) status=%s (%s), Time=%s-%s, prio=%d wp=%s targets=%d",
i, tostring(mission.name), mission.type, mission:GetGroupStatus(self), tostring(mission.status), Cstart, Cstop, mission.prio, tostring(mission:GetGroupWaypointIndex(self)), mission:CountMissionTargets())
end
self:I(self.lid..text)
end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Waypoints & Routing -- Waypoints & Routing
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -2653,9 +2728,13 @@ function OPSGROUP:InitWaypoints()
for index,wp in pairs(self.waypoints0) do for index,wp in pairs(self.waypoints0) do
local waypoint=self:_CreateWaypoint(wp) --local waypoint=self:_CreateWaypoint(wp)
--self:_AddWaypoint(waypoint)
self:_AddWaypoint(waypoint) local coordinate=COORDINATE:New(wp.x, wp.alt, wp.y)
local speedknots=UTILS.MpsToKnots(wp.speed)
self:AddWaypoint(coordinate, speedknots, index-1, nil, false)
end end
@ -2871,19 +2950,26 @@ end
--- Set current ROE for the group. --- Set current ROE for the group.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string roe ROE of group. Default is the value defined by :SetDefaultROE(). -- @param #string roe ROE of group. Default is `ENUMS.ROE.ReturnFire`.
-- @return #OPSGROUP self -- @return #OPSGROUP self
function OPSGROUP:SwitchROE(roe) function OPSGROUP:SwitchROE(roe)
self.option.ROE=roe or self.optionDefault.ROE if self:IsAlive() or self:IsInUtero() then
if self:IsAlive() then self.option.ROE=roe or ENUMS.ROE.ReturnFire
self.group:OptionROE(self.option.ROE) if self:IsInUtero() then
self:I(self.lid..string.format("Setting current ROE=%d when GROUP is SPAWNED", self.option.ROE))
else
self.group:OptionROE(roe)
self:I(self.lid..string.format("Setting current ROE=%d (0=WeaponFree, 1=OpenFireWeaponFree, 2=OpenFire, 3=ReturnFire, 4=WeaponHold)", self.option.ROE)) self:I(self.lid..string.format("Setting current ROE=%d (0=WeaponFree, 1=OpenFireWeaponFree, 2=OpenFire, 3=ReturnFire, 4=WeaponHold)", self.option.ROE))
end
else else
-- TODO WARNING self:E(self.lid.."WARNING: Cannot switch ROE! Group is not alive")
end end
return self return self
@ -2907,19 +2993,26 @@ end
--- Set ROT for the group. --- Set ROT for the group.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string rot ROT of group. Default is the value defined by :SetDefaultROT(). -- @param #string rot ROT of group. Default is `ENUMS.ROT.PassiveDefense`.
-- @return #OPSGROUP self -- @return #OPSGROUP self
function OPSGROUP:SwitchROT(rot) function OPSGROUP:SwitchROT(rot)
self.option.ROT=rot or self.optionDefault.ROT if self:IsAlive() or self:IsInUtero() then
if self:IsAlive() then self.option.ROT=rot or ENUMS.ROT.PassiveDefense
if self:IsInUtero() then
self:I(self.lid..string.format("Setting current ROT=%d when GROUP is SPAWNED", self.option.ROT))
else
self.group:OptionROT(self.option.ROT) self.group:OptionROT(self.option.ROT)
self:T2(self.lid..string.format("Setting current ROT=%d (0=NoReaction, 1=Passive, 2=Evade, 3=ByPass, 4=AllowAbort)", self.option.ROT)) self:I(self.lid..string.format("Setting current ROT=%d (0=NoReaction, 1=Passive, 2=Evade, 3=ByPass, 4=AllowAbort)", self.option.ROT))
end
else else
-- TODO WARNING self:E(self.lid.."WARNING: Cannot switch ROT! Group is not alive")
end end
return self return self
@ -2943,14 +3036,23 @@ function OPSGROUP:SetDefaultAlarmstate(alarmstate)
end end
--- Set current Alarm State of the group. --- Set current Alarm State of the group.
--
-- * 0 = "Auto"
-- * 1 = "Green"
-- * 2 = "Red"
--
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string alarmstate Alarm state of group. Default is the value defined by :SetDefaultAlarmstate(). -- @param #number alarmstate Alarm state of group. Default is 0="Auto".
-- @return #OPSGROUP self -- @return #OPSGROUP self
function OPSGROUP:SwitchAlarmstate(alarmstate) function OPSGROUP:SwitchAlarmstate(alarmstate)
self.option.Alarm=alarmstate or self.optionDefault.Alarm if self:IsAlive() or self:IsInUtero() then
if self:IsAlive() then self.option.Alarm=alarmstate or 0
if self:IsInUtero() then
self:I(self.lid..string.format("Setting current Alarm State=%d when GROUP is SPAWNED", self.option.Alarm))
else
if self.option.Alarm==0 then if self.option.Alarm==0 then
self.group:OptionAlarmStateAuto() self.group:OptionAlarmStateAuto()
@ -2959,13 +3061,16 @@ function OPSGROUP:SwitchAlarmstate(alarmstate)
elseif self.option.Alarm==2 then elseif self.option.Alarm==2 then
self.group:OptionAlarmStateRed() self.group:OptionAlarmStateRed()
else else
self:E("ERROR: Unknown Alarm State! Setting to AUTO.") self:E("ERROR: Unknown Alarm State! Setting to AUTO")
self.group:OptionAlarmStateAuto() self.group:OptionAlarmStateAuto()
self.option.Alarm=0
end end
self:I(self.lid..string.format("Setting current Alarm State=%d (0=Auto, 1=Green, 2=Red)", self.option.Alarm)) self:I(self.lid..string.format("Setting current Alarm State=%d (0=Auto, 1=Green, 2=Red)", self.option.Alarm))
end
else else
-- TODO WARNING self:E(self.lid.."WARNING: Cannot switch Alarm State! Group is not alive.")
end end
return self return self
@ -2996,6 +3101,15 @@ function OPSGROUP:SetDefaultTACAN(Channel, Morse, UnitName, Band)
return self return self
end end
--- Activate/switch TACAN beacon settings.
-- @param #OPSGROUP self
-- @param #OPSGROUP.Beacon Tacan Tacan data table.
-- @return #OPSGROUP self
function OPSGROUP:_SwitchTACAN(Tacan)
self:SwitchTACAN(Tacan.Channel, Tacan.Morse, Tacan.BeaconName, Tacan.Band)
end
--- Activate/switch TACAN beacon settings. --- Activate/switch TACAN beacon settings.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #number Channel TACAN Channel. -- @param #number Channel TACAN Channel.
@ -3005,7 +3119,7 @@ end
-- @return #OPSGROUP self -- @return #OPSGROUP self
function OPSGROUP:SwitchTACAN(Channel, Morse, UnitName, Band) function OPSGROUP:SwitchTACAN(Channel, Morse, UnitName, Band)
if self:IsAlive() then if self:IsAlive() or self:IsInUtero() then
local unit=self.group:GetUnit(1) --Wrapper.Unit#UNIT local unit=self.group:GetUnit(1) --Wrapper.Unit#UNIT
@ -3022,15 +3136,10 @@ function OPSGROUP:SwitchTACAN(Channel, Morse, UnitName, Band)
unit=self.group:GetUnit(1) unit=self.group:GetUnit(1)
end end
if not Channel then Channel=Channel or 74
Channel=self.tacanDefault and self.tacanDefault.Channel or nil Morse=Morse or "XXX"
end
if not Morse then if unit and unit:IsAlive() or self:IsInUtero() then
Morse=self.tacanDefault and self.tacanDefault.Morse or "XXX"
end
if unit and unit:IsAlive() and Channel then
local UnitID=unit:GetID() local UnitID=unit:GetID()
@ -3048,26 +3157,31 @@ function OPSGROUP:SwitchTACAN(Channel, Morse, UnitName, Band)
-- Tacan frequency. -- Tacan frequency.
local Frequency=UTILS.TACANToFrequency(Channel, Band) local Frequency=UTILS.TACANToFrequency(Channel, Band)
-- Activate beacon.
unit:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Band, true, Morse, true)
-- Update info. -- Update info.
self.tacan={}
self.tacan.Channel=Channel self.tacan.Channel=Channel
self.tacan.Morse=Morse self.tacan.Morse=Morse
self.tacan.Band=Band self.tacan.Band=Band
self.tacan.BeaconName=unit:GetName() self.tacan.BeaconName=unit:GetName()
self.tacan.BeaconUnit=unit self.tacan.BeaconUnit=unit
self.tacan.On=true
-- TACAN is now on. if self:IsInUtero() then
self.tacanOn=true self:I(self.lid..string.format("Switching TACAN to Channel %d%s Morse %s on unit %s when GROUP is SPAWNED", self.tacan.Channel, self.tacan.Band, tostring(self.tacan.Morse), self.tacan.BeaconName))
else
-- Activate beacon.
unit:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Band, true, Morse, true)
self:I(self.lid..string.format("Switching TACAN to Channel %d%s Morse %s on unit %s", self.tacan.Channel, self.tacan.Band, tostring(self.tacan.Morse), self.tacan.BeaconName)) self:I(self.lid..string.format("Switching TACAN to Channel %d%s Morse %s on unit %s", self.tacan.Channel, self.tacan.Band, tostring(self.tacan.Morse), self.tacan.BeaconName))
else
self:E(self.lid.."ERROR: Cound not set TACAN! Unit is not alive.")
end end
else
self:E(self.lid.."ERROR: Cound not set TACAN! Unit is not alive")
end
else
self:E(self.lid.."ERROR: Cound not set TACAN! Group is not alive")
end end
return self return self
@ -3107,13 +3221,21 @@ end
--- Activate/switch ICLS beacon settings. --- Activate/switch ICLS beacon settings.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #number Channel ICLS Channel. -- @param #OPSGROUP.Beacon Icls ICLS data table.
-- @param #string Morse ICLS morse code. Default is the value set in @{#OPSGROUP.SetDefaultICLS} or if not set "XXX". -- @return #OPSGROUP self
function OPSGROUP:_SwitchICLS(Icls)
self:SwitchICLS(Icls.Channel, Icls.Morse, Icls.BeaconName)
end
--- Activate/switch ICLS beacon settings.
-- @param #OPSGROUP self
-- @param #number Channel ICLS Channel. Default is 1.
-- @param #string Morse ICLS morse code. Default is "XXX".
-- @param #string UnitName Name of the unit in the group which should activate the ICLS beacon. Can also be given as #number to specify the unit number. Default is the first unit of the group. -- @param #string UnitName Name of the unit in the group which should activate the ICLS beacon. Can also be given as #number to specify the unit number. Default is the first unit of the group.
-- @return #OPSGROUP self -- @return #OPSGROUP self
function OPSGROUP:SwitchICLS(Channel, Morse, UnitName) function OPSGROUP:SwitchICLS(Channel, Morse, UnitName)
if self:IsAlive() then if self:IsAlive() or self:IsInUtero() then
local unit=self.group:GetUnit(1) --Wrapper.Unit#UNIT local unit=self.group:GetUnit(1) --Wrapper.Unit#UNIT
@ -3130,34 +3252,33 @@ function OPSGROUP:SwitchICLS(Channel, Morse, UnitName)
unit=self.group:GetUnit(1) unit=self.group:GetUnit(1)
end end
if not Channel then Channel=Channel or 1
Channel=self.iclsDefault and self.iclsDefault.Channel or nil Morse=Morse or "XXX"
end
if not Morse then if unit and unit:IsAlive() or self:IsInUtero() then
Morse=self.iclsDefault and self.iclsDefault.Morse or "XXX"
end
if unit and unit:IsAlive() and Channel then
local UnitID=unit:GetID() local UnitID=unit:GetID()
-- Update info.
self.icls.Channel=Channel
self.icls.Morse=Morse
self.icls.Band=nil
self.icls.BeaconName=unit:GetName()
self.icls.BeaconUnit=unit
self.icls.On=true
if self:IsInUtero() then
self:I(self.lid..string.format("Switching ICLS to Channel %d Morse %s on unit %s when GROUP is SPAWNED", self.icls.Channel, tostring(self.icls.Morse), self.icls.BeaconName))
else
-- Activate beacon. -- Activate beacon.
unit:CommandActivateICLS(Channel, UnitID, Morse) unit:CommandActivateICLS(Channel, UnitID, Morse)
-- Update info.
self.icls={}
self.icls.Channel=Channel
self.icls.Morse=Morse
self.icls.Band=Band
self.icls.BeaconName=unit:GetName()
self.icls.BeaconUnit=unit
-- ICLS is now on.
self.iclsOn=true
self:I(self.lid..string.format("Switching ICLS to Channel %d Morse %s on unit %s", self.icls.Channel, tostring(self.icls.Morse), self.icls.BeaconName)) self:I(self.lid..string.format("Switching ICLS to Channel %d Morse %s on unit %s", self.icls.Channel, tostring(self.icls.Morse), self.icls.BeaconName))
end
else else
self:E(self.lid.."ERROR: Cound not set ICLS! Unit is not alive.") self:E(self.lid.."ERROR: Cound not set ICLS! Unit is not alive.")
end end
@ -3204,35 +3325,44 @@ function OPSGROUP:GetRadio()
return self.radio.Freq, self.radio.Modu return self.radio.Freq, self.radio.Modu
end end
--- Turn radio on. --- Turn radio on or switch frequency/modulation.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #number Frequency Radio frequency in MHz. -- @param #number Frequency Radio frequency in MHz. Default is 127.5 MHz.
-- @param #number Modulation Radio modulation. Default `radio.Modulation.AM`. -- @param #number Modulation Radio modulation. Default `radio.Modulation.AM`.
-- @return #OPSGROUP self -- @return #OPSGROUP self
function OPSGROUP:SwitchRadio(Frequency, Modulation) function OPSGROUP:SwitchRadio(Frequency, Modulation)
if self:IsAlive() and Frequency then if self:IsAlive() or self:IsInUtero() then
Modulation=Modulation or self.radioDefault.Modu Frequency=Frequency or 127.5
Modulation=Modulation or radio.modulation.AM
local group=self.group --Wrapper.Group#GROUP local group=self.group --Wrapper.Group#GROUP
if self.isAircraft and not self.radioOn then if self.isAircraft and not self.radio.On then
group:SetOption(AI.Option.Air.id.SILENCE, false) group:SetOption(AI.Option.Air.id.SILENCE, false)
end end
group:CommandSetFrequency(Frequency, Modulation) -- Set radio
self.radio.Freq=Frequency self.radio.Freq=Frequency
self.radio.Modu=Modulation self.radio.Modu=Modulation
self.radio.On=true
-- Radio is on. if self:IsInUtero() then
self.radioOn=true self:I(self.lid..string.format("Switching radio to frequency %.3f MHz %s when GROUP is SPAWNED", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu)))
else
-- Give command
group:CommandSetFrequency(Frequency, Modulation)
self:I(self.lid..string.format("Switching radio to frequency %.3f MHz %s", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu))) self:I(self.lid..string.format("Switching radio to frequency %.3f MHz %s", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu)))
end end
else
self:E(self.lid.."ERROR: Cound not set Radio! Group is not alive")
end
return self return self
end end
@ -3252,11 +3382,11 @@ function OPSGROUP:TurnOffRadio()
--self.radio.Modu=nil --self.radio.Modu=nil
-- Radio is off. -- Radio is off.
self.radioOn=false self.radio.On=false
self:I(self.lid..string.format("Switching radio OFF")) self:I(self.lid..string.format("Switching radio OFF"))
else else
self:E(self.lid.."ERROR radio can only be turned off for aircraft!") self:E(self.lid.."ERROR: Radio can only be turned off for aircraft!")
end end
end end

View File

@ -156,8 +156,10 @@ function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName)
-- From State --> Event --> To State -- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "OnDuty") -- Start FSM. self:AddTransition("Stopped", "Start", "OnDuty") -- Start FSM.
self:AddTransition("*", "Status", "*") -- Status update. self:AddTransition("*", "Status", "*") -- Status update.
self:AddTransition("OnDuty", "Pause", "Paused") -- Pause squadron. self:AddTransition("OnDuty", "Pause", "Paused") -- Pause squadron.
self:AddTransition("Paused", "Unpause", "OnDuty") -- Unpause squadron. self:AddTransition("Paused", "Unpause", "OnDuty") -- Unpause squadron.
self:AddTransition("*", "Stop", "Stopped") -- Stop squadron. self:AddTransition("*", "Stop", "Stopped") -- Stop squadron.