Merge branch 'develop' into FF/Ops

This commit is contained in:
Frank 2024-01-01 21:54:51 +01:00
commit c8b36b8c99
50 changed files with 2571 additions and 1278 deletions

View File

@ -95,10 +95,6 @@ jobs:
export COMMIT_TIME=$(git show -s --format=%cd ${{ github.sha }} --date=iso-strict) export COMMIT_TIME=$(git show -s --format=%cd ${{ github.sha }} --date=iso-strict)
lua5.3 "./Moose Setup/Moose_Create.lua" D "$COMMIT_TIME-${{ github.sha }}" "./Moose Development/Moose" "./Moose Setup" "./build/result/Moose_Include_Dynamic" lua5.3 "./Moose Setup/Moose_Create.lua" D "$COMMIT_TIME-${{ github.sha }}" "./Moose Development/Moose" "./Moose Setup" "./build/result/Moose_Include_Dynamic"
- name: Run LuaSrcDiet
run: |
luasrcdiet --basic --opt-emptylines ./build/result/Moose_Include_Static/Moose.lua -o ./build/result/Moose_Include_Static/Moose_.lua
######################################################################### #########################################################################
# Run LuaCheck # Run LuaCheck
######################################################################### #########################################################################
@ -108,6 +104,10 @@ jobs:
run: | run: |
luacheck --std=lua51c --config=.luacheckrc -gurasqq "Moose Development/Moose" luacheck --std=lua51c --config=.luacheckrc -gurasqq "Moose Development/Moose"
- name: Run LuaSrcDiet
run: |
luasrcdiet --basic --opt-emptylines ./build/result/Moose_Include_Static/Moose.lua -o ./build/result/Moose_Include_Static/Moose_.lua
######################################################################### #########################################################################
# Push to MOOSE_INCLUDE # Push to MOOSE_INCLUDE
######################################################################### #########################################################################

View File

@ -23,7 +23,7 @@
-- --
-- ## Missions: -- ## Missions:
-- --
-- [AID-A2A - AI A2A Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching) -- [AID-A2A - AI A2A Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher)
-- --
-- === -- ===
-- --
@ -310,7 +310,7 @@ do -- AI_A2A_DISPATCHER
-- Use the method @{#AI_A2A_DISPATCHER.SetEngageRadius}() to set a specific Engage Radius. -- Use the method @{#AI_A2A_DISPATCHER.SetEngageRadius}() to set a specific Engage Radius.
-- **The Engage Radius is defined for ALL squadrons which are operational.** -- **The Engage Radius is defined for ALL squadrons which are operational.**
-- --
-- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching/AID-A2A-019%20-%20Engage%20Range%20Test) -- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher/AID-A2A-019%20-%20Engage%20Range%20Test)
-- --
-- In this example an Engage Radius is set to various values. -- In this example an Engage Radius is set to various values.
-- --
@ -333,7 +333,7 @@ do -- AI_A2A_DISPATCHER
-- Use the method @{#AI_A2A_DISPATCHER.SetGciRadius}() to set a specific controlled ground intercept radius. -- Use the method @{#AI_A2A_DISPATCHER.SetGciRadius}() to set a specific controlled ground intercept radius.
-- **The Ground Controlled Intercept radius is defined for ALL squadrons which are operational.** -- **The Ground Controlled Intercept radius is defined for ALL squadrons which are operational.**
-- --
-- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching/AID-A2A-013%20-%20Intercept%20Test) -- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher/AID-A2A-013%20-%20Intercept%20Test)
-- --
-- In these examples, the Gci Radius is set to various values: -- In these examples, the Gci Radius is set to various values:
-- --
@ -366,7 +366,7 @@ do -- AI_A2A_DISPATCHER
-- it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. -- it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are.
-- In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. -- In a hot war the borders are effectively defined by the ground based radar coverage of a coalition.
-- --
-- Demonstration Mission: [AID-009 - AI_A2A - Border Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching/AID-A2A-009%20-%20Border%20Test) -- Demonstration Mission: [AID-009 - AI_A2A - Border Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher/AID-A2A-009%20-%20Border%20Test)
-- --
-- In this example a border is set for the CCCP A2A dispatcher: -- In this example a border is set for the CCCP A2A dispatcher:
-- --
@ -1233,7 +1233,7 @@ do -- AI_A2A_DISPATCHER
-- --
-- **Use the method @{#AI_A2A_DISPATCHER.SetEngageRadius}() to modify the default Engage Radius for ALL squadrons.** -- **Use the method @{#AI_A2A_DISPATCHER.SetEngageRadius}() to modify the default Engage Radius for ALL squadrons.**
-- --
-- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching/AID-A2A-019%20-%20Engage%20Range%20Test) -- Demonstration Mission: [AID-019 - AI_A2A - Engage Range Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher/AID-A2A-019%20-%20Engage%20Range%20Test)
-- --
-- @param #AI_A2A_DISPATCHER self -- @param #AI_A2A_DISPATCHER self
-- @param #number EngageRadius (Optional, Default = 100000) The radius to report friendlies near the target. -- @param #number EngageRadius (Optional, Default = 100000) The radius to report friendlies near the target.
@ -1283,7 +1283,7 @@ do -- AI_A2A_DISPATCHER
-- Use the method @{#AI_A2A_DISPATCHER.SetGciRadius}() to set a specific controlled ground intercept radius. -- Use the method @{#AI_A2A_DISPATCHER.SetGciRadius}() to set a specific controlled ground intercept radius.
-- **The Ground Controlled Intercept radius is defined for ALL squadrons which are operational.** -- **The Ground Controlled Intercept radius is defined for ALL squadrons which are operational.**
-- --
-- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching/AID-A2A-013%20-%20Intercept%20Test) -- Demonstration Mission: [AID-013 - AI_A2A - Intercept Test](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher/AID-A2A-013%20-%20Intercept%20Test)
-- --
-- @param #AI_A2A_DISPATCHER self -- @param #AI_A2A_DISPATCHER self
-- @param #number GciRadius (Optional, Default = 200000) The radius to ground control intercept detected targets from the nearest airbase. -- @param #number GciRadius (Optional, Default = 200000) The radius to ground control intercept detected targets from the nearest airbase.
@ -3257,7 +3257,8 @@ do -- AI_A2A_DISPATCHER
end end
end end
--- @param #AI_A2A_DISPATCHER self --- AI_A2A_Fsm:onafterHome
-- @param #AI_A2A_DISPATCHER self
function AI_A2A_Fsm:onafterHome( Defender, From, Event, To, Action ) function AI_A2A_Fsm:onafterHome( Defender, From, Event, To, Action )
if Defender and Defender:IsAlive() then if Defender and Defender:IsAlive() then
self:F( { "CAP Home", Defender:GetName() } ) self:F( { "CAP Home", Defender:GetName() } )
@ -3505,7 +3506,8 @@ do -- AI_A2A_DISPATCHER
Dispatcher:ClearDefenderTaskTarget( DefenderGroup ) Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
end end
--- @param #AI_A2A_DISPATCHER self --- function Fsm:onafterLostControl
-- @param #AI_A2A_DISPATCHER self
function Fsm:onafterLostControl( Defender, From, Event, To ) function Fsm:onafterLostControl( Defender, From, Event, To )
self:F( { "GCI LostControl", Defender:GetName() } ) self:F( { "GCI LostControl", Defender:GetName() } )
self:GetParent( self ).onafterHome( self, Defender, From, Event, To ) self:GetParent( self ).onafterHome( self, Defender, From, Event, To )
@ -3518,7 +3520,8 @@ do -- AI_A2A_DISPATCHER
end end
end end
--- @param #AI_A2A_DISPATCHER self --- function Fsm:onafterHome
-- @param #AI_A2A_DISPATCHER self
function Fsm:onafterHome( DefenderGroup, From, Event, To, Action ) function Fsm:onafterHome( DefenderGroup, From, Event, To, Action )
self:F( { "GCI Home", DefenderGroup:GetName() } ) self:F( { "GCI Home", DefenderGroup:GetName() } )
self:GetParent( self ).onafterHome( self, DefenderGroup, From, Event, To ) self:GetParent( self ).onafterHome( self, DefenderGroup, From, Event, To )
@ -3959,7 +3962,7 @@ do
-- --
-- # Demo Missions -- # Demo Missions
-- --
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching) -- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher)
-- --
-- === -- ===
-- --

View File

@ -24,7 +24,7 @@
-- --
-- ## Missions: -- ## Missions:
-- --
-- [AID-A2G - AI A2G Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2G%20-%20AI%20A2G%20Dispatching) -- [AID-A2G - AI A2G Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2G_Dispatcher)
-- --
-- === -- ===
-- --

View File

@ -24,7 +24,7 @@
-- --
-- ## Missions: -- ## Missions:
-- --
-- [AID-AIR - AI AIR Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching) -- [AI_A2A_Dispatcher](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_A2A_Dispatcher)
-- --
-- === -- ===
-- --

View File

@ -9,7 +9,7 @@
-- --
-- === -- ===
-- --
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AIB%20-%20AI%20Balancing) -- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_Balancer)
-- --
-- === -- ===
-- --
@ -168,7 +168,8 @@ function AI_BALANCER:ReturnToHomeAirbase( ReturnThresholdRange )
self.ReturnThresholdRange = ReturnThresholdRange self.ReturnThresholdRange = ReturnThresholdRange
end end
--- @param #AI_BALANCER self --- AI_BALANCER:onenterSpawning
-- @param #AI_BALANCER self
-- @param Core.Set#SET_GROUP SetGroup -- @param Core.Set#SET_GROUP SetGroup
-- @param #string ClientName -- @param #string ClientName
-- @param Wrapper.Group#GROUP AIGroup -- @param Wrapper.Group#GROUP AIGroup
@ -190,7 +191,8 @@ function AI_BALANCER:onenterSpawning( SetGroup, From, Event, To, ClientName )
end end
end end
--- @param #AI_BALANCER self --- AI_BALANCER:onenterDestroying
-- @param #AI_BALANCER self
-- @param Core.Set#SET_GROUP SetGroup -- @param Core.Set#SET_GROUP SetGroup
-- @param Wrapper.Group#GROUP AIGroup -- @param Wrapper.Group#GROUP AIGroup
function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup ) function AI_BALANCER:onenterDestroying( SetGroup, From, Event, To, ClientName, AIGroup )
@ -233,15 +235,16 @@ function AI_BALANCER:onenterReturning( SetGroup, From, Event, To, AIGroup )
end end
--- AI_BALANCER:onenterMonitoring
--- @param #AI_BALANCER self -- @param #AI_BALANCER self
function AI_BALANCER:onenterMonitoring( SetGroup ) function AI_BALANCER:onenterMonitoring( SetGroup )
self:T2( { self.SetClient:Count() } ) self:T2( { self.SetClient:Count() } )
--self.SetClient:Flush() --self.SetClient:Flush()
self.SetClient:ForEachClient( self.SetClient:ForEachClient(
--- @param Wrapper.Client#CLIENT Client --- SetClient:ForEachClient
-- @param Wrapper.Client#CLIENT Client
function( Client ) function( Client )
self:T3(Client.ClientName) self:T3(Client.ClientName)
@ -264,7 +267,8 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
self:T2( RangeZone ) self:T2( RangeZone )
_DATABASE:ForEachPlayerUnit( _DATABASE:ForEachPlayerUnit(
--- @param Wrapper.Unit#UNIT RangeTestUnit --- Nameless function
-- @param Wrapper.Unit#UNIT RangeTestUnit
function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange ) function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange )
self:T2( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } ) self:T2( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } )
if RangeTestUnit:IsInZone( RangeZone ) == true then if RangeTestUnit:IsInZone( RangeZone ) == true then
@ -276,7 +280,8 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
end end
end, end,
--- @param Core.Zone#ZONE_RADIUS RangeZone --- Nameless function
-- @param Core.Zone#ZONE_RADIUS RangeZone
-- @param Wrapper.Group#GROUP AIGroup -- @param Wrapper.Group#GROUP AIGroup
function( RangeZone, AIGroup, PlayerInRange ) function( RangeZone, AIGroup, PlayerInRange )
if PlayerInRange.Value == false then if PlayerInRange.Value == false then
@ -307,6 +312,3 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
self:__Monitor( 10 ) self:__Monitor( 10 )
end end

View File

@ -18,7 +18,7 @@
-- --
-- Test missions can be located on the main GITHUB site. -- Test missions can be located on the main GITHUB site.
-- --
-- [FlightControl-Master/MOOSE_MISSIONS/AID - AI Dispatching/AID-CGO - AI Cargo Dispatching/](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/AID%20-%20AI%20Dispatching/AID-CGO%20-%20AI%20Cargo%20Dispatching) -- [FlightControl-Master/MOOSE_MISSIONS/AID - AI Dispatching/AID-CGO - AI Cargo Dispatching/](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AI/AI_Cargo_Dispatcher)
-- --
-- === -- ===
-- --
@ -583,10 +583,12 @@ AI_CARGO_DISPATCHER = {
PickupCargo = {} PickupCargo = {}
} }
--- @field #list --- List of AI_Cargo
-- @field #list
AI_CARGO_DISPATCHER.AI_Cargo = {} AI_CARGO_DISPATCHER.AI_Cargo = {}
--- @field #list --- List of PickupCargo
-- @field #list
AI_CARGO_DISPATCHER.PickupCargo = {} AI_CARGO_DISPATCHER.PickupCargo = {}

View File

@ -370,7 +370,7 @@ CARGOS = {}
do -- CARGO do -- CARGO
--- @type CARGO -- @type CARGO
-- @extends Core.Fsm#FSM_PROCESS -- @extends Core.Fsm#FSM_PROCESS
-- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers. -- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers.
-- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo. -- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo.
@ -433,7 +433,7 @@ do -- CARGO
Reported = {}, Reported = {},
} }
--- @type CARGO.CargoObjects -- @type CARGO.CargoObjects
-- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo. -- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo.
--- CARGO Constructor. This class is an abstract class and should not be instantiated. --- CARGO Constructor. This class is an abstract class and should not be instantiated.
@ -447,7 +447,7 @@ do -- CARGO
function CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) --R2.1 function CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) --R2.1
local self = BASE:Inherit( self, FSM:New() ) -- #CARGO local self = BASE:Inherit( self, FSM:New() ) -- #CARGO
self:F( { Type, Name, Weight, LoadRadius, NearRadius } ) self:T( { Type, Name, Weight, LoadRadius, NearRadius } )
self:SetStartState( "UnLoaded" ) self:SetStartState( "UnLoaded" )
self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" ) self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" )
@ -711,7 +711,7 @@ do -- CARGO
-- @param #CARGO self -- @param #CARGO self
-- @return #CARGO -- @return #CARGO
function CARGO:Spawn( PointVec2 ) function CARGO:Spawn( PointVec2 )
self:F() self:T()
end end
@ -812,7 +812,7 @@ do -- CARGO
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the CargoGroup is within the loading radius. -- @return #boolean true if the CargoGroup is within the loading radius.
function CARGO:IsInLoadRadius( Coordinate ) function CARGO:IsInLoadRadius( Coordinate )
self:F( { Coordinate, LoadRadius = self.LoadRadius } ) self:T( { Coordinate, LoadRadius = self.LoadRadius } )
local Distance = 0 local Distance = 0
if self:IsUnLoaded() then if self:IsUnLoaded() then
@ -832,7 +832,7 @@ do -- CARGO
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the Cargo can report itself. -- @return #boolean true if the Cargo can report itself.
function CARGO:IsInReportRadius( Coordinate ) function CARGO:IsInReportRadius( Coordinate )
self:F( { Coordinate } ) self:T( { Coordinate } )
local Distance = 0 local Distance = 0
if self:IsUnLoaded() then if self:IsUnLoaded() then
@ -853,23 +853,23 @@ do -- CARGO
-- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision).
-- @return #boolean -- @return #boolean
function CARGO:IsNear( Coordinate, NearRadius ) function CARGO:IsNear( Coordinate, NearRadius )
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) --self:T( { PointVec2 = PointVec2, NearRadius = NearRadius } )
if self.CargoObject:IsAlive() then if self.CargoObject:IsAlive() then
--local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) --local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() )
--self:F( { CargoObjectName = self.CargoObject:GetName() } ) --self:T( { CargoObjectName = self.CargoObject:GetName() } )
--self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) --self:T( { CargoObjectVec2 = self.CargoObject:GetVec2() } )
--self:F( { PointVec2 = PointVec2:GetVec2() } ) --self:T( { PointVec2 = PointVec2:GetVec2() } )
local Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) local Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
--self:F( { Distance = Distance, NearRadius = NearRadius or "nil" } ) --self:T( { Distance = Distance, NearRadius = NearRadius or "nil" } )
if Distance <= NearRadius then if Distance <= NearRadius then
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = true } ) --self:T( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = true } )
return true return true
end end
end end
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = false } ) --self:T( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = false } )
return false return false
end end
@ -878,12 +878,12 @@ do -- CARGO
-- @param Core.Zone#ZONE_BASE Zone -- @param Core.Zone#ZONE_BASE Zone
-- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone. -- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone.
function CARGO:IsInZone( Zone ) function CARGO:IsInZone( Zone )
--self:F( { Zone } ) --self:T( { Zone } )
if self:IsLoaded() then if self:IsLoaded() then
return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() ) return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() )
else else
--self:F( { Size = self.CargoObject:GetSize(), Units = self.CargoObject:GetUnits() } ) --self:T( { Size = self.CargoObject:GetSize(), Units = self.CargoObject:GetUnits() } )
if self.CargoObject:GetSize() ~= 0 then if self.CargoObject:GetSize() ~= 0 then
return Zone:IsPointVec2InZone( self.CargoObject:GetPointVec2() ) return Zone:IsPointVec2InZone( self.CargoObject:GetPointVec2() )
else else
@ -1034,7 +1034,7 @@ end -- CARGO
do -- CARGO_REPRESENTABLE do -- CARGO_REPRESENTABLE
--- @type CARGO_REPRESENTABLE -- @type CARGO_REPRESENTABLE
-- @extends #CARGO -- @extends #CARGO
-- @field test -- @field test
@ -1056,7 +1056,7 @@ do -- CARGO_REPRESENTABLE
-- Inherit CARGO. -- Inherit CARGO.
local self = BASE:Inherit( self, CARGO:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE local self = BASE:Inherit( self, CARGO:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE
self:F( { Type, Name, LoadRadius, NearRadius } ) self:T( { Type, Name, LoadRadius, NearRadius } )
-- Descriptors. -- Descriptors.
local Desc=CargoObject:GetDesc() local Desc=CargoObject:GetDesc()
@ -1086,7 +1086,7 @@ do -- CARGO_REPRESENTABLE
function CARGO_REPRESENTABLE:Destroy() function CARGO_REPRESENTABLE:Destroy()
-- Cargo objects are deleted from the _DATABASE and SET_CARGO objects. -- Cargo objects are deleted from the _DATABASE and SET_CARGO objects.
self:F( { CargoName = self:GetName() } ) self:T( { CargoName = self:GetName() } )
--_EVENTDISPATCHER:CreateEventDeleteCargo( self ) --_EVENTDISPATCHER:CreateEventDeleteCargo( self )
return self return self
@ -1123,12 +1123,12 @@ do -- CARGO_REPRESENTABLE
CoordinateZone:Scan( { Object.Category.UNIT } ) CoordinateZone:Scan( { Object.Category.UNIT } )
for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do
local NearUnit = UNIT:Find( DCSUnit ) local NearUnit = UNIT:Find( DCSUnit )
self:F({NearUnit=NearUnit}) self:T({NearUnit=NearUnit})
local NearUnitCoalition = NearUnit:GetCoalition() local NearUnitCoalition = NearUnit:GetCoalition()
local CargoCoalition = self:GetCoalition() local CargoCoalition = self:GetCoalition()
if NearUnitCoalition == CargoCoalition then if NearUnitCoalition == CargoCoalition then
local Attributes = NearUnit:GetDesc() local Attributes = NearUnit:GetDesc()
self:F({Desc=Attributes}) self:T({Desc=Attributes})
if NearUnit:HasAttribute( "Trucks" ) then if NearUnit:HasAttribute( "Trucks" ) then
MESSAGE:New( Message, 20, NearUnit:GetCallsign() .. " reporting - Cargo " .. self:GetName() ):ToGroup( TaskGroup ) MESSAGE:New( Message, 20, NearUnit:GetCallsign() .. " reporting - Cargo " .. self:GetName() ):ToGroup( TaskGroup )
break break
@ -1142,7 +1142,7 @@ end -- CARGO_REPRESENTABLE
do -- CARGO_REPORTABLE do -- CARGO_REPORTABLE
--- @type CARGO_REPORTABLE -- @type CARGO_REPORTABLE
-- @extends #CARGO -- @extends #CARGO
CARGO_REPORTABLE = { CARGO_REPORTABLE = {
ClassName = "CARGO_REPORTABLE" ClassName = "CARGO_REPORTABLE"
@ -1158,7 +1158,7 @@ do -- CARGO_REPORTABLE
-- @return #CARGO_REPORTABLE -- @return #CARGO_REPORTABLE
function CARGO_REPORTABLE:New( Type, Name, Weight, LoadRadius, NearRadius ) function CARGO_REPORTABLE:New( Type, Name, Weight, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_REPORTABLE local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_REPORTABLE
self:F( { Type, Name, Weight, LoadRadius, NearRadius } ) self:T( { Type, Name, Weight, LoadRadius, NearRadius } )
return self return self
end end
@ -1178,7 +1178,7 @@ end
do -- CARGO_PACKAGE do -- CARGO_PACKAGE
--- @type CARGO_PACKAGE -- @type CARGO_PACKAGE
-- @extends #CARGO_REPRESENTABLE -- @extends #CARGO_REPRESENTABLE
CARGO_PACKAGE = { CARGO_PACKAGE = {
ClassName = "CARGO_PACKAGE" ClassName = "CARGO_PACKAGE"
@ -1195,7 +1195,7 @@ do -- CARGO_PACKAGE
-- @return #CARGO_PACKAGE -- @return #CARGO_PACKAGE
function CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, LoadRadius, NearRadius ) function CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_PACKAGE local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_PACKAGE
self:F( { Type, Name, Weight, LoadRadius, NearRadius } ) self:T( { Type, Name, Weight, LoadRadius, NearRadius } )
self:T( CargoCarrier ) self:T( CargoCarrier )
self.CargoCarrier = CargoCarrier self.CargoCarrier = CargoCarrier
@ -1213,7 +1213,7 @@ end
-- @param #number BoardDistance -- @param #number BoardDistance
-- @param #number Angle -- @param #number Angle
function CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) function CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle )
self:F() self:T()
self.CargoInAir = self.CargoCarrier:InAir() self.CargoInAir = self.CargoCarrier:InAir()
@ -1246,7 +1246,7 @@ end
-- @param Wrapper.Unit#UNIT CargoCarrier -- @param Wrapper.Unit#UNIT CargoCarrier
-- @return #boolean -- @return #boolean
function CARGO_PACKAGE:IsNear( CargoCarrier ) function CARGO_PACKAGE:IsNear( CargoCarrier )
self:F() self:T()
local CargoCarrierPoint = CargoCarrier:GetCoordinate() local CargoCarrierPoint = CargoCarrier:GetCoordinate()
@ -1271,7 +1271,7 @@ end
-- @param #number LoadDistance -- @param #number LoadDistance
-- @param #number Angle -- @param #number Angle
function CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) function CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle )
self:F() self:T()
if self:IsNear( CargoCarrier ) then if self:IsNear( CargoCarrier ) then
self:__Load( 1, CargoCarrier, Speed, LoadDistance, Angle ) self:__Load( 1, CargoCarrier, Speed, LoadDistance, Angle )
@ -1292,7 +1292,7 @@ end
-- @param #number Radius -- @param #number Radius
-- @param #number Angle -- @param #number Angle
function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle ) function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle )
self:F() self:T()
self.CargoInAir = self.CargoCarrier:InAir() self.CargoInAir = self.CargoCarrier:InAir()
@ -1331,7 +1331,7 @@ end
-- @param Wrapper.Unit#UNIT CargoCarrier -- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number Speed -- @param #number Speed
function CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed ) function CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed )
self:F() self:T()
if self:IsNear( CargoCarrier ) then if self:IsNear( CargoCarrier ) then
self:__UnLoad( 1, CargoCarrier, Speed ) self:__UnLoad( 1, CargoCarrier, Speed )
@ -1350,7 +1350,7 @@ end
-- @param #number LoadDistance -- @param #number LoadDistance
-- @param #number Angle -- @param #number Angle
function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle ) function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle )
self:F() self:T()
self.CargoCarrier = CargoCarrier self.CargoCarrier = CargoCarrier
@ -1378,7 +1378,7 @@ end
-- @param #number Distance -- @param #number Distance
-- @param #number Angle -- @param #number Angle
function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle ) function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle )
self:F() self:T()
local StartPointVec2 = self.CargoCarrier:GetPointVec2() local StartPointVec2 = self.CargoCarrier:GetPointVec2()
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.

