Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Applevangelist 2022-11-05 14:05:16 +01:00
commit e512569d5c
9 changed files with 953 additions and 351 deletions

View File

@ -68,7 +68,7 @@ ARMYGROUP = {
--- Army Group version. --- Army Group version.
-- @field #string version -- @field #string version
ARMYGROUP.version="0.7.9" ARMYGROUP.version="0.8.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -775,8 +775,8 @@ function ARMYGROUP:Status()
end end
-- Info text. -- 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", 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, hdg, ammo, ndetected, cargo) 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) self:I(self.lid..text)
end end
@ -1071,89 +1071,182 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation)
-- Next waypoint. -- Next waypoint.
local wp=self.waypoints[n] --Ops.OpsGroup#OPSGROUP.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. -- Formation at the current position.
local formation0=wp.action local formation0=wp.action
if formation0==ENUMS.Formation.Vehicle.OnRoad then if formation0==ENUMS.Formation.Vehicle.OnRoad then
if wp.roadcoord then -- Next waypoint is on road. Check if we are already on road.
if wp.roaddist>10 then if roaddist>10 then
formation0=ENUMS.Formation.Vehicle.OffRoad -- Currently off road ==> we add an on road WP later.
end
else
formation0=ENUMS.Formation.Vehicle.OffRoad 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
end end
-- Debug
--env.info(self.lid.."FF formation0="..tostring(formation0))
-- Current point. -- 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) table.insert(waypoints, 1, current)
-- Loop over waypoints. -- Check if route consists of more than one waypoint (otherwise we have no previous waypoint)
for j=n, N do if N-n>0 then
-- Index of previous waypoint. -- Loop over waypoints.
local i=j-1 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. -- Index of previous waypoint.
if i==0 then local i=j-1
i=self.currentwp
-- 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 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. -- Next waypoint.
local wp=UTILS.DeepCopy(self.waypoints[j]) --Ops.OpsGroup#OPSGROUP.Waypoint local wp=UTILS.DeepCopy(self.waypoints[n]) --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)
-- Speed. -- Speed.
if Speed then if wp.speed<0.1 then
wp.speed=UTILS.KnotsToMps(tonumber(Speed)) wp.speed=UTILS.KmphToMps(self.speedCruise)
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 end
-- Formation. -- Formation.
local formation=wp.action
if self.formationPerma then if self.formationPerma then
wp.action=self.formationPerma formation=self.formationPerma
elseif Formation then elseif Formation then
wp.action=Formation formation=Formation
end end
-- Add waypoint in between because this waypoint is "On Road" but lies "Off Road". -- Debug
if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp0.roaddist>=0 then --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. if roaddist>10 then
local wproad=wp0.roadcoord:WaypointGround(UTILS.MpsToKmph(wp.speed), ENUMS.Formation.Vehicle.OnRoad) --Ops.OpsGroup#OPSGROUP.Waypoint
-- 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 end
-- Add waypoint in between because this waypoint is "On Road" but lies "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>=0 then if wp.action==ENUMS.Formation.Vehicle.OnRoad and wp.roaddist>10 then
--env.info("FF adding waypoint on road #"..i)
-- The real waypoint is actually off road.
wp.action=ENUMS.Formation.Vehicle.OffRoad 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 end
-- Debug
--wp.coordinate:MarkToAll(self.lid.." Added coord "..tostring(wp.action))
-- Add waypoint. -- Add actual waypoint.
table.insert(waypoints, wp) table.insert(waypoints, wp)
end end
-- First (next wp). -- First (next wp).
@ -1166,7 +1259,7 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation)
self.speedWp=wp.speed self.speedWp=wp.speed
-- Debug output. -- 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 for i,_wp in pairs(waypoints) do
local wp=_wp --Ops.OpsGroup#OPSGROUP.Waypoint 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) self:SwitchROE(ENUMS.ROE.OpenFire)
-- ID of current waypoint. -- ID of current waypoint.
local uid=self:GetWaypointCurrent().uid local uid=self:GetWaypointCurrentUID()
-- Set formation. -- Set formation.
self.engage.Formation=Formation or ENUMS.Formation.Vehicle.Vee self.engage.Formation=Formation or ENUMS.Formation.Vehicle.Vee
@ -1844,7 +1937,7 @@ end
function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute) function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute)
-- Debug info. -- 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. -- Create coordinate.
local coordinate=self:_CoordinateFromObject(Coordinate) local coordinate=self:_CoordinateFromObject(Coordinate)
@ -1862,8 +1955,10 @@ function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation
elseif self.option.Formation then elseif self.option.Formation then
Formation = self.option.Formation Formation = self.option.Formation
else else
Formation = "On Road" -- Default formation is on road.
Formation = ENUMS.Formation.Vehicle.OnRoad
end end
self:T2(self.lid..string.format("Formation set to = %s", tostring(Formation)))
end end
-- Create a Ground waypoint. -- Create a Ground waypoint.

