From 62725b1930ef445ece9b370ed9259fa97796cf2d Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 23 May 2022 23:11:23 +0200 Subject: [PATCH] OPS **AUFTRAG** - Added *invisible* and *immortal* options **TARGET** - Added `AddResource` function **OPSGROUP** - Added *invisible* and *immortal* options **LEGION** - Fixed bug in properties requirement **COMMANDER** - Added `AddTarget` function (still **WIP**) **ARMYGROUP** - Fixed routing bug after teleporting --- Moose Development/Moose/Ops/ArmyGroup.lua | 15 +- Moose Development/Moose/Ops/Auftrag.lua | 41 ++++- Moose Development/Moose/Ops/Commander.lua | 143 +++++++++++++++++ Moose Development/Moose/Ops/FlightGroup.lua | 8 +- Moose Development/Moose/Ops/Legion.lua | 8 +- Moose Development/Moose/Ops/NavyGroup.lua | 13 +- Moose Development/Moose/Ops/OpsGroup.lua | 160 +++++++++++++++++--- Moose Development/Moose/Ops/OpsZone.lua | 34 ++++- Moose Development/Moose/Ops/Target.lua | 58 +++++++ 9 files changed, 448 insertions(+), 32 deletions(-) diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index 35ba2606f..7102a7aa0 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -63,7 +63,7 @@ ARMYGROUP = { --- Army Group version. -- @field #string version -ARMYGROUP.version="0.7.3" +ARMYGROUP.version="0.7.9" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -880,6 +880,12 @@ function ARMYGROUP:onafterSpawned(From, Event, To) -- Set default EPLRS. self:SwitchEPLRS(self.option.EPLRS) + + -- Set default Invisible. + self:SwitchInvisible(self.option.Invisible) + + -- Set default Immortal. + self:SwitchImmortal(self.option.Immortal) -- Set TACAN to default. self:_SwitchTACAN() @@ -943,6 +949,9 @@ function ARMYGROUP:onbeforeUpdateRoute(From, Event, To, n, N, Speed, Formation) elseif self:IsHolding() then self:T(self.lid.."Update route denied. Group is holding position!") return false + elseif self:IsEngaging() then + self:T(self.lid.."Update route allowed. Group is engaging!") + return true end -- Check for a current task. @@ -960,7 +969,7 @@ function ARMYGROUP:onbeforeUpdateRoute(From, Event, To, n, N, Speed, Formation) self:T2(self.lid.."Allowing update route for Task: ReconMission") elseif task.dcstask.id==AUFTRAG.SpecialTask.RELOCATECOHORT then -- For relocate - self:T2(self.lid.."Allowing update route for Task: Relocate Cohort") + self:T2(self.lid.."Allowing update route for Task: Relocate Cohort") else local taskname=task and task.description or "No description" self:T(self.lid..string.format("WARNING: Update route denied because taskcurrent=%d>0! Task description = %s", self.taskcurrent, tostring(taskname))) @@ -1117,7 +1126,7 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation) self.speedWp=wp.speed -- Debug output. - if self.verbose>=10 then + if self.verbose>=10 or true then for i,_wp in pairs(waypoints) do local wp=_wp --Ops.OpsGroup#OPSGROUP.Waypoint diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index a1e46b10b..2361a21d5 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -111,6 +111,9 @@ -- @field #number artyAngle Shooting angle in degrees (for Barrage). -- -- @field #string alert5MissionType Alert 5 mission type. This is the mission type, the alerted assets will be able to carry out. +-- +-- @field #table attributes Generalized attribute(s) of assets. +-- @field #table properties DCS attribute(s) of assets. -- -- @field Ops.Chief#CHIEF chief The CHIEF managing this mission. -- @field Ops.Commander#COMMANDER commander The COMMANDER managing this mission. @@ -168,6 +171,8 @@ -- @field #number optionRTBfuel RTB on out-of-fuel. -- @field #number optionECM ECM. -- @field #boolean optionEmission Emission is on or off. +-- @field #boolean optionInvisible Invisible is on/off. +-- @field #boolean optionImmortal Immortal is on/off. -- -- @extends Core.Fsm#FSM @@ -1763,7 +1768,7 @@ end --- **[GROUND, NAVAL]** Create an ARTY mission. -- @param #AUFTRAG self -- @param Core.Point#COORDINATE Target Center of the firing solution. --- @param #number Nshots Number of shots to be fired. Default 3. +-- @param #number Nshots Number of shots to be fired. Default `#nil`. -- @param #number Radius Radius of the shells in meters. Default 100 meters. -- @param #number Altitude Altitude in meters. Can be used to setup a Barrage. Default `#nil`. -- @return #AUFTRAG self @@ -2196,7 +2201,9 @@ function AUFTRAG:NewFromTarget(Target, MissionType) elseif MissionType==AUFTRAG.Type.STRIKE then mission=self:NewSTRIKE(Target, Altitude) elseif MissionType==AUFTRAG.Type.ARMORATTACK then - mission=self:NewARMORATTACK(Target,Speed) + mission=self:NewARMORATTACK(Target, Speed) + elseif MissionType==AUFTRAG.Type.GROUNDATTACK then + mission=self:NewGROUNDATTACK(Target, Speed, Formation) else return nil end @@ -2970,6 +2977,36 @@ function AUFTRAG:SetEmission(OnOffSwitch) return self end +--- Set invisibility setting for this mission. +-- @param #AUFTRAG self +-- @param #boolean OnOffSwitch If `true` or `nil`, invisible is on. If `false`, invisible is off. +-- @return #AUFTRAG self +function AUFTRAG:SetInvisible(OnOffSwitch) + + if OnOffSwitch==nil then + self.optionInvisible=true + else + self.optionInvisible=OnOffSwitch + end + + return self +end + +--- Set immortality setting for this mission. +-- @param #AUFTRAG self +-- @param #boolean OnOffSwitch If `true` or `nil`, immortal is on. If `false`, immortal is off. +-- @return #AUFTRAG self +function AUFTRAG:SetImmortal(OnOffSwitch) + + if OnOffSwitch==nil then + self.optionImmortal=true + else + self.optionImmortal=OnOffSwitch + end + + return self +end + --- Set formation for this mission. -- @param #AUFTRAG self -- @param #number Formation Formation. diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index 5049e05e9..0ec0e9886 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -24,6 +24,7 @@ -- @field #table legions Table of legions which are commanded. -- @field #table missionqueue Mission queue. -- @field #table transportqueue Transport queue. +-- @field #table targetqueue Target queue. -- @field #table rearmingZones Rearming zones. Each element is of type `#BRIGADE.SupplyZone`. -- @field #table refuellingZones Refuelling zones. Each element is of type `#BRIGADE.SupplyZone`. -- @field #table capZones CAP zones. Each element is of type `#AIRWING.PatrolZone`. @@ -125,6 +126,7 @@ COMMANDER = { legions = {}, missionqueue = {}, transportqueue = {}, + targetqueue = {}, rearmingZones = {}, refuellingZones = {}, capZones = {}, @@ -514,6 +516,55 @@ function COMMANDER:RemoveTransport(Transport) return self end +--- Add target. +-- @param #COMMANDER self +-- @param Ops.Target#TARGET Target Target object to be added. +-- @return #COMMANDER self +function COMMANDER:AddTarget(Target) + + if not self:IsTarget(Target) then + table.insert(self.targetqueue, Target) + end + + return self +end + +--- Check if a TARGET is already in the queue. +-- @param #COMMANDER self +-- @param Ops.Target#TARGET Target Target object to be added. +-- @return #boolean If `true`, target exists in the target queue. +function COMMANDER:IsTarget(Target) + + for _,_target in pairs(self.targetqueue) do + local target=_target --Ops.Target#TARGET + if target.uid==Target.uid or target:GetName()==Target:GetName() then + return true + end + end + + return false +end + +--- Remove target from queue. +-- @param #COMMANDER self +-- @param Ops.Target#TARGET Target The target. +-- @return #COMMANDER self +function COMMANDER:RemoveTarget(Target) + + for i,_target in pairs(self.targetqueue) do + local target=_target --Ops.Target#TARGET + + if target.uid==Target.uid then + self:T(self.lid..string.format("Removing target %s from queue", Target.name)) + table.remove(self.targetqueue, i) + break + end + + end + + return self +end + --- Add a rearming zone. -- @param #COMMANDER self -- @param Core.Zone#ZONE RearmingZone Rearming zone. @@ -789,6 +840,9 @@ function COMMANDER:onafterStatus(From, Event, To) local text=string.format("Status %s: Legions=%d, Missions=%d, Transports", fsmstate, #self.legions, #self.missionqueue, #self.transportqueue) self:T(self.lid..text) end + + -- Check target queue and add missions. + self:CheckTargetQueue() -- Check mission queue and assign one PLANNED mission. self:CheckMissionQueue() @@ -1148,6 +1202,95 @@ end -- Mission Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- Check target queue and assign ONE valid target by adding it to the mission queue of the COMMANDER. +-- @param #COMMANDER self +function COMMANDER:CheckTargetQueue() + + -- Number of missions. + local Ntargets=#self.targetqueue + + -- Treat special cases. + if Ntargets==0 then + return nil + end + + -- Check if total number of missions is reached. + local NoLimit=self:_CheckMissionLimit("Total") + if NoLimit==false then + return nil + end + + -- Sort results table wrt prio and threatlevel. + local function _sort(a, b) + local taskA=a --Ops.Target#TARGET + local taskB=b --Ops.Target#TARGET + return (taskA.priotaskB.threatlevel0) + end + table.sort(self.targetqueue, _sort) + + -- Get the lowest importance value (lower means more important). + -- If a target with importance 1 exists, targets with importance 2 will not be assigned. Targets with no importance (nil) can still be selected. + local vip=math.huge + for _,_target in pairs(self.targetqueue) do + local target=_target --Ops.Target#TARGET + if target:IsAlive() and target.importance and target.importance Creating mission type %s: Nmin=%d, Nmax=%d", target:GetName(), missionType, resource.Nmin, resource.Nmax)) + + -- Create a mission. + local mission=AUFTRAG:NewFromTarget(target, missionType) + + if mission then + mission:SetRequiredAssets(resource.Nmin, resource.Nmax) + mission:SetRequiredAttribute(resource.Attributes) + mission:SetRequiredProperty(resource.Properties) + + resource.mission=mission + + -- Add mission to queue. + self:AddMission(resource.mission) + + end + + end + + end + + end + end + +end + + --- Check mission queue and assign ONE planned mission. -- @param #COMMANDER self function COMMANDER:CheckMissionQueue() diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 50f9116fa..f94433a41 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -183,7 +183,7 @@ FLIGHTGROUP.RadioMessage = { --- FLIGHTGROUP class version. -- @field #string version -FLIGHTGROUP.version="0.7.3" +FLIGHTGROUP.version="0.7.9" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -1549,6 +1549,12 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To) -- Set default EPLRS. self:SwitchEPLRS(self.option.EPLRS) + + -- Set default Invisible. + self:SwitchInvisible(self.option.Invisible) + + -- Set default Immortal. + self:SwitchImmortal(self.option.Immortal) -- Set Formation self:SwitchFormation(self.option.Formation) diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index 66888cb66..b0076b4f7 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -2246,7 +2246,7 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, local cohort=_cohort --Ops.Cohort#COHORT if Properties and #Properties>0 then for _,Property in pairs(Properties) do - for _,property in pairs(cohort.properties) do + for property,value in pairs(cohort.properties) do if Property==property then return true end @@ -2277,8 +2277,8 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, else return true end - end - + end + -- Loops over cohorts. for _,_cohort in pairs(Cohorts) do local cohort=_cohort --Ops.Cohort#COHORT @@ -2329,7 +2329,7 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, end -- Debug info. - cohort:T2(cohort.lid..string.format("State=%s: Capable=%s, InRange=%s, Refuel=%s, CanCarry=%s, Category=%s, Attribute=%s, Property=%s, Weapon=%s", + cohort:I(cohort.lid..string.format("State=%s: Capable=%s, InRange=%s, Refuel=%s, CanCarry=%s, Category=%s, Attribute=%s, Property=%s, Weapon=%s", cohort:GetState(), tostring(Capable), tostring(InRange), tostring(Refuel), tostring(CanCarry), tostring(RightCategory), tostring(RightAttribute), tostring(RightProperty), tostring(RightWeapon))) -- Check OnDuty, capable, in range and refueling type (if TANKER). diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index f0d5268e0..f0ca112df 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -90,7 +90,7 @@ NAVYGROUP = { --- NavyGroup version. -- @field #string version -NAVYGROUP.version="0.7.3" +NAVYGROUP.version="0.7.9" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -987,8 +987,17 @@ function NAVYGROUP:onafterSpawned(From, Event, To) -- Set default Alarm State. self:SwitchAlarmstate(self.option.Alarm) + -- Set emission. + self:SwitchEmission(self.option.Emission) + -- Set default EPLRS. - self:SwitchEPLRS(self.option.EPLRS) + self:SwitchEPLRS(self.option.EPLRS) + + -- Set default Invisible. + self:SwitchInvisible(self.option.Invisible) + + -- Set default Immortal. + self:SwitchImmortal(self.option.Immortal) -- Set TACAN beacon. self:_SwitchTACAN() diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index ebbfdf6ef..181c371b0 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -308,6 +308,18 @@ OPSGROUP.TaskType={ -- @field Core.UserFlag#USERFLAG stopflag If flag is set to 1 (=true), the task is stopped. -- @field #number backupROE Rules of engagement that are restored once the task is over. +--- Option data. +-- @type OPSGROUP.Option +-- @field #number ROE Rule of engagement. +-- @field #number ROT Reaction on threat. +-- @field #number Alarm Alarm state. +-- @field #number Formation Formation. +-- @field #boolean EPLRS data link. +-- @field #boolean Disperse Disperse under fire. +-- @field #boolean Emission Emission on/off. +-- @field #boolean Invisible Invisible on/off. +-- @field #boolean Immortal Immortal on/off. + --- Beacon data. -- @type OPSGROUP.Beacon -- @field #number Channel Channel. @@ -329,16 +341,6 @@ OPSGROUP.TaskType={ -- @field #number NumberGroup Group number. First number after name, e.g. "Uzi-**1**-1". -- @field #string NameSquad Name of the squad, e.g. "Uzi". ---- Option data. --- @type OPSGROUP.Option --- @field #number ROE Rule of engagement. --- @field #number ROT Reaction on threat. --- @field #number Alarm Alarm state. --- @field #number Formation Formation. --- @field #boolean EPLRS data link. --- @field #boolean Disperse Disperse under fire. --- @field #boolean Emission Emission on/off. - --- Weapon range data. -- @type OPSGROUP.WeaponData -- @field #number BitType Type of weapon. @@ -469,21 +471,21 @@ OPSGROUP.CargoStatus={ --- OpsGroup version. -- @field #string version -OPSGROUP.version="0.7.8" +OPSGROUP.version="0.7.9" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO: AI on/off. --- TODO: Emission on/off. --- TODO: Invisible/immortal. -- TODO: F10 menu. -- TODO: Add pseudo function. -- TODO: Afterburner restrict. -- TODO: What more options? -- TODO: Shot events? -- TODO: Marks to add waypoints/tasks on-the-fly. +-- DONE: Invisible/immortal. +-- DONE: Emission on/off -- DONE: Damage? -- DONE: Options EPLRS @@ -4997,6 +4999,14 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission) if Mission.optionEmission then self:SwitchEmission() end + -- Invisible to default. + if Mission.optionInvisible then + self:SwitchInvisible() + end + -- Immortal to default. + if Mission.optionImmortal then + self:SwitchImmortal() + end -- Formation to default. if Mission.optionFormation and self:IsFlightgroup() then self:SwitchFormation() @@ -5103,9 +5113,13 @@ function OPSGROUP:RouteToMission(mission, delay) self:MissionExecute(mission) return end + + if self.speedMax<=3.6 or mission.teleport then + --self:ClearWaypoints() + end -- ID of current waypoint. - local uid=self:GetWaypointCurrent().uid + local uid=self:GetWaypointCurrentUID() -- Ingress waypoint coordinate where the mission is executed. local waypointcoord=nil --Core.Point#COORDINATE @@ -5113,6 +5127,8 @@ function OPSGROUP:RouteToMission(mission, delay) -- Current coordinate of the group. local currentcoord=self:GetCoordinate() + currentcoord:MarkToAll(mission:GetName(),ReadOnly,Text) + -- Road connection. local roadcoord=currentcoord:GetClosestPointToRoad() @@ -5173,6 +5189,7 @@ function OPSGROUP:RouteToMission(mission, delay) -- Random coordinate. waypointcoord=targetzone:GetRandomCoordinate(nil , nil, surfacetypes) + waypointcoord:MarkToAll(mission:GetName(),ReadOnly,Text) elseif mission.type==AUFTRAG.Type.ONGUARD or mission.type==AUFTRAG.Type.ARMOREDGUARD then --- -- Guard @@ -5237,7 +5254,7 @@ function OPSGROUP:RouteToMission(mission, delay) waypointcoord=CarrierCoordinate:Translate(10000, heading-180):SetAltitude(2000) - waypointcoord:MarkToAll("Recoverytanker",ReadOnly,Text) + waypointcoord:MarkToAll("Recoverytanker") else --- @@ -5466,9 +5483,17 @@ function OPSGROUP:_SetMissionOptions(mission) self:SwitchEPLRS(mission.optionEPLRS) end -- Emission - if mission.optionEPLRS then + if mission.optionEmission then self:SwitchEmission(mission.optionEmission) - end + end + -- Invisible + if mission.optionInvisible then + self:SwitchInvisible(mission.optionInvisible) + end + -- Immortal + if mission.optionImmortal then + self:SwitchImmortal(mission.optionImmortal) + end -- Formation if mission.optionFormation and self:IsFlightgroup() then self:SwitchFormation(mission.optionFormation) @@ -6762,6 +6787,10 @@ function OPSGROUP:Teleport(Coordinate, Delay, NoPauseMission) -- Set waypoint in air for flighgroups. if self:IsFlightgroup() then Template.route.points[1]=Coordinate:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, 300, true, nil, nil, "Spawnpoint") + elseif self:IsArmygroup() then + Template.route.points[1]=Coordinate:WaypointGround() + elseif self:IsNavygroup() then + Template.route.points[1]=Coordinate:WaypointNaval() end -- Template units. @@ -10790,6 +10819,103 @@ function OPSGROUP:GetEmission() return self.option.Emission or self.optionDefault.Emission end +--- Set the default invisible for the group. +-- @param #OPSGROUP self +-- @param #boolean OnOffSwitch If `true`, group is ivisible by default. +-- @return #OPSGROUP self +function OPSGROUP:SetDefaultInvisible(OnOffSwitch) + + if OnOffSwitch==nil then + self.optionDefault.Invisible=true + else + self.optionDefault.Invisible=OnOffSwitch + end + + return self +end + +--- Switch invisibility on or off. +-- @param #OPSGROUP self +-- @param #boolean OnOffSwitch If `true` or `nil`, switch invisibliity on. If `false` invisibility switched off. +-- @return #OPSGROUP self +function OPSGROUP:SwitchInvisible(OnOffSwitch) + + if self:IsAlive() or self:IsInUtero() then + + if OnOffSwitch==nil then + + self.option.Invisible=self.optionDefault.Invisible + + else + + self.option.Invisible=OnOffSwitch + + end + + if self:IsInUtero() then + self:T2(self.lid..string.format("Setting current INVISIBLE=%s when GROUP is SPAWNED", tostring(self.option.Invisible))) + else + + self.group:SetCommandInvisible(self.option.Invisible) + self:T(self.lid..string.format("Setting current INVISIBLE=%s", tostring(self.option.Invisible))) + + end + else + self:E(self.lid.."WARNING: Cannot switch Invisible! Group is not alive") + end + + return self +end + + +--- Set the default immortal for the group. +-- @param #OPSGROUP self +-- @param #boolean OnOffSwitch If `true`, group is immortal by default. +-- @return #OPSGROUP self +function OPSGROUP:SetDefaultImmortal(OnOffSwitch) + + if OnOffSwitch==nil then + self.optionDefault.Immortal=true + else + self.optionDefault.Immortal=OnOffSwitch + end + + return self +end + +--- Switch immortality on or off. +-- @param #OPSGROUP self +-- @param #boolean OnOffSwitch If `true` or `nil`, switch immortality on. If `false` immortality switched off. +-- @return #OPSGROUP self +function OPSGROUP:SwitchImmortal(OnOffSwitch) + + if self:IsAlive() or self:IsInUtero() then + + if OnOffSwitch==nil then + + self.option.Immortal=self.optionDefault.Immortal + + else + + self.option.Immortal=OnOffSwitch + + end + + if self:IsInUtero() then + self:T2(self.lid..string.format("Setting current IMMORTAL=%s when GROUP is SPAWNED", tostring(self.option.Immortal))) + else + + self.group:SetCommandImmortal(self.option.Immortal) + self:T(self.lid..string.format("Setting current IMMORTAL=%s", tostring(self.option.Immortal))) + + end + else + self:E(self.lid.."WARNING: Cannot switch Immortal! Group is not alive") + end + + return self +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- SETTINGS FUNCTIONS ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Ops/OpsZone.lua b/Moose Development/Moose/Ops/OpsZone.lua index 8e1a79068..ce8f3227b 100644 --- a/Moose Development/Moose/Ops/OpsZone.lua +++ b/Moose Development/Moose/Ops/OpsZone.lua @@ -2,8 +2,9 @@ -- -- **Main Features:** -- --- * Monitor if a zone is captured. --- * Monitor if an airbase is captured. +-- * Monitor if a zone is captured +-- * Monitor if an airbase is captured +-- * Define conditions under which zones are captured/held -- -- === -- @@ -79,6 +80,7 @@ OPSZONE.version="0.3.0" -- ToDo list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- TODO: Capturing based on (total) threat level threshold. Unarmed units do not pose a threat and should not be able to hold a zone. -- TODO: Pause/unpause evaluations. -- TODO: Capture time, i.e. time how long a single coalition has to be inside the zone to capture it. -- TODO: Differentiate between ground attack and boming by air or arty. @@ -348,7 +350,7 @@ end --- Set categories of units that can capture or hold the zone. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). -- @param #OPSZONE self -- @param #table Categories Table of unit categories. Default `{Unit.Category.GROUND_UNIT}`. --- @return #OPSZONE +-- @return #OPSZONE self function OPSZONE:SetUnitCategories(Categories) -- Ensure table. @@ -362,6 +364,32 @@ function OPSZONE:SetUnitCategories(Categories) return self end +--- Set threat level threshold that the defending units must have to hold a zone. +-- The reason why you might want to set this is that unarmed units (*e.g.* fuel trucks) should not be able to hold a zone as they do not pose a threat. +-- @param #OPSZONE self +-- @param #number Threatlevel Threat level threshod. Default 0. +-- @return #OPSZONE self +function OPSZONE:SetThreatlevelDefinding(Threatlevel) + + self.threatlevelDefending=Threatlevel or 0 + + return self +end + + +--- Set threat level threshold that the offending units must have to capture a zone. +-- The reason why you might want to set this is that unarmed units (*e.g.* fuel trucks) should not be able to capture a zone as they do not pose a threat. +-- @param #OPSZONE self +-- @param #number Threatlevel Threat level threshod. Default 0. +-- @return #OPSZONE self +function OPSZONE:SetThreatlevelOffending(Threatlevel) + + self.threatlevelOffending=Threatlevel or 0 + + return self +end + + --- Set whether *neutral* units can capture the zone. -- @param #OPSZONE self -- @param #boolean CanCapture If `true`, neutral units can. diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index e06e7df43..faba46a41 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -36,6 +36,7 @@ -- @field Ops.Auftrag#AUFTRAG mission Mission attached to this target. -- @field Ops.Intelligence#INTEL.Contact contact Contact attached to this target. -- @field #boolean isDestroyed If true, target objects were destroyed. +-- @field #table resources Resource list. -- @extends Core.Fsm#FSM --- **It is far more important to be able to hit the target than it is to haggle over who makes a weapon or who pulls a trigger** -- Dwight D Eisenhower @@ -113,6 +114,16 @@ TARGET.ObjectStatus={ ALIVE="Alive", DEAD="Dead", } + +--- Resource. +-- @type TARGET.Resource +-- @field #string MissionType Mission type, e.g. `AUFTRAG.Type.BAI`. +-- @field #number Nmin Min number of assets. +-- @field #number Nmax Max number of assets. +-- @field #table Attributes Generalized attribute, e.g. `{GROUP.Attribute.GROUND_INFANTRY}`. +-- @field #table Properties Properties ([DCS attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes)), e.g. `"Attack helicopters"` or `"Mobile AAA"`. +-- @field Ops.Auftrag#AUFTRAG mission Attached mission. + --- Target object. -- @type TARGET.Object -- @field #number ID Target unique ID. @@ -307,6 +318,53 @@ function TARGET:SetImportance(Importance) return self end +--- Add mission type and number of required assets to resource. +-- @param #TARGET self +-- @param #string MissionType Mission Type. +-- @param #number Nmin Min number of required assets. +-- @param #number Nmax Max number of requried assets. +-- @param #table Attributes Generalized attribute(s). +-- @param #table Properties DCS attribute(s). Default `nil`. +-- @return #TARGET.Resource The resource table. +function TARGET:AddResource(MissionType, Nmin, Nmax, Attributes, Properties) + + -- Ensure table. + if Attributes and type(Attributes)~="table" then + Attributes={Attributes} + end + + -- Ensure table. + if Properties and type(Properties)~="table" then + Properties={Properties} + end + + -- Create new resource table. + local resource={} --#TARGET.Resource + resource.MissionType=MissionType + resource.Nmin=Nmin or 1 + resource.Nmax=Nmax or 1 + resource.Attributes=Attributes or {} + resource.Properties=Properties or {} + + -- Init resource table. + self.resources=self.resources or {} + + -- Add to table. + table.insert(self.resources, resource) + + -- Debug output. + if self.verbose>10 then + local text="Resource:" + for _,_r in pairs(self.resources) do + local r=_r --#TARGET.Resource + text=text..string.format("\nmission=%s, Nmin=%d, Nmax=%d, attribute=%s, properties=%s", r.MissionType, r.Nmin, r.Nmax, tostring(r.Attributes[1]), tostring(r.Properties[1])) + end + self:I(self.lid..text) + end + + return resource +end + --- Check if TARGET is alive. -- @param #TARGET self -- @return #boolean If true, target is alive.