diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index 1555b3229..e1eb895ac 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -463,12 +463,12 @@ function AIRWING:FetchPayloadFromStock(UnitType, MissionType, Payloads) -- Debug. if self.verbose>=4 then - self:I(self.lid..string.format("Sorted payloads for mission type X and aircraft type=Y:")) + self:I(self.lid..string.format("Sorted payloads for mission type %s and aircraft type=%s:", MissionType, UnitType)) for _,_payload in ipairs(self.payloads) do local payload=_payload --#AIRWING.Payload if payload.aircrafttype==UnitType and self:CheckMissionCapability(MissionType, payload.capabilities) then local performace=self:GetPayloadPeformance(payload, MissionType) - self:I(self.lid..string.format("FF %s payload for %s: avail=%d performace=%d", MissionType, payload.aircrafttype, payload.navail, performace)) + self:I(self.lid..string.format("- %s payload for %s: avail=%d performace=%d", MissionType, payload.aircrafttype, payload.navail, performace)) end end end @@ -476,7 +476,7 @@ function AIRWING:FetchPayloadFromStock(UnitType, MissionType, Payloads) -- Cases: if #payloads==0 then -- No payload available. - self:T(self.lid.."Warning could not find a payload for airframe X mission type Y!") + self:T(self.lid..string.format("WARNING: Could not find a payload for airframe %s mission type %s!", UnitType, MissionType)) return nil elseif #payloads==1 then -- Only one payload anyway. diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index d45c51332..84cfec085 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -3420,6 +3420,9 @@ function AUFTRAG:onafterRepeat(From, Event, To) self.Ncasualties=0 self.Nelements=0 + -- Update DCS mission task. Could be that the initial task (e.g. for bombing) was destroyed. Then we need to update the coordinate. + self.DCStask=self:GetDCSMissionTask() + -- Call status again. self:__Status(-30) diff --git a/Moose Development/Moose/Ops/Chief.lua b/Moose Development/Moose/Ops/Chief.lua index 255cb9f4f..008e71b85 100644 --- a/Moose Development/Moose/Ops/Chief.lua +++ b/Moose Development/Moose/Ops/Chief.lua @@ -182,6 +182,26 @@ function CHIEF:New(AgentSet, Coalition) -- @param #string To To state. -- @param Ops.Auftrag#AUFTRAG Mission The mission. + + --- Triggers the FSM event "TransportCancel". + -- @function [parent=#CHIEF] TransportCancel + -- @param #CHIEF self + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- Triggers the FSM event "TransportCancel" after a delay. + -- @function [parent=#CHIEF] TransportCancel + -- @param #CHIEF self + -- @param #number delay Delay in seconds. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- On after "TransportCancel" event. + -- @function [parent=#CHIEF] OnAfterTransportCancel + -- @param #CHIEF self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + return self end @@ -672,6 +692,33 @@ function CHIEF:onafterMissionCancel(From, Event, To, Mission) end +--- On after "TransportCancel" event. +-- @param #CHIEF self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. +function CHIEF:onafterTransportCancel(From, Event, To, Transport) + + -- Debug info. + self:I(self.lid..string.format("Cancelling transport UID=%d in status %s", Transport.uid, Transport:GetState())) + + if Transport:IsPlanned() then + + -- Mission is still in planning stage. Should not have any LEGIONS assigned ==> Just remove it form the COMMANDER queue. + self:RemoveTransport(Transport) + + else + + -- COMMANDER will cancel mission. + if Transport.commander then + Transport.commander:TransportCancel(Transport) + end + + end + +end + --- On before "Defcon" event. -- @param #CHIEF self -- @param #string From From state. diff --git a/Moose Development/Moose/Ops/Commander.lua b/Moose Development/Moose/Ops/Commander.lua index f8776fa98..a739f045c 100644 --- a/Moose Development/Moose/Ops/Commander.lua +++ b/Moose Development/Moose/Ops/Commander.lua @@ -572,6 +572,43 @@ function COMMANDER:onafterTransportAssign(From, Event, To, Legion, Transport) end +--- On after "TransportCancel" event. +-- @param #COMMANDER self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. +function COMMANDER:onafterTransportCancel(From, Event, To, Transport) + + -- Debug info. + self:I(self.lid..string.format("Cancelling Transport UID=%d in status %s", Transport.uid, Transport:GetState())) + + -- Set commander status. + Transport.statusCommander=OPSTRANSPORT.Status.CANCELLED + + if Transport:IsPlanned() then + + -- Transport is still in planning stage. Should not have a legion assigned ==> Just remove it form the queue. + self:RemoveTransport(Transport) + + else + + -- Legion will cancel mission. + if #Transport.legions>0 then + for _,_legion in pairs(Transport.legions) do + local legion=_legion --Ops.Legion#LEGION + + -- TODO: Should check that this legions actually belongs to this commander. + + -- Legion will cancel the mission. + legion:TransportCancel(Transport) + end + end + + end + +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Mission Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -689,7 +726,7 @@ function COMMANDER:RecruitAssets(Mission) MissionType=Mission.alert5MissionType end Npayloads[cohort.aircrafttype]=legion:IsAirwing() and legion:CountPayloadsInStock(MissionType, cohort.aircrafttype, Mission.payloads) or 999 - self:I(self.lid..string.format("Got N=%d payloads for mission type %s [%s]", Npayloads[cohort.aircrafttype], MissionType, cohort.aircrafttype)) + self:T2(self.lid..string.format("Got N=%d payloads for mission type %s [%s]", Npayloads[cohort.aircrafttype], MissionType, cohort.aircrafttype)) end end @@ -728,16 +765,16 @@ function COMMANDER:RecruitAssets(Mission) if not asset.payload then -- Set mission type. - local MissionType=Mission.Type + local MissionType=Mission.type -- Get a loadout for the actual mission this group is waiting for. if Mission.type==AUFTRAG.Type.ALERT5 and Mission.alert5MissionType then MissionType=Mission.alert5MissionType - end - + end + -- Fetch payload for asset. This can be nil! asset.payload=asset.legion:FetchPayloadFromStock(asset.unittype, MissionType, Mission.payloads) - + end end @@ -748,6 +785,7 @@ function COMMANDER:RecruitAssets(Mission) for i=#Assets,1,-1 do local asset=Assets[i] --Functional.Warehouse#WAREHOUSE.Assetitem if asset.legion:IsAirwing() and not asset.payload then + self:T3(self.lid..string.format("Remove asset %s with no payload", tostring(asset.spawngroupname))) table.remove(Assets, i) end end @@ -791,13 +829,12 @@ function COMMANDER:RecruitAssets(Mission) --- -- Return payloads of assets. - if self:IsAirwing() then - for i=1,#Assets do - local asset=Assets[i] --Functional.Warehouse#WAREHOUSE.Assetitem - if asset.legion:IsAirwing() and not asset.spawned then - self:T2(self.lid..string.format("Returning payload from asset %s", asset.spawngroupname)) - asset.legion:ReturnPayloadFromAsset(asset) - end + + for i=1,#Assets do + local asset=Assets[i] --Functional.Warehouse#WAREHOUSE.Assetitem + if asset.legion:IsAirwing() and not asset.spawned then + self:T2(self.lid..string.format("Returning payload from asset %s", asset.spawngroupname)) + asset.legion:ReturnPayloadFromAsset(asset) end end @@ -972,7 +1009,7 @@ function COMMANDER:RecruitAssetsForTransport(Transport) local cohort=_cohort --Ops.Cohort#COHORT if Npayloads[cohort.aircrafttype]==nil then Npayloads[cohort.aircrafttype]=legion:IsAirwing() and legion:CountPayloadsInStock(AUFTRAG.Type.OPSTRANSPORT, cohort.aircrafttype) or 999 - self:I(self.lid..string.format("Got N=%d payloads for mission type %s [%s]", Npayloads[cohort.aircrafttype], AUFTRAG.Type.OPSTRANSPORT, cohort.aircrafttype)) + self:T2(self.lid..string.format("Got N=%d payloads for mission type %s [%s]", Npayloads[cohort.aircrafttype], AUFTRAG.Type.OPSTRANSPORT, cohort.aircrafttype)) end end diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index 96de22712..be466cc7c 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -84,6 +84,7 @@ function LEGION:New(WarehouseName, LegionName) self:AddTransition("*", "MissionCancel", "*") -- Cancel mission. self:AddTransition("*", "TransportRequest", "*") -- Add a (mission) request to the warehouse. + self:AddTransition("*", "TransportCancel", "*") -- Cancel transport. self:AddTransition("*", "OpsOnMission", "*") -- An OPSGROUP was send on a Mission (AUFTRAG). @@ -171,6 +172,26 @@ function LEGION:New(WarehouseName, LegionName) -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + --- Triggers the FSM event "TransportCancel". + -- @function [parent=#LEGION] TransportCancel + -- @param #LEGION self + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- Triggers the FSM event "TransportCancel" after a delay. + -- @function [parent=#LEGION] __TransportCancel + -- @param #LEGION self + -- @param #number delay Delay in seconds. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- On after "TransportCancel" event. + -- @function [parent=#LEGION] OnAfterTransportCancel + -- @param #LEGION self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- Triggers the FSM event "OpsOnMission". -- @function [parent=#LEGION] OpsOnMission -- @param #LEGION self @@ -671,6 +692,50 @@ function LEGION:onafterTransportRequest(From, Event, To, OpsTransport) end +--- On after "TransportCancel" event. +-- @param #LEGION self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport to be cancelled. +function LEGION:onafterTransportCancel(From, Event, To, Transport) + + -- Info message. + self:I(self.lid..string.format("Cancel transport UID=%d", Transport.uid)) + + -- Set status to cancelled. + Transport:SetLegionStatus(self, OPSTRANSPORT.Status.CANCELLED) + + for i=#Transport.assets, 1, -1 do + local asset=Transport.assets[i] --Functional.Warehouse#WAREHOUSE.Assetitem + + -- Asset should belong to this legion. + if asset.wid==self.uid then + + local opsgroup=asset.flightgroup + + if opsgroup then + opsgroup:TransportCancel(Transport) + end + + -- Remove asset from mission. + Transport:DelAsset(asset) + + -- Not requested any more (if it was). + asset.requested=nil + asset.isReserved=nil + + end + end + + -- Remove queued request (if any). + if Transport.requestID[self.alias] then + self:_DeleteQueueItemByID(Transport.requestID[self.alias], self.queue) + end + +end + + --- On after "MissionCancel" event. Cancels the missions of all flightgroups. Deletes request from warehouse queue. -- @param #LEGION self -- @param #string From From state. @@ -1625,7 +1690,7 @@ function LEGION:RecruitAssets(Mission) if not asset.payload then -- Set mission type. - local MissionType=Mission.Type + local MissionType=Mission.type -- Get a loadout for the actual mission this group is waiting for. if Mission.type==AUFTRAG.Type.ALERT5 and Mission.alert5MissionType then @@ -1729,7 +1794,7 @@ function LEGION:CalculateAssetMissionScore(asset, Mission, includePayload) end -- Add mission performance to score. - score=score+asset.cohort:GetMissionPeformance(Mission.Type) + score=score+asset.cohort:GetMissionPeformance(Mission.type) -- Add payload performance to score. if includePayload and asset.payload then diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 3fcc7f0eb..ee5501cf9 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -659,7 +659,7 @@ function OPSGROUP:New(group) self:AddTransition("*", "MissionStart", "*") -- Mission is started. self:AddTransition("*", "MissionExecute", "*") -- Mission execution began. - self:AddTransition("*", "MissionCancel", "*") -- Cancel current mission. + self:AddTransition("*", "MissionCancel", "*") -- Cancel current mission. self:AddTransition("*", "PauseMission", "*") -- Pause the current mission. self:AddTransition("*", "UnpauseMission", "*") -- Unpause the the paused mission. self:AddTransition("*", "MissionDone", "*") -- Mission is over. @@ -684,6 +684,8 @@ function OPSGROUP:New(group) self:AddTransition("*", "Unloaded", "*") -- Carrier unloaded all its current cargo. self:AddTransition("*", "UnloadingDone", "*") -- Carrier is unloading the cargo. self:AddTransition("*", "Delivered", "*") -- Carrier delivered ALL cargo of the transport assignment. + + self:AddTransition("*", "TransportCancel", "*") -- Cancel (current) transport. ------------------------ --- Pseudo Functions --- @@ -786,6 +788,26 @@ function OPSGROUP:New(group) -- @param #string To To state. -- @param Ops.Auftrag#AUFTRAG Mission The mission. + + --- Triggers the FSM event "TransportCancel". + -- @function [parent=#OPSGROUP] TransportCancel + -- @param #OPSGROUP self + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- Triggers the FSM event "TransportCancel" after a delay. + -- @function [parent=#OPSGROUP] __TransportCancel + -- @param #OPSGROUP self + -- @param #number delay Delay in seconds. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- On after "TransportCancel" event. + -- @function [parent=#OPSGROUP] OnAfterTransportCancel + -- @param #OPSGROUP self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + -- TODO: Add pseudo functions. return self @@ -6206,11 +6228,17 @@ function OPSGROUP:DelOpsTransport(CargoTransport) for i=#self.cargoqueue,1,-1 do local transport=self.cargoqueue[i] --Ops.OpsTransport#OPSTRANSPORT if transport.uid==CargoTransport.uid then + + -- Remove from queue. table.remove(self.cargoqueue, i) + + -- Remove carrier from ops transport. + CargoTransport:_DelCarrier(self) + return self end end - + return self end @@ -7445,6 +7473,112 @@ function OPSGROUP:onafterDelivered(From, Event, To, CargoTransport) end +--- On after "TransportCancel" event. +-- @param #OPSGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Ops.OpsTransport#OPSTRANSPORT The transport to be cancelled. +function OPSGROUP:onafterTransportCancel(From, Event, To, Transport) + + if self.cargoTransport and self.cargoTransport.uid==Transport.uid then + + --- + -- Current Transport + --- + + -- Debug info. + self:T(self.lid..string.format("Cancel current transport %d", Transport.uid)) + + -- Call delivered= + local calldelivered=false + + if self:IsPickingup() then + + -- On its way to the pickup zone. Remove waypoint. Will be done in delivered. + calldelivered=true + + elseif self:IsLoading() then + + -- Handle cargo groups. + local cargos=Transport:GetCargoOpsGroups(false) + + for _,_opsgroup in pairs(cargos) do + local opsgroup=_opsgroup --#OPSGROUP + + if opsgroup:IsBoarding(self.groupname) then + + -- Remove boarding waypoint. + opsgroup:RemoveWaypoint(self.currentwp+1) + + -- Remove from cargo bay (reserved), remove mycarrier, set cargo status. + self:_DelCargobay(opsgroup) + opsgroup:_RemoveMyCarrier() + opsgroup:_NewCargoStatus(OPSGROUP.CargoStatus.NOTCARGO) + + elseif opsgroup:IsLoaded(self.groupname) then + + -- Get random point in disembark zone. + local zoneCarrier=self:GetElementZoneUnload(opsgroup:_GetMyCarrierElement().name) + + -- Random coordinate/heading in the zone. + local Coordinate=zoneCarrier and zoneCarrier:GetRandomCoordinate() or self.cargoTransport:GetEmbarkZone(self.cargoTZC):GetRandomCoordinate() + + -- Random heading of the group. + local Heading=math.random(0,359) + + -- Unload to Coordinate. + self:Unload(opsgroup, Coordinate, self.cargoTransport:GetDisembarkActivation(self.cargoTZC), Heading) + + -- Trigger "Unloaded" event for current cargo transport + self.cargoTransport:Unloaded(opsgroup, self) + + end + + end + + -- Call delivered. + calldelivered=true + + elseif self:IsTransporting() then + + -- Well, we cannot just unload the cargo anywhere. + + -- TODO: Best would be to bring the cargo back to the pickup zone! + + elseif self:IsUnloading() then + -- Unloading anyway... delivered will be called when done. + else + + end + + -- Transport delivered. + if calldelivered then + self:Delivered(Transport) + end + + else + + --- + -- NOT the current transport + --- + + -- Set mission group status. + --Transport:SetGroupStatus(self, AUFTRAG.GroupStatus.CANCELLED) + + -- Remove transport from queue. + self:DelOpsTransport(Transport) + + -- Remove carrier. + Transport:_DelCarrier(self) + + -- Send group RTB or WAIT if nothing left to do. + self:_CheckGroupDone(1) + + end + +end + --- -- Cargo Group Functions diff --git a/Moose Development/Moose/Ops/OpsTransport.lua b/Moose Development/Moose/Ops/OpsTransport.lua index d33453ad9..87352904b 100644 --- a/Moose Development/Moose/Ops/OpsTransport.lua +++ b/Moose Development/Moose/Ops/OpsTransport.lua @@ -250,6 +250,8 @@ function OPSTRANSPORT:New(CargoGroups, PickupZone, DeployZone) self:AddTransition("*", "Status", "*") self:AddTransition("*", "Stop", "*") + self:AddTransition("*", "Cancel", OPSTRANSPORT.Status.CANCELLED) -- Command to cancel the transport. + self:AddTransition("*", "Loaded", "*") self:AddTransition("*", "Unloaded", "*") @@ -331,6 +333,26 @@ function OPSTRANSPORT:New(CargoGroups, PickupZone, DeployZone) -- @param #number delay Delay in seconds. + --- Triggers the FSM event "Cancel". + -- @function [parent=#OPSTRANSPORT] Cancel + -- @param #OPSTRANSPORT self + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- Triggers the FSM event "Cancel" after a delay. + -- @function [parent=#OPSTRANSPORT] __Cancel + -- @param #OPSTRANSPORT self + -- @param #number delay Delay in seconds. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- On after "Cancel" event. + -- @function [parent=#OPSTRANSPORT] OnAfterCancel + -- @param #OPSTRANSPORT self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport. + + --- Triggers the FSM event "Loaded". -- @function [parent=#OPSTRANSPORT] Loaded -- @param #OPSTRANSPORT self @@ -348,7 +370,7 @@ function OPSTRANSPORT:New(CargoGroups, PickupZone, DeployZone) --- On after "Loaded" event. -- @function [parent=#OPSTRANSPORT] OnAfterLoaded - -- @param #OPSGROUP self + -- @param #OPSTRANSPORT self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. @@ -372,7 +394,7 @@ function OPSTRANSPORT:New(CargoGroups, PickupZone, DeployZone) --- On after "Unloaded" event. -- @function [parent=#OPSTRANSPORT] OnAfterUnloaded - -- @param #OPSGROUP self + -- @param #OPSTRANSPORT self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. @@ -1616,6 +1638,74 @@ function OPSTRANSPORT:onafterDeadCarrierAll(From, Event, To) end end +--- On after "Cancel" event. +-- @param #OPSTRANSPORT self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function OPSTRANSPORT:onafterCancel(From, Event, To) + + -- Number of OPSGROUPS assigned and alive. + local Ngroups = #self.carriers + + -- Debug info. + self:I(self.lid..string.format("CANCELLING mission in status %s. Will wait for %d groups to report mission DONE before evaluation", self.status, Ngroups)) + + -- Time stamp. + self.Tover=timer.getAbsTime() + + + if self.chief then + + -- Debug info. + self:T(self.lid..string.format("CHIEF will cancel the transport. Will wait for mission DONE before evaluation!")) + + -- CHIEF will cancel the transport. + self.chief:TransportCancel(self) + + elseif self.commander then + + -- Debug info. + self:T(self.lid..string.format("COMMANDER will cancel the transport. Will wait for transport DELIVERED before evaluation!")) + + -- COMMANDER will cancel the transport. + self.commander:TransportCancel(self) + + elseif self.legions and #self.legions>0 then + + -- Loop over all LEGIONs. + for _,_legion in pairs(self.legions or {}) do + local legion=_legion --Ops.Legion#LEGION + + -- Debug info. + self:T(self.lid..string.format("LEGION %s will cancel the transport. Will wait for transport DELIVERED before evaluation!", legion.alias)) + + -- Legion will cancel all flight missions and remove queued request from warehouse queue. + legion:TransportCancel(self) + + end + + else + + -- Debug info. + self:T(self.lid..string.format("No legion, commander or chief. Attached OPS groups will cancel the transport on their own. Will wait for transport DELIVERED before evaluation!")) + + -- Loop over all carrier groups. + for _,_carrier in pairs(self:GetCarriers()) do + local carrier=_carrier --Ops.OpsGroup#OPSGROUP + carrier:TransportCancel(self) + end + + end + + -- Special mission states. + if self:IsPlanned() or self:IsQueued() or self:IsRequested() or Ngroups==0 then + self:T(self.lid..string.format("Cancelled transport was in %s stage with %d carrier groups assigned and alive. Call it DELIVERED!", self.status, Ngroups)) + self:Delivered() + end + +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Misc Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1653,11 +1743,10 @@ function OPSTRANSPORT:_CheckDelivered() end if dead then - --self:CargoDead() - self:I(self.lid.."All cargo DEAD!") + self:I(self.lid.."All cargo DEAD ==> Delivered!") self:Delivered() elseif done then - self:I(self.lid.."All cargo delivered") + self:I(self.lid.."All cargo DONE ==> Delivered!") self:Delivered() end