diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index 3c5a9d193..f4d8194a2 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -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 diff --git a/Moose Development/Moose/Ops/Brigade.lua b/Moose Development/Moose/Ops/Brigade.lua index 70d5505cd..77d0b2948 100644 --- a/Moose Development/Moose/Ops/Brigade.lua +++ b/Moose Development/Moose/Ops/Brigade.lua @@ -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 diff --git a/Moose Development/Moose/Ops/Cohort.lua b/Moose Development/Moose/Ops/Cohort.lua index fdd4aa811..afc15c1ee 100644 --- a/Moose Development/Moose/Ops/Cohort.lua +++ b/Moose Development/Moose/Ops/Cohort.lua @@ -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 diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index a01333e08..33d508e8e 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -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 diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index 4e59e5151..762800ccf 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -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 diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index ca2230f8c..e4414fd86 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -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 diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 1f31accd0..010470b21 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -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