diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 0a6522bcf..29afa533d 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -4250,11 +4250,10 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) -- Get stock item. local _assetitem=_assetstock[i] --#WAREHOUSE.Assetitem - -- Create an alias name with the UIDs for the sending warehouse, asset and request. - --local _alias=self:_alias(_assetitem.unittype, self.uid, _assetitem.uid, Request.uid) - + -- Spawn group name local _alias=_assetitem.spawngroupname + -- Set Request ID. _assetitem.rid=Request.uid -- Asset is transport. @@ -5374,11 +5373,11 @@ function WAREHOUSE:_SpawnAssetRequest(Request) -- Set asset status to not spawned until we capture its birth event. asset.spawned=false asset.iscargo=true + + -- Set request ID. asset.rid=Request.uid - -- Alias of the group. - --local _alias=self:_Alias(asset, Request) - + -- Spawn group name. local _alias=asset.spawngroupname -- Spawn an asset group. @@ -7594,25 +7593,32 @@ end -- @return #boolean True if group is transport, false if group is cargo and nil otherwise. function WAREHOUSE:_GroupIsTransport(group, request) - -- Name of the group under question. - local groupname=self:_GetNameWithOut(group) + local asset=self:FindAssetInDB(group) + + if asset and asset.iscargo~=nil then + return not asset.iscargo + else - if request.transportgroupset then - local transporters=request.transportgroupset:GetSetObjects() - - for _,transport in pairs(transporters) do - if transport:GetName()==groupname then - return true + -- Name of the group under question. + local groupname=self:_GetNameWithOut(group) + + if request.transportgroupset then + local transporters=request.transportgroupset:GetSetObjects() + + for _,transport in pairs(transporters) do + if transport:GetName()==groupname then + return true + end end end - end - - if request.cargogroupset then - local cargos=request.cargogroupset:GetSetObjects() - - for _,cargo in pairs(cargos) do - if self:_GetNameWithOut(cargo)==groupname then - return false + + if request.cargogroupset then + local cargos=request.cargogroupset:GetSetObjects() + + for _,cargo in pairs(cargos) do + if self:_GetNameWithOut(cargo)==groupname then + return false + end end end end @@ -7621,35 +7627,12 @@ function WAREHOUSE:_GroupIsTransport(group, request) end ---- Creates a unique name for spawned assets. From the group name the original warehouse, global asset and the request can be derived. --- @param #WAREHOUSE self --- @param #WAREHOUSE.Assetitem _assetitem Asset for which the name is created. --- @param #WAREHOUSE.Queueitem _queueitem (Optional) Request specific name. --- @return #string Alias name "UnitType\_WID-%d\_AID-%d\_RID-%d" -function WAREHOUSE:_Alias(_assetitem,_queueitem) - return self:_alias(_assetitem.unittype, self.uid, _assetitem.uid,_queueitem.uid) -end - ---- Creates a unique name for spawned assets. From the group name the original warehouse, global asset and the request can be derived. --- @param #WAREHOUSE self --- @param #string unittype Type of unit. --- @param #number wid Warehouse id. --- @param #number aid Asset item id. --- @param #number qid Queue/request item id. --- @return #string Alias name "UnitType\_WID-%d\_AID-%d\_RID-%d" -function WAREHOUSE:_alias(unittype, wid, aid, qid) - local _alias=string.format("%s_WID-%d_AID-%d", unittype, wid, aid) - if qid then - _alias=_alias..string.format("_RID-%d", qid) - end - return _alias -end - --- Get group name without any spawn or cargo suffix #CARGO etc. -- @param #WAREHOUSE self -- @param Wrapper.Group#GROUP group The group from which the info is gathered. -- @return #string Name of the object without trailing #... function WAREHOUSE:_GetNameWithOut(group) + if group then local name if type(group)=="string" then @@ -7657,18 +7640,23 @@ function WAREHOUSE:_GetNameWithOut(group) else name=group:GetName() end - local namewithout=UTILS.Split(name, "#")[1] + + local namewithout=UTILS.Split(name, "#CARGO")[1] + if namewithout then return namewithout else return name end end + + if type(group)=="string" then return group else return group:GetName() end + end diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index 53df9815a..85479930a 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -131,8 +131,7 @@ function AIRWING:New(warehousename, airwingname) -- Add FSM transitions. -- From State --> Event --> To State self:AddTransition("*", "MissionRequest", "*") -- Add a (mission) request to the warehouse. - self:AddTransition("*", "MissionDone", "*") -- Mission is over. - self:AddTransition("*", "MissionCancel", "*") -- Mission is over. + self:AddTransition("*", "MissionCancel", "*") -- Cancel mission. ------------------------ --- Pseudo Functions --- @@ -223,6 +222,11 @@ function AIRWING:NewPayload(Unit, MissionTypes, Npayloads, Unlimited) if Unit:IsInstanceOf("GROUP") then Unit=Unit:GetUnit(1) end + + -- Ensure Missiontypes is a table. + if MissionTypes and type(MissionTypes)~="table" then + MissionTypes={MissionTypes} + end if Unit then @@ -512,6 +516,13 @@ function AIRWING:onafterStatus(From, Event, To) text=text..string.format("\n -[%d] %s*%d: spawned=%s, mission=%s%s", j, typename, asset.nunits, spawned, tostring(self:IsAssetOnMission(asset)), missiontext) + local payload=asset.payload + if payload then + text=text.." payload "..table.concat(payload.missiontypes, ", ") + else + text=text.." NO payload!" + end + end end self:I(self.lid..text) @@ -798,6 +809,10 @@ function AIRWING:onafterNewAsset(From, Event, To, asset, assignment) -- Call parent warehouse function first. self:GetParent(self).onafterNewAsset(self, 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:I(self.lid..text) + -- Get squadron. local squad=self:GetSquadron(asset.assignment) @@ -815,14 +830,21 @@ function AIRWING:onafterNewAsset(From, Event, To, asset, assignment) else + self:I(self.lid..string.format("Asset %s from squadron %s returned! asset.assignment=\"%s\", assignment=\"%s\"", asset.spawngroupname, squad.name, tostring(asset.assignment), tostring(assignment))) + self:ReturnPayloadFromAsset(asset) + + -- Mission might already be removed from the queue! + --[[ local mission=self:GetMissionByID(assignment) if mission then local text=string.format("Asset %s returned from %s mission %s", asset.spawngroupname, mission.type, mission.name) self:I(self.lid..text) + self:ReturnPayloadFromAsset(asset) else - self:E(self.lid.."ERROR: new asset not beloning to any s") + self:E(self.lid..string.format("ERROR: asset %s from squadron %s returned but could not find its mission! asset.assignment=\"%s\", assignment=\"%s\"", asset.spawngroupname, squad.name, tostring(asset.assignment), tostring(assignment))) end + ]] end @@ -1189,7 +1211,10 @@ function AIRWING:CanMission(MissionType, Nassets) -- Now clear all reserved payloads. for _,_asset in pairs(Assets) do local asset=_asset --#AIRWING.SquadronAsset - self:ReturnPayloadFromAsset(asset) + -- Only unspawned payloads are returned. + if not asset.spawned then + self:ReturnPayloadFromAsset(asset) + end end return Can, Assets diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 11e6394b2..ff8149248 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -703,6 +703,12 @@ end -- @param #string status New status. function AUFTRAG:SetFlightStatus(flightgroup, status) self.flightdata[flightgroup.groupname].status=status + + -- Check if ALL flights are done with their mission. + if self:IsNotOver() and self:CheckFlightsDone() then + self:Done() + end + end --- Get flightgroup mission status. @@ -907,7 +913,7 @@ end --- Add asset to mission. -- @param #AUFTRAG self -- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset to be added to the mission. --- @return #AIRWING self +-- @return #AUFTRAG self function AUFTRAG:AddAsset(Asset) self.assets=self.assets or {} @@ -920,7 +926,7 @@ end --- Delete asset from mission. -- @param #AUFTRAG self -- @param Ops.AirWing#AIRWING.SquadronAsset Asset The asset to be removed. --- @return #AIRWING self +-- @return #AUFTRAG self function AUFTRAG:DelAsset(Asset) for i,_asset in pairs(self.assets or {}) do @@ -928,10 +934,12 @@ function AUFTRAG:DelAsset(Asset) if asset.uid==Asset.uid then table.remove(self.assets, i) + return self end end + return self end @@ -1006,6 +1014,19 @@ function AUFTRAG:GetTargetCoordinate() return nil end +--- Get coordinate of target. First unit/group of the set is used. +-- @param #AUFTRAG self +-- @return #string +function AUFTRAG:GetMissionTypesText(MissionTypes) + + local text="" + for _,missiontype in pairs(MissionTypes) do + text=text..string.format("%s, ", missiontype) + end + + return text +end + --- Get DCS task table for the given mission. -- @param #AUFTRAG self -- @return DCS#Task The DCS task table. If multiple tasks are necessary, this is returned as a combo task. diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 701ed27d1..df7c63315 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -49,7 +49,8 @@ -- @field #boolean fuellowrtb RTB on low fuel switch. -- @field #boolean fuelcritical Fuel critical switch. -- @field #number fuelcriticalthresh Critical fuel threshold in percent. --- @field #boolean fuelcriticalrtb RTB on critical fuel switch. +-- @field #boolean fuelcriticalrtb RTB on critical fuel switch. +-- @field #boolean passedfinalwp Group has passed the final waypoint. -- @field Ops.Airwing#AIRWING airwing The airwing the flight group belongs to. -- @field Ops.FlightControl#FLIGHTCONTROL flightcontrol The flightcontrol handling this group. -- @field Core.UserFlag#USERFLAG flaghold Flag for holding. @@ -1265,7 +1266,7 @@ function FLIGHTGROUP:onafterFlightStatus(From, Event, To) local nTaskTot, nTaskSched, nTaskWP=self:CountRemainingTasks() -- Short info. - local text=string.format("Flight status %s [%d/%d]. Tasks=%d (%d,%d) Current=%d. Waypoint=%d/%d. Detected=%d. Destination=%s, FC=%s", + local text=string.format("Status %s [%d/%d]: Tasks=%d (%d,%d) Current=%d. Waypoint=%d/%d. Detected=%d. Destination=%s, FC=%s", fsmstate, #self.elements, #self.elements, nTaskTot, nTaskSched, nTaskWP, self.taskcurrent, self.currentwp or 0, self.waypoints and #self.waypoints or 0, self.detectedunits:Count(), self.destbase and self.destbase:GetName() or "unknown", self.flightcontrol and self.flightcontrol.airbasename or "none") self:I(self.lid..text) @@ -2215,7 +2216,6 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n) MESSAGE:New(text, 10):ToAllIf(false) self:I(self.lid..text) - -- Update waypoint tasks, i.e. inject WP tasks into waypoint table. self:_UpdateWaypointTasks() @@ -2270,22 +2270,25 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n) -- No waypoints left --- - self:E(self.lid.."WARNING: No waypoints left. Dunno what to do!") + if self.passedfinalwp then - --[[ + self:I(self.lid.."UpdateRoute: Passed Final WP ==> RTB/RTZ/Wait!") - -- Send flight to destination. NOTE that if there are still remaining tasks, the RTB call is delayed by 10 sec until all tasks are done. - if self.destbase then - self:__RTB(-1, self.destbase) - elseif self.destzone then - self:__RTZ(-1, self.destzone) + -- Send flight to destination. NOTE that if there are still remaining tasks, the RTB call is delayed by 10 sec until all tasks are done. + if self.destbase then + self:I(self.lid.."UpdateRoute: Passed Final WP ==> RTB!") + self:__RTB(-1, self.destbase) + elseif self.destzone then + self:I(self.lid.."UpdateRoute: Passed Final WP ==> RTZ!") + self:__RTZ(-1, self.destzone) + else + self:I(self.lid.."UpdateRoute: Passed Final WP ==> Wait!") + self:__Wait(-1) + end else - self:__Wait(-1) - self:E(self.lid.."ERROR: Reached final waypoint but no destination set! Don't know what to do?!") + self:E(self.lid.."WARNING: No waypoints left. Dunno what to do!") end - ]] - end end @@ -2298,6 +2301,8 @@ end -- @param #table Template The template used to respawn the group. function FLIGHTGROUP:onafterRespawn(From, Event, To, Template) + self:I(self.lid.."Respawning group!") + local template=UTILS.DeepCopy(Template or self.template) if self.group and self.group:InAir() then @@ -2320,14 +2325,12 @@ function FLIGHTGROUP:onafterPassingWaypoint(From, Event, To, n, N) self:I(self.lid..text) MESSAGE:New(text, 30, "DEBUG"):ToAllIf(self.Debug) - if true then - -- Get all waypoint tasks. local tasks=self:GetTasksWaypoint(n) -- Debug info. local text=string.format("WP %d/%d tasks:", n, N) - if tasks then + if #tasks>0 then for i,_task in pairs(tasks) do local task=_task --#FLIGHTGROUP.Task text=text..string.format("\n[%d] %s", i, task.description) @@ -2365,27 +2368,26 @@ function FLIGHTGROUP:onafterPassingWaypoint(From, Event, To, n, N) self:PushTask(self.group:TaskCombo(taskswp)) end - end - -- Final AIR waypoint reached? if n==N then --TODO: Find better way to RTB! self:I(self.lid.."FF group passed final waypoint!") - - --[[ - - -- Send flight to destination. NOTE that if there are still remaining tasks, the RTB call is delayed by 10 sec until all tasks are done. - if self.destbase then - self:__RTB(-1, self.destbase) - elseif self.destzone then - self:__RTZ(-1, self.destzone) - else - self:__Wait(-1) - self:E(self.lid.."ERROR: Reached final waypoint but no destination set! Don't know what to do?!") - end - ]] + self.passedfinalwp=true + + if #taskswp==0 then + + if self.destbase then + self:__RTB(-1, self.destbase) + elseif self.destzone then + self:__RTZ(-1, self.destzone) + else + self:__Wait(-1) + self:E(self.lid.."ERROR: Reached final waypoint but no destination set! Don't know what to do?!") + end + + end end @@ -2480,6 +2482,8 @@ end -- @param #number SpeedHold Holding speed in knots. Default 250 kts. -- @param #number SpeedLand Landing speed in knots. Default 170 kts. function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, SpeedLand) + + self:I(self.lid..string.format("RTB: event=%s: %s --> %s", Event, From, To)) -- Defaults: SpeedTo=SpeedTo or 350 @@ -2559,10 +2563,13 @@ function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, Sp if fc or world.event.S_EVENT_KILL then -- Just route the group. Respawn will happen when going from holding to final. + env.info("FF route (not repawn)") self:Route(wp, 1) else + env.info("FF respawn (not route)") + -- Get group template. local Template=self.group:GetTemplate() @@ -3958,6 +3965,13 @@ function FLIGHTGROUP:InitWaypoints(waypoints) -- Update route. if #self.waypoints>0 then + + -- Check if only 1 wp? + if #self.waypoints==1 then + self.passedfinalwp=true + end + + -- Update route (when airborne). self:__UpdateRoute(-1) end @@ -3977,6 +3991,10 @@ function FLIGHTGROUP:AddWaypointAir(coordinate, wpnumber, speed, updateroute) --TODO: by default add after last AIR waypoint! Last WP could be landing... wpnumber=wpnumber or #self.waypoints+1 + if wpnumber>self.currentwp then + self.passedfinalwp=false + end + -- Speed in knots. speed=speed or 350 @@ -4006,7 +4024,7 @@ function FLIGHTGROUP:AddWaypointAir(coordinate, wpnumber, speed, updateroute) if mission.waypointindex and mission.waypointindex>=wpnumber then mission.waypointindex=mission.waypointindex+1 end - end + end -- Update route. if updateroute==nil or updateroute==true then