View File

@ -59,6 +59,7 @@
-- @field #number Nelements Number of elements (units) assigned to mission. -- @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 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 #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 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 conditionSuccess If all conditions are true, the mission is cancelled.
-- @field #table conditionFailure 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 orbitAltitude Orbit altitude in meters.
-- @field #number orbitHeading Orbit heading in degrees. -- @field #number orbitHeading Orbit heading in degrees.
-- @field #number orbitLeg Length of orbit leg in meters. -- @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 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. -- @field Ops.Operation#OPERATION operation Operation this mission is part of.
-- --
@ -624,7 +628,7 @@ AUFTRAG.Category={
--- AUFTRAG class version. --- AUFTRAG class version.
-- @field #string version -- @field #string version
AUFTRAG.version="0.9.6" AUFTRAG.version="0.9.7"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- 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: Replace engageRange by missionRange. Here and in other classes. CTRL+H is your friend!
-- TODO: Mission success options damaged, destroyed. -- TODO: Mission success options damaged, destroyed.
-- TODO: F10 marker to create new missions. -- 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: Added auftrag category.
-- DONE: Missions can be assigned to multiple legions. -- DONE: Missions can be assigned to multiple legions.
-- DONE: Option to assign a specific payload for the mission (requires an AIRWING). -- 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. --- **[AIR]** Create an ORBIT mission, which can be either a circular orbit or a race-track pattern.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param Core.Point#COORDINATE Coordinate Where to orbit. -- @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 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 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. -- @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) local mission=AUFTRAG:New(AUFTRAG.Type.ORBIT)
-- Altitude. -- Target.
mission:_TargetFromObject(Coordinate)
-- Set Altitude.
if Altitude then if Altitude then
mission.orbitAltitude=UTILS.FeetToMeters(Altitude) mission.orbitAltitude=UTILS.FeetToMeters(Altitude)
else else
mission.orbitAltitude=Coordinate.y mission.orbitAltitude=Coordinate.y
end 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) mission.missionSpeed = UTILS.KnotsToKmph(Speed or 350)
if Heading and Leg then if Leg then
mission.orbitHeading=Heading
mission.orbitLeg=UTILS.NMToMeters(Leg) 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 options:
mission.missionAltitude=mission.orbitAltitude*0.9 mission.missionAltitude=mission.orbitAltitude*0.9
@ -1093,6 +1107,53 @@ function AUFTRAG:NewORBIT_RACETRACK(Coordinate, Altitude, Speed, Heading, Leg)
return mission return mission
end 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 --- **[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. -- themselfs. They wait for the CHIEF to tell them whom to engage.
-- @param #AUFTRAG self -- @param #AUFTRAG self
@ -1631,25 +1692,45 @@ function AUFTRAG:NewRESCUEHELO(Carrier)
return mission return mission
end end
--- **[AIRPANE]** Create a RECOVERY TANKER mission. **WIP and not working coorectly yet!** --- **[AIRPANE]** Create a RECOVERY TANKER mission.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param Wrapper.Unit#UNIT Carrier The carrier unit. -- @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 -- @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 options:
mission.missionTask=ENUMS.MissionTask.REFUELING mission.missionTask=ENUMS.MissionTask.REFUELING
mission.missionFraction=0.5 mission.missionFraction=0.9
mission.optionROE=ENUMS.ROE.WeaponHold mission.optionROE=ENUMS.ROE.WeaponHold
mission.optionROT=ENUMS.ROT.NoReaction mission.optionROT=ENUMS.ROT.NoReaction
mission.missionAltitude=UTILS.FeetToMeters(6000)
mission.missionSpeed=UTILS.KnotsToKmph(274)
mission.categories={AUFTRAG.Category.AIRPLANE} mission.categories={AUFTRAG.Category.AIRPLANE}
mission.DCStask=mission:GetDCSMissionTask() mission.DCStask=mission:GetDCSMissionTask()
@ -4974,6 +5055,17 @@ function AUFTRAG:GetTargetCoordinate()
return nil return nil
end 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. --- Get name of the target.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @return #string Name of the target or "N/A". -- @return #string Name of the target or "N/A".
@ -5239,6 +5331,17 @@ function AUFTRAG:_SetLogID()
return self return self
end end
--- Update DCS task.
-- @param #AUFTRAG self
-- @return #AUFTRAG self
function AUFTRAG:_UpdateTask()
return self
end
--- Update mission F10 map marker. --- Update mission F10 map marker.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @return #AUFTRAG self -- @return #AUFTRAG self
@ -5412,47 +5515,6 @@ function AUFTRAG:GetDCSMissionTask()
table.insert(DCStasks, DCStask) 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 elseif self.type==AUFTRAG.Type.INTERCEPT then
----------------------- -----------------------
@ -5522,7 +5584,7 @@ function AUFTRAG:GetDCSMissionTask()
table.insert(DCStasks, DCStask) 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 -- -- TANKER Mission --
@ -5890,17 +5952,91 @@ function AUFTRAG:GetDCSMissionTask()
self.type==AUFTRAG.Type.CAS or self.type==AUFTRAG.Type.CAS or
self.type==AUFTRAG.Type.GCICAP or self.type==AUFTRAG.Type.GCICAP or
self.type==AUFTRAG.Type.AWACS 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 -- -- 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 end
@ -6087,6 +6223,8 @@ function AUFTRAG.CheckMissionCapabilityAll(MissionTypes, Capabilities)
return res return res
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -42,7 +42,8 @@
-- --
-- # The CHIEF Concept -- # 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 -- # Territory
-- --
@ -299,10 +300,14 @@ CHIEF.Strategy = {
-- @field Ops.OpsZone#OPSZONE opszone OPS zone. -- @field Ops.OpsZone#OPSZONE opszone OPS zone.
-- @field #number prio Priority. -- @field #number prio Priority.
-- @field #number importance Importance. -- @field #number importance Importance.
-- @field #table resourceEmpty Resource list. -- @field #CHIEF.Resources resourceEmpty List of resources employed when the zone is empty.
-- @field #table resourceOccup Resource list. -- @field #CHIEF.Resources resourceOccup List of resources employed when the zone is occupied by an enemy.
-- @field #table missions Mission. -- @field #table missions Mission.
--- Resource list.
-- @type CHIEF.Resources
-- @field <#CHIEF.Resource> List of resources.
--- Resource. --- Resource.
-- @type CHIEF.Resource -- @type CHIEF.Resource
-- @field #string MissionType Mission type, e.g. `AUFTRAG.Type.BAI`. -- @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 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 #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 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. --- CHIEF class version.
-- @field #string version -- @field #string version
CHIEF.version="0.4.0" CHIEF.version="0.5.1"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Let user specify amount of resources. -- TODO: PLAYERTASK integration.
-- DONE: Let user specify amount of resources.
-- DONE: Tactical overview. -- DONE: Tactical overview.
-- DONE: Add event for opsgroups on mission. -- DONE: Add event for opsgroups on mission.
-- DONE: Add event for zone captured. -- DONE: Add event for zone captured.
@ -736,44 +751,45 @@ end
-- @param #number Nmax Max number of requried assets. Default 1. -- @param #number Nmax Max number of requried assets. Default 1.
-- @param #table Attributes Generalized attribute(s). Default `nil`. -- @param #table Attributes Generalized attribute(s). Default `nil`.
-- @param #table Properties DCS 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) 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 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 #CHIEF self
-- @param #table Resource Resource table. -- @param #CHIEF.Resources Resource List of resources.
-- @param #string MissionType Mission Type. -- @param #string MissionType Mission Type.
-- @param #number Nmin Min number of required assets. -- @param #number Nmin Min number of required assets. Default 1.
-- @param #number Nmax Max number of requried assets. -- @param #number Nmax Max number of requried assets. Default equal `Nmin`.
-- @param #table Attributes Generalized attribute(s). -- @param #table Attributes Generalized attribute(s).
-- @param #table Properties DCS attribute(s). Default `nil`. -- @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) 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. -- Create new resource table.
local resource={} --#CHIEF.Resource local resource={} --#CHIEF.Resource
resource.MissionType=MissionType resource.MissionType=MissionType
resource.Nmin=Nmin or 1 resource.Nmin=Nmin or 1
resource.Nmax=Nmax or 1 resource.Nmax=Nmax or Nmin
resource.Attributes=Attributes or {} resource.Attributes=UTILS.EnsureTable(Attributes)
resource.Properties=Properties or {} 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. -- Add to table.
table.insert(Resource, resource) table.insert(Resource, resource)
@ -788,6 +804,32 @@ function CHIEF:AddToResource(Resource, MissionType, Nmin, Nmax, Attributes, Prop
self:I(self.lid..text) self:I(self.lid..text)
end 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 return self
end end
@ -1193,17 +1235,17 @@ end
-- --
-- Empty: -- 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.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. -- Resources can be created with the @{#CHIEF.CreateResource} and @{#CHIEF.AddToResource} functions.
-- --
-- @param #CHIEF self -- @param #CHIEF self
-- @param Ops.OpsZone#OPSZONE OpsZone OPS zone object. -- @param Ops.OpsZone#OPSZONE OpsZone OPS zone object.
-- @param #number Priority Priority. Default 50. -- @param #number Priority Priority. Default 50.
-- @param #number Importance Importance. Default nil. -- @param #number Importance Importance. Default `#nil`.
-- @param #CHIEF.Resource ResourceOccupied (Optional) Resources used then zone is occupied by the enemy. -- @param #CHIEF.Resources ResourceOccupied (Optional) Resources used then zone is occupied by the enemy.
-- @param #CHIEF.Resource ResourceEmpty (Optional) Resources used then zone is empty. -- @param #CHIEF.Resources ResourceEmpty (Optional) Resources used then zone is empty.
-- @return #CHIEF.StrategicZone The strategic zone. -- @return #CHIEF.StrategicZone The strategic zone.
function CHIEF:AddStrategicZone(OpsZone, Priority, Importance, ResourceOccupied, ResourceEmpty) function CHIEF:AddStrategicZone(OpsZone, Priority, Importance, ResourceOccupied, ResourceEmpty)
@ -1232,8 +1274,11 @@ function CHIEF:AddStrategicZone(OpsZone, Priority, Importance, ResourceOccupied,
if ResourceEmpty then if ResourceEmpty then
stratzone.resourceEmpty=UTILS.DeepCopy(ResourceEmpty) stratzone.resourceEmpty=UTILS.DeepCopy(ResourceEmpty)
else else
stratzone.resourceEmpty=self:CreateResource(AUFTRAG.Type.ONGUARD, 1, 3, GROUP.Attribute.GROUND_INFANTRY) local resourceEmpty, resourceInfantry=self:CreateResource(AUFTRAG.Type.ONGUARD, 1, 3, GROUP.Attribute.GROUND_INFANTRY)
self:AddToResource(stratzone.resourceEmpty, AUFTRAG.Type.ONGUARD, 1, 1, GROUP.Attribute.GROUND_TANK) 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 end
-- Add to table. -- Add to table.
@ -1438,7 +1483,7 @@ end
-- * Enemies in these zones will only be engaged if strategy is at least `CHIEF.STRATEGY.DEFENSIVE`. -- * Enemies in these zones will only be engaged if strategy is at least `CHIEF.STRATEGY.DEFENSIVE`.
-- --
-- @param #CHIEF self -- @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 -- @return #CHIEF self
function CHIEF:SetBorderZones(BorderZoneSet) 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`. -- * Enemies in these zones will only be engaged if strategy is at least `CHIEF.STRATEGY.DEFENSIVE`.
-- --
-- @param #CHIEF self -- @param #CHIEF self
-- @param Core.Zone#ZONE Zone The zone. -- @param Core.Zone#ZONE Zone The zone to be added.
-- @return #CHIEF self -- @return #CHIEF self
function CHIEF:AddBorderZone(Zone) function CHIEF:AddBorderZone(Zone)
@ -1464,6 +1509,18 @@ function CHIEF:AddBorderZone(Zone)
return self return self
end 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. --- Set conflict zone set.
-- --
-- * Detected enemy troops in these zones will trigger defence condition `YELLOW`. -- * 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`. -- * Enemies in these zones will only be engaged if strategy is at least `CHIEF.STRATEGY.OFFENSIVE`.
-- --
-- @param #CHIEF self -- @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 -- @return #CHIEF self
function CHIEF:AddConflictZone(Zone) function CHIEF:AddConflictZone(Zone)
@ -1496,6 +1553,19 @@ function CHIEF:AddConflictZone(Zone)
return self return self
end 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. --- Set attack zone set.
-- --
-- * Enemies in these zones will only be engaged if strategy is at least `CHIEF.STRATEGY.AGGRESSIVE`. -- * 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 return self
end 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 --- 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. -- if a destination can be reached on land.
-- @param #CHIEF self -- @param #CHIEF self
-- @return #CHIEF self -- @return #CHIEF self
function CHIEF:AllowGroundTransport() 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} self.TransportCategories = {Group.Category.GROUND, Group.Category.HELICOPTER}
return self return self
end end
@ -1539,6 +1622,7 @@ end
-- @param #CHIEF self -- @param #CHIEF self
-- @return #CHIEF self -- @return #CHIEF self
function CHIEF:ForbidGroundTransport() function CHIEF:ForbidGroundTransport()
env.warning("WARNING: CHIEF:ForbidGroundTransport() is depricated and will be removed in the future!")
self.TransportCategories = {Group.Category.HELICOPTER} self.TransportCategories = {Group.Category.HELICOPTER}
return self return self
end end
@ -2114,7 +2198,16 @@ function CHIEF:_TacticalOverview()
for _,_stratzone in pairs(self.zonequeue) do for _,_stratzone in pairs(self.zonequeue) do
local stratzone=_stratzone --#CHIEF.StrategicZone local stratzone=_stratzone --#CHIEF.StrategicZone
local owner=stratzone.opszone:GetOwnerName() 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 end
-- Message to coalition. -- Message to coalition.
@ -2867,9 +2960,36 @@ function CHIEF:RecruitAssetsForZone(StratZone, Resource)
-- Debug messgage. -- Debug messgage.
self:T2(self.lid..string.format("Recruited %d assets for %s mission STRATEGIC zone %s", #assets, MissionType, tostring(StratZone.opszone.zoneName))) 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 TargetZone = StratZone.opszone.zone
local TargetCoord = TargetZone:GetCoordinate() 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 if MissionType==AUFTRAG.Type.PATROLZONE or MissionType==AUFTRAG.Type.ONGUARD then
--- ---
@ -2879,47 +2999,15 @@ function CHIEF:RecruitAssetsForZone(StratZone, Resource)
-- Debug messgage. -- Debug messgage.
self:T2(self.lid..string.format("Recruited %d assets for PATROL mission", #assets)) self:T2(self.lid..string.format("Recruited %d assets for PATROL mission", #assets))
-- First check if we need a transportation. if MissionType==AUFTRAG.Type.PATROLZONE then
local recruitedTrans=true ; local transport=nil mission=AUFTRAG:NewPATROLZONE(TargetZone)
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)
elseif MissionType==AUFTRAG.Type.ONGUARD then
mission=AUFTRAG:NewONGUARD(TargetZone:GetRandomCoordinate(nil, nil, {land.SurfaceType.LAND}))
end end
if recruitedTrans then -- Engage detected targets.
mission:SetEngageDetected(25, {"Ground Units", "Light armed ships", "Helicopters"})
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
elseif MissionType==AUFTRAG.Type.CASENHANCED then elseif MissionType==AUFTRAG.Type.CASENHANCED then
@ -3043,6 +3131,15 @@ function CHIEF:RecruitAssetsForZone(StratZone, Resource)
-- Attach mission to resource. -- Attach mission to resource.
Resource.mission=mission 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 return true
else else
@ -3061,6 +3158,89 @@ function CHIEF:RecruitAssetsForZone(StratZone, Resource)
return false return false
end 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
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -210,7 +210,7 @@ FLIGHTGROUP.Players={}
--- FLIGHTGROUP class version. --- FLIGHTGROUP class version.
-- @field #string version -- @field #string version
FLIGHTGROUP.version="0.8.1" FLIGHTGROUP.version="0.8.2"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -899,6 +899,60 @@ function FLIGHTGROUP:Status()
end end
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 -- TODO: _CheckParking() function
@ -1157,16 +1211,6 @@ function FLIGHTGROUP:Status()
-- Current mission. -- Current mission.
local mission=self:GetMissionCurrent() 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 end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -499,7 +499,7 @@ OPSGROUP.CargoStatus={
--- OpsGroup version. --- OpsGroup version.
-- @field #string version -- @field #string version
OPSGROUP.version="0.7.9" OPSGROUP.version="0.8.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -4070,6 +4070,23 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
-- Get mission of this task (if any). -- Get mission of this task (if any).
local Mission=self:GetMissionByTaskID(self.taskcurrent) 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 if Task.dcstask.id==AUFTRAG.SpecialTask.FORMATION then
-- Set of group(s) to follow Mother. -- Set of group(s) to follow Mother.
@ -4421,13 +4438,6 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
-- Set quantity of task. -- Set quantity of task.
DCSTask.params.expendQty=nShots 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 else
--- ---
-- Take DCS task -- Take DCS task
@ -4435,38 +4445,7 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
DCSTask=Task.dcstask DCSTask=Task.dcstask
end end
local DCStasks={} self:_SandwitchDCSTask(DCSTask, Task)
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)
elseif Task.type==OPSGROUP.TaskType.WAYPOINT then elseif Task.type==OPSGROUP.TaskType.WAYPOINT then
-- Waypoint tasks are executed elsewhere! -- Waypoint tasks are executed elsewhere!
@ -4476,14 +4455,61 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
end 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
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. --- 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 #OPSGROUP self
-- @param #string From From state. -- @param #string From From state.
@ -5535,22 +5561,6 @@ function OPSGROUP:RouteToMission(mission, delay)
waypointcoord=currentcoord:GetIntermediateCoordinate(ToCoordinate, 0.05) waypointcoord=currentcoord:GetIntermediateCoordinate(ToCoordinate, 0.05)
end 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 else
--- ---
-- Default case -- Default case
@ -5642,18 +5652,33 @@ function OPSGROUP:RouteToMission(mission, delay)
end 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. -- Add mission execution (ingress) waypoint.
local waypoint=nil --#OPSGROUP.Waypoint local waypoint=nil --#OPSGROUP.Waypoint
if self:IsFlightgroup() then if self:IsFlightgroup() then
waypoint=FLIGHTGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false) waypoint=FLIGHTGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false)
elseif self:IsArmygroup() then elseif self:IsArmygroup() then
-- Set formation.
local formation=mission.optionFormation 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 formation=ENUMS.Formation.Vehicle.OffRoad
end end
waypoint=ARMYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, formation, false) waypoint=ARMYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, formation, false)
elseif self:IsNavygroup() then elseif self:IsNavygroup() then
waypoint=NAVYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false) waypoint=NAVYGROUP.AddWaypoint(self, waypointcoord, SpeedToMission, uid, UTILS.MetersToFeet(mission.missionAltitude or self.altitudeCruise), false)
end end
waypoint.missionUID=mission.auftragsnummer waypoint.missionUID=mission.auftragsnummer
@ -5682,13 +5707,6 @@ function OPSGROUP:RouteToMission(mission, delay)
mission:SetGroupEgressWaypointUID(self, Ewaypoint.uid) mission:SetGroupEgressWaypointUID(self, Ewaypoint.uid)
end 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. -- Check if we are already where we want to be.
if targetzone and self:IsInZone(targetzone) then if targetzone and self:IsInZone(targetzone) then
self:T(self.lid.."Already in mission zone ==> TaskExecute()") 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. -- Get a random coordinate in the pickup zone and let the carrier go there.
local Coordinate=Zone:GetRandomCoordinate(nil, nil, surfacetypes) 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. -- Current waypoint ID.
local uid=cwp and cwp.uid or nil local uid=self:GetWaypointCurrentUID()
-- Add waypoint. -- Add waypoint.
if self:IsFlightgroup() then if self:IsFlightgroup() then
@ -8546,8 +8560,6 @@ function OPSGROUP:onafterPickup(From, Event, To)
local coordinate=self:GetCoordinate():GetIntermediateCoordinate(Coordinate, 0.5) 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. -- 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 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) local path=self.cargoTransport:_GetPathTransport(self.category, self.cargoTZC)
-- Formation used to go to the pickup zone.. -- 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. -- Get transport path.
if path and oldstatus~=OPSGROUP.CarrierStatus.NOTCARRIER then 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 local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, uid, Formation, false) ; waypoint.detour=1
-- Give cruise command. -- Give cruise command.
self:__Cruise(-2) self:__Cruise(-2, nil, Formation)
end end
@ -8917,7 +8929,8 @@ function OPSGROUP:onafterTransport(From, Event, To)
-- Coord where the carrier goes to unload. -- Coord where the carrier goes to unload.
local Coordinate=Zone:GetRandomCoordinate(nil, nil, surfacetypes) --Core.Point#COORDINATE 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. -- Add waypoint.
if self:IsFlightgroup() then if self:IsFlightgroup() then
@ -8933,9 +8946,6 @@ function OPSGROUP:onafterTransport(From, Event, To)
-- Deploy at airbase -- Deploy at airbase
--- ---
local cwp=self:GetWaypointCurrent()
local uid=cwp and cwp.uid or nil
-- Get a (random) pre-defined transport path. -- Get a (random) pre-defined transport path.
local path=self.cargoTransport:_GetPathTransport(self.category, self.cargoTZC) 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) 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. -- 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 local waypoint=FLIGHTGROUP.AddWaypoint(self, coordinate, nil, uid, UTILS.MetersToFeet(self.altitudeCruise), true) ; waypoint.detour=1
end end
-- Order group to land at an airbase.
--self:__LandAtAirbase(-0.1, airbaseDeploy)
elseif self.isHelo then 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. -- 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 else
self:T(self.lid.."ERROR: Aircraft (cargo carrier) cannot land in Deploy zone! Specify a ZONE_AIRBASE as deploy zone") 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 elseif self:IsArmygroup() then
local cwp=self:GetWaypointCurrent()
local uid=cwp and cwp.uid or nil
-- Get transport path. -- Get transport path.
local path=self.cargoTransport:_GetPathTransport(self.category, self.cargoTZC) local path=self.cargoTransport:_GetPathTransport(self.category, self.cargoTZC)
-- Formation used for transporting. -- Formation used for transporting.
local Formation=self.cargoTransport:_GetFormationTransport(self.cargoTZC) local Formation=self.cargoTransport:_GetFormationTransport(self.cargoTZC, self)
-- Get transport path. -- Get transport path.
if path then 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 local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, uid, Formation, false) ; waypoint.detour=1
-- Give cruise command. -- Give cruise command.
self:Cruise() self:Cruise(nil, Formation)
elseif self:IsNavygroup() then elseif self:IsNavygroup() then
local cwp=self:GetWaypointCurrent()
local uid=cwp and cwp.uid or nil
-- Get a (random) pre-defined transport path. -- Get a (random) pre-defined transport path.
local path=self.cargoTransport:_GetPathTransport(self.category, self.cargoTZC) local path=self.cargoTransport:_GetPathTransport(self.category, self.cargoTZC)
@ -9434,7 +9433,7 @@ function OPSGROUP:onafterDelivered(From, Event, To, CargoTransport)
end end
else else
-- Army & Navy: give Cruise command to "wake up" from waiting status. -- Army & Navy: give Cruise command to "wake up" from waiting status.
self:__Cruise(0.1) self:__Cruise(-0.1)
end end
-- Set carrier transport status. -- Set carrier transport status.
@ -9859,14 +9858,14 @@ function OPSGROUP:_CheckGroupDone(delay)
if delay and delay>0 then if delay and delay>0 then
-- Debug info. -- 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. -- Delayed call.
self:ScheduleOnce(delay, self._CheckGroupDone, self) self:ScheduleOnce(delay, self._CheckGroupDone, self)
else else
-- Debug info. -- 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. -- Group is engaging something.
if self:IsEngaging() then if self:IsEngaging() then
@ -10646,7 +10645,7 @@ function OPSGROUP._PassingWaypoint(opsgroup, uid)
-- Set formation. -- Set formation.
if opsgroup.isArmygroup then if opsgroup.isArmygroup then
opsgroup.formation=wpnext.action opsgroup.option.Formation=wpnext.action
end end
-- Set speed to next wp. -- Set speed to next wp.

