diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index f38c71d8e..e7e2a0a5c 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -4039,7 +4039,7 @@ function WAREHOUSE:onafterAddAsset(From, Event, To, group, ngroups, forceattribu self:_DebugMessage(string.format("Removing group %s", group:GetName()), 5) local opsgroup=_DATABASE:GetOpsGroup(group:GetName()) - if opsgroup then + if opsgroup then opsgroup:Despawn(0, true) opsgroup:__Stop(-0.01) else @@ -5452,6 +5452,55 @@ function WAREHOUSE:onafterAssetDead(From, Event, To, asset, request) local text=string.format("Asset %s from request id=%d is dead!", asset.templatename, request.uid) self:T(self.lid..text) self:_DebugMessage(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 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 + + end @@ -6556,7 +6605,8 @@ function WAREHOUSE:_OnEventCrashOrDead(EventData) end end - --self:I(self.lid..string.format("Warehouse %s captured event dead or crash or unit %s.", self.alias, tostring(EventData.IniUnitName))) + -- Debug info. + self:T2(self.lid..string.format("Warehouse %s captured event dead or crash or unit %s", self.alias, tostring(EventData.IniUnitName))) -- Check if an asset unit was destroyed. if EventData.IniGroup then @@ -6571,7 +6621,7 @@ function WAREHOUSE:_OnEventCrashOrDead(EventData) if wid==self.uid then -- Debug message. - self:T(self.lid..string.format("Warehouse %s captured event dead or crash of its asset unit %s.", self.alias, EventData.IniUnitName)) + self:T(self.lid..string.format("Warehouse %s captured event dead or crash of its asset unit %s", self.alias, EventData.IniUnitName)) -- Loop over all pending requests and get the one belonging to this unit. for _,request in pairs(self.pending) do @@ -6581,7 +6631,7 @@ function WAREHOUSE:_OnEventCrashOrDead(EventData) if request.uid==rid then -- Update cargo and transport group sets of this request. We need to know if this job is finished. - self:_UnitDead(EventData.IniUnit, request) + self:_UnitDead(EventData.IniUnit, EventData.IniGroup, request) end end @@ -6594,38 +6644,51 @@ end -- This is important in order to determine if a job is done and can be removed from the (pending) queue. -- @param #WAREHOUSE self -- @param Wrapper.Unit#UNIT deadunit Unit that died. +-- @param Wrapper.Group#GROUP deadgroup Group of unit that died. -- @param #WAREHOUSE.Pendingitem request Request that needs to be updated. -function WAREHOUSE:_UnitDead(deadunit, request) +function WAREHOUSE:_UnitDead(deadunit, deadgroup, request) + --env.info("FF unit dead "..deadunit:GetName()) - -- Flare unit. - if self.Debug then - deadunit:FlareRed() - end - - -- Group the dead unit belongs to. - local group=deadunit:GetGroup() - - -- Number of alive units in group. - local nalive=group:CountAliveUnits() - - -- Whole group is dead? - local groupdead=true - if nalive>0 then - groupdead=false + -- Find asset. + local asset=self:FindAssetInDB(deadgroup) + + -- Find opsgroup. + local opsgroup=_DATABASE:FindOpsGroup(deadgroup) + + local groupdead=false + if opsgroup then + + if opsgroup:IsDead() then + groupdead=true + end + + else + + -- Number of alive units in group. + local nalive=deadgroup:CountAliveUnits() + + -- Whole group is dead? + if nalive>0 then + groupdead=false + else + groupdead=true + end + end + -- Here I need to get rid of the #CARGO at the end to obtain the original name again! local unitname=self:_GetNameWithOut(deadunit) - local groupname=self:_GetNameWithOut(group) + local groupname=self:_GetNameWithOut(deadgroup) -- Group is dead! if groupdead then - self:T(self.lid..string.format("Group %s (transport=%s) is dead!", groupname, tostring(self:_GroupIsTransport(group,request)))) + -- Debug output. + self:T(self.lid..string.format("Group %s (transport=%s) is dead!", groupname, tostring(self:_GroupIsTransport(deadgroup,request)))) if self.Debug then - group:SmokeWhite() + deadgroup:SmokeWhite() end - -- Trigger AssetDead event. - local asset=self:FindAssetInDB(group) + -- Trigger AssetDead event. self:AssetDead(asset, request) end @@ -6633,19 +6696,7 @@ function WAREHOUSE:_UnitDead(deadunit, request) -- 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. - if groupdead==true then - request.cargogroupset:Remove(groupname, NoTriggerEvent) - self:T(self.lid..string.format("Removed selfpropelled cargo %s: ncargo=%d.", groupname, request.cargogroupset:Count())) - end - - else + if not request.transporttype==WAREHOUSE.TransportType.SELFPROPELLED then --- -- Complicated case: Dead unit could be: @@ -6653,10 +6704,7 @@ function WAREHOUSE:_UnitDead(deadunit, request) -- 2.) A Transport unit which itself holds cargo groups. --- - -- Check if this a cargo or transport group. - local istransport=self:_GroupIsTransport(group,request) - - if istransport==true then + if not asset.iscargo then -- Get the carrier unit table holding the cargo groups inside this carrier. local cargogroupnames=request.carriercargo[unitname] @@ -6671,25 +6719,8 @@ function WAREHOUSE:_UnitDead(deadunit, request) end - -- Whole carrier group is dead. Remove it from the carrier group set. - if groupdead then - request.transportgroupset:Remove(groupname, NoTriggerEvent) - self:T(self.lid..string.format("Removed transport %s: ntransport=%d", groupname, request.transportgroupset:Count())) - end - - 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. - if groupdead==true then - 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) - end - else - self:E(self.lid..string.format("ERROR: Group %s is neither cargo nor transport!", group:GetName())) + self:E(self.lid..string.format("ERROR: Group %s is neither cargo nor transport!", deadgroup:GetName())) end end @@ -8056,57 +8087,12 @@ end -- @return #number Request ID. function WAREHOUSE:_GetIDsFromGroup(group) - ---@param #string text The text to analyse. - local function analyse(text) - - -- Get rid of #0001 tail from spawn. - local unspawned=UTILS.Split(text, "#")[1] - - -- Split keywords. - local keywords=UTILS.Split(unspawned, "_") - local _wid=nil -- warehouse UID - local _aid=nil -- asset UID - local _rid=nil -- request UID - - -- Loop over keys. - for _,keys in pairs(keywords) do - local str=UTILS.Split(keys, "-") - local key=str[1] - local val=str[2] - if key:find("WID") then - _wid=tonumber(val) - elseif key:find("AID") then - _aid=tonumber(val) - elseif key:find("RID") then - _rid=tonumber(val) - end - end - - return _wid,_aid,_rid - end - if group then - + -- Group name - local name=group:GetName() - - -- Get asset id from group name. - local wid,aid,rid=analyse(name) - - -- Get Asset. - local asset=self:GetAssetByID(aid) - - -- Get warehouse and request id from asset table. - if asset then - wid=asset.wid - rid=asset.rid - end - - -- Debug info - self:T3(self.lid..string.format("Group Name = %s", tostring(name))) - self:T3(self.lid..string.format("Warehouse ID = %s", tostring(wid))) - self:T3(self.lid..string.format("Asset ID = %s", tostring(aid))) - self:T3(self.lid..string.format("Request ID = %s", tostring(rid))) + local groupname=group:GetName() + + local wid, aid, rid=self:_GetIDsFromGroupName(groupname) return wid,aid,rid else @@ -8115,14 +8101,13 @@ function WAREHOUSE:_GetIDsFromGroup(group) end - --- Get warehouse id, asset id and request id from group name (alias). -- @param #WAREHOUSE self --- @param Wrapper.Group#GROUP group The group from which the info is gathered. +-- @param #string groupname Name of the group from which the info is gathered. -- @return #number Warehouse ID. -- @return #number Asset ID. -- @return #number Request ID. -function WAREHOUSE:_GetIDsFromGroupOLD(group) +function WAREHOUSE:_GetIDsFromGroupName(groupname) ---@param #string text The text to analyse. local function analyse(text) @@ -8153,25 +8138,26 @@ function WAREHOUSE:_GetIDsFromGroupOLD(group) return _wid,_aid,_rid end - if group then - -- Group name - local name=group:GetName() + -- Get asset id from group name. + local wid,aid,rid=analyse(groupname) - -- Get ids - local wid,aid,rid=analyse(name) + -- Get Asset. + local asset=self:GetAssetByID(aid) - -- Debug info - self:T3(self.lid..string.format("Group Name = %s", tostring(name))) - self:T3(self.lid..string.format("Warehouse ID = %s", tostring(wid))) - self:T3(self.lid..string.format("Asset ID = %s", tostring(aid))) - self:T3(self.lid..string.format("Request ID = %s", tostring(rid))) - - return wid,aid,rid - else - self:E("WARNING: Group not found in GetIDsFromGroup() function!") + -- Get warehouse and request id from asset table. + if asset then + wid=asset.wid + rid=asset.rid end + -- Debug info + self:T3(self.lid..string.format("Group Name = %s", tostring(groupname))) + self:T3(self.lid..string.format("Warehouse ID = %s", tostring(wid))) + self:T3(self.lid..string.format("Asset ID = %s", tostring(aid))) + self:T3(self.lid..string.format("Request ID = %s", tostring(rid))) + + return wid,aid,rid end --- Filter stock assets by descriptor and attribute. diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 08d316299..c50df7056 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -384,6 +384,7 @@ _AUFTRAGSNR=0 -- @field #string ARMOREDGUARD On guard - with armored groups. -- @field #string BARRAGE Barrage. -- @field #string ARMORATTACK Armor attack. +-- @field #string CASENHANCED Enhanced CAS. AUFTRAG.Type={ ANTISHIP="Anti Ship", AWACS="AWACS", @@ -416,6 +417,7 @@ AUFTRAG.Type={ ARMOREDGUARD="Armored Guard", BARRAGE="Barrage", ARMORATTACK="Armor Attack", + CASENHANCED="CAS Enhanced", } --- Mission status of an assigned group. @@ -558,7 +560,7 @@ AUFTRAG.Category={ --- AUFTRAG class version. -- @field #string version -AUFTRAG.version="0.8.2" +AUFTRAG.version="0.8.3" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -1187,6 +1189,45 @@ function AUFTRAG:NewCAS(ZoneCAS, Altitude, Speed, Coordinate, Heading, Leg, Targ return mission end +--- **[AIR]** Create a CASENHANCED mission. Group(s) will go to the zone and patrol it randomly. +-- @param #AUFTRAG self +-- @param Core.Zone#ZONE CasZone The CAS zone. +-- @param #number Altitude Altitude in feet. Only for airborne units. Default 2000 feet ASL. +-- @param #number Speed Speed in knots. +-- @param #number RangeMax Max range in NM. Only detected targets within this radius from the group will be engaged. Default is 25 NM. +-- @param #table TargetTypes Types of target attributes that will be engaged. See [DCS enum attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes). Default `{"Helicopters", "Ground Units", "Light armed ships"}`. +-- @param Core.Set#SET_ZONE NoEngageZoneSet Set of zones in which targets are *not* engaged. Default is nowhere. +-- @return #AUFTRAG self +function AUFTRAG:NewCASENHANCED(CasZone, Altitude, Speed, RangeMax, NoEngageZoneSet, TargetTypes) + + local mission=AUFTRAG:New(AUFTRAG.Type.CASENHANCED) + + -- Ensure we got a ZONE and not just the zone name. + if type(CasZone)=="string" then + CasZone=ZONE:New(CasZone) + end + + mission:_TargetFromObject(CasZone) + + mission.missionTask=mission:GetMissionTaskforMissionType(AUFTRAG.Type.CASENHANCED) + + mission:SetEngageDetected(RangeMax, TargetTypes or {"Helicopters", "Ground Units", "Light armed ships"}, CasZone, NoEngageZoneSet) + + mission.optionROE=ENUMS.ROE.OpenFire + mission.optionROT=ENUMS.ROT.EvadeFire + + mission.missionFraction=1.0 + mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or nil + mission.missionAltitude=Altitude and UTILS.FeetToMeters(Altitude) or nil + + mission.categories={AUFTRAG.Category.AIRCRAFT} + + mission.DCStask=mission:GetDCSMissionTask() + + return mission +end + + --- **[AIR]** Create a FACA mission. -- @param #AUFTRAG self -- @param Wrapper.Group#GROUP Target Target group. Must be a GROUP object. @@ -1678,6 +1719,7 @@ function AUFTRAG:NewPATROLZONE(Zone, Speed, Altitude) return mission end + --- **[GROUND]** Create a ARMORATTACK mission. Armoured ground group(s) will go to the zone and attack. -- @param #AUFTRAG self -- @param Wrapper.Positionable#POSITIONABLE Target The target to attack. Can be a GROUP, UNIT or STATIC object. @@ -4942,6 +4984,26 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable) DCStask.params=param table.insert(DCStasks, DCStask) + + elseif self.type==AUFTRAG.Type.CASENHANCED then + + ------------------------- + -- CAS ENHANCED Mission -- + ------------------------- + + local DCStask={} + + DCStask.id="PatrolZone" + + -- We create a "fake" DCS task and pass the parameters to the FLIGHTGROUP. + local param={} + param.zone=self:GetObjective() + param.altitude=self.missionAltitude + param.speed=self.missionSpeed + + DCStask.params=param + + table.insert(DCStasks, DCStask) elseif self.type==AUFTRAG.Type.ARMORATTACK then @@ -5131,6 +5193,8 @@ function AUFTRAG:GetMissionTaskforMissionType(MissionType) mtask=ENUMS.MissionTask.CAS elseif MissionType==AUFTRAG.Type.PATROLZONE then mtask=ENUMS.MissionTask.CAS + elseif MissionType==AUFTRAG.Type.CASENHANCED then + mtask=ENUMS.MissionTask.CAS elseif MissionType==AUFTRAG.Type.ESCORT then mtask=ENUMS.MissionTask.ESCORT elseif MissionType==AUFTRAG.Type.FACA then diff --git a/Moose Development/Moose/Ops/Chief.lua b/Moose Development/Moose/Ops/Chief.lua index 7ba916181..3519b48a7 100644 --- a/Moose Development/Moose/Ops/Chief.lua +++ b/Moose Development/Moose/Ops/Chief.lua @@ -103,7 +103,7 @@ -- -- Strategically important zones, which should be captured can be added via the @{#CHIEF.AddStrategicZone}() function. -- --- If the zone is currently owned by another coalition and enemy ground troops are present in the zone, a CAS mission is lauchned. +-- 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. -- -- 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. @@ -1731,7 +1731,7 @@ function CHIEF:CheckOpsZoneQueue() -- 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.CAS) + local hasMissionCAS=stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.CASENHANCED) -- Has a ARTY mission? local hasMissionARTY=stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.ARTY) @@ -1775,12 +1775,13 @@ function CHIEF:CheckOpsZoneQueue() -- Recruite CAS assets. - local recruited=self:RecruitAssetsForZone(stratzone, AUFTRAG.Type.CAS, 1, 1) + 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 not hasMissionARTY then -- Debug message. @@ -1811,7 +1812,7 @@ function CHIEF:CheckOpsZoneQueue() local hasMissionPATROL=stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.PATROLZONE) -- Has a CAS mission? - local hasMissionCAS, CASMissions = stratzone.opszone:_FindMissions(self.coalition,AUFTRAG.Type.CAS) + 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 @@ -2260,12 +2261,48 @@ function CHIEF:RecruitAssetsForZone(StratZone, MissionType, NassetsMin, NassetsM -- 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 else LEGION.UnRecruitAssets(assets) return false end + + elseif MissionType==AUFTRAG.Type.CASENHANCED then + + -- Create Patrol zone mission. + local caszone = StratZone.opszone.zone + local coord = caszone:GetCoordinate() + local height = UTILS.MetersToFeet(coord: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 + + --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. diff --git a/Moose Development/Moose/Ops/Cohort.lua b/Moose Development/Moose/Ops/Cohort.lua index 9dc2a66d5..3780cbf07 100644 --- a/Moose Development/Moose/Ops/Cohort.lua +++ b/Moose Development/Moose/Ops/Cohort.lua @@ -919,36 +919,38 @@ function COHORT:RecruitAssets(MissionType, Npayloads) -- ARMY/NAVYGROUP combat ready? --- + -- Disable this for now as it can cause problems - at least with transport and cargo assets. + --self:I("Attribute is: "..asset.attribute) + if flightgroup:IsArmygroup() then + -- check for fighting assets + if asset.attribute == WAREHOUSE.Attribute.GROUND_ARTILLERY or + asset.attribute == WAREHOUSE.Attribute.GROUND_TANK or + asset.attribute == WAREHOUSE.Attribute.GROUND_INFANTRY or + asset.attribute == WAREHOUSE.Attribute.GROUND_AAA or + asset.attribute == WAREHOUSE.Attribute.GROUND_SAM + then + combatready=true + end + else + combatready=false + end + + -- Not ready when rearming, retreating or returning! if flightgroup:IsRearming() or flightgroup:IsRetreating() or flightgroup:IsReturning() then combatready=false end end - -- Check transport/cargo for combat readyness! + -- Not ready when currently acting as ops transport carrier. if flightgroup:IsLoading() or flightgroup:IsTransporting() or flightgroup:IsUnloading() or flightgroup:IsPickingup() or flightgroup:IsCarrier() then combatready=false - end + end + -- Not ready when currently acting as ops transport cargo. if flightgroup:IsCargo() or flightgroup:IsBoarding() or flightgroup:IsAwaitingLift() then combatready=false end - - -- Disable this for now as it can cause problems - at least with transport and cargo assets. - --self:I("Attribute is: "..asset.attribute) - if flightgroup:IsArmygroup() then - -- check for fighting assets - if asset.attribute == WAREHOUSE.Attribute.GROUND_ARTILLERY or - asset.attribute == WAREHOUSE.Attribute.GROUND_TANK or - asset.attribute == WAREHOUSE.Attribute.GROUND_INFANTRY or - asset.attribute == WAREHOUSE.Attribute.GROUND_AAA or - asset.attribute == WAREHOUSE.Attribute.GROUND_SAM - then - combatready=true - end - else - combatready=false - end - + -- This asset is "combatready". if combatready then self:T(self.lid.."Adding SPAWNED asset to ANOTHER mission as it is COMBATREADY") diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index bec5b72c6..7073651da 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -81,6 +81,10 @@ function LEGION:New(WarehouseName, LegionName) -- Defaults: -- TODO: What? self:SetMarker(false) + + -- Dead and crash events are handled via opsgroups. + self:UnHandleEvent(EVENTS.Crash) + self:UnHandleEvent(EVENTS.Dead) -- Add FSM transitions. -- From State --> Event --> To State @@ -882,7 +886,18 @@ function LEGION:onafterTransportCancel(From, Event, To, Transport) local cargos=Transport:GetCargoOpsGroups(false) for _,_cargo in pairs(cargos) do local cargo=_cargo --Ops.OpsGroup#OPSGROUP + + -- Remover my lift. cargo:_DelMyLift(Transport) + + -- Legion of cargo group + local legion=cargo.legion + + -- Add asset back to legion. + if legion then + legion:T(self.lid..string.format("Adding cargo group %s back to legion", cargo:GetName())) + legion:__AddAsset(0.1, cargo.group, 1) + end end -- Remove asset from mission. @@ -993,7 +1008,7 @@ function LEGION:onafterNewAsset(From, Event, To, asset, assignment) -- Debug text. local text=string.format("New asset %s with assignment %s and request assignment %s", asset.spawngroupname, tostring(asset.assignment), tostring(assignment)) - self:T3(self.lid..text) + self:T(self.lid..text) -- Get cohort. local cohort=self:_GetCohort(asset.assignment) @@ -1061,6 +1076,8 @@ function LEGION:onafterNewAsset(From, Event, To, asset, assignment) -- Asset is returned to the COHORT --- + self:T(self.lid..string.format("Asset returned to legion ==> calling LegionAssetReturned event")) + -- Trigger event. self:LegionAssetReturned(cohort, asset) @@ -1078,7 +1095,7 @@ end -- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset that returned. function LEGION:onafterLegionAssetReturned(From, Event, To, Cohort, Asset) -- Debug message. - self:T(self.lid..string.format("Asset %s from Cohort %s returned! asset.assignment=\"%s\"", Asset.spawngroupname, Cohort.name, tostring(Asset.assignment))) + self:I(self.lid..string.format("Asset %s from Cohort %s returned! asset.assignment=\"%s\"", Asset.spawngroupname, Cohort.name, tostring(Asset.assignment))) -- Stop flightgroup. if Asset.flightgroup and not Asset.flightgroup:IsStopped() then @@ -1246,7 +1263,7 @@ function LEGION:onafterAssetDead(From, Event, To, asset, request) -- Remove group from the detection set of the CHIEF (INTEL). if self.commander and self.commander.chief then self.commander.chief.detectionset:RemoveGroupsByName({asset.spawngroupname}) - end + end -- Remove asset from mission is done via Mission:AssetDead() call from flightgroup onafterFlightDead function -- Remove asset from squadron same @@ -2396,12 +2413,34 @@ function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, Inclu -- Reduce score for legions that are futher away. score=score-distance - -- Intercepts need to be carried out quickly. We prefer spawned assets. - --if MissionType==AUFTRAG.Type.INTERCEPT then - if asset.spawned then - score=score+25 + -- Intercepts need to be carried out quickly. We prefer spawned assets. + if asset.spawned and asset.flightgroup and asset.flightgroup:IsAlive() then + + local currmission=asset.flightgroup:GetMissionCurrent() + + if currmission then + + if currmission.type==AUFTRAG.Type.ALERT5 and currmission.alert5MissionType==MissionType then + -- Prefer assets that are on ALERT5 for this mission type. + score=score+25 + elseif currmission==AUFTRAG.Type.GCICAP and MissionType==AUFTRAG.Type.INTERCEPT then + -- Prefer assets that are on GCICAP to perform INTERCEPTS + score=score+25 + end end - --end + + if MissionType==AUFTRAG.Type.OPSTRANSPORT or MissionType==AUFTRAG.Type.AMMOSUPPLY or MissionType==AUFTRAG.Type.AWACS or MissionType==AUFTRAG.Type.FUELSUPPLY or MissionType==AUFTRAG.Type.TANKER then + -- TODO: need to check for missions that do not require ammo like transport, recon, awacs, tanker etc. + -- We better take a fresh asset. Sometimes spawned assets to something else, which is difficult to check. + score=score-10 + else + -- Combat mission. + if asset.flightgroup:IsOutOfAmmo() then + -- Assets that are out of ammo are not considered. + score=score-1000 + end + end + end -- TRANSPORT specific. if MissionType==AUFTRAG.Type.OPSTRANSPORT then diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 7ab4996bf..4b427a81f 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -3673,7 +3673,6 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task) -- BARRAGE is special! if Task.dcstask.id==AUFTRAG.SpecialTask.BARRAGE then - env.info("FF Barrage") local vec2=self:GetVec2() local param=Task.dcstask.params local heading=param.heading or math.random(1, 360) @@ -4230,7 +4229,7 @@ function OPSGROUP:onafterMissionStart(From, Event, To, Mission) -- IMMOBILE Group --- - env.info("FF Immobile GROUP") + --env.info("FF Immobile GROUP") -- Add waypoint task. UpdateRoute is called inside. local Clock=Mission.Tpush and UTILS.SecondsToClock(Mission.Tpush) or 5 @@ -5768,6 +5767,32 @@ function OPSGROUP:onafterElementInUtero(From, Event, To, Element) end +--- On after "ElementDamaged" event. +-- @param #OPSGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #OPSGROUP.Element Element The flight group element. +function OPSGROUP:onafterElementDamaged(From, Event, To, Element) + self:T(self.lid..string.format("Element damaged %s", Element.name)) + + if Element and Element.status~=OPSGROUP.ElementStatus.DEAD then + + local lifepoints=Element.DCSunit:getLife() + local lifepoint0=Element.DCSunit:getLife0() + + self:T(self.lid..string.format("Element life %s: %.2f/%.2f", Element.name, lifepoints, lifepoint0)) + + if lifepoints<=1.0 then + self:T(self.lid..string.format("Element %s life %.2f <= 1.0 ==> Destroyed!", Element.name, lifepoints)) + self:ElementDestroyed(Element) + end + + end + +end + + --- On after "ElementDestroyed" event. -- @param #OPSGROUP self -- @param #string From From state. @@ -5802,10 +5827,18 @@ end function OPSGROUP:onafterElementDead(From, Event, To, Element) -- Debug info. - self:T(self.lid..string.format("Element dead %s at t=%.3f", Element.name, timer.getTime())) + self:I(self.lid..string.format("Element dead %s at t=%.3f", Element.name, timer.getTime())) -- Set element status. self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD) + + if self.legion then + if not self:IsInUtero() then + local asset=self.legion:GetAssetByName(self.groupname) + local request=self.legion:GetRequestByID(asset.rid) + self.legion:_UnitDead(Element.unit, self.group, request) + end + end -- Check if element was lasing and if so, switch to another unit alive to lase. if self.spot.On and self.spot.element.name==Element.name then @@ -6140,12 +6173,18 @@ function OPSGROUP:onafterDead(From, Event, To) -- All elements were destroyed ==> Asset group is gone. self.cohort:DelGroup(self.groupname) end + if self.legion then + --self.legion:Get + --self.legion:AssetDead() + end else -- Not all assets were destroyed (despawn) ==> Add asset back to legion? end - -- Stop in a sec. - --self:__Stop(-5) + -- Stop in 5 sec to give possible respawn attempts a chance. + if self.legion then + self:__Stop(-5) + end end --- On before "Stop" event. @@ -6187,6 +6226,11 @@ function OPSGROUP:onafterStop(From, Event, To) self:UnHandleEvent(EVENTS.Crash) self.currbase=nil end + + for _,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + self:MissionCancel(mission) + end -- Stop check timers. self.timerCheckZone:Stop() diff --git a/Moose Development/Moose/Ops/OpsTransport.lua b/Moose Development/Moose/Ops/OpsTransport.lua index c15154747..7940c17d7 100644 --- a/Moose Development/Moose/Ops/OpsTransport.lua +++ b/Moose Development/Moose/Ops/OpsTransport.lua @@ -57,6 +57,8 @@ -- @field #table statusLegion Transport status of all assigned LEGIONs. -- @field #string statusCommander Staus of the COMMANDER. -- @field Ops.Commander#COMMANDER commander Commander of the transport. +-- @field Ops.Chief#CHIEF chief Chief of the transport. +-- @field Ops.OpsZone#OPSZONE opszone OPS zone. -- @field #table requestID The ID of the queued warehouse request. Necessary to cancel the request if the transport was cancelled before the request is processed. -- -- @extends Core.Fsm#FSM @@ -1305,7 +1307,7 @@ function OPSTRANSPORT:GetNcarrier() return self.Ncarrier end ---- Add asset to transport. +--- Add carrier asset to transport. -- @param #OPSTRANSPORT self -- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset to be added. -- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo. @@ -1323,7 +1325,7 @@ function OPSTRANSPORT:AddAsset(Asset, TransportZoneCombo) return self end ---- Delete asset from mission. +--- Delete carrier asset from transport. -- @param #OPSTRANSPORT self -- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset to be removed. -- @return #OPSTRANSPORT self @@ -1736,12 +1738,12 @@ function OPSTRANSPORT:onafterDeadCarrierGroup(From, Event, To, OpsGroup) -- Increase dead counter. self.NcarrierDead=self.NcarrierDead+1 - if #self.carriers==0 then - self:DeadCarrierAll() - end - -- Remove group from carrier list/table. self:_DelCarrier(OpsGroup) + + if #self.carriers==0 then + self:DeadCarrierAll() + end end --- On after "DeadCarrierAll" event. @@ -1750,15 +1752,30 @@ end -- @param #string Event Event. -- @param #string To To state. function OPSTRANSPORT:onafterDeadCarrierAll(From, Event, To) - self:I(self.lid..string.format("ALL Carrier OPSGROUPs are dead! Setting stage to PLANNED if not all cargo was delivered.")) + self:I(self.lid..string.format("ALL Carrier OPSGROUPs are dead!")) + + if self.opszone then + + self:I(self.lid..string.format("Cancelling transport on CHIEF level")) + self.chief:TransportCancel(self) + + --for _,_legion in pairs(self.legions) do + -- local legion=_legion --Ops.Legion#LEGION + -- legion:TransportCancel(self) + --end + + else - -- Check if cargo was delivered. - self:_CheckDelivered() + -- Check if cargo was delivered. + self:_CheckDelivered() + + -- Set state back to PLANNED if not delivered. + if not self:IsDelivered() then + self:Planned() + end - -- Set state back to PLANNED if not delivered. - if not self:IsDelivered() then - self:Planned() end + end --- On after "Cancel" event.