This commit is contained in:
Frank 2021-08-25 17:20:17 +02:00
parent 259b201e65
commit 1e6899c40b
9 changed files with 289 additions and 229 deletions

View File

@ -1187,11 +1187,6 @@ function ARMYGROUP:_InitGroup(Template)
-- Get template of group.
local template=Template or self:_GetTemplate()
-- Define category.
self.isAircraft=false
self.isNaval=false
self.isGround=true
-- Ground are always AI.
self.isAI=true
@ -1243,21 +1238,8 @@ function ARMYGROUP:_InitGroup(Template)
self:_AddElementByName(unit:GetName())
end
-- Get first unit. This is used to extract other parameters.
local unit=units[1] --Wrapper.Unit#UNIT
if unit then
-- Get Descriptors.
self.descriptors=unit:GetDesc()
-- Set type name.
self.actype=unit:GetTypeName()
-- Init done.
self.groupinitialized=true
end
-- Init done.
self.groupinitialized=true
return self
end

View File

@ -16,7 +16,6 @@
-- @type BRIGADE
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @field Ops.General#GENERAL general The genral responsible for this brigade.
-- @extends Ops.Legion#LEGION
--- Be surprised!
@ -31,8 +30,7 @@
-- @field #BRIGADE
BRIGADE = {
ClassName = "BRIGADE",
verbose = 3,
genral = nil,
verbose = 0,
}
@ -44,7 +42,7 @@ BRIGADE.version="0.0.1"
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot!
-- TODO: Add weapon range.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
@ -89,13 +87,13 @@ function BRIGADE:AddPlatoon(Platoon)
-- Add platoon to brigade.
table.insert(self.cohorts, Platoon)
-- Add assets to squadron.
-- Add assets to platoon.
self:AddAssetToPlatoon(Platoon, Platoon.Ngroups)
-- Set airwing to squadron.
-- Set brigade of platoon.
Platoon:SetBrigade(self)
-- Start squadron.
-- Start platoon.
if Platoon:IsStopped() then
Platoon:Start()
end
@ -114,7 +112,7 @@ function BRIGADE:AddAssetToPlatoon(Platoon, Nassets)
if Platoon then
-- Get the template group of the squadron.
-- Get the template group of the platoon.
local Group=GROUP:FindByName(Platoon.templatename)
if Group then
@ -131,7 +129,7 @@ function BRIGADE:AddAssetToPlatoon(Platoon, Nassets)
end
else
self:E(self.lid.."ERROR: Squadron does not exit!")
self:E(self.lid.."ERROR: Platoon does not exit!")
end
return self
@ -148,20 +146,20 @@ end
--- Get platoon of an asset.
-- @param #BRIGADE self
-- @param Ops.Warehouse#WAREHOUSE.Assetitem Asset The platoon asset.
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The platoon asset.
-- @return Ops.Platoon#PLATOON The platoon object.
function BRIGADE:GetPlatoonOfAsset(Asset)
local platoon=self:GetPlatoon(Asset.squadname)
return platoon
end
--- Remove asset from squadron.
--- Remove asset from platoon.
-- @param #BRIGADE self
-- @param #BRIGADE.SquadronAsset Asset The squad asset.
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The platoon asset.
function BRIGADE:RemoveAssetFromPlatoon(Asset)
local squad=self:GetPlatoonOfAsset(Asset)
if squad then
squad:DelAsset(Asset)
local platoon=self:GetPlatoonOfAsset(Asset)
if platoon then
platoon:DelAsset(Asset)
end
end
@ -188,9 +186,8 @@ function BRIGADE:onafterStatus(From, Event, To)
-- Status of parent Warehouse.
self:GetParent(self).onafterStatus(self, From, Event, To)
-- FSM state.
local fsmstate=self:GetState()
env.info("FF Brigade status "..fsmstate)
-- General info:
if self.verbose>=1 then
@ -198,13 +195,14 @@ function BRIGADE:onafterStatus(From, Event, To)
-- Count missions not over yet.
local Nmissions=self:CountMissionsInQueue()
-- Assets tot
-- Asset count.
local Npq, Np, Nq=self:CountAssetsOnMission()
local assets=string.format("%d (OnMission: Total=%d, Active=%d, Queued=%d)", self:CountAssets(), Npq, Np, Nq)
-- Asset string.
local assets=string.format("%d [OnMission: Total=%d, Active=%d, Queued=%d]", self:CountAssets(), Npq, Np, Nq)
-- Output.
local text=string.format("%s: Missions=%d, Squads=%d, Assets=%s", fsmstate, Nmissions, #self.cohorts, assets)
local text=string.format("%s: Missions=%d, Platoons=%d, Assets=%s", fsmstate, Nmissions, #self.cohorts, assets)
self:I(self.lid..text)
end
@ -226,19 +224,19 @@ function BRIGADE:onafterStatus(From, Event, To)
end
-------------------
-- Squadron Info --
-- Platoon Info --
-------------------
if self.verbose>=3 then
local text="Platoons:"
for i,_squadron in pairs(self.cohorts) do
local squadron=_squadron --Ops.Squadron#SQUADRON
for i,_platoon in pairs(self.cohorts) do
local platoon=_platoon --Ops.Platoon#PLATOON
local callsign=squadron.callsignName and UTILS.GetCallsignName(squadron.callsignName) or "N/A"
local modex=squadron.modex and squadron.modex or -1
local skill=squadron.skill and tostring(squadron.skill) or "N/A"
local callsign=platoon.callsignName and UTILS.GetCallsignName(platoon.callsignName) or "N/A"
local modex=platoon.modex and platoon.modex or -1
local skill=platoon.skill and tostring(platoon.skill) or "N/A"
-- Squadron text
text=text..string.format("\n* %s %s: %s*%d/%d, Callsign=%s, Modex=%d, Skill=%s", squadron.name, squadron:GetState(), squadron.aircrafttype, squadron:CountAssets(true), #squadron.assets, callsign, modex, skill)
-- Platoon text.
text=text..string.format("\n* %s %s: %s*%d/%d, Callsign=%s, Modex=%d, Skill=%s", platoon.name, platoon:GetState(), platoon.aircrafttype, platoon:CountAssets(true), #platoon.assets, callsign, modex, skill)
end
self:I(self.lid..text)
end

View File

@ -783,109 +783,115 @@ end
function COHORT:RecruitAssets(Mission, Npayloads)
-- Number of payloads available.
Npayloads=Npayloads or self.legion:CountPayloadsInStock(Mission.type, self.aircrafttype, Mission.payloads)
Npayloads=Npayloads or self.legion:CountPayloadsInStock(Mission.type, self.aircrafttype, Mission.payloads)
-- Recruited assets.
local assets={}
-- Loop over assets.
for _,_asset in pairs(self.assets) do
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
-- First check that asset is not requested. This could happen if multiple requests are processed simultaniously.
if not asset.requested then
-- Check if asset is currently on a mission (STARTED or QUEUED).
if self.legion:IsAssetOnMission(asset) then
---
-- Asset is already on a mission.
---
-- Check if this asset is currently on a GCICAP mission (STARTED or EXECUTING).
if self.legion:IsAssetOnMission(asset, AUFTRAG.Type.GCICAP) and Mission.type==AUFTRAG.Type.INTERCEPT then
-- Check if the payload of this asset is compatible with the mission.
-- Note: we do not check the payload as an asset that is on a GCICAP mission should be able to do an INTERCEPT as well!
self:I(self.lid.."Adding asset on GCICAP mission for an INTERCEPT mission")
table.insert(assets, asset)
end
else
---
-- Asset as NO current mission
---
if asset.spawned then
---
-- Asset is already SPAWNED (could be uncontrolled on the airfield or inbound after another mission)
---
local flightgroup=asset.flightgroup
-- Firstly, check if it has the right payload.
if self:CheckMissionCapability(Mission.type, asset.payload.capabilities) and flightgroup and flightgroup:IsAlive() then
-- Assume we are ready and check if any condition tells us we are not.
local combatready=true
-- Check if asset is currently on a mission (STARTED or QUEUED).
if self.legion:IsAssetOnMission(asset) then
if Mission.type==AUFTRAG.Type.INTERCEPT then
combatready=flightgroup:CanAirToAir()
else
local excludeguns=Mission.type==AUFTRAG.Type.BOMBING or Mission.type==AUFTRAG.Type.BOMBRUNWAY or Mission.type==AUFTRAG.Type.BOMBCARPET or Mission.type==AUFTRAG.Type.SEAD or Mission.type==AUFTRAG.Type.ANTISHIP
combatready=flightgroup:CanAirToGround(excludeguns)
end
---
-- Asset is already on a mission.
---
-- Check if this asset is currently on a GCICAP mission (STARTED or EXECUTING).
if self.legion:IsAssetOnMission(asset, AUFTRAG.Type.GCICAP) and Mission.type==AUFTRAG.Type.INTERCEPT then
-- Check if the payload of this asset is compatible with the mission.
-- Note: we do not check the payload as an asset that is on a GCICAP mission should be able to do an INTERCEPT as well!
self:I(self.lid.."Adding asset on GCICAP mission for an INTERCEPT mission")
table.insert(assets, asset)
-- No more attacks if fuel is already low. Safety first!
if flightgroup:IsFuelLow() then
combatready=false
end
-- Check if in a state where we really do not want to fight any more.
if flightgroup:IsFlightgroup() then
if flightgroup:IsHolding() or flightgroup:IsLanding() or flightgroup:IsLanded() or flightgroup:IsArrived() then
combatready=false
end
else
if flightgroup:IsRearming() or flightgroup:IsRetreating() or flightgroup:IsReturning() then
combatready=false
end
end
-- Applies to all opsgroups.
if flightgroup:IsDead() or flightgroup:IsStopped() then
combatready=false
end
--TODO: Check transport for combat readyness!
end
-- This asset is "combatready".
if combatready then
self:I(self.lid.."Adding SPAWNED asset to ANOTHER mission as it is COMBATREADY")
table.insert(assets, asset)
end
end
else
---
-- Asset is still in STOCK
---
-- Check that asset is not already requested for another mission.
if Npayloads>0 and self:IsRepaired(asset) and (not asset.requested) then
-- Add this asset to the selection.
table.insert(assets, asset)
-- Reduce number of payloads so we only return the number of assets that could do the job.
Npayloads=Npayloads-1
end
-- Asset as NO current mission
---
if asset.spawned then
end
end
---
-- Asset is already SPAWNED (could be uncontrolled on the airfield or inbound after another mission)
---
local flightgroup=asset.flightgroup
-- Firstly, check if it has the right payload.
if self:CheckMissionCapability(Mission.type, asset.payload.capabilities) and flightgroup and flightgroup:IsAlive() then
-- Assume we are ready and check if any condition tells us we are not.
local combatready=true
if Mission.type==AUFTRAG.Type.INTERCEPT then
combatready=flightgroup:CanAirToAir()
else
local excludeguns=Mission.type==AUFTRAG.Type.BOMBING or Mission.type==AUFTRAG.Type.BOMBRUNWAY or Mission.type==AUFTRAG.Type.BOMBCARPET or Mission.type==AUFTRAG.Type.SEAD or Mission.type==AUFTRAG.Type.ANTISHIP
combatready=flightgroup:CanAirToGround(excludeguns)
end
-- No more attacks if fuel is already low. Safety first!
if flightgroup:IsFuelLow() then
combatready=false
end
-- Check if in a state where we really do not want to fight any more.
if flightgroup:IsFlightgroup() then
if flightgroup:IsHolding() or flightgroup:IsLanding() or flightgroup:IsLanded() or flightgroup:IsArrived() then
combatready=false
end
else
if flightgroup:IsRearming() or flightgroup:IsRetreating() or flightgroup:IsReturning() then
combatready=false
end
end
-- Applies to all opsgroups.
if flightgroup:IsDead() or flightgroup:IsStopped() then
combatready=false
end
--TODO: Check transport for combat readyness!
-- This asset is "combatready".
if combatready then
self:I(self.lid.."Adding SPAWNED asset to ANOTHER mission as it is COMBATREADY")
table.insert(assets, asset)
end
end
else
---
-- Asset is still in STOCK
---
-- Check that we have payloads and asset is repaired.
if Npayloads>0 and self:IsRepaired(asset) then
-- Add this asset to the selection.
table.insert(assets, asset)
-- Reduce number of payloads so we only return the number of assets that could do the job.
Npayloads=Npayloads-1
end
end
end
end -- not requested check
end -- loop over assets
return assets

View File

@ -2612,7 +2612,11 @@ function FLIGHTGROUP:onafterWait(From, Event, To, Duration, Altitude, Speed)
local Coord=self.group:GetCoordinate()
-- Set altitude: 1000 ft for helos and 10,000 ft for panes.
Altitude=Altitude or (self.isHelo and 1000 or 10000)
if Altitude then
Altitude=UTILS.FeetToMeters(Altitude)
else
Altitude=self.altitudeCruise
end
-- Set speed.
Speed=Speed or (self.isHelo and 20 or 250)
@ -2624,7 +2628,7 @@ function FLIGHTGROUP:onafterWait(From, Event, To, Duration, Altitude, Speed)
--TODO: set ROE passive. introduce roe event/state/variable.
-- Orbit until flaghold=1 (true) but max 5 min if no FC is giving the landing clearance.
local TaskOrbit = self.group:TaskOrbit(Coord, UTILS.FeetToMeters(Altitude), UTILS.KnotsToMps(Speed))
local TaskOrbit = self.group:TaskOrbit(Coord, Altitude, UTILS.KnotsToMps(Speed))
local TaskStop = self.group:TaskCondition(nil, nil, nil, nil, Duration)
local TaskCntr = self.group:TaskControlled(TaskOrbit, TaskStop)
local TaskOver = self.group:TaskFunction("FLIGHTGROUP._FinishedWaiting", self)
@ -3022,7 +3026,7 @@ function FLIGHTGROUP._FinishedWaiting(group, flightgroup)
flightgroup.Twaiting=nil
flightgroup.dTwait=nil
-- Trigger Holding event.
-- Check group done.
flightgroup:_CheckGroupDone(0.1)
end
@ -3048,11 +3052,6 @@ function FLIGHTGROUP:_InitGroup(Template)
-- Get template of group.
local template=Template or self:_GetTemplate()
-- Define category.
self.isAircraft=true
self.isNaval=false
self.isGround=false
-- Helo group.
self.isHelo=group:IsHelicopter()
@ -3130,32 +3129,9 @@ function FLIGHTGROUP:_InitGroup(Template)
self:_AddElementByName(unit:GetName())
end
-- Get first unit. This is used to extract other parameters.
local unit=units[1] --Wrapper.Unit#UNIT
if unit then
self.rangemax=unit:GetRange()
self.descriptors=unit:GetDesc()
self.actype=unit:GetTypeName()
self.ceiling=self.descriptors.Hmax
self.tankertype=select(2, unit:IsTanker())
self.refueltype=select(2, unit:IsRefuelable())
--env.info("DCS Unit BOOM_AND_RECEPTACLE="..tostring(Unit.RefuelingSystem.BOOM_AND_RECEPTACLE))
--env.info("DCS Unit PROBE_AND_DROGUE="..tostring(Unit.RefuelingSystem.PROBE_AND_DROGUE))
-- Init done.
self.groupinitialized=true
-- Init done.
self.groupinitialized=true
else
self:E(self.lid.."ERROR: no unit in _InigGroup!")
end
return self
end

View File

@ -1164,25 +1164,54 @@ end
function LEGION:_CreateFlightGroup(asset)
-- Create flightgroup.
local flightgroup=nil --Ops.OpsGroup#OPSGROUP
local opsgroup=nil --Ops.OpsGroup#OPSGROUP
if self:IsAirwing() then
flightgroup=FLIGHTGROUP:New(asset.spawngroupname)
---
-- FLIGHTGROUP
---
opsgroup=FLIGHTGROUP:New(asset.spawngroupname)
elseif self:IsBrigade() then
flightgroup=ARMYGROUP:New(asset.spawngroupname)
---
-- ARMYGROUP
---
opsgroup=ARMYGROUP:New(asset.spawngroupname)
else
self:E(self.lid.."ERROR: not airwing or brigade!")
end
-- Set legion.
flightgroup:_SetLegion(self)
opsgroup:_SetLegion(self)
-- Set cohort.
flightgroup.cohort=self:_GetCohortOfAsset(asset)
opsgroup.cohort=self:_GetCohortOfAsset(asset)
-- Set home base.
flightgroup.homebase=self.airbase
opsgroup.homebase=self.airbase
return flightgroup
-- Set weapon data.
if opsgroup.cohort.weaponData then
local text="Weapon data for group:"
opsgroup.weaponData=opsgroup.weaponData or {}
for bittype,_weapondata in pairs(opsgroup.cohort.weaponData) do
local weapondata=_weapondata --Ops.OpsGroup#OPSGROUP.WeaponData
opsgroup.weaponData[bittype]=UTILS.DeepCopy(weapondata) -- Careful with the units.
text=text..string.format("\n- Bit=%s: Rmin=%.1f km, Rmax=%.1f km", bittype, weapondata.RangeMin/1000, weapondata.RangeMax/1000)
end
self:T3(self.lid..text)
end
return opsgroup
end

View File

@ -1142,11 +1142,6 @@ function NAVYGROUP:_InitGroup(Template)
-- Get template of group.
local template=Template or self:_GetTemplate()
-- Define category.
self.isAircraft=false
self.isNaval=true
self.isGround=false
--TODO: Submarine check
--self.isSubmarine=self.group:IsSubmarine()
@ -1202,21 +1197,8 @@ function NAVYGROUP:_InitGroup(Template)
self:_AddElementByName(unit:GetName())
end
-- Get first unit. This is used to extract other parameters.
local unit=units[1] --Wrapper.Unit#UNIT
if unit then
-- Get Descriptors.
self.descriptors=unit:GetDesc()
-- Set type name.
self.actype=unit:GetTypeName()
-- Init done.
self.groupinitialized=true
end
-- Init done.
self.groupinitialized=true
return self
end

View File

@ -20,18 +20,16 @@
-- @field Wrapper.Group#GROUP group Group object.
-- @field DCS#Controller controller The DCS controller of the group.
-- @field DCS#Template template Template table of the group.
-- @field #table elements Table of elements, i.e. units of the group.
-- @field #boolean isLateActivated Is the group late activated.
-- @field #boolean isUncontrolled Is the group uncontrolled.
-- @field #boolean isFlightgroup Is a FLIGHTGROUP.
-- @field #boolean isArmygroup Is an ARMYGROUP.
-- @field #boolean isNavygroup Is a NAVYGROUP.
-- @field #boolean isHelo If true, the is a helicopter group.
-- @field #boolean isVTOL If true, the is capable of Vertical TakeOff and Landing (VTOL).
-- @field #table elements Table of elements, i.e. units of the group.
-- @field #boolean isHelo If true, this is a helicopter group.
-- @field #boolean isVTOL If true, this is capable of Vertical TakeOff and Landing (VTOL).
-- @field #boolean isSubmarine If true, this is a submarine group.
-- @field #boolean isAI If true, group is purely AI.
-- @field #boolean isAircraft If true, group is airplane or helicopter.
-- @field #boolean isNaval If true, group is ships or submarine.
-- @field #boolean isGround If true, group is some ground unit.
-- @field #boolean isDestroyed If true, the whole group was destroyed.
-- @field #boolean isDead If true, the whole group is dead.
-- @field #table waypoints Table of waypoints.
@ -504,6 +502,7 @@ function OPSGROUP:New(group)
-- Set some string id for output to DCS.log file.
self.lid=string.format("OPSGROUP %s | ", tostring(self.groupname))
-- Check if group exists.
if self.group then
if not self:IsExist() then
self:E(self.lid.."ERROR: GROUP does not exist! Returning nil")
@ -517,6 +516,34 @@ function OPSGROUP:New(group)
-- Set DCS group and controller.
self.dcsgroup=self:GetDCSGroup()
self.controller=self.dcsgroup:getController()
local units=self.group:GetUnits()
if units then
local masterunit=units[1] --Wrapper.Unit#UNIT
-- Get Descriptors.
self.descriptors=masterunit:GetDesc()
-- Set type name.
self.actype=masterunit:GetTypeName()
if self:IsFlightgroup() then
self.rangemax=masterunit:GetRange()
self.descriptors=masterunit:GetDesc()
self.ceiling=self.descriptors.Hmax
self.tankertype=select(2, masterunit:IsTanker())
self.refueltype=select(2, masterunit:IsRefuelable())
--env.info("DCS Unit BOOM_AND_RECEPTACLE="..tostring(Unit.RefuelingSystem.BOOM_AND_RECEPTACLE))
--env.info("DCS Unit PROBE_AND_DROGUE="..tostring(Unit.RefuelingSystem.PROBE_AND_DROGUE))
end
end
-- Init set of detected units.
self.detectedunits=SET_UNIT:New()
@ -876,7 +903,7 @@ function OPSGROUP:AddWeaponRange(RangeMin, RangeMax, BitType)
weapon.RangeMin=RangeMin
self.weaponData=self.weaponData or {}
self.weaponData[weapon.BitType]=weapon
self.weaponData[tostring(weapon.BitType)]=weapon
return self
end
@ -887,12 +914,12 @@ end
-- @return #OPSGROUP.WeaponData Weapon range data.
function OPSGROUP:GetWeaponData(BitType)
BitType=BitType or ENUMS.WeaponFlag.Auto
BitType=tostring(BitType or ENUMS.WeaponFlag.Auto)
if self.weaponData[BitType] then
return self.weaponData[BitType]
else
return self.weaponData[ENUMS.WeaponFlag.Auto]
return self.weaponData[tostring(ENUMS.WeaponFlag.Auto)]
end
end
@ -3937,7 +3964,7 @@ function OPSGROUP:RouteToMission(mission, delay)
end
elseif mission.type==AUFTRAG.Type.ARTY then
-- Get weapon range.
local weapondata=self:GetWeaponData(mission.engageWeaponType)
@ -3959,8 +3986,9 @@ function OPSGROUP:RouteToMission(mission, delay)
-- New waypoint coord.
waypointcoord=self:GetCoordinate():Translate(d, heading)
self:T(self.lid..string.format("Out of max range = %.1f km for weapon %d", weapondata.RangeMax/1000, mission.engageWeaponType))
-- Debug info.
self:T(self.lid..string.format("Out of max range = %.1f km for weapon %s", weapondata.RangeMax/1000, tostring(mission.engageWeaponType)))
elseif dist<weapondata.RangeMin then
local d=(dist-weapondata.RangeMin)*1.1
@ -3968,15 +3996,18 @@ function OPSGROUP:RouteToMission(mission, delay)
-- New waypoint coord.
waypointcoord=self:GetCoordinate():Translate(d, heading)
self:T(self.lid..string.format("Out of min range = %.1f km for weapon %d", weapondata.RangeMax/1000, mission.engageWeaponType))
-- Debug info.
self:T(self.lid..string.format("Out of min range = %.1f km for weapon %s", weapondata.RangeMax/1000, tostring(mission.engageWeaponType)))
end
else
self:T(self.lid..string.format("No weapon data for weapon type %s", tostring(mission.engageWeaponType)))
end
end
-- Formation.
local formation=nil
if self.isGround and mission.optionFormation then
if self.isArmygroup and mission.optionFormation then
formation=mission.optionFormation
end
@ -4526,7 +4557,7 @@ function OPSGROUP:onbeforeLaserOn(From, Event, To, Target)
-- Height offset. No offset for aircraft. We take the height for ground or naval.
local offsetY=0
if self.isGround or self.isNaval then
if self.isFlightgroup or self.isNavygroup then
offsetY=element.height
end
@ -6288,7 +6319,7 @@ function OPSGROUP:onafterPickup(From, Event, To)
end
-- 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, 200, false) ; waypoint.detour=1
local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid, self.altitudeCruise, false) ; waypoint.detour=1
else
self:E(self.lid.."ERROR: Carrier aircraft cannot land in Pickup zone! Specify a ZONE_AIRBASE as pickup zone")
@ -6660,7 +6691,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, 200, false) ; waypoint.detour=1
local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid, self.altitudeCruise, false) ; waypoint.detour=1
-- Cancel landedAt task. This should trigger Cruise once airborne.
if self:IsFlightgroup() and self:IsLandedAt() then
@ -7870,14 +7901,20 @@ function OPSGROUP:Route(waypoints, delay)
if self:IsAlive() then
-- Clear all DCS tasks.
-- Clear all DCS tasks. NOTE: This can make DCS crash!
--self:ClearTasks()
-- Route (Mission) task.
local TaskRoute=self.group:TaskRoute(waypoints)
-- DCS mission task.
local DCSTask = {
id = 'Mission',
params = {
airborne = self:IsFlightgroup(),
route={points=waypoints},
},
}
-- Set mission task.
self:SetTask(TaskRoute)
self:SetTask(DCSTask)
else
self:E(self.lid.."ERROR: Group is not alive! Cannot route group.")
@ -7965,7 +8002,7 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
opsgroup:T(opsgroup.lid..string.format("Next waypoint UID=%d index=%d", wpnext.uid, opsgroup:GetWaypointIndex(wpnext.uid)))
-- Set formation.
if opsgroup.isGround then
if opsgroup.isArmygroup then
opsgroup.formation=wpnext.action
end
@ -8733,7 +8770,7 @@ function OPSGROUP:SwitchFormation(Formation)
self.group:SetOption(AI.Option.Air.id.FORMATION, Formation)
elseif self.isGround then
elseif self.isArmygroup then
-- Polymorphic and overwritten in ARMYGROUP.
@ -9684,6 +9721,38 @@ function OPSGROUP:_IsElement(unitname)
return false
end
--- Count elements of the group.
-- @param #OPSGROUP self
-- @param #table States (Optional) Only count elements in specific states. Can also be a single state passed as #string.
-- @return #number Number of elements.
function OPSGROUP:CountElements(States)
if States then
if type(States)=="string" then
States={States}
end
else
States=OPSGROUP.ElementStatus
end
local IncludeDeads=true
local N=0
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
if element and (IncludeDeads or element.status~=OPSGROUP.ElementStatus.DEAD) then
for _,state in pairs(States) do
if element.status==state then
N=N+1
break
end
end
end
end
return N
end
--- Add a unit/element to the OPS group.
-- @param #OPSGROUP self
-- @param #string unitname Name of unit.

