diff --git a/Moose Development/Moose/AI/AI_Air.lua b/Moose Development/Moose/AI/AI_Air.lua index 6c8c9579c..3c0724585 100644 --- a/Moose Development/Moose/AI/AI_Air.lua +++ b/Moose Development/Moose/AI/AI_Air.lua @@ -585,7 +585,7 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To ) if AIGroup and AIGroup:IsAlive() then - self:I( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" ) + self:T( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" ) self:ClearTargetDistance() --AIGroup:ClearTasks() diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index adf56da93..679ba9820 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -20,9 +20,9 @@ -- Various types of SET_ classes are available: -- -- * @{#SET_GROUP}: Defines a collection of @{Wrapper.Group}s filtered by filter criteria. --- * @{#SET_UNIT}: Defines a colleciton of @{Wrapper.Unit}s filtered by filter criteria. +-- * @{#SET_UNIT}: Defines a collection of @{Wrapper.Unit}s filtered by filter criteria. -- * @{#SET_STATIC}: Defines a collection of @{Wrapper.Static}s filtered by filter criteria. --- * @{#SET_CLIENT}: Defines a collection of @{Client}s filterd by filter criteria. +-- * @{#SET_CLIENT}: Defines a collection of @{Client}s filtered by filter criteria. -- * @{#SET_AIRBASE}: Defines a collection of @{Wrapper.Airbase}s filtered by filter criteria. -- * @{#SET_CARGO}: Defines a collection of @{Cargo.Cargo}s filtered by filter criteria. -- * @{#SET_ZONE}: Defines a collection of @{Core.Zone}s filtered by filter criteria. @@ -50,14 +50,14 @@ do -- SET_BASE --- @type SET_BASE -- @field #table Filter Table of filters. -- @field #table Set Table of objects. - -- @field #table Index Table of indicies. + -- @field #table Index Table of indices. -- @field #table List Unused table. -- @field Core.Scheduler#SCHEDULER CallScheduler -- @extends Core.Base#BASE --- The @{Core.Set#SET_BASE} class defines the core functions that define a collection of objects. - -- A SET provides iterators to iterate the SET, but will **temporarily** yield the ForEach interator loop at defined **"intervals"** to the mail simulator loop. + -- A SET provides iterators to iterate the SET, but will **temporarily** yield the ForEach iterator loop at defined **"intervals"** to the mail simulator loop. -- In this way, large loops can be done while not blocking the simulator main processing loop. -- The default **"yield interval"** is after 10 objects processed. -- The default **"time interval"** is after 0.001 seconds. @@ -68,7 +68,7 @@ do -- SET_BASE -- -- ## Define the SET iterator **"yield interval"** and the **"time interval"** -- - -- Modify the iterator intervals with the @{Core.Set#SET_BASE.SetInteratorIntervals} method. + -- Modify the iterator intervals with the @{Core.Set#SET_BASE.SetIteratorIntervals} method. -- You can set the **"yield interval"**, and the **"time interval"**. (See above). -- -- @field #SET_BASE SET_BASE @@ -787,7 +787,7 @@ do -- SET_BASE end - ----- Iterate the SET_BASE and call an interator function for each **alive** unit, providing the Unit and optional parameters. + ----- Iterate the SET_BASE and call an iterator function for each **alive** unit, providing the Unit and optional parameters. ---- @param #SET_BASE self ---- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET_BASE. The function needs to accept a UNIT parameter. ---- @return #SET_BASE self @@ -799,7 +799,7 @@ do -- SET_BASE -- return self --end -- - ----- Iterate the SET_BASE and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. + ----- Iterate the SET_BASE and call an iterator function for each **alive** player, providing the Unit of the player and optional parameters. ---- @param #SET_BASE self ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a UNIT parameter. ---- @return #SET_BASE self @@ -812,7 +812,7 @@ do -- SET_BASE --end -- -- - ----- Iterate the SET_BASE and call an interator function for each client, providing the Client to the function and optional parameters. + ----- Iterate the SET_BASE and call an iterator function for each client, providing the Client to the function and optional parameters. ---- @param #SET_BASE self ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a CLIENT parameter. ---- @return #SET_BASE self @@ -919,17 +919,13 @@ do -- SET_GROUP -- * @{#SET_GROUP.FilterCategoryGround}: Builds the SET_GROUP from ground vehicles or infantry. -- * @{#SET_GROUP.FilterCategoryShip}: Builds the SET_GROUP from ships. -- * @{#SET_GROUP.FilterCategoryStructure}: Builds the SET_GROUP from structures. - -- + -- * @{#SET_GROUP.FilterZones}: Builds the SET_GROUP with the groups within a @{Core.Zone#ZONE}. -- -- Once the filter criteria have been set for the SET_GROUP, you can start filtering using: -- -- * @{#SET_GROUP.FilterStart}: Starts the filtering of the groups within the SET_GROUP and add or remove GROUP objects **dynamically**. -- * @{#SET_GROUP.FilterOnce}: Filters of the groups **once**. -- - -- Planned filter criteria within development are (so these are not yet available): - -- - -- * @{#SET_GROUP.FilterZones}: Builds the SET_GROUP with the groups within a @{Core.Zone#ZONE}. - -- -- ## SET_GROUP iterators -- -- Once the filters have been defined and the SET_GROUP has been built, you can iterate the SET_GROUP with the available iterator methods. @@ -949,7 +945,7 @@ do -- SET_GROUP -- ### When a GROUP object crashes or is dead, the SET_GROUP will trigger a **Dead** event. -- -- You can handle the event using the OnBefore and OnAfter event handlers. - -- The event handlers need to have the paramters From, Event, To, GroupObject. + -- The event handlers need to have the parameters From, Event, To, GroupObject. -- The GroupObject is the GROUP object that is dead and within the SET_GROUP, and is passed as a parameter to the event handler. -- See the following example: -- @@ -964,7 +960,7 @@ do -- SET_GROUP -- end -- -- While this is a good example, there is a catch. - -- Imageine you want to execute the code above, the the self would need to be from the object declared outside (above) the OnAfterDead method. + -- Imagine you want to execute the code above, the the self would need to be from the object declared outside (above) the OnAfterDead method. -- So, the self would need to contain another object. Fortunately, this can be done, but you must use then the **`.`** notation for the method. -- See the modified example: -- @@ -996,6 +992,7 @@ do -- SET_GROUP Categories = nil, Countries = nil, GroupPrefixes = nil, + Zones = nil, }, FilterMeta = { Coalitions = { @@ -1171,6 +1168,30 @@ do -- SET_GROUP end + --- Builds a set of groups in zones. + -- @param #SET_GROUP self + -- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE + -- @return #SET_GROUP self + function SET_GROUP:FilterZones( Zones ) + if not self.Filter.Zones then + self.Filter.Zones = {} + end + local zones = {} + if Zones.ClassName and Zones.ClassName == "SET_ZONE" then + zones = Zones.Set + elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then + self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!") + return self + else + zones = Zones + end + for _,Zone in pairs( zones ) do + local zonename = Zone:GetName() + self.Filter.Zones[zonename] = Zone + end + return self + end + --- Builds a set of groups of coalitions. -- Possible current coalitions are red, blue and neutral. -- @param #SET_GROUP self @@ -1513,7 +1534,7 @@ do -- SET_GROUP --- Iterate the SET_GROUP and return true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE} -- @param #SET_GROUP self -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. - -- @return #boolean true if all the @{Wrapper.Group#GROUP} are completly in the @{Core.Zone#ZONE}, false otherwise + -- @return #boolean true if all the @{Wrapper.Group#GROUP} are completely in the @{Core.Zone#ZONE}, false otherwise -- @usage -- local MyZone = ZONE:New("Zone1") -- local MySetGroup = SET_GROUP:New() @@ -1561,7 +1582,7 @@ do -- SET_GROUP --- Iterate the SET_GROUP and return true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE} -- @param #SET_GROUP self -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. - -- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is completly inside the @{Core.Zone#ZONE}, false otherwise. + -- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is completely inside the @{Core.Zone#ZONE}, false otherwise. -- @usage -- local MyZone = ZONE:New("Zone1") -- local MySetGroup = SET_GROUP:New() @@ -1586,7 +1607,7 @@ do -- SET_GROUP --- Iterate the SET_GROUP and return true if at least one @{#UNIT} of one @{GROUP} of the @{SET_GROUP} is in @{ZONE} -- @param #SET_GROUP self -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. - -- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completly inside the @{Core.Zone#ZONE}, false otherwise. + -- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise. -- @usage -- local MyZone = ZONE:New("Zone1") -- local MySetGroup = SET_GROUP:New() @@ -1612,7 +1633,7 @@ do -- SET_GROUP -- Will return false if a @{GROUP} is fully in the @{ZONE} -- @param #SET_GROUP self -- @param Core.Zone#ZONE ZoneObject The Zone to be tested for. - -- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completly inside the @{Core.Zone#ZONE}, false otherwise. + -- @return #boolean true if at least one of the @{Wrapper.Group#GROUP} is partly or completely inside the @{Core.Zone#ZONE}, false otherwise. -- @usage -- local MyZone = ZONE:New("Zone1") -- local MySetGroup = SET_GROUP:New() @@ -1742,7 +1763,7 @@ do -- SET_GROUP return CountG,CountU end - ----- Iterate the SET_GROUP and call an interator function for each **alive** player, providing the Group of the player and optional parameters. + ----- Iterate the SET_GROUP and call an iterator function for each **alive** player, providing the Group of the player and optional parameters. ---- @param #SET_GROUP self ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a GROUP parameter. ---- @return #SET_GROUP self @@ -1755,7 +1776,7 @@ do -- SET_GROUP --end -- -- - ----- Iterate the SET_GROUP and call an interator function for each client, providing the Client to the function and optional parameters. + ----- Iterate the SET_GROUP and call an iterator function for each client, providing the Client to the function and optional parameters. ---- @param #SET_GROUP self ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a CLIENT parameter. ---- @return #SET_GROUP self @@ -1828,7 +1849,18 @@ do -- SET_GROUP end MGroupInclude = MGroupInclude and MGroupPrefix end - + + if self.Filter.Zones then + local MGroupZone = false + for ZoneName, Zone in pairs( self.Filter.Zones ) do + self:T3( "Zone:", ZoneName ) + if MGroup:IsInZone(Zone) then + MGroupZone = true + end + end + MGroupInclude = MGroupInclude and MGroupZone + end + self:T2( MGroupInclude ) return MGroupInclude end @@ -1889,16 +1921,13 @@ do -- SET_UNIT -- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies). -- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units sharing the same string(s) in their name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*. -- * @{#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}. + -- -- Once the filter criteria have been set for the SET_UNIT, you can start filtering using: -- -- * @{#SET_UNIT.FilterStart}: Starts the filtering of the units **dynamically**. -- * @{#SET_UNIT.FilterOnce}: Filters of the units **once**. -- - -- Planned filter criteria within development are (so these are not yet available): - -- - -- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Core.Zone#ZONE}. - -- -- ## 4) SET_UNIT iterators -- -- Once the filters have been defined and the SET_UNIT has been built, you can iterate the SET_UNIT with the available iterator methods. @@ -1928,7 +1957,7 @@ do -- SET_UNIT -- ### 6.1) When a UNIT object crashes or is dead, the SET_UNIT will trigger a **Dead** event. -- -- You can handle the event using the OnBefore and OnAfter event handlers. - -- The event handlers need to have the paramters From, Event, To, GroupObject. + -- The event handlers need to have the parameters From, Event, To, GroupObject. -- The GroupObject is the UNIT object that is dead and within the SET_UNIT, and is passed as a parameter to the event handler. -- See the following example: -- @@ -1943,7 +1972,7 @@ do -- SET_UNIT -- end -- -- While this is a good example, there is a catch. - -- Imageine you want to execute the code above, the the self would need to be from the object declared outside (above) the OnAfterDead method. + -- Imagine you want to execute the code above, the the self would need to be from the object declared outside (above) the OnAfterDead method. -- So, the self would need to contain another object. Fortunately, this can be done, but you must use then the **`.`** notation for the method. -- See the modified example: -- @@ -1975,6 +2004,7 @@ do -- SET_UNIT Types = nil, Countries = nil, UnitPrefixes = nil, + Zones = nil, }, FilterMeta = { Coalitions = { @@ -2166,7 +2196,31 @@ do -- SET_UNIT end return self end - + + --- Builds a set of units in zones. + -- @param #SET_UNIT self + -- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE + -- @return #SET_UNIT self + function SET_UNIT:FilterZones( Zones ) + if not self.Filter.Zones then + self.Filter.Zones = {} + end + local zones = {} + if Zones.ClassName and Zones.ClassName == "SET_ZONE" then + zones = Zones.Set + elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then + self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!") + return self + else + zones = Zones + end + for _,Zone in pairs( zones ) do + local zonename = Zone:GetName() + self.Filter.Zones[zonename] = Zone + end + return self + end + --- Builds a set of units that are only active. -- Only the units that are active will be included within the set. -- @param #SET_UNIT self @@ -2344,7 +2398,7 @@ do -- SET_UNIT end - --- Iterate the SET_UNIT and call an interator function for each **alive** UNIT, providing the UNIT and optional parameters. + --- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters. -- @param #SET_UNIT self -- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter. -- @return #SET_UNIT self @@ -2404,7 +2458,7 @@ do -- SET_UNIT end - --- Iterate the SET_UNIT **sorted *per Threat Level** and call an interator function for each **alive** UNIT, providing the UNIT and optional parameters. + --- Iterate the SET_UNIT **sorted *per Threat Level** and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters. -- -- @param #SET_UNIT self -- @param #number FromThreatLevel The TreatLevel to start the evaluation **From** (this must be a value between 0 and 10). @@ -2800,7 +2854,7 @@ do -- SET_UNIT - ----- Iterate the SET_UNIT and call an interator function for each **alive** player, providing the Unit of the player and optional parameters. + ----- Iterate the SET_UNIT and call an iterator function for each **alive** player, providing the Unit of the player and optional parameters. ---- @param #SET_UNIT self ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter. ---- @return #SET_UNIT self @@ -2813,7 +2867,7 @@ do -- SET_UNIT --end -- -- - ----- Iterate the SET_UNIT and call an interator function for each client, providing the Client to the function and optional parameters. + ----- Iterate the SET_UNIT and call an iterator function for each client, providing the Client to the function and optional parameters. ---- @param #SET_UNIT self ---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a CLIENT parameter. ---- @return #SET_UNIT self @@ -2925,7 +2979,18 @@ do -- SET_UNIT MUnitInclude = MUnitInclude and MUnitSEAD end end - + + if self.Filter.Zones then + local MGroupZone = false + for ZoneName, Zone in pairs( self.Filter.Zones ) do + self:T3( "Zone:", ZoneName ) + if MUnit:IsInZone(Zone) then + MGroupZone = true + end + end + MUnitInclude = MUnitInclude and MGroupZone + end + self:T2( MUnitInclude ) return MUnitInclude end @@ -3008,15 +3073,12 @@ do -- SET_STATIC -- * @{#SET_STATIC.FilterTypes}: Builds the SET_STATIC with the units belonging to the unit type(s). -- * @{#SET_STATIC.FilterCountries}: Builds the SET_STATIC with the units belonging to the country(ies). -- * @{#SET_STATIC.FilterPrefixes}: Builds the SET_STATIC with the units containing the same string(s) in their name. **ATTENTION** bad naming convention as this *does not** only filter *prefixes*. - -- + -- * @{#SET_STATIC.FilterZones}: Builds the SET_STATIC with the units within a @{Core.Zone#ZONE}. + -- -- Once the filter criteria have been set for the SET_STATIC, you can start filtering using: -- -- * @{#SET_STATIC.FilterStart}: Starts the filtering of the units within the SET_STATIC. -- - -- Planned filter criteria within development are (so these are not yet available): - -- - -- * @{#SET_STATIC.FilterZones}: Builds the SET_STATIC with the units within a @{Core.Zone#ZONE}. - -- -- ## SET_STATIC iterators -- -- Once the filters have been defined and the SET_STATIC has been built, you can iterate the SET_STATIC with the available iterator methods. @@ -3024,14 +3086,9 @@ do -- SET_STATIC -- The following iterator methods are currently available within the SET_STATIC: -- -- * @{#SET_STATIC.ForEachStatic}: Calls a function for each alive unit it finds within the SET_STATIC. - -- * @{#SET_GROUP.ForEachGroupCompletelyInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function. - -- * @{#SET_GROUP.ForEachGroupNotInZone}: Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence not in a @{Zone}, providing the GROUP and optional parameters to the called function. - -- - -- Planned iterators methods in development are (so these are not yet available): - -- - -- * @{#SET_STATIC.ForEachStaticInZone}: Calls a function for each unit contained within the SET_STATIC. - -- * @{#SET_STATIC.ForEachStaticCompletelyInZone}: Iterate and call an iterator function for each **alive** STATIC presence completely in a @{Zone}, providing the STATIC and optional parameters to the called function. - -- * @{#SET_STATIC.ForEachStaticNotInZone}: Iterate and call an iterator function for each **alive** STATIC presence not in a @{Zone}, providing the STATIC and optional parameters to the called function. + -- * @{#SET_STATIC.ForEachStaticCompletelyInZone}: Iterate the SET_STATIC and call an iterator function for each **alive** STATIC presence completely in a @{Zone}, providing the STATIC and optional parameters to the called function. + -- * @{#SET_STATIC.ForEachStaticInZone}: Iterate the SET_STATIC and call an iterator function for each **alive** STATIC presence completely in a @{Zone}, providing the STATIC and optional parameters to the called function. + -- * @{#SET_STATIC.ForEachStaticNotInZone}: Iterate the SET_STATIC and call an iterator function for each **alive** STATIC presence not in a @{Zone}, providing the STATIC and optional parameters to the called function. -- -- ## SET_STATIC atomic methods -- @@ -3050,6 +3107,7 @@ do -- SET_STATIC Types = nil, Countries = nil, StaticPrefixes = nil, + Zones = nil, }, FilterMeta = { Coalitions = { @@ -3161,7 +3219,31 @@ do -- SET_STATIC end return self end - + + + --- Builds a set of statics in zones. + -- @param #SET_STATIC self + -- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE + -- @return #SET_STATIC self + function SET_STATIC:FilterZones( Zones ) + if not self.Filter.Zones then + self.Filter.Zones = {} + end + local zones = {} + if Zones.ClassName and Zones.ClassName == "SET_ZONE" then + zones = Zones.Set + elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then + self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!") + return self + else + zones = Zones + end + for _,Zone in pairs( zones ) do + local zonename = Zone:GetName() + self.Filter.Zones[zonename] = Zone + end + return self + end --- Builds a set of units out of categories. -- Possible current categories are plane, helicopter, ground, ship. @@ -3371,7 +3453,7 @@ do -- SET_STATIC end - --- Iterate the SET_STATIC and call an interator function for each **alive** STATIC, providing the STATIC and optional parameters. + --- Iterate the SET_STATIC and call an iterator function for each **alive** STATIC, providing the STATIC and optional parameters. -- @param #SET_STATIC self -- @param #function IteratorFunction The function that will be called when there is an alive STATIC in the SET_STATIC. The function needs to accept a STATIC parameter. -- @return #SET_STATIC self @@ -3650,7 +3732,18 @@ do -- SET_STATIC end MStaticInclude = MStaticInclude and MStaticPrefix end - + + if self.Filter.Zones then + local MStaticZone = false + for ZoneName, Zone in pairs( self.Filter.Zones ) do + self:T3( "Zone:", ZoneName ) + if MStatic and MStatic:IsInZone(Zone) then + MStaticZone = true + end + end + MStaticInclude = MStaticInclude and MStaticZone + end + self:T2( MStaticInclude ) return MStaticInclude end @@ -3721,16 +3814,13 @@ do -- SET_CLIENT -- * @{#SET_CLIENT.FilterCountries}: Builds the SET_CLIENT with the clients belonging to the country(ies). -- * @{#SET_CLIENT.FilterPrefixes}: Builds the SET_CLIENT with the clients containing the same string(s) in their unit/pilot name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*. -- * @{#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}. + -- -- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using: -- -- * @{#SET_CLIENT.FilterStart}: Starts the filtering of the clients **dynamically**. -- * @{#SET_CLIENT.FilterOnce}: Filters the clients **once**. -- - -- Planned filter criteria within development are (so these are not yet available): - -- - -- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Core.Zone#ZONE}. - -- -- ## 4) SET_CLIENT iterators -- -- Once the filters have been defined and the SET_CLIENT has been built, you can iterate the SET_CLIENT with the available iterator methods. @@ -3750,6 +3840,7 @@ do -- SET_CLIENT Types = nil, Countries = nil, ClientPrefixes = nil, + Zones = nil, }, FilterMeta = { Coalitions = { @@ -3946,7 +4037,29 @@ do -- SET_CLIENT return self end - + --- Builds a set of clients in zones. + -- @param #SET_CLIENT self + -- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE + -- @return #SET_TABLE self + function SET_CLIENT:FilterZones( Zones ) + if not self.Filter.Zones then + self.Filter.Zones = {} + end + local zones = {} + if Zones.ClassName and Zones.ClassName == "SET_ZONE" then + zones = Zones.Set + elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then + self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!") + return self + else + zones = Zones + end + for _,Zone in pairs( zones ) do + local zonename = Zone:GetName() + self.Filter.Zones[zonename] = Zone + end + return self + end --- Starts the filtering. -- @param #SET_CLIENT self @@ -3987,7 +4100,7 @@ do -- SET_CLIENT return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] end - --- Iterate the SET_CLIENT and call an interator function for each **alive** CLIENT, providing the CLIENT and optional parameters. + --- Iterate the SET_CLIENT and call an iterator function for each **alive** CLIENT, providing the CLIENT and optional parameters. -- @param #SET_CLIENT self -- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_CLIENT. The function needs to accept a CLIENT parameter. -- @return #SET_CLIENT self @@ -4145,6 +4258,18 @@ do -- SET_CLIENT end end + if self.Filter.Zones then + local MClientZone = false + for ZoneName, Zone in pairs( self.Filter.Zones ) do + self:T3( "Zone:", ZoneName ) + local unit = MClient:GetClientGroupUnit() + if unit and unit:IsInZone(Zone) then + MClientZone = true + end + end + MClientInclude = MClientInclude and MClientZone + end + self:T2( MClientInclude ) return MClientInclude end @@ -4205,6 +4330,7 @@ do -- SET_PLAYER Types = nil, Countries = nil, ClientPrefixes = nil, + Zones = nil, }, FilterMeta = { Coalitions = { @@ -4296,7 +4422,31 @@ do -- SET_PLAYER end return self end - + + --- Builds a set of players in zones. + -- @param #SET_PLAYER self + -- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE + -- @return #SET_PLAYER self + function SET_PLAYER:FilterZones( Zones ) + if not self.Filter.Zones then + self.Filter.Zones = {} + end + local zones = {} + if Zones.ClassName and Zones.ClassName == "SET_ZONE" then + zones = Zones.Set + elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then + self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!") + return self + else + zones = Zones + end + for _,Zone in pairs( zones ) do + local zonename = Zone:GetName() + self.Filter.Zones[zonename] = Zone + end + return self + end + --- Builds a set of clients out of categories joined by players. -- Possible current categories are plane, helicopter, ground, ship. @@ -4415,7 +4565,7 @@ do -- SET_PLAYER return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] end - --- Iterate the SET_PLAYER and call an interator function for each **alive** CLIENT, providing the CLIENT and optional parameters. + --- Iterate the SET_PLAYER and call an iterator function for each **alive** CLIENT, providing the CLIENT and optional parameters. -- @param #SET_PLAYER self -- @param #function IteratorFunction The function that will be called when there is an alive CLIENT in the SET_PLAYER. The function needs to accept a CLIENT parameter. -- @return #SET_PLAYER self @@ -4546,7 +4696,19 @@ do -- SET_PLAYER MClientInclude = MClientInclude and MClientPrefix end end - + + if self.Filter.Zones then + local MClientZone = false + for ZoneName, Zone in pairs( self.Filter.Zones ) do + self:T3( "Zone:", ZoneName ) + local unit = MClient:GetClientGroupUnit() + if unit and unit:IsInZone(Zone) then + MClientZone = true + end + end + MClientInclude = MClientInclude and MClientZone + end + self:T2( MClientInclude ) return MClientInclude end @@ -4837,7 +4999,7 @@ do -- SET_AIRBASE return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] end - --- Iterate the SET_AIRBASE and call an interator function for each AIRBASE, providing the AIRBASE and optional parameters. + --- Iterate the SET_AIRBASE and call an iterator function for each AIRBASE, providing the AIRBASE and optional parameters. -- @param #SET_AIRBASE self -- @param #function IteratorFunction The function that will be called when there is an alive AIRBASE in the SET_AIRBASE. The function needs to accept a AIRBASE parameter. -- @return #SET_AIRBASE self @@ -5168,7 +5330,7 @@ do -- SET_CARGO return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] end - --- (R2.1) Iterate the SET_CARGO and call an interator function for each CARGO, providing the CARGO and optional parameters. + --- (R2.1) Iterate the SET_CARGO and call an iterator function for each CARGO, providing the CARGO and optional parameters. -- @param #SET_CARGO self -- @param #function IteratorFunction The function that will be called when there is an alive CARGO in the SET_CARGO. The function needs to accept a CARGO parameter. -- @return #SET_CARGO self @@ -5589,7 +5751,7 @@ do -- SET_ZONE return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] end - --- Iterate the SET_ZONE and call an interator function for each ZONE, providing the ZONE and optional parameters. + --- Iterate the SET_ZONE and call an iterator function for each ZONE, providing the ZONE and optional parameters. -- @param #SET_ZONE self -- @param #function IteratorFunction The function that will be called when there is an alive ZONE in the SET_ZONE. The function needs to accept a AIRBASE parameter. -- @return #SET_ZONE self @@ -5907,7 +6069,7 @@ do -- SET_ZONE_GOAL return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] end - --- Iterate the SET_ZONE_GOAL and call an interator function for each ZONE, providing the ZONE and optional parameters. + --- Iterate the SET_ZONE_GOAL and call an iterator function for each ZONE, providing the ZONE and optional parameters. -- @param #SET_ZONE_GOAL self -- @param #function IteratorFunction The function that will be called when there is an alive ZONE in the SET_ZONE_GOAL. The function needs to accept a AIRBASE parameter. -- @return #SET_ZONE_GOAL self @@ -6077,7 +6239,7 @@ do -- SET_OPSGROUP -- ### When a GROUP object crashes or is dead, the SET_OPSGROUP will trigger a **Dead** event. -- -- You can handle the event using the OnBefore and OnAfter event handlers. - -- The event handlers need to have the paramters From, Event, To, GroupObject. + -- The event handlers need to have the parameters From, Event, To, GroupObject. -- The GroupObject is the GROUP object that is dead and within the SET_OPSGROUP, and is passed as a parameter to the event handler. -- See the following example: -- diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index 53780719e..5eb53c664 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -878,16 +878,16 @@ end -- @param #number Formation Formation of the group. function ARMYGROUP:onbeforeUpdateRoute(From, Event, To, n, N, Speed, Formation) if self:IsWaiting() then - self:E(self.lid.."Update route denied. Group is WAIRING!") + self:T(self.lid.."Update route denied. Group is WAIRING!") return false elseif self:IsInUtero() then - self:E(self.lid.."Update route denied. Group is INUTERO!") + self:T(self.lid.."Update route denied. Group is INUTERO!") return false elseif self:IsDead() then - self:E(self.lid.."Update route denied. Group is DEAD!") + self:T(self.lid.."Update route denied. Group is DEAD!") return false elseif self:IsStopped() then - self:E(self.lid.."Update route denied. Group is STOPPED!") + self:T(self.lid.."Update route denied. Group is STOPPED!") return false elseif self:IsHolding() then self:T(self.lid.."Update route denied. Group is holding position!") @@ -908,7 +908,7 @@ end function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation) -- Debug info. - local text=string.format("Update route state=%s: n=%s, N=%s, Speed=%s, Formation=%s", self:GetState(), tostring(n), tostring(N), tostring(Speed), tostring(Formation)) + local text=string.format("Update route state=%s: n=%s, N=%s, Speed=%d, Formation=%s", self:GetState(), tostring(n), tostring(N), tonumber(Speed), tostring(Formation)) self:T(self.lid..text) -- Update route from this waypoint number onwards. @@ -929,7 +929,7 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation) self:T({wp}) -- Speed. if Speed then - wp.speed=UTILS.KnotsToMps(Speed) + wp.speed=UTILS.KnotsToMps(tonumber(Speed)) else -- Take default waypoint speed. But make sure speed>0 if patrol ad infinitum. if wp.speed<0.1 then --self.adinfinitum and @@ -1031,7 +1031,7 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation) -- Passed final WP ==> Full Stop --- - self:E(self.lid..string.format("WARNING: Passed final WP when UpdateRoute() ==> Full Stop!")) + self:T(self.lid..string.format("WARNING: Passed final WP when UpdateRoute() ==> Full Stop!")) self:FullStop() end @@ -1250,7 +1250,7 @@ function ARMYGROUP:onafterRTZ(From, Event, To, Zone, Formation) end else - self:E(self.lid.."ERROR: No RTZ zone given!") + self:T(self.lid.."ERROR: No RTZ zone given!") end end @@ -1386,7 +1386,7 @@ function ARMYGROUP:onbeforeEngageTarget(From, Event, To, Target) local ammo=self:GetAmmoTot() if ammo.Total==0 then - self:E(self.lid.."WARNING: Cannot engage TARGET because no ammo left!") + self:T(self.lid.."WARNING: Cannot engage TARGET because no ammo left!") return false end @@ -1684,7 +1684,7 @@ function ARMYGROUP:_InitGroup(Template) -- Quick check. if #units~=size0 then - self:E(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units!", #units, size0)) + self:T(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units!", #units, size0)) end -- Add elemets. @@ -1714,7 +1714,7 @@ function ARMYGROUP:SwitchFormation(Formation, Permanently, NoRouteUpdate) if self:IsAlive() or self:IsInUtero() then - Formation=Formation or self.optionDefault.Formation + Formation=Formation or (self.optionDefault.Formation or "Off road") Permanently = Permanently or false if Permanently then @@ -1724,7 +1724,7 @@ function ARMYGROUP:SwitchFormation(Formation, Permanently, NoRouteUpdate) end -- Set current formation. - self.option.Formation=Formation + self.option.Formation=Formation or "Off road" if self:IsInUtero() then self:T(self.lid..string.format("Will switch formation to %s (permanently=%s) when group is spawned", tostring(self.option.Formation), tostring(Permanently))) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index d290944dd..e09404c29 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1977,7 +1977,7 @@ function AUFTRAG:_DetermineAuftragType(Target) auftrag=AUFTRAG.Type.ANTISHIP else - self:E(self.lid.."ERROR: Unknown Group category!") + self:T(self.lid.."ERROR: Unknown Group category!") end elseif airbase then @@ -3237,7 +3237,7 @@ function AUFTRAG:onafterStatus(From, Event, To) -- Check for error. if fsmstate~=self.status then - self:E(self.lid..string.format("ERROR: FSM state %s != %s mission status!", fsmstate, self.status)) + self:T(self.lid..string.format("ERROR: FSM state %s != %s mission status!", fsmstate, self.status)) end -- General info. @@ -3254,7 +3254,7 @@ function AUFTRAG:onafterStatus(From, Event, To) local chief=self.chief and self.statusChief or "N/A" -- Info message. - self:I(self.lid..string.format("Status %s: Target=%s, T=%s-%s, assets=%d, groups=%d, targets=%d, legions=%d, commander=%s, chief=%s", + self:T(self.lid..string.format("Status %s: Target=%s, T=%s-%s, assets=%d, groups=%d, targets=%d, legions=%d, commander=%s, chief=%s", self.status, targetname, Cstart, Cstop, #self.assets, Ngroups, Ntargets, Nlegions, commander, chief)) end @@ -3366,22 +3366,23 @@ function AUFTRAG:Evaluate() end -- Debug text. - local text=string.format("Evaluating mission:\n") - text=text..string.format("Own casualties = %d/%d\n", self.Ncasualties, self.Nelements) - text=text..string.format("Own losses = %.1f %%\n", owndamage) - text=text..string.format("Killed units = %d\n", self.Nkills) - text=text..string.format("--------------------------\n") - text=text..string.format("Targets left = %d/%d\n", Ntargets, Ntargets0) - text=text..string.format("Targets life = %.1f/%.1f\n", Life, Life0) - text=text..string.format("Enemy losses = %.1f %%\n", targetdamage) - text=text..string.format("--------------------------\n") - text=text..string.format("Success Cond = %s\n", tostring(successCondition)) - text=text..string.format("Failure Cond = %s\n", tostring(failureCondition)) - text=text..string.format("--------------------------\n") - text=text..string.format("Final Success = %s\n", tostring(not failed)) - text=text..string.format("=========================") - self:I(self.lid..text) - + if self.verbose > 0 then + local text=string.format("Evaluating mission:\n") + text=text..string.format("Own casualties = %d/%d\n", self.Ncasualties, self.Nelements) + text=text..string.format("Own losses = %.1f %%\n", owndamage) + text=text..string.format("Killed units = %d\n", self.Nkills) + text=text..string.format("--------------------------\n") + text=text..string.format("Targets left = %d/%d\n", Ntargets, Ntargets0) + text=text..string.format("Targets life = %.1f/%.1f\n", Life, Life0) + text=text..string.format("Enemy losses = %.1f %%\n", targetdamage) + text=text..string.format("--------------------------\n") + text=text..string.format("Success Cond = %s\n", tostring(successCondition)) + text=text..string.format("Failure Cond = %s\n", tostring(failureCondition)) + text=text..string.format("--------------------------\n") + text=text..string.format("Final Success = %s\n", tostring(not failed)) + text=text..string.format("=========================") + self:I(self.lid..text) + end if failed then self:Failed() else @@ -3446,7 +3447,7 @@ function AUFTRAG:SetGroupStatus(opsgroup, status) if groupdata then groupdata.status=status else - self:E(self.lid.."WARNING: Could not SET flight data for flight group. Setting status to DONE") + self:T(self.lid.."WARNING: Could not SET flight data for flight group. Setting status to DONE") end end @@ -3483,7 +3484,7 @@ function AUFTRAG:GetGroupStatus(opsgroup) return groupdata.status else - self:E(self.lid..string.format("WARNING: Could not GET groupdata for opsgroup %s. Returning status DONE.", opsgroup and opsgroup.groupname or "nil")) + self:T(self.lid..string.format("WARNING: Could not GET groupdata for opsgroup %s. Returning status DONE.", opsgroup and opsgroup.groupname or "nil")) return AUFTRAG.GroupStatus.DONE end @@ -3521,7 +3522,7 @@ function AUFTRAG:RemoveLegion(Legion) end end - self:E(self.lid..string.format("ERROR: Legion %s not found and could not be removed!", Legion.alias)) + self:T(self.lid..string.format("ERROR: Legion %s not found and could not be removed!", Legion.alias)) return self end @@ -3735,7 +3736,7 @@ function AUFTRAG:OnEventUnitLost(EventData) for _,_groupdata in pairs(self.groupdata) do local groupdata=_groupdata --#AUFTRAG.GroupData if groupdata and groupdata.opsgroup and groupdata.opsgroup.groupname==EventData.IniGroupName then - self:I(self.lid..string.format("UNIT LOST event for opsgroup %s unit %s", groupdata.opsgroup.groupname, EventData.IniUnitName)) + self:T(self.lid..string.format("UNIT LOST event for opsgroup %s unit %s", groupdata.opsgroup.groupname, EventData.IniUnitName)) end end @@ -3858,7 +3859,7 @@ function AUFTRAG:onafterAssetDead(From, Event, To, Asset) -- Number of groups alive. local N=self:CountOpsGroups() - self:I(self.lid..string.format("Asset %s dead! Number of ops groups remaining %d", tostring(Asset.spawngroupname), N)) + self:T(self.lid..string.format("Asset %s dead! Number of ops groups remaining %d", tostring(Asset.spawngroupname), N)) -- All assets dead? if N==0 then @@ -3892,7 +3893,7 @@ function AUFTRAG:onafterCancel(From, Event, To) local Ngroups = self:CountOpsGroups() -- Debug info. - self:I(self.lid..string.format("CANCELLING mission in status %s. Will wait for %d groups to report mission DONE before evaluation", self.status, Ngroups)) + self:T(self.lid..string.format("CANCELLING mission in status %s. Will wait for %d groups to report mission DONE before evaluation", self.status, Ngroups)) -- Time stamp. self.Tover=timer.getAbsTime() @@ -4010,13 +4011,13 @@ function AUFTRAG:onafterSuccess(From, Event, To) local N=math.max(self.NrepeatSuccess, self.Nrepeat) -- Repeat mission. - self:I(self.lid..string.format("Mission SUCCESS! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N)) + self:T(self.lid..string.format("Mission SUCCESS! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N)) self:Repeat() else -- Stop mission. - self:I(self.lid..string.format("Mission SUCCESS! Number of max repeats %d reached ==> Stopping mission!", self.repeated+1)) + self:T(self.lid..string.format("Mission SUCCESS! Number of max repeats %d reached ==> Stopping mission!", self.repeated+1)) self:Stop() end @@ -4052,13 +4053,13 @@ function AUFTRAG:onafterFailed(From, Event, To) local N=math.max(self.NrepeatFailure, self.Nrepeat) -- Repeat mission. - self:I(self.lid..string.format("Mission FAILED! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N)) + self:T(self.lid..string.format("Mission FAILED! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N)) self:Repeat() else -- Stop mission. - self:I(self.lid..string.format("Mission FAILED! Number of max repeats %d reached ==> Stopping mission!", self.repeated+1)) + self:T(self.lid..string.format("Mission FAILED! Number of max repeats %d reached ==> Stopping mission!", self.repeated+1)) self:Stop() end @@ -4185,7 +4186,7 @@ end function AUFTRAG:onafterStop(From, Event, To) -- Debug info. - self:I(self.lid..string.format("STOPPED mission in status=%s. Removing missions from queues. Stopping CallScheduler!", self.status)) + self:T(self.lid..string.format("STOPPED mission in status=%s. Removing missions from queues. Stopping CallScheduler!", self.status)) -- TODO: Mission should be OVER! we dont want to remove running missions from any queues. @@ -4378,7 +4379,7 @@ function AUFTRAG:GetTargetCoordinate() return nil else - self:E(self.lid.."ERROR: Cannot get target coordinate!") + self:T(self.lid.."ERROR: Cannot get target coordinate!") end return nil @@ -4409,7 +4410,7 @@ function AUFTRAG:GetTargetDistance(FromCoord) if TargetCoord and FromCoord then return TargetCoord:Get2DDistance(FromCoord) else - self:E(self.lid.."ERROR: TargetCoord or FromCoord does not exist in AUFTRAG:GetTargetDistance() function! Returning 0") + self:T(self.lid.."ERROR: TargetCoord or FromCoord does not exist in AUFTRAG:GetTargetDistance() function! Returning 0") end return 0 @@ -5021,7 +5022,7 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable) table.insert(DCStasks, DCStask) else - self:E(self.lid..string.format("ERROR: Unknown mission task!")) + self:T(self.lid..string.format("ERROR: Unknown mission task!")) return nil end diff --git a/Moose Development/Moose/Ops/Brigade.lua b/Moose Development/Moose/Ops/Brigade.lua index 5c390f3fb..9ce7e379f 100644 --- a/Moose Development/Moose/Ops/Brigade.lua +++ b/Moose Development/Moose/Ops/Brigade.lua @@ -49,7 +49,7 @@ BRIGADE = { --- BRIGADE class version. -- @field #string version -BRIGADE.version="0.1.0" +BRIGADE.version="0.1.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -288,6 +288,126 @@ function BRIGADE:RemoveAssetFromPlatoon(Asset) end end + +--- [ GROUND ] Function to load back an asset in the field that has been filed before. +-- @param #BRIGADE self +-- @param #string Templatename e.g."1 PzDv LogRg I\_AID-976" - that's the alias (name) of an platoon spawned as `"platoon - alias"_AID-"asset-ID"` +-- @param Core.Point#COORDINATE Position where to spawn the platoon +-- @return #BRIGADE self +-- @usage +-- Prerequisites: +-- Save the assets spawned by BRIGADE/CHIEF regularly (~every 5 mins) into a file, e.g. like this: +-- +-- local Path = FilePath or "C:\\Users\\\\Saved Games\\DCS\\Missions\\" -- example path +-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename +-- local BlueSaveOps = SET_GROUP:New():FilterCoalitions("blue"):FilterPrefixes("AID"):FilterCategoryGround():FilterOnce() +-- UTILS.SaveSetOfGroups(BlueSaveOps,Path,BlueOpsFilename) +-- +-- where Path and Filename are strings, as chosen by you. +-- You can then load back the assets at the start of your next mission run. Be aware that it takes a couple of seconds for the +-- platoon data to arrive in brigade, so make this an action after ~20 seconds, e.g. like so: +-- +-- function LoadBackAssets() +-- local Path = FilePath or "C:\\Users\\\\Saved Games\\DCS\\Missions\\" -- example path +-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename +-- if UTILS.CheckFileExists(Path,BlueOpsFilename) then +-- local loadback = UTILS.LoadSetOfGroups(Path,BlueOpsFilename,false) +-- for _,_platoondata in pairs (loadback) do +-- local groupname = _platoondata.groupname -- #string +-- local coordinate = _platoondata.coordinate -- Core.Point#COORDINATE +-- Your_Brigade:LoadBackAssetInPosition(groupname,coordinate) +-- end +-- end +-- end +-- +-- local AssetLoader = TIMER:New(LoadBackAssets) +-- AssetLoader:Start(20) +-- +-- The assets loaded back into the mission will be considered for AUFTRAG type missions from CHIEF and BRIGADE. +function BRIGADE:LoadBackAssetInPosition(Templatename,Position) + self:T(self.lid .. "LoadBackAssetInPosition: " .. tostring(Templatename)) + + -- get Platoon alias from Templatename + local nametbl = UTILS.Split(Templatename,"_") + + local name = nametbl[1] + + self:T(string.format("*** Target Platoon = %s ***",name)) + + -- find a matching asset table from BRIGADE + local cohorts = self.cohorts or {} + local thisasset = nil --Functional.Warehouse#WAREHOUSE.Assetitem + local found = false + + for _,_cohort in pairs(cohorts) do + local asset = _cohort:GetName() + self:T(string.format("*** Looking at Platoon = %s ***",asset)) + if asset == name then + self:T("**** Found Platoon ****") + local cohassets = _cohort.assets or {} + for _,_zug in pairs (cohassets) do + local zug = _zug -- Functional.Warehouse#WAREHOUSE.Assetitem + if zug.assignment == name and zug.requested == false then + self:T("**** Found Asset ****") + found = true + thisasset = zug --Functional.Warehouse#WAREHOUSE.Assetitem + break + end + end + end + end + + if found then + + -- prep asset + thisasset.rid = thisasset.uid + thisasset.requested = false + thisasset.score=100 + thisasset.missionTask="CAS" + thisasset.spawned = true + local template = thisasset.templatename + local alias = thisasset.spawngroupname + + -- Spawn group + local spawnasset = SPAWN:NewWithAlias(template,alias) + :InitDelayOff() + :SpawnFromCoordinate(Position) + + -- build a new self request + local request = {} --Functional.Warehouse#WAREHOUSE.Pendingitem + request.assignment = name + request.warehouse = self + request.assets = {thisasset} + request.ntransporthome = 0 + request.ndelivered = 0 + request.ntransport = 0 + request.cargoattribute = thisasset.attribute + request.category = thisasset.category + request.cargoassets = {thisasset} + request.assetdesc = WAREHOUSE.Descriptor.ASSETLIST + request.cargocategory = thisasset.category + request.toself = true + request.transporttype = WAREHOUSE.TransportType.SELFPROPELLED + request.assetproblem = {} + request.born = true + request.prio = 50 + request.uid = thisasset.uid + request.airbase = nil + request.timestamp = timer.getAbsTime() + request.assetdescval = {thisasset} + request.nasset = 1 + request.cargogroupset = SET_GROUP:New() + request.cargogroupset:AddGroup(spawnasset) + request.iscargo = true + + -- Call Brigade self + self:__AssetSpawned(2, spawnasset, thisasset, request) + + end + return self +end + + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- FSM Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 110fdbd8c..0ca2f1058 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -45,7 +45,7 @@ -- * Object oriented refactoring of Ciribob\'s fantastic CSAR script. -- * No need for extra MIST loading. -- * Additional events to tailor your mission. --- * Optional SpawnCASEVAC to create casualties without beacon (e.g. handling dead ground vehicles and create CASVAC requests). +-- * Optional SpawnCASEVAC to create casualties without beacon (e.g. handling dead ground vehicles and create CASVAC requests). -- -- ## 0. Prerequisites -- @@ -117,7 +117,7 @@ -- self.SRSchannel = 300 -- radio channel -- self.SRSModulation = radio.modulation.AM -- modulation -- -- --- self.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection --shagrat +-- self.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection --shagrat -- -- ## 3. Results -- @@ -178,8 +178,8 @@ -- -- Create downed "Pilot Wagner" in #ZONE "CSAR_Start_1" at a random point for the blue coalition -- my_csar:SpawnCSARAtZone( "CSAR_Start_1", coalition.side.BLUE, "Pilot Wagner", true ) -- --- --Create a casualty and CASEVAC request from a "Point" (VEC2) for the blue coalition --shagrat --- my_csar:SpawnCASEVAC(Point, coalition.side.BLUE) +-- --Create a casualty and CASEVAC request from a "Point" (VEC2) for the blue coalition --shagrat +-- my_csar:SpawnCASEVAC(Point, coalition.side.BLUE) -- -- @field #CSAR CSAR = { @@ -243,11 +243,11 @@ CSAR.AircraftType["Mi-8MTV2"] = 12 CSAR.AircraftType["Mi-8MT"] = 12 CSAR.AircraftType["Mi-24P"] = 8 CSAR.AircraftType["Mi-24V"] = 8 -CSAR.AircraftType["Bell-47"] = 2 +CSAR.AircraftType["Bell-47"] = 2 --- CSAR class version. -- @field #string version -CSAR.version="0.1.12r5" +CSAR.version="1.0.1r1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -356,6 +356,7 @@ function CSAR:New(Coalition, Template, Alias) self.extractDistance = 500 -- Distance the Downed pilot will run to the rescue helicopter self.loadtimemax = 135 -- seconds self.radioSound = "beacon.ogg" -- the name of the sound file to use for the Pilot radio beacons. If this isnt added to the mission BEACONS WONT WORK! + self.beaconRefresher = 29 -- seconds self.allowFARPRescue = true --allows pilot to be rescued by landing at a FARP or Airbase self.FARPRescueDistance = 1000 -- you need to be this close to a FARP or Airport for the pilot to be rescued. self.max_units = 6 --max number of pilots that can be carried @@ -654,10 +655,10 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla if not noMessage then if _freq ~= 0 then --shagrat different CASEVAC msg - self:_DisplayToAllSAR("MAYDAY MAYDAY! " .. _typeName .. " is down. ", self.coalition, self.messageTime) - else - self:_DisplayToAllSAR("Troops In Contact. " .. _typeName .. " requests CASEVAC. ", self.coalition, self.messageTime) - end + self:_DisplayToAllSAR("MAYDAY MAYDAY! " .. _typeName .. " is down. ", self.coalition, self.messageTime) + else + self:_DisplayToAllSAR("Troops In Contact. " .. _typeName .. " requests CASEVAC. ", self.coalition, self.messageTime) + end end if (_freq and _freq ~= 0) then --shagrat only add beacon if _freq is NOT 0 @@ -669,18 +670,18 @@ function CSAR:_AddCsar(_coalition , _country, _point, _typeName, _unitName, _pla local _text = _description if not forcedesc then if _playerName ~= nil then - if _freq ~= 0 then --shagrat - _text = "Pilot " .. _playerName - else - _text = "TIC - " .. _playerName - end + if _freq ~= 0 then --shagrat + _text = "Pilot " .. _playerName + else + _text = "TIC - " .. _playerName + end elseif _unitName ~= nil then if _freq ~= 0 then --shagrat - _text = "AI Pilot of " .. _unitName - else - _text = "TIC - " .. _unitName - end - end + _text = "AI Pilot of " .. _unitName + else + _text = "TIC - " .. _unitName + end + end end self:T({_spawnedGroup, _alias}) @@ -901,12 +902,12 @@ function CSAR:_EventHandler(EventData) local _unit = _event.IniUnit local _unitname = _event.IniUnitName local _group = _event.IniGroup - + if _unit == nil then return -- error! end - - local _coalition = _unit:GetCoalition() + + local _coalition = _unit:GetCoalition() if _coalition ~= self.coalition then return --ignore! end @@ -926,28 +927,28 @@ function CSAR:_EventHandler(EventData) end -- all checks passed, get going. - if self.csarUsePara == false then --shagrat check parameter LandingAfterEjection, if true don't spawn a Pilot from EJECTION event, wait for the Chute to land - local _freq = self:_GenerateADFFrequency() - self:_AddCsar(_coalition, _unit:GetCountry(), _unit:GetCoordinate() , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none") - return true - end - - ---- shagrat on event LANDING_AFTER_EJECTION spawn pilot at parachute location - elseif (_event.id == EVENTS.LandingAfterEjection and self.csarUsePara == true) then - self:I({EVENT=_event}) - local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p) - local _unitname = "Aircraft" --_event.initiator:getName() or "Aircraft" --shagrat Optional use of Object name which is unfortunately 'f15_Pilot_Parachute' - local _typename = "Ejected Pilot" --_event.Initiator.getTypeName() or "Ejected Pilot" - local _country = _event.initiator:getCountry() - local _coalition = coalition.getCountryCoalition( _country ) - if _coalition == self.coalition then - local _freq = self:_GenerateADFFrequency() - self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq}) - self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, false, "none")--shagrat add CSAR at Parachute location. - - Unit.destroy(_event.initiator) -- shagrat remove static Pilot model - end - return true + if self.csarUsePara == false then --shagrat check parameter LandingAfterEjection, if true don't spawn a Pilot from EJECTION event, wait for the Chute to land + local _freq = self:_GenerateADFFrequency() + self:_AddCsar(_coalition, _unit:GetCountry(), _unit:GetCoordinate() , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none") + return true + end + + ---- shagrat on event LANDING_AFTER_EJECTION spawn pilot at parachute location + elseif (_event.id == EVENTS.LandingAfterEjection and self.csarUsePara == true) then + self:I({EVENT=_event}) + local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p) + local _unitname = "Aircraft" --_event.initiator:getName() or "Aircraft" --shagrat Optional use of Object name which is unfortunately 'f15_Pilot_Parachute' + local _typename = "Ejected Pilot" --_event.Initiator.getTypeName() or "Ejected Pilot" + local _country = _event.initiator:getCountry() + local _coalition = coalition.getCountryCoalition( _country ) + if _coalition == self.coalition then + local _freq = self:_GenerateADFFrequency() + self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq}) + self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, false, "none")--shagrat add CSAR at Parachute location. + + Unit.destroy(_event.initiator) -- shagrat remove static Pilot model + end + return true elseif _event.id == EVENTS.Land then self:T(self.lid .. " Landing") @@ -1012,13 +1013,13 @@ function CSAR:_InitSARForPilot(_downedGroup, _GroupName, _freq, _nomessage) local _leadername = _leader:GetName() if not _nomessage then - if _freq ~= 0 then --shagrat - local _text = string.format("%s requests SAR at %s, beacon at %.2f KHz", _groupName, _coordinatesText, _freqk)--shagrat _groupName to prevent 'f15_Pilot_Parachute' - self:_DisplayToAllSAR(_text,self.coalition,self.messageTime) - else --shagrat CASEVAC msg - local _text = string.format("Pickup Zone at %s.", _coordinatesText ) - self:_DisplayToAllSAR(_text,self.coalition,self.messageTime) - end + if _freq ~= 0 then --shagrat + local _text = string.format("%s requests SAR at %s, beacon at %.2f KHz", _groupName, _coordinatesText, _freqk)--shagrat _groupName to prevent 'f15_Pilot_Parachute' + self:_DisplayToAllSAR(_text,self.coalition,self.messageTime) + else --shagrat CASEVAC msg + local _text = string.format("Pickup Zone at %s.", _coordinatesText ) + self:_DisplayToAllSAR(_text,self.coalition,self.messageTime) + end end for _,_heliName in pairs(self.csarUnits) do @@ -1456,12 +1457,13 @@ end -- @param #number _time Message show duration. -- @param #boolean _clear (optional) Clear screen. -- @param #boolean _speak (optional) Speak message via SRS. -function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak) +-- @param #boolean _override (optional) Override message suppression +function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _override) self:T(self.lid .. " _DisplayMessageToSAR") local group = _unit:GetGroup() local _clear = _clear or nil local _time = _time or self.messageTime - if not self.suppressmessages then + if _override or not self.suppressmessages then local m = MESSAGE:New(_text,_time,"Info",_clear):ToGroup(group) end -- integrate SRS @@ -1531,11 +1533,11 @@ function CSAR:_DisplayActiveSAR(_unitName) else distancetext = string.format("%.1fkm", _distance/1000.0) end - if _value.frequency == 0 then--shagrat insert CASEVAC without Frequency - table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %s ", _value.desc, _coordinatesText, distancetext) }) - else - table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %.2f KHz ADF - %s ", _value.desc, _coordinatesText, _value.frequency / 1000, distancetext) }) - end + if _value.frequency == 0 then--shagrat insert CASEVAC without Frequency + table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %s ", _value.desc, _coordinatesText, distancetext) }) + else + table.insert(_csarList, { dist = _distance, msg = string.format("%s at %s - %.2f KHz ADF - %s ", _value.desc, _coordinatesText, _value.frequency / 1000, distancetext) }) + end end end @@ -1549,7 +1551,7 @@ function CSAR:_DisplayActiveSAR(_unitName) _msg = _msg .. "\n" .. _line.msg end - self:_DisplayMessageToSAR(_heli, _msg, self.messageTime*2) + self:_DisplayMessageToSAR(_heli, _msg, self.messageTime*2, false, false, true) return self end @@ -1617,7 +1619,7 @@ function CSAR:_SignalFlare(_unitName) _distance = string.format("%.1fkm",_closest.distance) end local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance) - self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true) + self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true) local _coord = _closest.pilot:GetCoordinate() _coord:FlareRed(_clockDir) @@ -1628,7 +1630,7 @@ function CSAR:_SignalFlare(_unitName) else _distance = string.format("%.1fkm",smokedist/1000) end - self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime) + self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true) end return self end @@ -1671,7 +1673,7 @@ function CSAR:_Reqsmoke( _unitName ) _distance = string.format("%.1fkm",_closest.distance/1000) end local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance) - self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true) + self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true) local _coord = _closest.pilot:GetCoordinate() local color = self.smokecolor _coord:Smoke(color) @@ -1682,7 +1684,7 @@ function CSAR:_Reqsmoke( _unitName ) else _distance = string.format("%.1fkm",smokedist/1000) end - self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime) + self:_DisplayMessageToSAR(_heli, string.format("No Pilots within %s",_distance), self.messageTime, false, false, true) end return self end @@ -1754,13 +1756,13 @@ function CSAR:_CheckOnboard(_unitName) --list onboard pilots local _inTransit = self.inTransitGroups[_unitName] if _inTransit == nil then - self:_DisplayMessageToSAR(_unit, "No Rescued Pilots onboard", self.messageTime) + self:_DisplayMessageToSAR(_unit, "No Rescued Pilots onboard", self.messageTime, false, false, true) else local _text = "Onboard - RTB to FARP/Airfield or MASH: " for _, _onboard in pairs(self.inTransitGroups[_unitName]) do _text = _text .. "\n" .. _onboard.desc end - self:_DisplayMessageToSAR(_unit, _text, self.messageTime*2) + self:_DisplayMessageToSAR(_unit, _text, self.messageTime*2, false, false, true) end return self end @@ -2020,7 +2022,12 @@ function CSAR:onbeforeStatus(From, Event, To) self:T({From, Event, To}) -- housekeeping self:_AddMedevacMenuItem() - self:_RefreshRadioBeacons() + + if not self.BeaconTimer or (self.BeaconTimer and not self.BeaconTimer:IsRunning()) then + self.BeaconTimer = TIMER:New(self._RefreshRadioBeacons,self) + self.BeaconTimer:Start(2,self.beaconRefresher) + end + self:_CheckDownedPilotTable() for _,_sar in pairs (self.csarUnits) do local PilotTable = self.downedPilots diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 6abfd8477..c626472b0 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -22,7 +22,7 @@ -- @module Ops.CTLD -- @image OPS_CTLD.jpg --- Date: Oct 2021 +-- Date: Dec 2021 do ------------------------------------------------------ @@ -669,7 +669,9 @@ do -- my_ctld.cratecountry = country.id.GERMANY -- ID of crates. Will default to country.id.RUSSIA for RED coalition setups. -- my_ctld.allowcratepickupagain = true -- allow re-pickup crates that were dropped. -- my_ctld.enableslingload = false -- allow cargos to be slingloaded - might not work for all cargo types --- my_ctld.pilotmustopendoors = false -- -- force opening of doors +-- my_ctld.pilotmustopendoors = false -- force opening of doors +-- my_ctld.SmokeColor = SMOKECOLOR.Red -- color to use when dropping smoke from heli +-- my_ctld.FlareColor = FLARECOLOR.Red -- color to use when flaring from heli -- -- ## 2.1 User functions -- @@ -812,7 +814,7 @@ do -- -- ## 4.1 Manage Crates -- --- Use this entry to get, load, list nearby, drop, build and repair crates. Also @see options. +-- Use this entry to get, load, list nearby, drop, build and repair crates. Also see options. -- -- ## 4.2 Manage Troops -- @@ -823,7 +825,7 @@ do -- -- Lists what you have loaded. Shows load capabilities for number of crates and number of seats for troops. -- --- ## 4.4 Smoke & Flare zones nearby +-- ## 4.4 Smoke & Flare zones nearby or drop smoke or flare from Heli -- -- Does what it says. -- @@ -920,7 +922,7 @@ CTLD = { -- DONE: Added support for Hercules -- TODO: Possibly - either/or loading crates and troops -- DONE: Make inject respect existing cargo types --- TODO: Drop beacons or flares/smoke +-- DONE: Drop beacons or flares/smoke -- DONE: Add statics as cargo -- DONE: List cargo in stock -- DONE: Limit of troops, crates buildable? @@ -988,7 +990,7 @@ CTLD.UnitTypes = { --- CTLD class version. -- @field #string version -CTLD.version="0.2.4" +CTLD.version="1.0.1" --- Instantiate a new CTLD. -- @param #CTLD self @@ -1154,6 +1156,10 @@ function CTLD:New(Coalition, Prefixes, Alias) -- slingload self.enableslingload = false + -- Smokes and Flares + self.SmokeColor = SMOKECOLOR.Red + self.FlareColor = FLARECOLOR.Red + for i=1,100 do math.random() end @@ -2911,8 +2917,11 @@ function CTLD:_RefreshF10Menus() local listmenu = MENU_GROUP_COMMAND:New(_group,"List boarded cargo",topmenu, self._ListCargo, self, _group, _unit) local invtry = MENU_GROUP_COMMAND:New(_group,"Inventory",topmenu, self._ListInventory, self, _group, _unit) local rbcns = MENU_GROUP_COMMAND:New(_group,"List active zone beacons",topmenu, self._ListRadioBeacons, self, _group, _unit) - local smokemenu = MENU_GROUP_COMMAND:New(_group,"Smoke zones nearby",topmenu, self.SmokeZoneNearBy, self, _unit, false) - local smokemenu = MENU_GROUP_COMMAND:New(_group,"Flare zones nearby",topmenu, self.SmokeZoneNearBy, self, _unit, true):Refresh() + local smoketopmenu = MENU_GROUP:New(_group,"Smokes & Flares",topmenu) + local smokemenu = MENU_GROUP_COMMAND:New(_group,"Smoke zones nearby",smoketopmenu, self.SmokeZoneNearBy, self, _unit, false) + local smokeself = MENU_GROUP_COMMAND:New(_group,"Drop smoke now",smoketopmenu, self.SmokePositionNow, self, _unit, false) + local flaremenu = MENU_GROUP_COMMAND:New(_group,"Flare zones nearby",smoketopmenu, self.SmokeZoneNearBy, self, _unit, true) + local flareself = MENU_GROUP_COMMAND:New(_group,"Fire flare now",smoketopmenu, self.SmokePositionNow, self, _unit, true):Refresh() -- sub menus -- sub menu troops management if cantroops then @@ -3373,7 +3382,28 @@ function CTLD:IsUnitInZone(Unit,Zonetype) end end ---- User function - Start smoke in a zone close to the Unit. +--- User function - Drop a smoke or flare at current location. +-- @param #CTLD self +-- @param Wrapper.Unit#UNIT Unit The Unit. +-- @param #boolean Flare If true, flare instead. +function CTLD:SmokePositionNow(Unit, Flare) + self:T(self.lid .. " SmokePositionNow") + local SmokeColor = self.SmokeColor or SMOKECOLOR.Red + local FlareColor = self.FlareColor or FLARECOLOR.Red + -- table of #CTLD.CargoZone table + local unitcoord = Unit:GetCoordinate() -- Core.Point#COORDINATE + local Group = Unit:GetGroup() + if Flare then + unitcoord:Flare(FlareColor, 90) + else + local height = unitcoord:GetLandHeight() + 2 + unitcoord.y = height + unitcoord:Smoke(SmokeColor) + end + return self +end + +--- User function - Start smoke/flare in a zone close to the Unit. -- @param #CTLD self -- @param Wrapper.Unit#UNIT Unit The Unit. -- @param #boolean Flare If true, flare instead. @@ -4188,7 +4218,7 @@ end local statics = nil local statics = {} - self:I(self.lid.."Bulding Statics Table for Saving") + self:T(self.lid.."Bulding Statics Table for Saving") for _,_cargo in pairs (stcstable) do local cargo = _cargo -- #CTLD_CARGO local object = cargo:GetPositionable() -- Wrapper.Static#STATIC diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 92aa167f5..a83d19fac 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -668,7 +668,7 @@ function FLIGHTGROUP:StartUncontrolled(delay) self.group:StartUncontrolled(_delay) self.isUncontrolled=false else - self:E(self.lid.."ERROR: Could not start uncontrolled group as it is NOT alive!") + self:T(self.lid.."ERROR: Could not start uncontrolled group as it is NOT alive!") end end @@ -766,7 +766,7 @@ function FLIGHTGROUP:onbeforeStatus(From, Event, To) if isdead then local text=string.format("Element %s is dead at t=%.3f but has status %s! Maybe despawned without notice or landed at a too small airbase. Calling ElementDead in 60 sec to give other events a chance", tostring(element.name), timer.getTime(), tostring(element.status)) - self:E(self.lid..text) + self:T(self.lid..text) self:__ElementDead(60, element) end @@ -841,7 +841,7 @@ function FLIGHTGROUP:Status() end else - --self:E(self.lid..string.format("Element %s is in PARKING queue but has no parking spot assigned!", element.name)) + --self:T(self.lid..string.format("Element %s is in PARKING queue but has no parking spot assigned!", element.name)) end end end @@ -957,7 +957,7 @@ function FLIGHTGROUP:Status() end -- Log outut. - self:I(self.lid..string.format("Travelled ds=%.1f km dt=%.1f s ==> v=%.1f knots. Fuel left for %.1f min", self.traveldist/1000, dt, UTILS.MpsToKnots(v), TmaxFuel/60)) + self:T(self.lid..string.format("Travelled ds=%.1f km dt=%.1f s ==> v=%.1f knots. Fuel left for %.1f min", self.traveldist/1000, dt, UTILS.MpsToKnots(v), TmaxFuel/60)) end @@ -1897,10 +1897,10 @@ function FLIGHTGROUP:onbeforeUpdateRoute(From, Event, To, n, N) self:T3(self.lid.."Update route possible. Group is ALIVE") elseif self:IsDead() then -- Group is dead! No more updates. - self:E(self.lid.."Update route denied. Group is DEAD!") + self:T(self.lid.."Update route denied. Group is DEAD!") allowed=false elseif self:IsInUtero() then - self:E(self.lid.."Update route denied. Group is INUTERO!") + self:T(self.lid.."Update route denied. Group is INUTERO!") allowed=false else -- Not airborne yet. Try again in 5 sec. @@ -1923,19 +1923,19 @@ function FLIGHTGROUP:onbeforeUpdateRoute(From, Event, To, n, N) -- Requested waypoint index <1. Something is seriously wrong here! if n and n<1 then - self:E(self.lid.."Update route denied because waypoint n<1!") + self:T(self.lid.."Update route denied because waypoint n<1!") allowed=false end -- No current waypoint. Something is serously wrong! if not self.currentwp then - self:E(self.lid.."Update route denied because self.currentwp=nil!") + self:T(self.lid.."Update route denied because self.currentwp=nil!") allowed=false end local Nn=n or self.currentwp+1 if not Nn or Nn<1 then - self:E(self.lid.."Update route denied because N=nil or N<1") + self:T(self.lid.."Update route denied because N=nil or N<1") trepeat=-5 allowed=false end @@ -1958,7 +1958,7 @@ function FLIGHTGROUP:onbeforeUpdateRoute(From, Event, To, n, N) self:T2(self.lid.."Allowing update route for Task: Task_Land_At") else local taskname=task and task.description or "No description" - self:E(self.lid..string.format("WARNING: Update route denied because taskcurrent=%d>0! Task description = %s", self.taskcurrent, tostring(taskname))) + self:T(self.lid..string.format("WARNING: Update route denied because taskcurrent=%d>0! Task description = %s", self.taskcurrent, tostring(taskname))) allowed=false end else @@ -2229,24 +2229,24 @@ function FLIGHTGROUP:onbeforeRTB(From, Event, To, airbase, SpeedTo, SpeedHold) local Tsuspend=nil if airbase==nil then - self:E(self.lid.."ERROR: Airbase is nil in RTB() call!") + self:T(self.lid.."ERROR: Airbase is nil in RTB() call!") allowed=false end -- Check that coaliton is okay. We allow same (blue=blue, red=red) or landing on neutral bases. if airbase and airbase:GetCoalition()~=self.group:GetCoalition() and airbase:GetCoalition()>0 then - self:E(self.lid..string.format("ERROR: Wrong airbase coalition %d in RTB() call! We allow only same as group %d or neutral airbases 0", airbase:GetCoalition(), self.group:GetCoalition())) + self:T(self.lid..string.format("ERROR: Wrong airbase coalition %d in RTB() call! We allow only same as group %d or neutral airbases 0", airbase:GetCoalition(), self.group:GetCoalition())) return false end if self.currbase and self.currbase:GetName()==airbase:GetName() then - self:E(self.lid.."WARNING: Currbase is already same as RTB airbase. RTB canceled!") + self:T(self.lid.."WARNING: Currbase is already same as RTB airbase. RTB canceled!") return false end -- Check if the group has landed at an airbase. If so, we lost control and RTBing is not possible (only after a respawn). if self:IsLanded() then - self:E(self.lid.."WARNING: Flight has already landed. RTB canceled!") + self:T(self.lid.."WARNING: Flight has already landed. RTB canceled!") return false end @@ -2260,7 +2260,7 @@ function FLIGHTGROUP:onbeforeRTB(From, Event, To, airbase, SpeedTo, SpeedHold) self.RTBRecallCount = self.RTBRecallCount+1 end if self.RTBRecallCount>6 then - self:I(self.lid..string.format("WARNING: Group [%s] is not moving and was called RTB %d times. Assuming a problem and despawning!", self:GetState(), self.RTBRecallCount)) + self:T(self.lid..string.format("WARNING: Group [%s] is not moving and was called RTB %d times. Assuming a problem and despawning!", self:GetState(), self.RTBRecallCount)) self.RTBRecallCount=0 self:Despawn(5) return @@ -2274,25 +2274,25 @@ function FLIGHTGROUP:onbeforeRTB(From, Event, To, airbase, SpeedTo, SpeedHold) local Ntot,Nsched, Nwp=self:CountRemainingTasks() if self.taskcurrent>0 then - self:I(self.lid..string.format("WARNING: Got current task ==> RTB event is suspended for 10 sec")) + self:T(self.lid..string.format("WARNING: Got current task ==> RTB event is suspended for 10 sec")) Tsuspend=-10 allowed=false end if Nsched>0 then - self:I(self.lid..string.format("WARNING: Still got %d SCHEDULED tasks in the queue ==> RTB event is suspended for 10 sec", Nsched)) + self:T(self.lid..string.format("WARNING: Still got %d SCHEDULED tasks in the queue ==> RTB event is suspended for 10 sec", Nsched)) Tsuspend=-10 allowed=false end if Nwp>0 then - self:I(self.lid..string.format("WARNING: Still got %d WAYPOINT tasks in the queue ==> RTB event is suspended for 10 sec", Nwp)) + self:T(self.lid..string.format("WARNING: Still got %d WAYPOINT tasks in the queue ==> RTB event is suspended for 10 sec", Nwp)) Tsuspend=-10 allowed=false end if self.Twaiting and self.dTwait then - self:I(self.lid..string.format("WARNING: Group is Waiting for a specific duration ==> RTB event is canceled", Nwp)) + self:T(self.lid..string.format("WARNING: Group is Waiting for a specific duration ==> RTB event is canceled", Nwp)) allowed=false end @@ -2305,7 +2305,7 @@ function FLIGHTGROUP:onbeforeRTB(From, Event, To, airbase, SpeedTo, SpeedHold) return allowed else - self:E(self.lid.."WARNING: Group is not alive! RTB call not allowed.") + self:T(self.lid.."WARNING: Group is not alive! RTB call not allowed.") return false end @@ -2361,35 +2361,35 @@ function FLIGHTGROUP:onbeforeLandAtAirbase(From, Event, To, airbase) local Tsuspend=nil if airbase==nil then - self:E(self.lid.."ERROR: Airbase is nil in LandAtAirase() call!") + self:T(self.lid.."ERROR: Airbase is nil in LandAtAirase() call!") allowed=false end -- Check that coaliton is okay. We allow same (blue=blue, red=red) or landing on neutral bases. if airbase and airbase:GetCoalition()~=self.group:GetCoalition() and airbase:GetCoalition()>0 then - self:E(self.lid..string.format("ERROR: Wrong airbase coalition %d in LandAtAirbase() call! We allow only same as group %d or neutral airbases 0", airbase:GetCoalition(), self.group:GetCoalition())) + self:T(self.lid..string.format("ERROR: Wrong airbase coalition %d in LandAtAirbase() call! We allow only same as group %d or neutral airbases 0", airbase:GetCoalition(), self.group:GetCoalition())) return false end if self.currbase and self.currbase:GetName()==airbase:GetName() then - self:E(self.lid.."WARNING: Currbase is already same as LandAtAirbase airbase. LandAtAirbase canceled!") + self:T(self.lid.."WARNING: Currbase is already same as LandAtAirbase airbase. LandAtAirbase canceled!") return false end -- Check if the group has landed at an airbase. If so, we lost control and RTBing is not possible (only after a respawn). if self:IsLanded() then - self:E(self.lid.."WARNING: Flight has already landed. LandAtAirbase canceled!") + self:T(self.lid.."WARNING: Flight has already landed. LandAtAirbase canceled!") return false end if self:IsParking() then allowed=false Tsuspend=-30 - self:E(self.lid.."WARNING: Flight is parking. LandAtAirbase call delayed by 30 sec") + self:T(self.lid.."WARNING: Flight is parking. LandAtAirbase call delayed by 30 sec") elseif self:IsTaxiing() then allowed=false Tsuspend=-1 - self:E(self.lid.."WARNING: Flight is parking. LandAtAirbase call delayed by 1 sec") + self:T(self.lid.."WARNING: Flight is parking. LandAtAirbase call delayed by 1 sec") end if Tsuspend and not allowed then @@ -2398,7 +2398,7 @@ function FLIGHTGROUP:onbeforeLandAtAirbase(From, Event, To, airbase) return allowed else - self:E(self.lid.."WARNING: Group is not alive! LandAtAirbase call not allowed") + self:T(self.lid.."WARNING: Group is not alive! LandAtAirbase call not allowed") return false end @@ -2573,14 +2573,14 @@ function FLIGHTGROUP:onbeforeWait(From, Event, To, Duration, Altitude, Speed) -- Check for a current task. if self.taskcurrent>0 and not self:IsLandedAt() then - self:I(self.lid..string.format("WARNING: Got current task ==> WAIT event is suspended for 30 sec!")) + self:T(self.lid..string.format("WARNING: Got current task ==> WAIT event is suspended for 30 sec!")) Tsuspend=-30 allowed=false end -- Check for a current transport assignment. if self.cargoTransport and not self:IsLandedAt() then - --self:I(self.lid..string.format("WARNING: Got current TRANSPORT assignment ==> WAIT event is suspended for 30 sec!")) + --self:T(self.lid..string.format("WARNING: Got current TRANSPORT assignment ==> WAIT event is suspended for 30 sec!")) --Tsuspend=-30 --allowed=false end @@ -2803,7 +2803,7 @@ function FLIGHTGROUP:onafterEngageTarget(From, Event, To, Target) DCStask=self:GetGroup():TaskCombo(DCSTasks) else - self:E("ERROR: unknown Target in EngageTarget! Needs to be a UNIT, STATIC, GROUP, SET_UNIT or SET_GROUP") + self:T("ERROR: unknown Target in EngageTarget! Needs to be a UNIT, STATIC, GROUP, SET_UNIT or SET_GROUP") return end @@ -3094,7 +3094,7 @@ function FLIGHTGROUP:_InitGroup(Template) -- Quick check. if #units~=size0 then - self:E(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units!", #units, size0)) + self:T(self.lid..string.format("ERROR: Got #units=%d but group consists of %d units!", #units, size0)) end -- Add elemets. @@ -3893,7 +3893,7 @@ function FLIGHTGROUP:GetParking(airbase) -- No parking spot for at least one asset :( if not gotit then - self:E(self.lid..string.format("WARNING: No free parking spot for element %s", element.name)) + self:T(self.lid..string.format("WARNING: No free parking spot for element %s", element.name)) return nil end diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 4a44b31c3..6975f91f8 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -512,7 +512,7 @@ function OPSGROUP:New(group) -- Check if group exists. if self.group then if not self:IsExist() then - self:E(self.lid.."ERROR: GROUP does not exist! Returning nil") + self:T(self.lid.."ERROR: GROUP does not exist! Returning nil") return nil end end @@ -1382,7 +1382,7 @@ function OPSGROUP:GetCoordinate(NewObject) return self.coordinate end else - self:E(self.lid.."WARNING: Cannot get coordinate!") + self:T(self.lid.."WARNING: Cannot get coordinate!") end return nil @@ -1413,11 +1413,11 @@ function OPSGROUP:GetVelocity(UnitName) return vel else - self:E(self.lid.."WARNING: Unit does not exist. Cannot get velocity!") + self:T(self.lid.."WARNING: Unit does not exist. Cannot get velocity!") end else - self:E(self.lid.."WARNING: Group does not exist. Cannot get velocity!") + self:T(self.lid.."WARNING: Group does not exist. Cannot get velocity!") end return nil @@ -1454,7 +1454,7 @@ function OPSGROUP:GetHeading(UnitName) end else - self:E(self.lid.."WARNING: Group does not exist. Cannot get heading!") + self:T(self.lid.."WARNING: Group does not exist. Cannot get heading!") end return nil @@ -1486,7 +1486,7 @@ function OPSGROUP:GetOrientation(UnitName) end else - self:E(self.lid.."WARNING: Group does not exist. Cannot get orientation!") + self:T(self.lid.."WARNING: Group does not exist. Cannot get orientation!") end return nil @@ -1724,9 +1724,9 @@ function OPSGROUP:Activate(delay) self.isLateActivated=false elseif self:IsAlive()==true then - self:E(self.lid.."WARNING: Activating group that is already activated") + self:T(self.lid.."WARNING: Activating group that is already activated") else - self:E(self.lid.."ERROR: Activating group that is does not exist!") + self:T(self.lid.."ERROR: Activating group that is does not exist!") end end @@ -2790,13 +2790,13 @@ function OPSGROUP:RemoveWaypoint(wpindex) -- Always keep at least one waypoint. if N==1 then - self:E(self.lid..string.format("ERROR: Cannot remove waypoint with index=%d! It is the only waypoint and a group needs at least ONE waypoint", wpindex)) + self:T(self.lid..string.format("ERROR: Cannot remove waypoint with index=%d! It is the only waypoint and a group needs at least ONE waypoint", wpindex)) return self end -- Check that wpindex is not larger than the number of waypoints in the table. if wpindex>N then - self:E(self.lid..string.format("ERROR: Cannot remove waypoint with index=%d as there are only N=%d waypoints!", wpindex, N)) + self:T(self.lid..string.format("ERROR: Cannot remove waypoint with index=%d as there are only N=%d waypoints!", wpindex, N)) return self end @@ -3101,7 +3101,7 @@ end function OPSGROUP:ClearTasks() local hastask=self:HasTaskController() if self:IsAlive() and self.controller and self:HasTaskController() then - self:I(self.lid..string.format("CLEARING Tasks")) + self:T(self.lid..string.format("CLEARING Tasks")) self.controller:resetTask() end return self @@ -3639,7 +3639,7 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task) --- -- Just stay put and wait until something happens. - + elseif Task.dcstask.id==AUFTRAG.SpecialTask.ALERT5 then --- @@ -3723,7 +3723,7 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task) elseif Task.type==OPSGROUP.TaskType.WAYPOINT then -- Waypoint tasks are executed elsewhere! else - self:E(self.lid.."ERROR: Unknown task type: ") + self:T(self.lid.."ERROR: Unknown task type: ") end end @@ -3803,7 +3803,7 @@ function OPSGROUP:onafterTaskCancel(From, Event, To, Task) else local text=string.format("WARNING: No (current) task to cancel!") - self:E(self.lid..text) + self:T(self.lid..text) end @@ -3925,9 +3925,9 @@ function OPSGROUP:AddMission(Mission) table.insert(self.missionqueue, Mission) -- ad infinitum? - + self.adinfinitum = Mission.DCStask.params.adinfinitum and Mission.DCStask.params.adinfinitum or false - + -- Info text. local text=string.format("Added %s mission %s starting at %s, stopping at %s", tostring(Mission.type), tostring(Mission.name), UTILS.SecondsToClock(Mission.Tstart, true), Mission.Tstop and UTILS.SecondsToClock(Mission.Tstop, true) or "INF") @@ -3953,7 +3953,7 @@ function OPSGROUP:RemoveMission(Mission) if Task then self:RemoveTask(Task) end - + -- Take care of a paused mission. if self.missionpaused and self.missionpaused.auftragsnummer==Mission.auftragsnummer then self.missionpaused=nil @@ -4222,14 +4222,14 @@ function OPSGROUP:onafterMissionStart(From, Event, To, Mission) -- Route group to mission zone. if self.speedMax>3.6 then - + self:RouteToMission(Mission, 3) - + else --- -- IMMOBILE Group --- - + env.info("FF Immobile GROUP") -- Add waypoint task. UpdateRoute is called inside. @@ -4240,7 +4240,7 @@ function OPSGROUP:onafterMissionStart(From, Event, To, Mission) -- Set waypoint task. Mission:SetGroupWaypointTask(self, Task) - -- Execute task. This calls mission execute. + -- Execute task. This calls mission execute. self:__TaskExecute(3, Task) end @@ -4320,7 +4320,7 @@ function OPSGROUP:onafterUnpauseMission(From, Event, To) self.missionpaused=nil else - self:E(self.lid.."ERROR: No mission to unpause!") + self:T(self.lid.."ERROR: No mission to unpause!") end end @@ -4543,7 +4543,7 @@ function OPSGROUP:RouteToMission(mission, delay) end -- Get ingress waypoint. - if mission.type==AUFTRAG.Type.PATROLZONE or mission.type==AUFTRAG.Type.BARRAGE or mission.type==AUFTRAG.Type.AMMOSUPPLY + if mission.type==AUFTRAG.Type.PATROLZONE or mission.type==AUFTRAG.Type.BARRAGE or mission.type==AUFTRAG.Type.AMMOSUPPLY or mission.type.FUELSUPPLY then local zone=mission.engageTarget:GetObject() --Core.Zone#ZONE waypointcoord=zone:GetRandomCoordinate(nil , nil, surfacetypes) @@ -4552,7 +4552,7 @@ function OPSGROUP:RouteToMission(mission, delay) else waypointcoord=mission:GetMissionWaypointCoord(self.group, randomradius, surfacetypes) end - + local armorwaypointcoord = nil if mission.type==AUFTRAG.Type.ARMORATTACK then local target=mission.engageTarget:GetObject() -- Wrapper.Positionable#POSITIONABLE @@ -4562,7 +4562,7 @@ function OPSGROUP:RouteToMission(mission, delay) -- Ingress - add formation to this one armorwaypointcoord = zone:GetRandomCoordinate(1000, 500, surfacetypes) -- Core.Point#COORDINATE end - + -- Add enroute tasks. for _,task in pairs(mission.enrouteTasks) do self:AddTaskEnroute(task) @@ -5301,7 +5301,7 @@ function OPSGROUP:onbeforeLaserOn(From, Event, To, Target) else -- No target specified. - self:E(self.lid.."ERROR: No target provided for LASER!") + self:T(self.lid.."ERROR: No target provided for LASER!") return false end @@ -5328,7 +5328,7 @@ function OPSGROUP:onbeforeLaserOn(From, Event, To, Target) -- Check LOS. local los=self:HasLoS(self.spot.Coordinate, self.spot.element, self.spot.offset) - --self:I({los=los, coord=self.spot.Coordinate, offset=self.spot.offset}) + --self:T({los=los, coord=self.spot.Coordinate, offset=self.spot.offset}) if los then self:LaserGotLOS() @@ -5342,7 +5342,7 @@ function OPSGROUP:onbeforeLaserOn(From, Event, To, Target) end else - self:E(self.lid.."ERROR: No element alive for lasing") + self:T(self.lid.."ERROR: No element alive for lasing") return false end @@ -5609,7 +5609,7 @@ function OPSGROUP:SetLaserTarget(Target) end else - self:E("WARNING: LASER target is not alive!") + self:T("WARNING: LASER target is not alive!") return end @@ -5620,7 +5620,7 @@ function OPSGROUP:SetLaserTarget(Target) self.spot.offsetTarget={x=0, y=0, z=0} else - self:E(self.lid.."ERROR: LASER target should be a POSITIONABLE (GROUP, UNIT or STATIC) or a COORDINATE object!") + self:T(self.lid.."ERROR: LASER target should be a POSITIONABLE (GROUP, UNIT or STATIC) or a COORDINATE object!") return end @@ -5713,7 +5713,7 @@ function OPSGROUP:_UpdateLaser() if los then -- Got LOS if self.spot.lostLOS then - --self:I({los=self.spot.LOS, coord=self.spot.Coordinate, offset=self.spot.offset}) + --self:T({los=self.spot.LOS, coord=self.spot.Coordinate, offset=self.spot.offset}) self:LaserGotLOS() end @@ -5878,7 +5878,7 @@ end function OPSGROUP:onafterRespawn(From, Event, To, Template) -- Debug info. - self:I(self.lid.."Respawning group!") + self:T(self.lid.."Respawning group!") -- Copy template. local template=UTILS.DeepCopy(Template or self.template) @@ -6148,7 +6148,7 @@ function OPSGROUP:onbeforeStop(From, Event, To) -- We check if if self:IsAlive() then - self:E(self.lid..string.format("WARNING: Group is still alive! Will not stop the FSM. Use :Despawn() instead")) + self:T(self.lid..string.format("WARNING: Group is still alive! Will not stop the FSM. Use :Despawn() instead")) return false end @@ -6205,7 +6205,7 @@ function OPSGROUP:onafterStop(From, Event, To) local life, life0=self:GetLifePoints() local state=self:GetState() local text=string.format("WARNING: Group is still alive! Current state=%s. Life points=%d/%d. Use OPSGROUP:Destroy() or OPSGROUP:Despawn() for a clean stop", state, life, life0) - self:E(self.lid..text) + self:T(self.lid..text) end -- Remove flight from data base. @@ -6249,7 +6249,7 @@ function OPSGROUP:_CheckCargoTransport() if text=="" then text=" empty" end - self:I(self.lid.."Cargo bay:"..text) + self:T(self.lid.."Cargo bay:"..text) end -- Cargo queue debug info. @@ -6274,7 +6274,7 @@ function OPSGROUP:_CheckCargoTransport() end end if text~="" then - self:I(self.lid.."Cargo queue:"..text) + self:T(self.lid.."Cargo queue:"..text) end end @@ -6589,7 +6589,7 @@ function OPSGROUP:_DelCargobay(CargoGroup) return true end - self:E(self.lid.."ERROR: Group is not in cargo bay. Cannot remove it!") + self:T(self.lid.."ERROR: Group is not in cargo bay. Cannot remove it!") return false end @@ -6928,7 +6928,7 @@ function OPSGROUP:GetWeightCargo(UnitName, IncludeReserved) -- Quick check. if IncludeReserved==false and gewicht~=weight then - self:E(self.lid..string.format("ERROR: FF weight!=gewicht: weight=%.1f, gewicht=%.1f", weight, gewicht)) + self:T(self.lid..string.format("ERROR: FF weight!=gewicht: weight=%.1f, gewicht=%.1f", weight, gewicht)) end return gewicht @@ -7262,7 +7262,7 @@ function OPSGROUP:onafterPickup(From, Event, To) local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate, nil, uid, UTILS.MetersToFeet(self.altitudeCruise), false) ; waypoint.detour=1 else - self:E(self.lid.."ERROR: Transportcarrier aircraft cannot land in Pickup zone! Specify a ZONE_AIRBASE as pickup zone") + self:T(self.lid.."ERROR: Transportcarrier aircraft cannot land in Pickup zone! Specify a ZONE_AIRBASE as pickup zone") end -- Cancel landedAt task. This should trigger Cruise once airborne. @@ -7271,7 +7271,7 @@ function OPSGROUP:onafterPickup(From, Event, To) if Task then self:TaskCancel(Task) else - self:E(self.lid.."ERROR: No current task but landed at?!") + self:T(self.lid.."ERROR: No current task but landed at?!") end end @@ -7502,7 +7502,7 @@ function OPSGROUP:onafterLoad(From, Event, To, CargoGroup, Carrier) end else - self:E(self.lid.."ERROR: Cargo has no carrier on Load event!") + self:T(self.lid.."ERROR: Cargo has no carrier on Load event!") end end @@ -7656,7 +7656,7 @@ function OPSGROUP:onafterTransport(From, Event, To) local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid, UTILS.MetersToFeet(self.altitudeCruise), false) ; waypoint.detour=1 else - self:E(self.lid.."ERROR: Aircraft (cargo carrier) cannot land in Deploy zone! Specify a ZONE_AIRBASE as deploy zone") + self:T(self.lid.."ERROR: Aircraft (cargo carrier) cannot land in Deploy zone! Specify a ZONE_AIRBASE as deploy zone") end -- Cancel landedAt task. This should trigger Cruise once airborne. @@ -7665,7 +7665,7 @@ function OPSGROUP:onafterTransport(From, Event, To) if Task then self:TaskCancel(Task) else - self:E(self.lid.."ERROR: No current task but landed at?!") + self:T(self.lid.."ERROR: No current task but landed at?!") end end @@ -7793,7 +7793,7 @@ function OPSGROUP:onafterUnloading(From, Event, To) --- -- Issue warning. - self:E(self.lid.."ERROR: Deploy/disembark zone is a ZONE_AIRBASE of a ship! Where to put the cargo? Dumping into the sea, sorry!") + self:T(self.lid.."ERROR: Deploy/disembark zone is a ZONE_AIRBASE of a ship! Where to put the cargo? Dumping into the sea, sorry!") -- Unload but keep "in utero" (no coordinate provided). self:Unload(cargo.opsgroup) @@ -7992,7 +7992,7 @@ end -- @param #string To To state. -- @param #OPSGROUP OpsGroupCargo Cargo OPSGROUP that was unloaded from a carrier. function OPSGROUP:onafterUnloaded(From, Event, To, OpsGroupCargo) - self:I(self.lid..string.format("Unloaded OPSGROUP %s", OpsGroupCargo:GetName())) + self:T(self.lid..string.format("Unloaded OPSGROUP %s", OpsGroupCargo:GetName())) end @@ -8023,13 +8023,13 @@ function OPSGROUP:onafterUnloadingDone(From, Event, To) if self.cargoTZC then -- Pickup the next batch. - self:I(self.lid.."Unloaded: Still cargo left ==> Pickup") + self:T(self.lid.."Unloaded: Still cargo left ==> Pickup") self:Pickup() else -- Debug info. - self:I(self.lid..string.format("WARNING: Not all cargo was delivered but could not get a transport zone combo ==> setting carrier state to NOT CARRIER")) + self:T(self.lid..string.format("WARNING: Not all cargo was delivered but could not get a transport zone combo ==> setting carrier state to NOT CARRIER")) -- This is not a carrier anymore. self:_NewCarrierStatus(OPSGROUP.CarrierStatus.NOTCARRIER) @@ -8039,7 +8039,7 @@ function OPSGROUP:onafterUnloadingDone(From, Event, To) else -- Everything delivered. - self:I(self.lid.."Unloaded: ALL cargo unloaded ==> Delivered (current)") + self:T(self.lid.."Unloaded: ALL cargo unloaded ==> Delivered (current)") self:Delivered(self.cargoTransport) end @@ -8239,14 +8239,14 @@ end function OPSGROUP:onbeforeBoard(From, Event, To, CarrierGroup, Carrier) if self:IsDead() then - self:I(self.lid.."Group DEAD ==> Deny Board transition!") + self:T(self.lid.."Group DEAD ==> Deny Board transition!") return false elseif CarrierGroup:IsDead() then - self:I(self.lid.."Carrier Group DEAD ==> Deny Board transition!") + self:T(self.lid.."Carrier Group DEAD ==> Deny Board transition!") self:_NewCargoStatus(OPSGROUP.CargoStatus.NOTCARGO) return false elseif Carrier.status==OPSGROUP.ElementStatus.DEAD then - self:I(self.lid.."Carrier Element DEAD ==> Deny Board transition!") + self:T(self.lid.."Carrier Element DEAD ==> Deny Board transition!") self:_NewCargoStatus(OPSGROUP.CargoStatus.NOTCARGO) return false end @@ -8592,7 +8592,7 @@ function OPSGROUP:_CheckGroupDone(delay) self:T(self.lid..string.format("Adinfinitum=TRUE ==> Goto WP index=%d at speed=%d knots", i, speed)) else - self:E(self.lid..string.format("WARNING: No waypoints left! Commanding a Full Stop")) + self:T(self.lid..string.format("WARNING: No waypoints left! Commanding a Full Stop")) self:__FullStop(-1) end @@ -8632,7 +8632,7 @@ function OPSGROUP:_CheckGroupDone(delay) self:T(self.lid..string.format("NOT Passed final WP, #WP>0 ==> Update Route")) self:Cruise() else - self:E(self.lid..string.format("WARNING: No waypoints left! Commanding a Full Stop")) + self:T(self.lid..string.format("WARNING: No waypoints left! Commanding a Full Stop")) self:__FullStop(-1) end @@ -8686,7 +8686,7 @@ function OPSGROUP:_CheckStuck() if holdtime>=5*60 and holdtime<10*60 then -- Debug warning. - self:E(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected for %d sec", speed, ExpectedSpeed, holdtime)) + self:T(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected for %d sec", speed, ExpectedSpeed, holdtime)) -- Give cruise command again. if self:IsReturning() then @@ -8698,14 +8698,14 @@ function OPSGROUP:_CheckStuck() elseif holdtime>=10*60 and holdtime<30*60 then -- Debug warning. - self:E(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected for %d sec", speed, ExpectedSpeed, holdtime)) + self:T(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected for %d sec", speed, ExpectedSpeed, holdtime)) --TODO: Stuck event! -- Look for a current mission and cancel it as we do not seem to be able to perform it. local mission=self:GetMissionCurrent() if mission then - self:E(self.lid..string.format("WARNING: Cancelling mission %s [%s] due to being stuck", mission:GetName(), mission:GetType())) + self:T(self.lid..string.format("WARNING: Cancelling mission %s [%s] due to being stuck", mission:GetName(), mission:GetType())) self:MissionCancel(mission) else -- Give cruise command again. @@ -8719,7 +8719,7 @@ function OPSGROUP:_CheckStuck() elseif holdtime>=30*60 then -- Debug warning. - self:E(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected for %d sec", speed, ExpectedSpeed, holdtime)) + self:T(self.lid..string.format("WARNING: Group came to an unexpected standstill. Speed=%.1f<%.1f m/s expected for %d sec", speed, ExpectedSpeed, holdtime)) end @@ -9137,7 +9137,7 @@ function OPSGROUP:_InitWaypoints(WpIndexMin, WpIndexMax) end else - self:E(self.lid.."WARNING: No waypoints initialized. Number of waypoints is 0!") + self:T(self.lid.."WARNING: No waypoints initialized. Number of waypoints is 0!") end return self @@ -9172,7 +9172,7 @@ function OPSGROUP:Route(waypoints, delay) self:SetTask(DCSTask) else - self:E(self.lid.."ERROR: Group is not alive! Cannot route group.") + self:T(self.lid.."ERROR: Group is not alive! Cannot route group.") end end @@ -9289,7 +9289,7 @@ function OPSGROUP._PassingWaypoint(opsgroup, uid) if (opsgroup:IsNavygroup() or opsgroup:IsArmygroup()) and opsgroup.currentwp==#opsgroup.waypoints then --TODO: not sure if this works with FLIGHTGROUPS - + -- Removing this for now. opsgroup:Cruise() end @@ -9502,7 +9502,7 @@ function OPSGROUP:SwitchROE(roe) if self:IsInUtero() then self:T2(self.lid..string.format("Setting current ROE=%d when GROUP is SPAWNED", self.option.ROE)) else - + self.group:OptionROE(self.option.ROE) self:T(self.lid..string.format("Setting current ROE=%d (%s)", self.option.ROE, self:_GetROEName(self.option.ROE))) @@ -9510,7 +9510,7 @@ function OPSGROUP:SwitchROE(roe) else - self:E(self.lid.."WARNING: Cannot switch ROE! Group is not alive") + self:T(self.lid.."WARNING: Cannot switch ROE! Group is not alive") end return self @@ -9575,7 +9575,7 @@ function OPSGROUP:SwitchROT(rot) else - self:E(self.lid.."WARNING: Cannot switch ROT! Group is not alive") + self:T(self.lid.."WARNING: Cannot switch ROT! Group is not alive") end end @@ -9628,7 +9628,7 @@ function OPSGROUP:SwitchAlarmstate(alarmstate) elseif self.option.Alarm==2 then self.group:OptionAlarmStateRed() else - self:E("ERROR: Unknown Alarm State! Setting to AUTO") + self:T("ERROR: Unknown Alarm State! Setting to AUTO") self.group:OptionAlarmStateAuto() self.option.Alarm=0 end @@ -9639,7 +9639,7 @@ function OPSGROUP:SwitchAlarmstate(alarmstate) end else - self:E(self.lid.."WARNING: Cannot switch Alarm State! Group is not alive.") + self:T(self.lid.."WARNING: Cannot switch Alarm State! Group is not alive.") end return self @@ -9888,11 +9888,11 @@ function OPSGROUP:SwitchTACAN(Channel, Morse, UnitName, Band) self:T(self.lid..string.format("Switching TACAN to Channel %d%s Morse %s on unit %s", self.tacan.Channel, self.tacan.Band, tostring(self.tacan.Morse), self.tacan.BeaconName)) else - self:E(self.lid.."ERROR: Cound not set TACAN! Unit is not alive") + self:T(self.lid.."ERROR: Cound not set TACAN! Unit is not alive") end else - self:E(self.lid.."ERROR: Cound not set TACAN! Group is not alive and not in utero any more") + self:T(self.lid.."ERROR: Cound not set TACAN! Group is not alive and not in utero any more") end return self @@ -10030,7 +10030,7 @@ function OPSGROUP:SwitchICLS(Channel, Morse, UnitName) self:T(self.lid..string.format("Switching ICLS to Channel %d Morse %s on unit %s", self.icls.Channel, tostring(self.icls.Morse), self.icls.BeaconName)) else - self:E(self.lid.."ERROR: Cound not set ICLS! Unit is not alive.") + self:T(self.lid.."ERROR: Cound not set ICLS! Unit is not alive.") end end @@ -10119,7 +10119,7 @@ function OPSGROUP:SwitchRadio(Frequency, Modulation) self:T(self.lid..string.format("Switching radio to frequency %.3f MHz %s", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu))) else - self:E(self.lid.."ERROR: Cound not set Radio! Group is not alive or not in utero any more") + self:T(self.lid.."ERROR: Cound not set Radio! Group is not alive or not in utero any more") end return self @@ -10142,7 +10142,7 @@ function OPSGROUP:TurnOffRadio() self:T(self.lid..string.format("Switching radio OFF")) else - self:E(self.lid.."ERROR: Radio can only be turned off for aircraft!") + self:T(self.lid.."ERROR: Radio can only be turned off for aircraft!") end end @@ -10182,7 +10182,7 @@ function OPSGROUP:SwitchFormation(Formation) -- Polymorphic and overwritten in ARMYGROUP. else - self:E(self.lid.."ERROR: Formation can only be set for aircraft or ground units!") + self:T(self.lid.."ERROR: Formation can only be set for aircraft or ground units!") return self end @@ -10255,7 +10255,7 @@ function OPSGROUP:SwitchCallsign(CallsignName, CallsignNumber) end else - self:E(self.lid.."ERROR: Group is not alive and not in utero! Cannot switch callsign") + self:T(self.lid.."ERROR: Group is not alive and not in utero! Cannot switch callsign") end return self @@ -11101,11 +11101,11 @@ function OPSGROUP:_CoordinateFromObject(Object) local coord=Object:GetCoordinate() return coord else - self:E(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE or ZONE!") + self:T(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE or ZONE!") end end else - self:E(self.lid.."ERROR: Object passed is nil!") + self:T(self.lid.."ERROR: Object passed is nil!") end return nil @@ -11213,8 +11213,8 @@ function OPSGROUP:_AddElementByName(unitname) element.category=unit:GetUnitCategory() element.categoryname=unit:GetCategoryName() element.typename=unit:GetTypeName() - - + + --self:I({desc=element.descriptors}) -- Ammo. @@ -11327,7 +11327,7 @@ function OPSGROUP:_GetTemplate(Copy) end else - self:E(self.lid..string.format("ERROR: No template was set yet!")) + self:T(self.lid..string.format("ERROR: No template was set yet!")) end return nil diff --git a/Moose Development/Moose/Ops/RescueHelo.lua b/Moose Development/Moose/Ops/RescueHelo.lua index 6aaf8d69b..4820b6501 100644 --- a/Moose Development/Moose/Ops/RescueHelo.lua +++ b/Moose Development/Moose/Ops/RescueHelo.lua @@ -802,7 +802,7 @@ function RESCUEHELO:_OnEventCrashOrEject(EventData) -- Debug. local text=string.format("Unit %s crashed or ejected.", unitname) MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug) - self:I(self.lid..text) + self:T(self.lid..text) -- Get coordinate of unit. local coord=unit:GetCoordinate() diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index ea55e3357..a2bff9566 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -409,7 +409,11 @@ end -- @param #number knots Speed in knots. -- @return #number Speed in m/s. UTILS.KnotsToMps = function( knots ) - return knots / 1.94384 --* 1852 / 3600 + if type(knots) == "number" then + return knots / 1.94384 --* 1852 / 3600 + else + return 0 + end end --- Convert temperature from Celsius to Farenheit.