mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
OPS
CHIEF - Added option to customize reaction on strategic zones AUFTRAG - Added new type GROUNDATTACK
This commit is contained in:
parent
e8303064b9
commit
c5a50d23b6
@ -5453,57 +5453,63 @@ end
|
||||
-- @param #WAREHOUSE.Pendingitem request The request of the dead asset.
|
||||
function WAREHOUSE:onafterAssetDead(From, Event, To, asset, request)
|
||||
|
||||
-- Debug message.
|
||||
local text=string.format("Asset %s from request id=%d is dead!", asset.templatename, request.uid)
|
||||
self:T(self.lid..text)
|
||||
if asset and request then
|
||||
|
||||
-- Here I need to get rid of the #CARGO at the end to obtain the original name again!
|
||||
local groupname=asset.spawngroupname --self:_GetNameWithOut(group)
|
||||
|
||||
-- Dont trigger a Remove event for the group sets.
|
||||
local NoTriggerEvent=true
|
||||
|
||||
if request.transporttype==WAREHOUSE.TransportType.SELFPROPELLED then
|
||||
|
||||
---
|
||||
-- Easy case: Group can simply be removed from the cargogroupset.
|
||||
---
|
||||
|
||||
-- Remove dead group from cargo group set.
|
||||
request.cargogroupset:Remove(groupname, NoTriggerEvent)
|
||||
self:T(self.lid..string.format("Removed selfpropelled cargo %s: ncargo=%d.", groupname, request.cargogroupset:Count()))
|
||||
|
||||
else
|
||||
|
||||
---
|
||||
-- Complicated case: Dead unit could be:
|
||||
-- 1.) A Cargo unit (e.g. waiting to be picked up).
|
||||
-- 2.) A Transport unit which itself holds cargo groups.
|
||||
---
|
||||
|
||||
-- Check if this a cargo or transport group.
|
||||
local istransport=not asset.iscargo --self:_GroupIsTransport(group, request)
|
||||
|
||||
if istransport==true then
|
||||
|
||||
-- Whole carrier group is dead. Remove it from the carrier group set.
|
||||
request.transportgroupset:Remove(groupname, NoTriggerEvent)
|
||||
self:T(self.lid..string.format("Removed transport %s: ntransport=%d", groupname, request.transportgroupset:Count()))
|
||||
|
||||
elseif istransport==false then
|
||||
|
||||
-- This must have been an alive cargo group that was killed outside the carrier, e.g. waiting to be transported or waiting to be put back.
|
||||
-- Debug message.
|
||||
local text=string.format("Asset %s from request id=%d is dead!", asset.templatename, request.uid)
|
||||
self:T(self.lid..text)
|
||||
|
||||
-- Here I need to get rid of the #CARGO at the end to obtain the original name again!
|
||||
local groupname=asset.spawngroupname --self:_GetNameWithOut(group)
|
||||
|
||||
-- Dont trigger a Remove event for the group sets.
|
||||
local NoTriggerEvent=true
|
||||
|
||||
if request.transporttype==WAREHOUSE.TransportType.SELFPROPELLED then
|
||||
|
||||
---
|
||||
-- Easy case: Group can simply be removed from the cargogroupset.
|
||||
---
|
||||
|
||||
-- Remove dead group from cargo group set.
|
||||
request.cargogroupset:Remove(groupname, NoTriggerEvent)
|
||||
self:T(self.lid..string.format("Removed transported cargo %s outside carrier: ncargo=%d", groupname, request.cargogroupset:Count()))
|
||||
-- This as well?
|
||||
--request.transportcargoset:RemoveCargosByName(RemoveCargoNames)
|
||||
|
||||
else
|
||||
--self:E(self.lid..string.format("ERROR: Group %s is neither cargo nor transport!", group:GetName()))
|
||||
end
|
||||
end
|
||||
self:T(self.lid..string.format("Removed selfpropelled cargo %s: ncargo=%d.", groupname, request.cargogroupset:Count()))
|
||||
|
||||
else
|
||||
|
||||
---
|
||||
-- Complicated case: Dead unit could be:
|
||||
-- 1.) A Cargo unit (e.g. waiting to be picked up).
|
||||
-- 2.) A Transport unit which itself holds cargo groups.
|
||||
---
|
||||
|
||||
-- Check if this a cargo or transport group.
|
||||
local istransport=not asset.iscargo --self:_GroupIsTransport(group, request)
|
||||
|
||||
if istransport==true then
|
||||
|
||||
-- Whole carrier group is dead. Remove it from the carrier group set.
|
||||
request.transportgroupset:Remove(groupname, NoTriggerEvent)
|
||||
self:T(self.lid..string.format("Removed transport %s: ntransport=%d", groupname, request.transportgroupset:Count()))
|
||||
|
||||
elseif istransport==false then
|
||||
|
||||
-- This must have been an alive cargo group that was killed outside the carrier, e.g. waiting to be transported or waiting to be put back.
|
||||
-- Remove dead group from cargo group set.
|
||||
request.cargogroupset:Remove(groupname, NoTriggerEvent)
|
||||
self:T(self.lid..string.format("Removed transported cargo %s outside carrier: ncargo=%d", groupname, request.cargogroupset:Count()))
|
||||
-- This as well?
|
||||
--request.transportcargoset:RemoveCargosByName(RemoveCargoNames)
|
||||
|
||||
else
|
||||
--self:E(self.lid..string.format("ERROR: Group %s is neither cargo nor transport!", group:GetName()))
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
self:E(self.lid.."ERROR: Asset and/or Request is nil in onafterAssetDead")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -1405,7 +1405,9 @@ function ARMYGROUP:onbeforeEngageTarget(From, Event, To, Target)
|
||||
end
|
||||
|
||||
-- Pause current mission.
|
||||
if self.currentmission and self.currentmission>0 then
|
||||
local mission=self:GetMissionCurrent()
|
||||
|
||||
if mission and mission.type~=AUFTRAG.Type.GROUNDATTACK then
|
||||
self:T(self.lid.."Engage command but have current mission ==> Pausing mission!")
|
||||
self:PauseMission()
|
||||
dt=-0.1
|
||||
@ -1533,6 +1535,15 @@ function ARMYGROUP:onafterDisengage(From, Event, To)
|
||||
self:SwitchROE(self.engage.roe)
|
||||
self:SwitchAlarmstate(self.engage.alarmstate)
|
||||
|
||||
-- Get current task
|
||||
local task=self:GetTaskCurrent()
|
||||
|
||||
-- Get if current task is ground attack.
|
||||
if task and task.dcstask.id==AUFTRAG.SpecialTask.GROUNDATTACK then
|
||||
self:T(self.lid.."Disengage with current task GROUNDATTACK ==> Task Done!")
|
||||
self:TaskDone(task)
|
||||
end
|
||||
|
||||
-- Remove current waypoint
|
||||
if self.engage.Waypoint then
|
||||
self:RemoveWaypointByID(self.engage.Waypoint.uid)
|
||||
|
||||
@ -385,6 +385,7 @@ _AUFTRAGSNR=0
|
||||
-- @field #string BARRAGE Barrage.
|
||||
-- @field #string ARMORATTACK Armor attack.
|
||||
-- @field #string CASENHANCED Enhanced CAS.
|
||||
-- @field #string GROUNDATTACK Ground attack.
|
||||
AUFTRAG.Type={
|
||||
ANTISHIP="Anti Ship",
|
||||
AWACS="AWACS",
|
||||
@ -419,6 +420,7 @@ AUFTRAG.Type={
|
||||
ARMORATTACK="Armor Attack",
|
||||
CASENHANCED="CAS Enhanced",
|
||||
HOVER="Hover",
|
||||
GROUNDATTACK="Ground Attack"
|
||||
}
|
||||
|
||||
--- Mission status of an assigned group.
|
||||
@ -431,6 +433,7 @@ AUFTRAG.Type={
|
||||
-- @field #string ONGUARD On guard.
|
||||
-- @field #string ARMOREDGUARD On guard with armor.
|
||||
-- @field #string BARRAGE Barrage.
|
||||
-- @field #string GROUNDATTACK Ground attack.
|
||||
AUFTRAG.SpecialTask={
|
||||
PATROLZONE="PatrolZone",
|
||||
RECON="ReconMission",
|
||||
@ -442,6 +445,7 @@ AUFTRAG.SpecialTask={
|
||||
BARRAGE="Barrage",
|
||||
ARMORATTACK="AmorAttack",
|
||||
HOVER="Hover",
|
||||
GROUNDATTACK="Ground Attack",
|
||||
}
|
||||
|
||||
--- Mission status.
|
||||
@ -562,7 +566,7 @@ AUFTRAG.Category={
|
||||
|
||||
--- AUFTRAG class version.
|
||||
-- @field #string version
|
||||
AUFTRAG.version="0.8.5"
|
||||
AUFTRAG.version="0.9.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -1792,6 +1796,35 @@ function AUFTRAG:NewARMORATTACK(Target, Speed, Formation)
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[GROUND]** Create a GROUNDATTACK mission. Ground group(s) will go to a target object and attack.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Wrapper.Positionable#POSITIONABLE Target The target to attack. Can be a GROUP, UNIT or STATIC object.
|
||||
-- @param #number Speed Speed in knots.
|
||||
-- @param #string Formation The attack formation, e.g. "Wedge", "Vee" etc.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewGROUNDATTACK(Target, Speed, Formation)
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.GROUNDATTACK)
|
||||
|
||||
mission:_TargetFromObject(Target)
|
||||
|
||||
mission.missionTask=mission:GetMissionTaskforMissionType(AUFTRAG.Type.GROUNDATTACK)
|
||||
|
||||
mission.optionROE=ENUMS.ROE.OpenFire
|
||||
mission.optionAlarm=ENUMS.AlarmState.Auto
|
||||
mission.optionFormation="On Road"
|
||||
mission.optionAttackFormation=Formation or "Wedge"
|
||||
|
||||
mission.missionFraction=0.75
|
||||
mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or 20
|
||||
|
||||
mission.categories={AUFTRAG.Category.GROUND}
|
||||
|
||||
mission.DCStask=mission:GetDCSMissionTask()
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[AIR, GROUND, NAVAL]** Create a RECON mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Set#SET_ZONE ZoneSet The recon zones.
|
||||
@ -3315,6 +3348,7 @@ function AUFTRAG:onafterStatus(From, Event, To)
|
||||
|
||||
-- Cancel mission if mission targets are gone (if there were any in the beginning).
|
||||
-- TODO: I commented this out for some reason but I forgot why...
|
||||
self:T(self.lid.."No targets left cancelling mission!")
|
||||
self:Cancel()
|
||||
|
||||
elseif self:IsExecuting() then
|
||||
@ -5098,6 +5132,26 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.GROUNDATTACK then
|
||||
|
||||
---------------------------
|
||||
-- GROUND ATTACK Mission --
|
||||
---------------------------
|
||||
|
||||
local DCStask={}
|
||||
|
||||
DCStask.id=AUFTRAG.SpecialTask.GROUNDATTACK
|
||||
|
||||
-- We create a "fake" DCS task and pass the parameters to the ARMYGROUP.
|
||||
local param={}
|
||||
param.target=self:GetTargetData()
|
||||
param.action="Wedge"
|
||||
param.speed=self.missionSpeed
|
||||
|
||||
DCStask.params=param
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.AMMOSUPPLY then
|
||||
|
||||
-------------------------
|
||||
|
||||
@ -100,15 +100,107 @@
|
||||
-- local text=string.format("Strategy changd to %s", Strategy)
|
||||
-- MESSAGE:New(text, 120):ToAll()
|
||||
-- end
|
||||
--
|
||||
-- # Resources
|
||||
--
|
||||
-- A chief needs resources such as air, ground and naval assets. These can be added in form of AIRWINGs, BRIGADEs and FLEETs.
|
||||
--
|
||||
-- Whenever the chief detects a target or receives a mission, he will select the best available assets and assign them to the mission.
|
||||
-- The best assets are determined by their mission performance, payload performance (in case of air), distance to the target, skill level, etc.
|
||||
--
|
||||
-- ## Adding Airwings
|
||||
--
|
||||
-- Airwings can be added via the @{#CHIEF.AddAirwing}() function.
|
||||
--
|
||||
-- ## Adding Brigades
|
||||
--
|
||||
-- Brigades can be added via the @{#CHIEF.AddBrigade}() function.
|
||||
--
|
||||
-- ## Adding Fleets
|
||||
--
|
||||
-- Fleets are not implemented yet.
|
||||
--
|
||||
--
|
||||
-- # Strategic (Capture) Zones
|
||||
--
|
||||
-- Strategically important zones, which should be captured can be added via the @{#CHIEF.AddStrategicZone}() function.
|
||||
-- Strategically important zones, which should be captured can be added via the @{#CHIEF.AddStrategicZone}(*OpsZone, Prio, Importance*) function.
|
||||
-- The first parameter *OpsZone* is an @{Ops.OpsZone#OPSZONE} specifying the zone. This has to be a **circular zone** due to DCS API restrictions.
|
||||
-- The second parameter *Prio* is the priority. The zone queue is sorted wrt to lower prio values. By default this is set to 50.
|
||||
-- The third parameter *Importance* is the importance of the zone. By default this is `nil`. If you specify one zone with importance 2 and a second zone with
|
||||
-- importance 3, then the zone of importance 2 is attacked first and only if that zone has been captured, zones that have importances with higher values are attacked.
|
||||
--
|
||||
-- If the zone is currently owned by another coalition and enemy ground troops are present in the zone, a CAS and an ARTY mission are lauchned, provided assets are available.
|
||||
-- For example:
|
||||
--
|
||||
-- Once the zone is cleaned of enemy forces, ground (infantry) troops are send there. These require a transportation via helicopters.
|
||||
-- So in order to deploy our own troops, infantry assets with `AUFTRAG.Type.ONGUARD` and helicopters with `AUFTRAG.Type.OPSTRANSPORT` need to be available.
|
||||
-- local myStratZone=myChief:AddStrategicZone(myOpsZone, nil , 2)
|
||||
--
|
||||
-- Will at a strategic zone with importance 2.
|
||||
--
|
||||
-- If the zone is currently owned by another coalition and enemy ground troops are present in the zone, a CAS and an ARTY mission are lauchned:
|
||||
--
|
||||
-- * A mission of type `AUFTRAG.Type.CASENHANCED` is started if assets are available that can carry out this mission type.
|
||||
-- * A mission of type `AUFTRAG.Type.ARTY` is started provided assets are available.
|
||||
--
|
||||
-- The CAS flight(s) will patrol the zone randomly and take out enemy ground units they detect. It can always be possible that the enemies cannot be detected however.
|
||||
-- The assets will shell the zone. However, it is unlikely that they hit anything as they do not have any information about the location of the enemies.
|
||||
--
|
||||
-- Once the zone is cleaned of enemy forces, ground troops are send there. By default, two missions are launched:
|
||||
--
|
||||
-- * First mission is of type `AUFTRAG.Type.ONGUARD` and will send infantry groups. These are transported by helicopters. Therefore, helo assets with `AUFTRAG.Type.OPSTRANSPORT` need to be available.
|
||||
-- * The second mission is also of type `AUFTRAG.Type.ONGUARD` but will send tanks if these are available.
|
||||
--
|
||||
-- ## Customized Reaction
|
||||
--
|
||||
-- The default mission types and number of assets can be customized for the two scenarious (zone empty or zone occupied by the enemy).
|
||||
--
|
||||
-- In order to do this, you need to create resource lists (one for each scenario) via the @{#CHIEF.CreateResource}() function.
|
||||
-- These list can than be used to replace the default resources employed with
|
||||
--
|
||||
-- * @{CHIEF.SetStrategicZoneResourceOccupied}(*StrateticZone, ResourceOccupied*) for the case that the zone is occupied by the enemy and
|
||||
-- * @{CHIEF.SetStrategicZoneResourceEmpty}(*StrateticZone, ResourceEmpty*) for the case that the zone is empty.
|
||||
--
|
||||
-- The first parameter *StrateticZone* is the strategic zone object that is returned by the @{#CHIEF.AddStrategicZone}() function.
|
||||
-- The second parameter is the resource list created with the @{#CHIEF.CreateResource}() function.
|
||||
--
|
||||
-- For example:
|
||||
--
|
||||
-- -- Create a resource list of mission types and required assets for the case that the zone is occupied.
|
||||
-- -- Here, we create an enhanced CAS mission and employ at least on and at most two asset groups.
|
||||
-- local ResourceOccupied=myChief:CreateResource(AUFTRAG.Type.CASENHANCED, 1, 2)
|
||||
-- -- We also add ARTY missions with at least one and at most two assets. We additionally require these to be MLRS groups (and not howitzers).
|
||||
-- myChief:AddToResource(ResourceOccupied, AUFTRAG.Type.ARTY, 1, 2, nil, "MLRS")
|
||||
-- -- Add at least one RECON mission that uses UAV type assets.
|
||||
-- myChief:AddToResource(ResourceOccupied, AUFTRAG.Type.RECON, 1, nil, GROUP.Attribute.AIR_UAV)
|
||||
-- -- Add at least one but at most two BOMBCARPET missions.
|
||||
-- myChief:AddToResource(ResourceOccupied, AUFTRAG.Type.BOMBCARPET, 1, 2)
|
||||
--
|
||||
-- -- Replace the default list with the customized one.
|
||||
-- myChief:SetStrategicZoneResourceOccupied(myStratZone, ResourceOccupied)
|
||||
--
|
||||
--
|
||||
-- -- Create a resource list of mission types and required assets for the case that the zone is empty.
|
||||
-- -- Here, we create an ONGUARD mission and employ at least on and at most five infantry assets.
|
||||
-- local ResourceEmpty=myChief:CreateResource(AUFTRAG.Type.ONGUARD, 1, 5, GROUP.Attribute.GROUND_INFANTRY)
|
||||
-- -- Additionally, we send up to three tank groups.
|
||||
-- myChief:AddToResource(ResourceEmpty, AUFTRAG.Type.ONGUARD, 1, 3, GROUP.Attribute.GROUND_TANK)
|
||||
-- -- Finally, we send two groups that patrol the zone.
|
||||
-- myChief:AddToResource(ResourceEmpty, AUFTRAG.Type.PATROLZONE, 2)
|
||||
--
|
||||
-- -- Set this to be the resources employed when the zone is empty.
|
||||
-- myChief:SetStrategicZoneResourceEmpty(myStratZone, ResourceEmpty)
|
||||
--
|
||||
-- As the location of the enemies is not known, only mission types that don't require and explicit target group are possible. These are
|
||||
--
|
||||
-- * `AUFTRAG.Type.CASENHANCED`
|
||||
-- * `AUFTRAG.Type.ARTY`
|
||||
-- * `AUFTRAG.Type.PATROLZONE`
|
||||
-- * `AUFTRAG.Type.ONGUARD`
|
||||
-- * `AUFTRAG.Type.RECON`
|
||||
-- * `AUFTRAG.Type.AMMOSUPPLY`
|
||||
-- * `AUFTRAG.Type.BOMBING`
|
||||
-- * `AUFTRAG.Type.BOMBCARPET`
|
||||
-- * `AUFTRAG.Type.BARRAGE`
|
||||
--
|
||||
-- ## Events
|
||||
--
|
||||
-- Whenever a strategic zone is captured by us the FSM event @{#CHIEF.ZoneCaptured} is triggered and customized further actions can be executed
|
||||
-- with the @{#CHIEF.OnAfterZoneCaptured}() function.
|
||||
@ -176,16 +268,23 @@ CHIEF.Strategy = {
|
||||
-- @type CHIEF.StrategicZone
|
||||
-- @field Ops.OpsZone#OPSZONE opszone OPS zone.
|
||||
-- @field #number prio Priority.
|
||||
-- @field #number importance Importance
|
||||
-- @field Ops.Auftrag#AUFTRAG missionPatrol Patrol mission.
|
||||
-- @field Ops.Auftrag#AUFTRAG missionCAS CAS mission.
|
||||
-- @field Ops.Auftrag#AUFTRAG missionPatrol Patrol mission.
|
||||
-- @field Ops.Auftrag#AUFTRAG missionARTY Artillery mission.
|
||||
-- @field #number importance Importance.
|
||||
-- @field #table resourceEmpty Resource list.
|
||||
-- @field #table resourceOccup Resource list.
|
||||
-- @field #table missions Mission.
|
||||
|
||||
--- Resource.
|
||||
-- @type CHIEF.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.
|
||||
|
||||
--- CHIEF class version.
|
||||
-- @field #string version
|
||||
CHIEF.version="0.2.0"
|
||||
CHIEF.version="0.3.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -600,6 +699,88 @@ function CHIEF:SetDefcon(Defcon)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new resource list of required assets.
|
||||
-- @param #CHIEF self
|
||||
-- @param #string MissionType The mission type.
|
||||
-- @param #number Nmin Min number of required assets. Default 1.
|
||||
-- @param #number Nmax Max number of requried assets. Default 1.
|
||||
-- @param #table Attributes Generalized attribute(s). Default `nil`.
|
||||
-- @param #table Properties DCS attribute(s). Default `nil`.
|
||||
-- @return #table The resource object.
|
||||
function CHIEF:CreateResource(MissionType, Nmin, Nmax, Attributes, Properties)
|
||||
|
||||
local resource={}
|
||||
|
||||
self:AddToResource(resource, MissionType, Nmin, Nmax, Attributes, Properties)
|
||||
|
||||
return resource
|
||||
end
|
||||
|
||||
--- Add mission type and number of required assets to resource.
|
||||
-- @param #CHIEF self
|
||||
-- @param #table Resource Resource table.
|
||||
-- @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 #CHIEF self
|
||||
function CHIEF:AddToResource(Resource, MissionType, Nmin, Nmax, Attributes, Properties)
|
||||
|
||||
-- Ensure table.
|
||||
if Attributes and type(Attributes)~="table" then
|
||||
Attributes={Attributes}
|
||||
end
|
||||
|
||||
-- Ensure table.
|
||||
if Properties and type(Properties)~="table" then
|
||||
Properties={Properties}
|
||||
end
|
||||
|
||||
-- Create new resource table.
|
||||
local resource={} --#CHIEF.Resource
|
||||
resource.MissionType=MissionType
|
||||
resource.Nmin=Nmin or 1
|
||||
resource.Nmax=Nmax or 1
|
||||
resource.Attributes=Attributes or {}
|
||||
resource.Properties=Properties or {}
|
||||
|
||||
-- Add to table.
|
||||
table.insert(Resource, resource)
|
||||
|
||||
-- Debug output.
|
||||
if self.verbose>10 then
|
||||
local text="Resource:"
|
||||
for _,_r in pairs(Resource) do
|
||||
local r=_r --#CHIEF.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 self
|
||||
end
|
||||
|
||||
--- Delete mission type from resource list. All running missions are cancelled.
|
||||
-- @param #CHIEF self
|
||||
-- @param #table Resource Resource table.
|
||||
-- @param #string MissionType Mission Type.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:DeleteFromResource(Resource, MissionType)
|
||||
|
||||
for i=#Resource,1,-1 do
|
||||
local resource=Resource[i] --#CHIEF.Resource
|
||||
if resource.MissionType==MissionType then
|
||||
if resource.mission and resource.mission:IsNotOver() then
|
||||
resource.mission:Cancel()
|
||||
end
|
||||
table.remove(Resource, i)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get defence condition.
|
||||
-- @param #CHIEF self
|
||||
-- @param #string Current Defence condition. See @{#CHIEF.DEFCON}, e.g. `CHIEF.DEFCON.RED`.
|
||||
@ -813,11 +994,22 @@ function CHIEF:RemoveTarget(Target)
|
||||
end
|
||||
|
||||
--- Add strategically important zone.
|
||||
-- By default two resource lists are created. One for the case that the zone is empty and the other for the case that the zone is occupied
|
||||
-- Empty:
|
||||
--
|
||||
-- * `AUFTRAG.Type.ARTY` with Nmin=1, Nmax=2
|
||||
-- * `AUFTRAG.Type.CASENHANCED` with Nmin=1, Nmax=2
|
||||
--
|
||||
-- Occupied:
|
||||
--
|
||||
-- * `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`.
|
||||
--
|
||||
-- @param #CHIEF self
|
||||
-- @param Ops.OpsZone#OPSZONE OpsZone OPS zone object.
|
||||
-- @param #number Priority Priority.
|
||||
-- @param #number Importance Importance.
|
||||
-- @return #CHIEF self
|
||||
-- @return #CHIEF.StrategicZone The strategic zone.
|
||||
function CHIEF:AddStrategicZone(OpsZone, Priority, Importance)
|
||||
|
||||
local stratzone={} --#CHIEF.StrategicZone
|
||||
@ -825,11 +1017,21 @@ function CHIEF:AddStrategicZone(OpsZone, Priority, Importance)
|
||||
stratzone.opszone=OpsZone
|
||||
stratzone.prio=Priority or 50
|
||||
stratzone.importance=Importance
|
||||
|
||||
stratzone.missions={}
|
||||
|
||||
-- Start ops zone.
|
||||
if OpsZone:IsStopped() then
|
||||
OpsZone:Start()
|
||||
end
|
||||
|
||||
-- Add resources if zone is occupied.
|
||||
stratzone.resourceOccup=self:CreateResource(AUFTRAG.Type.ARTY, 1, 2)
|
||||
self:AddToResource(stratzone.resourceOccup, AUFTRAG.Type.CASENHANCED, 1, 2)
|
||||
|
||||
-- Add resources if zone is empty
|
||||
stratzone.resourceEmpty=self:CreateResource(AUFTRAG.Type.ONGUARD, 1, 3, GROUP.Attribute.GROUND_INFANTRY)
|
||||
self:AddToResource(stratzone.resourceEmpty, AUFTRAG.Type.ONGUARD, 1, 1, GROUP.Attribute.GROUND_TANK)
|
||||
|
||||
-- Add to table.
|
||||
table.insert(self.zonequeue, stratzone)
|
||||
@ -837,9 +1039,56 @@ function CHIEF:AddStrategicZone(OpsZone, Priority, Importance)
|
||||
-- Add chief so we get informed when something happens.
|
||||
OpsZone:_AddChief(self)
|
||||
|
||||
return stratzone
|
||||
end
|
||||
|
||||
--- Set the resource list of missions and assets employed when the zone is empty.
|
||||
-- @param #CHIEF self
|
||||
-- @param #CHIEF.StrategicZone StrategicZone The strategic zone.
|
||||
-- @param #CHIEF.Resource Resource Resource list of missions and assets.
|
||||
-- @param #boolean NoCopy If `true`, do **not** create a deep copy of the resource.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:SetStrategicZoneResourceEmpty(StrategicZone, Resource, NoCopy)
|
||||
if NoCopy then
|
||||
StrategicZone.resourceEmpty=Resource
|
||||
else
|
||||
StrategicZone.resourceEmpty=UTILS.DeepCopy(Resource)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the resource list of missions and assets employed when the zone is occupied by the enemy.
|
||||
-- @param #CHIEF self
|
||||
-- @param #CHIEF.StrategicZone StrategicZone The strategic zone.
|
||||
-- @param #CHIEF.Resource Resource Resource list of missions and assets.
|
||||
-- @param #boolean NoCopy If `true`, do **not** create a deep copy of the resource.
|
||||
-- @return #CHIEF self
|
||||
function CHIEF:SetStrategicZoneResourceOccupied(StrategicZone, Resource, NoCopy)
|
||||
if NoCopy then
|
||||
StrategicZone.resourceOccup=Resource
|
||||
else
|
||||
StrategicZone.resourceOccup=UTILS.DeepCopy(Resource)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the resource list of missions and assets employed when the zone is empty.
|
||||
-- @param #CHIEF self
|
||||
-- @param #CHIEF.StrategicZone StrategicZone The strategic zone.
|
||||
-- @return #CHIEF.Resource Resource list of missions and assets.
|
||||
function CHIEF:GetStrategicZoneResourceEmpty(StrategicZone)
|
||||
return StrategicZone.resourceEmpty
|
||||
end
|
||||
|
||||
--- Get the resource list of missions and assets employed when the zone is occupied by the enemy.
|
||||
-- @param #CHIEF self
|
||||
-- @param #CHIEF.StrategicZone StrategicZone The strategic zone.
|
||||
-- @return #CHIEF.Resource Resource list of missions and assets.
|
||||
function CHIEF:GetStrategicZoneResourceOccupied(StrategicZone)
|
||||
return StrategicZone.resourceOccup
|
||||
end
|
||||
|
||||
|
||||
--- Remove strategically important zone. All runing missions are cancelled.
|
||||
-- @param #CHIEF self
|
||||
-- @param Ops.OpsZone#OPSZONE OpsZone OPS zone object.
|
||||
@ -860,15 +1109,23 @@ function CHIEF:RemoveStrategicZone(OpsZone, Delay)
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Removing OPS zone \"%s\" from queue! All running missions will be cancelled", OpsZone.zoneName))
|
||||
|
||||
-- Cancel all running missions.
|
||||
for _,_entry in pairs(OpsZone.Missions or {}) do
|
||||
local entry = _entry -- Ops.OpsZone#OPSZONE.MISSION
|
||||
if entry.Coalition==self.coalition and entry.Mission and entry.Mission:IsNotOver() then
|
||||
entry.Mission:Cancel()
|
||||
|
||||
-- Cancel running missions.
|
||||
for _,_resource in pairs(stratzone.resourceEmpty) do
|
||||
local resource=_resource --#CHIEF.Resource
|
||||
if resource.mission and resource.mission:IsNotOver() then
|
||||
resource.mission:Cancel()
|
||||
end
|
||||
end
|
||||
|
||||
-- Cancel running missions.
|
||||
for _,_resource in pairs(stratzone.resourceOccup) do
|
||||
local resource=_resource --#CHIEF.Resource
|
||||
if resource.mission and resource.mission:IsNotOver() then
|
||||
resource.mission:Cancel()
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove from table.
|
||||
table.remove(self.zonequeue, i)
|
||||
|
||||
@ -1566,13 +1823,14 @@ function CHIEF:_TacticalOverview()
|
||||
local NmissionsRunni=self.commander:CountMissions(AUFTRAG.Type, true)
|
||||
local Ntargets=#self.targetqueue
|
||||
local Nzones=#self.zonequeue
|
||||
local Nagents=self.detectionset:CountAlive()
|
||||
|
||||
-- Info message
|
||||
local text=string.format("Tactical Overview\n")
|
||||
text=text..string.format("=================\n")
|
||||
|
||||
-- Strategy and defcon info.
|
||||
text=text..string.format("Strategy: %s - Defcon: %s\n", self.strategy, self.Defcon)
|
||||
text=text..string.format("Strategy: %s - Defcon: %s - Agents=%s\n", self.strategy, self.Defcon, Nagents)
|
||||
|
||||
-- Contact info.
|
||||
text=text..string.format("Contacts: %d [Border=%d, Conflict=%d, Attack=%d]\n", Ncontacts, self.Nborder, self.Nconflict, self.Nattack)
|
||||
@ -1866,11 +2124,6 @@ end
|
||||
-- @param #CHIEF self
|
||||
function CHIEF:CheckOpsZoneQueue()
|
||||
|
||||
-- Passive strategy ==> Do not act.
|
||||
if self:IsPassive() then
|
||||
return
|
||||
end
|
||||
|
||||
-- Number of zones.
|
||||
local Nzones=#self.zonequeue
|
||||
|
||||
@ -1878,10 +2131,45 @@ function CHIEF:CheckOpsZoneQueue()
|
||||
if Nzones==0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Loop over strategic zone and remove stopped zones.
|
||||
for i=Nzones, 1, -1 do
|
||||
local stratzone=self.zonequeue[i] --#CHIEF.StrategicZone
|
||||
if stratzone.opszone:IsStopped() then
|
||||
self:RemoveStrategicZone(stratzone.opszone)
|
||||
end
|
||||
end
|
||||
|
||||
-- Loop over strategic zones and cancel missions for occupied zones if zone is not occupied any more.
|
||||
for _,_startzone in pairs(self.zonequeue) do
|
||||
local stratzone=_startzone --#CHIEF.StrategicZone
|
||||
|
||||
-- Current owner of the zone.
|
||||
local ownercoalition=stratzone.opszone:GetOwner()
|
||||
|
||||
-- Check if we own the zone or it is empty.
|
||||
if ownercoalition==self.coalition or stratzone.opszone:IsEmpty() then
|
||||
|
||||
-- Loop over resources.
|
||||
for _,_resource in pairs(stratzone.resourceOccup or {}) do
|
||||
local resource=_resource --#CHIEF.Resource
|
||||
|
||||
-- Cancel running missions.
|
||||
if resource.mission then
|
||||
resource.mission:Cancel()
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Passive strategy ==> Do not act.
|
||||
if self:IsPassive() then
|
||||
return
|
||||
end
|
||||
|
||||
-- Check if total number of missions is reached.
|
||||
local NoLimit=self:_CheckMissionLimit("Total")
|
||||
--env.info("FF chief zone total nolimit="..tostring(NoLimit))
|
||||
if NoLimit==false then
|
||||
return nil
|
||||
end
|
||||
@ -1911,19 +2199,15 @@ function CHIEF:CheckOpsZoneQueue()
|
||||
|
||||
-- Current owner of the zone.
|
||||
local ownercoalition=stratzone.opszone:GetOwner()
|
||||
|
||||
-- Name of the zone.
|
||||
local zoneName=stratzone.opszone.zone:GetName()
|
||||
|
||||
-- Check coalition and importance.
|
||||
if ownercoalition~=self.coalition and (stratzone.importance==nil or stratzone.importance<=vip) and (not stratzone.opszone:IsStopped()) then
|
||||
|
||||
-- Has a patrol mission?
|
||||
local hasMissionPatrol=stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.ONGUARD) or stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.ARMOREDGUARD)
|
||||
-- Has a CAS mission?
|
||||
local hasMissionCAS=stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.CASENHANCED)
|
||||
-- Has a ARTY mission?
|
||||
local hasMissionARTY=stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.ARTY)
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Zone %s [%s] is owned by coalition %d", stratzone.opszone.zone:GetName(), stratzone.opszone:GetState(), ownercoalition))
|
||||
self:T(self.lid..string.format("Zone %s [%s] is owned by coalition %d", zoneName, stratzone.opszone:GetState(), ownercoalition))
|
||||
|
||||
if stratzone.opszone:IsEmpty() then
|
||||
|
||||
@ -1932,19 +2216,29 @@ function CHIEF:CheckOpsZoneQueue()
|
||||
--
|
||||
-- We send ground troops to capture the zone.
|
||||
---
|
||||
|
||||
if not hasMissionPatrol then
|
||||
|
||||
-- Debug info.
|
||||
self:T3(self.lid..string.format("Zone is empty ==> Recruit Patrol zone infantry assets"))
|
||||
|
||||
-- Recruit ground assets that
|
||||
local recruitedI=self:RecruitAssetsForZone(stratzone, AUFTRAG.Type.ONGUARD, 1, 3, {Group.Category.GROUND}, {GROUP.Attribute.GROUND_INFANTRY})
|
||||
local recruitedT=self:RecruitAssetsForZone(stratzone, AUFTRAG.Type.ARMOREDGUARD, 1, 1, {Group.Category.GROUND}, {GROUP.Attribute.GROUND_TANK})
|
||||
|
||||
for _,_resource in pairs(stratzone.resourceEmpty or {}) do
|
||||
local resource=_resource --#CHIEF.Resource
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Zone is empty ==> Recruit Patrol zone infantry assets=%s", tostring(recruitedI)))
|
||||
self:T(self.lid..string.format("Zone is empty ==> Recruit Patrol zone armored assets=%s", tostring(recruitedT)))
|
||||
-- Mission type.
|
||||
local missionType=resource.MissionType
|
||||
|
||||
if (not resource.mission) or resource.mission:IsOver() then
|
||||
|
||||
-- Debug info.
|
||||
self:T2(self.lid..string.format("Zone \"%s\" is empty ==> Recruiting for mission type %s: Nmin=%d, Nmax=%d", zoneName, missionType, resource.Nmin, resource.Nmax))
|
||||
|
||||
-- Recruit assets.
|
||||
local recruited=self:RecruitAssetsForZone(stratzone, resource)
|
||||
|
||||
if recruited then
|
||||
self:T(self.lid..string.format("Successfully recruited assets for empty zone \"%s\" [mission type=%s]", zoneName, missionType))
|
||||
else
|
||||
self:T(self.lid..string.format("Could not recruited assets for empty zone \"%s\" [mission type=%s]", zoneName, missionType))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
@ -1954,79 +2248,35 @@ function CHIEF:CheckOpsZoneQueue()
|
||||
--
|
||||
-- We first send a CAS flight to eliminate enemy activity.
|
||||
---
|
||||
|
||||
if not hasMissionCAS then
|
||||
|
||||
-- Debug message.
|
||||
self:T3(self.lid..string.format("Zone is NOT empty ==> Recruit CAS assets"))
|
||||
for _,_resource in pairs(stratzone.resourceOccup or {}) do
|
||||
local resource=_resource --#CHIEF.Resource
|
||||
|
||||
-- Mission type.
|
||||
local missionType=resource.MissionType
|
||||
|
||||
if (not resource.mission) or resource.mission:IsOver() then
|
||||
|
||||
-- Debug info.
|
||||
self:T2(self.lid..string.format("Zone %s is NOT empty ==> Recruiting for mission type %s: Nmin=%d, Nmax=%d", zoneName, missionType, resource.Nmin, resource.Nmax))
|
||||
|
||||
-- Recruit assets.
|
||||
local recruited=self:RecruitAssetsForZone(stratzone, resource)
|
||||
|
||||
-- Recruite CAS assets.
|
||||
local recruited=self:RecruitAssetsForZone(stratzone, AUFTRAG.Type.CASENHANCED, 1, 1)
|
||||
|
||||
-- Debug message.
|
||||
self:T(self.lid..string.format("Zone is NOT empty ==> Recruit CAS assets=%s", tostring(recruited)))
|
||||
|
||||
end
|
||||
if recruited then
|
||||
self:T(self.lid..string.format("Successfully recruited assets for occupied zone %s, mission type=%s", zoneName, missionType))
|
||||
else
|
||||
self:T(self.lid..string.format("Could not recruited assets for occupied zone %s, mission type=%s", zoneName, missionType))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if not hasMissionARTY then
|
||||
|
||||
-- Debug message.
|
||||
self:T3(self.lid..string.format("Zone is NOT empty ==> Recruit ARTY assets"))
|
||||
|
||||
|
||||
-- Recruite CAS assets.
|
||||
local recruited=self:RecruitAssetsForZone(stratzone, AUFTRAG.Type.ARTY, 1, 1)
|
||||
|
||||
-- Debug message.
|
||||
self:T(self.lid..string.format("Zone is NOT empty ==> Recruit ARTY assets=%s", tostring(recruited)))
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Loop over strategic zone.
|
||||
for _,_startzone in pairs(self.zonequeue) do
|
||||
local stratzone=_startzone --#CHIEF.StrategicZone
|
||||
|
||||
-- Current owner of the zone.
|
||||
local ownercoalition=stratzone.opszone:GetOwner()
|
||||
|
||||
-- Has a patrol mission?
|
||||
local hasMissionPATROL=stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.PATROLZONE)
|
||||
|
||||
-- Has a CAS mission?
|
||||
local hasMissionCAS, CASMissions = stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.CASENHANCED)
|
||||
local hasMissionARTY, ARTYMissions = stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.ARTY)
|
||||
|
||||
if ownercoalition==self.coalition and stratzone.opszone:IsEmpty() and hasMissionCAS then
|
||||
-- Cancel CAS mission if zone is ours and no enemies are present.
|
||||
-- TODO: Might want to check if we still have CAS capable assets in stock?!
|
||||
--stratzone.missionCAS:Cancel()
|
||||
for _,_auftrag in pairs(CASMissions) do
|
||||
_auftrag:Cancel()
|
||||
end
|
||||
end
|
||||
|
||||
if ownercoalition==self.coalition and hasMissionARTY then
|
||||
-- Cancel ARTY mission if zone is ours and no enemies are present.
|
||||
for _,_auftrag in pairs(ARTYMissions) do
|
||||
_auftrag:Cancel()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Loop over strategic zone and remove stopped zones.
|
||||
for i=#self.zonequeue, 1, -1 do
|
||||
local stratzone=self.zonequeue[i] --#CHIEF.StrategicZone
|
||||
if stratzone.opszone:IsStopped() then
|
||||
self:RemoveStrategicZone(stratzone.opszone)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -2360,13 +2610,9 @@ end
|
||||
--- Recruit assets for a given OPS zone.
|
||||
-- @param #CHIEF self
|
||||
-- @param #CHIEF.StrategicZone StratZone The strategic zone.
|
||||
-- @param #string MissionType Mission Type.
|
||||
-- @param #number NassetsMin Min number of required assets.
|
||||
-- @param #number NassetsMax Max number of required assets.
|
||||
-- @param #table Categories Group categories of the assets.
|
||||
-- @param #table Attributes Generalized group attributes.
|
||||
-- @param #CHIEF.Resource Resource The required resources.
|
||||
-- @return #boolean If `true` enough assets could be recruited.
|
||||
function CHIEF:RecruitAssetsForZone(StratZone, MissionType, NassetsMin, NassetsMax, Categories, Attributes)
|
||||
function CHIEF:RecruitAssetsForZone(StratZone, Resource)
|
||||
|
||||
-- Cohorts.
|
||||
local Cohorts={}
|
||||
@ -2385,7 +2631,15 @@ function CHIEF:RecruitAssetsForZone(StratZone, MissionType, NassetsMin, NassetsM
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Shortcuts.
|
||||
local MissionType=Resource.MissionType
|
||||
local NassetsMin=Resource.Nmax
|
||||
local NassetsMax=Resource.Nmax
|
||||
local Categories=Resource.Categories
|
||||
local Attributes=Resource.Attributes
|
||||
local Properties=Resource.Properties
|
||||
|
||||
-- Target position.
|
||||
local TargetVec2=StratZone.opszone.zone:GetVec2()
|
||||
@ -2398,26 +2652,36 @@ function CHIEF:RecruitAssetsForZone(StratZone, MissionType, NassetsMin, NassetsM
|
||||
RangeMax=UTILS.NMToMeters(250)
|
||||
end
|
||||
|
||||
-- Set max range to 50 NM because we use armor
|
||||
-- Set max range to 50 NM because we use armor.
|
||||
if MissionType==AUFTRAG.Type.ARMOREDGUARD then
|
||||
RangeMax=UTILS.NMToMeters(50)
|
||||
end
|
||||
|
||||
-- Recruite infantry assets.
|
||||
local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, MissionType, nil, NassetsMin, NassetsMax, TargetVec2, nil, RangeMax, nil, nil, nil, Categories, Attributes)
|
||||
local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, MissionType, nil, NassetsMin, NassetsMax, TargetVec2, nil, RangeMax, nil, nil, nil, Categories, Attributes, Properties)
|
||||
|
||||
if recruited then
|
||||
|
||||
-- Mission for zone.
|
||||
local mission=nil --Ops.Auftrag#AUFTRAG
|
||||
|
||||
-- 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)))
|
||||
|
||||
local TargetZone = StratZone.opszone.zone
|
||||
local TargetCoord = TargetZone:GetCoordinate()
|
||||
|
||||
if MissionType==AUFTRAG.Type.PATROLZONE or MissionType==AUFTRAG.Type.ONGUARD then
|
||||
|
||||
|
||||
---
|
||||
-- PATROLZONE or ONGUARD
|
||||
---
|
||||
|
||||
-- Debug messgage.
|
||||
self:T2(self.lid..string.format("Recruited %d assets for PATROL mission", #assets))
|
||||
|
||||
local recruitedTrans=true
|
||||
local transport=nil
|
||||
-- First check if we need a transportation.
|
||||
local recruitedTrans=true ; local transport=nil
|
||||
if Attributes and Attributes[1]==GROUP.Attribute.GROUND_INFANTRY then
|
||||
|
||||
-- Categories. Currently only helicopters are allowed due to problems with ground transports (might get stuck, might not be a land connection.
|
||||
@ -2425,55 +2689,66 @@ function CHIEF:RecruitAssetsForZone(StratZone, MissionType, NassetsMin, NassetsM
|
||||
local Categories=self.TransportCategories
|
||||
|
||||
-- Recruit transport assets for infantry.
|
||||
recruitedTrans, transport=LEGION.AssignAssetsForTransport(self.commander, self.commander.legions, assets, 1, 1, StratZone.opszone.zone, nil, Categories)
|
||||
recruitedTrans, transport=LEGION.AssignAssetsForTransport(self.commander, self.commander.legions, assets, 1, 1, TargetZone, nil, Categories)
|
||||
|
||||
end
|
||||
|
||||
if recruitedTrans then
|
||||
|
||||
-- Create Patrol zone mission.
|
||||
local mission=nil --Ops.Auftrag#AUFTRAG
|
||||
|
||||
if MissionType==AUFTRAG.Type.PATROLZONE then
|
||||
mission=AUFTRAG:NewPATROLZONE(StratZone.opszone.zone)
|
||||
mission:SetEngageDetected(25, {"Ground Units", "Light armed ships", "Helicopters"})
|
||||
mission=AUFTRAG:NewPATROLZONE(TargetZone)
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.ONGUARD then
|
||||
mission=AUFTRAG:NewONGUARD(StratZone.opszone.zone:GetRandomCoordinate(), nil, nil, {land.SurfaceType.LAND})
|
||||
mission=AUFTRAG:NewONGUARD(TargetZone:GetRandomCoordinate(nil, nil, {land.SurfaceType.LAND}))
|
||||
end
|
||||
mission:SetEngageDetected()
|
||||
|
||||
-- Add assets to mission.
|
||||
for _,asset in pairs(assets) do
|
||||
mission:AddAsset(asset)
|
||||
end
|
||||
|
||||
|
||||
-- Engage detected targets.
|
||||
mission:SetEngageDetected(25, {"Ground Units", "Light armed ships", "Helicopters"})
|
||||
|
||||
-- Attach OPS transport to mission.
|
||||
mission.opstransport=transport
|
||||
|
||||
-- Assign mission to legions.
|
||||
self:MissionAssign(mission, legions)
|
||||
|
||||
-- Attach mission to ops zone.
|
||||
StratZone.opszone:_AddMission(self.coalition, MissionType, mission)
|
||||
|
||||
|
||||
-- Set ops zone to transport.
|
||||
transport.opszone=StratZone.opszone
|
||||
transport.chief=self
|
||||
transport.commander=self.commander
|
||||
|
||||
return true
|
||||
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
|
||||
|
||||
---
|
||||
-- CAS ENHANCED
|
||||
---
|
||||
|
||||
-- Create Patrol zone mission.
|
||||
local caszone = StratZone.opszone.zone
|
||||
local coord = caszone:GetCoordinate()
|
||||
local height = UTILS.MetersToFeet(coord:GetLandHeight())+2500
|
||||
local height = UTILS.MetersToFeet(TargetCoord:GetLandHeight())+2500
|
||||
|
||||
local Speed=200
|
||||
if assets[1] then
|
||||
if assets[1].speedmax then
|
||||
Speed = UTILS.KmphToKnots(assets[1].speedmax * 0.7) or 200
|
||||
end
|
||||
end
|
||||
|
||||
-- CAS mission.
|
||||
mission=AUFTRAG:NewCASENHANCED(TargetZone, height, Speed)
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.CAS then
|
||||
|
||||
---
|
||||
-- CAS
|
||||
---
|
||||
|
||||
-- Create Patrol zone mission.
|
||||
local height = UTILS.MetersToFeet(TargetCoord:GetLandHeight())+2500
|
||||
|
||||
local Speed = 200
|
||||
if assets[1] then
|
||||
@ -2481,82 +2756,80 @@ function CHIEF:RecruitAssetsForZone(StratZone, MissionType, NassetsMin, NassetsM
|
||||
Speed = UTILS.KmphToKnots(assets[1].speedmax * 0.7) or 200
|
||||
end
|
||||
end
|
||||
|
||||
--local mission=AUFTRAG:NewCAS(caszone,height,Speed,coord,math.random(0,359),Leg)
|
||||
local mission=AUFTRAG:NewCASENHANCED(caszone, height, Speed)
|
||||
|
||||
-- Add assets to mission.
|
||||
for _,asset in pairs(assets) do
|
||||
mission:AddAsset(asset)
|
||||
end
|
||||
|
||||
-- Assign mission to legions.
|
||||
self:MissionAssign(mission, legions)
|
||||
|
||||
-- Attach mission to ops zone.
|
||||
StratZone.opszone:_AddMission(self.coalition, MissionType, mission)
|
||||
|
||||
return true
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.CAS then
|
||||
|
||||
-- Create Patrol zone mission.
|
||||
local caszone = StratZone.opszone.zone
|
||||
local coord = caszone:GetCoordinate()
|
||||
local height = UTILS.MetersToFeet(coord:GetLandHeight())+2500
|
||||
local Speed = 200
|
||||
--local mission=AUFTRAG:NewPATROLZONE(caszone)
|
||||
if assets[1] then
|
||||
if assets[1].speedmax then
|
||||
Speed = UTILS.KmphToKnots(assets[1].speedmax * 0.7) or 200
|
||||
end
|
||||
end
|
||||
--local Speed = UTILS.KmphToKnots(assets[1].speedmax * 0.7) or 200
|
||||
local Leg = caszone:GetRadius() <= 10000 and 5 or UTILS.MetersToNM(caszone:GetRadius())
|
||||
local mission=AUFTRAG:NewCAS(caszone,height,Speed,coord,math.random(0,359),Leg)
|
||||
mission:SetEngageDetected(25, {"Ground Units", "Light armed ships", "Helicopters"})
|
||||
mission:SetWeaponExpend(AI.Task.WeaponExpend.ALL)
|
||||
mission:SetMissionSpeed(Speed)
|
||||
-- Leg length.
|
||||
local Leg = TargetZone:GetRadius() <= 10000 and 5 or UTILS.MetersToNM(TargetZone:GetRadius())
|
||||
|
||||
-- Add assets to mission.
|
||||
for _,asset in pairs(assets) do
|
||||
mission:AddAsset(asset)
|
||||
end
|
||||
|
||||
-- Assign mission to legions.
|
||||
self:MissionAssign(mission, legions)
|
||||
|
||||
-- Attach mission to ops zone.
|
||||
StratZone.opszone:_AddMission(self.coalition, MissionType, mission)
|
||||
-- CAS mission.
|
||||
mission=AUFTRAG:NewCAS(TargetZone, height, Speed, TargetCoord, math.random(0,359), Leg)
|
||||
|
||||
return true
|
||||
elseif MissionType==AUFTRAG.Type.ARTY then
|
||||
|
||||
---
|
||||
-- ARTY
|
||||
---
|
||||
|
||||
-- Create ARTY zone mission.
|
||||
local TargetZone = StratZone.opszone.zone
|
||||
local Target = TargetZone:GetCoordinate()
|
||||
local Radius = TargetZone:GetRadius()
|
||||
local mission=AUFTRAG:NewARTY(Target,120,Radius)
|
||||
|
||||
-- Add assets to mission.
|
||||
for _,asset in pairs(assets) do
|
||||
mission:AddAsset(asset)
|
||||
end
|
||||
|
||||
-- Assign mission to legions.
|
||||
self:MissionAssign(mission, legions)
|
||||
|
||||
-- Attach mission to ops zone.
|
||||
StratZone.opszone:_AddMission(self.coalition, MissionType, mission)
|
||||
|
||||
return true
|
||||
|
||||
mission=AUFTRAG:NewARTY(TargetCoord, 120, Radius)
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.ARMOREDGUARD then
|
||||
|
||||
---
|
||||
-- ARMORGUARD
|
||||
---
|
||||
|
||||
-- Create Armored on guard mission
|
||||
local TargetZone = StratZone.opszone.zone
|
||||
local Target = TargetZone:GetCoordinate()
|
||||
local mission=AUFTRAG:NewARMOREDGUARD(Target)
|
||||
|
||||
mission=AUFTRAG:NewARMOREDGUARD(TargetCoord)
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.BOMBCARPET then
|
||||
|
||||
---
|
||||
-- BOMB CARPET
|
||||
---
|
||||
|
||||
-- Create ARTY zone mission.
|
||||
mission=AUFTRAG:NewBOMBCARPET(TargetCoord, nil, 1000)
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.BOMBING then
|
||||
|
||||
---
|
||||
-- BOMBING
|
||||
---
|
||||
|
||||
local coord=TargetZone:GetRandomCoordinate()
|
||||
|
||||
mission=AUFTRAG:NewBOMBING(TargetCoord)
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.RECON then
|
||||
|
||||
---
|
||||
-- RECON
|
||||
---
|
||||
|
||||
mission=AUFTRAG:NewRECON(TargetZone, nil, 5000)
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.BARRAGE then
|
||||
|
||||
---
|
||||
-- BARRAGE
|
||||
---
|
||||
|
||||
mission=AUFTRAG:NewBARRAGE(TargetZone)
|
||||
|
||||
elseif MissionType==AUFTRAG.Type.AMMOSUPPLY then
|
||||
|
||||
---
|
||||
-- AMMO SUPPLY
|
||||
---
|
||||
|
||||
mission=AUFTRAG:NewAMMOSUPPLY(TargetZone)
|
||||
|
||||
end
|
||||
|
||||
if mission then
|
||||
|
||||
-- Add assets to mission.
|
||||
for _,asset in pairs(assets) do
|
||||
mission:AddAsset(asset)
|
||||
@ -2567,8 +2840,18 @@ function CHIEF:RecruitAssetsForZone(StratZone, MissionType, NassetsMin, NassetsM
|
||||
|
||||
-- Attach mission to ops zone.
|
||||
StratZone.opszone:_AddMission(self.coalition, MissionType, mission)
|
||||
|
||||
-- Attach mission to resource.
|
||||
Resource.mission=mission
|
||||
|
||||
return true
|
||||
return true
|
||||
else
|
||||
|
||||
-- Mission not supported.
|
||||
self:E(self.lid..string.format("ERROR: Mission type not supported for OPSZONE! Unrecruiting assets..."))
|
||||
LEGION.UnRecruitAssets(assets)
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -35,6 +35,8 @@
|
||||
-- @field #number Nkilled Number of destroyed asset groups.
|
||||
-- @field #number engageRange Mission range in meters.
|
||||
-- @field #string attribute Generalized attribute of the cohort template group.
|
||||
-- @field #table descriptors DCS descriptors.
|
||||
-- @field #table properties DCS attributes.
|
||||
-- @field #table tacanChannel List of TACAN channels available to the cohort.
|
||||
-- @field #number radioFreq Radio frequency in MHz the cohort uses.
|
||||
-- @field #number radioModu Radio modulation the cohort uses.
|
||||
@ -73,17 +75,20 @@ COHORT = {
|
||||
tacanChannel = {},
|
||||
weightAsset = 99999,
|
||||
cargobayLimit = 0,
|
||||
descriptors = {},
|
||||
properties = {},
|
||||
}
|
||||
|
||||
--- COHORT class version.
|
||||
-- @field #string version
|
||||
COHORT.version="0.1.0"
|
||||
COHORT.version="0.2.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Create FLOTILLA class.
|
||||
-- DONE: Added check for properties.
|
||||
-- DONE: Make general so that PLATOON and SQUADRON can inherit this class.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -127,6 +132,15 @@ function COHORT:New(TemplateGroupName, Ngroups, CohortName)
|
||||
|
||||
-- Aircraft type.
|
||||
self.aircrafttype=self.templategroup:GetTypeName()
|
||||
|
||||
-- Get descriptors.
|
||||
self.descriptors=self.templategroup:GetUnit(1):GetDesc()
|
||||
|
||||
-- Properties (DCS attributes).
|
||||
self.properties=self.descriptors.attributes
|
||||
|
||||
-- Print properties.
|
||||
--self:I(self.properties)
|
||||
|
||||
-- Defaults.
|
||||
self.Ngroups=Ngroups or 3
|
||||
@ -321,6 +335,21 @@ function COHORT:AddMissionCapability(MissionTypes, Performance)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Check if cohort assets have a given property (DCS attribute).
|
||||
-- @param #COHORT self
|
||||
-- @param #string Property The property.
|
||||
-- @return #boolean If `true`, cohort assets have the attribute.
|
||||
function COHORT:HasProperty(Property)
|
||||
|
||||
for _,property in pairs(self.properties) do
|
||||
if Property==property then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Get mission types this cohort is able to perform.
|
||||
-- @param #COHORT self
|
||||
-- @return #table Table of mission types. Could be empty {}.
|
||||
|
||||
@ -166,6 +166,20 @@ FLIGHTGROUP.Attribute = {
|
||||
OTHER="Other",
|
||||
}
|
||||
|
||||
--- Radio Text.
|
||||
-- @type FLIGHTGROUP.RadioText
|
||||
-- @field #string normal
|
||||
-- @field #string enhanced
|
||||
|
||||
--- Radio messages.
|
||||
-- @type FLIGHTGROUP.RadioMessage
|
||||
-- @field #FLIGHTGROUP.RadioText AIRBORNE
|
||||
-- @field #FLIGHTGROUP.RadioText TAXIING
|
||||
FLIGHTGROUP.RadioMessage = {
|
||||
AIRBORNE={normal="Airborn", enhanced="Airborn"},
|
||||
TAXIING={normal="Taxiing", enhanced="Taxiing"},
|
||||
}
|
||||
|
||||
--- FLIGHTGROUP class version.
|
||||
-- @field #string version
|
||||
FLIGHTGROUP.version="0.7.1"
|
||||
|
||||
@ -1964,10 +1964,11 @@ end
|
||||
-- @param #number TotalWeight Total cargo weight in kg.
|
||||
-- @param #table Categories Group categories.
|
||||
-- @param #table Attributes Group attributes. See `GROUP.Attribute.`
|
||||
-- @param #table Properties DCS attributes.
|
||||
-- @return #boolean If `true` enough assets could be recruited.
|
||||
-- @return #table Recruited assets. **NOTE** that we set the `asset.isReserved=true` flag so it cant be recruited by anyone else.
|
||||
-- @return #table Legions of recruited assets.
|
||||
function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, NreqMin, NreqMax, TargetVec2, Payloads, RangeMax, RefuelSystem, CargoWeight, TotalWeight, Categories, Attributes)
|
||||
function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, NreqMin, NreqMax, TargetVec2, Payloads, RangeMax, RefuelSystem, CargoWeight, TotalWeight, Categories, Attributes, Properties)
|
||||
|
||||
-- The recruited assets.
|
||||
local Assets={}
|
||||
@ -2006,7 +2007,26 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Function to check property.
|
||||
local function CheckProperty(_cohort)
|
||||
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
|
||||
if Property==property then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--BASE:I({Attributes=Attributes})
|
||||
--BASE:I({Properties=Properties})
|
||||
|
||||
-- Loops over cohorts.
|
||||
for _,_cohort in pairs(Cohorts) do
|
||||
@ -2045,12 +2065,15 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
|
||||
-- Right attribute.
|
||||
local RightAttribute=CheckAttribute(cohort)
|
||||
|
||||
-- Right property (DCS attribute).
|
||||
local RightProperty=CheckProperty(cohort)
|
||||
|
||||
-- Debug info.
|
||||
cohort:T(cohort.lid..string.format("State=%s: Capable=%s, InRange=%s, Refuel=%s, CanCarry=%s, RightCategory=%s, RightAttribute=%s",
|
||||
cohort:GetState(), tostring(Capable), tostring(InRange), tostring(Refuel), tostring(CanCarry), tostring(RightCategory), tostring(RightAttribute)))
|
||||
cohort:T2(cohort.lid..string.format("State=%s: Capable=%s, InRange=%s, Refuel=%s, CanCarry=%s, RightCategory=%s, RightAttribute=%s, RightProperty=%s",
|
||||
cohort:GetState(), tostring(Capable), tostring(InRange), tostring(Refuel), tostring(CanCarry), tostring(RightCategory), tostring(RightAttribute), tostring(RightProperty)))
|
||||
|
||||
-- Check OnDuty, capable, in range and refueling type (if TANKER).
|
||||
if cohort:IsOnDuty() and Capable and InRange and Refuel and CanCarry and RightCategory and RightAttribute then
|
||||
if cohort:IsOnDuty() and Capable and InRange and Refuel and CanCarry and RightCategory and RightAttribute and RightProperty then
|
||||
|
||||
-- Recruit assets from cohort.
|
||||
local assets, npayloads=cohort:RecruitAssets(MissionTypeRecruit, 999)
|
||||
@ -2100,7 +2123,7 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
|
||||
---
|
||||
-- Found enough assets
|
||||
---
|
||||
|
||||
|
||||
-- Add assets to mission.
|
||||
local cargobay=0
|
||||
for i=1,Nassets do
|
||||
|
||||
@ -3807,12 +3807,26 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
else
|
||||
-- FLIGHTGROUP not implemented (intended!) for this AUFTRAG type.
|
||||
end
|
||||
|
||||
---
|
||||
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.GROUNDATTACK then
|
||||
|
||||
---
|
||||
-- Task "Ground Attack" Mission.
|
||||
---
|
||||
|
||||
-- Engage target.
|
||||
local target=Task.dcstask.params.target --Ops.Target#TARGET
|
||||
|
||||
if target then
|
||||
self:EngageTarget(target)
|
||||
end
|
||||
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.HOVER then
|
||||
|
||||
---
|
||||
-- Task "Hover" Mission.
|
||||
---
|
||||
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.HOVER then
|
||||
|
||||
if self.isFlightgroup then
|
||||
self:T("We are Special Auftrag HOVER, hovering now ...")
|
||||
--self:I({Task.dcstask.params})
|
||||
@ -3836,6 +3850,7 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
local timer = TIMER:New(FlyOn,helo,Speed,CruiseAlt,Task)
|
||||
timer:Start(time)
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
-- If task is scheduled (not waypoint) set task.
|
||||
@ -3952,6 +3967,8 @@ function OPSGROUP:onafterTaskCancel(From, Event, To, Task)
|
||||
done=true
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ONGUARD or Task.dcstask.id==AUFTRAG.SpecialTask.ARMOREDGUARD then
|
||||
done=true
|
||||
elseif Task.dcstask.id==AUFTRAG.SpecialTask.GROUNDATTACK then
|
||||
done=true
|
||||
elseif stopflag==1 or (not self:IsAlive()) or self:IsDead() or self:IsStopped() then
|
||||
-- Manual call TaskDone if setting flag to one was not successful.
|
||||
done=true
|
||||
@ -4714,8 +4731,7 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
end
|
||||
|
||||
-- Get ingress waypoint.
|
||||
if mission.type==AUFTRAG.Type.PATROLZONE or mission.type==AUFTRAG.Type.BARRAGE or mission.type==AUFTRAG.Type.AMMOSUPPLY
|
||||
or mission.type.FUELSUPPLY then
|
||||
if mission.type==AUFTRAG.Type.PATROLZONE or mission.type==AUFTRAG.Type.BARRAGE or mission.type==AUFTRAG.Type.AMMOSUPPLY or mission.type.FUELSUPPLY then
|
||||
local zone=mission.engageTarget:GetObject() --Core.Zone#ZONE
|
||||
waypointcoord=zone:GetRandomCoordinate(nil , nil, surfacetypes)
|
||||
elseif mission.type==AUFTRAG.Type.ONGUARD or mission.type==AUFTRAG.Type.ARMOREDGUARD then
|
||||
|
||||
@ -587,14 +587,6 @@ function OPSZONE:onafterStop(From, Event, To)
|
||||
|
||||
-- Unhandle events.
|
||||
self:UnHandleEvent(EVENTS.BaseCaptured)
|
||||
|
||||
-- Cancel all running missions.
|
||||
for _,_entry in pairs(self.Missions or {}) do
|
||||
local entry = _entry -- Ops.OpsZone#OPSZONE.MISSION
|
||||
if entry.Mission and entry.Mission:IsNotOver() then
|
||||
entry.Mission:Cancel()
|
||||
end
|
||||
end
|
||||
|
||||
-- Stop FSM scheduler.
|
||||
self.CallScheduler:Clear()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user