View File

@ -46,7 +46,7 @@ PLATOON.version="0.0.1"
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot!
-- TODO: Add weapon data.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
@ -60,7 +60,7 @@ PLATOON.version="0.0.1"
-- @return #PLATOON self
function PLATOON:New(TemplateGroupName, Ngroups, PlatoonName)
-- Inherit everything from FSM class.
-- Inherit everything from COHORT class.
local self=BASE:Inherit(self, COHORT:New(TemplateGroupName, Ngroups, PlatoonName)) -- #PLATOON
@ -107,7 +107,17 @@ function PLATOON:AddWeaponRange(RangeMin, RangeMax, BitType)
weapon.RangeMin=RangeMin
self.weaponData=self.weaponData or {}
self.weaponData[weapon.BitType]=weapon
self.weaponData[tostring(weapon.BitType)]=weapon
-- Debug info.
env.info(string.format("FF Adding weapon data: Bit=%s, Rmin=%d m, Rmax=%d m", tostring(weapon.BitType), weapon.RangeMin, weapon.RangeMax))
local text="Weapon data:"
for _,_weapondata in pairs(self.weaponData) do
local weapondata=_weapondata
text=text..string.format("\n- Bit=%s, Rmin=%d m, Rmax=%d m", tostring(weapondata.BitType), weapondata.RangeMin, weapondata.RangeMax)
end
self:I(self.lid..text)
return self
end
@ -150,8 +160,8 @@ function PLATOON:onafterStatus(From, Event, To)
local NassetsTot=#self.assets
local NassetsInS=self:CountAssets(true)
local NassetsQP=0 ; local NassetsP=0 ; local NassetsQ=0
if self.brigade then
NassetsQP, NassetsP, NassetsQ=self.brigade:CountAssetsOnMission(nil, self)
if self.legion then
NassetsQP, NassetsP, NassetsQ=self.legion:CountAssetsOnMission(nil, self)
end
-- Short info.
@ -159,6 +169,16 @@ function PLATOON:onafterStatus(From, Event, To)
fsmstate, self.aircrafttype, callsign, modex, skill, NassetsTot, NassetsInS, NassetsQP, NassetsP, NassetsQ)
self:I(self.lid..text)
-- Weapon data info.
if self.weaponData then
local text="Weapon Data:"
for bit,_weapondata in pairs(self.weaponData) do
local weapondata=_weapondata --Ops.OpsGroup#OPSGROUP.WeaponData
text=text..string.format("\n- Bit=%s: Rmin=%.1f km, Rmax=%.1f km", bit, weapondata.RangeMin/1000, weapondata.RangeMax/1000)
end
self:I(self.lid..text)
end
-- Check if group has detected any units.
self:_CheckAssetStatus()

View File

@ -2022,22 +2022,20 @@ do -- Patrol methods
end
--- Return a Misson task to follow a given route defined by Points.
--- Return a "Misson" task to follow a given route defined by Points.
-- @param #CONTROLLABLE self
-- @param #table Points A table of route points.
-- @return DCS#Task
-- @return DCS#Task DCS mission task. Has entries `.id="Mission"`, `params`, were params has entries `airborne` and `route`, which is a table of `points`.
function CONTROLLABLE:TaskRoute( Points )
self:F2( Points )
local DCSTask = {
id = 'Mission',
params = {
airborne = self:IsAir(),
airborne = self:IsAir(), -- This is important to make aircraft land without respawning them (which was a long standing DCS issue).
route = {points = Points},
},
}
self:T3( { DCSTask } )
return DCSTask
end