Merge branch 'develop'

This commit is contained in:
FlightControl 2018-10-06 07:56:40 +02:00
commit 8d30dfacd5
9 changed files with 443 additions and 166 deletions

View File

@ -1383,9 +1383,53 @@ do -- COORDINATE
return surface return surface
end end
--- Checks if the surface type is on land.
-- @param #COORDINATE self
-- @return #boolean If true, the surface type at the coordinate is land.
function COORDINATE:IsSurfaceTypeLand()
return self:GetSurfaceType()==land.SurfaceType.LAND
end
--- Checks if the surface type is road.
-- @param #COORDINATE self
-- @return #boolean If true, the surface type at the coordinate is land.
function COORDINATE:IsSurfaceTypeLand()
return self:GetSurfaceType()==land.SurfaceType.LAND
end
--- Checks if the surface type is road.
-- @param #COORDINATE self
-- @return #boolean If true, the surface type at the coordinate is a road.
function COORDINATE:IsSurfaceTypeRoad()
return self:GetSurfaceType()==land.SurfaceType.ROAD
end
--- Checks if the surface type is runway.
-- @param #COORDINATE self
-- @return #boolean If true, the surface type at the coordinate is a runway or taxi way.
function COORDINATE:IsSurfaceTypeRunway()
return self:GetSurfaceType()==land.SurfaceType.RUNWAY
end
--- Checks if the surface type is shallow water.
-- @param #COORDINATE self
-- @return #boolean If true, the surface type at the coordinate is a shallow water.
function COORDINATE:IsSurfaceTypeShallowWater()
return self:GetSurfaceType()==land.SurfaceType.SHALLOW_WATER
end
--- Checks if the surface type is water.
-- @param #COORDINATE self
-- @return #boolean If true, the surface type at the coordinate is a deep water.
function COORDINATE:IsSurfaceTypeWater()
return self:GetSurfaceType()==land.SurfaceType.WATER
end
--- Creates an explosion at the point of a certain intensity. --- Creates an explosion at the point of a certain intensity.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #number ExplosionIntensity -- @param #number ExplosionIntensity Intensity of the explosion in kg TNT.
function COORDINATE:Explosion( ExplosionIntensity ) function COORDINATE:Explosion( ExplosionIntensity )
self:F2( { ExplosionIntensity } ) self:F2( { ExplosionIntensity } )
trigger.action.explosion( self:GetVec3(), ExplosionIntensity ) trigger.action.explosion( self:GetVec3(), ExplosionIntensity )

View File

@ -2431,92 +2431,98 @@ do -- SET_UNIT
-- @return #SET_UNIT self -- @return #SET_UNIT self
function SET_UNIT:IsIncludeObject( MUnit ) function SET_UNIT:IsIncludeObject( MUnit )
self:F2( MUnit ) self:F2( MUnit )
local MUnitInclude = true
local MUnitInclude = false
if MUnit:IsAlive() ~= nil then
if self.Filter.Active ~= nil then MUnitInclude = true
local MUnitActive = false
if self.Filter.Active == false or ( self.Filter.Active == true and MUnit:IsActive() == true ) then
MUnitActive = true
end
MUnitInclude = MUnitInclude and MUnitActive
end
if self.Filter.Coalitions then if self.Filter.Active ~= nil then
local MUnitCoalition = false local MUnitActive = false
for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do if self.Filter.Active == false or ( self.Filter.Active == true and MUnit:IsActive() == true ) then
self:F( { "Coalition:", MUnit:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } ) MUnitActive = true
if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MUnit:GetCoalition() then
MUnitCoalition = true
end end
MUnitInclude = MUnitInclude and MUnitActive
end end
MUnitInclude = MUnitInclude and MUnitCoalition
end
if self.Filter.Categories then if self.Filter.Coalitions then
local MUnitCategory = false local MUnitCoalition = false
for CategoryID, CategoryName in pairs( self.Filter.Categories ) do for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do
self:T3( { "Category:", MUnit:GetDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } ) self:F( { "Coalition:", MUnit:GetCoalition(), self.FilterMeta.Coalitions[CoalitionName], CoalitionName } )
if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MUnit:GetDesc().category then if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MUnit:GetCoalition() then
MUnitCategory = true MUnitCoalition = true
end
end
MUnitInclude = MUnitInclude and MUnitCategory
end
if self.Filter.Types then
local MUnitType = false
for TypeID, TypeName in pairs( self.Filter.Types ) do
self:T3( { "Type:", MUnit:GetTypeName(), TypeName } )
if TypeName == MUnit:GetTypeName() then
MUnitType = true
end
end
MUnitInclude = MUnitInclude and MUnitType
end
if self.Filter.Countries then
local MUnitCountry = false
for CountryID, CountryName in pairs( self.Filter.Countries ) do
self:T3( { "Country:", MUnit:GetCountry(), CountryName } )
if country.id[CountryName] == MUnit:GetCountry() then
MUnitCountry = true
end
end
MUnitInclude = MUnitInclude and MUnitCountry
end
if self.Filter.UnitPrefixes then
local MUnitPrefix = false
for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do
self:T3( { "Prefix:", string.find( MUnit:GetName(), UnitPrefix, 1 ), UnitPrefix } )
if string.find( MUnit:GetName(), UnitPrefix, 1 ) then
MUnitPrefix = true
end
end
MUnitInclude = MUnitInclude and MUnitPrefix
end
if self.Filter.RadarTypes then
local MUnitRadar = false
for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do
self:T3( { "Radar:", RadarType } )
if MUnit:HasSensors( Unit.SensorType.RADAR, RadarType ) == true then
if MUnit:GetRadar() == true then -- This call is necessary to evaluate the SEAD capability.
self:T3( "RADAR Found" )
end end
MUnitRadar = true
end end
MUnitInclude = MUnitInclude and MUnitCoalition
end end
MUnitInclude = MUnitInclude and MUnitRadar
end if self.Filter.Categories then
local MUnitCategory = false
if self.Filter.SEAD then for CategoryID, CategoryName in pairs( self.Filter.Categories ) do
local MUnitSEAD = false self:T3( { "Category:", MUnit:GetDesc().category, self.FilterMeta.Categories[CategoryName], CategoryName } )
if MUnit:HasSEAD() == true then if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MUnit:GetDesc().category then
self:T3( "SEAD Found" ) MUnitCategory = true
MUnitSEAD = true end
end
MUnitInclude = MUnitInclude and MUnitCategory
end
if self.Filter.Types then
local MUnitType = false
for TypeID, TypeName in pairs( self.Filter.Types ) do
self:T3( { "Type:", MUnit:GetTypeName(), TypeName } )
if TypeName == MUnit:GetTypeName() then
MUnitType = true
end
end
MUnitInclude = MUnitInclude and MUnitType
end
if self.Filter.Countries then
local MUnitCountry = false
for CountryID, CountryName in pairs( self.Filter.Countries ) do
self:T3( { "Country:", MUnit:GetCountry(), CountryName } )
if country.id[CountryName] == MUnit:GetCountry() then
MUnitCountry = true
end
end
MUnitInclude = MUnitInclude and MUnitCountry
end
if self.Filter.UnitPrefixes then
local MUnitPrefix = false
for UnitPrefixId, UnitPrefix in pairs( self.Filter.UnitPrefixes ) do
self:T3( { "Prefix:", string.find( MUnit:GetName(), UnitPrefix, 1 ), UnitPrefix } )
if string.find( MUnit:GetName(), UnitPrefix, 1 ) then
MUnitPrefix = true
end
end
MUnitInclude = MUnitInclude and MUnitPrefix
end
if self.Filter.RadarTypes then
local MUnitRadar = false
for RadarTypeID, RadarType in pairs( self.Filter.RadarTypes ) do
self:T3( { "Radar:", RadarType } )
if MUnit:HasSensors( Unit.SensorType.RADAR, RadarType ) == true then
if MUnit:GetRadar() == true then -- This call is necessary to evaluate the SEAD capability.
self:T3( "RADAR Found" )
end
MUnitRadar = true
end
end
MUnitInclude = MUnitInclude and MUnitRadar
end
if self.Filter.SEAD then
local MUnitSEAD = false
if MUnit:HasSEAD() == true then
self:T3( "SEAD Found" )
MUnitSEAD = true
end
MUnitInclude = MUnitInclude and MUnitSEAD
end end
MUnitInclude = MUnitInclude and MUnitSEAD
end end
self:T2( MUnitInclude ) self:T2( MUnitInclude )

