diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 26cef4db9..6283a28b3 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -5810,6 +5810,7 @@ function WAREHOUSE:_SpawnAssetRequest(Request) -- Now we try to find all parking spots for all cargo groups in advance. Due to the for loop, the parking spots do not get updated while spawning. local Parking={} if Request.cargocategory==Group.Category.AIRPLANE or Request.cargocategory==Group.Category.HELICOPTER then + --TODO: Check for airstart. Should be a request property. Parking=self:_FindParkingForAssets(self.airbase, cargoassets) or {} end @@ -6069,7 +6070,9 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol end if self.Debug then - coord:MarkToAll(string.format("Spawnplace unit %s terminal %d.", unit.name, terminal)) + local text=string.format("Spawnplace unit %s terminal %d.", unit.name, terminal) + coord:MarkToAll(text) + env.info(text) end unit.x=coord.x @@ -7374,6 +7377,7 @@ function WAREHOUSE:_CheckRequestNow(request) local _transports local _assetattribute local _assetcategory + local _assetairstart=false -- Check if at least one (cargo) asset is available. if _nassets>0 then @@ -7381,21 +7385,28 @@ function WAREHOUSE:_CheckRequestNow(request) -- Get the attibute of the requested asset. _assetattribute=_assets[1].attribute _assetcategory=_assets[1].category + _assetairstart=_assets[1].takeoffType and _assets[1].takeoffType==COORDINATE.WaypointType.TurningPoint or false -- Check available parking for air asset units. if _assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER then if self.airbase and self.airbase:GetCoalition()==self:GetCoalition() then - if self:IsRunwayOperational() then + if self:IsRunwayOperational() or _assetairstart then - local Parking=self:_FindParkingForAssets(self.airbase,_assets) - - --if Parking==nil and not (self.category==Airbase.Category.HELIPAD) then - if Parking==nil then - local text=string.format("Warehouse %s: Request denied! Not enough free parking spots for all requested assets at the moment.", self.alias) - self:_InfoMessage(text, 5) - return false + if _assetairstart then + -- Airstart no need to check parking + else + + -- Check parking. + local Parking=self:_FindParkingForAssets(self.airbase,_assets) + + -- No parking? + if Parking==nil then + local text=string.format("Warehouse %s: Request denied! Not enough free parking spots for all requested assets at the moment.", self.alias) + self:_InfoMessage(text, 5) + return false + end end else @@ -7986,9 +7997,36 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets) local gotit=false for _,_parkingspot in pairs(parkingdata) do local parkingspot=_parkingspot --Wrapper.Airbase#AIRBASE.ParkingSpot + + -- Parking valid? + local valid=true + + if asset.parkingIDs then + -- If asset has assigned parking spots, we take these no matter what. + valid=self:_CheckParkingAsset(parkingspot, asset) + else + + -- Valid terminal type depending on attribute. + local validTerminal=AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) + + -- Valid parking list. + local validParking=self:_CheckParkingValid(parkingspot) + + -- Black and white list. + local validBWlist=airbase:_CheckParkingLists(parkingspot.TerminalID) + + -- Debug info. + --env.info(string.format("FF validTerminal = %s", tostring(validTerminal))) + --env.info(string.format("FF validParking = %s", tostring(validParking))) + --env.info(string.format("FF validBWlist = %s", tostring(validBWlist))) + + -- Check if all are true + valid=validTerminal and validParking and validBWlist + end + -- Check correct terminal type for asset. We don't want helos in shelters etc. - if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) and self:_CheckParkingValid(parkingspot) and self:_CheckParkingAsset(parkingspot, asset) and airbase:_CheckParkingLists(parkingspot.TerminalID) then + if valid then -- Coordinate of the parking spot. local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index 0dae8cb06..fe0d22de5 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -863,7 +863,7 @@ function AIRWING:SetAirboss(airboss) return self end ---- Set takeoff type. All assets of this squadron will be spawned with cold (default) or hot engines. +--- Set takeoff type. All assets of this airwing will be spawned with this takeoff type. -- Spawning on runways is not supported. -- @param #AIRWING self -- @param #string TakeoffType Take off type: "Cold" (default) or "Hot" with engines on or "Air" for spawning in air. diff --git a/Moose Development/Moose/Ops/Chief.lua b/Moose Development/Moose/Ops/Chief.lua index b83e3c352..fe60fed48 100644 --- a/Moose Development/Moose/Ops/Chief.lua +++ b/Moose Development/Moose/Ops/Chief.lua @@ -188,7 +188,8 @@ -- --- 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) +-- -- NOTE that two objects are returned, the resource list (ResourceOccupied) and the first resource of that list (resourceCAS). +-- local ResourceOccupied, resourceCAS=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. @@ -197,14 +198,17 @@ -- myChief:AddToResource(ResourceOccupied, AUFTRAG.Type.BOMBCARPET, 1, 2) -- -- --- Create a resource list of mission types and required assets for the case that the zone is EMPTY. --- -- +-- -- NOTE that two objects are returned, the resource list (ResourceEmpty) and the first resource of that list (resourceInf). -- -- 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) +-- local ResourceEmpty, resourceInf=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) -- +-- -- Add a transport to the infantry resource. We want at least one and up to two transport helicopters. +-- myChief:AddTransportToResource(resourceInf, 1, 2, GROUP.Attribute.AIR_TRANSPORTHELO) +-- -- -- Add stratetic zone with customized reaction. -- myChief:AddStrategicZone(myOpsZone, nil , 2, ResourceOccupied, ResourceEmpty) -- @@ -315,12 +319,10 @@ CHIEF.Strategy = { -- @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 #table Categories Categories Group categories. -- @field Ops.Auftrag#AUFTRAG mission Attached mission. -- @field #number carrierNmin Min number of assets. -- @field #number carrierNmax Max number of assets. --- @field #table cargoCategories Group categories. --- @field #table cargoAttributes Generalized attribute, e.g. `{GROUP.Attribute.GROUND_INFANTRY}`. --- @field #table cargoProperties Properties ([DCS attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes)), e.g. `"Attack helicopters"` or `"Mobile AAA"`. -- @field #table carrierCategories Group categories. -- @field #table carrierAttributes Generalized attribute, e.g. `{GROUP.Attribute.GROUND_INFANTRY}`. -- @field #table carrierProperties Properties ([DCS attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes)), e.g. `"Attack helicopters"` or `"Mobile AAA"`. @@ -328,12 +330,13 @@ CHIEF.Strategy = { --- CHIEF class version. -- @field #string version -CHIEF.version="0.5.1" +CHIEF.version="0.5.3" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- TODO: Event when asset groups die. -- TODO: PLAYERTASK integration. -- DONE: Let user specify amount of resources. -- DONE: Tactical overview. @@ -751,13 +754,14 @@ end -- @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`. +-- @param #table Categories Group categories. -- @return #CHIEF.Resources The newly created resource list table. -- @return #CHIEF.Resource The resource object that was added. -function CHIEF:CreateResource(MissionType, Nmin, Nmax, Attributes, Properties) +function CHIEF:CreateResource(MissionType, Nmin, Nmax, Attributes, Properties, Categories) local resources={} - local resource=self:AddToResource(resources, MissionType, Nmin, Nmax, Attributes, Properties) + local resource=self:AddToResource(resources, MissionType, Nmin, Nmax, Attributes, Properties, Categories) return resources, resource end @@ -770,21 +774,20 @@ end -- @param #number Nmax Max number of requried assets. Default equal `Nmin`. -- @param #table Attributes Generalized attribute(s). -- @param #table Properties DCS attribute(s). Default `nil`. +-- @param #table Categories Group categories. -- @return #CHIEF.Resource Resource table. -function CHIEF:AddToResource(Resource, MissionType, Nmin, Nmax, Attributes, Properties) +function CHIEF:AddToResource(Resource, MissionType, Nmin, Nmax, Attributes, Properties, Categories) -- Create new resource table. local resource={} --#CHIEF.Resource resource.MissionType=MissionType resource.Nmin=Nmin or 1 resource.Nmax=Nmax or Nmin - resource.Attributes=UTILS.EnsureTable(Attributes) - resource.Properties=UTILS.EnsureTable(Properties) + resource.Attributes=UTILS.EnsureTable(Attributes, true) + resource.Properties=UTILS.EnsureTable(Properties, true) + resource.Categories=UTILS.EnsureTable(Categories, true) -- Transport carrier parameters. - resource.cargoAttributes=nil - resource.cargoProperties=nil - resource.cargoCategories=nil resource.carrierNmin=nil resource.carrierNmax=nil resource.carrierAttributes=nil @@ -810,25 +813,19 @@ end --- Define which assets will be transported and define the number and attributes/properties of the cargo carrier assets. -- @param #CHIEF self -- @param #CHIEF.Resource Resource Resource table. --- @param #table CargoAttributes Generalized attribute(s) of the cargo assets. --- @param #table CargoProperties DCS attribute(s) of the cargo assets. --- @param #table CargoCategories Group categories of the cargo assets. -- @param #number Nmin Min number of required assets. Default 1. -- @param #number Nmax Max number of requried assets. Default is equal to `Nmin`. -- @param #table CarrierAttributes Generalized attribute(s) of the carrier assets. -- @param #table CarrierProperties DCS attribute(s) of the carrier assets. -- @param #table CarrierCategories Group categories of the carrier assets. -- @return #CHIEF self -function CHIEF:AddTransportToResource(Resource, CargoAttributes, CargoProperties, CargoCategories, Nmin, Nmax, CarrierAttributes, CarrierProperties, CarrierCategories) +function CHIEF:AddTransportToResource(Resource, Nmin, Nmax, CarrierAttributes, CarrierProperties, CarrierCategories) - Resource.cargoCategories=CargoCategories - Resource.cargoAttributes=CargoAttributes - Resource.cargoProperties=CargoProperties Resource.carrierNmin=Nmin or 1 Resource.carrierNmax=Nmax or Nmin - Resource.carrierCategories=CarrierCategories - Resource.carrierAttributes=CarrierAttributes - Resource.carrierProperties=CarrierProperties + Resource.carrierCategories=UTILS.EnsureTable(CarrierCategories, true) + Resource.carrierAttributes=UTILS.EnsureTable(CarrierAttributes, true) + Resource.carrierProperties=UTILS.EnsureTable(CarrierProperties, true) return self end @@ -1277,7 +1274,7 @@ function CHIEF:AddStrategicZone(OpsZone, Priority, Importance, ResourceOccupied, local resourceEmpty, resourceInfantry=self:CreateResource(AUFTRAG.Type.ONGUARD, 1, 3, GROUP.Attribute.GROUND_INFANTRY) self:AddToResource(resourceEmpty, AUFTRAG.Type.ONGUARD, 0, 1, GROUP.Attribute.GROUND_TANK) self:AddToResource(resourceEmpty, AUFTRAG.Type.ONGUARD, 0, 1, GROUP.Attribute.GROUND_IFV) - self:AddTransportToResource(resourceInfantry, GROUP.Attribute.GROUND_INFANTRY, nil, nil, 0, 1, {GROUP.Attribute.AIR_TRANSPORTHELO, GROUP.Attribute.GROUND_APC}) + self:AddTransportToResource(resourceInfantry, 0, 1, {GROUP.Attribute.AIR_TRANSPORTHELO, GROUP.Attribute.GROUND_APC}) stratzone.resourceEmpty=resourceEmpty end @@ -1613,7 +1610,7 @@ end -- @param #CHIEF self -- @return #CHIEF self function CHIEF:AllowGroundTransport() - env.warning("WARNING: CHIEF:AllowGroundTransport() is depricated and will be removed in the future!") + env.warning("WARNING: CHIEF:AllowGroundTransport() is deprecated and will be removed in the future!") self.TransportCategories = {Group.Category.GROUND, Group.Category.HELICOPTER} return self end @@ -1622,7 +1619,7 @@ end -- @param #CHIEF self -- @return #CHIEF self function CHIEF:ForbidGroundTransport() - env.warning("WARNING: CHIEF:ForbidGroundTransport() is depricated and will be removed in the future!") + env.warning("WARNING: CHIEF:ForbidGroundTransport() is deprecated and will be removed in the future!") self.TransportCategories = {Group.Category.HELICOPTER} return self end @@ -2559,7 +2556,7 @@ function CHIEF:CheckOpsZoneQueue() 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)) + 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) @@ -2969,13 +2966,13 @@ function CHIEF:RecruitAssetsForZone(StratZone, Resource) if Resource.carrierNmin and Resource.carrierNmax and Resource.carrierNmax>0 then -- Filter only those assets that shall be transported. - local cargoassets=CHIEF._FilterAssets(assets, Resource.cargoCategories, Resource.cargoAttributes, Resource.cargoProperties) + local cargoassets=CHIEF._FilterAssets(assets, Resource.Categories, Resource.Attributes, Resource.Properties) if #cargoassets>0 then -- Recruit transport carrier assets. recruited, transport=LEGION.AssignAssetsForTransport(self.commander, self.commander.legions, cargoassets, - Resource.carrierNmin, Resource.carrierNmax, TargetZone, nil, Resource.carrierCategories, Resource.carrierAttributes) + Resource.carrierNmin, Resource.carrierNmax, TargetZone, nil, Resource.carrierCategories, Resource.carrierAttributes, Resource.carrierProperties) end diff --git a/Moose Development/Moose/Ops/Cohort.lua b/Moose Development/Moose/Ops/Cohort.lua index 4c059b639..9b748e992 100644 --- a/Moose Development/Moose/Ops/Cohort.lua +++ b/Moose Development/Moose/Ops/Cohort.lua @@ -504,6 +504,37 @@ function COHORT:SetCallsign(Callsign, Index) return self end +--- Set generalized attribute. +-- @param #COHORT self +-- @param #string Attribute Generalized attribute, e.g. `GROUP.Attribute.Ground_Infantry`. +-- @return #COHORT self +function COHORT:SetAttribute(Attribute) + self.attribute=Attribute + return self +end + +--- Get generalized attribute. +-- @param #COHORT self +-- @return #string Generalized attribute, e.g. `GROUP.Attribute.Ground_Infantry`. +function COHORT:GetAttribute() + return self.attribute +end + +--- Get group category. +-- @param #COHORT self +-- @return #string Group category +function COHORT:GetCategory() + return self.category +end + +--- Get properties, *i.e.* DCS attributes. +-- @param #COHORT self +-- @return #table Properties table. +function COHORT:GetProperties() + return self.properties +end + + --- Set modex. -- @param #COHORT self -- @param #number Modex A number like 100. diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index d2e0574e9..80fdf1e9e 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -2640,13 +2640,16 @@ end -- @param #number NcarriersMax Max number of carrier assets. -- @param Core.Zone#ZONE DeployZone Deploy zone. -- @param Core.Zone#ZONE DisembarkZone (Optional) Disembark zone. +-- @param #table Categories Group categories. +-- @param #table Attributes Generalizes group attributes. +-- @param #table Properties DCS attributes. -- @return #boolean If `true`, enough assets could be recruited and an OPSTRANSPORT object was created. -- @return Ops.OpsTransport#OPSTRANSPORT Transport The transport. -function LEGION:AssignAssetsForTransport(Legions, CargoAssets, NcarriersMin, NcarriersMax, DeployZone, DisembarkZone, Categories, Attributes) +function LEGION:AssignAssetsForTransport(Legions, CargoAssets, NcarriersMin, NcarriersMax, DeployZone, DisembarkZone, Categories, Attributes, Properties) -- Is an escort requested in the first place? if NcarriersMin and NcarriersMax and (NcarriersMin>0 or NcarriersMax>0) then - + -- Cohorts. local Cohorts={} for _,_legion in pairs(Legions) do @@ -2682,10 +2685,10 @@ function LEGION:AssignAssetsForTransport(Legions, CargoAssets, NcarriersMin, Nca -- Recruit assets and legions. local TransportAvail, CarrierAssets, CarrierLegions= - LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.OPSTRANSPORT, nil, NcarriersMin, NcarriersMax, TargetVec2, nil, nil, nil, CargoWeight, TotalWeight, Categories, Attributes) + LEGION.RecruitCohortAssets(Cohorts, AUFTRAG.Type.OPSTRANSPORT, nil, NcarriersMin, NcarriersMax, TargetVec2, nil, nil, nil, CargoWeight, TotalWeight, Categories, Attributes, Properties) if TransportAvail then - + -- Create and OPSTRANSPORT assignment. local Transport=OPSTRANSPORT:New(nil, nil, DeployZone) if DisembarkZone then @@ -2732,6 +2735,9 @@ function LEGION:AssignAssetsForTransport(Legions, CargoAssets, NcarriersMin, Nca -- Got transport. return true, Transport else + -- Debug info. + self:T(self.lid..string.format("Transport assets could not be allocated ==> Unrecruiting assets")) + -- Uncrecruit transport assets. LEGION.UnRecruitAssets(CarrierAssets) return false, nil diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 214bf8a69..704eca831 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -2019,15 +2019,21 @@ end --- Ensure the passed object is a table. -- @param #table Object The object that should be a table. --- @return #table The object that is a table. Note that if the Object is `#nil` initially, and empty table `{}` is returned. -function UTILS.EnsureTable(Object) +-- @param #boolean ReturnNil If `true`, return `#nil` if `Object` is nil. Otherwise an empty table `{}` is returned. +-- @return #table The object that now certainly *is* a table. +function UTILS.EnsureTable(Object, ReturnNil) if Object then if type(Object)~="table" then Object={Object} end else - Object={} + if ReturnNil then + return nil + else + Object={} + end + end return Object