View File

@ -59,7 +59,7 @@ do -- CARGO_CRATE
-- @return #CARGO_CRATE -- @return #CARGO_CRATE
function CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) function CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_CRATE local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_CRATE
self:F( { Type, Name, NearRadius } ) self:T( { Type, Name, NearRadius } )
self.CargoObject = CargoStatic -- Wrapper.Static#STATIC self.CargoObject = CargoStatic -- Wrapper.Static#STATIC
@ -116,7 +116,7 @@ do -- CARGO_CRATE
-- @param #string To -- @param #string To
-- @param Core.Point#POINT_VEC2 -- @param Core.Point#POINT_VEC2
function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 ) function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 )
--self:F( { ToPointVec2, From, Event, To } ) --self:T( { ToPointVec2, From, Event, To } )
local Angle = 180 local Angle = 180
local Speed = 10 local Speed = 10
@ -153,7 +153,7 @@ do -- CARGO_CRATE
-- @param #string To -- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier -- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_CRATE:onenterLoaded( From, Event, To, CargoCarrier ) function CARGO_CRATE:onenterLoaded( From, Event, To, CargoCarrier )
--self:F( { From, Event, To, CargoCarrier } ) --self:T( { From, Event, To, CargoCarrier } )
self.CargoCarrier = CargoCarrier self.CargoCarrier = CargoCarrier
@ -190,7 +190,7 @@ do -- CARGO_CRATE
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the Cargo Crate is within the report radius. -- @return #boolean true if the Cargo Crate is within the report radius.
function CARGO_CRATE:IsInReportRadius( Coordinate ) function CARGO_CRATE:IsInReportRadius( Coordinate )
--self:F( { Coordinate, LoadRadius = self.LoadRadius } ) --self:T( { Coordinate, LoadRadius = self.LoadRadius } )
local Distance = 0 local Distance = 0
if self:IsUnLoaded() then if self:IsUnLoaded() then
@ -210,7 +210,7 @@ do -- CARGO_CRATE
-- @param Core.Point#Coordinate Coordinate -- @param Core.Point#Coordinate Coordinate
-- @return #boolean true if the Cargo Crate is within the loading radius. -- @return #boolean true if the Cargo Crate is within the loading radius.
function CARGO_CRATE:IsInLoadRadius( Coordinate ) function CARGO_CRATE:IsInLoadRadius( Coordinate )
--self:F( { Coordinate, LoadRadius = self.NearRadius } ) --self:T( { Coordinate, LoadRadius = self.NearRadius } )
local Distance = 0 local Distance = 0
if self:IsUnLoaded() then if self:IsUnLoaded() then
@ -231,7 +231,7 @@ do -- CARGO_CRATE
-- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup.
-- @return #nil There is no valid Cargo in the CargoGroup. -- @return #nil There is no valid Cargo in the CargoGroup.
function CARGO_CRATE:GetCoordinate() function CARGO_CRATE:GetCoordinate()
--self:F() --self:T()
return self.CargoObject:GetCoordinate() return self.CargoObject:GetCoordinate()
end end
@ -261,7 +261,7 @@ do -- CARGO_CRATE
-- @param #CARGO_CRATE self -- @param #CARGO_CRATE self
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
function CARGO_CRATE:RouteTo( Coordinate ) function CARGO_CRATE:RouteTo( Coordinate )
self:F( {Coordinate = Coordinate } ) self:T( {Coordinate = Coordinate } )
end end
@ -274,7 +274,7 @@ do -- CARGO_CRATE
-- @return #boolean The Cargo is near to the Carrier. -- @return #boolean The Cargo is near to the Carrier.
-- @return #nil The Cargo is not near to the Carrier. -- @return #nil The Cargo is not near to the Carrier.
function CARGO_CRATE:IsNear( CargoCarrier, NearRadius ) function CARGO_CRATE:IsNear( CargoCarrier, NearRadius )
self:F( {NearRadius = NearRadius } ) self:T( {NearRadius = NearRadius } )
return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius )
end end
@ -283,7 +283,7 @@ do -- CARGO_CRATE
-- @param #CARGO_CRATE self -- @param #CARGO_CRATE self
function CARGO_CRATE:Respawn() function CARGO_CRATE:Respawn()
self:F( { "Respawning crate " .. self:GetName() } ) self:T( { "Respawning crate " .. self:GetName() } )
-- Respawn the group... -- Respawn the group...
@ -300,7 +300,7 @@ do -- CARGO_CRATE
-- @param #CARGO_CRATE self -- @param #CARGO_CRATE self
function CARGO_CRATE:onafterReset() function CARGO_CRATE:onafterReset()
self:F( { "Reset crate " .. self:GetName() } ) self:T( { "Reset crate " .. self:GetName() } )
-- Respawn the group... -- Respawn the group...

View File

@ -64,7 +64,7 @@ do -- CARGO_GROUP
-- Inherit CAROG_REPORTABLE -- Inherit CAROG_REPORTABLE
local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_GROUP local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_GROUP
self:F( { Type, Name, LoadRadius } ) self:T( { Type, Name, LoadRadius } )
self.CargoSet = SET_CARGO:New() self.CargoSet = SET_CARGO:New()
self.CargoGroup = CargoGroup self.CargoGroup = CargoGroup
@ -146,7 +146,7 @@ do -- CARGO_GROUP
-- @param #CARGO_GROUP self -- @param #CARGO_GROUP self
function CARGO_GROUP:Respawn() function CARGO_GROUP:Respawn()
self:F( { "Respawning" } ) self:T( { "Respawning" } )
for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do
local Cargo = CargoData -- Cargo.Cargo#CARGO local Cargo = CargoData -- Cargo.Cargo#CARGO
@ -227,7 +227,7 @@ do -- CARGO_GROUP
-- @param #CARGO_GROUP self -- @param #CARGO_GROUP self
function CARGO_GROUP:Regroup() function CARGO_GROUP:Regroup()
self:F("Regroup") self:T("Regroup")
if self.Grouped == false then if self.Grouped == false then
@ -241,7 +241,7 @@ do -- CARGO_GROUP
for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do
local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT
self:F( { CargoUnit:GetName(), UnLoaded = CargoUnit:IsUnLoaded() } ) self:T( { CargoUnit:GetName(), UnLoaded = CargoUnit:IsUnLoaded() } )
if CargoUnit:IsUnLoaded() then if CargoUnit:IsUnLoaded() then
@ -258,7 +258,7 @@ do -- CARGO_GROUP
-- Then we register the new group in the database -- Then we register the new group in the database
self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID ) self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID )
self:F( { "Regroup", GroupTemplate } ) self:T( { "Regroup", GroupTemplate } )
-- Now we spawn the new group based on the template created. -- Now we spawn the new group based on the template created.
self.CargoObject = _DATABASE:Spawn( GroupTemplate ) self.CargoObject = _DATABASE:Spawn( GroupTemplate )
@ -271,7 +271,7 @@ do -- CARGO_GROUP
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function CARGO_GROUP:OnEventCargoDead( EventData ) function CARGO_GROUP:OnEventCargoDead( EventData )
self:E(EventData) self:T(EventData)
local Destroyed = false local Destroyed = false
@ -296,7 +296,7 @@ do -- CARGO_GROUP
if Destroyed then if Destroyed then
self:Destroyed() self:Destroyed()
self:E( { "Cargo group destroyed" } ) self:T( { "Cargo group destroyed" } )
end end
end end
@ -309,14 +309,14 @@ do -- CARGO_GROUP
-- @param Wrapper.Unit#UNIT CargoCarrier -- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... ) function CARGO_GROUP:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } ) self:T( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } )
NearRadius = NearRadius or self.NearRadius NearRadius = NearRadius or self.NearRadius
-- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach( self.CargoSet:ForEach(
function( Cargo, ... ) function( Cargo, ... )
self:F( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } ) self:T( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } )
local CargoGroup = Cargo.CargoObject --Wrapper.Group#GROUP local CargoGroup = Cargo.CargoObject --Wrapper.Group#GROUP
CargoGroup:OptionAlarmStateGreen() CargoGroup:OptionAlarmStateGreen()
Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) Cargo:__Board( 1, CargoCarrier, NearRadius, ... )
@ -334,7 +334,7 @@ do -- CARGO_GROUP
-- @param #string To -- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier -- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_GROUP:onafterLoad( From, Event, To, CargoCarrier, ... ) function CARGO_GROUP:onafterLoad( From, Event, To, CargoCarrier, ... )
--self:F( { From, Event, To, CargoCarrier, ...} ) --self:T( { From, Event, To, CargoCarrier, ...} )
if From == "UnLoaded" then if From == "UnLoaded" then
-- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier.
@ -359,7 +359,7 @@ do -- CARGO_GROUP
-- @param Wrapper.Unit#UNIT CargoCarrier -- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
--self:F( { CargoCarrier.UnitName, From, Event, To } ) --self:T( { CargoCarrier.UnitName, From, Event, To } )
local Boarded = true local Boarded = true
local Cancelled = false local Cancelled = false
@ -393,7 +393,7 @@ do -- CARGO_GROUP
if not Boarded then if not Boarded then
self:__Boarding( -5, CargoCarrier, NearRadius, ... ) self:__Boarding( -5, CargoCarrier, NearRadius, ... )
else else
self:F("Group Cargo is loaded") self:T("Group Cargo is loaded")
self:__Load( 1, CargoCarrier, ... ) self:__Load( 1, CargoCarrier, ... )
end end
else else
@ -413,7 +413,7 @@ do -- CARGO_GROUP
-- @param Core.Point#POINT_VEC2 ToPointVec2 -- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... ) function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... )
self:F( {From, Event, To, ToPointVec2, NearRadius } ) self:T( {From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25 NearRadius = NearRadius or 25
@ -456,7 +456,7 @@ do -- CARGO_GROUP
-- @param Core.Point#POINT_VEC2 ToPointVec2 -- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
--self:F( { From, Event, To, ToPointVec2, NearRadius } ) --self:T( { From, Event, To, ToPointVec2, NearRadius } )
--local NearRadius = NearRadius or 25 --local NearRadius = NearRadius or 25
@ -493,7 +493,7 @@ do -- CARGO_GROUP
-- @param #string To -- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2 -- @param Core.Point#POINT_VEC2 ToPointVec2
function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... ) function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... )
--self:F( { From, Event, To, ToPointVec2 } ) --self:T( { From, Event, To, ToPointVec2 } )
if From == "Loaded" then if From == "Loaded" then
@ -611,7 +611,7 @@ do -- CARGO_GROUP
-- @param #CARGO_GROUP self -- @param #CARGO_GROUP self
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
function CARGO_GROUP:RouteTo( Coordinate ) function CARGO_GROUP:RouteTo( Coordinate )
--self:F( {Coordinate = Coordinate } ) --self:T( {Coordinate = Coordinate } )
-- For each Cargo within the CargoSet, route each object to the Coordinate -- For each Cargo within the CargoSet, route each object to the Coordinate
self.CargoSet:ForEach( self.CargoSet:ForEach(
@ -629,13 +629,13 @@ do -- CARGO_GROUP
-- @param #number NearRadius -- @param #number NearRadius
-- @return #boolean The Cargo is near to the Carrier or #nil if the Cargo is not near to the Carrier. -- @return #boolean The Cargo is near to the Carrier or #nil if the Cargo is not near to the Carrier.
function CARGO_GROUP:IsNear( CargoCarrier, NearRadius ) function CARGO_GROUP:IsNear( CargoCarrier, NearRadius )
self:F( {NearRadius = NearRadius } ) self:T( {NearRadius = NearRadius } )
for _, Cargo in pairs( self.CargoSet:GetSet() ) do for _, Cargo in pairs( self.CargoSet:GetSet() ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO local Cargo = Cargo -- Cargo.Cargo#CARGO
if Cargo:IsAlive() then if Cargo:IsAlive() then
if Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) then if Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) then
self:F( "Near" ) self:T( "Near" )
return true return true
end end
end end
@ -649,7 +649,7 @@ do -- CARGO_GROUP
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the Cargo Group is within the load radius. -- @return #boolean true if the Cargo Group is within the load radius.
function CARGO_GROUP:IsInLoadRadius( Coordinate ) function CARGO_GROUP:IsInLoadRadius( Coordinate )
--self:F( { Coordinate } ) --self:T( { Coordinate } )
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
@ -669,7 +669,7 @@ do -- CARGO_GROUP
return false return false
end end
self:F( { Distance = Distance, LoadRadius = self.LoadRadius } ) self:T( { Distance = Distance, LoadRadius = self.LoadRadius } )
if Distance <= self.LoadRadius then if Distance <= self.LoadRadius then
return true return true
else else
@ -687,12 +687,12 @@ do -- CARGO_GROUP
-- @param Core.Point#Coordinate Coordinate -- @param Core.Point#Coordinate Coordinate
-- @return #boolean true if the Cargo Group is within the report radius. -- @return #boolean true if the Cargo Group is within the report radius.
function CARGO_GROUP:IsInReportRadius( Coordinate ) function CARGO_GROUP:IsInReportRadius( Coordinate )
--self:F( { Coordinate } ) --self:T( { Coordinate } )
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
if Cargo then if Cargo then
self:F( { Cargo } ) self:T( { Cargo } )
local Distance = 0 local Distance = 0
if Cargo:IsUnLoaded() then if Cargo:IsUnLoaded() then
Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() ) Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() )
@ -738,7 +738,7 @@ do -- CARGO_GROUP
-- @return #boolean **true** if the first element of the CargoGroup is in the Zone -- @return #boolean **true** if the first element of the CargoGroup is in the Zone
-- @return #boolean **false** if there is no element of the CargoGroup in the Zone. -- @return #boolean **false** if there is no element of the CargoGroup in the Zone.
function CARGO_GROUP:IsInZone( Zone ) function CARGO_GROUP:IsInZone( Zone )
--self:F( { Zone } ) --self:T( { Zone } )
local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO

View File