View File

@ -5,7 +5,8 @@
-- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to: -- SPOT implements the DCS Spot class functionality, but adds additional luxury to be able to:
-- --
-- * Spot for a defined duration. -- * Spot for a defined duration.
-- * wiggle the spot at the target. -- * Updates of laer spot position every 0.2 seconds for moving targets.
-- * Wiggle the spot at the target.
-- * Provide a @{Wrapper.Unit} as a target, instead of a point. -- * Provide a @{Wrapper.Unit} as a target, instead of a point.
-- * Implement a status machine, LaseOn, LaseOff. -- * Implement a status machine, LaseOn, LaseOff.
-- --
@ -49,7 +50,8 @@ do
--- Implements the target spotting or marking functionality, but adds additional luxury to be able to: --- Implements the target spotting or marking functionality, but adds additional luxury to be able to:
-- --
-- * Mark targets for a defined duration. -- * Mark targets for a defined duration.
-- * wiggle the spot at the target. -- * Updates of laer spot position every 0.2 seconds for moving targets.
-- * Wiggle the spot at the target.
-- * Provide a @{Wrapper.Unit} as a target, instead of a point. -- * Provide a @{Wrapper.Unit} as a target, instead of a point.
-- * Implement a status machine, LaseOn, LaseOff. -- * Implement a status machine, LaseOn, LaseOff.
-- --
@ -85,9 +87,7 @@ do
--- SPOT Constructor. --- SPOT Constructor.
-- @param #SPOT self -- @param #SPOT self
-- @param Wrapper.Unit#UNIT Recce -- @param Wrapper.Unit#UNIT Recce Unit that is lasing
-- @param #number LaserCode
-- @param #number Duration
-- @return #SPOT -- @return #SPOT
function SPOT:New( Recce ) function SPOT:New( Recce )
@ -115,12 +115,17 @@ do
--- LaseOn Trigger for SPOT --- LaseOn Trigger for SPOT
-- @function [parent=#SPOT] LaseOn -- @function [parent=#SPOT] LaseOn
-- @param #SPOT self -- @param #SPOT self
-- @param Wrapper.Positionable#POSITIONABLE Target
-- @param #number LaserCode Laser code.
-- @param #number Duration Duration of lasing in seconds.
--- LaseOn Asynchronous Trigger for SPOT --- LaseOn Asynchronous Trigger for SPOT
-- @function [parent=#SPOT] __LaseOn -- @function [parent=#SPOT] __LaseOn
-- @param #SPOT self -- @param #SPOT self
-- @param #number Delay -- @param #number Delay
-- @param Wrapper.Positionable#POSITIONABLE Target
-- @param #number LaserCode Laser code.
-- @param #number Duration Duration of lasing in seconds.
self:AddTransition( "On", "Lasing", "On" ) self:AddTransition( "On", "Lasing", "On" )
@ -193,9 +198,9 @@ do
-- @param From -- @param From
-- @param Event -- @param Event
-- @param To -- @param To
-- @param Wrapper.Positionable#POSITIONABLE Target -- @param Wrapper.Positionable#POSITIONABLE Target Unit that is being lased.
-- @param #number LaserCode -- @param #number LaserCode Laser code.
-- @param #number Duration -- @param #number Duration Duration of lasing in seconds.
function SPOT:onafterLaseOn( From, Event, To, Target, LaserCode, Duration ) function SPOT:onafterLaseOn( From, Event, To, Target, LaserCode, Duration )
self:F( { "LaseOn", Target, LaserCode, Duration } ) self:F( { "LaseOn", Target, LaserCode, Duration } )

View File

@ -597,8 +597,15 @@ ARTY={
autorelocateonroad=false, autorelocateonroad=false,
} }
--- Weapong type ID. http://wiki.hoggit.us/view/DCS_enum_weapon_flag --- Weapong type ID. See [here](http://wiki.hoggit.us/view/DCS_enum_weapon_flag).
-- @list WeaponType -- @type ARTY.WeaponType
-- @field #number Auto Automatic selection of weapon type.
-- @field #number Cannon Cannons using conventional shells.
-- @field #number Rockets Unguided rockets.
-- @field #number CruiseMissile Cruise missiles.
-- @field #number TacticalNukes Tactical nuclear shells (simulated).
-- @field #number IlluminationShells Illumination shells (simulated).
-- @field #number SmokeShells Smoke shells (simulated).
ARTY.WeaponType={ ARTY.WeaponType={
Auto=1073741822, Auto=1073741822,
Cannon=805306368, Cannon=805306368,
@ -610,7 +617,7 @@ ARTY.WeaponType={
} }
--- Database of common artillery unit properties. --- Database of common artillery unit properties.
-- @list db -- @type ARTY.db
ARTY.db={ ARTY.db={
["2B11 mortar"] = { -- type "2B11 mortar" ["2B11 mortar"] = { -- type "2B11 mortar"
minrange = 500, -- correct? minrange = 500, -- correct?
@ -675,7 +682,7 @@ ARTY.id="ARTY | "
--- Arty script version. --- Arty script version.
-- @field #string version -- @field #string version
ARTY.version="1.0.5" ARTY.version="1.0.6"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -1189,7 +1196,14 @@ function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage, time, w
end end
-- Time in seconds. -- Time in seconds.
local _time=self:_ClockToSeconds(time) local _time
if type(time)=="string" then
_time=self:_ClockToSeconds(time)
elseif type(time)=="number" then
_time=timer.getAbsTime()+time
else
_time=timer.getAbsTime()
end
-- Prepare target array. -- Prepare target array.
local _target={name=_name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio, maxengage=maxengage, time=_time, weapontype=weapontype} local _target={name=_name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio, maxengage=maxengage, time=_time, weapontype=weapontype}
@ -1240,9 +1254,6 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name, unique)
return nil return nil
end end
-- Default is current time if no time was specified.
time=time or self:_SecondsToClock(timer.getAbsTime())
-- Set speed. -- Set speed.
if speed then if speed then
-- Make sure, given speed is less than max physiaclly possible speed of group. -- Make sure, given speed is less than max physiaclly possible speed of group.
@ -1264,7 +1275,14 @@ function ARTY:AssignMoveCoord(coord, time, speed, onroad, cancel, name, unique)
end end
-- Time in seconds. -- Time in seconds.
local _time=self:_ClockToSeconds(time) local _time
if type(time)=="string" then
_time=self:_ClockToSeconds(time)
elseif type(time)=="number" then
_time=timer.getAbsTime()+time
else
_time=timer.getAbsTime()
end
-- Prepare move array. -- Prepare move array.
local _move={name=_name, coord=coord, time=_time, speed=speed, onroad=onroad, cancel=cancel} local _move={name=_name, coord=coord, time=_time, speed=speed, onroad=onroad, cancel=cancel}

View File

@ -112,6 +112,20 @@ function CLEANUP_AIRBASE:New( AirbaseNames )
self:HandleEvent( EVENTS.PilotDead, self.__.OnEventCrash ) self:HandleEvent( EVENTS.PilotDead, self.__.OnEventCrash )
self:HandleEvent( EVENTS.Dead, self.__.OnEventCrash ) self:HandleEvent( EVENTS.Dead, self.__.OnEventCrash )
self:HandleEvent( EVENTS.Crash, self.__.OnEventCrash ) self:HandleEvent( EVENTS.Crash, self.__.OnEventCrash )
for UnitName, Unit in pairs( _DATABASE.UNITS ) do
local Unit = Unit -- Wrapper.Unit#UNIT
if Unit:IsAlive() ~= nil then
if self:IsInAirbase( Unit:GetVec2() ) then
self:F( { UnitName = UnitName } )
self.CleanUpList[UnitName] = {}
self.CleanUpList[UnitName].CleanUpUnit = Unit
self.CleanUpList[UnitName].CleanUpGroup = Unit:GetGroup()
self.CleanUpList[UnitName].CleanUpGroupName = Unit:GetGroup():GetName()
self.CleanUpList[UnitName].CleanUpUnitName = Unit:GetName()
end
end
end
return self return self
end end
@ -213,11 +227,15 @@ end
function CLEANUP_AIRBASE.__:OnEventBirth( EventData ) function CLEANUP_AIRBASE.__:OnEventBirth( EventData )
self:F( { EventData } ) self:F( { EventData } )
self.CleanUpList[EventData.IniDCSUnitName] = {} if EventData.IniUnit:IsAlive() ~= nil then
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnit = EventData.IniUnit if self:IsInAirbase( EventData.IniUnit:GetVec2() ) then
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroup = EventData.IniGroup self.CleanUpList[EventData.IniDCSUnitName] = {}
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroupName = EventData.IniDCSGroupName self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnit = EventData.IniUnit
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnitName = EventData.IniDCSUnitName self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroup = EventData.IniGroup
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroupName = EventData.IniDCSGroupName
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnitName = EventData.IniDCSUnitName
end
end
end end
@ -349,45 +367,50 @@ function CLEANUP_AIRBASE.__:CleanUpSchedule()
local CleanUpGroupName = CleanUpListData.CleanUpGroupName local CleanUpGroupName = CleanUpListData.CleanUpGroupName
if CleanUpUnit:IsAlive() ~= nil then if CleanUpUnit:IsAlive() ~= nil then
if self:IsInAirbase( CleanUpUnit:GetVec2() ) then
if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then
local CleanUpCoordinate = CleanUpUnit:GetCoordinate() local CleanUpCoordinate = CleanUpUnit:GetCoordinate()
self:T( { "CleanUp Scheduler", CleanUpUnitName } ) self:T( { "CleanUp Scheduler", CleanUpUnitName } )
if CleanUpUnit:GetLife() <= CleanUpUnit:GetLife0() * 0.95 then if CleanUpUnit:GetLife() <= CleanUpUnit:GetLife0() * 0.95 then
if CleanUpUnit:IsAboveRunway() then if CleanUpUnit:IsAboveRunway() then
if CleanUpUnit:InAir() then if CleanUpUnit:InAir() then
local CleanUpLandHeight = CleanUpCoordinate:GetLandHeight() local CleanUpLandHeight = CleanUpCoordinate:GetLandHeight()
local CleanUpUnitHeight = CleanUpCoordinate.y - CleanUpLandHeight local CleanUpUnitHeight = CleanUpCoordinate.y - CleanUpLandHeight
if CleanUpUnitHeight < 100 then if CleanUpUnitHeight < 100 then
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because below safe height and damaged." } ) self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because below safe height and damaged." } )
self:DestroyUnit( CleanUpUnit ) self:DestroyUnit( CleanUpUnit )
end end
else else
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because on runway and damaged." } ) self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because on runway and damaged." } )
self:DestroyUnit( CleanUpUnit ) self:DestroyUnit( CleanUpUnit )
end end
end end
end end
-- Clean Units which are waiting for a very long time in the CleanUpZone. -- Clean Units which are waiting for a very long time in the CleanUpZone.
if CleanUpUnit then if CleanUpUnit and not CleanUpUnit:GetPlayerName() then
local CleanUpUnitVelocity = CleanUpUnit:GetVelocityKMH() local CleanUpUnitVelocity = CleanUpUnit:GetVelocityKMH()
if CleanUpUnitVelocity < 1 then if CleanUpUnitVelocity < 1 then
if CleanUpListData.CleanUpMoved then if CleanUpListData.CleanUpMoved then
if CleanUpListData.CleanUpTime + 180 <= timer.getTime() then if CleanUpListData.CleanUpTime + 180 <= timer.getTime() then
self:T( { "CleanUp Scheduler", "Destroy due to not moving anymore " .. CleanUpUnitName } ) self:T( { "CleanUp Scheduler", "Destroy due to not moving anymore " .. CleanUpUnitName } )
self:DestroyUnit( CleanUpUnit ) self:DestroyUnit( CleanUpUnit )
end end
end end
else else
CleanUpListData.CleanUpTime = timer.getTime() CleanUpListData.CleanUpTime = timer.getTime()
CleanUpListData.CleanUpMoved = true CleanUpListData.CleanUpMoved = true
end end
end end
else
-- not anymore in an airbase zone, remove from cleanup list.
self.CleanUpList[CleanUpUnitName] = nil
end
else else
-- Do nothing ... -- Do nothing ...
self.CleanUpList[CleanUpUnitName] = nil self.CleanUpList[CleanUpUnitName] = nil

View File

@ -24,7 +24,7 @@
-- ### Co-author: FlightControl (cargo dispatcher classes) -- ### Co-author: FlightControl (cargo dispatcher classes)
-- --
-- @module Functional.Warehouse -- @module Functional.Warehouse
-- @image Warehouse.JPG -- @image MOOSE.JPG
--- WAREHOUSE class. --- WAREHOUSE class.
-- @type WAREHOUSE -- @type WAREHOUSE
@ -60,6 +60,8 @@
-- --
-- === -- ===
-- --
-- ![Banner Image](..\Presentations\WAREHOUSE\Warehouse_Main.png)
--
-- # The Warehouse Concept -- # The Warehouse Concept
-- --
-- The MOOSE warehouse adds a new logistic component to the DCS World. *Assets*, i.e. ground, airborne and naval units, can be transferred from one place -- The MOOSE warehouse adds a new logistic component to the DCS World. *Assets*, i.e. ground, airborne and naval units, can be transferred from one place
@ -604,6 +606,7 @@
-- * "Attacked" --> "Captured" --> "Running" (warehouse was captured by the enemy) -- * "Attacked" --> "Captured" --> "Running" (warehouse was captured by the enemy)
-- * "*" --> "AirbaseCaptured" --> "*" (airbase belonging to the warehouse was captured by the enemy) -- * "*" --> "AirbaseCaptured" --> "*" (airbase belonging to the warehouse was captured by the enemy)
-- * "*" --> "AirbaseRecaptured" --> "*" (airbase was re-captured) -- * "*" --> "AirbaseRecaptured" --> "*" (airbase was re-captured)
-- * "*" --> "AssetDead" --> "*" (a whole asset group is dead)
-- * "*" --> "Destroyed" --> "Destroyed" (warehouse was destroyed) -- * "*" --> "Destroyed" --> "Destroyed" (warehouse was destroyed)
-- * "Running" --> "Pause" --> "Paused" (warehouse is paused) -- * "Running" --> "Pause" --> "Paused" (warehouse is paused)
-- * "Paused" --> "Unpause" --> "Running" (warehouse is unpaused) -- * "Paused" --> "Unpause" --> "Running" (warehouse is unpaused)
@ -870,7 +873,7 @@
-- --
-- -- Big explosion at the warehose. It has a very nice damage model by the way :) -- -- Big explosion at the warehose. It has a very nice damage model by the way :)
-- local function DestroyWarehouse() -- local function DestroyWarehouse()
-- warehouse.Batumi.warehouse:GetCoordinate():Explosion(999) -- warehouse.Batumi:GetCoordinate():Explosion(999)
-- end -- end
-- SCHEDULER:New(nil, DestroyWarehouse, {}, 30) -- SCHEDULER:New(nil, DestroyWarehouse, {}, 30)
-- --
@ -933,9 +936,9 @@
-- -- Get Number of ships at Batumi. -- -- Get Number of ships at Batumi.
-- local nships=warehouse.Batumi:GetNumberOfAssets(WAREHOUSE.Descriptor.CATEGORY, Group.Category.SHIP) -- local nships=warehouse.Batumi:GetNumberOfAssets(WAREHOUSE.Descriptor.CATEGORY, Group.Category.SHIP)
-- --
-- -- Send one ship every 5 minutes. -- -- Send one ship every 3 minutes (ships do not evade each other well, so we need a bit space between them).
-- for i=1, nships do -- for i=1, nships do
-- warehouse.Batumi:__AddRequest(300*(i-1)+10, warehouse.Kobuleti, WAREHOUSE.Descriptor.CATEGORY, Group.Category.SHIP, 1) -- warehouse.Batumi:__AddRequest(180*(i-1)+10, warehouse.Kobuleti, WAREHOUSE.Descriptor.CATEGORY, Group.Category.SHIP, 1)
-- end -- end
-- --
-- ## Example 10: Warehouse on Aircraft Carrier -- ## Example 10: Warehouse on Aircraft Carrier
@ -998,8 +1001,7 @@
-- warehouse.Stennis:__AddRequest(45, warehouse.Stennis, WAREHOUSE.Descriptor.ATTRIBUTE, WAREHOUSE.Attribute.NAVAL_ARMEDSHIP, 5, nil, nil, nil, "Speedboats Right") -- warehouse.Stennis:__AddRequest(45, warehouse.Stennis, WAREHOUSE.Descriptor.ATTRIBUTE, WAREHOUSE.Attribute.NAVAL_ARMEDSHIP, 5, nil, nil, nil, "Speedboats Right")
-- --
-- --- Function called after self request -- --- Function called after self request
-- function warehouse.Stennis:OnAfterSelfRequest(From, Event, To,_groupset, request) -- function warehouse.Stennis:OnAfterSelfRequest(From, Event, To,_groupset, request)
--
-- local groupset=_groupset --Core.Set#SET_GROUP -- local groupset=_groupset --Core.Set#SET_GROUP
-- local request=request --Functional.Warehouse#WAREHOUSE.Pendingitem -- local request=request --Functional.Warehouse#WAREHOUSE.Pendingitem
-- --
@ -1214,15 +1216,14 @@
-- for _,_group in pairs(groupset:GetSet()) do -- for _,_group in pairs(groupset:GetSet()) do
-- local group=_group --Wrapper.Group#GROUP -- local group=_group --Wrapper.Group#GROUP
-- --
-- -- Start uncontrolled aircraft.
-- group:StartUncontrolled() -- group:StartUncontrolled()
-- group:SmokeBlue()
-- --
-- -- Target coordinate! -- -- Target coordinate!
-- local ToCoord=warehouse.Sukhumi:GetCoordinate() -- local ToCoord=warehouse.Sukhumi:GetCoordinate():SetAltitude(5000)
-- ToCoord.y=5000 -- Adjust altitude
-- --
-- local FoCoord=warehouse.Kobuleti:GetCoordinate() -- -- Home coordinate.
-- FoCoord.y=3000 -- Ajust altitude. -- local HomeCoord=warehouse.Kobuleti:GetCoordinate():SetAltitude(3000)
-- --
-- -- Task bomb Sukhumi warehouse using all bombs (2032) from direction 180 at altitude 5000 m. -- -- Task bomb Sukhumi warehouse using all bombs (2032) from direction 180 at altitude 5000 m.
-- local task=group:TaskBombing(warehouse.Sukhumi:GetCoordinate():GetVec2(), false, "All", nil , 180, 5000, 2032) -- local task=group:TaskBombing(warehouse.Sukhumi:GetCoordinate():GetVec2(), false, "All", nil , 180, 5000, 2032)
@ -1235,7 +1236,7 @@
-- -- Begin bombing run 20 km south of target. -- -- Begin bombing run 20 km south of target.
-- WayPoints[2]=ToCoord:Translate(20*1000, 180):WaypointAirTurningPoint(nil, 600, {task}, "Bombing Run") -- WayPoints[2]=ToCoord:Translate(20*1000, 180):WaypointAirTurningPoint(nil, 600, {task}, "Bombing Run")
-- -- Return to base. -- -- Return to base.
-- WayPoints[3]=FoCoord:WaypointAirTurningPoint() -- WayPoints[3]=HomeCoord:WaypointAirTurningPoint()
-- -- Land at homebase. Bombers are added back to stock and can be employed in later assignments. -- -- Land at homebase. Bombers are added back to stock and can be employed in later assignments.
-- WayPoints[4]=warehouse.Kobuleti:GetCoordinate():WaypointAirLanding() -- WayPoints[4]=warehouse.Kobuleti:GetCoordinate():WaypointAirLanding()
-- --
@ -1260,6 +1261,7 @@
-- -- Define a polygon zone as spawn zone at Kobuleti. -- -- Define a polygon zone as spawn zone at Kobuleti.
-- warehouse.Kobuleti:SetSpawnZone(ZONE_POLYGON:New("Warehouse Kobuleti Spawn Zone", GROUP:FindByName("Warehouse Kobuleti Spawn Zone"))) -- warehouse.Kobuleti:SetSpawnZone(ZONE_POLYGON:New("Warehouse Kobuleti Spawn Zone", GROUP:FindByName("Warehouse Kobuleti Spawn Zone")))
-- --
-- -- Add assets.
-- warehouse.Kobuleti:AddAsset("M978", 20) -- warehouse.Kobuleti:AddAsset("M978", 20)
-- warehouse.London:AddAsset("M818", 20) -- warehouse.London:AddAsset("M818", 20)
-- --
@ -1273,6 +1275,70 @@
-- -- Kobuleti requests all available trucks from London. -- -- Kobuleti requests all available trucks from London.
-- warehouse.London:AddRequest(warehouse.Kobuleti, WAREHOUSE.Descriptor.ATTRIBUTE, WAREHOUSE.Attribute.GROUND_TRUCK, WAREHOUSE.Quantity.HALF) -- warehouse.London:AddRequest(warehouse.Kobuleti, WAREHOUSE.Descriptor.ATTRIBUTE, WAREHOUSE.Attribute.GROUND_TRUCK, WAREHOUSE.Quantity.HALF)
-- --
--## Example 16 Resupply of Dead Assets
--
-- Warehouse at FARP Berlin is located at the front line and sends infantry groups to the battle zone.
-- Whenever a group dies, a new group is send from the warehouse to the battle zone.
-- Additionally, for each dead group, Berlin requests resupply from Batumi.
--
-- -- Start warehouses.
-- warehouse.Batumi:Start()
-- warehouse.Berlin:Start()
--
-- -- Front line warehouse.
-- warehouse.Berlin:AddAsset("Infantry Platoon Alpha", 6)
--
-- -- Resupply warehouse.
-- warehouse.Batumi:AddAsset("Infantry Platoon Alpha", 50)
--
-- -- Battle zone near FARP Berlin. This is where the action is!
-- local BattleZone=ZONE:New("Virtual Battle Zone")
--
-- -- Send infantry groups to the battle zone. Two groups every ~60 seconds.
-- for i=1,2 do
-- local time=(i-1)*60+10
-- warehouse.Berlin:__AddRequest(time, warehouse.Berlin, WAREHOUSE.Descriptor.ATTRIBUTE, WAREHOUSE.Attribute.GROUND_INFANTRY, 2, nil, nil, nil, "To Battle Zone")
-- end
--
-- -- Take care of the spawned units.
-- function warehouse.Berlin:OnAfterSelfRequest(From,Event,To,groupset,request)
-- local groupset=groupset --Core.Set#SET_GROUP
-- local request=request --Functional.Warehouse#WAREHOUSE.Pendingitem
--
-- -- Get assignment of this request.
-- local assignment=warehouse.Berlin:GetAssignment(request)
--
-- if assignment=="To Battle Zone" then
--
-- for _,group in pairs(groupset:GetSet()) do
-- local group=group --Wrapper.Group#GROUP
--
-- -- Route group to Battle zone.
-- local ToCoord=BattleZone:GetRandomCoordinate()
-- group:RouteGroundOnRoad(ToCoord, group:GetSpeedMax()*0.8)
--
-- -- After 3-5 minutes we create an explosion to destroy the group.
-- SCHEDULER:New(nil, Explosion, {group, 50}, math.random(180, 300))
-- end
--
-- end
--
-- end
--
-- -- An asset has died ==> request resupply for it.
-- function warehouse.Berlin:OnAfterAssetDead(From, Event, To, asset, request)
-- local asset=asset --Functional.Warehouse#WAREHOUSE.Assetitem
-- local request=request --Functional.Warehouse#WAREHOUSE.Pendingitem
--
-- -- Get assignment.
-- local assignment=warehouse.Berlin:GetAssignment(request)
--
-- -- Request resupply for dead asset from Batumi.
-- warehouse.Batumi:AddRequest(warehouse.Berlin, WAREHOUSE.Descriptor.ATTRIBUTE, asset.attribute, nil, nil, nil, nil, "Resupply")
--
-- -- Send asset to Battle zone either now or when they arrive.
-- warehouse.Berlin:AddRequest(warehouse.Berlin, WAREHOUSE.Descriptor.ATTRIBUTE, asset.attribute, 1, nil, nil, nil, assignment)
-- end
-- --
-- @field #WAREHOUSE -- @field #WAREHOUSE
WAREHOUSE = { WAREHOUSE = {
@ -1348,6 +1414,7 @@ WAREHOUSE = {
--- Item of the warehouse pending queue table. --- Item of the warehouse pending queue table.
-- @type WAREHOUSE.Pendingitem -- @type WAREHOUSE.Pendingitem
-- @field #number timestamp Absolute mission time in seconds when the request was processed. -- @field #number timestamp Absolute mission time in seconds when the request was processed.
-- @field #table assetproblem Table with assets that might have problems (damage or stuck).
-- @field Core.Set#SET_GROUP cargogroupset Set of cargo groups do be delivered. -- @field Core.Set#SET_GROUP cargogroupset Set of cargo groups do be delivered.
-- @field #number ndelivered Number of groups delivered to destination. -- @field #number ndelivered Number of groups delivered to destination.
-- @field Core.Set#SET_GROUP transportgroupset Set of cargo transport carrier groups. -- @field Core.Set#SET_GROUP transportgroupset Set of cargo transport carrier groups.
@ -1469,7 +1536,7 @@ WAREHOUSE.db = {
--- Warehouse class version. --- Warehouse class version.
-- @field #string version -- @field #string version
WAREHOUSE.version="0.5.5" WAREHOUSE.version="0.5.8"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Warehouse todo list. -- TODO: Warehouse todo list.
@ -2584,6 +2651,8 @@ function WAREHOUSE:onafterStart(From, Event, To)
self.spawnzone:BoundZone(30, self.country) self.spawnzone:BoundZone(30, self.country)
]] ]]
--self.spawnzone:GetCoordinate():MarkToCoalition(string.format("Warehouse %s spawn zone", self.alias), self:GetCoalition())
-- Get the closest point on road wrt spawnzone of ground assets. -- Get the closest point on road wrt spawnzone of ground assets.
local _road=self.spawnzone:GetCoordinate():GetClosestPointToRoad() local _road=self.spawnzone:GetCoordinate():GetClosestPointToRoad()
if _road and self.road==nil then if _road and self.road==nil then
@ -2630,7 +2699,6 @@ function WAREHOUSE:onafterStart(From, Event, To)
-- Start the status monitoring. -- Start the status monitoring.
self:__Status(-1) self:__Status(-1)
end end
--- On after "Stop" event. Stops the warehouse, unhandles all events. --- On after "Stop" event. Stops the warehouse, unhandles all events.
@ -2912,6 +2980,84 @@ function WAREHOUSE:_JobDone()
self:_DeleteQueueItem(request, self.pending) self:_DeleteQueueItem(request, self.pending)
end end
end end
--- Function that checks if an asset group is still okay.
-- @param #WAREHOUSE self
function WAREHOUSE:_CheckAssetStatus()
-- Check if a unit of the group has problems.
local function _CheckGroup(_request, _group)
local request=_request --#WAREHOUSE.Pendingitem
local group=_group --Wrapper.Group#GROUP
if group and group:IsAlive() then
-- Category of group.
local category=group:GetCategory()
for _,_unit in pairs(group:GetUnits()) do
local unit=_unit --Wrapper.Unit#UNIT
if unit and unit:IsAlive() then
local unitid=unit:GetID()
local life9=unit:GetLife()
local life0=unit:GetLife0()
local life=life9/life0*100
local speed=unit:GetVelocityMPS()
local onground=unit:InAir()
local problem=false
if life<10 then
self:T(string.format("Unit %s is heavily damaged!", unit:GetName()))
end
if speed<1 and unit:GetSpeedMax()>1 and onground then
self:T(string.format("Unit %s is not moving!", unit:GetName()))
problem=true
end
if problem then
if request.assetproblem[unitid] then
local deltaT=timer.getAbsTime()-request.assetproblem[unitid]
if deltaT>300 then
--Todo: which event to generate? Removeunit or Dead/Creash or both?
unit:Destroy()
end
else
request.assetproblem[unitid]=timer.getAbsTime()
end
end
end
end
end
end
for _,request in pairs(self.pending) do
local request=request --#WAREHOUSE.Pendingitem
-- Cargo groups.
if request.cargogroupset then
for _,_group in pairs(request.cargogroupset:GetSet()) do
local group=_group --Wrapper.Group#GROUP
_CheckGroup(request, group)
end
end
-- Transport groups.
if request.transportgroupset then
for _,group in pairs(request.transportgroupset:GetSet()) do
_CheckGroup(request, group)
end
end
end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after "AddAsset" event. Add a group to the warehouse stock. If the group is alive, it is destroyed. --- On after "AddAsset" event. Add a group to the warehouse stock. If the group is alive, it is destroyed.
@ -3388,6 +3534,9 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request)
-- Set time stamp. -- Set time stamp.
Pending.timestamp=timer.getAbsTime() Pending.timestamp=timer.getAbsTime()
-- Init problem table.
Pending.assetproblem={}
-- Spawn assets of this request. -- Spawn assets of this request.
local _spawngroups=self:_SpawnAssetRequest(Pending) --Core.Set#SET_GROUP local _spawngroups=self:_SpawnAssetRequest(Pending) --Core.Set#SET_GROUP
@ -5234,6 +5383,11 @@ function WAREHOUSE:_CheckConquered()
end end
elseif self:GetCoalition()==coalition.side.NEUTRAL then elseif self:GetCoalition()==coalition.side.NEUTRAL then
-- Neutrals dont attack! -- Neutrals dont attack!
if self:IsRunning() and Nred>0 then
self:Attacked(coalition.side.RED, CountryRed)
elseif self:IsRunning() and Nblue>0 then
self:Attacked(coalition.side.BLUE, CountryBlue)
end
end end
end end
@ -5439,13 +5593,21 @@ function WAREHOUSE:_CheckRequestValid(request)
end end
elseif asset_ground then elseif asset_ground then
-- Check that both spawn zones are not in water.
local inwater=self.spawnzone:GetCoordinate():IsSurfaceTypeWater() or request.warehouse.spawnzone:GetCoordinate():IsSurfaceTypeWater()
if inwater then
self:E("ERROR: Incorrect request. Ground asset requested but at least one spawn zone is in water!")
valid=false
end
-- No ground assets directly to or from ships. -- No ground assets directly to or from ships.
-- TODO: May needs refinement if warehouse is on land and requestor is ship in harbour?! -- TODO: May needs refinement if warehouse is on land and requestor is ship in harbour?!
if (requestcategory==Airbase.Category.SHIP or self:GetAirbaseCategory()==Airbase.Category.SHIP) then --if (requestcategory==Airbase.Category.SHIP or self:GetAirbaseCategory()==Airbase.Category.SHIP) then
self:E("ERROR: Incorrect request. Ground asset requested but warehouse or requestor is SHIP!") -- self:E("ERROR: Incorrect request. Ground asset requested but warehouse or requestor is SHIP!")
valid=false -- valid=false
end --end
if asset_train then if asset_train then
@ -5633,7 +5795,6 @@ function WAREHOUSE:_CheckRequestNow(request)
-- Check if number of requested assets is in stock. -- Check if number of requested assets is in stock.
local _assets,_nassets,_enough=self:_FilterStock(self.stock, request.assetdesc, request.assetdescval, request.nasset, onlymobile) local _assets,_nassets,_enough=self:_FilterStock(self.stock, request.assetdesc, request.assetdescval, request.nasset, onlymobile)
local _transports
-- Check if enough assets are in stock. -- Check if enough assets are in stock.
if not _enough then if not _enough then
@ -5643,13 +5804,17 @@ function WAREHOUSE:_CheckRequestNow(request)
self:T(self.wid..text) self:T(self.wid..text)
return false return false
end end
local _transports
local _assetattribute
local _assetcategory
-- Check if at least one (cargo) asset is available. -- Check if at least one (cargo) asset is available.
if _nassets>0 then if _nassets>0 then
-- Get the attibute of the requested asset. -- Get the attibute of the requested asset.
local _assetattribute=_assets[1].attribute _assetattribute=_assets[1].attribute
local _assetcategory=_assets[1].category _assetcategory=_assets[1].category
-- Check available parking for air asset units. -- Check available parking for air asset units.
if self.airbase and (_assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER) then if self.airbase and (_assetcategory==Group.Category.AIRPLANE or _assetcategory==Group.Category.HELICOPTER) then
@ -5707,7 +5872,23 @@ function WAREHOUSE:_CheckRequestNow(request)
else else
-- Self propelled case. Nothing to do for now. -- Self propelled case. Nothing to do for now.
-- Ground asset checks.
if _assetcategory==Group.Category.GROUND then
-- Distance between warehouse and spawn zone.
local dist=self.warehouse:GetCoordinate():Get2DDistance(request.warehouse.spawnzone:GetCoordinate())
-- Check min dist to spawn zone.
if dist>5000 then
-- Not close enough to spawn zone.
local text=string.format("Warehouse %s: Request denied! Not close enough to spawn zone. Distance = %d m. We need to be at least within 5000 m range to spawn.", self.alias, dist)
self:_InfoMessage(text, 5)
return false
end
end
end end

