mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
e512569d5c
@ -68,7 +68,7 @@ ARMYGROUP = {
|
||||
|
||||
--- Army Group version.
|
||||
-- @field #string version
|
||||
ARMYGROUP.version="0.7.9"
|
||||
ARMYGROUP.version="0.8.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -775,8 +775,8 @@ function ARMYGROUP:Status()
|
||||
end
|
||||
|
||||
-- Info text.
|
||||
local text=string.format("%s [%d/%d]: ROE/AS=%d/%d | T/M=%d/%d | Wp=%d[%d]-->%d[%d]/%d [%s] | Life=%.1f | v=%.1f (%d) | Hdg=%03d | Ammo=%d | Detect=%s | Cargo=%.1f",
|
||||
fsmstate, nelem, Nelem, roe, als, nTaskTot, nMissions, wpidxCurr, wpuidCurr, wpidxNext, wpuidNext, wpN, wpF, life, speed, speedEx, hdg, ammo, ndetected, cargo)
|
||||
local text=string.format("%s [%d/%d]: ROE/AS=%d/%d | T/M=%d/%d | Wp=%d[%d]-->%d[%d]/%d [%s] | Life=%.1f | v=%.1f (%d) [%s] | Hdg=%03d | Ammo=%d | Detect=%s | Cargo=%.1f",
|
||||
fsmstate, nelem, Nelem, roe, als, nTaskTot, nMissions, wpidxCurr, wpuidCurr, wpidxNext, wpuidNext, wpN, wpF, life, speed, speedEx, formation, hdg, ammo, ndetected, cargo)
|
||||
self:I(self.lid..text)
|
||||
|
||||
end
|
||||
@ -1071,89 +1071,182 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation)
|
||||
-- Next waypoint.
|
||||
local wp=self.waypoints[n] --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
-- Current position.
|
||||
local coordinate=self:GetCoordinate()
|
||||
|
||||
-- Road coordinate.
|
||||
local coordRoad=coordinate:GetClosestPointToRoad()
|
||||
|
||||
-- Road distance.
|
||||
local roaddist=coordinate:Get2DDistance(coordRoad)
|
||||
|
||||
-- Formation at the current position.
|
||||
local formation0=wp.action
|
||||
if formation0==ENUMS.Formation.Vehicle.OnRoad then
|
||||
if wp.roadcoord then
|
||||
if wp.roaddist>10 then
|
||||
formation0=ENUMS.Formation.Vehicle.OffRoad
|
||||
end
|
||||
else
|
||||
-- Next waypoint is on road. Check if we are already on road.
|
||||
if roaddist>10 then
|
||||
-- Currently off road ==> we add an on road WP later.
|
||||
formation0=ENUMS.Formation.Vehicle.OffRoad
|
||||
else
|
||||
-- Already on road. We won't add an extra on road WP.
|
||||
formation0=ENUMS.Formation.Vehicle.OnRoad
|
||||
end
|
||||
end
|
||||
|
||||
-- Debug
|
||||
--env.info(self.lid.."FF formation0="..tostring(formation0))
|
||||
|
||||
-- Current point.
|
||||
local current=self:GetCoordinate():WaypointGround(UTILS.MpsToKmph(self.speedWp), formation0) --ENUMS.Formation.Vehicle.OffRoad)
|
||||
local current=coordinate:WaypointGround(UTILS.MpsToKmph(self.speedWp), formation0)
|
||||
table.insert(waypoints, 1, current)
|
||||
|
||||
-- Loop over waypoints.
|
||||
for j=n, N do
|
||||
-- Check if route consists of more than one waypoint (otherwise we have no previous waypoint)
|
||||
if N-n>0 then
|
||||
|
||||
-- Index of previous waypoint.
|
||||
local i=j-1
|
||||
-- Loop over waypoints.
|
||||
for j=n, N do
|
||||
|
||||
-- If we go to the first waypoint j=1 ==> i=0, so we take the last waypoint passed. E.g. when adinfinitum and passed final waypoint.
|
||||
if i==0 then
|
||||
i=self.currentwp
|
||||
-- Index of previous waypoint.
|
||||
local i=j-1
|
||||
|
||||
-- If we go to the first waypoint j=1 ==> i=0, so we take the last waypoint passed. E.g. when adinfinitum and passed final waypoint.
|
||||
if i==0 then
|
||||
i=self.currentwp
|
||||
end
|
||||
|
||||
-- Next waypoint. We create a copy because we need to modify it.
|
||||
local wp=UTILS.DeepCopy(self.waypoints[j]) --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
-- Previous waypoint. Index is i and not i-1 because we added the current position.
|
||||
local wp0=self.waypoints[i] --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
-- Debug
|
||||
if false and self.attribute==GROUP.Attribute.GROUND_APC then
|
||||
local text=string.format("FF Update: i=%d, wp[i]=%s, wp[i-1]=%s", i, wp.action, wp0.action)
|
||||
env.info(text)
|
||||
end
|
||||
|
||||
-- Speed.
|
||||
if Speed then
|
||||
wp.speed=UTILS.KnotsToMps(tonumber(Speed))
|
||||
else
|
||||
-- Take default waypoint speed. But make sure speed>0 if patrol ad infinitum.
|
||||
if wp.speed<0.1 then
|
||||
wp.speed=UTILS.KmphToMps(self.speedCruise)
|
||||
end
|
||||
end
|
||||
|
||||
-- Formation.
|
||||
if self.formationPerma then
|
||||
wp.action=self.formationPerma
|
||||
elseif Formation then
|
||||
wp.action=Formation
|
||||
end
|
||||
|
||||
-- Add waypoint in between because this waypoint is "On Road" but lies "Off Road".
|
||||
if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp0.roaddist>=0 then
|
||||
|
||||
-- Add "On Road" waypoint in between.
|
||||
local wproad=wp0.roadcoord:WaypointGround(UTILS.MpsToKmph(wp.speed), ENUMS.Formation.Vehicle.OnRoad) --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
-- Debug
|
||||
--wp0.roadcoord:MarkToAll(self.lid.." Added road wp near "..tostring(wproad.action))
|
||||
|
||||
-- Insert road waypoint.
|
||||
table.insert(waypoints, wproad)
|
||||
end
|
||||
|
||||
-- Add waypoint in between because this waypoint is "On Road" but lies "Off Road".
|
||||
if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp.roaddist>=0 then
|
||||
|
||||
-- The real waypoint is actually off road.
|
||||
wp.action=ENUMS.Formation.Vehicle.OffRoad
|
||||
|
||||
-- Add "On Road" waypoint in between.
|
||||
local wproad=wp.roadcoord:WaypointGround(UTILS.MpsToKmph(wp.speed), ENUMS.Formation.Vehicle.OnRoad) --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
-- Debug
|
||||
--wp.roadcoord:MarkToAll(self.lid.." Added road wp far "..tostring(wproad.action))
|
||||
|
||||
-- Insert road waypoint.
|
||||
table.insert(waypoints, wproad)
|
||||
end
|
||||
|
||||
-- Debug
|
||||
--wp.coordinate:MarkToAll(self.lid.." Added wp actual"..tostring(wp.action))
|
||||
|
||||
-- Add waypoint.
|
||||
table.insert(waypoints, wp)
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
---
|
||||
-- This is the case, where we have only one WP left.
|
||||
-- Could be because we had only one WP and did a detour (temp waypoint, which was deleted).
|
||||
---
|
||||
|
||||
-- Next waypoint.
|
||||
local wp=UTILS.DeepCopy(self.waypoints[j]) --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
-- Previous waypoint. Index is i and not i-1 because we added the current position.
|
||||
local wp0=self.waypoints[i] --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
--local text=string.format("FF Update: i=%d, wp[i]=%s, wp[i-1]=%s", i, wp.action, wp0.action)
|
||||
--env.info(text)
|
||||
local wp=UTILS.DeepCopy(self.waypoints[n]) --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
-- Speed.
|
||||
if Speed then
|
||||
wp.speed=UTILS.KnotsToMps(tonumber(Speed))
|
||||
else
|
||||
-- Take default waypoint speed. But make sure speed>0 if patrol ad infinitum.
|
||||
if wp.speed<0.1 then
|
||||
wp.speed=UTILS.KmphToMps(self.speedCruise)
|
||||
end
|
||||
if wp.speed<0.1 then
|
||||
wp.speed=UTILS.KmphToMps(self.speedCruise)
|
||||
end
|
||||
|
||||
-- Formation.
|
||||
local formation=wp.action
|
||||
if self.formationPerma then
|
||||
wp.action=self.formationPerma
|
||||
formation=self.formationPerma
|
||||
elseif Formation then
|
||||
wp.action=Formation
|
||||
formation=Formation
|
||||
end
|
||||
|
||||
-- Add waypoint in between because this waypoint is "On Road" but lies "Off Road".
|
||||
if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp0.roaddist>=0 then
|
||||
-- Debug
|
||||
--env.info(self.lid..string.format("FF Formation %s", formation))
|
||||
|
||||
--env.info("FF adding waypoint0 on road #"..i)
|
||||
-- Add road waypoint.
|
||||
if formation==ENUMS.Formation.Vehicle.OnRoad then
|
||||
|
||||
-- Add "On Road" waypoint in between.
|
||||
local wproad=wp0.roadcoord:WaypointGround(UTILS.MpsToKmph(wp.speed), ENUMS.Formation.Vehicle.OnRoad) --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
if roaddist>10 then
|
||||
|
||||
-- Add "On Road" waypoint in between.
|
||||
local wproad=coordRoad:WaypointGround(UTILS.MpsToKmph(wp.speed), ENUMS.Formation.Vehicle.OnRoad) --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
-- Debug
|
||||
--coordRoad:MarkToAll(self.lid.." Added road wp near "..tostring(wp.action))
|
||||
|
||||
-- Insert road waypoint.
|
||||
table.insert(waypoints, wproad)
|
||||
|
||||
end
|
||||
|
||||
if wp.roaddist>10 then
|
||||
|
||||
-- Add "On Road" waypoint in between.
|
||||
local wproad=wp.roadcoord:WaypointGround(UTILS.MpsToKmph(wp.speed), ENUMS.Formation.Vehicle.OnRoad) --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
-- Debug
|
||||
--wp.roadcoord:MarkToAll(self.lid.." Added road wp far "..tostring(wp.action))
|
||||
|
||||
-- Insert road waypoint.
|
||||
table.insert(waypoints, wproad)
|
||||
|
||||
end
|
||||
|
||||
-- Insert road waypoint.
|
||||
table.insert(waypoints, wproad)
|
||||
end
|
||||
|
||||
-- Add waypoint in between because this waypoint is "On Road" but lies "Off Road".
|
||||
if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp.roaddist>=0 then
|
||||
|
||||
--env.info("FF adding waypoint on road #"..i)
|
||||
|
||||
-- The real waypoint is actually off road.
|
||||
-- Waypoint set set to on-road but lies off-road. We set it to off-road. the on-road wp has been inserted.
|
||||
if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp.roaddist>10 then
|
||||
wp.action=ENUMS.Formation.Vehicle.OffRoad
|
||||
|
||||
-- Add "On Road" waypoint in between.
|
||||
local wproad=wp.roadcoord:WaypointGround(UTILS.MpsToKmph(wp.speed), ENUMS.Formation.Vehicle.OnRoad) --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
-- Insert road waypoint.
|
||||
table.insert(waypoints, wproad)
|
||||
end
|
||||
|
||||
-- Debug
|
||||
--wp.coordinate:MarkToAll(self.lid.." Added coord "..tostring(wp.action))
|
||||
|
||||
-- Add waypoint.
|
||||
-- Add actual waypoint.
|
||||
table.insert(waypoints, wp)
|
||||
|
||||
end
|
||||
|
||||
-- First (next wp).
|
||||
@ -1166,7 +1259,7 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation)
|
||||
self.speedWp=wp.speed
|
||||
|
||||
-- Debug output.
|
||||
if self.verbose>=10 then
|
||||
if self.verbose>=10 then --or self.attribute==GROUP.Attribute.GROUND_APC then
|
||||
for i,_wp in pairs(waypoints) do
|
||||
local wp=_wp --Ops.OpsGroup#OPSGROUP.Waypoint
|
||||
|
||||
@ -1662,7 +1755,7 @@ function ARMYGROUP:onafterEngageTarget(From, Event, To, Target, Speed, Formation
|
||||
self:SwitchROE(ENUMS.ROE.OpenFire)
|
||||
|
||||
-- ID of current waypoint.
|
||||
local uid=self:GetWaypointCurrent().uid
|
||||
local uid=self:GetWaypointCurrentUID()
|
||||
|
||||
-- Set formation.
|
||||
self.engage.Formation=Formation or ENUMS.Formation.Vehicle.Vee
|
||||
@ -1844,7 +1937,7 @@ end
|
||||
function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute)
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("AddWaypoint Formation = %s",tostring(Formation) or "none"))
|
||||
self:T(self.lid..string.format("AddWaypoint Formation = %s", tostring(Formation)))
|
||||
|
||||
-- Create coordinate.
|
||||
local coordinate=self:_CoordinateFromObject(Coordinate)
|
||||
@ -1862,8 +1955,10 @@ function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation
|
||||
elseif self.option.Formation then
|
||||
Formation = self.option.Formation
|
||||
else
|
||||
Formation = "On Road"
|
||||
-- Default formation is on road.
|
||||
Formation = ENUMS.Formation.Vehicle.OnRoad
|
||||
end
|
||||
self:T2(self.lid..string.format("Formation set to = %s", tostring(Formation)))
|
||||
end
|
||||
|
||||
-- Create a Ground waypoint.
|
||||
|
||||
@ -59,6 +59,7 @@
|
||||
-- @field #number Nelements Number of elements (units) assigned to mission.
|
||||
-- @field #number dTevaluate Time interval in seconds before the mission result is evaluated after mission is over.
|
||||
-- @field #number Tover Mission abs. time stamp, when mission was over.
|
||||
-- @field #boolean updateDCSTask If `true`, DCS task is updated at every status update of the assigned groups.
|
||||
-- @field #table conditionStart Condition(s) that have to be true, before the mission will be started.
|
||||
-- @field #table conditionSuccess If all conditions are true, the mission is cancelled.
|
||||
-- @field #table conditionFailure If all conditions are true, the mission is cancelled.
|
||||
@ -68,9 +69,12 @@
|
||||
-- @field #number orbitAltitude Orbit altitude in meters.
|
||||
-- @field #number orbitHeading Orbit heading in degrees.
|
||||
-- @field #number orbitLeg Length of orbit leg in meters.
|
||||
-- @field Core.Point#COORDINATE orbitRaceTrack Race-track orbit coordinate.
|
||||
-- @field DCS#Vec2 orbitOffsetVec2 2D offset vector.
|
||||
-- @field DCS#Vec2 orbitVec2 2D orbit vector.
|
||||
-- @field #number orbitDeltaR Distance threshold in meters for moving orbit targets.
|
||||
--
|
||||
-- @field Ops.Target#TARGET engageTarget Target data to engage.
|
||||
-- @field #number targetHeading Heading of target in degrees.
|
||||
--
|
||||
-- @field Ops.Operation#OPERATION operation Operation this mission is part of.
|
||||
--
|
||||
@ -624,7 +628,7 @@ AUFTRAG.Category={
|
||||
|
||||
--- AUFTRAG class version.
|
||||
-- @field #string version
|
||||
AUFTRAG.version="0.9.6"
|
||||
AUFTRAG.version="0.9.7"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -633,7 +637,8 @@ AUFTRAG.version="0.9.6"
|
||||
-- TODO: Replace engageRange by missionRange. Here and in other classes. CTRL+H is your friend!
|
||||
-- TODO: Mission success options damaged, destroyed.
|
||||
-- TODO: F10 marker to create new missions.
|
||||
-- TODO: Add recovery tanker mission for boat ops.
|
||||
-- DONE: Add orbit mission for moving anker points.
|
||||
-- DONE: Add recovery tanker mission for boat ops.
|
||||
-- DONE: Added auftrag category.
|
||||
-- DONE: Missions can be assigned to multiple legions.
|
||||
-- DONE: Option to assign a specific payload for the mission (requires an AIRWING).
|
||||
@ -1020,7 +1025,7 @@ end
|
||||
--- **[AIR]** Create an ORBIT mission, which can be either a circular orbit or a race-track pattern.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Point#COORDINATE Coordinate Where to orbit.
|
||||
-- @param #number Altitude Orbit altitude in feet. Default is y component of `Coordinate`.
|
||||
-- @param #number Altitude Orbit altitude in feet above sea level. Default is y component of `Coordinate`.
|
||||
-- @param #number Speed Orbit speed in knots. Default 350 KIAS.
|
||||
-- @param #number Heading Heading of race-track pattern in degrees. If not specified, a circular orbit is performed.
|
||||
-- @param #number Leg Length of race-track in NM. If not specified, a circular orbit is performed.
|
||||
@ -1029,25 +1034,34 @@ function AUFTRAG:NewORBIT(Coordinate, Altitude, Speed, Heading, Leg)
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.ORBIT)
|
||||
|
||||
-- Altitude.
|
||||
-- Target.
|
||||
mission:_TargetFromObject(Coordinate)
|
||||
|
||||
-- Set Altitude.
|
||||
if Altitude then
|
||||
mission.orbitAltitude=UTILS.FeetToMeters(Altitude)
|
||||
else
|
||||
mission.orbitAltitude=Coordinate.y
|
||||
end
|
||||
Coordinate.y=mission.orbitAltitude
|
||||
|
||||
mission:_TargetFromObject(Coordinate)
|
||||
-- Orbit speed in m/s.
|
||||
mission.orbitSpeed = UTILS.KnotsToMps(UTILS.KnotsToAltKIAS(Speed or 350, UTILS.MetersToFeet(mission.orbitAltitude)))
|
||||
|
||||
mission.orbitSpeed = UTILS.KnotsToMps(Speed or 350) -- the DCS Task itself will shortly be build with this so MPS
|
||||
-- Mission speed in km/h.
|
||||
mission.missionSpeed = UTILS.KnotsToKmph(Speed or 350)
|
||||
|
||||
if Heading and Leg then
|
||||
mission.orbitHeading=Heading
|
||||
if Leg then
|
||||
mission.orbitLeg=UTILS.NMToMeters(Leg)
|
||||
mission.orbitRaceTrack=Coordinate:Translate(mission.orbitLeg, mission.orbitHeading, true)
|
||||
end
|
||||
|
||||
-- Relative heading
|
||||
if Heading and Heading<0 then
|
||||
mission.orbitHeadingRel=true
|
||||
Heading=-Heading
|
||||
end
|
||||
|
||||
-- Heading if given.
|
||||
mission.orbitHeading=Heading
|
||||
end
|
||||
|
||||
-- Mission options:
|
||||
mission.missionAltitude=mission.orbitAltitude*0.9
|
||||
@ -1093,6 +1107,53 @@ function AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg)
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[AIR]** Create an ORBIT mission, where the aircraft will fly a circular or race-track pattern over a given group or unit.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Wrapper.Group#GROUP Group Group where to orbit around. Can also be a UNIT object.
|
||||
-- @param #number Altitude Orbit altitude in feet. Default is 6,000 ft.
|
||||
-- @param #number Speed Orbit speed in knots. Default 350 KIAS.
|
||||
-- @param #number Leg Length of race-track in NM. Default nil.
|
||||
-- @param #number Heading Heading of race-track pattern in degrees. Default is heading of the group.
|
||||
-- @param DCS#Vec2 OffsetVec2 Offset 2D-vector {x=0, y=0} in NM with respect to the group. Default directly overhead. Can also be given in polar coordinates `{r=5, phi=45}`.
|
||||
-- @param #number Distance Threshold distance in NM before orbit pattern is updated. Default 5 NM.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewORBIT_GROUP(Group, Altitude, Speed, Leg, Heading, OffsetVec2, Distance)
|
||||
|
||||
-- Set default altitude.
|
||||
Altitude = Altitude or 6000
|
||||
|
||||
-- Create orbit mission.
|
||||
local mission=AUFTRAG:NewORBIT(Group, Altitude, Speed, Heading, Leg)
|
||||
|
||||
-- DCS tasks needs to be updated from time to time.
|
||||
mission.updateDCSTask=true
|
||||
|
||||
-- Convert offset vector to meters.
|
||||
if OffsetVec2 then
|
||||
if OffsetVec2.x then
|
||||
OffsetVec2.x=UTILS.NMToMeters(OffsetVec2.x)
|
||||
end
|
||||
if OffsetVec2.y then
|
||||
OffsetVec2.y=UTILS.NMToMeters(OffsetVec2.y)
|
||||
end
|
||||
if OffsetVec2.r then
|
||||
OffsetVec2.r=UTILS.NMToMeters(OffsetVec2.r)
|
||||
end
|
||||
end
|
||||
|
||||
-- Offset vector.
|
||||
mission.orbitOffsetVec2=OffsetVec2
|
||||
|
||||
-- Pattern update distance.
|
||||
mission.orbitDeltaR=UTILS.NMToMeters(Distance or 5)
|
||||
|
||||
-- Update task with offset etc.
|
||||
mission:GetDCSMissionTask()
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
|
||||
--- **[AIR]** Create a Ground Controlled CAP (GCICAP) mission. Flights with this task are considered for A2A INTERCEPT missions by the CHIEF class. They will perform a compat air patrol but not engage by
|
||||
-- themselfs. They wait for the CHIEF to tell them whom to engage.
|
||||
-- @param #AUFTRAG self
|
||||
@ -1631,25 +1692,45 @@ function AUFTRAG:NewRESCUEHELO(Carrier)
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[AIRPANE]** Create a RECOVERY TANKER mission. **WIP and not working coorectly yet!**
|
||||
--- **[AIRPANE]** Create a RECOVERY TANKER mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Wrapper.Unit#UNIT Carrier The carrier unit.
|
||||
-- @param #number Altitude Orbit altitude in feet. Default is 6,000 ft.
|
||||
-- @param #number Speed Orbit speed in knots. Default 250 KIAS.
|
||||
-- @param #number Leg Length of race-track in NM. Default 14 NM.
|
||||
-- @param #number RelHeading Relative heading [0, 360) of race-track pattern in degrees wrt heading of the carrier. Default is heading of the carrier.
|
||||
-- @param #number OffsetDist Relative distance of the first race-track point wrt to the carrier. Default 6 NM.
|
||||
-- @param #number OffsetAngle Relative angle of the first race-track point wrt. to the carrier. Default 180 (behind the boat).
|
||||
-- @param #number UpdateDistance Threshold distance in NM before orbit pattern is updated. Default 5 NM.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewRECOVERYTANKER(Carrier)
|
||||
function AUFTRAG:NewRECOVERYTANKER(Carrier, Altitude, Speed, Leg, RelHeading, OffsetDist, OffsetAngle, UpdateDistance)
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.RECOVERYTANKER)
|
||||
-- Six NM astern.
|
||||
local OffsetVec2={r=OffsetDist or 6, phi=OffsetAngle or 180}
|
||||
|
||||
mission:_TargetFromObject(Carrier)
|
||||
-- Default leg.
|
||||
Leg=Leg or 14
|
||||
|
||||
-- Default Speed.
|
||||
Speed=Speed or 250
|
||||
|
||||
local Heading=nil
|
||||
if RelHeading then
|
||||
Heading=-math.abs(RelHeading)
|
||||
end
|
||||
|
||||
-- Create orbit mission.
|
||||
local mission=AUFTRAG:NewORBIT_GROUP(Carrier, Altitude, Speed, Leg, Heading, OffsetVec2, UpdateDistance)
|
||||
|
||||
-- Set the type.
|
||||
mission.type=AUFTRAG.Type.RECOVERYTANKER
|
||||
|
||||
-- Mission options:
|
||||
mission.missionTask=ENUMS.MissionTask.REFUELING
|
||||
mission.missionFraction=0.5
|
||||
mission.missionFraction=0.9
|
||||
mission.optionROE=ENUMS.ROE.WeaponHold
|
||||
mission.optionROT=ENUMS.ROT.NoReaction
|
||||
|
||||
mission.missionAltitude=UTILS.FeetToMeters(6000)
|
||||
mission.missionSpeed=UTILS.KnotsToKmph(274)
|
||||
|
||||
mission.categories={AUFTRAG.Category.AIRPLANE}
|
||||
|
||||
mission.DCStask=mission:GetDCSMissionTask()
|
||||
@ -4974,6 +5055,17 @@ function AUFTRAG:GetTargetCoordinate()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get heading of target.
|
||||
-- @param #AUFTRAG self
|
||||
-- @return #number Heading of target in degrees.
|
||||
function AUFTRAG:GetTargetHeading()
|
||||
if self.engageTarget then
|
||||
local heading=self.engageTarget:GetHeading()
|
||||
return heading
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get name of the target.
|
||||
-- @param #AUFTRAG self
|
||||
-- @return #string Name of the target or "N/A".
|
||||
@ -5239,6 +5331,17 @@ function AUFTRAG:_SetLogID()
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Update DCS task.
|
||||
-- @param #AUFTRAG self
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:_UpdateTask()
|
||||
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Update mission F10 map marker.
|
||||
-- @param #AUFTRAG self
|
||||
-- @return #AUFTRAG self
|
||||
@ -5412,47 +5515,6 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.RECOVERYTANKER then
|
||||
|
||||
----------------------------
|
||||
-- RECOVERYTANKER Mission --
|
||||
----------------------------
|
||||
|
||||
-- Get the carrier unit.
|
||||
local Carrier=self:GetObjective() --Wrapper.Unit#UNIT
|
||||
|
||||
-- Carrier coordinate.
|
||||
local Coord=Carrier:GetCoordinate()
|
||||
|
||||
-- Get current heading of carrier.
|
||||
local hdg=Carrier:GetHeading()
|
||||
|
||||
-- Altitude
|
||||
local Altitude=self.missionAltitude
|
||||
|
||||
-- Race-track distances.
|
||||
local distStern=UTILS.NMToMeters(4)
|
||||
local distBow=UTILS.NMToMeters(10)
|
||||
|
||||
-- Racetrack pattern points.
|
||||
local p1=Coord:Translate(distStern, hdg):SetAltitude(self.missionAltitude)
|
||||
local p2=Coord:Translate(distBow, hdg):SetAltitude(self.missionAltitude)
|
||||
|
||||
p1:MarkToAll("p1")
|
||||
p2:MarkToAll("p2")
|
||||
|
||||
-- Set speed in m/s.
|
||||
local Speed=UTILS.KmphToMps(self.missionSpeed)
|
||||
|
||||
-- Orbit task.
|
||||
local DCStask=CONTROLLABLE.TaskOrbit(nil, p1, Altitude, Speed, p2)
|
||||
|
||||
-- Set carrier as parameter.
|
||||
DCStask.params.carrier=Carrier
|
||||
|
||||
-- Add to DCS tasks.
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.INTERCEPT then
|
||||
|
||||
-----------------------
|
||||
@ -5522,7 +5584,7 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.TANKER then
|
||||
elseif self.type==AUFTRAG.Type.TANKER or self.type==AUFTRAG.Type.RECOVERYTANKER then
|
||||
|
||||
--------------------
|
||||
-- TANKER Mission --
|
||||
@ -5890,17 +5952,91 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
self.type==AUFTRAG.Type.CAS or
|
||||
self.type==AUFTRAG.Type.GCICAP or
|
||||
self.type==AUFTRAG.Type.AWACS or
|
||||
self.type==AUFTRAG.Type.TANKER then
|
||||
self.type==AUFTRAG.Type.TANKER or
|
||||
self.type==AUFTRAG.Type.RECOVERYTANKER then
|
||||
|
||||
-------------------
|
||||
-- ORBIT Mission --
|
||||
-------------------
|
||||
|
||||
local Coordinate=self:GetTargetCoordinate()
|
||||
-- Get/update orbit vector.
|
||||
self.orbitVec2=self:GetTargetVec2()
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskOrbit(nil, Coordinate, self.orbitAltitude, self.orbitSpeed, self.orbitRaceTrack)
|
||||
if self.orbitVec2 then
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
-- Heading of the target.
|
||||
self.targetHeading=self:GetTargetHeading()
|
||||
|
||||
local OffsetVec2=nil --DCS#Vec2
|
||||
if (self.orbitOffsetVec2~=nil) then
|
||||
OffsetVec2=UTILS.DeepCopy(self.orbitOffsetVec2)
|
||||
end
|
||||
|
||||
if OffsetVec2 then
|
||||
|
||||
if self.orbitOffsetVec2.r then
|
||||
-- Polar coordinates
|
||||
local r=self.orbitOffsetVec2.r
|
||||
local phi=(self.orbitOffsetVec2.phi or 0) + self.targetHeading
|
||||
|
||||
OffsetVec2.x=r*math.cos(math.rad(phi))
|
||||
OffsetVec2.y=r*math.sin(math.rad(phi))
|
||||
else
|
||||
-- Cartesian coordinates
|
||||
OffsetVec2.x=self.orbitOffsetVec2.x
|
||||
OffsetVec2.y=self.orbitOffsetVec2.y
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Actual orbit position with possible offset.
|
||||
local orbitVec2=OffsetVec2 and UTILS.Vec2Add(self.orbitVec2, OffsetVec2) or self.orbitVec2
|
||||
|
||||
-- Check for race-track pattern.
|
||||
local orbitRaceTrack=nil --DCS#Vec2
|
||||
if self.orbitLeg then
|
||||
|
||||
-- Default heading is due North.
|
||||
local heading=0
|
||||
|
||||
-- Check if specific heading was specified.
|
||||
if self.orbitHeading then
|
||||
|
||||
-- Is heading realtive to target?
|
||||
if self.orbitHeadingRel then
|
||||
-- Relative heading wrt target.
|
||||
heading=self.targetHeading+self.orbitHeading
|
||||
else
|
||||
-- Take given heading.
|
||||
heading=self.orbitHeading
|
||||
end
|
||||
|
||||
else
|
||||
-- Not specific heading specified ==> Take heading of target.
|
||||
heading=self.targetHeading or 0
|
||||
end
|
||||
|
||||
-- Race-track vector.
|
||||
orbitRaceTrack=UTILS.Vec2Translate(orbitVec2, self.orbitLeg, heading)
|
||||
end
|
||||
|
||||
-- Debug
|
||||
--UTILS.RemoveMark(self.orbitCenterMarkID)
|
||||
--self.orbitCenterMarkID=COORDINATE:NewFromVec2(orbitVec2):MarkToAll("Orbit Center")
|
||||
|
||||
-- Debug show arrow.
|
||||
--if orbitRaceTrack then
|
||||
--UTILS.RemoveMark(self.orbitArrowMarkID)
|
||||
--self.orbitArrowMarkID=COORDINATE:NewFromVec2(orbitVec2):ArrowToAll(COORDINATE:NewFromVec2(orbitRaceTrack))
|
||||
--end
|
||||
|
||||
-- Create orbit task.
|
||||
local DCStask=CONTROLLABLE.TaskOrbit(nil, orbitVec2, self.orbitAltitude, self.orbitSpeed, orbitRaceTrack)
|
||||
|
||||
-- Add DCS task.
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -6087,6 +6223,8 @@ function AUFTRAG.CheckMissionCapabilityAll(MissionTypes, Capabilities)
|
||||
return res
|
||||
end
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -42,7 +42,8 @@
|
||||
--
|
||||
-- # The CHIEF Concept
|
||||
--
|
||||
-- The Chief of staff gathers INTEL and assigns missions (AUFTRAG) the airforce, army and/or navy.
|
||||
-- The Chief of staff gathers INTEL and assigns missions (AUFTRAG) to the airforce, army and/or navy. The distinguished feature here is that this class combines all three
|
||||
-- forces under one hood. Therefore, this class be used as an air-to-air, air-to-ground, ground-to-ground, air-to-sea, sea-to-ground, etc. dispachter.
|
||||
--
|
||||
-- # Territory
|
||||
--
|
||||
@ -299,10 +300,14 @@ CHIEF.Strategy = {
|
||||
-- @field Ops.OpsZone#OPSZONE opszone OPS zone.
|
||||
-- @field #number prio Priority.
|
||||
-- @field #number importance Importance.
|
||||
-- @field #table resourceEmpty Resource list.
|
||||
-- @field #table resourceOccup Resource list.
|
||||
-- @field #CHIEF.Resources resourceEmpty List of resources employed when the zone is empty.
|
||||
-- @field #CHIEF.Resources resourceOccup List of resources employed when the zone is occupied by an enemy.
|
||||
-- @field #table missions Mission.
|
||||
|
||||
--- Resource list.
|
||||
-- @type CHIEF.Resources
|
||||
-- @field <#CHIEF.Resource> List of resources.
|
||||
|
||||
--- Resource.
|
||||
-- @type CHIEF.Resource
|
||||
-- @field #string MissionType Mission type, e.g. `AUFTRAG.Type.BAI`.
|
||||
@ -311,16 +316,26 @@ CHIEF.Strategy = {
|
||||
-- @field #table Attributes Generalized attribute, e.g. `{GROUP.Attribute.GROUND_INFANTRY}`.
|
||||
-- @field #table Properties Properties ([DCS attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes)), e.g. `"Attack helicopters"` or `"Mobile AAA"`.
|
||||
-- @field Ops.Auftrag#AUFTRAG mission Attached mission.
|
||||
-- @field #number carrierNmin Min number of assets.
|
||||
-- @field #number carrierNmax Max number of assets.
|
||||
-- @field #table cargoCategories Group categories.
|
||||
-- @field #table cargoAttributes Generalized attribute, e.g. `{GROUP.Attribute.GROUND_INFANTRY}`.
|
||||
-- @field #table cargoProperties Properties ([DCS attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes)), e.g. `"Attack helicopters"` or `"Mobile AAA"`.
|
||||
-- @field #table carrierCategories Group categories.
|
||||
-- @field #table carrierAttributes Generalized attribute, e.g. `{GROUP.Attribute.GROUND_INFANTRY}`.
|
||||
-- @field #table carrierProperties Properties ([DCS attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes)), e.g. `"Attack helicopters"` or `"Mobile AAA"`.
|
||||
|
||||
|
||||
--- CHIEF class version.
|
||||
-- @field #string version
|
||||
CHIEF.version="0.4.0"
|
||||
CHIEF.version="0.5.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Let user specify amount of resources.
|
||||
-- TODO: PLAYERTASK integration.
|
||||
-- DONE: Let user specify amount of resources.
|
||||
-- DONE: Tactical overview.
|
||||
-- DONE: Add event for opsgroups on mission.
|
||||
-- DONE: Add event for zone captured.
|
||||
@ -736,44 +751,45 @@ end
|
||||
-- @param #number Nmax Max number of requried assets. Default 1.
|
||||
-- @param #table Attributes Generalized attribute(s). Default `nil`.
|
||||
-- @param #table Properties DCS attribute(s). Default `nil`.
|
||||
-- @return #table The resource object.
|
||||
-- @return #CHIEF.Resources The newly created resource list table.
|
||||
-- @return #CHIEF.Resource The resource object that was added.
|
||||
function CHIEF:CreateResource(MissionType, Nmin, Nmax, Attributes, Properties)
|
||||
|
||||
local resource={}
|
||||
local resources={}
|
||||
|
||||
self:AddToResource(resource, MissionType, Nmin, Nmax, Attributes, Properties)
|
||||
local resource=self:AddToResource(resources, MissionType, Nmin, Nmax, Attributes, Properties)
|
||||
|
||||
return resource
|
||||
return resources, resource
|
||||
end
|
||||
|
||||
--- Add mission type and number of required assets to resource.
|
||||
--- Add mission type and number of required assets to resource list.
|
||||
-- @param #CHIEF self
|
||||
-- @param #table Resource Resource table.
|
||||
-- @param #CHIEF.Resources Resource List of resources.
|
||||
-- @param #string MissionType Mission Type.
|
||||
-- @param #number Nmin Min number of required assets.
|
||||
-- @param #number Nmax Max number of requried assets.
|
||||
-- @param #number Nmin Min number of required assets. Default 1.
|
||||
-- @param #number Nmax Max number of requried assets. Default equal `Nmin`.
|
||||
-- @param #table Attributes Generalized attribute(s).
|
||||
-- @param #table Properties DCS attribute(s). Default `nil`.
|
||||
-- @return #CHIEF self
|
||||
-- @return #CHIEF.Resource Resource table.
|
||||
function CHIEF:AddToResource(Resource, MissionType, Nmin, Nmax, Attributes, Properties)
|
||||
|
||||
-- Ensure table.
|
||||
if Attributes and type(Attributes)~="table" then
|
||||
Attributes={Attributes}
|
||||
end
|
||||
|
||||
-- Ensure table.
|
||||
if Properties and type(Properties)~="table" then
|
||||
Properties={Properties}
|
||||
end
|
||||
|
||||
-- Create new resource table.
|
||||
local resource={} --#CHIEF.Resource
|
||||
resource.MissionType=MissionType
|
||||
resource.Nmin=Nmin or 1
|
||||
resource.Nmax=Nmax or 1
|
||||
resource.Attributes=Attributes or {}
|
||||
resource.Properties=Properties or {}
|
||||
resource.Nmax=Nmax or Nmin
|
||||
resource.Attributes=UTILS.EnsureTable(Attributes)
|
||||
resource.Properties=UTILS.EnsureTable(Properties)
|
||||
|
||||
-- Transport carrier parameters.
|
||||
resource.cargoAttributes=nil
|
||||
resource.cargoProperties=nil
|
||||
resource.cargoCategories=nil
|
||||
resource.carrierNmin=nil
|
||||
resource.carrierNmax=nil
|
||||
resource.carrierAttributes=nil
|
||||
resource.carrierProperties=nil
|
||||
resource.carrierCategories=nil
|
||||
|
||||
-- Add to table.
|
||||
table.insert(Resource, resource)
|
||||
@ -788,6 +804,32 @@ function CHIEF:AddToResource(Resource, MissionType, Nmin, Nmax, Attributes, Prop
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
return resource
|
||||
end
|
||||
|
||||
--- Define which assets will be transported and define the number and attributes/properties of the cargo carrier assets.
|
||||
-- @param #CHIEF self
|
||||
-- @param #CHIEF.Resource Resource Resource table.
|
||||
-- @param #table CargoAttributes Generalized attribute(s) of the cargo assets.
|
||||
-- @param #table CargoProperties DCS attribute(s) of the cargo assets.
|
||||
-- @param #table CargoCategories Group categories of the cargo assets.
|
||||
-- @param #number Nmin Min number of required assets. Default 1.
|
||||
-- @param #number Nmax Max number of requried assets. Default is equal to `Nmin`.
|
||||
-- @param #table CarrierAttributes Generalized attribute(s) of the carrier assets.
|
||||
-- @param #table CarrierProperties DCS attribute(s) of the carrier assets.
|
||||
-- @param #table CarrierCategories Group categories of the carrier assets.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:AddTransportToResource(Resource, CargoAttributes, CargoProperties, CargoCategories, Nmin, Nmax, CarrierAttributes, CarrierProperties, CarrierCategories)
|
||||
|
||||
Resource.cargoCategories=CargoCategories
|
||||
Resource.cargoAttributes=CargoAttributes
|
||||
Resource.cargoProperties=CargoProperties
|
||||
Resource.carrierNmin=Nmin or 1
|
||||
Resource.carrierNmax=Nmax or Nmin
|
||||
Resource.carrierCategories=CarrierCategories
|
||||
Resource.carrierAttributes=CarrierAttributes
|
||||
Resource.carrierProperties=CarrierProperties
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@ -1193,17 +1235,17 @@ end
|
||||
--
|
||||
-- Empty:
|
||||
--
|
||||
-- * `AUFTRAG.Type.ONGUARD` with Nmin=1 and Nmax=3 assets, Attribute=`GROUP.Attribute.GROUND_INFANTRY`.
|
||||
-- * `AUFTRAG.Type.ONGURAD` with Nmin=1 and Nmax=1 assets, Attribute=`GROUP.Attribute.GROUND_TANK`.
|
||||
-- * `AUFTRAG.Type.ONGUARD` with Nmin=1 and Nmax=3 assets, Attribute=`GROUP.Attribute.GROUND_INFANTRY`.
|
||||
--
|
||||
-- Resources can be created with the @{#CHIEF.CreateResource} and @{#CHIEF.AddToResource} functions.
|
||||
--
|
||||
-- @param #CHIEF self
|
||||
-- @param Ops.OpsZone#OPSZONE OpsZone OPS zone object.
|
||||
-- @param #number Priority Priority. Default 50.
|
||||
-- @param #number Importance Importance. Default nil.
|
||||
-- @param #CHIEF.Resource ResourceOccupied (Optional) Resources used then zone is occupied by the enemy.
|
||||
-- @param #CHIEF.Resource ResourceEmpty (Optional) Resources used then zone is empty.
|
||||
-- @param #number Importance Importance. Default `#nil`.
|
||||
-- @param #CHIEF.Resources ResourceOccupied (Optional) Resources used then zone is occupied by the enemy.
|
||||
-- @param #CHIEF.Resources ResourceEmpty (Optional) Resources used then zone is empty.
|
||||
-- @return #CHIEF.StrategicZone The strategic zone.
|
||||
function CHIEF:AddStrategicZone(OpsZone, Priority, Importance, ResourceOccupied, ResourceEmpty)
|
||||
|
||||
@ -1232,8 +1274,11 @@ function CHIEF:AddStrategicZone(OpsZone, Priority, Importance, ResourceOccupied,
|
||||
if ResourceEmpty then
|
||||
stratzone.resourceEmpty=UTILS.DeepCopy(ResourceEmpty)
|
||||
else
|
||||
stratzone.resourceEmpty=self:CreateResource(AUFTRAG.Type.ONGUARD, 1, 3, GROUP.Attribute.GROUND_INFANTRY)
|
||||
self:AddToResource(stratzone.resourceEmpty, AUFTRAG.Type.ONGUARD, 1, 1, GROUP.Attribute.GROUND_TANK)
|
||||
local resourceEmpty, resourceInfantry=self:CreateResource(AUFTRAG.Type.ONGUARD, 1, 3, GROUP.Attribute.GROUND_INFANTRY)
|
||||
self:AddToResource(resourceEmpty, AUFTRAG.Type.ONGUARD, 0, 1, GROUP.Attribute.GROUND_TANK)
|
||||
self:AddToResource(resourceEmpty, AUFTRAG.Type.ONGUARD, 0, 1, GROUP.Attribute.GROUND_IFV)
|
||||
self:AddTransportToResource(resourceInfantry, GROUP.Attribute.GROUND_INFANTRY, nil, nil, 0, 1, {GROUP.Attribute.AIR_TRANSPORTHELO, GROUP.Attribute.GROUND_APC})
|
||||
stratzone.resourceEmpty=resourceEmpty
|
||||
end
|
||||
|
||||
-- Add to table.
|
||||
@ -1438,7 +1483,7 @@ end
|
||||
-- * Enemies in these zones will only be engaged if strategy is at least `CHIEF.STRATEGY.DEFENSIVE`.
|
||||
--
|
||||
-- @param #CHIEF self
|
||||
-- @param Core.Set#SET_ZONE BorderZoneSet Set of zones, defining our borders.
|
||||
-- @param Core.Set#SET_ZONE BorderZoneSet Set of zones defining our borders.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:SetBorderZones(BorderZoneSet)
|
||||
|
||||
@ -1454,7 +1499,7 @@ end
|
||||
-- * Enemies in these zones will only be engaged if strategy is at least `CHIEF.STRATEGY.DEFENSIVE`.
|
||||
--
|
||||
-- @param #CHIEF self
|
||||
-- @param Core.Zone#ZONE Zone The zone.
|
||||
-- @param Core.Zone#ZONE Zone The zone to be added.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:AddBorderZone(Zone)
|
||||
|
||||
@ -1464,6 +1509,18 @@ function CHIEF:AddBorderZone(Zone)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove a border zone defining your territory.
|
||||
-- @param #CHIEF self
|
||||
-- @param Core.Zone#ZONE Zone The zone to be removed.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:RemoveBorderZone(Zone)
|
||||
|
||||
-- Add a border zone.
|
||||
self.borderzoneset:Remove(Zone:GetName())
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set conflict zone set.
|
||||
--
|
||||
-- * Detected enemy troops in these zones will trigger defence condition `YELLOW`.
|
||||
@ -1486,7 +1543,7 @@ end
|
||||
-- * Enemies in these zones will only be engaged if strategy is at least `CHIEF.STRATEGY.OFFENSIVE`.
|
||||
--
|
||||
-- @param #CHIEF self
|
||||
-- @param Core.Zone#ZONE Zone The zone to add.
|
||||
-- @param Core.Zone#ZONE Zone The zone to be added.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:AddConflictZone(Zone)
|
||||
|
||||
@ -1496,6 +1553,19 @@ function CHIEF:AddConflictZone(Zone)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove a conflict zone.
|
||||
-- @param #CHIEF self
|
||||
-- @param Core.Zone#ZONE Zone The zone to be removed.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:RemoveConflictZone(Zone)
|
||||
|
||||
-- Add a conflict zone.
|
||||
self.yellowzoneset:Remove(Zone:GetName())
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set attack zone set.
|
||||
--
|
||||
-- * Enemies in these zones will only be engaged if strategy is at least `CHIEF.STRATEGY.AGGRESSIVE`.
|
||||
@ -1526,11 +1596,24 @@ function CHIEF:AddAttackZone(Zone)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove an attack zone.
|
||||
-- @param #CHIEF self
|
||||
-- @param Core.Zone#ZONE Zone The zone to be removed.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:RemoveAttackZone(Zone)
|
||||
|
||||
-- Add an attack zone.
|
||||
self.engagezoneset:Remove(Zone:GetName())
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Allow chief to use GROUND units for transport tasks. Helicopters are still preferred, and be aware there's no check as of now
|
||||
-- if a destination can be reached on land.
|
||||
-- @param #CHIEF self
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:AllowGroundTransport()
|
||||
env.warning("WARNING: CHIEF:AllowGroundTransport() is depricated and will be removed in the future!")
|
||||
self.TransportCategories = {Group.Category.GROUND, Group.Category.HELICOPTER}
|
||||
return self
|
||||
end
|
||||
@ -1539,6 +1622,7 @@ end
|
||||
-- @param #CHIEF self
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:ForbidGroundTransport()
|
||||
env.warning("WARNING: CHIEF:ForbidGroundTransport() is depricated and will be removed in the future!")
|
||||
self.TransportCategories = {Group.Category.HELICOPTER}
|
||||
return self
|
||||
end
|
||||
@ -2114,7 +2198,16 @@ function CHIEF:_TacticalOverview()
|
||||
for _,_stratzone in pairs(self.zonequeue) do
|
||||
local stratzone=_stratzone --#CHIEF.StrategicZone
|
||||
local owner=stratzone.opszone:GetOwnerName()
|
||||
text=text..string.format(" - %s: %s - %s [I=%d, P=%d]\n", stratzone.opszone:GetName(), owner, stratzone.opszone:GetState(), stratzone.importance, stratzone.prio)
|
||||
text=text..string.format(" - %s: %s - %s [I=%d, P=%d]\n", stratzone.opszone:GetName(), owner, stratzone.opszone:GetState(), stratzone.importance or 0, stratzone.prio or 0)
|
||||
end
|
||||
|
||||
local Ntransports=#self.commander.transportqueue
|
||||
if Ntransports>0 then
|
||||
text=text..string.format("Transports: %d\n", Ntransports)
|
||||
for _,_transport in pairs(self.commander.transportqueue) do
|
||||
local transport=_transport --Ops.OpsTransport#OPSTRANSPORT
|
||||
text=text..string.format(" - %s", transport:GetState())
|
||||
end
|
||||
end
|
||||
|
||||
-- Message to coalition.
|
||||
@ -2867,9 +2960,36 @@ function CHIEF:RecruitAssetsForZone(StratZone, Resource)
|
||||
-- Debug messgage.
|
||||
self:T2(self.lid..string.format("Recruited %d assets for %s mission STRATEGIC zone %s", #assets, MissionType, tostring(StratZone.opszone.zoneName)))
|
||||
|
||||
-- Short cuts.
|
||||
local TargetZone = StratZone.opszone.zone
|
||||
local TargetCoord = TargetZone:GetCoordinate()
|
||||
|
||||
-- First check if we need a transportation.
|
||||
local transport=nil
|
||||
if Resource.carrierNmin and Resource.carrierNmax and Resource.carrierNmax>0 then
|
||||
|
||||
-- Filter only those assets that shall be transported.
|
||||
local cargoassets=CHIEF._FilterAssets(assets, Resource.cargoCategories, Resource.cargoAttributes, Resource.cargoProperties)
|
||||
|
||||
if #cargoassets>0 then
|
||||
|
||||
-- Recruit transport carrier assets.
|
||||
recruited, transport=LEGION.AssignAssetsForTransport(self.commander, self.commander.legions, cargoassets,
|
||||
Resource.carrierNmin, Resource.carrierNmax, TargetZone, nil, Resource.carrierCategories, Resource.carrierAttributes)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Check if everything was recruited.
|
||||
if not recruited then
|
||||
-- No (transport) assets ==> no mission!
|
||||
self:T(self.lid..string.format("Could not allocate assets or transport of OPSZONE!"))
|
||||
LEGION.UnRecruitAssets(assets)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
if MissionType==AUFTRAG.Type.PATROLZONE or MissionType==AUFTRAG.Type.ONGUARD then
|
||||
|
||||
---
|
||||
@ -2879,47 +2999,15 @@ function CHIEF:RecruitAssetsForZone(StratZone, Resource)
|
||||
-- Debug messgage.
|
||||
self:T2(self.lid..string.format("Recruited %d assets for PATROL mission", #assets))
|
||||
|
||||
-- First check if we need a transportation.
|
||||
local recruitedTrans=true ; local transport=nil
|
||||
if Attributes and Attributes[1]==GROUP.Attribute.GROUND_INFANTRY then
|
||||
|
||||
-- Categories. Currently only helicopters are allowed due to problems with ground transports (might get stuck, might not be a land connection.
|
||||
-- TODO: Check if ground transport is possible. For example, by trying land.getPathOnRoad or something.
|
||||
local Categories=self.TransportCategories
|
||||
|
||||
-- Recruit transport assets for infantry.
|
||||
recruitedTrans, transport=LEGION.AssignAssetsForTransport(self.commander, self.commander.legions, assets, 1, 1, TargetZone, nil, Categories)
|
||||
if MissionType==AUFTRAG.Type.PATROLZONE then
|
||||
mission=AUFTRAG:NewPATROLZONE(TargetZone)
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.ONGUARD then
|
||||
mission=AUFTRAG:NewONGUARD(TargetZone:GetRandomCoordinate(nil, nil, {land.SurfaceType.LAND}))
|
||||
end
|
||||
|
||||
if recruitedTrans then
|
||||
|
||||
if MissionType==AUFTRAG.Type.PATROLZONE then
|
||||
mission=AUFTRAG:NewPATROLZONE(TargetZone)
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.ONGUARD then
|
||||
mission=AUFTRAG:NewONGUARD(TargetZone:GetRandomCoordinate(nil, nil, {land.SurfaceType.LAND}))
|
||||
end
|
||||
|
||||
-- Engage detected targets.
|
||||
mission:SetEngageDetected(25, {"Ground Units", "Light armed ships", "Helicopters"})
|
||||
|
||||
-- Attach OPS transport to mission.
|
||||
mission.opstransport=transport
|
||||
|
||||
-- Set ops zone to transport.
|
||||
if transport then
|
||||
transport.opszone=StratZone.opszone
|
||||
transport.chief=self
|
||||
transport.commander=self.commander
|
||||
end
|
||||
|
||||
else
|
||||
-- No transport ==> no mission!
|
||||
self:T(self.lid..string.format("Could not allocate transport of OPSZONE infantry!"))
|
||||
LEGION.UnRecruitAssets(assets)
|
||||
return false
|
||||
end
|
||||
-- Engage detected targets.
|
||||
mission:SetEngageDetected(25, {"Ground Units", "Light armed ships", "Helicopters"})
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.CASENHANCED then
|
||||
|
||||
@ -3043,6 +3131,15 @@ function CHIEF:RecruitAssetsForZone(StratZone, Resource)
|
||||
-- Attach mission to resource.
|
||||
Resource.mission=mission
|
||||
|
||||
if transport then
|
||||
-- Attach OPS transport to mission.
|
||||
mission.opstransport=transport
|
||||
-- Set ops zone to transport.
|
||||
transport.opszone=StratZone.opszone
|
||||
transport.chief=self
|
||||
transport.commander=self.commander
|
||||
end
|
||||
|
||||
return true
|
||||
else
|
||||
|
||||
@ -3061,6 +3158,89 @@ function CHIEF:RecruitAssetsForZone(StratZone, Resource)
|
||||
return false
|
||||
end
|
||||
|
||||
--- Filter assets, which have certain categories, attributes and/or properties.
|
||||
-- @param #table Assets The assets to be filtered.
|
||||
-- @param #table Categories Group categories.
|
||||
-- @param #table Attributes Generalized attributes.
|
||||
-- @param #table Properties DCS attributes
|
||||
-- @return #table Table of filtered assets.
|
||||
function CHIEF._FilterAssets(Assets, Categories, Attributes, Properties)
|
||||
|
||||
local filtered={}
|
||||
|
||||
for _,_asset in pairs(Assets) do
|
||||
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
|
||||
local hasCat=CHIEF._CheckAssetCategories(asset, Categories)
|
||||
local hasAtt=CHIEF._CheckAssetAttributes(asset, Attributes)
|
||||
local hasPro=CHIEF._CheckAssetProperties(asset, Properties)
|
||||
|
||||
if hasAtt and hasCat and hasPro then
|
||||
table.insert(filtered, asset)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return filtered
|
||||
end
|
||||
|
||||
--- Check if a given asset has certain attribute(s).
|
||||
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset item.
|
||||
-- @param #table Attributes The required attributes. See `WAREHOUSE.Attribute` enum. Can also be passed as a single attribute `#string`.
|
||||
-- @return #boolean Returns `true`, the asset has at least one requested attribute.
|
||||
function CHIEF._CheckAssetAttributes(Asset, Attributes)
|
||||
|
||||
if not Attributes then
|
||||
return true
|
||||
end
|
||||
|
||||
for _,attribute in pairs(UTILS.EnsureTable(Attributes)) do
|
||||
if attribute==Asset.attribute then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Check if a given asset has certain categories.
|
||||
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset item.
|
||||
-- @param #table Categories DCS group categories.
|
||||
-- @return #boolean Returns `true`, the asset has at least one requested category.
|
||||
function CHIEF._CheckAssetCategories(Asset, Categories)
|
||||
|
||||
if not Categories then
|
||||
return true
|
||||
end
|
||||
|
||||
for _,attribute in pairs(UTILS.EnsureTable(Categories)) do
|
||||
if attribute==Asset.category then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Check if a given asset has certain properties.
|
||||
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset item.
|
||||
-- @param #table Categories DCS group categories.
|
||||
-- @return #boolean Returns `true`, the asset has at least one requested property.
|
||||
function CHIEF._CheckAssetProperties(Asset, Properties)
|
||||
|
||||
if not Properties then
|
||||
return true
|
||||
end
|
||||
|
||||
for _,attribute in pairs(UTILS.EnsureTable(Properties)) do
|
||||
if attribute==Asset.DCSdesc then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -210,7 +210,7 @@ FLIGHTGROUP.Players={}
|
||||
|
||||
--- FLIGHTGROUP class version.
|
||||
-- @field #string version
|
||||
FLIGHTGROUP.version="0.8.1"
|
||||
FLIGHTGROUP.version="0.8.2"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -899,6 +899,60 @@ function FLIGHTGROUP:Status()
|
||||
end
|
||||
end
|
||||
|
||||
-- Get current mission (if any).
|
||||
local mission=self:GetMissionCurrent()
|
||||
|
||||
-- If mission, check if DCS task needs to be updated.
|
||||
if mission and mission.updateDCSTask then
|
||||
|
||||
-- Orbit missions might need updates.
|
||||
if (mission:GetType()==AUFTRAG.Type.ORBIT or mission:GetType()==AUFTRAG.Type.RECOVERYTANKER) and mission.orbitVec2 then
|
||||
|
||||
-- Get 2D vector of orbit target.
|
||||
local vec2=mission:GetTargetVec2()
|
||||
|
||||
-- Heading.
|
||||
local hdg=mission:GetTargetHeading()
|
||||
|
||||
-- Heading change?
|
||||
local hdgchange=false
|
||||
if mission.orbitLeg then
|
||||
if UTILS.HdgDiff(hdg, mission.targetHeading)>0 then
|
||||
hdgchange=true
|
||||
end
|
||||
end
|
||||
|
||||
-- Distance to previous position.
|
||||
local dist=UTILS.VecDist2D(vec2, mission.orbitVec2)
|
||||
|
||||
-- Distance change?
|
||||
local distchange=dist>mission.orbitDeltaR
|
||||
|
||||
-- Debug info.
|
||||
self:T3(self.lid..string.format("Checking orbit mission dist=%d meters", dist))
|
||||
|
||||
-- Check if distance is larger than threshold.
|
||||
if distchange or hdgchange then
|
||||
|
||||
-- Debug info.
|
||||
self:T3(self.lid..string.format("Updating orbit!"))
|
||||
|
||||
-- Update DCS task. This also sets the new mission.orbitVec2.
|
||||
local DCSTask=mission:GetDCSMissionTask() --DCS#Task
|
||||
|
||||
-- Get task.
|
||||
local Task=self:GetTaskByID(mission.auftragsnummer)
|
||||
|
||||
-- Reset current orbit task.
|
||||
self.controller:resetTask()
|
||||
|
||||
-- Push task after one second. We need to give resetTask some time or it will not work!
|
||||
self:_SandwitchDCSTask(DCSTask, Task, false, 1)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- TODO: _CheckParking() function
|
||||
|
||||
@ -1157,16 +1211,6 @@ function FLIGHTGROUP:Status()
|
||||
-- Current mission.
|
||||
local mission=self:GetMissionCurrent()
|
||||
|
||||
if mission and mission.type==AUFTRAG.Type.RECOVERYTANKER and mission:GetGroupStatus(self)==AUFTRAG.GroupStatus.EXECUTING then
|
||||
|
||||
--env.info("FF recovery tanker updating DCS task")
|
||||
--self:ClearTasks()
|
||||
|
||||
local DCSTask=mission:GetDCSMissionTask()
|
||||
self:SetTask(DCSTask)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -499,7 +499,7 @@ OPSGROUP.CargoStatus={
|
||||
|
||||
--- OpsGroup version.
|
||||
-- @field #string version
|
||||
OPSGROUP.version="0.7.9"
|
||||
OPSGROUP.version="0.8.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -4070,6 +4070,23 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
-- Get mission of this task (if any).
|
||||
local Mission=self:GetMissionByTaskID(self.taskcurrent)
|
||||
|
||||
|
||||
self:_UpdateTask(Task, Mission)
|
||||
|
||||
-- Set AUFTRAG status.
|
||||
if Mission then
|
||||
self:MissionExecute(Mission)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Push task
|
||||
-- @param #OPSGROUP self
|
||||
-- @param Ops.OpsGroup#OPSGROUP.Task Task The task.
|
||||
function OPSGROUP:_UpdateTask(Task, Mission)
|
||||
|
||||
local Mission=Mission or self:GetMissionByTaskID(self.taskcurrent)
|
||||
|
||||
if Task.dcstask.id==AUFTRAG.SpecialTask.FORMATION then
|
||||
|
||||
-- Set of group(s) to follow Mother.
|
||||
@ -4421,13 +4438,6 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
-- Set quantity of task.
|
||||
DCSTask.params.expendQty=nShots
|
||||
|
||||
elseif Mission and Mission.type==AUFTRAG.Type.RECOVERYTANKER then
|
||||
|
||||
env.info("FF recoverytanker setting DCS task")
|
||||
|
||||
-- Update DCS task with the current carrier parameters.
|
||||
DCSTask=Mission:GetDCSMissionTask()
|
||||
|
||||
else
|
||||
---
|
||||
-- Take DCS task
|
||||
@ -4435,38 +4445,7 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
DCSTask=Task.dcstask
|
||||
end
|
||||
|
||||
local DCStasks={}
|
||||
if DCSTask.id=='ComboTask' then
|
||||
-- Loop over all combo tasks.
|
||||
for TaskID, Task in ipairs(DCSTask.params.tasks) do
|
||||
table.insert(DCStasks, Task)
|
||||
end
|
||||
else
|
||||
table.insert(DCStasks, DCSTask)
|
||||
end
|
||||
|
||||
-- Combo task.
|
||||
local TaskCombo=self.group:TaskCombo(DCStasks)
|
||||
|
||||
-- Stop condition!
|
||||
local TaskCondition=self.group:TaskCondition(nil, Task.stopflag:GetName(), 1, nil, Task.duration)
|
||||
|
||||
-- Controlled task.
|
||||
local TaskControlled=self.group:TaskControlled(TaskCombo, TaskCondition)
|
||||
|
||||
-- Task done.
|
||||
local TaskDone=self.group:TaskFunction("OPSGROUP._TaskDone", self, Task)
|
||||
|
||||
-- Final task.
|
||||
local TaskFinal=self.group:TaskCombo({TaskControlled, TaskDone})
|
||||
|
||||
-- Set task for group.
|
||||
-- NOTE: I am pushing the task instead of setting it as it seems to keep the mission task alive.
|
||||
-- There were issues that flights did not proceed to a later waypoint because the task did not finish until the fired missiles
|
||||
-- impacted (took rather long). Then the flight flew to the nearest airbase and one lost completely the control over the group.
|
||||
self:PushTask(TaskFinal)
|
||||
--self:SetTask(TaskFinal)
|
||||
|
||||
self:_SandwitchDCSTask(DCSTask, Task)
|
||||
|
||||
elseif Task.type==OPSGROUP.TaskType.WAYPOINT then
|
||||
-- Waypoint tasks are executed elsewhere!
|
||||
@ -4476,14 +4455,61 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Sandwitch DCS task in stop condition and push the task to the group.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param DCS#Task DCSTask The DCS task.
|
||||
-- @param Ops.OpsGroup#OPSGROUP.Task Task
|
||||
-- @param #boolean SetTask Set task instead of pushing it.
|
||||
-- @param #number Delay Delay in seconds. Default nil.
|
||||
function OPSGROUP:_SandwitchDCSTask(DCSTask, Task, SetTask, Delay)
|
||||
|
||||
if Delay and Delay>0 then
|
||||
-- Delayed call.
|
||||
self:ScheduleOnce(Delay, OPSGROUP._SandwitchDCSTask, self, DCSTask, Task, SetTask)
|
||||
else
|
||||
|
||||
local DCStasks={}
|
||||
if DCSTask.id=='ComboTask' then
|
||||
-- Loop over all combo tasks.
|
||||
for TaskID, Task in ipairs(DCSTask.params.tasks) do
|
||||
table.insert(DCStasks, Task)
|
||||
end
|
||||
else
|
||||
table.insert(DCStasks, DCSTask)
|
||||
end
|
||||
|
||||
-- Combo task.
|
||||
local TaskCombo=self.group:TaskCombo(DCStasks)
|
||||
|
||||
-- Stop condition!
|
||||
local TaskCondition=self.group:TaskCondition(nil, Task.stopflag:GetName(), 1, nil, Task.duration)
|
||||
|
||||
-- Controlled task.
|
||||
local TaskControlled=self.group:TaskControlled(TaskCombo, TaskCondition)
|
||||
|
||||
-- Task done.
|
||||
local TaskDone=self.group:TaskFunction("OPSGROUP._TaskDone", self, Task)
|
||||
|
||||
-- Final task.
|
||||
local TaskFinal=self.group:TaskCombo({TaskControlled, TaskDone})
|
||||
|
||||
-- Set task for group.
|
||||
-- NOTE: I am pushing the task instead of setting it as it seems to keep the mission task alive.
|
||||
-- There were issues that flights did not proceed to a later waypoint because the task did not finish until the fired missiles
|
||||
-- impacted (took rather long). Then the flight flew to the nearest airbase and one lost completely the control over the group.
|
||||
if SetTask then
|
||||
self:SetTask(TaskFinal)
|
||||
else
|
||||
self:PushTask(TaskFinal)
|
||||
end
|
||||
|
||||
-- Set AUFTRAG status.
|
||||
if Mission then
|
||||
self:MissionExecute(Mission)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- On after "TaskCancel" event. Cancels the current task or simply sets the status to DONE if the task is not the current one.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param #string From From state.
|
||||
@ -5535,22 +5561,6 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
waypointcoord=currentcoord:GetIntermediateCoordinate(ToCoordinate, 0.05)
|
||||
end
|
||||
|
||||
elseif mission.type==AUFTRAG.Type.RECOVERYTANKER then
|
||||
---
|
||||
-- Recoverytanker
|
||||
---
|
||||
|
||||
local carrier=mission.DCStask.params.carrier --Wrapper.Unit#UNIT
|
||||
|
||||
-- Roughly go to the new legion.
|
||||
local CarrierCoordinate=carrier:GetCoordinate()
|
||||
|
||||
local heading=carrier:GetHeading()
|
||||
|
||||
waypointcoord=CarrierCoordinate:Translate(10000, heading-180):SetAltitude(2000)
|
||||
|
||||
waypointcoord:MarkToAll("Recoverytanker")
|
||||
|
||||
else
|
||||
---
|
||||
-- Default case
|
||||
@ -5642,18 +5652,33 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
end
|
||||
|
||||
|
||||
-- Distance to waypoint coordinate.
|
||||
local d=currentcoord:Get2DDistance(waypointcoord)
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Distance to ingress waypoint=%.1f m", d))
|
||||
|
||||
-- Add mission execution (ingress) waypoint.
|
||||
local waypoint=nil --#OPSGROUP.Waypoint
|
||||
if self:IsFlightgroup() then
|
||||
|
||||
waypoint=FLIGHTGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false)
|
||||
|
||||
elseif self:IsArmygroup() then
|
||||
|
||||
-- Set formation.
|
||||
local formation=mission.optionFormation
|
||||
if mission.type==AUFTRAG.Type.RELOCATECOHORT then
|
||||
|
||||
-- If distance is < 1 km or RELOCATECOHORT mission, go off-road.
|
||||
if d<1000 or mission.type==AUFTRAG.Type.RELOCATECOHORT then
|
||||
formation=ENUMS.Formation.Vehicle.OffRoad
|
||||
end
|
||||
|
||||
waypoint=ARMYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, formation, false)
|
||||
elseif self:IsNavygroup() then
|
||||
|
||||
waypoint=NAVYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false)
|
||||
|
||||
end
|
||||
waypoint.missionUID=mission.auftragsnummer
|
||||
|
||||
@ -5682,13 +5707,6 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
mission:SetGroupEgressWaypointUID(self, Ewaypoint.uid)
|
||||
end
|
||||
|
||||
|
||||
-- Distance to waypoint coordinate.
|
||||
local d=currentcoord:Get2DDistance(waypointcoord)
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("FF distance to ingress waypoint=%.1f m", d))
|
||||
|
||||
-- Check if we are already where we want to be.
|
||||
if targetzone and self:IsInZone(targetzone) then
|
||||
self:T(self.lid.."Already in mission zone ==> TaskExecute()")
|
||||
@ -8499,13 +8517,9 @@ function OPSGROUP:onafterPickup(From, Event, To)
|
||||
|
||||
-- Get a random coordinate in the pickup zone and let the carrier go there.
|
||||
local Coordinate=Zone:GetRandomCoordinate(nil, nil, surfacetypes)
|
||||
--Coordinate:MarkToAll(string.format("Pickup coordinate for group %s [Surface type=%d]", self:GetName(), Coordinate:GetSurfaceType()))
|
||||
|
||||
-- Current Waypoint.
|
||||
local cwp=self:GetWaypointCurrent()
|
||||
|
||||
-- Current waypoint ID.
|
||||
local uid=cwp and cwp.uid or nil
|
||||
local uid=self:GetWaypointCurrentUID()
|
||||
|
||||
-- Add waypoint.
|
||||
if self:IsFlightgroup() then
|
||||
@ -8546,8 +8560,6 @@ function OPSGROUP:onafterPickup(From, Event, To)
|
||||
|
||||
local coordinate=self:GetCoordinate():GetIntermediateCoordinate(Coordinate, 0.5)
|
||||
|
||||
--coordinate:MarkToAll("Pickup Inter Coord")
|
||||
|
||||
-- If this is a helo and no ZONE_AIRBASE was given, we make the helo land in the pickup zone.
|
||||
local waypoint=FLIGHTGROUP.AddWaypoint(self, coordinate, nil, uid, UTILS.MetersToFeet(self.altitudeCruise), true) ; waypoint.detour=1
|
||||
|
||||
@ -8616,7 +8628,7 @@ function OPSGROUP:onafterPickup(From, Event, To)
|
||||
local path=self.cargoTransport:_GetPathTransport(self.category, self.cargoTZC)
|
||||
|
||||
-- Formation used to go to the pickup zone..
|
||||
local Formation=self.cargoTransport:_GetFormationTransport(self.cargoTZC)
|
||||
local Formation=self.cargoTransport:_GetFormationPickup(self.cargoTZC, self)
|
||||
|
||||
-- Get transport path.
|
||||
if path and oldstatus~=OPSGROUP.CarrierStatus.NOTCARRIER then
|
||||
@ -8632,7 +8644,7 @@ function OPSGROUP:onafterPickup(From, Event, To)
|
||||
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, uid, Formation, false) ; waypoint.detour=1
|
||||
|
||||
-- Give cruise command.
|
||||
self:__Cruise(-2)
|
||||
self:__Cruise(-2, nil, Formation)
|
||||
|
||||
end
|
||||
|
||||
@ -8917,7 +8929,8 @@ function OPSGROUP:onafterTransport(From, Event, To)
|
||||
-- Coord where the carrier goes to unload.
|
||||
local Coordinate=Zone:GetRandomCoordinate(nil, nil, surfacetypes) --Core.Point#COORDINATE
|
||||
|
||||
--Coordinate:MarkToAll(string.format("Deploy coordinate for group %s [Surface type=%d]", self:GetName(), Coordinate:GetSurfaceType()))
|
||||
-- Current waypoint UID.
|
||||
local uid=self:GetWaypointCurrentUID()
|
||||
|
||||
-- Add waypoint.
|
||||
if self:IsFlightgroup() then
|
||||
@ -8933,9 +8946,6 @@ function OPSGROUP:onafterTransport(From, Event, To)
|
||||
-- Deploy at airbase
|
||||
---
|
||||
|
||||
local cwp=self:GetWaypointCurrent()
|
||||
local uid=cwp and cwp.uid or nil
|
||||
|
||||
-- Get a (random) pre-defined transport path.
|
||||
local path=self.cargoTransport:_GetPathTransport(self.category, self.cargoTZC)
|
||||
|
||||
@ -8957,16 +8967,11 @@ function OPSGROUP:onafterTransport(From, Event, To)
|
||||
|
||||
local coordinate=self:GetCoordinate():GetIntermediateCoordinate(Coordinate, 0.5)
|
||||
|
||||
--coordinate:MarkToAll("Transport Inter Waypoint")
|
||||
|
||||
-- If this is a helo and no ZONE_AIRBASE was given, we make the helo land in the pickup zone.
|
||||
local waypoint=FLIGHTGROUP.AddWaypoint(self, coordinate, nil, uid, UTILS.MetersToFeet(self.altitudeCruise), true) ; waypoint.detour=1
|
||||
|
||||
end
|
||||
|
||||
-- Order group to land at an airbase.
|
||||
--self:__LandAtAirbase(-0.1, airbaseDeploy)
|
||||
|
||||
elseif self.isHelo then
|
||||
|
||||
---
|
||||
@ -8974,7 +8979,7 @@ function OPSGROUP:onafterTransport(From, Event, To)
|
||||
---
|
||||
|
||||
-- If this is a helo and no ZONE_AIRBASE was given, we make the helo land in the pickup zone.
|
||||
local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid, UTILS.MetersToFeet(self.altitudeCruise), false) ; waypoint.detour=1
|
||||
local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate, nil, uid, UTILS.MetersToFeet(self.altitudeCruise), false) ; waypoint.detour=1
|
||||
|
||||
else
|
||||
self:T(self.lid.."ERROR: Aircraft (cargo carrier) cannot land in Deploy zone! Specify a ZONE_AIRBASE as deploy zone")
|
||||
@ -8992,14 +8997,11 @@ function OPSGROUP:onafterTransport(From, Event, To)
|
||||
|
||||
elseif self:IsArmygroup() then
|
||||
|
||||
local cwp=self:GetWaypointCurrent()
|
||||
local uid=cwp and cwp.uid or nil
|
||||
|
||||
-- Get transport path.
|
||||
local path=self.cargoTransport:_GetPathTransport(self.category, self.cargoTZC)
|
||||
|
||||
-- Formation used for transporting.
|
||||
local Formation=self.cargoTransport:_GetFormationTransport(self.cargoTZC)
|
||||
local Formation=self.cargoTransport:_GetFormationTransport(self.cargoTZC, self)
|
||||
|
||||
-- Get transport path.
|
||||
if path then
|
||||
@ -9015,13 +9017,10 @@ function OPSGROUP:onafterTransport(From, Event, To)
|
||||
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, uid, Formation, false) ; waypoint.detour=1
|
||||
|
||||
-- Give cruise command.
|
||||
self:Cruise()
|
||||
self:Cruise(nil, Formation)
|
||||
|
||||
elseif self:IsNavygroup() then
|
||||
|
||||
local cwp=self:GetWaypointCurrent()
|
||||
local uid=cwp and cwp.uid or nil
|
||||
|
||||
-- Get a (random) pre-defined transport path.
|
||||
local path=self.cargoTransport:_GetPathTransport(self.category, self.cargoTZC)
|
||||
|
||||
@ -9434,7 +9433,7 @@ function OPSGROUP:onafterDelivered(From, Event, To, CargoTransport)
|
||||
end
|
||||
else
|
||||
-- Army & Navy: give Cruise command to "wake up" from waiting status.
|
||||
self:__Cruise(0.1)
|
||||
self:__Cruise(-0.1)
|
||||
end
|
||||
|
||||
-- Set carrier transport status.
|
||||
@ -9859,14 +9858,14 @@ function OPSGROUP:_CheckGroupDone(delay)
|
||||
|
||||
if delay and delay>0 then
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Check OPSGROUP [state=%s] done in %.3f seconds...", fsmstate, delay))
|
||||
self:T(self.lid..string.format("Check OPSGROUP done? [state=%s] in %.3f seconds...", fsmstate, delay))
|
||||
|
||||
-- Delayed call.
|
||||
self:ScheduleOnce(delay, self._CheckGroupDone, self)
|
||||
else
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Check OSGROUP [state=%s] done?", fsmstate))
|
||||
self:T(self.lid..string.format("Check OSGROUP done? [state=%s]", fsmstate))
|
||||
|
||||
-- Group is engaging something.
|
||||
if self:IsEngaging() then
|
||||
@ -10646,7 +10645,7 @@ function OPSGROUP._PassingWaypoint(opsgroup, uid)
|
||||
|
||||
-- Set formation.
|
||||
if opsgroup.isArmygroup then
|
||||
opsgroup.formation=wpnext.action
|
||||
opsgroup.option.Formation=wpnext.action
|
||||
end
|
||||
|
||||
-- Set speed to next wp.
|
||||
|
||||
@ -50,6 +50,10 @@
|
||||
-- @field #number NcarrierDead Total number of dead carrier groups
|
||||
-- @field #number NcargoDead Totalnumber of dead cargo groups.
|
||||
--
|
||||
-- @field #string formationArmy Default formation for ground vehicles.
|
||||
-- @field #string formationHelo Default formation for helicopters.
|
||||
-- @field #string formationPlane Default formation for airplanes.
|
||||
--
|
||||
-- @field Ops.Auftrag#AUFTRAG mission The mission attached to this transport.
|
||||
-- @field #table assets Warehouse assets assigned for this transport.
|
||||
-- @field #table legions Assigned legions.
|
||||
@ -191,7 +195,7 @@ _OPSTRANSPORTID=0
|
||||
|
||||
--- Army Group version.
|
||||
-- @field #string version
|
||||
OPSTRANSPORT.version="0.6.0"
|
||||
OPSTRANSPORT.version="0.6.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -235,6 +239,10 @@ function OPSTRANSPORT:New(CargoGroups, PickupZone, DeployZone)
|
||||
self:SetTime()
|
||||
self:SetRequiredCarriers()
|
||||
|
||||
self.formationArmy=ENUMS.Formation.Vehicle.OnRoad
|
||||
self.formationHelo=ENUMS.Formation.RotaryWing.Wedge
|
||||
self.formationPlane=ENUMS.Formation.FixedWing.Wedge
|
||||
|
||||
-- Init arrays and counters.
|
||||
self.carriers={}
|
||||
self.Ncargo=0
|
||||
@ -809,16 +817,44 @@ function OPSTRANSPORT:SetFormationPickup(Formation, TransportZoneCombo)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get pickup formation.
|
||||
-- @param #OPSTRANSPORT self
|
||||
-- @param Ops.OpsGroup#OPSGROUP OpsGroup
|
||||
-- @return #string Formation.
|
||||
function OPSTRANSPORT:_GetFormationDefault(OpsGroup)
|
||||
|
||||
if OpsGroup.isArmygroup then
|
||||
|
||||
return self.formationArmy
|
||||
|
||||
elseif OpsGroup.isFlightgroup then
|
||||
|
||||
if OpsGroup.isHelo then
|
||||
return self.formationHelo
|
||||
else
|
||||
return self.formationPlane
|
||||
end
|
||||
|
||||
else
|
||||
return ENUMS.Formation.Vehicle.OffRoad
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get pickup formation.
|
||||
-- @param #OPSTRANSPORT self
|
||||
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
||||
-- @param Ops.OpsGroup#OPSGROUP OpsGroup
|
||||
-- @return #number Formation.
|
||||
function OPSTRANSPORT:_GetFormationPickup(TransportZoneCombo)
|
||||
function OPSTRANSPORT:_GetFormationPickup(TransportZoneCombo, OpsGroup)
|
||||
|
||||
-- Use default TZC if no transport zone combo is provided.
|
||||
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
||||
|
||||
return TransportZoneCombo.PickupFormation
|
||||
local formation=TransportZoneCombo.PickupFormation or self:_GetFormationDefault(OpsGroup)
|
||||
|
||||
return formation
|
||||
end
|
||||
|
||||
--- Set transport formation.
|
||||
@ -839,13 +875,16 @@ end
|
||||
--- Get transport formation.
|
||||
-- @param #OPSTRANSPORT self
|
||||
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
||||
-- @param Ops.OpsGroup#OPSGROUP OpsGroup
|
||||
-- @return #number Formation.
|
||||
function OPSTRANSPORT:_GetFormationTransport(TransportZoneCombo)
|
||||
function OPSTRANSPORT:_GetFormationTransport(TransportZoneCombo, OpsGroup)
|
||||
|
||||
-- Use default TZC if no transport zone combo is provided.
|
||||
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
||||
|
||||
return TransportZoneCombo.TransportFormation
|
||||
local formation=TransportZoneCombo.TransportFormation or self:_GetFormationDefault(OpsGroup)
|
||||
|
||||
return formation
|
||||
end
|
||||
|
||||
|
||||
|
||||
@ -641,10 +641,8 @@ function OPSZONE:onafterStop(From, Event, To)
|
||||
-- Reinit the timer.
|
||||
self.timerStatus:Stop()
|
||||
|
||||
-- Draw zone.
|
||||
if self.drawZone then
|
||||
self.zone:UndrawZone()
|
||||
end
|
||||
-- Undraw zone.
|
||||
self.zone:UndrawZone()
|
||||
|
||||
-- Remove marker.
|
||||
if self.markZone then
|
||||
@ -691,6 +689,11 @@ function OPSZONE:Status()
|
||||
-- Update F10 marker (only if enabled).
|
||||
self:_UpdateMarker()
|
||||
|
||||
-- Undraw zone.
|
||||
if self.zone.DrawID and not self.drawZone then
|
||||
self.zone:UndrawZone()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -151,7 +151,7 @@ _TARGETID=0
|
||||
|
||||
--- TARGET class version.
|
||||
-- @field #string version
|
||||
TARGET.version="0.5.5"
|
||||
TARGET.version="0.5.6"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -1108,7 +1108,7 @@ function TARGET:GetTargetLife(Target)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get current life points.
|
||||
--- Get current total life points. This is the sum of all target objects.
|
||||
-- @param #TARGET self
|
||||
-- @return #number Life points of target.
|
||||
function TARGET:GetLife()
|
||||
@ -1311,6 +1311,89 @@ function TARGET:GetTargetVec3(Target, Average)
|
||||
self:E(self.lid.."ERROR: Unknown TARGET type! Cannot get Vec3")
|
||||
end
|
||||
|
||||
--- Get heading of the target.
|
||||
-- @param #TARGET self
|
||||
-- @param #TARGET.Object Target Target object.
|
||||
-- @return #number Heading in degrees.
|
||||
function TARGET:GetTargetHeading(Target)
|
||||
|
||||
if Target.Type==TARGET.ObjectType.GROUP then
|
||||
|
||||
local object=Target.Object --Wrapper.Group#GROUP
|
||||
|
||||
if object and object:IsAlive() then
|
||||
local heading=object:GetHeading()
|
||||
|
||||
if heading then
|
||||
return heading
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
elseif Target.Type==TARGET.ObjectType.UNIT then
|
||||
|
||||
local object=Target.Object --Wrapper.Unit#UNIT
|
||||
|
||||
if object and object:IsAlive() then
|
||||
local heading=object:GetHeading()
|
||||
return heading
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
elseif Target.Type==TARGET.ObjectType.STATIC then
|
||||
|
||||
local object=Target.Object --Wrapper.Static#STATIC
|
||||
|
||||
if object and object:IsAlive() then
|
||||
local heading=object:GetHeading()
|
||||
return heading
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
elseif Target.Type==TARGET.ObjectType.SCENERY then
|
||||
|
||||
local object=Target.Object --Wrapper.Scenery#SCENERY
|
||||
|
||||
if object then
|
||||
local heading=object:GetHeading()
|
||||
return heading
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
elseif Target.Type==TARGET.ObjectType.AIRBASE then
|
||||
|
||||
local object=Target.Object --Wrapper.Airbase#AIRBASE
|
||||
|
||||
-- Airbase has no real heading. Return 0. Maybe take the runway heading?
|
||||
return 0
|
||||
|
||||
elseif Target.Type==TARGET.ObjectType.COORDINATE then
|
||||
|
||||
local object=Target.Object --Core.Point#COORDINATE
|
||||
|
||||
-- A coordinate has no heading. Return 0.
|
||||
return 0
|
||||
|
||||
elseif Target.Type==TARGET.ObjectType.ZONE then
|
||||
|
||||
local object=Target.Object --Core.Zone#ZONE
|
||||
|
||||
-- A zone has no heading. Return 0.
|
||||
return 0
|
||||
|
||||
end
|
||||
|
||||
self:E(self.lid.."ERROR: Unknown TARGET type! Cannot get heading")
|
||||
end
|
||||
|
||||
|
||||
--- Get target coordinate.
|
||||
-- @param #TARGET self
|
||||
@ -1473,7 +1556,7 @@ function TARGET:GetAverageCoordinate()
|
||||
for _,_target in pairs(self.targets) do
|
||||
local Target=_target --#TARGET.Object
|
||||
|
||||
local coordinate=self:GetTargetCoordinate(Target,true)
|
||||
local coordinate=self:GetTargetCoordinate(Target, true)
|
||||
|
||||
if coordinate then
|
||||
return coordinate
|
||||
@ -1485,6 +1568,26 @@ function TARGET:GetAverageCoordinate()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get heading of target.
|
||||
-- @param #TARGET self
|
||||
-- @return #number Heading of the target in degrees.
|
||||
function TARGET:GetHeading()
|
||||
|
||||
for _,_target in pairs(self.targets) do
|
||||
local Target=_target --#TARGET.Object
|
||||
|
||||
local heading=self:GetTargetHeading(Target)
|
||||
|
||||
if heading then
|
||||
return heading
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:E(self.lid..string.format("ERROR: Cannot get heading of target %s", tostring(self.name)))
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get category.
|
||||
-- @param #TARGET self
|
||||
-- @return #string Target category. See `TARGET.Category.X`, where `X=AIRCRAFT, GROUND`.
|
||||
@ -1492,6 +1595,7 @@ function TARGET:GetCategory()
|
||||
return self.category
|
||||
end
|
||||
|
||||
|
||||
--- Get target category.
|
||||
-- @param #TARGET self
|
||||
-- @param #TARGET.Object Target Target object.
|
||||
|
||||
@ -1259,7 +1259,7 @@ end
|
||||
|
||||
--- (AIR) Orbit at a position with at a given altitude and speed. Optionally, a race track pattern can be specified.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Point#COORDINATE Coord Coordinate at which the CONTROLLABLE orbits.
|
||||
-- @param Core.Point#COORDINATE Coord Coordinate at which the CONTROLLABLE orbits. Can also be given as a `DCS#Vec3` or `DCS#Vec2` object.
|
||||
-- @param #number Altitude Altitude in meters of the orbit pattern. Default y component of Coord.
|
||||
-- @param #number Speed Speed [m/s] flying the orbit pattern. Default 128 m/s = 250 knots.
|
||||
-- @param Core.Point#COORDINATE CoordRaceTrack (Optional) If this coordinate is specified, the CONTROLLABLE will fly a race-track pattern using this and the initial coordinate.
|
||||
@ -1268,11 +1268,11 @@ function CONTROLLABLE:TaskOrbit( Coord, Altitude, Speed, CoordRaceTrack )
|
||||
|
||||
local Pattern = AI.Task.OrbitPattern.CIRCLE
|
||||
|
||||
local P1 = Coord:GetVec2()
|
||||
local P1 = {x=Coord.x, y=Coord.z or Coord.y}
|
||||
local P2 = nil
|
||||
if CoordRaceTrack then
|
||||
Pattern = AI.Task.OrbitPattern.RACE_TRACK
|
||||
P2 = CoordRaceTrack:GetVec2()
|
||||
P2 = {x=CoordRaceTrack.x, y=CoordRaceTrack.z or CoordRaceTrack.y}
|
||||
end
|
||||
|
||||
local Task = {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user