@ -52,7 +52,7 @@ do -- CARGO_SLINGLOAD
-- @return #CARGO_SLINGLOAD -- @return #CARGO_SLINGLOAD
function CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) function CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_SLINGLOAD local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_SLINGLOAD
self:F( { Type, Name, NearRadius } ) self:T( { Type, Name, NearRadius } )
self.CargoObject = CargoStatic self.CargoObject = CargoStatic
@ -130,7 +130,7 @@ do -- CARGO_SLINGLOAD
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the Cargo Crate is within the report radius. -- @return #boolean true if the Cargo Crate is within the report radius.
function CARGO_SLINGLOAD:IsInReportRadius( Coordinate ) function CARGO_SLINGLOAD:IsInReportRadius( Coordinate )
--self:F( { Coordinate, LoadRadius = self.LoadRadius } ) --self:T( { Coordinate, LoadRadius = self.LoadRadius } )
local Distance = 0 local Distance = 0
if self:IsUnLoaded() then if self:IsUnLoaded() then
@ -149,7 +149,7 @@ do -- CARGO_SLINGLOAD
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
-- @return #boolean true if the Cargo Slingload is within the loading radius. -- @return #boolean true if the Cargo Slingload is within the loading radius.
function CARGO_SLINGLOAD:IsInLoadRadius( Coordinate ) function CARGO_SLINGLOAD:IsInLoadRadius( Coordinate )
--self:F( { Coordinate } ) --self:T( { Coordinate } )
local Distance = 0 local Distance = 0
if self:IsUnLoaded() then if self:IsUnLoaded() then
@ -169,7 +169,7 @@ do -- CARGO_SLINGLOAD
-- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup.
-- @return #nil There is no valid Cargo in the CargoGroup. -- @return #nil There is no valid Cargo in the CargoGroup.
function CARGO_SLINGLOAD:GetCoordinate() function CARGO_SLINGLOAD:GetCoordinate()
--self:F() --self:T()
return self.CargoObject:GetCoordinate() return self.CargoObject:GetCoordinate()
end end
@ -199,7 +199,7 @@ do -- CARGO_SLINGLOAD
-- @param #CARGO_SLINGLOAD self -- @param #CARGO_SLINGLOAD self
-- @param Core.Point#COORDINATE Coordinate -- @param Core.Point#COORDINATE Coordinate
function CARGO_SLINGLOAD:RouteTo( Coordinate ) function CARGO_SLINGLOAD:RouteTo( Coordinate )
--self:F( {Coordinate = Coordinate } ) --self:T( {Coordinate = Coordinate } )
end end
@ -212,7 +212,7 @@ do -- CARGO_SLINGLOAD
-- @return #boolean The Cargo is near to the Carrier. -- @return #boolean The Cargo is near to the Carrier.
-- @return #nil The Cargo is not near to the Carrier. -- @return #nil The Cargo is not near to the Carrier.
function CARGO_SLINGLOAD:IsNear( CargoCarrier, NearRadius ) function CARGO_SLINGLOAD:IsNear( CargoCarrier, NearRadius )
--self:F( {NearRadius = NearRadius } ) --self:T( {NearRadius = NearRadius } )
return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius )
end end
@ -222,7 +222,7 @@ do -- CARGO_SLINGLOAD
-- @param #CARGO_SLINGLOAD self -- @param #CARGO_SLINGLOAD self
function CARGO_SLINGLOAD:Respawn() function CARGO_SLINGLOAD:Respawn()
--self:F( { "Respawning slingload " .. self:GetName() } ) --self:T( { "Respawning slingload " .. self:GetName() } )
-- Respawn the group... -- Respawn the group...
@ -239,7 +239,7 @@ do -- CARGO_SLINGLOAD
-- @param #CARGO_SLINGLOAD self -- @param #CARGO_SLINGLOAD self
function CARGO_SLINGLOAD:onafterReset() function CARGO_SLINGLOAD:onafterReset()
--self:F( { "Reset slingload " .. self:GetName() } ) --self:T( { "Reset slingload " .. self:GetName() } )
-- Respawn the group... -- Respawn the group...

View File

@ -75,7 +75,7 @@ do -- CARGO_UNIT
-- @param Core.Point#POINT_VEC2 ToPointVec2 -- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius (optional) Defaut 25 m. -- @param #number NearRadius (optional) Defaut 25 m.
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } ) self:T( { From, Event, To, ToPointVec2, NearRadius } )
local Angle = 180 local Angle = 180
local Speed = 60 local Speed = 60
@ -114,7 +114,7 @@ do -- CARGO_UNIT
else else
self.CargoObject:ReSpawnAt( FromPointVec2, CargoDeployHeading ) self.CargoObject:ReSpawnAt( FromPointVec2, CargoDeployHeading )
end end
self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) self:T( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } )
self.CargoCarrier = nil self.CargoCarrier = nil
local Points = {} local Points = {}
@ -148,7 +148,7 @@ do -- CARGO_UNIT
-- @param Core.Point#POINT_VEC2 ToPointVec2 -- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius (optional) Defaut 100 m. -- @param #number NearRadius (optional) Defaut 100 m.
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius ) function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } ) self:T( { From, Event, To, ToPointVec2, NearRadius } )
local Angle = 180 local Angle = 180
local Speed = 10 local Speed = 10
@ -174,7 +174,7 @@ do -- CARGO_UNIT
-- @param Core.Point#POINT_VEC2 ToPointVec2 -- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius (optional) Defaut 100 m. -- @param #number NearRadius (optional) Defaut 100 m.
function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } ) self:T( { From, Event, To, ToPointVec2, NearRadius } )
self.CargoInAir = self.CargoObject:InAir() self.CargoInAir = self.CargoObject:InAir()
@ -199,7 +199,7 @@ do -- CARGO_UNIT
-- @param #string To -- @param #string To
-- @param Core.Point#POINT_VEC2 -- @param Core.Point#POINT_VEC2
function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 ) function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 )
self:F( { ToPointVec2, From, Event, To } ) self:T( { ToPointVec2, From, Event, To } )
local Angle = 180 local Angle = 180
local Speed = 10 local Speed = 10
@ -236,7 +236,7 @@ do -- CARGO_UNIT
-- @param Wrapper.Group#GROUP CargoCarrier -- @param Wrapper.Group#GROUP CargoCarrier
-- @param #number NearRadius -- @param #number NearRadius
function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... ) function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier, NearRadius = NearRadius } ) self:T( { From, Event, To, CargoCarrier, NearRadius = NearRadius } )
self.CargoInAir = self.CargoObject:InAir() self.CargoInAir = self.CargoObject:InAir()
@ -244,7 +244,7 @@ do -- CARGO_UNIT
local MaxSpeed = Desc.speedMaxOffRoad local MaxSpeed = Desc.speedMaxOffRoad
local TypeName = Desc.typeName local TypeName = Desc.typeName
--self:F({Unit=self.CargoObject:GetName()}) --self:T({Unit=self.CargoObject:GetName()})
-- A cargo unit can only be boarded if it is not dead -- A cargo unit can only be boarded if it is not dead
@ -298,9 +298,9 @@ do -- CARGO_UNIT
-- @param Wrapper.Client#CLIENT CargoCarrier -- @param Wrapper.Client#CLIENT CargoCarrier
-- @param #number NearRadius Default 25 m. -- @param #number NearRadius Default 25 m.
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } ) self:T( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } )
self:F( { IsAlive=self.CargoObject:IsAlive() } ) self:T( { IsAlive=self.CargoObject:IsAlive() } )
if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then
if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then
@ -321,7 +321,7 @@ do -- CARGO_UNIT
local Angle = 180 local Angle = 180
local Distance = 0 local Distance = 0
--self:F({Unit=self.CargoObject:GetName()}) --self:T({Unit=self.CargoObject:GetName()})
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
@ -348,7 +348,7 @@ do -- CARGO_UNIT
self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) ) self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) )
end end
else else
self:E("Something is wrong") self:T("Something is wrong")
end end
end end
@ -361,11 +361,11 @@ do -- CARGO_UNIT
-- @param #string To -- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier -- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier ) function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier )
self:F( { From, Event, To, CargoCarrier } ) self:T( { From, Event, To, CargoCarrier } )
self.CargoCarrier = CargoCarrier self.CargoCarrier = CargoCarrier
--self:F({Unit=self.CargoObject:GetName()}) --self:T({Unit=self.CargoObject:GetName()})
-- Only destroy the CargoObject if there is a CargoObject (packages don't have CargoObjects). -- Only destroy the CargoObject if there is a CargoObject (packages don't have CargoObjects).
if self.CargoObject then if self.CargoObject then

View File

@ -489,8 +489,30 @@ do -- Zones and Pathlines
-- Create new polygon zone. -- Create new polygon zone.
local Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName, points) local Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName, points)
--Zone.DrawID = objectID
-- Set color. -- Set color.
Zone:SetColor({1, 0, 0}, 0.15) Zone:SetColor({1, 0, 0}, 0.15)
Zone:SetFillColor({1, 0, 0}, 0.15)
if objectData.colorString then
-- eg colorString = 0xff0000ff
local color = string.gsub(objectData.colorString,"^0x","")
local r = tonumber(string.sub(color,1,2),16)/255
local g = tonumber(string.sub(color,3,4),16)/255
local b = tonumber(string.sub(color,5,6),16)/255
local a = tonumber(string.sub(color,7,8),16)/255
Zone:SetColor({r, g, b}, a)
end
if objectData.fillColorString then
-- eg fillColorString = 0xff00004b
local color = string.gsub(objectData.colorString,"^0x","")
local r = tonumber(string.sub(color,1,2),16)/255
local g = tonumber(string.sub(color,3,4),16)/255
local b = tonumber(string.sub(color,5,6),16)/255
local a = tonumber(string.sub(color,7,8),16)/255
Zone:SetFillColor({r, g, b}, a)
end
-- Store in DB. -- Store in DB.
self.ZONENAMES[ZoneName] = ZoneName self.ZONENAMES[ZoneName] = ZoneName
@ -533,6 +555,25 @@ do -- Zones and Pathlines
-- Set color. -- Set color.
Zone:SetColor({1, 0, 0}, 0.15) Zone:SetColor({1, 0, 0}, 0.15)
if objectData.colorString then
-- eg colorString = 0xff0000ff
local color = string.gsub(objectData.colorString,"^0x","")
local r = tonumber(string.sub(color,1,2),16)/255
local g = tonumber(string.sub(color,3,4),16)/255
local b = tonumber(string.sub(color,5,6),16)/255
local a = tonumber(string.sub(color,7,8),16)/255
Zone:SetColor({r, g, b}, a)
end
if objectData.fillColorString then
-- eg fillColorString = 0xff00004b
local color = string.gsub(objectData.colorString,"^0x","")
local r = tonumber(string.sub(color,1,2),16)/255
local g = tonumber(string.sub(color,3,4),16)/255
local b = tonumber(string.sub(color,5,6),16)/255
local a = tonumber(string.sub(color,7,8),16)/255
Zone:SetFillColor({r, g, b}, a)
end
-- Store in DB. -- Store in DB.
self.ZONENAMES[ZoneName] = ZoneName self.ZONENAMES[ZoneName] = ZoneName
@ -756,7 +797,7 @@ end -- cargo
--- Finds a CLIENT based on the ClientName. --- Finds a CLIENT based on the ClientName.
-- @param #DATABASE self -- @param #DATABASE self
-- @param #string ClientName -- @param #string ClientName - Note this is the UNIT name of the client!
-- @return Wrapper.Client#CLIENT The found CLIENT. -- @return Wrapper.Client#CLIENT The found CLIENT.
function DATABASE:FindClient( ClientName ) function DATABASE:FindClient( ClientName )

View File

@ -498,7 +498,6 @@ function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,G
_MESSAGESRS.Gender = Gender or "female" _MESSAGESRS.Gender = Gender or "female"
_MESSAGESRS.MSRS:SetGoogle(PathToCredentials) _MESSAGESRS.MSRS:SetGoogle(PathToCredentials)
_MESSAGESRS.google = PathToCredentials
_MESSAGESRS.MSRS:SetLabel(Label or "MESSAGE") _MESSAGESRS.MSRS:SetLabel(Label or "MESSAGE")
_MESSAGESRS.label = Label or "MESSAGE" _MESSAGESRS.label = Label or "MESSAGE"
@ -512,8 +511,6 @@ function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,G
if Voice then _MESSAGESRS.MSRS:SetVoice(Voice) end if Voice then _MESSAGESRS.MSRS:SetVoice(Voice) end
_MESSAGESRS.voice = Voice --or MSRS.Voices.Microsoft.Hedda _MESSAGESRS.voice = Voice --or MSRS.Voices.Microsoft.Hedda
--if _MESSAGESRS.google and not Voice then _MESSAGESRS.Voice = MSRS.Voices.Google.Standard.en_GB_Standard_A end
--_MESSAGESRS.MSRS:SetVoice(Voice or _MESSAGESRS.voice)
_MESSAGESRS.SRSQ = MSRSQUEUE:New(Label or "MESSAGE") _MESSAGESRS.SRSQ = MSRSQUEUE:New(Label or "MESSAGE")
end end

View File

@ -2456,15 +2456,18 @@ do -- COORDINATE
-- Write command as string and execute that. Idea by Grimes https://forum.dcs.world/topic/324201-mark-to-all-function/#comment-5273793 -- Write command as string and execute that. Idea by Grimes https://forum.dcs.world/topic/324201-mark-to-all-function/#comment-5273793
local s=string.format("trigger.action.markupToAll(7, %d, %d,", Coalition, MarkID) local s=string.format("trigger.action.markupToAll(7, %d, %d,", Coalition, MarkID)
for _,vec in pairs(vecs) do for _,vec in pairs(vecs) do
s=s..string.format("%s,", UTILS._OneLineSerialize(vec)) --s=s..string.format("%s,", UTILS._OneLineSerialize(vec))
s=s..string.format("{x=%.1f, y=%.1f, z=%.1f},", vec.x, vec.y, vec.z)
end end
s=s..string.format("%s, %s, %s, %s", UTILS._OneLineSerialize(Color), UTILS._OneLineSerialize(FillColor), tostring(LineType), tostring(ReadOnly)) s=s..string.format("{%.3f, %.3f, %.3f, %.3f},", Color[1], Color[2], Color[3], Color[4])
if Text and Text~="" then s=s..string.format("{%.3f, %.3f, %.3f, %.3f},", FillColor[1], FillColor[2], FillColor[3], FillColor[4])
s=s..string.format(", \"%s\"", Text) s=s..string.format("%d,", LineType or 1)
s=s..string.format("%s", tostring(ReadOnly))
if Text and type(Text)=="string" and string.len(Text)>0 then
s=s..string.format(", \"%s\"", tostring(Text))
end end
s=s..")" s=s..")"
-- Execute string command -- Execute string command
local success=UTILS.DoString(s) local success=UTILS.DoString(s)

View File