View File

@ -623,10 +623,8 @@ end
-- @return #CONTROLLABLE self -- @return #CONTROLLABLE self
function CONTROLLABLE:StartUncontrolled(delay) function CONTROLLABLE:StartUncontrolled(delay)
if delay and delay>0 then if delay and delay>0 then
env.info(string.format("FF %s delayed start after %d seconds", self:GetName(), delay))
SCHEDULER:New(nil, CONTROLLABLE.StartUncontrolled, {self}, delay) SCHEDULER:New(nil, CONTROLLABLE.StartUncontrolled, {self}, delay)
else else
env.info(string.format("FF %s instant start", self:GetName()))
self:SetCommand({id='Start', params={}}) self:SetCommand({id='Start', params={}})
end end
return self return self
@ -1079,10 +1077,10 @@ end
-- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders. -- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders.
-- The unit / controllable will also protect that controllable from threats of specified types. -- The unit / controllable will also protect that controllable from threats of specified types.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @param Wrapper.Controllable#CONTROLLABLE EscortControllable The controllable to be escorted. -- @param Wrapper.Controllable#CONTROLLABLE FollowControllable The controllable to be escorted.
-- @param DCS#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around. -- @param DCS#Vec3 Vec3 Position of the unit / lead unit of the controllable relative lead unit of another controllable in frame reference oriented by course of lead unit of another controllable. If another controllable is on land the unit / controllable will orbit around.
-- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished. -- @param #number LastWaypointIndex Detach waypoint of another controllable. Once reached the unit / controllable Follow task is finished.
-- @param #number EngagementDistanceMax Maximal distance from escorted controllable to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax. -- @param #number EngagementDistance Maximal distance from escorted controllable to threat. If the threat is already engaged by escort escort will disengage if the distance becomes greater than 1.5 * engagementDistMax.
-- @param DCS#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage. -- @param DCS#AttributeNameArray TargetTypes Array of AttributeName that is contains threat categories allowed to engage.
-- @return DCS#Task The DCS task structure. -- @return DCS#Task The DCS task structure.
function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes ) function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, EngagementDistance, TargetTypes )
@ -1105,6 +1103,8 @@ function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, E
LastWaypointIndexFlag = true LastWaypointIndexFlag = true
end end
TargetTypes=TargetTypes or {}
local DCSTask local DCSTask
DCSTask = { id = 'Escort', DCSTask = { id = 'Escort',
params = { params = {