View File

@ -50,6 +50,10 @@
-- @field #number NcarrierDead Total number of dead carrier groups -- @field #number NcarrierDead Total number of dead carrier groups
-- @field #number NcargoDead Totalnumber of dead cargo 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 Ops.Auftrag#AUFTRAG mission The mission attached to this transport.
-- @field #table assets Warehouse assets assigned for this transport. -- @field #table assets Warehouse assets assigned for this transport.
-- @field #table legions Assigned legions. -- @field #table legions Assigned legions.
@ -191,7 +195,7 @@ _OPSTRANSPORTID=0
--- Army Group version. --- Army Group version.
-- @field #string version -- @field #string version
OPSTRANSPORT.version="0.6.0" OPSTRANSPORT.version="0.6.1"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -235,6 +239,10 @@ function OPSTRANSPORT:New(CargoGroups, PickupZone, DeployZone)
self:SetTime() self:SetTime()
self:SetRequiredCarriers() self:SetRequiredCarriers()
self.formationArmy=ENUMS.Formation.Vehicle.OnRoad
self.formationHelo=ENUMS.Formation.RotaryWing.Wedge
self.formationPlane=ENUMS.Formation.FixedWing.Wedge
-- Init arrays and counters. -- Init arrays and counters.
self.carriers={} self.carriers={}
self.Ncargo=0 self.Ncargo=0
@ -809,16 +817,44 @@ function OPSTRANSPORT:SetFormationPickup(Formation, TransportZoneCombo)
return self return self
end 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. --- Get pickup formation.
-- @param #OPSTRANSPORT self -- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo. -- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @param Ops.OpsGroup#OPSGROUP OpsGroup
-- @return #number Formation. -- @return #number Formation.
function OPSTRANSPORT:_GetFormationPickup(TransportZoneCombo) function OPSTRANSPORT:_GetFormationPickup(TransportZoneCombo, OpsGroup)
-- Use default TZC if no transport zone combo is provided. -- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.PickupFormation local formation=TransportZoneCombo.PickupFormation or self:_GetFormationDefault(OpsGroup)
return formation
end end
--- Set transport formation. --- Set transport formation.
@ -839,13 +875,16 @@ end
--- Get transport formation. --- Get transport formation.
-- @param #OPSTRANSPORT self -- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo. -- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @param Ops.OpsGroup#OPSGROUP OpsGroup
-- @return #number Formation. -- @return #number Formation.
function OPSTRANSPORT:_GetFormationTransport(TransportZoneCombo) function OPSTRANSPORT:_GetFormationTransport(TransportZoneCombo, OpsGroup)
-- Use default TZC if no transport zone combo is provided. -- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.TransportFormation local formation=TransportZoneCombo.TransportFormation or self:_GetFormationDefault(OpsGroup)
return formation
end end