@ -147,6 +147,44 @@ do -- SET_BASE
return self return self
end end
--- [Internal] Add a functional filter
-- @param #SET_BASE self
-- @param #function ConditionFunction If this function returns `true`, the object is added to the SET. The function needs to take a CONTROLLABLE object as first argument.
-- @param ... Condition function arguments, if any.
-- @return #boolean If true, at least one condition is true
function SET_BASE:FilterFunction(ConditionFunction, ...)
local condition={}
condition.func=ConditionFunction
condition.arg={}
if arg then
condition.arg=arg
end
if not self.Filter.Functions then self.Filter.Functions = {} end
table.insert(self.Filter.Functions, condition)
return self
end
--- [Internal] Check if the condition functions returns true.
-- @param #SET_BASE self
-- @param Wrapper.Controllable#CONTROLLABLE Object The object to filter for
-- @return #boolean If true, if **all** conditions are true
function SET_BASE:_EvalFilterFunctions(Object)
-- All conditions must be true.
for _,_condition in pairs(self.Filter.Functions or {}) do
local condition=_condition
-- Call function.
if condition.func(Object,unpack(condition.arg)) == false then
return false
end
end
-- No condition was true.
return true
end
--- Clear the Objects in the Set. --- Clear the Objects in the Set.
-- @param #SET_BASE self -- @param #SET_BASE self
-- @param #boolean TriggerEvent If `true`, an event remove is triggered for each group that is removed from the set. -- @param #boolean TriggerEvent If `true`, an event remove is triggered for each group that is removed from the set.
@ -967,6 +1005,7 @@ do
-- * @{#SET_GROUP.FilterCategoryShip}: Builds the SET_GROUP from ships. -- * @{#SET_GROUP.FilterCategoryShip}: Builds the SET_GROUP from ships.
-- * @{#SET_GROUP.FilterCategoryStructure}: Builds the SET_GROUP from structures. -- * @{#SET_GROUP.FilterCategoryStructure}: Builds the SET_GROUP from structures.
-- * @{#SET_GROUP.FilterZones}: Builds the SET_GROUP with the groups within a @{Core.Zone#ZONE}. -- * @{#SET_GROUP.FilterZones}: Builds the SET_GROUP with the groups within a @{Core.Zone#ZONE}.
-- * @{#SET_GROUP.FilterFunction}: Builds the SET_GROUP with a custom condition.
-- --
-- Once the filter criteria have been set for the SET_GROUP, you can start filtering using: -- Once the filter criteria have been set for the SET_GROUP, you can start filtering using:
-- --
@ -1040,6 +1079,7 @@ do
Countries = nil, Countries = nil,
GroupPrefixes = nil, GroupPrefixes = nil,
Zones = nil, Zones = nil,
Functions = nil,
}, },
FilterMeta = { FilterMeta = {
Coalitions = { Coalitions = {
@ -1254,6 +1294,25 @@ do
return self return self
end end
--- [User] Add a custom condition function.
-- @function [parent=#SET_GROUP] FilterFunction
-- @param #SET_GROUP self
-- @param #function ConditionFunction If this function returns `true`, the object is added to the SET. The function needs to take a GROUP object as first argument.
-- @param ... Condition function arguments if any.
-- @return #SET_GROUP self
-- @usage
-- -- Image you want to exclude a specific GROUP from a SET:
-- local groundset = SET_GROUP:New():FilterCoalitions("blue"):FilterCategoryGround():FilterFunction(
-- -- The function needs to take a GROUP object as first - and in this case, only - argument.
-- function(grp)
-- local isinclude = true
-- if grp:GetName() == "Exclude Me" then isinclude = false end
-- return isinclude
-- end
-- ):FilterOnce()
-- BASE:I(groundset:Flush())
--- Builds a set of groups of coalitions. --- Builds a set of groups of coalitions.
-- Possible current coalitions are red, blue and neutral. -- Possible current coalitions are red, blue and neutral.
-- @param #SET_GROUP self -- @param #SET_GROUP self
@ -1927,7 +1986,7 @@ do
MGroupInclude = MGroupInclude and MGroupActive MGroupInclude = MGroupInclude and MGroupActive
end end
if self.Filter.Coalitions then if self.Filter.Coalitions and MGroupInclude then
local MGroupCoalition = false local MGroupCoalition = false
for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do
self:T3( { "Coalition:", MGroup:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) self:T3( { "Coalition:", MGroup:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } )
@ -1938,7 +1997,7 @@ do
MGroupInclude = MGroupInclude and MGroupCoalition MGroupInclude = MGroupInclude and MGroupCoalition
end end
if self.Filter.Categories then if self.Filter.Categories and MGroupInclude then
local MGroupCategory = false local MGroupCategory = false
for CategoryID, CategoryName in pairs( self.Filter.Categories ) do for CategoryID, CategoryName in pairs( self.Filter.Categories ) do
self:T3( { "Category:", MGroup:GetCategory(), self.FilterMeta.Categories[CategoryName], CategoryName } ) self:T3( { "Category:", MGroup:GetCategory(), self.FilterMeta.Categories[CategoryName], CategoryName } )
@ -1949,7 +2008,7 @@ do
MGroupInclude = MGroupInclude and MGroupCategory MGroupInclude = MGroupInclude and MGroupCategory
end end
if self.Filter.Countries then if self.Filter.Countries and MGroupInclude then
local MGroupCountry = false local MGroupCountry = false
for CountryID, CountryName in pairs( self.Filter.Countries ) do for CountryID, CountryName in pairs( self.Filter.Countries ) do
self:T3( { "Country:", MGroup:GetCountry(), CountryName } ) self:T3( { "Country:", MGroup:GetCountry(), CountryName } )
@ -1960,7 +2019,7 @@ do
MGroupInclude = MGroupInclude and MGroupCountry MGroupInclude = MGroupInclude and MGroupCountry
end end
if self.Filter.GroupPrefixes then if self.Filter.GroupPrefixes and MGroupInclude then
local MGroupPrefix = false local MGroupPrefix = false
for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do
self:T3( { "Prefix:", string.find( MGroup:GetName(), GroupPrefix, 1 ), GroupPrefix } ) self:T3( { "Prefix:", string.find( MGroup:GetName(), GroupPrefix, 1 ), GroupPrefix } )
@ -1971,7 +2030,7 @@ do
MGroupInclude = MGroupInclude and MGroupPrefix MGroupInclude = MGroupInclude and MGroupPrefix
end end
if self.Filter.Zones then if self.Filter.Zones and MGroupInclude then
local MGroupZone = false local MGroupZone = false
for ZoneName, Zone in pairs( self.Filter.Zones ) do for ZoneName, Zone in pairs( self.Filter.Zones ) do
--self:T( "Zone:", ZoneName ) --self:T( "Zone:", ZoneName )
@ -1982,6 +2041,12 @@ do
MGroupInclude = MGroupInclude and MGroupZone MGroupInclude = MGroupInclude and MGroupZone
end end
if self.Filter.Functions and MGroupInclude then
local MGroupFunc = false
MGroupFunc = self:_EvalFilterFunctions(MGroup)
MGroupInclude = MGroupInclude and MGroupFunc
end
self:T2( MGroupInclude ) self:T2( MGroupInclude )
return MGroupInclude return MGroupInclude
end end
@ -2080,6 +2145,7 @@ do -- SET_UNIT
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching) -- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- * @{#SET_UNIT.FilterActive}: Builds the SET_UNIT with the units that are only active. Units that are inactive (late activation) won't be included in the set! -- * @{#SET_UNIT.FilterActive}: Builds the SET_UNIT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
-- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Core.Zone#ZONE}. -- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Core.Zone#ZONE}.
-- * @{#SET_UNIT.FilterFunction}: Builds the SET_UNIT with a custom condition.
-- --
-- Once the filter criteria have been set for the SET_UNIT, you can start filtering using: -- Once the filter criteria have been set for the SET_UNIT, you can start filtering using:
-- --
@ -2158,6 +2224,7 @@ do -- SET_UNIT
Countries = nil, Countries = nil,
UnitPrefixes = nil, UnitPrefixes = nil,
Zones = nil, Zones = nil,
Functions = nil,
}, },
FilterMeta = { FilterMeta = {
Coalitions = { Coalitions = {
@ -2529,6 +2596,25 @@ do -- SET_UNIT
return self return self
end end
--- [User] Add a custom condition function.
-- @function [parent=#SET_UNIT] FilterFunction
-- @param #SET_UNIT self
-- @param #function ConditionFunction If this function returns `true`, the object is added to the SET. The function needs to take a UNIT object as first argument.
-- @param ... Condition function arguments if any.
-- @return #SET_UNIT self
-- @usage
-- -- Image you want to exclude a specific UNIT from a SET:
-- local groundset = SET_UNIT:New():FilterCoalitions("blue"):FilterCategories("ground"):FilterFunction(
-- -- The function needs to take a UNIT object as first - and in this case, only - argument.
-- function(unit)
-- local isinclude = true
-- if unit:GetName() == "Exclude Me" then isinclude = false end
-- return isinclude
-- end
-- ):FilterOnce()
-- BASE:I(groundset:Flush())
--- Handles the Database to check on an event (birth) that the Object was added in the Database. --- Handles the Database to check on an event (birth) that the Object was added in the Database.
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! -- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
-- @param #SET_UNIT self -- @param #SET_UNIT self
@ -3106,7 +3192,7 @@ do -- SET_UNIT
MUnitInclude = MUnitInclude and MUnitActive MUnitInclude = MUnitInclude and MUnitActive
end end
if self.Filter.Coalitions then if self.Filter.Coalitions and MUnitInclude then
local MUnitCoalition = false local MUnitCoalition = false
for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do
self:F( { "Coalition:", MUnit:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) self:F( { "Coalition:", MUnit:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } )
@ -3117,7 +3203,7 @@ do -- SET_UNIT
MUnitInclude = MUnitInclude and MUnitCoalition MUnitInclude = MUnitInclude and MUnitCoalition
end end
if self.Filter.Categories then if self.Filter.Categories and MUnitInclude then
local MUnitCategory = false local MUnitCategory = false
for CategoryID, CategoryName in pairs( self.Filter.Categories ) do for CategoryID, CategoryName in pairs( self.Filter.Categories ) do
self:T3( { "Category:", MUnit:GetDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } ) self:T3( { "Category:", MUnit:GetDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } )
@ -3128,7 +3214,7 @@ do -- SET_UNIT
MUnitInclude = MUnitInclude and MUnitCategory MUnitInclude = MUnitInclude and MUnitCategory
end end
if self.Filter.Types then if self.Filter.Types and MUnitInclude then
local MUnitType = false local MUnitType = false
for TypeID, TypeName in pairs( self.Filter.Types ) do for TypeID, TypeName in pairs( self.Filter.Types ) do
self:T3( { "Type:", MUnit:GetTypeName(), TypeName } ) self:T3( { "Type:", MUnit:GetTypeName(), TypeName } )
@ -3139,7 +3225,7 @@ do -- SET_UNIT
MUnitInclude = MUnitInclude and MUnitType MUnitInclude = MUnitInclude and MUnitType
end end
if self.Filter.Countries then if self.Filter.Countries and MUnitInclude then
local MUnitCountry = false local MUnitCountry = false
for CountryID, CountryName in pairs( self.Filter.Countries ) do for CountryID, CountryName in pairs( self.Filter.Countries ) do
self:T3( { "Country:", MUnit:GetCountry(), CountryName } ) self:T3( { "Country:", MUnit:GetCountry(), CountryName } )
@ -3150,7 +3236,7 @@ do -- SET_UNIT
MUnitInclude = MUnitInclude and MUnitCountry MUnitInclude = MUnitInclude and MUnitCountry
end end
if self.Filter.UnitPrefixes then if self.Filter.UnitPrefixes and MUnitInclude then
local MUnitPrefix = false local MUnitPrefix = false
for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do
self:T3( { "Prefix:", string.find( MUnit:GetName(), UnitPrefix, 1 ), UnitPrefix } ) self:T3( { "Prefix:", string.find( MUnit:GetName(), UnitPrefix, 1 ), UnitPrefix } )
@ -3161,7 +3247,7 @@ do -- SET_UNIT
MUnitInclude = MUnitInclude and MUnitPrefix MUnitInclude = MUnitInclude and MUnitPrefix
end end
if self.Filter.RadarTypes then if self.Filter.RadarTypes and MUnitInclude then
local MUnitRadar = false local MUnitRadar = false
for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do
self:T3( { "Radar:", RadarType } ) self:T3( { "Radar:", RadarType } )
@ -3175,7 +3261,7 @@ do -- SET_UNIT
MUnitInclude = MUnitInclude and MUnitRadar MUnitInclude = MUnitInclude and MUnitRadar
end end
if self.Filter.SEAD then if self.Filter.SEAD and MUnitInclude then
local MUnitSEAD = false local MUnitSEAD = false
if MUnit:HasSEAD() == true then if MUnit:HasSEAD() == true then
self:T3( "SEAD Found" ) self:T3( "SEAD Found" )
@ -3185,7 +3271,7 @@ do -- SET_UNIT
end end
end end
if self.Filter.Zones then if self.Filter.Zones and MUnitInclude then
local MGroupZone = false local MGroupZone = false
for ZoneName, Zone in pairs( self.Filter.Zones ) do for ZoneName, Zone in pairs( self.Filter.Zones ) do
self:T3( "Zone:", ZoneName ) self:T3( "Zone:", ZoneName )
@ -3196,6 +3282,11 @@ do -- SET_UNIT
MUnitInclude = MUnitInclude and MGroupZone MUnitInclude = MUnitInclude and MGroupZone
end end
if self.Filter.Functions and MUnitInclude then
local MUnitFunc = self:_EvalFilterFunctions(MUnit)
MUnitInclude = MUnitInclude and MUnitFunc
end
self:T2( MUnitInclude ) self:T2( MUnitInclude )
return MUnitInclude return MUnitInclude
end end
@ -3277,6 +3368,7 @@ do -- SET_STATIC
-- * @{#SET_STATIC.FilterPrefixes}: Builds the SET_STATIC with the units containing the same string(s) in their name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results. -- * @{#SET_STATIC.FilterPrefixes}: Builds the SET_STATIC with the units containing the same string(s) in their name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching) -- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- * @{#SET_STATIC.FilterZones}: Builds the SET_STATIC with the units within a @{Core.Zone#ZONE}. -- * @{#SET_STATIC.FilterZones}: Builds the SET_STATIC with the units within a @{Core.Zone#ZONE}.
-- * @{#SET_STATIC.FilterFunction}: Builds the SET_STATIC with a custom condition.
-- --
-- Once the filter criteria have been set for the SET_STATIC, you can start filtering using: -- Once the filter criteria have been set for the SET_STATIC, you can start filtering using:
-- --
@ -3480,6 +3572,24 @@ do -- SET_STATIC
return self return self
end end
--- [User] Add a custom condition function.
-- @function [parent=#SET_STATIC] FilterFunction
-- @param #SET_STATIC self
-- @param #function ConditionFunction If this function returns `true`, the object is added to the SET. The function needs to take a STATIC object as first argument.
-- @param ... Condition function arguments if any.
-- @return #SET_STATIC self
-- @usage
-- -- Image you want to exclude a specific CLIENT from a SET:
-- local groundset = SET_STATIC:New():FilterCoalitions("blue"):FilterActive(true):FilterFunction(
-- -- The function needs to take a STATIC object as first - and in this case, only - argument.
-- function(static)
-- local isinclude = true
-- if static:GetName() == "Exclude Me" then isinclude = false end
-- return isinclude
-- end
-- ):FilterOnce()
-- BASE:I(groundset:Flush())
--- Builds a set of units of defined countries. --- Builds a set of units of defined countries.
-- Possible current countries are those known within DCS world. -- Possible current countries are those known within DCS world.
-- @param #SET_STATIC self -- @param #SET_STATIC self
@ -4036,6 +4146,7 @@ do -- SET_CLIENT
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching) -- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- * @{#SET_CLIENT.FilterActive}: Builds the SET_CLIENT with the units that are only active. Units that are inactive (late activation) won't be included in the set! -- * @{#SET_CLIENT.FilterActive}: Builds the SET_CLIENT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
-- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Core.Zone#ZONE}. -- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Core.Zone#ZONE}.
-- * @{#SET_CLIENT.FilterFunction}: Builds the SET_CLIENT with a custom condition.
-- --
-- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using: -- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using:
-- --
@ -4538,6 +4649,25 @@ do -- SET_CLIENT
return AliveSet.Set or {} return AliveSet.Set or {}
end end
--- [User] Add a custom condition function.
-- @function [parent=#SET_CLIENT] FilterFunction
-- @param #SET_CLIENT self
-- @param #function ConditionFunction If this function returns `true`, the object is added to the SET. The function needs to take a CLIENT object as first argument.
-- @param ... Condition function arguments if any.
-- @return #SET_CLIENT self
-- @usage
-- -- Image you want to exclude a specific CLIENT from a SET:
-- local groundset = SET_CLIENT:New():FilterCoalitions("blue"):FilterActive(true):FilterFunction(
-- -- The function needs to take a UNIT object as first - and in this case, only - argument.
-- function(client)
-- local isinclude = true
-- if client:GetPlayerName() == "Exclude Me" then isinclude = false end
-- return isinclude
-- end
-- ):FilterOnce()
-- BASE:I(groundset:Flush())
--- ---
-- @param #SET_CLIENT self -- @param #SET_CLIENT self
-- @param Wrapper.Client#CLIENT MClient -- @param Wrapper.Client#CLIENT MClient
@ -4559,7 +4689,7 @@ do -- SET_CLIENT
MClientInclude = MClientInclude and MClientActive MClientInclude = MClientInclude and MClientActive
end end
if self.Filter.Coalitions then if self.Filter.Coalitions and MClientInclude then
local MClientCoalition = false local MClientCoalition = false
for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do
local ClientCoalitionID = _DATABASE:GetCoalitionFromClientTemplate( MClientName ) local ClientCoalitionID = _DATABASE:GetCoalitionFromClientTemplate( MClientName )
@ -4572,7 +4702,7 @@ do -- SET_CLIENT
MClientInclude = MClientInclude and MClientCoalition MClientInclude = MClientInclude and MClientCoalition
end end
if self.Filter.Categories then if self.Filter.Categories and MClientInclude then
local MClientCategory = false local MClientCategory = false
for CategoryID, CategoryName in pairs( self.Filter.Categories ) do for CategoryID, CategoryName in pairs( self.Filter.Categories ) do
local ClientCategoryID = _DATABASE:GetCategoryFromClientTemplate( MClientName ) local ClientCategoryID = _DATABASE:GetCategoryFromClientTemplate( MClientName )
@ -4585,7 +4715,7 @@ do -- SET_CLIENT
MClientInclude = MClientInclude and MClientCategory MClientInclude = MClientInclude and MClientCategory
end end
if self.Filter.Types then if self.Filter.Types and MClientInclude then
local MClientType = false local MClientType = false
for TypeID, TypeName in pairs( self.Filter.Types ) do for TypeID, TypeName in pairs( self.Filter.Types ) do
self:T3( { "Type:", MClient:GetTypeName(), TypeName } ) self:T3( { "Type:", MClient:GetTypeName(), TypeName } )
@ -4597,7 +4727,7 @@ do -- SET_CLIENT
MClientInclude = MClientInclude and MClientType MClientInclude = MClientInclude and MClientType
end end
if self.Filter.Countries then if self.Filter.Countries and MClientInclude then
local MClientCountry = false local MClientCountry = false
for CountryID, CountryName in pairs( self.Filter.Countries ) do for CountryID, CountryName in pairs( self.Filter.Countries ) do
local ClientCountryID = _DATABASE:GetCountryFromClientTemplate( MClientName ) local ClientCountryID = _DATABASE:GetCountryFromClientTemplate( MClientName )
@ -4610,7 +4740,7 @@ do -- SET_CLIENT
MClientInclude = MClientInclude and MClientCountry MClientInclude = MClientInclude and MClientCountry
end end
if self.Filter.ClientPrefixes then if self.Filter.ClientPrefixes and MClientInclude then
local MClientPrefix = false local MClientPrefix = false
for ClientPrefixId, ClientPrefix in pairs( self.Filter.ClientPrefixes ) do for ClientPrefixId, ClientPrefix in pairs( self.Filter.ClientPrefixes ) do
self:T3( { "Prefix:", string.find( MClient.UnitName, ClientPrefix, 1 ), ClientPrefix } ) self:T3( { "Prefix:", string.find( MClient.UnitName, ClientPrefix, 1 ), ClientPrefix } )
@ -4622,7 +4752,7 @@ do -- SET_CLIENT
MClientInclude = MClientInclude and MClientPrefix MClientInclude = MClientInclude and MClientPrefix
end end
if self.Filter.Zones then if self.Filter.Zones and MClientInclude then
local MClientZone = false local MClientZone = false
for ZoneName, Zone in pairs( self.Filter.Zones ) do for ZoneName, Zone in pairs( self.Filter.Zones ) do
self:T3( "Zone:", ZoneName ) self:T3( "Zone:", ZoneName )
@ -4634,7 +4764,7 @@ do -- SET_CLIENT
MClientInclude = MClientInclude and MClientZone MClientInclude = MClientInclude and MClientZone
end end
if self.Filter.Playernames then if self.Filter.Playernames and MClientInclude then
local MClientPlayername = false local MClientPlayername = false
local playername = MClient:GetPlayerName() or "Unknown" local playername = MClient:GetPlayerName() or "Unknown"
--self:T(playername) --self:T(playername)
@ -4647,7 +4777,7 @@ do -- SET_CLIENT
MClientInclude = MClientInclude and MClientPlayername MClientInclude = MClientInclude and MClientPlayername
end end
if self.Filter.Callsigns then if self.Filter.Callsigns and MClientInclude then
local MClientCallsigns = false local MClientCallsigns = false
local callsign = MClient:GetCallsign() local callsign = MClient:GetCallsign()
--self:I(callsign) --self:I(callsign)
@ -4660,6 +4790,11 @@ do -- SET_CLIENT
MClientInclude = MClientInclude and MClientCallsigns MClientInclude = MClientInclude and MClientCallsigns
end end
if self.Filter.Functions and MClientInclude then
local MClientFunc = self:_EvalFilterFunctions(MClient)
MClientInclude = MClientInclude and MClientFunc
end
end end
self:T2( MClientInclude ) self:T2( MClientInclude )
return MClientInclude return MClientInclude
@ -5253,7 +5388,7 @@ do -- SET_AIRBASE
function SET_AIRBASE:GetRandomAirbase() function SET_AIRBASE:GetRandomAirbase()
local RandomAirbase = self:GetRandom() local RandomAirbase = self:GetRandom()
self:F( { RandomAirbase = RandomAirbase:GetName() } ) --self:F( { RandomAirbase = RandomAirbase:GetName() } )
return RandomAirbase return RandomAirbase
end end
@ -5419,7 +5554,7 @@ do -- SET_AIRBASE
MAirbaseInclude = MAirbaseInclude and MAirbaseCoalition MAirbaseInclude = MAirbaseInclude and MAirbaseCoalition
end end
if self.Filter.Categories then if self.Filter.Categories and MAirbaseInclude then
local MAirbaseCategory = false local MAirbaseCategory = false
for CategoryID, CategoryName in pairs( self.Filter.Categories ) do for CategoryID, CategoryName in pairs( self.Filter.Categories ) do
local AirbaseCategoryID = _DATABASE:GetCategoryFromAirbase( MAirbaseName ) local AirbaseCategoryID = _DATABASE:GetCategoryFromAirbase( MAirbaseName )
@ -7765,7 +7900,7 @@ do -- SET_OPSGROUP
end end
-- Filter coalitions. -- Filter coalitions.
if self.Filter.Coalitions then if self.Filter.Coalitions and MGroupInclude then
local MGroupCoalition = false local MGroupCoalition = false
@ -7779,7 +7914,7 @@ do -- SET_OPSGROUP
end end
-- Filter categories. -- Filter categories.
if self.Filter.Categories then if self.Filter.Categories and MGroupInclude then
local MGroupCategory = false local MGroupCategory = false
@ -7793,7 +7928,7 @@ do -- SET_OPSGROUP
end end
-- Filter countries. -- Filter countries.
if self.Filter.Countries then if self.Filter.Countries and MGroupInclude then
local MGroupCountry = false local MGroupCountry = false
for CountryID, CountryName in pairs( self.Filter.Countries ) do for CountryID, CountryName in pairs( self.Filter.Countries ) do
if country.id[CountryName] == MGroup:GetCountry() then if country.id[CountryName] == MGroup:GetCountry() then
@ -7804,12 +7939,12 @@ do -- SET_OPSGROUP
end end
-- Filter "prefixes". -- Filter "prefixes".
if self.Filter.GroupPrefixes then if self.Filter.GroupPrefixes and MGroupInclude then
local MGroupPrefix = false local MGroupPrefix = false
for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do
if string.find( MGroup:GetName(), GroupPrefix:gsub ("-", "%%-"), 1 ) then --Not sure why "-" is replaced by "%-" ?! if string.find( MGroup:GetName(), GroupPrefix:gsub ("-", "%%-"), 1 ) then --Not sure why "-" is replaced by "%-" ?! - So we can still match group names with a dash in them
MGroupPrefix = true MGroupPrefix = true
end end
end end

View File

@ -2020,7 +2020,7 @@ _ZONE_TRIANGLE = {
Coords={}, Coords={},
CenterVec2={x=0, y=0}, CenterVec2={x=0, y=0},
SurfaceArea=0, SurfaceArea=0,
DrawIDs={} DrawID={}
} }
--- ---
-- @param #_ZONE_TRIANGLE self -- @param #_ZONE_TRIANGLE self
@ -2100,15 +2100,35 @@ function _ZONE_TRIANGLE:Draw(Coalition, Color, Alpha, FillColor, FillAlpha, Line
for i=1, #self.Coords do for i=1, #self.Coords do
local c1 = self.Coords[i] local c1 = self.Coords[i]
local c2 = self.Coords[i % #self.Coords + 1] local c2 = self.Coords[i % #self.Coords + 1]
table.add(self.DrawIDs, c1:LineToAll(c2, Coalition, Color, Alpha, LineType, ReadOnly)) local id = c1:LineToAll(c2, Coalition, Color, Alpha, LineType, ReadOnly)
self.DrawID[#self.DrawID+1] = id
end end
return self.DrawIDs local newID = self.Coords[1]:MarkupToAllFreeForm({self.Coords[2],self.Coords[3]},Coalition,Color,Alpha,FillColor,FillAlpha,LineType,ReadOnly)
self.DrawID[#self.DrawID+1] = newID
return self.DrawID
end
--- Draw the triangle
-- @param #_ZONE_TRIANGLE self
-- @return #table of draw IDs
function _ZONE_TRIANGLE:Fill(Coalition, FillColor, FillAlpha, ReadOnly)
Coalition=Coalition or -1
FillColor = FillColor
FillAlpha = FillAlpha
local newID = self.Coords[1]:MarkupToAllFreeForm({self.Coords[2],self.Coords[3]},Coalition,nil,nil,FillColor,FillAlpha,0,nil)
self.DrawID[#self.DrawID+1] = newID
return self.DrawID
end end
--- ---
-- @type ZONE_POLYGON_BASE -- @type ZONE_POLYGON_BASE
-- @field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCS#Vec2}. -- @field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCS#Vec2}.
-- @field #number SurfaceArea
-- @field #table DrawID
-- @field #table FillTriangles
-- @field #table _Triangles
-- @field #table Borderlines
-- @extends #ZONE_BASE -- @extends #ZONE_BASE
@ -2133,9 +2153,11 @@ end
-- @field #ZONE_POLYGON_BASE -- @field #ZONE_POLYGON_BASE
ZONE_POLYGON_BASE = { ZONE_POLYGON_BASE = {
ClassName="ZONE_POLYGON_BASE", ClassName="ZONE_POLYGON_BASE",
_Triangles={}, -- _ZONE_TRIANGLES _Triangles={}, -- #table of #_ZONE_TRIANGLE
SurfaceArea=0, SurfaceArea=0,
DrawID={} -- making a table out of the MarkID so its easier to draw an n-sided polygon, see ZONE_POLYGON_BASE:Draw() DrawID={}, -- making a table out of the MarkID so its easier to draw an n-sided polygon, see ZONE_POLYGON_BASE:Draw()
FillTriangles = {},
Borderlines = {},
} }
--- A 2D points array. --- A 2D points array.
@ -2470,57 +2492,113 @@ end
-- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. -- doesn't seem to work -- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value. -- doesn't seem to work
-- @param #number FillAlpha Transparency [0,1]. Default 0.15. -- doesn't seem to work -- @param #number FillAlpha Transparency [0,1]. Default 0.15. -- doesn't seem to work
-- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid. -- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid.
-- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false. -- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false.s
-- @return #ZONE_POLYGON_BASE self -- @return #ZONE_POLYGON_BASE self
function ZONE_POLYGON_BASE:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, IncludeTriangles) function ZONE_POLYGON_BASE:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, IncludeTriangles)
if self._.Polygon and #self._.Polygon >= 3 then
Coalition = Coalition or self:GetDrawCoalition()
-- Set draw coalition.
self:SetDrawCoalition(Coalition)
Color = Color or self:GetColorRGB() if self._.Polygon and #self._.Polygon >= 3 then
Alpha = Alpha or 1 Coalition = Coalition or self:GetDrawCoalition()
-- Set color. -- Set draw coalition.
self:SetColor(Color, Alpha) self:SetDrawCoalition(Coalition)
FillColor = FillColor or self:GetFillColorRGB() Color = Color or self:GetColorRGB()
if not FillColor then Alpha = Alpha or self:GetColorAlpha()
UTILS.DeepCopy(Color)
end
FillAlpha = FillAlpha or self:GetFillColorAlpha()
if not FillAlpha then
FillAlpha = 0.15
end
-- Set fill color -----------> has fill color worked in recent versions of DCS? FillColor = FillColor or self:GetFillColorRGB()
-- doing something like FillAlpha = FillAlpha or self:GetFillColorAlpha()
--
-- trigger.action.markupToAll(7, -1, 501, p.Coords[1]:GetVec3(), p.Coords[2]:GetVec3(),p.Coords[3]:GetVec3(),p.Coords[4]:GetVec3(),{1,0,0, 1}, {1,0,0, 1}, 4, false, Text or "")
--
-- doesn't seem to fill in the shape for an n-sided polygon
self:SetFillColor(FillColor, FillAlpha)
IncludeTriangles = IncludeTriangles or false if FillColor then
self:ReFill(FillColor,FillAlpha)
-- just draw the triangles, we get the outline for free
if IncludeTriangles then
for _, triangle in pairs(self._Triangles) do
local draw_ids = triangle:Draw()
table.combine(self.DrawID, draw_ids)
end
-- draw outline only
else
local coords = self:GetVerticiesCoordinates()
for i = 1, #coords do
local c1 = coords[i]
local c2 = coords[i % #coords + 1]
table.add(self.DrawID, c1:LineToAll(c2, Coalition, Color, Alpha, LineType, ReadOnly))
end
end
end end
return self
if Color then
self:ReDrawBorderline(Color,Alpha,LineType)
end
end
if false then
local coords = self:GetVerticiesCoordinates()
local coord=coords[1] --Core.Point#COORDINATE
table.remove(coords, 1)
coord:MarkupToAllFreeForm(coords, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly, "Drew Polygon")
if true then
return
end
end
return self
end
--- Change/Re-fill a Polygon Zone
-- @param #ZONE_POLYGON_BASE self
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red.
-- @param #number Alpha Transparency [0,1]. Default 1.
-- @return #ZONE_POLYGON_BASE self
function ZONE_POLYGON_BASE:ReFill(Color,Alpha)
local color = Color or self:GetFillColorRGB() or {1,0,0}
local alpha = Alpha or self:GetFillColorAlpha() or 1
local coalition = self:GetDrawCoalition() or -1
-- undraw if already filled
if #self.FillTriangles > 0 then
for _, triangle in pairs(self._Triangles) do
triangle:UndrawZone()
end
-- remove mark IDs
for _,_value in pairs(self.FillTriangles) do
table.remove_by_value(self.DrawID, _value)
end
self.FillTriangles = nil
self.FillTriangles = {}
end
-- refill
for _, triangle in pairs(self._Triangles) do
local draw_ids = triangle:Fill(coalition,color,alpha,nil)
self.FillTriangles = draw_ids
table.combine(self.DrawID, draw_ids)
end
return self
end
--- Change/Re-draw the border of a Polygon Zone
-- @param #ZONE_POLYGON_BASE self
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red.
-- @param #number Alpha Transparency [0,1]. Default 1.
-- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid.
-- @return #ZONE_POLYGON_BASE
function ZONE_POLYGON_BASE:ReDrawBorderline(Color, Alpha, LineType)
local color = Color or self:GetFillColorRGB() or {1,0,0}
local alpha = Alpha or self:GetFillColorAlpha() or 1
local coalition = self:GetDrawCoalition() or -1
local linetype = LineType or 1
-- undraw if already drawn
if #self.Borderlines > 0 then
for _, MarkID in pairs(self.Borderlines) do
trigger.action.removeMark(MarkID)
end
-- remove mark IDs
for _,_value in pairs(self.Borderlines) do
table.remove_by_value(self.DrawID, _value)
end
self.Borderlines = nil
self.Borderlines = {}
end
-- Redraw border
local coords = self:GetVerticiesCoordinates()
for i = 1, #coords do
local c1 = coords[i]
local c2 = coords[i % #coords + 1]
local newID = c1:LineToAll(c2, coalition, color, alpha, linetype, nil)
self.DrawID[#self.DrawID+1]=newID
self.Borderlines[#self.Borderlines+1] = newID
end
return self
end end
--- Get the surface area of this polygon --- Get the surface area of this polygon
@ -2856,6 +2934,7 @@ function ZONE_POLYGON_BASE:Boundary(Coalition, Color, Radius, Alpha, Segments, C
Alpha = Alpha or 1 Alpha = Alpha or 1
Segments = Segments or 10 Segments = Segments or 10
Closed = Closed or false Closed = Closed or false
local Limit
local i = 1 local i = 1
local j = #self._.Polygon local j = #self._.Polygon
if (Closed) then if (Closed) then
@ -3610,13 +3689,17 @@ ZONE_OVAL = {
--- Creates a new ZONE_OVAL from a center point, major axis, minor axis, and angle. --- Creates a new ZONE_OVAL from a center point, major axis, minor axis, and angle.
--- ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Oval.lua --- ported from https://github.com/nielsvaes/CCMOOSE/blob/master/Moose%20Development/Moose/Shapes/Oval.lua
-- @param #ZONE_OVAL self
-- @param #string name Name of the zone.
-- @param #table vec2 The center point of the oval -- @param #table vec2 The center point of the oval
-- @param #number major_axis The major axis of the oval -- @param #number major_axis The major axis of the oval
-- @param #number minor_axis The minor axis of the oval -- @param #number minor_axis The minor axis of the oval
-- @param #number angle The angle of the oval -- @param #number angle The angle of the oval
-- @return #ZONE_OVAL The new oval -- @return #ZONE_OVAL The new oval
function ZONE_OVAL:New(name, vec2, major_axis, minor_axis, angle) function ZONE_OVAL:New(name, vec2, major_axis, minor_axis, angle)
self = BASE:Inherit(self, ZONE_BASE:New()) self = BASE:Inherit(self, ZONE_BASE:New())
self.ZoneName = name self.ZoneName = name
self.CenterVec2 = vec2 self.CenterVec2 = vec2
self.MajorAxis = major_axis self.MajorAxis = major_axis

View File

@ -606,8 +606,10 @@ function AICSAR:SetPilotTTSVoice(Voice,Culture,Gender)
self.SRSPilot:SetCulture(Culture or "en-US") self.SRSPilot:SetCulture(Culture or "en-US")
self.SRSPilot:SetGender(Gender or "male") self.SRSPilot:SetGender(Gender or "male")
self.SRSPilot:SetLabel("PILOT") self.SRSPilot:SetLabel("PILOT")
if self.SRS.google then if self.SRSGoogle then
self.SRSPilot:SetGoogle(self.SRS.google) local poptions = self.SRS:GetProviderOptions(MSRS.Provider.GOOGLE) -- Sound.SRS#MSRS.ProviderOptions
self.SRSPilot:SetGoogle(poptions.credentials)
self.SRSPilot:SetGoogleAPIKey(poptions.key)
end end
return self return self
end end
@ -627,9 +629,11 @@ function AICSAR:SetOperatorTTSVoice(Voice,Culture,Gender)
self.SRSOperator:SetVoice(Voice) self.SRSOperator:SetVoice(Voice)
self.SRSOperator:SetCulture(Culture or "en-GB") self.SRSOperator:SetCulture(Culture or "en-GB")
self.SRSOperator:SetGender(Gender or "female") self.SRSOperator:SetGender(Gender or "female")
self.SRSPilot:SetLabel("RESCUE") self.SRSOperator:SetLabel("RESCUE")
if self.SRS.google then if self.SRSGoogle then
self.SRSOperator:SetGoogle(self.SRS.google) local poptions = self.SRS:GetProviderOptions(MSRS.Provider.GOOGLE) -- Sound.SRS#MSRS.ProviderOptions
self.SRSOperator:SetGoogle(poptions.credentials)
self.SRSOperator:SetGoogleAPIKey(poptions.key)
end end
return self return self
end end

View File

@ -10,9 +10,7 @@
-- --
-- === -- ===
-- --
-- ## Missions: -- ## Missions: None
--
-- [ABP - Airbase Police](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/ABP%20-%20Airbase%20Police)
-- --
-- === -- ===
-- --
@ -699,7 +697,8 @@ end
function ATC_GROUND_UNIVERSAL:_AirbaseMonitor() function ATC_GROUND_UNIVERSAL:_AirbaseMonitor()
self:I("_AirbaseMonitor") self:I("_AirbaseMonitor")
self.SetClient:ForEachClient( self.SetClient:ForEachClient(
--- @param Wrapper.Client#CLIENT Client --- Nameless function
-- @param Wrapper.Client#CLIENT Client
function( Client ) function( Client )
if Client:IsAlive() then if Client:IsAlive() then

View File

@ -95,7 +95,7 @@ do -- DETECTION_BASE
-- --
-- ## Radar Blur - use to make the radar less exact, e.g. for WWII scenarios -- ## Radar Blur - use to make the radar less exact, e.g. for WWII scenarios
-- --
-- * @{DETECTION_BASE.SetRadarBlur}(): Set the radar blur to be used. -- * @{#DETECTION_BASE.SetRadarBlur}(): Set the radar blur to be used.
-- --
-- ## **DETECTION_ derived classes** group the detected units into a **DetectedItems[]** list -- ## **DETECTION_ derived classes** group the detected units into a **DetectedItems[]** list
-- --

View File

@ -22,7 +22,7 @@
-- @module Functional.Mantis -- @module Functional.Mantis
-- @image Functional.Mantis.jpg -- @image Functional.Mantis.jpg
-- --
-- Last Update: Nov 2023 -- Last Update: Dec 2023
------------------------------------------------------------------------- -------------------------------------------------------------------------
--- **MANTIS** class, extends Core.Base#BASE --- **MANTIS** class, extends Core.Base#BASE
@ -94,7 +94,7 @@
-- Known SAM types at the time of writing are: -- Known SAM types at the time of writing are:
-- --
-- * Avenger -- * Avenger
-- * Chaparrel -- * Chaparral
-- * Hawk -- * Hawk
-- * Linebacker -- * Linebacker
-- * NASAMS -- * NASAMS
@ -365,7 +365,7 @@ MANTIS.SamData = {
["SA-15"] = { Range=11, Blindspot=0, Height=6, Type="Short", Radar="Tor 9A331" }, ["SA-15"] = { Range=11, Blindspot=0, Height=6, Type="Short", Radar="Tor 9A331" },
["SA-13"] = { Range=5, Blindspot=0, Height=3, Type="Short", Radar="Strela" }, ["SA-13"] = { Range=5, Blindspot=0, Height=3, Type="Short", Radar="Strela" },
["Avenger"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Avenger" }, ["Avenger"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Avenger" },
["Chaparrel"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" }, ["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Linebacker" }, ["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Short", Radar="Linebacker" },
["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" }, ["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" },
-- units from HDS Mod, multi launcher options is tricky -- units from HDS Mod, multi launcher options is tricky
@ -631,7 +631,7 @@ do
-- TODO Version -- TODO Version
-- @field #string version -- @field #string version
self.version="0.8.15" self.version="0.8.16"
self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
--- FSM Functions --- --- FSM Functions ---
@ -1149,7 +1149,7 @@ do
--self:T(self.lid.." Relocating HQ") --self:T(self.lid.." Relocating HQ")
local text = self.lid.." Relocating HQ" local text = self.lid.." Relocating HQ"
--local m= MESSAGE:New(text,10,"MANTIS"):ToAll() --local m= MESSAGE:New(text,10,"MANTIS"):ToAll()
_hqgrp:RelocateGroundRandomInRadius(20,500,true,true) _hqgrp:RelocateGroundRandomInRadius(20,500,true,true,nil,true)
end end
--relocate EWR --relocate EWR
-- TODO: maybe dependent on AlarmState? Observed: SA11 SR only relocates if no objects in reach -- TODO: maybe dependent on AlarmState? Observed: SA11 SR only relocates if no objects in reach
@ -1163,7 +1163,7 @@ do
local text = self.lid.." Relocating EWR ".._grp:GetName() local text = self.lid.." Relocating EWR ".._grp:GetName()
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug) local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
if self.verbose then self:I(text) end if self.verbose then self:I(text) end
_grp:RelocateGroundRandomInRadius(20,500,true,true) _grp:RelocateGroundRandomInRadius(20,500,true,true,nil,true)
end end
end end
end end

View File

@ -170,7 +170,7 @@
-- --
-- * A specific departure and/or destination airport can be chosen. -- * A specific departure and/or destination airport can be chosen.
-- * Valid coalitions can be set, e.g. only red, blue or neutral, all three "colours". -- * Valid coalitions can be set, e.g. only red, blue or neutral, all three "colours".
-- * It is possible to start in air within a zone defined in the mission editor or within a zone above an airport of the map. -- * It is possible to start in air within a zone or within a zone above an airport of the map.
-- --
-- ## Flight Plan -- ## Flight Plan
-- --
@ -1179,13 +1179,13 @@ function RAT:SetTakeoffAir()
return self return self
end end
--- Set possible departure ports. This can be an airport or a zone defined in the mission editor. --- Set possible departure ports. This can be an airport or a zone.
-- @param #RAT self -- @param #RAT self
-- @param #string departurenames Name or table of names of departure airports or zones. -- @param #string departurenames Name or table of names of departure airports or zones.
-- @return #RAT RAT self object. -- @return #RAT RAT self object.
-- @usage RAT:SetDeparture("Sochi-Adler") will spawn RAT objects at Sochi-Adler airport. -- @usage RAT:SetDeparture("Sochi-Adler") will spawn RAT objects at Sochi-Adler airport.
-- @usage RAT:SetDeparture({"Sochi-Adler", "Gudauta"}) will spawn RAT aircraft radomly at Sochi-Adler or Gudauta airport. -- @usage RAT:SetDeparture({"Sochi-Adler", "Gudauta"}) will spawn RAT aircraft radomly at Sochi-Adler or Gudauta airport.
-- @usage RAT:SetDeparture({"Zone A", "Gudauta"}) will spawn RAT aircraft in air randomly within Zone A, which has to be defined in the mission editor, or within a zone around Gudauta airport. Note that this also requires RAT:takeoff("air") to be set. -- @usage RAT:SetDeparture({"Zone A", "Gudauta"}) will spawn RAT aircraft in air randomly within Zone A, or within a zone around Gudauta airport. Note that this also requires RAT:takeoff("air") to be set.
function RAT:SetDeparture(departurenames) function RAT:SetDeparture(departurenames)
self:F2(departurenames) self:F2(departurenames)
@ -2537,7 +2537,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint)
end end
elseif self:_ZoneExists(_departure) then elseif self:_ZoneExists(_departure) then
-- If it's not an airport, check whether it's a zone. -- If it's not an airport, check whether it's a zone.
departure=ZONE:New(_departure) departure=ZONE:FindByName(_departure)
else else
local text=string.format("ERROR! Specified departure airport %s does not exist for %s.", _departure, self.alias) local text=string.format("ERROR! Specified departure airport %s does not exist for %s.", _departure, self.alias)
self:E(RAT.id..text) self:E(RAT.id..text)
@ -2635,7 +2635,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint)
end end
elseif self:_ZoneExists(_destination) then elseif self:_ZoneExists(_destination) then
destination=ZONE:New(_destination) destination=ZONE:FindByName(_destination)
else else
local text=string.format("ERROR: Specified destination airport/zone %s does not exist for %s!", _destination, self.alias) local text=string.format("ERROR: Specified destination airport/zone %s does not exist for %s!", _destination, self.alias)
self:E(RAT.id.."ERROR: "..text) self:E(RAT.id.."ERROR: "..text)
@ -3142,7 +3142,7 @@ function RAT:_PickDeparture(takeoff)
end end
elseif self:_ZoneExists(name) then elseif self:_ZoneExists(name) then
if takeoff==RAT.wp.air then if takeoff==RAT.wp.air then
dep=ZONE:New(name) dep=ZONE:FindByName(name)
else else
self:E(RAT.id..string.format("ERROR! Takeoff is not in air. Cannot use %s as departure.", name)) self:E(RAT.id..string.format("ERROR! Takeoff is not in air. Cannot use %s as departure.", name))
end end
@ -3254,7 +3254,7 @@ function RAT:_PickDestination(departure, q, minrange, maxrange, random, landing)
end end
elseif self:_ZoneExists(name) then elseif self:_ZoneExists(name) then
if landing==RAT.wp.air then if landing==RAT.wp.air then
dest=ZONE:New(name) dest=ZONE:FindByName(name)
else else
self:E(RAT.id..string.format("ERROR! Landing is not in air. Cannot use zone %s as destination!", name)) self:E(RAT.id..string.format("ERROR! Landing is not in air. Cannot use zone %s as destination!", name))
end end
@ -4930,12 +4930,12 @@ function RAT:_AirportExists(name)
return false return false
end end
--- Test if a trigger zone defined in the mission editor exists. --- Test if a zone exists.
-- @param #RAT self -- @param #RAT self
-- @param #string name -- @param #string name
-- @return #boolean True if zone exsits, false otherwise. -- @return #boolean True if zone exsits, false otherwise.
function RAT:_ZoneExists(name) function RAT:_ZoneExists(name)
local z=trigger.misc.getZone(name) local z=ZONE:FindByName(name) --trigger.misc.getZone(name) as suggested by @Viking on MOOSE discord #rat
if z then if z then
return true return true
end end

View File

@ -1738,6 +1738,8 @@ end
function RANGE:OnEventBirth( EventData ) function RANGE:OnEventBirth( EventData )
self:F( { eventbirth = EventData } ) self:F( { eventbirth = EventData } )
if not EventData.IniPlayerName then return end
local _unitName = EventData.IniUnitName local _unitName = EventData.IniUnitName
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )

View File

@ -17,9 +17,9 @@
-- --
-- === -- ===
-- --
-- ### Authors: **FlightControl**, **applevangelist** -- ### Authors: **applevangelist**, **FlightControl**
-- --
-- Last Update: Oct 2023 -- Last Update: Dec 2023
-- --
-- === -- ===
-- --
@ -144,7 +144,7 @@ function SEAD:New( SEADGroupPrefixes, Padding )
self:AddTransition("*", "ManageEvasion", "*") self:AddTransition("*", "ManageEvasion", "*")
self:AddTransition("*", "CalculateHitZone", "*") self:AddTransition("*", "CalculateHitZone", "*")
self:I("*** SEAD - Started Version 0.4.5") self:I("*** SEAD - Started Version 0.4.6")
return self return self
end end
@ -401,7 +401,7 @@ function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADP
grp:EnableEmission(false) grp:EnableEmission(false)
end end
grp:OptionAlarmStateGreen() -- needed else we cannot move around grp:OptionAlarmStateGreen() -- needed else we cannot move around
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond") grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond",true)
if self.UseCallBack then if self.UseCallBack then
local object = self.CallBack local object = self.CallBack
object:SeadSuppressionStart(grp,name,attacker) object:SeadSuppressionStart(grp,name,attacker)

View File

@ -0,0 +1,590 @@
--- **Functional** - TIRESIAS - manages AI behaviour.
--
-- ===
--
-- The @{#TIRESIAS} class is working in the back to keep your large-scale ground units in check.
--
-- ## Features:
--
-- * Designed to keep CPU and Network usage lower on missions with a lot of ground units.
-- * Does not affect ships to keep the Navy guys happy.
-- * Does not affect OpsGroup type groups.
-- * Distinguishes between SAM groups, AAA groups and other ground groups.
-- * Exceptions can be defined to keep certain actions going.
-- * Works coalition-independent in the back
-- * Easy setup.
--
-- ===
--
-- ## Missions:
--
-- ### [TIRESIAS](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master)
--
-- ===
--
-- ### Author : **applevangelist **
--
-- @module Functional.Tiresias
-- @image Functional.Tiresias.jpg
--
-- Last Update: Dec 2023
-------------------------------------------------------------------------
--- **TIRESIAS** class, extends Core.Base#BASE
-- @type TIRESIAS
-- @field #string ClassName
-- @field #booelan debug
-- @field #string version
-- @field #number Interval
-- @field Core.Set#SET_GROUP GroundSet
-- @field #number Coalition
-- @field Core.Set#SET_GROUP VehicleSet
-- @field Core.Set#SET_GROUP AAASet
-- @field Core.Set#SET_GROUP SAMSet
-- @field Core.Set#SET_GROUP ExceptionSet
-- @field Core.Set#SET_OPSGROUP OpsGroupSet
-- @field #number AAARange
-- @field #number HeloSwitchRange
-- @field #number PlaneSwitchRange
-- @field Core.Set#SET_GROUP FlightSet
-- @field #boolean SwitchAAA
-- @extends Core.Fsm#FSM
---
-- @type TIRESIAS.Data
-- @field #string type
-- @field #number range
-- @field #boolean invisible
-- @field #boolean AIOff
-- @field #boolean exception
--- *Tiresias, Greek demi-god and shapeshifter, blinded by the Gods, works as oracle for you.* (Wiki)
--
-- ===
--
-- ## TIRESIAS Concept
--
-- * Designed to keep CPU and Network usage lower on missions with a lot of ground units.
-- * Does not affect ships to keep the Navy guys happy.
-- * Does not affect OpsGroup type groups.
-- * Distinguishes between SAM groups, AAA groups and other ground groups.
-- * Exceptions can be defined in SET_GROUP objects to keep certain actions going.
-- * Works coalition-independent in the back
-- * Easy setup.
--
-- ## Setup
--
-- Setup is a one-liner:
--
-- local blinder = TIRESIAS:New()
--
-- Optionally you can set up exceptions, e.g. for convoys driving around
--
-- local exceptionset = SET_GROUP:New():FilterCoalitions("red"):FilterPrefixes("Convoy"):FilterStart()
-- local blinder = TIRESIAS:New()
-- blinder:AddExceptionSet(exceptionset)
--
-- Options
--
-- -- Setup different radius for activation around helo and airplane groups (applies to AI and humans)
-- blinder:SetActivationRanges(10,25) -- defaults are 10, and 25
--
-- -- Setup engagement ranges for AAA (non-advanced SAM units like Flaks etc) and if you want them to be AIOff
-- blinder:SetAAARanges(60,true) -- defaults are 60, and true
--
-- @field #TIRESIAS
TIRESIAS = {
ClassName = "TIRESIAS",
debug = false,
version = "0.0.4",
Interval = 20,
GroundSet = nil,
VehicleSet = nil,
AAASet = nil,
SAMSet = nil,
ExceptionSet = nil,
AAARange = 60, -- 60%
HeloSwitchRange = 10, -- NM
PlaneSwitchRange = 25, -- NM
SwitchAAA = true,
}
--- [USER] Create a new Tiresias object and start it up.
-- @param #TIRESIAS self
-- @return #TIRESIAS self
function TIRESIAS:New()
-- Inherit everything from FSM class.
local self = BASE:Inherit(self, FSM:New()) -- #TIRESIAS
--- FSM Functions ---
-- Start State.
self:SetStartState("Stopped")
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
self:AddTransition("*", "Status", "*") -- TIRESIAS status update.
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
self.ExceptionSet = SET_GROUP:New():Clear(false)
self:HandleEvent(EVENTS.PlayerEnterAircraft,self._EventHandler)
self.lid = string.format("TIRESIAS %s | ",self.version)
self:I(self.lid.."Managing ground groups!")
--- Triggers the FSM event "Stop". Stops TIRESIAS and all its event handlers.
-- @function [parent=#TIRESIAS] Stop
-- @param #TIRESIAS self
--- Triggers the FSM event "Stop" after a delay. Stops TIRESIAS and all its event handlers.
-- @function [parent=#TIRESIAS] __Stop
-- @param #TIRESIAS self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Start". Starts TIRESIAS and all its event handlers. Note - `:New()` already starts the instance.
-- @function [parent=#TIRESIAS] Start
-- @param #TIRESIAS self
--- Triggers the FSM event "Start" after a delay. Starts TIRESIAS and all its event handlers. Note - `:New()` already starts the instance.
-- @function [parent=#TIRESIAS] __Start
-- @param #TIRESIAS self
-- @param #number delay Delay in seconds.
self:__Start(1)
return self
end
-------------------------------------------------------------------------------------------------------------
--
-- Helper Functions
--
-------------------------------------------------------------------------------------------------------------
---[USER] Set activation radius for Helos and Planes in Nautical Miles.
-- @param #TIRESIAS self
-- @param #number HeloMiles Radius around a Helicopter in which AI ground units will be activated. Defaults to 10NM.
-- @param #number PlaneMiles Radius around an Airplane in which AI ground units will be activated. Defaults to 25NM.
-- @return #TIRESIAS self
function TIRESIAS:SetActivationRanges(HeloMiles,PlaneMiles)
self.HeloSwitchRange = HeloMiles or 10
self.PlaneSwitchRange = PlaneMiles or 25
return self
end
---[USER] Set AAA Ranges - AAA equals non-SAM systems which qualify as AAA in DCS world.
-- @param #TIRESIAS self
-- @param #number FiringRange The engagement range that AAA units will be set to. Can be 0 to 100 (percent). Defaults to 60.
-- @param #boolean SwitchAAA Decide if these system will have their AI switched off, too. Defaults to true.
-- @return #TIRESIAS self
function TIRESIAS:SetAAARanges(FiringRange,SwitchAAA)
self.AAARange = FiringRange or 60
self.SwitchAAA = (SwitchAAA == false) and false or true
return self
end
--- [USER] Add a SET_GROUP of GROUP objects as exceptions. Can be done multiple times.
-- @param #TIRESIAS self
-- @param Core.Set#SET_GROUP Set to add to the exception list.
-- @return #TIRESIAS self
function TIRESIAS:AddExceptionSet(Set)
self:T(self.lid.."AddExceptionSet")
local exceptions = self.ExceptionSet
Set:ForEachGroupAlive(
function(grp)
if not grp.Tiresias then
grp.Tiresias = { -- #TIRESIAS.Data
type = "Exception",
exception = true,
}
exceptions:AddGroup(grp,true)
end
BASE:I("TIRESIAS: Added exception group: "..grp:GetName())
end
)
return self
end
--- [INTERNAL] Filter Function
-- @param Wrapper.Group#GROUP Group
-- @return #boolean isin
function TIRESIAS._FilterNotAAA(Group)
local grp = Group -- Wrapper.Group#GROUP
local isaaa = grp:IsAAA()
if isaaa == true and grp:IsGround() and not grp:IsShip() then
return false -- remove from SET
else
return true -- keep in SET
end
end
--- [INTERNAL] Filter Function
-- @param Wrapper.Group#GROUP Group
-- @return #boolean isin
function TIRESIAS._FilterNotSAM(Group)
local grp = Group -- Wrapper.Group#GROUP
local issam = grp:IsSAM()
if issam == true and grp:IsGround() and not grp:IsShip() then
return false -- remove from SET
else
return true -- keep in SET
end
end
--- [INTERNAL] Filter Function
-- @param Wrapper.Group#GROUP Group
-- @return #boolean isin
function TIRESIAS._FilterAAA(Group)
local grp = Group -- Wrapper.Group#GROUP
local isaaa = grp:IsAAA()
if isaaa == true and grp:IsGround() and not grp:IsShip() then
return true -- remove from SET
else
return false -- keep in SET
end
end
--- [INTERNAL] Filter Function
-- @param Wrapper.Group#GROUP Group
-- @return #boolean isin
function TIRESIAS._FilterSAM(Group)
local grp = Group -- Wrapper.Group#GROUP
local issam = grp:IsSAM()
if issam == true and grp:IsGround() and not grp:IsShip() then
return true -- remove from SET
else
return false -- keep in SET
end
end
--- [INTERNAL] Init Groups
-- @param #TIRESIAS self
-- @return #TIRESIAS self
function TIRESIAS:_InitGroups()
self:T(self.lid.."_InitGroups")
-- Set all groups invisible/motionless
local EngageRange = self.AAARange
local SwitchAAA = self.SwitchAAA
--- AAA
self.AAASet:ForEachGroupAlive(
function(grp)
if not grp.Tiresias then
grp:OptionEngageRange(EngageRange)
grp:SetCommandInvisible(true)
if SwitchAAA then
grp:SetAIOff()
grp:EnableEmission(false)
end
grp.Tiresias = { -- #TIRESIAS.Data
type = "AAA",
invisible = true,
range = EngageRange,
exception = false,
AIOff = SwitchAAA,
}
end
if grp.Tiresias and (not grp.Tiresias.exception == true) then
if grp.Tiresias.invisible and grp.Tiresias.invisible == false then
grp:SetCommandInvisible(true)
grp.Tiresias.invisible = true
if SwitchAAA then
grp:SetAIOff()
grp:EnableEmission(false)
grp.Tiresias.AIOff = true
end
end
end
--BASE:I(string.format("Init/Switch off AAA %s (Exception %s)",grp:GetName(),tostring(grp.Tiresias.exception)))
end
)
--- Vehicles
self.VehicleSet:ForEachGroupAlive(
function(grp)
if not grp.Tiresias then
grp:SetAIOff()
grp:SetCommandInvisible(true)
grp.Tiresias = { -- #TIRESIAS.Data
type = "Vehicle",
invisible = true,
AIOff = true,
exception = false,
}
end
if grp.Tiresias and (not grp.Tiresias.exception == true) then
if grp.Tiresias and grp.Tiresias.invisible and grp.Tiresias.invisible == false then
grp:SetCommandInvisible(true)
grp:SetAIOff()
grp.Tiresias.invisible = true
end
end
--BASE:I(string.format("Init/Switch off Vehicle %s (Exception %s)",grp:GetName(),tostring(grp.Tiresias.exception)))
end
)
--- SAM
self.SAMSet:ForEachGroupAlive(
function(grp)
if not grp.Tiresias then
grp:SetCommandInvisible(true)
grp.Tiresias = { -- #TIRESIAS.Data
type = "SAM",
invisible = true,
exception = false,
}
end
if grp.Tiresias and (not grp.Tiresias.exception == true) then
if grp.Tiresias and grp.Tiresias.invisible and grp.Tiresias.invisible == false then
grp:SetCommandInvisible(true)
grp.Tiresias.invisible = true
end
end
--BASE:I(string.format("Init/Switch off SAM %s (Exception %s)",grp:GetName(),tostring(grp.Tiresias.exception)))
end
)
return self
end
--- [INTERNAL] Event handler function
-- @param #TIRESIAS self
-- @param Core.Event#EVENTDATA EventData
-- @return #TIRESIAS self
function TIRESIAS:_EventHandler(EventData)
self:T(string.format("%s Event = %d",self.lid, EventData.id))
local event = EventData -- Core.Event#EVENTDATA
if event.id == EVENTS.PlayerEnterAircraft or event.id == EVENTS.PlayerEnterUnit then
--local _coalition = event.IniCoalition
--if _coalition ~= self.Coalition then
-- return --ignore!
--end
local unitname = event.IniUnitName or "none"
local _unit = event.IniUnit
local _group = event.IniGroup
if _group and _group:IsAlive() then
local radius = self.PlaneSwitchRange
if _group:IsHelicopter() then
radius = self.HeloSwitchRange
end
self:_SwitchOnGroups(_group,radius)
end
end
return self
end
--- [INTERNAL] Switch Groups Behaviour
-- @param #TIRESIAS self
-- @param Wrapper.Group#GROUP group
-- @param #number radius Radius in NM
-- @return #TIRESIAS self
function TIRESIAS:_SwitchOnGroups(group,radius)
self:T(self.lid.."_SwitchOnGroups "..group:GetName().." Radius "..radius.." NM")
local zone = ZONE_GROUP:New("Zone-"..group:GetName(),group,UTILS.NMToMeters(radius))
local ground = SET_GROUP:New():FilterCategoryGround():FilterZones({zone}):FilterOnce()
local count = ground:CountAlive()
if self.debug then
local text = string.format("There are %d groups around this plane or helo!",count)
self:I(text)
end
local SwitchAAA = self.SwitchAAA
if ground:CountAlive() > 0 then
ground:ForEachGroupAlive(
function(grp)
if grp.Tiresias and grp.Tiresias.type and (not grp.Tiresias.exception == true ) then
if grp.Tiresias.invisible == true then
grp:SetCommandInvisible(false)
grp.Tiresias.invisible = false
end
if grp.Tiresias.type == "Vehicle" and grp.Tiresias.AIOff and grp.Tiresias.AIOff == true then
grp:SetAIOn()
grp.Tiresias.AIOff = false
end
if SwitchAAA and grp.Tiresias.type == "AAA" and grp.Tiresias.AIOff and grp.Tiresias.AIOff == true then
grp:SetAIOn()
grp:EnableEmission(true)
grp.Tiresias.AIOff = false
end
--BASE:I(string.format("TIRESIAS - Switch on %s %s (Exception %s)",tostring(grp.Tiresias.type),grp:GetName(),tostring(grp.Tiresias.exception)))
else
BASE:E("TIRESIAS - This group has not been initialized or is an exception!")
end
end
)
end
return self
end
-------------------------------------------------------------------------------------------------------------
--
-- FSM Functions
--
-------------------------------------------------------------------------------------------------------------
--- [INTERNAL] FSM Function
-- @param #TIRESIAS self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #TIRESIAS self
function TIRESIAS:onafterStart(From, Event, To)
self:T({From, Event, To})
local VehicleSet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterNotAAA):FilterFunction(TIRESIAS._FilterNotSAM):FilterStart()
local AAASet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterAAA):FilterStart()
local SAMSet = SET_GROUP:New():FilterCategoryGround():FilterFunction(TIRESIAS._FilterSAM):FilterStart()
local OpsGroupSet = SET_OPSGROUP:New():FilterActive(true):FilterStart()
self.FlightSet = SET_GROUP:New():FilterCategories({"plane","helicopter"}):FilterStart()
local EngageRange = self.AAARange
local ExceptionSet = self.ExceptionSet
if self.ExceptionSet then
function ExceptionSet:OnAfterAdded(From,Event,To,ObjectName,Object)
BASE:I("TIRESIAS: EXCEPTION Object Added: "..Object:GetName())
if Object and Object:IsAlive() then
Object.Tiresias = { -- #TIRESIAS.Data
type = "Exception",
exception = true,
}
Object:SetAIOn()
Object:SetCommandInvisible(false)
Object:EnableEmission(true)
end
end
local OGS = OpsGroupSet:GetAliveSet()
for _,_OG in pairs(OGS or {}) do
local OG = _OG -- Ops.OpsGroup#OPSGROUP
local grp = OG:GetGroup()
ExceptionSet:AddGroup(grp,true)
end
function OpsGroupSet:OnAfterAdded(From,Event,To,ObjectName,Object)
local grp = Object:GetGroup()
ExceptionSet:AddGroup(grp,true)
end
end
function VehicleSet:OnAfterAdded(From,Event,To,ObjectName,Object)
BASE:I("TIRESIAS: VEHCILE Object Added: "..Object:GetName())
if Object and Object:IsAlive() then
Object:SetAIOff()
Object:SetCommandInvisible(true)
Object.Tiresias = { -- #TIRESIAS.Data
type = "Vehicle",
invisible = true,
AIOff = true,
exception = false,
}
end
end
local SwitchAAA = self.SwitchAAA
function AAASet:OnAfterAdded(From,Event,To,ObjectName,Object)
if Object and Object:IsAlive() then
BASE:I("TIRESIAS: AAA Object Added: "..Object:GetName())
Object:OptionEngageRange(EngageRange)
Object:SetCommandInvisible(true)
if SwitchAAA then
Object:SetAIOff()
Object:EnableEmission(false)
end
Object.Tiresias = { -- #TIRESIAS.Data
type = "AAA",
invisible = true,
range = EngageRange,
exception = false,
AIOff = SwitchAAA,
}
end
end
function SAMSet:OnAfterAdded(From,Event,To,ObjectName,Object)
if Object and Object:IsAlive() then
BASE:I("TIRESIAS: SAM Object Added: "..Object:GetName())
Object:SetCommandInvisible(true)
Object.Tiresias = { -- #TIRESIAS.Data
type = "SAM",
invisible = true,
exception = false,
}
end
end
self.VehicleSet = VehicleSet
self.AAASet = AAASet
self.SAMSet = SAMSet
self.OpsGroupSet = OpsGroupSet
self:_InitGroups()
self:__Status(1)
return self
end
--- [INTERNAL] FSM Function
-- @param #TIRESIAS self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #TIRESIAS self
function TIRESIAS:onbeforeStatus(From, Event, To)
self:T({From, Event, To})
if self:GetState() == "Stopped" then
return false
end
return self
end
--- [INTERNAL] FSM Function
-- @param #TIRESIAS self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #TIRESIAS self
function TIRESIAS:onafterStatus(From, Event, To)
self:T({From, Event, To})
if self.debug then
local count = self.VehicleSet:CountAlive()
local AAAcount = self.AAASet:CountAlive()
local SAMcount = self.SAMSet:CountAlive()
local text = string.format("Overall: %d | Vehicles: %d | AAA: %d | SAM: %d",count+AAAcount+SAMcount,count,AAAcount,SAMcount)
self:I(text)
end
self:_InitGroups()
if self.FlightSet:CountAlive() > 0 then
local Set = self.FlightSet:GetAliveSet()
for _,_plane in pairs(Set) do
local plane = _plane -- Wrapper.Group#GROUP
local radius = self.PlaneSwitchRange
if plane:IsHelicopter() then
radius = self.HeloSwitchRange
end
self:_SwitchOnGroups(_plane,radius)
end
end
if self:GetState() ~= "Stopped" then
self:__Status(self.Interval)
end
return self
end
--- [INTERNAL] FSM Function
-- @param #TIRESIAS self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #TIRESIAS self
function TIRESIAS:onafterStop(From, Event, To)
self:T({From, Event, To})
self:UnHandleEvent(EVENTS.PlayerEnterAircraft)
return self
end
-------------------------------------------------------------------------------------------------------------
--
-- End
--
-------------------------------------------------------------------------------------------------------------

View File

@ -83,6 +83,7 @@ __Moose.Include( 'Scripts/Moose/Functional/ZoneCaptureCoalition.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ZoneGoal.lua' ) __Moose.Include( 'Scripts/Moose/Functional/ZoneGoal.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ZoneGoalCargo.lua' ) __Moose.Include( 'Scripts/Moose/Functional/ZoneGoalCargo.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ZoneGoalCoalition.lua' ) __Moose.Include( 'Scripts/Moose/Functional/ZoneGoalCoalition.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Tiresias.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Airboss.lua' ) __Moose.Include( 'Scripts/Moose/Ops/Airboss.lua' )
__Moose.Include( 'Scripts/Moose/Ops/AirWing.lua' ) __Moose.Include( 'Scripts/Moose/Ops/AirWing.lua' )

View File

@ -890,7 +890,7 @@ _ATIS = {}
--- ATIS class version. --- ATIS class version.
-- @field #string version -- @field #string version
ATIS.version = "0.10.4" ATIS.version = "1.0.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -1528,12 +1528,12 @@ end
--- Use SRS Simple-Text-To-Speech for transmissions. No sound files necessary. --- Use SRS Simple-Text-To-Speech for transmissions. No sound files necessary.
-- @param #ATIS self -- @param #ATIS self
-- @param #string PathToSRS Path to SRS directory. -- @param #string PathToSRS Path to SRS directory (only necessary if SRS exe backend is used).
-- @param #string Gender Gender: "male" or "female" (default). -- @param #string Gender Gender: "male" or "female" (default).
-- @param #string Culture Culture, e.g. "en-GB" (default). -- @param #string Culture Culture, e.g. "en-GB" (default).
-- @param #string Voice Specific voice. Overrides `Gender` and `Culture`. -- @param #string Voice Specific voice. Overrides `Gender` and `Culture`.
-- @param #number Port SRS port. Default 5002. -- @param #number Port SRS port. Default 5002.
-- @param #string GoogleKey Path to Google JSON-Key. -- @param #string GoogleKey Path to Google JSON-Key (SRS exe backend) or Google API key (DCS-gRPC backend).
-- @return #ATIS self -- @return #ATIS self
function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port, GoogleKey) function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port, GoogleKey)
if PathToSRS or MSRS.path then if PathToSRS or MSRS.path then

View File

@ -8212,7 +8212,7 @@ function AIRBOSS:OnEventBirth( EventData )
self:E( EventData ) self:E( EventData )
return return
end end
if EventData.IniUnit == nil then if EventData.IniUnit == nil and (not EventData.IniObjectCategory == Object.Category.STATIC) then
self:E( self.lid .. "ERROR: EventData.IniUnit=nil in event BIRTH!" ) self:E( self.lid .. "ERROR: EventData.IniUnit=nil in event BIRTH!" )
self:E( EventData ) self:E( EventData )
return return
@ -11197,7 +11197,7 @@ function AIRBOSS:_AttitudeMonitor( playerData )
end end
text = text .. string.format( "\nPitch=%.1f° | Roll=%.1f° | Yaw=%.1f°", pitch, roll, yaw ) text = text .. string.format( "\nPitch=%.1f° | Roll=%.1f° | Yaw=%.1f°", pitch, roll, yaw )
text = text .. string.format( "\nClimb Angle=%.1f° | Rate=%d ft/min", unit:GetClimbAngle(), velo.y * 196.85 ) text = text .. string.format( "\nClimb Angle=%.1f° | Rate=%d ft/min", unit:GetClimbAngle(), velo.y * 196.85 )
local dist = self:_GetOptLandingCoordinate():Get3DDistance( playerData.unit ) local dist = self:_GetOptLandingCoordinate():Get3DDistance( playerData.unit:GetVec3() )
-- Get player velocity in km/h. -- Get player velocity in km/h.
local vplayer = playerData.unit:GetVelocityKMH() local vplayer = playerData.unit:GetVelocityKMH()
-- Get carrier velocity in km/h. -- Get carrier velocity in km/h.
@ -14957,7 +14957,7 @@ function AIRBOSS:SetSRSPilotVoice( Voice, Gender, Culture )
self.PilotRadio.gender = Gender or "male" self.PilotRadio.gender = Gender or "male"
self.PilotRadio.culture = Culture or "en-US" self.PilotRadio.culture = Culture or "en-US"
if (not Voice) and self.SRS and self.SRS.google then if (not Voice) and self.SRS and self.SRS:GetProvider() == MSRS.Provider.GOOGLE then
self.PilotRadio.voice = MSRS.Voices.Google.Standard.en_US_Standard_J self.PilotRadio.voice = MSRS.Voices.Google.Standard.en_US_Standard_J
end end

View File

@ -1861,6 +1861,7 @@ function ARMYGROUP:_UpdateEngageTarget()
else else
-- Could not get position of target (not alive any more?) ==> Disengage. -- Could not get position of target (not alive any more?) ==> Disengage.
self:T(self.lid.."Could not get position of target ==> Disengage!")
self:Disengage() self:Disengage()
end end
@ -1868,6 +1869,7 @@ function ARMYGROUP:_UpdateEngageTarget()
else else
-- Target not alive any more ==> Disengage. -- Target not alive any more ==> Disengage.
self:T(self.lid.."Target not ALIVE ==> Disengage!")
self:Disengage() self:Disengage()
end end

View File

@ -31,7 +31,7 @@
-- @image OPS_CSAR.jpg -- @image OPS_CSAR.jpg
-- Date: May 2023 -- Date: May 2023
-- Last: Update Oct 2024 -- Last: Update Dec 2024
------------------------------------------------------------------------- -------------------------------------------------------------------------
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM --- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM

View File

@ -1228,7 +1228,7 @@ CTLD.UnitTypeCapabilities = {
--- CTLD class version. --- CTLD class version.
-- @field #string version -- @field #string version
CTLD.version="1.0.44" CTLD.version="1.0.45"
--- Instantiate a new CTLD. --- Instantiate a new CTLD.
-- @param #CTLD self -- @param #CTLD self
@ -1443,6 +1443,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
-- @param #number delay Delay in seconds. -- @param #number delay Delay in seconds.
--- Triggers the FSM event "Stop". Stops the CTLD and all its event handlers. --- Triggers the FSM event "Stop". Stops the CTLD and all its event handlers.
-- @function [parent=#CTLD] Stop
-- @param #CTLD self -- @param #CTLD self
--- Triggers the FSM event "Stop" after a delay. Stops the CTLD and all its event handlers. --- Triggers the FSM event "Stop" after a delay. Stops the CTLD and all its event handlers.
@ -2455,10 +2456,12 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack)
table.insert(droppedcargo,realcargo) table.insert(droppedcargo,realcargo)
else else
realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,false,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],false,cargotype.PerCrateMass,nil,subcat) realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,false,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],false,cargotype.PerCrateMass,nil,subcat)
Cargo:RemoveStock()
end end
table.insert(self.Spawned_Cargo, realcargo) table.insert(self.Spawned_Cargo, realcargo)
end end
if not (drop or pack) then
Cargo:RemoveStock()
end
local text = string.format("Crates for %s have been positioned near you!",cratename) local text = string.format("Crates for %s have been positioned near you!",cratename)
if drop then if drop then
text = string.format("Crates for %s have been dropped!",cratename) text = string.format("Crates for %s have been dropped!",cratename)
@ -3824,7 +3827,7 @@ end
-- @param #CTLD_CARGO.Enum Type Type of cargo. I.e. VEHICLE or FOB. VEHICLE will move to destination zones when dropped/build, FOB stays put. -- @param #CTLD_CARGO.Enum Type Type of cargo. I.e. VEHICLE or FOB. VEHICLE will move to destination zones when dropped/build, FOB stays put.
-- @param #number NoCrates Number of crates needed to build this cargo. -- @param #number NoCrates Number of crates needed to build this cargo.
-- @param #number PerCrateMass Mass in kg of each crate -- @param #number PerCrateMass Mass in kg of each crate
-- @param #number Stock Number of groups in stock. Nil for unlimited. -- @param #number Stock Number of buildable groups in stock. Nil for unlimited.
-- @param #string SubCategory Name of sub-category (optional). -- @param #string SubCategory Name of sub-category (optional).
function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory) function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory)
self:T(self.lid .. " AddCratesCargo") self:T(self.lid .. " AddCratesCargo")

View File

@ -141,14 +141,14 @@
-- -- **Note** If you need different tanker types, i.e. Boom and Drogue, set them up at different AirWings! -- -- **Note** If you need different tanker types, i.e. Boom and Drogue, set them up at different AirWings!
-- -- Add a tanker point -- -- Add a tanker point
-- mywing:AddPatrolPointTanker(AIRBASE.Caucasus.Kutaisi,ZONE:FindByName("Blue Zone Tanker"):GetCoordinate(),20000,280,270,50) -- mywing:AddPatrolPointTanker(AIRBASE.Caucasus.Kutaisi,ZONE:FindByName("Blue Zone Tanker"):GetCoordinate(),20000,280,270,50)
-- -- Add an AWACS squad - Radio 251 AM, TACAN 51Y -- -- Add a tanker squad - Radio 251 AM, TACAN 51Y
-- mywing:AddTankerSquadron("Blue Tanker","Tanker Ops Kutaisi",AIRBASE.Caucasus.Kutaisi,20,AI.Skill.EXCELLENT,602,nil,251,radio.modulation.AM,51) -- mywing:AddTankerSquadron("Blue Tanker","Tanker Ops Kutaisi",AIRBASE.Caucasus.Kutaisi,20,AI.Skill.EXCELLENT,602,nil,251,radio.modulation.AM,51)
-- --
-- ### Add an AWACS (optional) -- ### Add an AWACS (optional)
-- --
-- -- Add an AWACS point -- -- Add an AWACS point
-- mywing:AddPatrolPointAwacs(AIRBASE.Caucasus.Kutaisi,ZONE:FindByName("Blue Zone AWACS"):GetCoordinate(),25000,300,270,50) -- mywing:AddPatrolPointAwacs(AIRBASE.Caucasus.Kutaisi,ZONE:FindByName("Blue Zone AWACS"):GetCoordinate(),25000,300,270,50)
-- -- Add a tanker squad - Radio 251 AM, TACAN 51Y -- -- Add an AWACS squad - Radio 251 AM, TACAN 51Y
-- mywing:AddAWACSSquadron("Blue AWACS","AWACS Ops Kutaisi",AIRBASE.Caucasus.Kutaisi,20,AI.Skill.AVERAGE,702,nil,271,radio.modulation.AM) -- mywing:AddAWACSSquadron("Blue AWACS","AWACS Ops Kutaisi",AIRBASE.Caucasus.Kutaisi,20,AI.Skill.AVERAGE,702,nil,271,radio.modulation.AM)
-- --
-- # Fine-Tuning -- # Fine-Tuning

View File

@ -4424,14 +4424,11 @@ end
-- Misc Functions -- Misc Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add parking guard in front of a parking aircraft. --- [INTERNAL] Add parking guard in front of a parking aircraft - delayed for MP.
-- @param #FLIGHTCONTROL self -- @param #FLIGHTCONTROL self
-- @param Wrapper.Unit#UNIT unit The aircraft. -- @param Wrapper.Unit#UNIT unit The aircraft.
function FLIGHTCONTROL:SpawnParkingGuard(unit) function FLIGHTCONTROL:_SpawnParkingGuard(unit)
-- Position of the unit.
if unit and self.parkingGuard then
-- Position of the unit.
local coordinate=unit:GetCoordinate() local coordinate=unit:GetCoordinate()
-- Parking spot. -- Parking spot.
@ -4478,6 +4475,17 @@ function FLIGHTCONTROL:SpawnParkingGuard(unit)
else else
self:E(self.lid.."ERROR: Parking Guard already exists!") self:E(self.lid.."ERROR: Parking Guard already exists!")
end end
end
--- Add parking guard in front of a parking aircraft.
-- @param #FLIGHTCONTROL self
-- @param Wrapper.Unit#UNIT unit The aircraft.
function FLIGHTCONTROL:SpawnParkingGuard(unit)
if unit and self.parkingGuard then
-- Schedule delay so in MP we get the heading of the client's plane
self:ScheduleOnce(1,FLIGHTCONTROL._SpawnParkingGuard,self,unit)
end end

View File

@ -526,7 +526,7 @@ function TARGET:IsAlive()
for _,_target in pairs(self.targets) do for _,_target in pairs(self.targets) do
local target=_target --Ops.Target#TARGET.Object local target=_target --Ops.Target#TARGET.Object
if target.Status==TARGET.ObjectStatus.ALIVE then if target.Status~=TARGET.ObjectStatus.DEAD then
return true return true
end end
end end

File diff suppressed because it is too large Load Diff

View File

@ -160,24 +160,28 @@ do -- Sound File
-- @param #string FileName The name of the sound file, e.g. "Hello World.ogg". -- @param #string FileName The name of the sound file, e.g. "Hello World.ogg".
-- @param #string Path The path of the directory, where the sound file is located. Default is "l10n/DEFAULT/" within the miz file. -- @param #string Path The path of the directory, where the sound file is located. Default is "l10n/DEFAULT/" within the miz file.
-- @param #number Duration Duration in seconds, how long it takes to play the sound file. Default is 3 seconds. -- @param #number Duration Duration in seconds, how long it takes to play the sound file. Default is 3 seconds.
-- @param #bolean UseSrs Set if SRS should be used to play this file. Default is false.
-- @return #SOUNDFILE self -- @return #SOUNDFILE self
function SOUNDFILE:New(FileName, Path, Duration) function SOUNDFILE:New(FileName, Path, Duration, UseSrs)
-- Inherit BASE. -- Inherit BASE.
local self=BASE:Inherit(self, BASE:New()) -- #SOUNDFILE local self=BASE:Inherit(self, BASE:New()) -- #SOUNDFILE
-- Debug info:
self:F( {FileName, Path, Duration, UseSrs} )
-- Set file name. -- Set file name.
self:SetFileName(FileName) self:SetFileName(FileName)
-- Set if SRS should be used to play this file
self:SetPlayWithSRS(UseSrs or false)
-- Set path. -- Set path.
self:SetPath(Path) self:SetPath(Path)
-- Set duration. -- Set duration.
self:SetDuration(Duration) self:SetDuration(Duration)
-- Debug info:
self:T(string.format("New SOUNDFILE: file name=%s, path=%s", self.filename, self.path))
return self return self
end end
@ -186,12 +190,17 @@ do -- Sound File
-- @param #string Path Path to the directory, where the sound file is located. In case this is nil, it defaults to the DCS mission temp directory. -- @param #string Path Path to the directory, where the sound file is located. In case this is nil, it defaults to the DCS mission temp directory.
-- @return #SOUNDFILE self -- @return #SOUNDFILE self
function SOUNDFILE:SetPath(Path) function SOUNDFILE:SetPath(Path)
self:F( {Path} )
-- Init path. -- Init path.
self.path=Path or "l10n/DEFAULT/" if not Path then
if self.useSRS then -- use path to mission temp dir
if not Path and self.useSRS then -- use path to mission temp dir self.path = lfs.tempdir() .. "Mission\\l10n\\DEFAULT"
self.path = os.getenv('TMP') .. "\\DCS\\Mission\\l10n\\DEFAULT" else -- use internal path in miz file
self.path="l10n/DEFAULT/"
end
else
self.path = Path
end end
-- Remove (back)slashes. -- Remove (back)slashes.
@ -204,6 +213,8 @@ do -- Sound File
-- Append slash. -- Append slash.
self.path=self.path.."/" self.path=self.path.."/"
self:T("self.path=".. self.path)
return self return self
end end
@ -264,11 +275,13 @@ do -- Sound File
-- @param #boolean Switch If true or nil, use SRS. If false, use DCS transmission. -- @param #boolean Switch If true or nil, use SRS. If false, use DCS transmission.
-- @return #SOUNDFILE self -- @return #SOUNDFILE self
function SOUNDFILE:SetPlayWithSRS(Switch) function SOUNDFILE:SetPlayWithSRS(Switch)
self:F( {Switch} )
if Switch==true or Switch==nil then if Switch==true or Switch==nil then
self.useSRS=true self.useSRS=true
else else
self.useSRS=false self.useSRS=false
end end
self:T("self.useSRS=".. tostring(self.useSRS))
return self return self
end end

View File

@ -523,6 +523,7 @@ ENUMS.ReportingName =
Hawkeye = "E-2D", Hawkeye = "E-2D",
Sentry = "E-3A", Sentry = "E-3A",
Stratotanker = "KC-135", Stratotanker = "KC-135",
Gasstation = "KC-135MPRS",
Extender = "KC-10", Extender = "KC-10",
Orion = "P-3C", Orion = "P-3C",
Viking = "S-3B", Viking = "S-3B",

View File

@ -1064,9 +1064,9 @@ function UTILS.BeaufortScale(speed)
return bn,bd return bn,bd
end end
--- Split string at seperators. C.f. [split-string-in-lua](http://stackoverflow.com/questions/1426954/split-string-in-lua). --- Split string at separators. C.f. [split-string-in-lua](http://stackoverflow.com/questions/1426954/split-string-in-lua).
-- @param #string str Sting to split. -- @param #string str Sting to split.
-- @param #string sep Speparator for split. -- @param #string sep Separator for split.
-- @return #table Split text. -- @return #table Split text.
function UTILS.Split(str, sep) function UTILS.Split(str, sep)
local result = {} local result = {}
@ -2146,17 +2146,17 @@ function UTILS.IsLoadingDoorOpen( unit_name )
return true return true
end end
if string.find(type_name, "Bell-47") then -- bell aint got no doors so always ready to load injured soldiers if type_name == "Bell-47" then -- bell aint got no doors so always ready to load injured soldiers
BASE:T(unit_name .. " door is open") BASE:T(unit_name .. " door is open")
return true return true
end end
if string.find(type_name, "UH-60L") and (unit:getDrawArgumentValue(401) == 1 or unit:getDrawArgumentValue(402) == 1) then if type_name == "UH-60L" and (unit:getDrawArgumentValue(401) == 1 or unit:getDrawArgumentValue(402) == 1) then
BASE:T(unit_name .. " cargo door is open") BASE:T(unit_name .. " cargo door is open")
return true return true
end end
if string.find(type_name, "UH-60L" ) and (unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(400) == 1 ) then if type_name == "UH-60L" and (unit:getDrawArgumentValue(38) > 0 or unit:getDrawArgumentValue(400) == 1 ) then
BASE:T(unit_name .. " front door(s) are open") BASE:T(unit_name .. " front door(s) are open")
return true return true
end end

View File

@ -2937,7 +2937,7 @@ function CONTROLLABLE:CopyRoute( Begin, End, Randomize, Radius )
end end
--- Return the detected targets of the controllable. --- Return the detected targets of the controllable.
-- The optional parametes specify the detection methods that can be applied. -- The optional parameters specify the detection methods that can be applied.
-- If no detection method is given, the detection will use all the available methods by default. -- If no detection method is given, the detection will use all the available methods by default.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @param #boolean DetectVisual (optional) -- @param #boolean DetectVisual (optional)
@ -3772,54 +3772,66 @@ function CONTROLLABLE:OptionProhibitAfterburner( Prohibit )
return self return self
end end
--- Defines the usage of Electronic Counter Measures by airborne forces. Disables the ability for AI to use their ECM. --- [Air] Defines the usage of Electronic Counter Measures by airborne forces.
-- @param #CONTROLLABLE self
-- @param #number ECMvalue Can be - 0=Never on, 1=if locked by radar, 2=if detected by radar, 3=always on, defaults to 1
-- @return #CONTROLLABLE self
function CONTROLLABLE:OptionECM( ECMvalue )
self:F2( { self.ControllableName } )
local DCSControllable = self:GetDCSObject()
if DCSControllable then
local Controller = self:_GetController()
if self:IsAir() then
Controller:setOption( AI.Option.Air.id.ECM_USING, ECMvalue or 1 )
end
end
return self
end
--- [Air] Defines the usage of Electronic Counter Measures by airborne forces. Disables the ability for AI to use their ECM.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @return #CONTROLLABLE self -- @return #CONTROLLABLE self
function CONTROLLABLE:OptionECM_Never() function CONTROLLABLE:OptionECM_Never()
self:F2( { self.ControllableName } ) self:F2( { self.ControllableName } )
if self:IsAir() then self:OptionECM(0)
self:SetOption( AI.Option.Air.id.ECM_USING, 0 )
end
return self return self
end end
--- Defines the usage of Electronic Counter Measures by airborne forces. If the AI is actively being locked by an enemy radar they will enable their ECM jammer. --- [Air] Defines the usage of Electronic Counter Measures by airborne forces. If the AI is actively being locked by an enemy radar they will enable their ECM jammer.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @return #CONTROLLABLE self -- @return #CONTROLLABLE self
function CONTROLLABLE:OptionECM_OnlyLockByRadar() function CONTROLLABLE:OptionECM_OnlyLockByRadar()
self:F2( { self.ControllableName } ) self:F2( { self.ControllableName } )
if self:IsAir() then self:OptionECM(1)
self:SetOption( AI.Option.Air.id.ECM_USING, 1 )
end
return self return self
end end
--- Defines the usage of Electronic Counter Measures by airborne forces. If the AI is being detected by a radar they will enable their ECM. --- [Air] Defines the usage of Electronic Counter Measures by airborne forces. If the AI is being detected by a radar they will enable their ECM.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @return #CONTROLLABLE self -- @return #CONTROLLABLE self
function CONTROLLABLE:OptionECM_DetectedLockByRadar() function CONTROLLABLE:OptionECM_DetectedLockByRadar()
self:F2( { self.ControllableName } ) self:F2( { self.ControllableName } )
if self:IsAir() then self:OptionECM(2)
self:SetOption( AI.Option.Air.id.ECM_USING, 2 )
end
return self return self
end end
--- Defines the usage of Electronic Counter Measures by airborne forces. AI will leave their ECM on all the time. --- [Air] Defines the usage of Electronic Counter Measures by airborne forces. AI will leave their ECM on all the time.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @return #CONTROLLABLE self -- @return #CONTROLLABLE self
function CONTROLLABLE:OptionECM_AlwaysOn() function CONTROLLABLE:OptionECM_AlwaysOn()
self:F2( { self.ControllableName } ) self:F2( { self.ControllableName } )
if self:IsAir() then self:OptionECM(3)
self:SetOption( AI.Option.Air.id.ECM_USING, 3 )
end
return self return self
end end
@ -4013,14 +4025,22 @@ end
-- @param #boolean onroad If true, route on road (less problems with AI way finding), default true -- @param #boolean onroad If true, route on road (less problems with AI way finding), default true
-- @param #boolean shortcut If true and onroad is set, take a shorter route - if available - off road, default false -- @param #boolean shortcut If true and onroad is set, take a shorter route - if available - off road, default false
-- @param #string formation Formation string as in the mission editor, e.g. "Vee", "Diamond", "Line abreast", etc. Defaults to "Off Road" -- @param #string formation Formation string as in the mission editor, e.g. "Vee", "Diamond", "Line abreast", etc. Defaults to "Off Road"
-- @param #boolean onland (optional) If true, try up to 50 times to get a coordinate on land.SurfaceType.LAND. Note - this descriptor value is not reliably implemented on all maps.
-- @return #CONTROLLABLE self -- @return #CONTROLLABLE self
function CONTROLLABLE:RelocateGroundRandomInRadius( speed, radius, onroad, shortcut, formation ) function CONTROLLABLE:RelocateGroundRandomInRadius( speed, radius, onroad, shortcut, formation, onland )
self:F2( { self.ControllableName } ) self:F2( { self.ControllableName } )
local _coord = self:GetCoordinate() local _coord = self:GetCoordinate()
local _radius = radius or 500 local _radius = radius or 500
local _speed = speed or 20 local _speed = speed or 20
local _tocoord = _coord:GetRandomCoordinateInRadius( _radius, 100 ) local _tocoord = _coord:GetRandomCoordinateInRadius( _radius, 100 )
if onland then
for i=1,50 do
local island = _tocoord:GetSurfaceType() == land.SurfaceType.LAND and true or false
if island then break end
_tocoord = _coord:GetRandomCoordinateInRadius( _radius, 100 )
end
end
local _onroad = onroad or true local _onroad = onroad or true
local _grptsk = {} local _grptsk = {}
local _candoroad = false local _candoroad = false

View File

@ -302,7 +302,7 @@ end
--- Find the first(!) GROUP matching using patterns. Note that this is **a lot** slower than `:FindByName()`! --- Find the first(!) GROUP matching using patterns. Note that this is **a lot** slower than `:FindByName()`!
-- @param #GROUP self -- @param #GROUP self
-- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_(Regular_Expressions)) for regular expressions in LUA. -- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_\(Regular_Expressions\)) for regular expressions in LUA.
-- @return #GROUP The GROUP. -- @return #GROUP The GROUP.
-- @usage -- @usage
-- -- Find a group with a partial group name -- -- Find a group with a partial group name
@ -327,7 +327,7 @@ end
--- Find all GROUP objects matching using patterns. Note that this is **a lot** slower than `:FindByName()`! --- Find all GROUP objects matching using patterns. Note that this is **a lot** slower than `:FindByName()`!
-- @param #GROUP self -- @param #GROUP self
-- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_(Regular_Expressions)) for regular expressions in LUA. -- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_\(Regular_Expressions\)) for regular expressions in LUA.
-- @return #table Groups Table of matching #GROUP objects found -- @return #table Groups Table of matching #GROUP objects found
-- @usage -- @usage
-- -- Find all group with a partial group name -- -- Find all group with a partial group name
@ -2765,7 +2765,7 @@ end
--- Switch on/off invisible flag for the group. --- Switch on/off invisible flag for the group.
-- @param #GROUP self -- @param #GROUP self
-- @param #boolean switch If true, emission is enabled. If false, emission is disabled. -- @param #boolean switch If true, Invisible is enabled. If false, Invisible is disabled.
-- @return #GROUP self -- @return #GROUP self
function GROUP:SetCommandInvisible(switch) function GROUP:SetCommandInvisible(switch)
self:F2( self.GroupName ) self:F2( self.GroupName )
@ -2779,7 +2779,7 @@ end
--- Switch on/off immortal flag for the group. --- Switch on/off immortal flag for the group.
-- @param #GROUP self -- @param #GROUP self
-- @param #boolean switch If true, emission is enabled. If false, emission is disabled. -- @param #boolean switch If true, Immortal is enabled. If false, Immortal is disabled.
-- @return #GROUP self -- @return #GROUP self
function GROUP:SetCommandImmortal(switch) function GROUP:SetCommandImmortal(switch)
self:F2( self.GroupName ) self:F2( self.GroupName )
@ -2985,3 +2985,36 @@ function GROUP:GetGroupSTN()
return tSTN,text return tSTN,text
end end
--- [GROUND] Determine if a GROUP is a SAM unit, i.e. has radar or optical tracker and is no mobile AAA.
-- @param #GROUP self
-- @return #boolean IsSAM True if SAM, else false
function GROUP:IsSAM()
local issam = false
local units = self:GetUnits()
for _,_unit in pairs(units or {}) do
local unit = _unit -- Wrapper.Unit#UNIT
if unit:HasSEAD() and unit:IsGround() and (not unit:HasAttribute("Mobile AAA")) then
issam = true
break
end
end
return issam
end
--- [GROUND] Determine if a GROUP has a AAA unit, i.e. has no radar or optical tracker but the AAA = true or the "Mobile AAA" = true attribute.
-- @param #GROUP self
-- @return #boolean IsSAM True if AAA, else false
function GROUP:IsAAA()
local issam = false
local units = self:GetUnits()
for _,_unit in pairs(units or {}) do
local unit = _unit -- Wrapper.Unit#UNIT
local desc = unit:GetDesc() or {}
local attr = desc.attributes or {}
if unit:HasSEAD() then return false end
if attr["AAA"] or attr["SAM related"] then
issam = true
end
end
return issam
end

View File

@ -164,7 +164,7 @@ end
--- Find the first(!) UNIT matching using patterns. Note that this is **a lot** slower than `:FindByName()`! --- Find the first(!) UNIT matching using patterns. Note that this is **a lot** slower than `:FindByName()`!
-- @param #UNIT self -- @param #UNIT self
-- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_(Regular_Expressions)) for regular expressions in LUA. -- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_\(Regular_Expressions\)) for regular expressions in LUA.
-- @return #UNIT The UNIT. -- @return #UNIT The UNIT.
-- @usage -- @usage
-- -- Find a group with a partial group name -- -- Find a group with a partial group name
@ -189,7 +189,7 @@ end
--- Find all UNIT objects matching using patterns. Note that this is **a lot** slower than `:FindByName()`! --- Find all UNIT objects matching using patterns. Note that this is **a lot** slower than `:FindByName()`!
-- @param #UNIT self -- @param #UNIT self
-- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_(Regular_Expressions)) for regular expressions in LUA. -- @param #string Pattern The pattern to look for. Refer to [LUA patterns](http://www.easyuo.com/openeuo/wiki/index.php/Lua_Patterns_and_Captures_\(Regular_Expressions\)) for regular expressions in LUA.
-- @return #table Units Table of matching #UNIT objects found -- @return #table Units Table of matching #UNIT objects found
-- @usage -- @usage
-- -- Find all group with a partial group name -- -- Find all group with a partial group name

View File

@ -83,6 +83,7 @@ Functional/Autolase.lua
Functional/AICSAR.lua Functional/AICSAR.lua
Functional/AmmoTruck.lua Functional/AmmoTruck.lua
Functional/ZoneGoalCargo.lua Functional/ZoneGoalCargo.lua
Functional/Tiresias.lua
Ops/Airboss.lua Ops/Airboss.lua
Ops/RecoveryTanker.lua Ops/RecoveryTanker.lua

View File

@ -0,0 +1,77 @@
---
parent: Beginner
nav_order: 06
---
# How to ask for help
{: .no_toc }
1. Table of contents
{:toc}
After you have tried to solve the problem on your own, you can also get help
from the community.
{: .highlight }
> But it is important to follow certain rules! Read them below.
## Communities
There are two ways to communicate with the community.
The fastest way is to use Discord:
- <https://discord.gg/gj68fm969S>{:target="_blank"}
But if you don't like Discord, you are able to post in the DCS forum.
Check out the MOOSE thread here:
- <https://forums.eagle.ru/showthread.php?t=138043>
## How to post requests
MOOSE is a community project and support is community based.
Please remember when posting a question:
- Before posting anything follow the [troubleshooting steps].
- **Read your logs**.
A post should contain the following:
1. A describtion what you expected to happen and what actually happened.
- Do not use vague words this stuff is hard to help with! Be specific.
2. Describe what happens instead.
- The less detail you offer, the less chance you can be helped.
- Dont say it doesnt work. Or is it broken. Say what it actually does.
3. Post your code in Discord as formatted code:
- Wrap a single line of code in backticks \` like this:
![discord-single-line-code.png](../images/beginner/discord-single-line-code.png)
- Multiple lines of code should be posted like this:
![discord-multi-line-code.png](../images/beginner/discord-multi-line-code.png)
- Post your log lines with the error or warning messages. Format them like this:
![discord-fomat-logs.png](../images/beginner/discord-fomat-logs.png)
- Some complex problems need the mission (.miz file) also.
- But post your mission only when requested.
- Try to simplify your mission if it is complex!
There are people in the Discord and in the forum, who spend their free time to
help you. <br />
It is your responsibility to make their "work" as easy as possible.
Welcome to MOOSE and good luck!
## Next step
Last but not least some [tipps and tricks].
[troubleshooting steps]: problems.md
[tipps and tricks]: tipps-and-tricks.md

View File

@ -9,5 +9,50 @@ nav_order: 04
1. Table of contents 1. Table of contents
{:toc} {:toc}
{: .warning } The best way to get comfortable with a Moose class is to try the demo missions
> THIS DOCUMENT IS STILL WORK IN PROGRESS! of the class you want to learn. The Moose team created a lot of demo missions
for most of the classes.
## Download demo missions
Go to the repository [MOOSE_MISSIONS]{:target="_blank"}, search the folder of
the class, download the mission (`.miz`) and run them.
## Read the mission script
In the same folder a `.lua` file with the same name is placed which is the
included mission script. You can watch these mission scripts easily online at
GitHub to understand what is happening in the mission.
## Read documentation
Next step is to read the [documentation]{:target="_blank"} of the class to
understand the code of the demo mission.
{: .note }
> The documentation is quite long and might be confusing for beginners.
> Start by looking at the description at the top of the documentation of a
> class. It often contains examples and explanations. <br /><br />
> Then search for the function names and look at the description of the
> functions and its parameters.
## Make small changes to the script
Download the `.lua` file, change the parameters to suit your needs in
[Notepad++]{:target="_blank"}, add it to the mission and rerun the mission.
Observe what happens and adapt the code.
If you want to use more functions combine them all up.
{: .note }
> But it is wise to do this in small steps. So it is easier to find errors.
## Next step
If the mission does not show the expected behaviour take a look at section
[problems].
[MOOSE_MISSIONS]: https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop
[documentation]: https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/index.html
[Notepad++]: https://notepad-plus-plus.org/downloads/
[problems]: problems.md

View File

@ -144,9 +144,16 @@ have create everything on your own.
- Change the text a little bit, like `Hello Dude! ...` and save the file. - Change the text a little bit, like `Hello Dude! ...` and save the file.
- Run the mission again. - Run the mission again.
- The text will not be changed in the mission. Why? - The text will not be changed in the mission. Why?
The mission editor copies the script into the mission file when you add it.
Ever change on the script file on your hard disk is not recognized by mission editor. {: .important }
You have to add the file after each change again. The mission editor copies the script into the mission file when you add it.
Every change on the script file on your hard disk is not recognized by mission
editor. **You have to add the file after each change again!**
There is also another method available to dynamically load mission scripts.
But this method has some brawbacks and will be explained in the advanced section.
Now we add the mission script again:
- On the left side of the `TRIGGERS` dialog click on `Load Mission Script`. - On the left side of the `TRIGGERS` dialog click on `Load Mission Script`.
- On the right side under `ACTIONS` you need to add the script again: - On the right side under `ACTIONS` you need to add the script again:

46
docs/beginner/problems.md Normal file
View File

@ -0,0 +1,46 @@
---
parent: Beginner
nav_order: 05
---
# Problems
{: .no_toc }
1. Table of contents
{:toc}
## Something went wrong
If the mission shows not the expected behaviour do the following steps:
1. Double check if you added the changed mission script to the mission again!
1. Check if the triggers are configured as requested in the last sections.
## Read the logs
The DCS log is a super important and useful log for the entire of DCS World.
All scripting and other errors are recorded here. It is the one stop shop for
things that occurred in your mission. It will tell you if there was a mistake.
1. Open the file `dcs.log` in the `Logs` subfolder in your DCS
[Saved Games folder].
1. Search for the following line: `*** MOOSE INCLUDE END ***`
- If it is included in the log, Moose was loaded.
- If the line is not in the log check the triggers again!
1. Search for lines with `SCRIPTING` and `WARNING` or `ERROR` and read them.
- This might help to find your error.
{: .note }
> You will find a lot of warning and error lines in the log which are not
> related to `SCRIPTING`. They are related to stuff from Eagle Dynamics or
> Third Parties and you have to ignore them. EA does the same. ;o)
## Next step
If you don't find the error and/or don't understand the messages in the log file
you can [ask for help].
[Saved Games folder]: tipps-and-tricks.md#find-the-saved-games-folder
[ask for help]: ask-for-help.md

View File

@ -33,7 +33,9 @@ This folder can be found in your userprofile as subfolder of `Saved Games`.
The easiest way to find it, is to open search and paste the text below into it The easiest way to find it, is to open search and paste the text below into it
and press Enter: and press Enter:
```%userprofile%\Saved Games``` ```
%userprofile%\Saved Games
```
{: .note } {: .note }
> The text will work even if your Windows is installed with another language, > The text will work even if your Windows is installed with another language,

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -26,14 +26,30 @@ You only need to load **one** of those files at the beginning of your mission.
This repository contains the generated documentation and pictures and other references. This repository contains the generated documentation and pictures and other references.
The generated documentation is reflected in html and is published at: The generated documentation is reflected in html and is published at:
- Stable `master` branch: <https://flightcontrol-master.github.io/MOOSE_DOCS/> - `master` branch: <https://flightcontrol-master.github.io/MOOSE_DOCS/>
- `develop` branch: <https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/> - `develop` branch: <https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/>
## [MOOSE_GUIDES](https://github.com/FlightControl-Master/MOOSE_GUIDES) - For external documentation and help
This repository will be removed in future.
## [MOOSE_PRESENTATIONS](https://github.com/FlightControl-Master/MOOSE_PRESENTATIONS)
A collection of presentations used in the videos on the youtube channel of FlightControl.
## [MOOSE_MISSIONS](https://github.com/FlightControl-Master/MOOSE_MISSIONS) - For users (provides demo missions) ## [MOOSE_MISSIONS](https://github.com/FlightControl-Master/MOOSE_MISSIONS) - For users (provides demo missions)
This repository contains all the demonstration missions in packed format (*.miz), This repository contains all the demonstration missions in packed format (*.miz),
and can be used without any further setup in DCS WORLD. and can be used without any further setup in DCS WORLD.
## [Moose_Community_Scripts](https://github.com/FlightControl-Master/Moose_Community_Scripts)
This repository is for Moose based helper scripts, snippets, functional demos.
## [MOOSE_SOUND](https://github.com/FlightControl-Master/MOOSE_SOUND)
Sound packs for different MOOSE framework classes.
## [MOOSE_MISSIONS_DYNAMIC](https://github.com/FlightControl-Master/MOOSE_MISSIONS_DYNAMIC) - Outdated ## [MOOSE_MISSIONS_DYNAMIC](https://github.com/FlightControl-Master/MOOSE_MISSIONS_DYNAMIC) - Outdated
This repository will be removed in future. This repository will be removed in future.
@ -41,3 +57,11 @@ This repository will be removed in future.
## [MOOSE_MISSIONS_UNPACKED](https://github.com/FlightControl-Master/MOOSE_MISSIONS_UNPACKED) - Outdated ## [MOOSE_MISSIONS_UNPACKED](https://github.com/FlightControl-Master/MOOSE_MISSIONS_UNPACKED) - Outdated
This repository will be removed in future. This repository will be removed in future.
## [MOOSE_COMMUNITY_MISSIONS](https://github.com/FlightControl-Master/MOOSE_COMMUNITY_MISSIONS) - Outdated
A database of missions created by the community, using MOOSE.
## [MOOSE_TOOLS](https://github.com/FlightControl-Master/MOOSE_TOOLS) - Outdated
A collection of the required tools to develop and contribute in the MOOSE framework for DCS World.