mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge branch 'FF/Ops' into FF/OpsDev
This commit is contained in:
commit
206528a530
@ -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
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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: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: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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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
|
||||
|
||||
@ -2781,6 +2783,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
|
||||
@ -3493,8 +3499,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
|
||||
@ -3531,13 +3544,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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.0"
|
||||
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 ---
|
||||
@ -231,13 +243,7 @@ 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
|
||||
|
||||
---
|
||||
@ -252,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
|
||||
@ -282,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
|
||||
@ -321,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
|
||||
@ -330,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
|
||||
@ -341,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
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -356,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
|
||||
@ -369,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
|
||||
@ -385,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
|
||||
@ -397,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
|
||||
|
||||
@ -408,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
|
||||
|
||||
@ -421,29 +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:I(self.lid..string.format("EVENT: Unit %s dead or lost!", EventData.IniUnitName))
|
||||
self:T3(self.lid..string.format("EVENT ID=%d: Unit %s dead or lost!", EventData.id, tostring(Name)))
|
||||
|
||||
-- Get target.
|
||||
local target=self:GetTargetByName(EventData.IniUnitName)
|
||||
-- Add to the list of casualties.
|
||||
table.insert(self.casualties, Name)
|
||||
|
||||
-- Try to get target Group.
|
||||
local target=self:GetTargetByName(EventData.IniGroupName)
|
||||
|
||||
if not target then
|
||||
target=self:GetTargetByName(EventData.IniGroupName)
|
||||
-- Try unit target.
|
||||
if not target then
|
||||
target=self:GetTargetByName(EventData.IniUnitName)
|
||||
end
|
||||
|
||||
-- Check if this is one of ours.
|
||||
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))
|
||||
|
||||
-- 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
|
||||
|
||||
@ -460,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
|
||||
@ -482,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
|
||||
@ -500,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
|
||||
@ -513,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
|
||||
@ -531,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
|
||||
|
||||
@ -545,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
|
||||
|
||||
@ -579,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
|
||||
@ -989,6 +1088,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=0
|
||||
|
||||
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()~=nil 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,60 +1158,52 @@ 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() 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
|
||||
|
||||
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
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user