View File

@ -641,10 +641,8 @@ function OPSZONE:onafterStop(From, Event, To)
-- Reinit the timer. -- Reinit the timer.
self.timerStatus:Stop() self.timerStatus:Stop()
-- Draw zone. -- Undraw zone.
if self.drawZone then self.zone:UndrawZone()
self.zone:UndrawZone()
end
-- Remove marker. -- Remove marker.
if self.markZone then if self.markZone then
@ -691,6 +689,11 @@ function OPSZONE:Status()
-- Update F10 marker (only if enabled). -- Update F10 marker (only if enabled).
self:_UpdateMarker() self:_UpdateMarker()
-- Undraw zone.
if self.zone.DrawID and not self.drawZone then
self.zone:UndrawZone()
end
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -151,7 +151,7 @@ _TARGETID=0
--- TARGET class version. --- TARGET class version.
-- @field #string version -- @field #string version
TARGET.version="0.5.5" TARGET.version="0.5.6"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -1108,7 +1108,7 @@ function TARGET:GetTargetLife(Target)
return self return self
end end
--- Get current life points. --- Get current total life points. This is the sum of all target objects.
-- @param #TARGET self -- @param #TARGET self
-- @return #number Life points of target. -- @return #number Life points of target.
function TARGET:GetLife() function TARGET:GetLife()
@ -1311,6 +1311,89 @@ function TARGET:GetTargetVec3(Target, Average)
self:E(self.lid.."ERROR: Unknown TARGET type! Cannot get Vec3") self:E(self.lid.."ERROR: Unknown TARGET type! Cannot get Vec3")
end 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. --- Get target coordinate.
-- @param #TARGET self -- @param #TARGET self
@ -1473,7 +1556,7 @@ function TARGET:GetAverageCoordinate()
for _,_target in pairs(self.targets) do for _,_target in pairs(self.targets) do
local Target=_target --#TARGET.Object local Target=_target --#TARGET.Object
local coordinate=self:GetTargetCoordinate(Target,true) local coordinate=self:GetTargetCoordinate(Target, true)
if coordinate then if coordinate then
return coordinate return coordinate
@ -1485,6 +1568,26 @@ function TARGET:GetAverageCoordinate()
return nil return nil
end 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. --- Get category.
-- @param #TARGET self -- @param #TARGET self
-- @return #string Target category. See `TARGET.Category.X`, where `X=AIRCRAFT, GROUND`. -- @return #string Target category. See `TARGET.Category.X`, where `X=AIRCRAFT, GROUND`.
@ -1492,6 +1595,7 @@ function TARGET:GetCategory()
return self.category return self.category
end end
--- Get target category. --- Get target category.
-- @param #TARGET self -- @param #TARGET self
-- @param #TARGET.Object Target Target object. -- @param #TARGET.Object Target Target object.

View File

@ -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. --- (AIR) Orbit at a position with at a given altitude and speed. Optionally, a race track pattern can be specified.
-- @param #CONTROLLABLE self -- @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 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 #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. -- @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 Pattern = AI.Task.OrbitPattern.CIRCLE
local P1 = Coord:GetVec2() local P1 = {x=Coord.x, y=Coord.z or Coord.y}
local P2 = nil local P2 = nil
if CoordRaceTrack then if CoordRaceTrack then
Pattern = AI.Task.OrbitPattern.RACE_TRACK Pattern = AI.Task.OrbitPattern.RACE_TRACK
P2 = CoordRaceTrack:GetVec2() P2 = {x=CoordRaceTrack.x, y=CoordRaceTrack.z or CoordRaceTrack.y}
end end
local Task = { local Task = {