diff --git a/Moose Development/Moose/Functional/CleanUp.lua b/Moose Development/Moose/Functional/CleanUp.lua index daed34b02..5cf990a34 100644 --- a/Moose Development/Moose/Functional/CleanUp.lua +++ b/Moose Development/Moose/Functional/CleanUp.lua @@ -134,7 +134,7 @@ function CLEANUP_AIRBASE:New( AirbaseNames ) for UnitName, Unit in pairs( _DATABASE.UNITS ) do local Unit = Unit -- Wrapper.Unit#UNIT if Unit:IsAlive() ~= nil then - if self:IsInAirbase( Unit:GetVec2() ) then + if self.__:IsInAirbase( Unit:GetVec2() ) then self:F( { UnitName = UnitName } ) self.CleanUpList[UnitName] = {} self.CleanUpList[UnitName].CleanUpUnit = Unit @@ -187,6 +187,10 @@ function CLEANUP_AIRBASE:SetCleanMissiles( CleanMissiles ) end end + +--- Check whether a Vec2 is in any cleanup airbase. +-- @param #CLEANUP_AIRBASE self +-- @param DCS#VEC2 Vec2 2D vector. function CLEANUP_AIRBASE.__:IsInAirbase( Vec2 ) local InAirbase = false @@ -194,7 +198,7 @@ function CLEANUP_AIRBASE.__:IsInAirbase( Vec2 ) local Airbase = Airbase -- Wrapper.Airbase#AIRBASE if Airbase:GetZone():IsVec2InZone( Vec2 ) then InAirbase = true - break; + break end end @@ -246,7 +250,7 @@ function CLEANUP_AIRBASE.__:OnEventBirth( EventData ) self:F( { EventData } ) if EventData.IniUnit:IsAlive() ~= nil then - if self:IsInAirbase( EventData.IniUnit:GetVec2() ) then + if self.__:IsInAirbase( EventData.IniUnit:GetVec2() ) then self.CleanUpList[EventData.IniDCSUnitName] = {} self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnit = EventData.IniUnit self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroup = EventData.IniGroup @@ -291,7 +295,7 @@ function CLEANUP_AIRBASE.__:OnEventShot( Event ) self:F( { Event } ) -- Test if the missile was fired within one of the CLEANUP_AIRBASE.AirbaseNames. - if self:IsInAirbase( Event.IniUnit:GetVec2() ) then + if self.__:IsInAirbase( Event.IniUnit:GetVec2() ) then -- Okay, the missile was fired within the CLEANUP_AIRBASE.AirbaseNames, destroy the fired weapon. self:DestroyMissile( Event.Weapon ) end @@ -304,7 +308,7 @@ function CLEANUP_AIRBASE.__:OnEventHit( Event ) self:F( { Event } ) if Event.IniUnit then - if self:IsInAirbase( Event.IniUnit:GetVec2() ) then + if self.__:IsInAirbase( Event.IniUnit:GetVec2() ) then self:T( { "Life: ", Event.IniDCSUnitName, ' = ', Event.IniUnit:GetLife(), "/", Event.IniUnit:GetLife0() } ) if Event.IniUnit:GetLife() < Event.IniUnit:GetLife0() then self:T( "CleanUp: Destroy: " .. Event.IniDCSUnitName ) @@ -314,7 +318,7 @@ function CLEANUP_AIRBASE.__:OnEventHit( Event ) end if Event.TgtUnit then - if self:IsInAirbase( Event.TgtUnit:GetVec2() ) then + if self.__:IsInAirbase( Event.TgtUnit:GetVec2() ) then self:T( { "Life: ", Event.TgtDCSUnitName, ' = ', Event.TgtUnit:GetLife(), "/", Event.TgtUnit:GetLife0() } ) if Event.TgtUnit:GetLife() < Event.TgtUnit:GetLife0() then self:T( "CleanUp: Destroy: " .. Event.TgtDCSUnitName ) @@ -356,7 +360,7 @@ function CLEANUP_AIRBASE.__:EventAddForCleanUp( Event ) if Event.IniDCSUnit and Event.IniCategory == Object.Category.UNIT then if self.CleanUpList[Event.IniDCSUnitName] == nil then - if self:IsInAirbase( Event.IniUnit:GetVec2() ) then + if self.__:IsInAirbase( Event.IniUnit:GetVec2() ) then self:AddForCleanUp( Event.IniUnit, Event.IniDCSUnitName ) end end @@ -364,7 +368,7 @@ function CLEANUP_AIRBASE.__:EventAddForCleanUp( Event ) if Event.TgtDCSUnit and Event.TgtCategory == Object.Category.UNIT then if self.CleanUpList[Event.TgtDCSUnitName] == nil then - if self:IsInAirbase( Event.TgtUnit:GetVec2() ) then + if self.__:IsInAirbase( Event.TgtUnit:GetVec2() ) then self:AddForCleanUp( Event.TgtUnit, Event.TgtDCSUnitName ) end end @@ -386,7 +390,7 @@ function CLEANUP_AIRBASE.__:CleanUpSchedule() if CleanUpUnit:IsAlive() ~= nil then - if self:IsInAirbase( CleanUpUnit:GetVec2() ) then + if self.__:IsInAirbase( CleanUpUnit:GetVec2() ) then if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index 00d00f5dd..8a8da6a4f 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -329,8 +329,9 @@ function AIRWING:AddAssetToSquadron(Squadron, Nassets) if Group then - local text=string.format("FF Adding asset %s to squadron %s", Group:GetName(), Squadron.name) - env.info(text) + -- Debug text. + local text=string.format("Adding asset %s to squadron %s", Group:GetName(), Squadron.name) + self:T(self.lid..text) -- Add assets to airwing warehouse. self:AddAsset(Group, Nassets, nil, nil, nil, nil, Squadron.skill, Squadron.livery, Squadron.name) @@ -1338,11 +1339,16 @@ function AIRWING:IsAssetOnMission(asset, MissionTypes) for _,_mission in pairs(asset.flightgroup.missionqueue or {}) do local mission=_mission --Ops.Auftrag#AUFTRAG - local status=mission:GetFlightStatus(asset.flightgroup) + if mission:IsNotOver() then - -- Only if mission is started or executing. - if (status==AUFTRAG.FlightStatus.STARTED or status==AUFTRAG.FlightStatus.EXECUTING) and self:CheckMissionType(mission.type, MissionTypes) then - return true + -- Get flight status. + local status=mission:GetFlightStatus(asset.flightgroup) + + -- Only if mission is started or executing. + if (status==AUFTRAG.FlightStatus.STARTED or status==AUFTRAG.FlightStatus.EXECUTING) and self:CheckMissionType(mission.type, MissionTypes) then + return true + end + end end @@ -1642,7 +1648,6 @@ function AIRWING:ReportSquadrons() local nstock=0 for _,_asset in pairs(squadron.assets) do local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem - --env.info(string.format("Asset name=%s", asset.spawngroupname)) local n=asset.nunits diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 1ce067fd5..6942537ea 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -34,7 +34,7 @@ -- @field #number Tstart Mission start time in seconds. -- @field #number Tstop Mission stop time in seconds. -- @field #number duration Mission duration in seconds. --- @field #number marker F10 map marker ID. +-- @field #number markerID F10 map marker ID. -- @field #table DCStask DCS task structure. -- @field #number Ntargets Number of mission targets. -- @@ -118,6 +118,7 @@ AUFTRAG = { assets = {}, missionFraction = 0.5, enrouteTasks = {}, + markerID = nil, } --- Global mission counter. @@ -230,6 +231,7 @@ AUFTRAG.TargetType={ -- @type AUFTRAG.TargetData -- @field Wrapper.Positionable#POSITIONABLE Target Target Object. -- @field #string Type Target type: "Group", "Unit", "Static", "Coordinate", "Airbase. +-- @field #number Ninital Number of initial targets. --- Mission success. -- @type AUFTRAG.Success @@ -257,11 +259,14 @@ AUFTRAG.version="0.0.9" -- TODO: Mission success options damaged, destroyed. -- DONE: Mission ROE and ROT. --- TODO: Mission formation, etc. +-- TODO: Mission frequency, formation, etc. -- DONE: FSM events. -- TODO: F10 marker functions that are updated on Status event. +-- TODO: F10 marker for new missions. -- DONE: Evaluate mission result ==> SUCCESS/FAILURE -- DONE: NewAUTO() NewA2G NewA2A +-- TODO: Transport mission. +-- TODO: Recon mission. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor @@ -354,9 +359,10 @@ function AUFTRAG:NewANTISHIP(Target) local mission=AUFTRAG:New(AUFTRAG.Type.ANTISHIP) mission.engageTarget=mission:_TargetFromObject(Target) + mission.engageWeaponType=ENUMS.WeaponFlag.Auto mission.missionTask=ENUMS.MissionTask.ANTISHIPSTRIKE - mission.missionFraction=0.5 + mission.missionFraction=0.4 mission.optionROE=ENUMS.ROE.OpenFire mission.optionROT=ENUMS.ROT.EvadeFire @@ -600,6 +606,30 @@ function AUFTRAG:NewBAI(Target) return mission end +--- Create a SEAD mission. +-- @param #AUFTRAG self +-- @param Wrapper.Positionable#POSITIONABLE Target The target to attack. Can be a GROUP or UNIT object. +-- @return #AUFTRAG self +function AUFTRAG:NewSEAD(Target) + + local mission=AUFTRAG:New(AUFTRAG.Type.SEAD) + + mission.engageTarget=mission:_TargetFromObject(Target) + mission.engageWeaponType=ENUMS.WeaponFlag.AnyAG + mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL + mission.engageAsGroup=true + + mission.missionTask=ENUMS.MissionTask.SEAD + mission.missionAltitude=nil + mission.missionFraction=0.4 + mission.optionROE=ENUMS.ROE.OpenFire + mission.optionROT=ENUMS.ROT.AllowAbortMission + + mission.DCStask=mission:GetDCSMissionTask() + + return mission +end + --- Create a STRIKE mission. Flight will attack the closest map object to the specified coordinate. -- @param #AUFTRAG self -- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT or STATIC object. @@ -754,20 +784,31 @@ function AUFTRAG:NewAUTO(EngageGroup) if attribute==GROUP.Attribute.GROUND_AAA or attribute==GROUP.Attribute.GROUND_SAM then - --TODO: SEAD/DEAD + -- SEAD/DEAD + + -- TODO: Attack radars first? Attack launchers? + + mission=AUFTRAG:NewSEAD(group) + + elseif attribute==GROUP.Attribute.GROUND_ARTILLERY then + + mission=AUFTRAG:NewBAI(group) + + elseif attribute==GROUP.Attribute.GROUND_INFANTRY then + + mission=AUFTRAG:NewBAI(group) + + else + + mission=AUFTRAG:NewBAI(group) end - mission=AUFTRAG:NewBAI(group) - - elseif category==Group.Category.SHIP then --- -- NAVAL --- - - --TODO: ANTISHIP mission=AUFTRAG:NewANTISHIP(group) @@ -961,9 +1002,16 @@ end -- @param #AUFTRAG self -- @param Ops.FlightGroup#FLIGHTGROUP FlightGroup The FLIGHTGROUP object. function AUFTRAG:DelFlightGroup(FlightGroup) - self:I(self.lid..string.format("Removing flight group %s", FlightGroup.groupname)) + self:I(self.lid..string.format("Removing flight group %s", FlightGroup and FlightGroup.groupname or "nil (ERROR)!")) - self.flightdata[FlightGroup.groupname]=nil + if FlightGroup then + + -- Remove mission form flightgroup queue. + FlightGroup:RemoveMission(self) + + self.flightdata[FlightGroup.groupname]=nil + + end end @@ -1082,7 +1130,7 @@ function AUFTRAG:onafterStatus(From, Event, To) local targetname=self:GetTargetName() or "unknown" local airwing=self.airwing and self.airwing.alias or "N/A" - local commander=self.wingcommander and tosting(self.wingcommander.coalition) or "N/A" + local commander=self.wingcommander and tostring(self.wingcommander.coalition) or "N/A" -- Info message. self:I(self.lid..string.format("Status %s: Target=%s, T=%s-%s, assets=%d, flights=%d, targets=%d, wing=%s, commander=%s", self.status, targetname, Cstart, Cstop, #self.assets, Nflights, Ntargets, airwing, commander)) @@ -1108,6 +1156,9 @@ function AUFTRAG:onafterStatus(From, Event, To) else self:__Status(-30) end + + -- Update F10 marker. + self:UpdateMarker() end --- Evaluate mission outcome - success or failure. @@ -1181,7 +1232,9 @@ end -- @param Ops.FlightGroup#FLIGHTGROUP flightgroup The flight group. -- @param #string status New status. function AUFTRAG:SetFlightStatus(flightgroup, status) + self:I(self.lid..string.format("Setting flight %s to status %s", flightgroup and flightgroup.groupname or "nil", tostring(status))) + env.info("FF trying to get flight status in AUFTRAG:GetFlightStatus") if self:GetFlightStatus(flightgroup)==AUFTRAG.FlightStatus.CANCELLED and status==AUFTRAG.FlightStatus.DONE then -- Do not overwrite a CANCELLED status with a DONE status. else @@ -1189,7 +1242,7 @@ function AUFTRAG:SetFlightStatus(flightgroup, status) if flightdata then flightdata.status=status else - self:E(self.lid.."WARNING: Could not SET flight data for flight group. Setting status to DONE.") + self:E(self.lid.."WARNING: Could not SET flight data for flight group. Setting status to DONE") end end @@ -1210,12 +1263,17 @@ end -- @param #AUFTRAG self -- @param Ops.FlightGroup#FLIGHTGROUP flightgroup The flight group. function AUFTRAG:GetFlightStatus(flightgroup) + self:T3(self.lid..string.format("Trying to get Flight status for flight group %s", flightgroup and flightgroup.groupname or "nil")) + local flightdata=self:GetFlightData(flightgroup) + if flightdata then return flightdata.status else - self:E(self.lid.."WARNING: Could not GET flightdata for flight group. Returning status DONE.") + + self:E(self.lid..string.format("WARNING: Could not GET flightdata for flightgroup %s. Returning status DONE.", flightgroup and flightgroup.groupname or "nil")) return AUFTRAG.FlightStatus.DONE + end end @@ -1471,8 +1529,14 @@ function AUFTRAG:onafterCancel(From, Event, To) -- Debug info. self:I(self.lid..string.format("CANCELLING mission in status %s. Will wait for flights to report mission DONE before evaluation.", self.status)) + + if self.wingcommander then + + env.info(string.format("FF calling CancelMission() for wingcommander")) + + self.wingcommander:CancelMission(self) - if self.airwing then + elseif self.airwing then env.info(string.format("FF calling MissionCancel() for airwing %s", self.airwing.alias)) @@ -1489,6 +1553,12 @@ function AUFTRAG:onafterCancel(From, Event, To) end end + + -- Special mission states. + if self.status==AUFTRAG.Status.PLANNED then + self:I(self.lid..string.format("Cancelled mission was in planned stage. Call it done!")) + self:Done() + end end @@ -1536,8 +1606,10 @@ function AUFTRAG:onafterRepeat(From, Event, To) if self.wingcommander then elseif self.airwing then + -- Already at the airwing ==> Queued() self:Queued(self.airwing) + else end @@ -1546,6 +1618,14 @@ function AUFTRAG:onafterRepeat(From, Event, To) -- No mission assets. self.assets={} + for _,_flightdata in pairs(self.flightdata) do + local flightdata=_flightdata --#AUFTRAG.FlightData + local flightgroup=flightdata.flightgroup + if flightgroup then + self:DelFlightGroup(flightgroup) + end + + end -- No flight data. self.flightdata={} @@ -1569,7 +1649,7 @@ function AUFTRAG:onafterStop(From, Event, To) -- TODO: Mission should be OVER! we dont want to remove running missions from any queues. if self.wingcommander then - + self.wingcommander:RemoveMission(self) end if self.airwing then @@ -1656,19 +1736,42 @@ function AUFTRAG:CountMissionTargets() local N=0 if self.engageTarget then + if self.engageTarget.Type==AUFTRAG.TargetType.GROUP then + local target=self.engageTarget.Target --Wrapper.Group#GROUP - N=N+target:CountAliveUnits() + + local units=target:GetUnits() + for _,_unit in pairs(units) do + local unit=_unit --Wrapper.Unit#UNIT + + -- We check that unit is "alive" and has health >1. Somtimes units get heavily damanged but are still alive. + -- TODO: here I could introduce and count that if units have only health < 50% if mission objective is to just "damage" the units. + if unit and unit:IsAlive() and unit:GetLife()>1 then + N=N+1 + end + end + elseif self.engageTarget.Type==AUFTRAG.TargetType.UNIT then + local target=self.engageTarget.Target --Wrapper.Unit#UNIT - if target and target:IsAlive() then + + if target and target:IsAlive() and target:GetLife()>1 then N=N+1 end + elseif self.engageTarget.Type==AUFTRAG.TargetType.STATIC then + local target=self.engageTarget.Target --Wrapper.Static#STATIC + if target and target:IsAlive() then N=N+1 end + + elseif self.engageTarget.Type==AUFTRAG.TargetType.AIRBASE then + + -- TODO: any (good) way to tell whether an airbase was "destroyed" or at least damaged? Is :GetLive() working? + end end @@ -1766,6 +1869,24 @@ function AUFTRAG:_SetLogID() return self end +--- Update mission F10 map marker. +-- @param #AUFTRAG self +-- @return #AUFTRAG self +function AUFTRAG:UpdateMarker() + + local text=string.format("%s %s", self.name, self.status) + text=text..string.format("Targets=%d", self:CountMissionTargets()) + + + if self.markerID then + COORDINATE.RemoveMark(nil, self.markerID) + end + + self.markerID=self:GetTargetCoordinate():MarkToAll(text, true) + + return self +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. @@ -1917,6 +2038,8 @@ function AUFTRAG:GetDCSMissionTask() -- RECON Mission -- ------------------- + -- TODO: What? + elseif self.type==AUFTRAG.Type.SEAD then ------------------ @@ -1955,6 +2078,8 @@ function AUFTRAG:GetDCSMissionTask() -- TRANSPORT Mission -- ----------------------- + -- TODO: What? + else self:E(self.lid..string.format("ERROR: Unknown mission task!")) return nil diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index e107c536e..660fa2bef 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -1533,17 +1533,22 @@ function FLIGHTGROUP:onafterFlightStatus(From, Event, To) -- Fuel State --- - local fuelmin=self:GetFuelMin() + -- Only if group is in air. + if self:IsAlive() and self.group:IsAirborne() then - -- Low fuel? - if fuelmin=mission.Tstart then return mission end @@ -2389,10 +2395,8 @@ function FLIGHTGROUP:onbeforeUpdateRoute(From, Event, To, n) end -- Not good, because mission will never start. Better only check if there is a current task! - if self.currentmission then - --self:I(self.lid.."FF update route denied because currentmission~=nil") - --allowed=false - end + --if self.currentmission then + --end -- Debug info. self:T2(self.lid..string.format("Onbefore Updateroute allowed=%s state=%s repeat in %s", tostring(allowed), self:GetState(), tostring(trepeat))) @@ -2594,7 +2598,7 @@ function FLIGHTGROUP:_CheckFlightDone(delay) self:I(self.lid..string.format("Passed Final WP but still have current Tasks (%s) or Missions (%s) left to do", tostring(self.taskcurrent), tostring(self.currentmission))) end else - self:I(self.lid.."Did NOT pass the final waypoint yet ==> update route") + self:I(self.lid..string.format("Flight (status=%s) did NOT pass the final waypoint yet ==> update route", self:GetState())) self:__UpdateRoute(-1) end end @@ -2775,13 +2779,14 @@ function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, Sp -- Respawn? 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:T(self.lid.."FF route (not repawn)") + + -- Just route the group. Respawn might happen when going from holding to final. self:Route(wp, 1) else - env.info("FF respawn (not route)") + self:T(self.lid.."FF respawn (not route)") -- Get group template. local Template=self.group:GetTemplate() @@ -3204,10 +3209,15 @@ function FLIGHTGROUP:CountRemainingMissison() for _,_mission in pairs(self.missionqueue) do local mission=_mission --Ops.Auftrag#AUFTRAG - local status=mission:GetFlightStatus(self) + if mission and mission:IsNotOver() then - if status~=AUFTRAG.FlightStatus.DONE and status~=AUFTRAG.FlightStatus.CANCELLED then - N=N+1 + -- Get flight status. + local status=mission:GetFlightStatus(self) + + if status~=AUFTRAG.FlightStatus.DONE and status~=AUFTRAG.FlightStatus.CANCELLED then + N=N+1 + end + end end @@ -3409,18 +3419,18 @@ function FLIGHTGROUP:onafterTaskDone(From, Event, To, Task) -- Check if this task was the task of the current mission ==> Mission Done! local Mission=self:GetMissionByTaskID(Task.id) - if Mission then + if Mission and Mission:IsNotOver() then local status=Mission:GetFlightStatus(self) if status~=AUFTRAG.FlightStatus.PAUSED then - env.info("FF Task Done ==> Mission Done!") + self:I(self.lid.."FF Task Done ==> Mission Done!") self:MissionDone(Mission) else --Mission paused. Do nothing! end else - env.info("FF Task Done but NO mission found ==> _CheckFlightDone in 1 sec") + self:I(self.lid.."FF Task Done but NO mission found ==> _CheckFlightDone in 1 sec") self:_CheckFlightDone(1) end @@ -3524,13 +3534,14 @@ function FLIGHTGROUP:onafterPauseMission(From, Event, To) if Mission then - -- Set flight mission status to EXECUTING. + -- Set flight mission status to PAUSED. Mission:SetFlightStatus(self, AUFTRAG.FlightStatus.PAUSED) -- Get mission waypoint task. local Task=Mission:GetFlightWaypointTask(self) - env.info(string.format("FF pausing current mission %s. Task=%s", tostring(Mission.name), tostring(Task and Task.description or "WTF"))) + -- Debug message. + self:I(self.lid..string.format("FF pausing current mission %s. Task=%s", tostring(Mission.name), tostring(Task and Task.description or "WTF"))) -- Cancelling the mission is actually cancelling the current task. self:TaskCancel(Task) @@ -3578,7 +3589,8 @@ function FLIGHTGROUP:onafterMissionCancel(From, Event, To, Mission) -- Get mission waypoint task. local Task=Mission:GetFlightWaypointTask(self) - env.info(string.format("FF Cancel current mission %s. Task=%s", tostring(Mission.name), tostring(Task and Task.description or "WTF"))) + -- Debug info. + self:I(self.lid..string.format("FF Cancel current mission %s. Task=%s", tostring(Mission.name), tostring(Task and Task.description or "WTF"))) -- Cancelling the mission is actually cancelling the current task. -- Note that two things can happen. @@ -3650,7 +3662,6 @@ function FLIGHTGROUP:RouteToMission(mission, delay) -- Set altitude of mission waypoint. if mission.missionAltitude then waypointcoord.y=mission.missionAltitude - env.info(string.format("FF mission altitude %d m = %d ft", waypointcoord.y, UTILS.MetersToFeet(waypointcoord.y))) end -- Add enroute tasks. diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index fd4ea847e..f2b468da7 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -16,7 +16,8 @@ -- @field #string ClassName Name of the class. -- @field #boolean Debug Debug mode. Messages to all about status. -- @field #string lid Class id string for output to DCS log file. --- @field #number coalition Coalition side number, e.g. coalition.side.RED. +-- @field #number coalition Coalition side number, e.g. `coalition.side.RED`. +-- @field #string alias Name of the agency. -- @field #table filterCategory Category filters. -- @field Core.Set#SET_ZONE acceptzoneset Set of accept zones. If defined, only contacts in these zones are considered. -- @field Core.Set#SET_ZONE rejectzoneset Set of reject zones. Contacts in these zones are not considered, even if they are in accept zones. @@ -41,6 +42,7 @@ INTEL = { ClassName = "INTEL", Debug = nil, lid = nil, + alias = nil, filterCategory = {}, detectionset = nil, Contacts = {}, @@ -100,17 +102,17 @@ function INTEL:New(DetectionSet, Coalition) self.coalition=Coalition or DetectionSet:CountAlive()>0 and DetectionSet:GetFirst():GetCoalition() or nil -- Set alias. - local alias="SPECTRE" + self.alias="SPECTRE" if self.coalition then if self.coalition==coalition.side.RED then - alias="KGB" + self.alias="KGB" elseif self.coalition==coalition.side.BLUE then - alias="CIA" + self.alias="CIA" end end -- Set some string id for output to DCS.log file. - self.lid=string.format("INTEL %s | ", alias) + self.lid=string.format("INTEL %s | ", self.alias) -- Start State. self:SetStartState("Stopped") diff --git a/Moose Development/Moose/Ops/WingCommander.lua b/Moose Development/Moose/Ops/WingCommander.lua index ce1046fa9..c5bd09397 100644 --- a/Moose Development/Moose/Ops/WingCommander.lua +++ b/Moose Development/Moose/Ops/WingCommander.lua @@ -89,7 +89,7 @@ function WINGCOMMANDER:New(AgentSet, Coalition) AgentSet=AgentSet or SET_GROUP:New() -- Inherit everything from INTEL class. - local self=BASE:Inherit(self, INTEL:New(AgentSet)) --#WINGCOMMANDER + local self=BASE:Inherit(self, INTEL:New(AgentSet, Coalition)) --#WINGCOMMANDER -- Set some string id for output to DCS.log file. --self.lid=string.format("WINGCOMMANDER | ") @@ -99,6 +99,7 @@ function WINGCOMMANDER:New(AgentSet, Coalition) -- Add FSM transitions. -- From State --> Event --> To State self:AddTransition("*", "MissionAssign", "*") -- Mission was assigned to an AIRWING. + self:AddTransition("*", "CancelMission", "*") -- Cancel mission. ------------------------ --- Pseudo Functions --- @@ -168,6 +169,8 @@ end -- @return #WINGCOMMANDER self function WINGCOMMANDER:AddMission(Mission) + Mission.wingcommander=self + table.insert(self.missionqueue, Mission) return self @@ -183,6 +186,7 @@ function WINGCOMMANDER:RemoveMission(Mission) local mission=_mission --Ops.Auftrag#AUFTRAG if mission.auftragsnummer==Mission.auftragsnummer then + self:I(self.lid..string.format("Removing mission %s (%s) status=%s from queue", Mission.name, Mission.type, Mission.status)) table.remove(self.missionqueue, i) break end @@ -210,9 +214,13 @@ end -- @param Core.Zone#ZONEBorderZone Add a zone to the accept zone set. -- @return #WINGCOMMANDER self function WINGCOMMANDER:AddBorderZone(BorderZone) + + -- Add a border zone. self.borderzoneset:AddZone(BorderZone) + -- Set accept zone. self:AddAcceptZone(BorderZone) + return self end @@ -304,6 +312,18 @@ function WINGCOMMANDER:onafterStatus(From, Event, To) -- Check mission queue and assign one PLANNED mission. self:CheckMissionQueue() + + if #self.missionqueue>0 then + local text="Mission queue:" + for i,_mission in pairs(self.missionqueue) do + local mission=_mission --Ops.Auftrag#AUFTRAG + + local target=mission:GetTargetName() or "unknown" + + text=text..string.format("\n[%d] %s (%s): status=%s, target=%s", i, mission.name, mission.type, mission.status, target) + end + self:I(self.lid..text) + end end @@ -320,10 +340,37 @@ end -- @param Ops.Auftrag#AUFTRAG Mission The mission. function WINGCOMMANDER:onafterMissionAssign(From, Event, To, Airwing, Mission) + self:I(self.lid..string.format("Assigning mission %s (%s) to airwing %s", Mission.name, Mission.type, Airwing.alias)) Airwing:AddMission(Mission) end +--- On after "CancelMission" event. +-- @param #WINGCOMMANDER self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Ops.Auftrag#AUFTRAG Mission The mission. +function WINGCOMMANDER:onafterCancelMission(From, Event, To, Mission) + + self:I(self.lid..string.format("Cancelling mission %s (%s) in status %s", Mission.name, Mission.type, Mission.status)) + + if Mission.status==AUFTRAG.Status.PLANNED then + + -- Mission is still in planning stage. Should not have an airbase assigned ==> Just remove it form the queue. + self:RemoveMission(Mission) + + else + + -- Airwing will cancel mission. + if Mission.airwing then + Mission.airwing:MissionCancel(Mission) + end + + end + +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Resources -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------