From 0c07a660ee05f4c9ac3d788acbff606fbd3bd216 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 17 Nov 2020 00:25:37 +0100 Subject: [PATCH 1/8] WAREHOUSE - Added runway destroyed check. --- .../Moose/Functional/Warehouse.lua | 112 ++++++++++++++++-- Moose Development/Moose/Ops/Auftrag.lua | 2 +- Moose Development/Moose/Ops/OpsGroup.lua | 4 + Moose Development/Moose/Ops/Squadron.lua | 10 ++ Moose Development/Moose/Ops/Target.lua | 6 +- 5 files changed, 122 insertions(+), 12 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 6e0ee387f..f6bb9c8da 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -84,6 +84,8 @@ -- @field #number lowfuelthresh Low fuel threshold. Triggers the event AssetLowFuel if for any unit fuel goes below this number. -- @field #boolean respawnafterdestroyed If true, warehouse is respawned after it was destroyed. Assets are kept. -- @field #number respawndelay Delay before respawn in seconds. +-- @field #number runwaydestroyed Time stamp timer.getAbsTime() when the runway was destroyed. +-- @field #number runwayrepairtime Time in seconds until runway will be repaired after it was destroyed. Default is 3600 sec (one hour). -- @extends Core.Fsm#FSM --- Have your assets at the right place at the right time - or not! @@ -1893,6 +1895,7 @@ function WAREHOUSE:New(warehouse, alias) -- Defaults self:SetMarker(true) self:SetReportOff() + self:SetRunwayRepairtime() --self:SetVerbosityLevel(0) -- Add warehouse to database. @@ -1944,6 +1947,8 @@ function WAREHOUSE:New(warehouse, alias) self:AddTransition("Attacked", "Captured", "Running") -- Warehouse was captured by another coalition. It must have been attacked first. self:AddTransition("*", "AirbaseCaptured", "*") -- Airbase was captured by other coalition. self:AddTransition("*", "AirbaseRecaptured", "*") -- Airbase was re-captured from other coalition. + self:AddTransition("*", "RunwayDestroyed", "*") -- Runway of the airbase was destroyed. + self:AddTransition("*", "RunwayRepaired", "*") -- Runway of the airbase was repaired. self:AddTransition("*", "AssetDead", "*") -- An asset group died. self:AddTransition("*", "Destroyed", "Destroyed") -- Warehouse was destroyed. All assets in stock are gone and warehouse is stopped. self:AddTransition("Destroyed", "Respawn", "Running") -- Respawn warehouse after it was destroyed. @@ -3245,6 +3250,44 @@ function WAREHOUSE:FindAssetInDB(group) return nil end +--- Check if runway is operational. +-- @param #WAREHOUSE self +-- @return #boolean If true, runway is operational. +function WAREHOUSE:IsRunwayOperational() + if self.airbase then + if self.runwaydestroyed then + return false + else + return true + end + end + return nil +end + +--- Set the time until the runway(s) of an airdrome are repaired after it has been destroyed. +-- Note that this is the time, the DCS engine uses not something we can control on a user level or we could get via scripting. +-- You need to input the value. On the DCS forum it was stated that this is currently one hour. Hence this is the default value. +-- @param #WAREHOUSE self +-- @param #number RepairTime Time in seconds until the runway is repaired. Default 3600 sec (one hour). +-- @return #WAREHOUSE self +function WAREHOUSE:SetRunwayRepairtime(RepairTime) + self.runwayrepairtime=RepairTime or 3600 + return self +end + +--- Check if runway is operational. +-- @param #WAREHOUSE self +-- @return #number Time in seconds until the runway is repaired. Will return 0 if runway is repaired. +function WAREHOUSE:GetRunwayRepairtime() + if self.runwaydestroyed then + local Tnow=timer.getAbsTime() + local Tsince=Tnow-self.runwaydestroyed + local Trepair=math.max(self.runwayrepairtime-Tsince, 0) + return Trepair + end + return 0 +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- FSM states ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -3425,6 +3468,14 @@ function WAREHOUSE:onafterStatus(From, Event, To) -- Check if warehouse is being attacked or has even been captured. self:_CheckConquered() + + if self:IsRunwayOperational()==false then + local Trepair=self:GetRunwayRepairtime() + self:I(self.lid..string.format("Runway destroyed! Will be repaired in %d sec", Trepair)) + if Trepair==0 then + self:RunwayRepaired() + end + end -- Check if requests are valid and remove invalid one. self:_CheckRequestConsistancy(self.queue) @@ -5132,6 +5183,38 @@ function WAREHOUSE:onafterAirbaseRecaptured(From, Event, To, Coalition) end +--- On after "RunwayDestroyed" event. +-- @param #WAREHOUSE self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param DCS#coalition.side Coalition Coalition side which originally captured the warehouse. +function WAREHOUSE:onafterRunwayDestroyed(From, Event, To) + + -- Message. + local text=string.format("Warehouse %s: Runway %s destroyed!", self.alias, self.airbasename) + self:_InfoMessage(text) + + self.runwaydestroyed=timer.getAbsTime() + +end + +--- On after "RunwayRepaired" event. +-- @param #WAREHOUSE self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function WAREHOUSE:onafterRunwayRepaired(From, Event, To) + + -- Message. + local text=string.format("Warehouse %s: Runway %s repaired!", self.alias, self.airbasename) + self:_InfoMessage(text) + + self.runwaydestroyed=nil + +end + + --- On before "AssetSpawned" event. Checks whether the asset was already set to "spawned" for groups with multiple units. -- @param #WAREHOUSE self -- @param #string From From state. @@ -6335,6 +6418,9 @@ function WAREHOUSE:_OnEventCrashOrDead(EventData) -- Trigger Destroyed event. self:Destroyed() end + if self.airbase and self.airbasename and self.airbasename==EventData.IniUnitName then + self:RunwayDestroyed() + end end --self:I(self.lid..string.format("Warehouse %s captured event dead or crash or unit %s.", self.alias, tostring(EventData.IniUnitName))) @@ -7079,15 +7165,23 @@ function WAREHOUSE:_CheckRequestNow(request) -- Check available parking for air asset units. if self.airbase and (_assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER) then + + if self:IsRunwayOperational() then - local Parking=self:_FindParkingForAssets(self.airbase,_assets) - - --if Parking==nil and not (self.category==Airbase.Category.HELIPAD) then - if Parking==nil then - local text=string.format("Warehouse %s: Request denied! Not enough free parking spots for all requested assets at the moment.", self.alias) + local Parking=self:_FindParkingForAssets(self.airbase,_assets) + + --if Parking==nil and not (self.category==Airbase.Category.HELIPAD) then + if Parking==nil then + local text=string.format("Warehouse %s: Request denied! Not enough free parking spots for all requested assets at the moment.", self.alias) + self:_InfoMessage(text, 5) + return false + end + + else + -- Runway destroyed. + local text=string.format("Warehouse %s: Request denied! Runway is still destroyed", self.alias) self:_InfoMessage(text, 5) - - return false + return false end end @@ -7132,7 +7226,9 @@ function WAREHOUSE:_CheckRequestNow(request) else - -- Self propelled case. Nothing to do for now. + --- + -- Self propelled case + --- -- Ground asset checks. if _assetcategory==Group.Category.GROUND then diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index dce4fe3be..465997776 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -2846,7 +2846,7 @@ function AUFTRAG:_TargetFromObject(Object) end -- Debug info. - self:T(self.lid..string.format("Mission Target %s Type=%s, Ntargets=%d, Lifepoints=%d", self.engageTarget.lid, self.engageTarget.lid, self.engageTarget.Ntargets0, self.engageTarget:GetLife())) + self:I(self.lid..string.format("Mission Target %s Type=%s, Ntargets=%d, Lifepoints=%d", self.engageTarget.lid, self.engageTarget.lid, self.engageTarget.Ntargets0, self.engageTarget:GetLife())) return self end diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index e61a371b0..79240503b 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -2781,6 +2781,10 @@ function OPSGROUP:RouteToMission(mission, delay) -- Delayed call. self:ScheduleOnce(delay, OPSGROUP.RouteToMission, self, mission) else + + if self:IsDead() then + return + end -- ID of current waypoint. local uid=self:GetWaypointCurrent().uid diff --git a/Moose Development/Moose/Ops/Squadron.lua b/Moose Development/Moose/Ops/Squadron.lua index a99891e2c..5ed71fba7 100644 --- a/Moose Development/Moose/Ops/Squadron.lua +++ b/Moose Development/Moose/Ops/Squadron.lua @@ -549,11 +549,21 @@ end function SQUADRON:AddTacanChannel(ChannelMin, ChannelMax) ChannelMax=ChannelMax or ChannelMin + + if ChannelMin>126 then + self:E(self.lid.."ERROR: TACAN Channel must be <= 126! Will not add to available channels") + return self + end + if ChannelMax>126 then + self:E(self.lid.."WARNING: TACAN Channel must be <= 126! Adjusting ChannelMax to 126") + ChannelMax=126 + end for i=ChannelMin,ChannelMax do self.tacanChannel[i]=true end + return self end --- Get an unused TACAN channel. diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index 3ab5aa43b..c86f41c52 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -425,7 +425,7 @@ function TARGET:OnEventUnitDeadOrLost(EventData) if EventData and EventData.IniUnitName then -- Debug info. - self:I(self.lid..string.format("EVENT: Unit %s dead or lost!", EventData.IniUnitName)) + self:T(self.lid..string.format("EVENT: Unit %s dead or lost!", tostring(EventData.IniUnitName))) -- Get target. local target=self:GetTargetByName(EventData.IniUnitName) @@ -438,7 +438,7 @@ function TARGET:OnEventUnitDeadOrLost(EventData) if target and target.Status==TARGET.ObjectStatus.ALIVE then -- Debug message. - self:I(self.lid..string.format("EVENT: target unit %s dead or lost ==> destroyed", target.Name)) + self:T(self.lid..string.format("EVENT: target unit %s dead or lost ==> destroyed", tostring(target.Name))) -- Trigger object destroyed event. self:ObjectDestroyed(target) @@ -1008,7 +1008,7 @@ function TARGET:CountTargets() for _,_unit in pairs(units or {}) do local unit=_unit --Wrapper.Unit#UNIT - if unit and unit:IsAlive() and unit:GetLife()>1 then + if unit and unit:IsAlive()~=nil and unit:GetLife()>1 then N=N+1 end end From 53c3996aef5fb6b67d4475732ae552ebaef4ab8c Mon Sep 17 00:00:00 2001 From: Applevangelist <72444570+Applevangelist@users.noreply.github.com> Date: Thu, 19 Nov 2020 15:51:09 +0100 Subject: [PATCH 2/8] Update Task_A2A_Dispatcher.lua Add boolean in new to suppress "... has new tasks..." flashes --- Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index 44db945c7..573b8c4b0 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -199,7 +199,7 @@ do -- TASK_A2A_DISPATCHER self.Detection = Detection self.Mission = Mission - + self.FlashNewTask = false -- TODO: Check detection through radar. self.Detection:FilterCategories( Unit.Category.AIRPLANE, Unit.Category.HELICOPTER ) @@ -610,7 +610,7 @@ do -- TASK_A2A_DISPATCHER local TaskText = TaskReport:Text(", ") for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then + if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and ( not not self.FlashNewTask) then Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup ) end end From 7ddec7609a6896632cfa7bf98547e60925afd85c Mon Sep 17 00:00:00 2001 From: Applevangelist <72444570+Applevangelist@users.noreply.github.com> Date: Thu, 19 Nov 2020 15:59:35 +0100 Subject: [PATCH 3/8] Update Task_Capture_Dispatcher.lua Last annoying flash gordon --- Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua index 0c05ba18b..e9b3954ac 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua @@ -83,7 +83,7 @@ do -- TASK_CAPTURE_DISPATCHER -- ## 1.1. Create a command center. -- -- First you need to create a command center using the @{Tasking.CommandCenter#COMMANDCENTER.New}() constructor. - -- The command assumes that you´ve setup a group in the mission editor with the name HQ. + -- The command assumes that you´ve setup a group in the mission editor with the name HQ. -- This group will act as the command center object. -- It is a good practice to mark this group as invisible and invulnerable. -- @@ -184,6 +184,7 @@ do -- TASK_CAPTURE_DISPATCHER local self = BASE:Inherit( self, TASK_MANAGER:New( SetGroup ) ) -- #TASK_CAPTURE_DISPATCHER self.Mission = Mission + self.FlashNewTask = false self:AddTransition( "Started", "Assign", "Started" ) self:AddTransition( "Started", "ZoneCaptured", "Started" ) @@ -383,7 +384,7 @@ do -- TASK_CAPTURE_DISPATCHER local TaskText = TaskReport:Text(", ") for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do - if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then + if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and ( not self.FlashNewTask ) then Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup ) end end From afb63a73318d03f7c0c59780a8b4fdc8bcea8343 Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 19 Nov 2020 19:51:58 +0100 Subject: [PATCH 4/8] Update Target.lua - Fixed escort problem --- Moose Development/Moose/Ops/Target.lua | 136 +++++++++++++++---------- 1 file changed, 81 insertions(+), 55 deletions(-) diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index c86f41c52..65c6ae7ea 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -113,7 +113,7 @@ _TARGETID=0 --- TARGET class version. -- @field #string version -TARGET.version="0.2.0" +TARGET.version="0.2.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -231,12 +231,14 @@ function TARGET:AddObject(Object) for _,object in pairs(set.Set) do self:AddObject(object) end - + +--[[ elseif Object:IsInstanceOf("GROUP") then for _,unit in pairs(Object:GetUnits()) do self:_AddObject(unit) end +]] else @@ -427,15 +429,27 @@ function TARGET:OnEventUnitDeadOrLost(EventData) -- Debug info. self:T(self.lid..string.format("EVENT: Unit %s dead or lost!", tostring(EventData.IniUnitName))) - -- Get target. - local target=self:GetTargetByName(EventData.IniUnitName) + local deadnow=false - if not target then - target=self:GetTargetByName(EventData.IniGroupName) + -- Target + local target=self:GetTargetByName(EventData.IniGroupName) + + if target then + + local N=self:CountObjectives(target) + if N==0 then + deadnow=true + end + + else + target=self:GetTargetByName(EventData.IniUnitName) + if target then + deadnow=true + end end -- Check if this is one of ours. - if target and target.Status==TARGET.ObjectStatus.ALIVE then + if deadnow and target.Status==TARGET.ObjectStatus.ALIVE then -- Debug message. self:T(self.lid..string.format("EVENT: target unit %s dead or lost ==> destroyed", tostring(target.Name))) @@ -989,6 +1003,65 @@ function TARGET:GetObject() return nil end +--- Count alive objects. +-- @param #TARGET self +-- @param #TARGET.Object Target Target objective. +-- @return #number Number of alive target objects. +function TARGET:CountObjectives(Target) + + local N=1 + + if Target.Type==TARGET.ObjectType.GROUP then + + local target=Target.Object --Wrapper.Group#GROUP + + local units=target:GetUnits() + + for _,_unit in pairs(units or {}) do + local unit=_unit --Wrapper.Unit#UNIT + if unit and unit:IsAlive()~=nil and unit:GetLife()>1 then + N=N+1 + end + end + + elseif Target.Type==TARGET.ObjectType.UNIT then + + local target=Target.Object --Wrapper.Unit#UNIT + + if target and target:IsAlive() and target:GetLife()>1 then + N=N+1 + end + + elseif Target.Type==TARGET.ObjectType.STATIC then + + local target=Target.Object --Wrapper.Static#STATIC + + if target and target:IsAlive() then + N=N+1 + end + + elseif Target.Type==TARGET.ObjectType.SCENERY then + + if Target.Status==TARGET.ObjectStatus.ALIVE then + N=N+1 + end + + elseif Target.Type==TARGET.ObjectType.AIRBASE then + + if Target.Status==TARGET.ObjectStatus.ALIVE then + N=N+1 + end + + elseif Target.Type==TARGET.ObjectType.COORDINATE then + + -- No target we can check! + + else + self:E(self.lid.."ERROR: Unknown target type! Cannot count targets") + end + + return N +end --- Count alive targets. -- @param #TARGET self @@ -1000,54 +1073,7 @@ function TARGET:CountTargets() for _,_target in pairs(self.targets) do local Target=_target --#TARGET.Object - if Target.Type==TARGET.ObjectType.GROUP then - - local target=Target.Object --Wrapper.Group#GROUP - - local units=target:GetUnits() - - for _,_unit in pairs(units or {}) do - local unit=_unit --Wrapper.Unit#UNIT - if unit and unit:IsAlive()~=nil and unit:GetLife()>1 then - N=N+1 - end - end - - elseif Target.Type==TARGET.ObjectType.UNIT then - - local target=Target.Object --Wrapper.Unit#UNIT - - if target and target:IsAlive() and target:GetLife()>1 then - N=N+1 - end - - elseif Target.Type==TARGET.ObjectType.STATIC then - - local target=Target.Object --Wrapper.Static#STATIC - - if target and target:IsAlive() then - N=N+1 - end - - elseif Target.Type==TARGET.ObjectType.SCENERY then - - if Target.Status==TARGET.ObjectStatus.ALIVE then - N=N+1 - end - - elseif Target.Type==TARGET.ObjectType.AIRBASE then - - if Target.Status==TARGET.ObjectStatus.ALIVE then - N=N+1 - end - - elseif Target.Type==TARGET.ObjectType.COORDINATE then - - -- No target we can check! - - else - self:E(self.lid.."ERROR: Unknown target type! Cannot count targets") - end + N=N+self:CountObjectives(Target) end From ab5167717db9131b6d89aa1ca66694225ffa7883 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 20 Nov 2020 10:17:45 +0100 Subject: [PATCH 5/8] Update Airboss.lua - Added F-14A-135-GR by Heatblur to the list of supported aircraft. --- Moose Development/Moose/Ops/Airboss.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 9a5628880..592adaf21 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -1261,7 +1261,7 @@ AIRBOSS.AircraftCarrier={ AV8B="AV8BNA", HORNET="FA-18C_hornet", A4EC="A-4E-C", - F14A="F-14A_tomcat", + F14A="F-14A-135-GR", F14B="F-14B", F14A_AI="F-14A", FA18C="F/A-18C", From 770fb3228f72ca897a423c27f158d505b34a2bea Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 21 Nov 2020 21:49:47 +0100 Subject: [PATCH 6/8] OPS AUFTRAG - Changed ESCORT engage distance input to NM (not meters) TARGET - Fixed bug in count targets - Improved dead/destroyed management FLIGHTGROUP - Only register UNIT/STATIC kills (not SCENERY) INTEL - Improved agent set --- Moose Development/Moose/Ops/Auftrag.lua | 10 +- Moose Development/Moose/Ops/FlightGroup.lua | 43 +++- Moose Development/Moose/Ops/Intelligence.lua | 42 ++- Moose Development/Moose/Ops/Target.lua | 258 ++++++++++++++----- 4 files changed, 260 insertions(+), 93 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 465997776..b7e19f41c 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1073,7 +1073,7 @@ end -- @param #AUFTRAG self -- @param Wrapper.Group#GROUP EscortGroup The group to escort. -- @param DCS#Vec3 OffsetVector A table with x, y and z components specifying the offset of the flight to the escorted group. Default {x=-100, y=0, z=200} for z=200 meters to the right, same alitude, x=100 meters behind. --- @param #number EngageMaxDistance Max engage distance of targets in meters. Default auto (*nil*). +-- @param #number EngageMaxDistance Max engage distance of targets in nautical miles. Default auto (*nil*). -- @param #table TargetTypes Types of targets to engage automatically. Default is {"Air"}, i.e. all enemy airborne units. Use an empty set {} for a simple "FOLLOW" mission. -- @return #AUFTRAG self function AUFTRAG:NewESCORT(EscortGroup, OffsetVector, EngageMaxDistance, TargetTypes) @@ -1084,7 +1084,7 @@ function AUFTRAG:NewESCORT(EscortGroup, OffsetVector, EngageMaxDistance, TargetT -- DCS task parameters: mission.escortVec3=OffsetVector or {x=-100, y=0, z=200} - mission.engageMaxDistance=EngageMaxDistance + mission.engageMaxDistance=EngageMaxDistance and UTILS.NMToMeters(EngageMaxDistance) or nil mission.engageTargetTypes=TargetTypes or {"Air"} -- Mission options: @@ -2608,7 +2608,7 @@ end function AUFTRAG:onafterCancel(From, Event, To) -- Debug info. - self:I(self.lid..string.format("CANCELLING mission in status %s. Will wait for groups to report mission DONE before evaluation.", self.status)) + self:I(self.lid..string.format("CANCELLING mission in status %s. Will wait for groups to report mission DONE before evaluation", self.status)) -- Time stamp. self.Tover=timer.getAbsTime() @@ -2846,7 +2846,7 @@ function AUFTRAG:_TargetFromObject(Object) end -- Debug info. - self:I(self.lid..string.format("Mission Target %s Type=%s, Ntargets=%d, Lifepoints=%d", self.engageTarget.lid, self.engageTarget.lid, self.engageTarget.Ntargets0, self.engageTarget:GetLife())) + --self:T2(self.lid..string.format("Mission Target %s Type=%s, Ntargets=%d, Lifepoints=%d", self.engageTarget.lid, self.engageTarget.lid, self.engageTarget.N0, self.engageTarget:GetLife())) return self end @@ -2871,7 +2871,7 @@ end function AUFTRAG:GetTargetInitialNumber() local target=self:GetTargetData() if target then - return target.Ntargets0 + return target.N0 else return 0 end diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index eb312d51e..d71f76d0e 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -225,7 +225,7 @@ FLIGHTGROUP.version="0.6.0" --- Create a new FLIGHTGROUP object and start the FSM. -- @param #FLIGHTGROUP self --- @param Wrapper.Group#GROUP Group The group object. Can also be given by its group name as `#string`. +-- @param Wrapper.Group#GROUP group The group object. Can also be given by its group name as `#string`. -- @return #FLIGHTGROUP self function FLIGHTGROUP:New(group) @@ -1229,17 +1229,34 @@ function FLIGHTGROUP:OnEventKill(EventData) -- Check that this is the right group. if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then - self:T2(self.lid..string.format("EVENT: Unit %s killed unit %s!", tostring(EventData.IniUnitName), tostring(EventData.TgtUnitName))) + + -- Target name + local targetname=tostring(EventData.TgtUnitName) + + -- Debug info. + self:T2(self.lid..string.format("EVENT: Unit %s killed object %s!", tostring(EventData.IniUnitName), targetname)) - local unit=EventData.IniUnit - local group=EventData.IniGroup - local unitname=EventData.IniUnitName + -- Check if this was a UNIT or STATIC object. + local target=UNIT:FindByName(targetname) + if not target then + target=STATIC:FindByName(targetname, false) + end - self.Nkills=self.Nkills+1 - - local mission=self:GetMissionCurrent() - if mission then - mission.Nkills=mission.Nkills+1 + -- Only count UNITS and STATICs (not SCENERY) + if target then + + -- Debug info. + self:T(self.lid..string.format("EVENT: Unit %s killed unit/static %s!", tostring(EventData.IniUnitName), targetname)) + + -- Kill counter. + self.Nkills=self.Nkills+1 + + -- Check if on a mission. + local mission=self:GetMissionCurrent() + if mission then + mission.Nkills=mission.Nkills+1 -- Increase mission kill counter. + end + end end @@ -1526,9 +1543,9 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To) end -- TODO: make this input. - self.group:SetOption(AI.Option.Air.id.PROHIBIT_JETT, true) - self.group:SetOption(AI.Option.Air.id.PROHIBIT_AB, true) -- Does not seem to work. AI still used the after burner. - self.group:SetOption(AI.Option.Air.id.RTB_ON_BINGO, false) + self:GetGroup():SetOption(AI.Option.Air.id.PROHIBIT_JETT, true) + self:GetGroup():SetOption(AI.Option.Air.id.PROHIBIT_AB, true) -- Does not seem to work. AI still used the after burner. + self:GetGroup():SetOption(AI.Option.Air.id.RTB_ON_BINGO, false) --self.group:SetOption(AI.Option.Air.id.RADAR_USING, AI.Option.Air.val.RADAR_USING.FOR_CONTINUOUS_SEARCH) -- Update route. diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index 584fb865e..ed82c4fa8 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -113,8 +113,9 @@ INTEL.version="0.0.3" -- @param #INTEL self -- @param Core.Set#SET_GROUP DetectionSet Set of detection groups. -- @param #number Coalition Coalition side. Can also be passed as a string "red", "blue" or "neutral". +-- @param #string Alias An *optional* alias how this object is called in the logs etc. -- @return #INTEL self -function INTEL:New(DetectionSet, Coalition) +function INTEL:New(DetectionSet, Coalition, Alias) -- Inherit everything from FSM class. local self=BASE:Inherit(self, FSM:New()) -- #INTEL @@ -122,21 +123,46 @@ function INTEL:New(DetectionSet, Coalition) -- Detection set. self.detectionset=DetectionSet or SET_GROUP:New() + if Coalition and type(Coalition)=="string" then + if Coalition=="blue" then + Coalition=coalition.side.BLUE + elseif Coalition=="red" then + Coalition=coalition.side.RED + elseif Coalition=="neutral" then + Coalition=coalition.side.NEUTRAL + else + self:E("ERROR: Unknown coalition in INTEL!") + end + end + -- Determine coalition from first group in set. self.coalition=Coalition or DetectionSet:CountAlive()>0 and DetectionSet:GetFirst():GetCoalition() or nil - -- Set alias. - self.alias="SPECTRE" + -- Filter coalition. if self.coalition then - if self.coalition==coalition.side.RED then - self.alias="KGB" - elseif self.coalition==coalition.side.BLUE then - self.alias="CIA" + local coalitionname=UTILS.GetCoalitionName(self.coalition):lower() + self.detectionset:FilterCoalitions(coalitionname) + end + + -- Filter once. + self.detectionset:FilterOnce() + + -- Set alias. + if Alias then + self.alias=tostring(Alias) + else + self.alias="SPECTRE" + if self.coalition then + if self.coalition==coalition.side.RED then + self.alias="KGB" + elseif self.coalition==coalition.side.BLUE then + self.alias="CIA" + end end end -- Set some string id for output to DCS.log file. - self.lid=string.format("INTEL %s | ", self.alias) + self.lid=string.format("INTEL %s (%s) | ", self.alias, self.coalition and UTILS.GetCoalitionName(self.coalition) or "unknown") -- Start State. self:SetStartState("Stopped") diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index 65c6ae7ea..41a53905a 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -16,7 +16,6 @@ --- TARGET class. -- @type TARGET -- @field #string ClassName Name of the class. --- @field #boolean Debug Debug mode. Messages to all about status. -- @field #number verbose Verbosity level. -- @field #string lid Class id string for output to DCS log file. -- @field #table targets Table of target objects. @@ -25,7 +24,12 @@ -- @field #number life0 Total life points of completely healthy targets. -- @field #number threatlevel0 Initial threat level. -- @field #number category Target category (Ground, Air, Sea). --- @field #number Ntargets0 Number of initial targets. +-- @field #number N0 Number of initial target elements/units. +-- @field #number Ntargets0 Number of initial target objects. +-- @field #number Ndestroyed Number of target elements/units that were destroyed. +-- @field #number Ndead Number of target elements/units that are dead (destroyed or despawned). +-- @field #table elements Table of target elements/units. +-- @field #table casualties Table of dead element names. -- @extends Core.Fsm#FSM --- **It is far more important to be able to hit the target than it is to haggle over who makes a weapon or who pulls a trigger** -- Dwight D. Eisenhower @@ -44,14 +48,18 @@ -- @field #TARGET TARGET = { ClassName = "TARGET", - Debug = nil, verbose = 0, lid = nil, targets = {}, targetcounter = 0, life = 0, life0 = 0, + N0 = 0, Ntargets0 = 0, + Ndestroyed = 0, + Ndead = 0, + elements = {}, + casualties = {}, threatlevel0 = 0 } @@ -83,7 +91,7 @@ TARGET.ObjectType={ -- @field #string COORDINATE TARGET.Category={ AIRCRAFT="Aircraft", - GROUND="Grund", + GROUND="Ground", NAVAL="Naval", AIRBASE="Airbase", COORDINATE="Coordinate", @@ -97,14 +105,17 @@ TARGET.ObjectStatus={ ALIVE="Alive", DEAD="Dead", } ---- Type. +--- Target object. -- @type TARGET.Object -- @field #number ID Target unique ID. -- @field #string Name Target name. -- @field #string Type Target type. --- @field Wrapper.Positionable#POSITIONABLE Object The object, which can be many things, e.g. a UNIT, GROUP, STATIC, AIRBASE or COORDINATE object. +-- @field Wrapper.Positionable#POSITIONABLE Object The object, which can be many things, e.g. a UNIT, GROUP, STATIC, SCENERY, AIRBASE or COORDINATE object. -- @field #number Life Life points on last status update. -- @field #number Life0 Life points of completely healthy target. +-- @field #number N0 Number of initial elements. +-- @field #number Ndead Number of dead elements. +-- @field #number Ndestroyed Number of destroyed elements. -- @field #string Status Status "Alive" or "Dead". -- @field Core.Point#COORDINATE Coordinate of the target object. @@ -113,7 +124,7 @@ _TARGETID=0 --- TARGET class version. -- @field #string version -TARGET.version="0.2.1" +TARGET.version="0.3.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -144,7 +155,7 @@ function TARGET:New(TargetObject) local Target=self.targets[1] --#TARGET.Object if not Target then - self:E(self.lid.."ERROR: No valid TARGET!") + self:E("ERROR: No valid TARGET!") return nil end @@ -155,7 +166,7 @@ function TARGET:New(TargetObject) self.category=self:GetTargetCategory(Target) -- Log ID. - self.lid=string.format("TARGET #%03d %s | ", _TARGETID, self.category) + self.lid=string.format("TARGET #%03d [%s] | ", _TARGETID, tostring(self.category)) -- Start state. self:SetStartState("Stopped") @@ -166,12 +177,13 @@ function TARGET:New(TargetObject) self:AddTransition("*", "Status", "*") -- Status update. self:AddTransition("*", "Stop", "Stopped") -- Stop FSM. - self:AddTransition("*", "ObjectDamaged", "*") -- A Target was damaged. - self:AddTransition("*", "ObjectDestroyed", "*") -- A Target was destroyed. - self:AddTransition("*", "ObjectRemoved", "*") -- A Target was removed. + self:AddTransition("*", "ObjectDamaged", "*") -- A target object was damaged. + self:AddTransition("*", "ObjectDestroyed", "*") -- A target object was destroyed. + self:AddTransition("*", "ObjectDead", "*") -- A target object is dead (destroyed or despawned). - self:AddTransition("*", "Damaged", "*") -- Target was damaged. + self:AddTransition("*", "Damaged", "*") -- Target was damaged. self:AddTransition("*", "Destroyed", "Dead") -- Target was completely destroyed. + self:AddTransition("*", "Dead", "Dead") -- Target was completely destroyed. ------------------------ --- Pseudo Functions --- @@ -232,14 +244,6 @@ function TARGET:AddObject(Object) self:AddObject(object) end ---[[ - elseif Object:IsInstanceOf("GROUP") then - - for _,unit in pairs(Object:GetUnits()) do - self:_AddObject(unit) - end -]] - else --- @@ -254,14 +258,14 @@ end --- Check if TARGET is alive. -- @param #TARGET self --- @param #boolean If true, target is alive. +-- @return #boolean If true, target is alive. function TARGET:IsAlive() return self:Is("Alive") end --- Check if TARGET is dead. -- @param #TARGET self --- @param #boolean If true, target is dead. +-- @return #boolean If true, target is dead. function TARGET:IsDead() return self:Is("Dead") end @@ -284,8 +288,7 @@ function TARGET:onafterStart(From, Event, To) self:HandleEvent(EVENTS.Dead, self.OnEventUnitDeadOrLost) self:HandleEvent(EVENTS.UnitLost, self.OnEventUnitDeadOrLost) - - self:HandleEvent(EVENTS.RemoveUnit, self.OnEventRemoveUnit) + self:HandleEvent(EVENTS.RemoveUnit, self.OnEventUnitDeadOrLost) self:__Status(-1) end @@ -323,8 +326,8 @@ function TARGET:onafterStatus(From, Event, To) end -- Log output verbose=1. - if self.verbose>=0 then - local text=string.format("%s: Targets=%d/%d Life=%.1f/%.1f Damage=%.1f", fsmstate, self:CountTargets(), self.Ntargets0, self:GetLife(), self:GetLife0(), self:GetDamage()) + if self.verbose>=1 then + local text=string.format("%s: Targets=%d/%d Life=%.1f/%.1f Damage=%.1f", fsmstate, self:CountTargets(), self.N0, self:GetLife(), self:GetLife0(), self:GetDamage()) if damaged then text=text.." Damaged!" end @@ -332,7 +335,7 @@ function TARGET:onafterStatus(From, Event, To) end -- Log output verbose=2. - if self.verbose>=0 then + if self.verbose>=2 then local text="Target:" for i,_target in pairs(self.targets) do local target=_target --#TARGET.Object @@ -343,7 +346,9 @@ function TARGET:onafterStatus(From, Event, To) end -- Update status again in 30 sec. - self:__Status(-30) + if self:IsAlive() then + self:__Status(-30) + end end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -358,6 +363,7 @@ end -- @param #TARGET.Object Target Target object. function TARGET:onafterObjectDamaged(From, Event, To, Target) + -- Debug info. self:T(self.lid..string.format("Object %s damaged", Target.Name)) end @@ -371,11 +377,33 @@ end function TARGET:onafterObjectDestroyed(From, Event, To, Target) -- Debug message. - self:I(self.lid..string.format("Object %s destroyed", Target.Name)) + self:T(self.lid..string.format("Object %s destroyed", Target.Name)) + -- Increase destroyed counter. + self.Ndestroyed=self.Ndestroyed+1 + + -- Call object dead event. + self:ObjectDead(Target) + +end + +--- On after "ObjectDead" event. +-- @param #TARGET self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param #TARGET.Object Target Target object. +function TARGET:onafterObjectDead(From, Event, To, Target) + + -- Debug message. + self:T(self.lid..string.format("Object %s dead", Target.Name)) + -- Set target status. Target.Status=TARGET.ObjectStatus.DEAD + -- Increase dead counter. + self.Ndead=self.Ndead+1 + -- Check if anyone is alive? local dead=true for _,_target in pairs(self.targets) do @@ -387,7 +415,16 @@ function TARGET:onafterObjectDestroyed(From, Event, To, Target) -- All dead ==> Trigger destroyed event. if dead then - self:Destroyed() + + if self.Ndestroyed==self.Ntargets0 then + + self:Destroyed() + + else + + self:Dead() + + end end end @@ -399,7 +436,7 @@ end -- @param #string To To state. function TARGET:onafterDamaged(From, Event, To) - self:T(self.lid..string.format("Target damaged")) + self:T(self.lid..string.format("TARGET damaged")) end @@ -410,7 +447,20 @@ end -- @param #string To To state. function TARGET:onafterDestroyed(From, Event, To) - self:I(self.lid..string.format("Target destroyed")) + self:T(self.lid..string.format("TARGET destroyed")) + + self:Dead() + +end + +--- On after "Dead" event. +-- @param #TARGET self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function TARGET:onafterDead(From, Event, To) + + self:T(self.lid..string.format("TARGET dead")) end @@ -423,41 +473,58 @@ end -- @param Core.Event#EVENTDATA EventData Event data. function TARGET:OnEventUnitDeadOrLost(EventData) + local Name=EventData and EventData.IniUnitName or nil + -- Check that this is the right group. - if EventData and EventData.IniUnitName then + if self:IsElement(Name) and not self:IsCasualty(Name) then -- Debug info. - self:T(self.lid..string.format("EVENT: Unit %s dead or lost!", tostring(EventData.IniUnitName))) + self:T3(self.lid..string.format("EVENT ID=%d: Unit %s dead or lost!", EventData.id, tostring(Name))) - local deadnow=false - - -- Target + -- Add to the list of casualties. + table.insert(self.casualties, Name) + + -- Try to get target Group. local target=self:GetTargetByName(EventData.IniGroupName) - if target then - - local N=self:CountObjectives(target) - if N==0 then - deadnow=true - end - - else - target=self:GetTargetByName(EventData.IniUnitName) - if target then - deadnow=true - end + -- Try unit target. + if not target then + target=self:GetTargetByName(EventData.IniUnitName) end - - -- Check if this is one of ours. - if deadnow and target.Status==TARGET.ObjectStatus.ALIVE then - -- Debug message. - self:T(self.lid..string.format("EVENT: target unit %s dead or lost ==> destroyed", tostring(target.Name))) - - -- Trigger object destroyed event. - self:ObjectDestroyed(target) + -- Check if we could find a target object. + if target then + + if EventData.id==EVENTS.RemoveUnit then + target.Ndead=target.Ndead+1 + else + target.Ndestroyed=target.Ndestroyed+1 + target.Ndead=target.Ndead+1 + end - end + if target.Ndead==target.N0 then + + if target.Ndestroyed>=target.N0 then + + -- Debug message. + self:T2(self.lid..string.format("EVENT ID=%d: target %s dead/lost ==> destroyed", EventData.id, tostring(target.Name))) + + -- Trigger object destroyed event. + self:ObjectDestroyed(target) + + else + + -- Debug message. + self:T2(self.lid..string.format("EVENT ID=%d: target %s removed ==> dead", EventData.id, tostring(target.Name))) + + -- Trigger object dead event. + self:ObjectDead(target) + + end + + end + + end -- Event belongs to this TARGET end @@ -474,6 +541,10 @@ function TARGET:_AddObject(Object) local target={} --#TARGET.Object + target.N0=0 + target.Ndead=0 + target.Ndestroyed=0 + if Object:IsInstanceOf("GROUP") then local group=Object --Wrapper.Group#GROUP @@ -496,7 +567,9 @@ function TARGET:_AddObject(Object) self.threatlevel0=self.threatlevel0+unit:GetThreatLevel() - self.Ntargets0=self.Ntargets0+1 + table.insert(self.elements, unit:GetName()) + + target.N0=target.N0+1 end elseif Object:IsInstanceOf("UNIT") then @@ -514,7 +587,9 @@ function TARGET:_AddObject(Object) self.threatlevel0=self.threatlevel0+unit:GetThreatLevel() - self.Ntargets0=self.Ntargets0+1 + table.insert(self.elements, unit:GetName()) + + target.N0=target.N0+1 end elseif Object:IsInstanceOf("STATIC") then @@ -527,10 +602,13 @@ function TARGET:_AddObject(Object) target.Coordinate=static:GetCoordinate() if static and static:IsAlive() then + target.Life0=1 - target.Life=1 + target.Life=1 + target.N0=target.N0+1 + + table.insert(self.elements, target.Name) - self.Ntargets0=self.Ntargets0+1 end elseif Object:IsInstanceOf("SCENERY") then @@ -545,7 +623,9 @@ function TARGET:_AddObject(Object) target.Life0=1 target.Life=1 - self.Ntargets0=self.Ntargets0+1 + target.N0=target.N0+1 + + table.insert(self.elements, target.Name) elseif Object:IsInstanceOf("AIRBASE") then @@ -559,7 +639,9 @@ function TARGET:_AddObject(Object) target.Life0=1 target.Life=1 - self.Ntargets0=self.Ntargets0+1 + target.N0=target.N0+1 + + table.insert(self.elements, target.Name) elseif Object:IsInstanceOf("COORDINATE") then @@ -593,6 +675,9 @@ function TARGET:_AddObject(Object) self.life=self.life+target.Life self.life0=self.life0+target.Life0 + + self.N0=self.N0+target.N0 + self.Ntargets0=self.Ntargets0+1 -- Increase counter. self.targetcounter=self.targetcounter+1 @@ -1009,7 +1094,7 @@ end -- @return #number Number of alive target objects. function TARGET:CountObjectives(Target) - local N=1 + local N=0 if Target.Type==TARGET.ObjectType.GROUP then @@ -1028,7 +1113,7 @@ function TARGET:CountObjectives(Target) local target=Target.Object --Wrapper.Unit#UNIT - if target and target:IsAlive() and target:GetLife()>1 then + if target and target:IsAlive()~=nil and target:GetLife()>1 then N=N+1 end @@ -1080,6 +1165,45 @@ function TARGET:CountTargets() return N end +--- Check if something is an element of the TARGET. +-- @param #TARGET self +-- @param #string Name The name of the potential element. +-- @return #boolean If `true`, this name is part of this TARGET. +function TARGET:IsElement(Name) + + if Name==nil then + return false + end + + for _,name in pairs(self.elements) do + if name==Name then + return true + end + end + + return false +end + +--- Check if something is a a casualty of this TARGET. +-- @param #TARGET self +-- @param #string Name The name of the potential element. +-- @return #boolean If `true`, this name is a casualty of this TARGET. +function TARGET:IsCasualty(Name) + + if Name==nil then + return false + end + + for _,name in pairs(self.casualties) do + if name==Name then + return true + end + end + + return false +end + + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From 94863ed8ae05bebe2f09998d68c5b4a070865655 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 24 Nov 2020 22:00:36 +0100 Subject: [PATCH 7/8] Update OpsGroup.lua --- Moose Development/Moose/Ops/OpsGroup.lua | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 79240503b..d1abc64bd 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -3497,8 +3497,15 @@ function OPSGROUP:SetLaserTarget(Target) if Target then - -- Check if we have a POSITIONABLE. - if Target:IsInstanceOf("POSITIONABLE") then + -- Check object type. + if Target:IsInstanceOf("SCENERY") then + + -- Scenery as target. Treat it like a coordinate. Set offset to 1 meter above ground. + self.spot.TargetType=0 + self.spot.offsetTarget={x=0, y=1, z=0} + + elseif Target:IsInstanceOf("POSITIONABLE") then + local target=Target --Wrapper.Positionable#POSITIONABLE if target:IsAlive() then @@ -3535,13 +3542,11 @@ function OPSGROUP:SetLaserTarget(Target) end elseif Target:IsInstanceOf("COORDINATE") then + -- Coordinate as target. self.spot.TargetType=0 self.spot.offsetTarget={x=0, y=0, z=0} - elseif Target:IsInstanceOf("SCENERY") then - -- Coordinate as target. - self.spot.TargetType=0 - self.spot.offsetTarget={x=0, y=1, z=0} + else self:E(self.lid.."ERROR: LASER target should be a POSITIONABLE (GROUP, UNIT or STATIC) or a COORDINATE object!") return From 5b83f8e45b0905100e31902f3cd29430e24f72d6 Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 25 Nov 2020 11:27:07 +0100 Subject: [PATCH 8/8] OPS --- Moose Development/Moose/Ops/OpsGroup.lua | 10 ++++++---- Moose Development/Moose/Utilities/Utils.lua | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index d1abc64bd..48145683b 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -90,6 +90,7 @@ -- @field #OPSGROUP.Spot spot Laser and IR spot. -- -- @field #OPSGROUP.Ammo ammo Initial ammount of ammo. +-- @field #OPSGROUP.WeaponData weaponData Weapon data table with key=BitType. -- -- @extends Core.Fsm#FSM @@ -144,6 +145,7 @@ OPSGROUP = { callsign = {}, Ndestroyed = 0, Nkills = 0, + weaponData = {}, } @@ -601,14 +603,14 @@ end --- Add a weapon range for ARTY auftrag. -- @param #OPSGROUP self --- @param #number RangeMin Minimum range in kilometers. Default 0 km. --- @param #number RangeMax Maximum range in kilometers. Default 10 km. +-- @param #number RangeMin Minimum range in nautical miles. Default 0 NM. +-- @param #number RangeMax Maximum range in nautical miles. Default 10 NM. -- @param #number BitType Bit mask of weapon type for which the given min/max ranges apply. Default is `ENUMS.WeaponFlag.Auto`, i.e. for all weapon types. -- @return #OPSGROUP self function OPSGROUP:AddWeaponRange(RangeMin, RangeMax, BitType) - RangeMin=(RangeMin or 0)*1000 - RangeMax=(RangeMax or 10)*1000 + RangeMin=UTILS.NMToMeters(RangeMin or 0) + RangeMax=UTILS.NMToMeters(RangeMax or 10) local weapon={} --#OPSGROUP.WeaponData diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 40ba3e932..e0eb873da 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -324,18 +324,34 @@ UTILS.MetersToNM = function(meters) return meters/1852 end +UTILS.KiloMetersToNM = function(kilometers) + return kilometers/1852*1000 +end + UTILS.MetersToSM = function(meters) return meters/1609.34 end +UTILS.KiloMetersToSM = function(kilometers) + return kilometers/1609.34*1000 +end + UTILS.MetersToFeet = function(meters) return meters/0.3048 end +UTILS.KiloMetersToFeet = function(kilometers) + return kilometers/0.3048*1000 +end + UTILS.NMToMeters = function(NM) return NM*1852 end +UTILS.NMToKiloMeters = function(NM) + return NM*1852/1000 +end + UTILS.FeetToMeters = function(feet) return feet*0.3048 end