mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Warehouse 0.1.9w
This commit is contained in:
@@ -729,6 +729,20 @@ do -- COORDINATE
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the heading from this to another coordinate.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #COORDINATE ToCoordinate
|
||||||
|
-- @return #number Heading in degrees.
|
||||||
|
function COORDINATE:HeadingTo(ToCoordinate)
|
||||||
|
local dz=ToCoordinate.z-self.z
|
||||||
|
local dx=ToCoordinate.x-self.x
|
||||||
|
local heading=math.deg(math.atan2(dz, dx))
|
||||||
|
if heading < 0 then
|
||||||
|
heading = 360 + heading
|
||||||
|
end
|
||||||
|
return heading
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns the wind direction (from) and strength.
|
--- Returns the wind direction (from) and strength.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground.
|
-- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground.
|
||||||
@@ -949,21 +963,53 @@ do -- COORDINATE
|
|||||||
-- @param #COORDINATE.WaypointAction Action The route point action.
|
-- @param #COORDINATE.WaypointAction Action The route point action.
|
||||||
-- @param DCS#Speed Speed Airspeed in km/h. Default is 500 km/h.
|
-- @param DCS#Speed Speed Airspeed in km/h. Default is 500 km/h.
|
||||||
-- @param #boolean SpeedLocked true means the speed is locked.
|
-- @param #boolean SpeedLocked true means the speed is locked.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE airbase The airbase for takeoff and landing points.
|
||||||
|
-- @param #table DCSTasks A table of DCS#Task items which are executed at the waypoint.
|
||||||
|
-- @param #string description A text description of the waypoint, which will be shown on the F10 map.
|
||||||
-- @return #table The route point.
|
-- @return #table The route point.
|
||||||
function COORDINATE:WaypointAir( AltType, Type, Action, Speed, SpeedLocked )
|
function COORDINATE:WaypointAir( AltType, Type, Action, Speed, SpeedLocked, airbase, DCSTasks, description )
|
||||||
self:F2( { AltType, Type, Action, Speed, SpeedLocked } )
|
self:F2( { AltType, Type, Action, Speed, SpeedLocked } )
|
||||||
|
|
||||||
|
-- Defaults
|
||||||
|
AltType=AltType or "RADIO"
|
||||||
|
if SpeedLocked==nil then
|
||||||
|
SpeedLocked=true
|
||||||
|
end
|
||||||
|
Speed=Speed or 500
|
||||||
|
|
||||||
|
-- Waypoint array.
|
||||||
local RoutePoint = {}
|
local RoutePoint = {}
|
||||||
|
|
||||||
|
-- Coordinates.
|
||||||
RoutePoint.x = self.x
|
RoutePoint.x = self.x
|
||||||
RoutePoint.y = self.z
|
RoutePoint.y = self.z
|
||||||
|
-- Altitude.
|
||||||
RoutePoint.alt = self.y
|
RoutePoint.alt = self.y
|
||||||
RoutePoint.alt_type = AltType or "RADIO"
|
RoutePoint.alt_type = AltType
|
||||||
|
-- Waypoint type.
|
||||||
RoutePoint.type = Type or nil
|
RoutePoint.type = Type or nil
|
||||||
RoutePoint.action = Action or nil
|
RoutePoint.action = Action or nil
|
||||||
|
-- Set speed/ETA.
|
||||||
RoutePoint.speed = ( Speed and Speed / 3.6 ) or ( 500 / 3.6 )
|
RoutePoint.speed = Speed/3.6
|
||||||
RoutePoint.speed_locked = true
|
RoutePoint.speed_locked = SpeedLocked
|
||||||
|
RoutePoint.ETA=nil
|
||||||
|
RoutePoint.ETA_locked = false
|
||||||
|
-- Waypoint description.
|
||||||
|
RoutePoint.name=description
|
||||||
|
-- Airbase parameters for takeoff and landing points.
|
||||||
|
if airbase then
|
||||||
|
local AirbaseID = airbase:GetID()
|
||||||
|
local AirbaseCategory = airbase:GetDesc().category
|
||||||
|
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then
|
||||||
|
RoutePoint.linkUnit = AirbaseID
|
||||||
|
RoutePoint.helipadId = AirbaseID
|
||||||
|
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||||
|
RoutePoint.airdromeId = AirbaseID
|
||||||
|
else
|
||||||
|
self:T("ERROR: Unknown airbase category in COORDINATE:WaypointAir()!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- ["task"] =
|
-- ["task"] =
|
||||||
-- {
|
-- {
|
||||||
@@ -976,12 +1022,11 @@ do -- COORDINATE
|
|||||||
-- }, -- end of ["params"]
|
-- }, -- end of ["params"]
|
||||||
-- }, -- end of ["task"]
|
-- }, -- end of ["task"]
|
||||||
|
|
||||||
|
-- Waypoint tasks.
|
||||||
RoutePoint.task = {}
|
RoutePoint.task = {}
|
||||||
RoutePoint.task.id = "ComboTask"
|
RoutePoint.task.id = "ComboTask"
|
||||||
RoutePoint.task.params = {}
|
RoutePoint.task.params = {}
|
||||||
RoutePoint.task.params.tasks = {}
|
RoutePoint.task.params.tasks = DCSTasks or {}
|
||||||
|
|
||||||
|
|
||||||
return RoutePoint
|
return RoutePoint
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2459,7 +2459,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint)
|
|||||||
local VxCruiseMin = math.min(VxCruiseMax*0.70, 166)
|
local VxCruiseMin = math.min(VxCruiseMax*0.70, 166)
|
||||||
|
|
||||||
-- Cruise speed (randomized). Expectation value at midpoint between min and max.
|
-- Cruise speed (randomized). Expectation value at midpoint between min and max.
|
||||||
local VxCruise = self:_Random_Gaussian((VxCruiseMax-VxCruiseMin)/2+VxCruiseMin, (VxCruiseMax-VxCruiseMax)/4, VxCruiseMin, VxCruiseMax)
|
local VxCruise = UTILS.RandomGaussian((VxCruiseMax-VxCruiseMin)/2+VxCruiseMin, (VxCruiseMax-VxCruiseMax)/4, VxCruiseMin, VxCruiseMax)
|
||||||
|
|
||||||
-- Climb speed 90% ov Vmax but max 720 km/h.
|
-- Climb speed 90% ov Vmax but max 720 km/h.
|
||||||
local VxClimb = math.min(self.aircraft.Vmax*0.90, 200)
|
local VxClimb = math.min(self.aircraft.Vmax*0.90, 200)
|
||||||
@@ -2817,7 +2817,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Set cruise altitude. Selected from Gaussian distribution but limited to FLmin and FLmax.
|
-- Set cruise altitude. Selected from Gaussian distribution but limited to FLmin and FLmax.
|
||||||
local FLcruise=self:_Random_Gaussian(FLcruise_expect, math.abs(FLmax-FLmin)/4, FLmin, FLmax)
|
local FLcruise=UTILS.RandomGaussian(FLcruise_expect, math.abs(FLmax-FLmin)/4, FLmin, FLmax)
|
||||||
|
|
||||||
-- Overrule setting if user specified a flight level explicitly.
|
-- Overrule setting if user specified a flight level explicitly.
|
||||||
if self.FLuser then
|
if self.FLuser then
|
||||||
@@ -5014,38 +5014,6 @@ function RAT:_Randomize(value, fac, lower, upper)
|
|||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Generate Gaussian pseudo-random numbers.
|
|
||||||
-- @param #number x0 Expectation value of distribution.
|
|
||||||
-- @param #number sigma (Optional) Standard deviation. Default 10.
|
|
||||||
-- @param #number xmin (Optional) Lower cut-off value.
|
|
||||||
-- @param #number xmax (Optional) Upper cut-off value.
|
|
||||||
-- @return #number Gaussian random number.
|
|
||||||
function RAT:_Random_Gaussian(x0, sigma, xmin, xmax)
|
|
||||||
|
|
||||||
-- Standard deviation. Default 10 if not given.
|
|
||||||
sigma=sigma or 10
|
|
||||||
|
|
||||||
local r
|
|
||||||
local gotit=false
|
|
||||||
local i=0
|
|
||||||
while not gotit do
|
|
||||||
|
|
||||||
-- Uniform numbers in [0,1). We need two.
|
|
||||||
local x1=math.random()
|
|
||||||
local x2=math.random()
|
|
||||||
|
|
||||||
-- Transform to Gaussian exp(-(x-x0)²/(2*sigma²).
|
|
||||||
r = math.sqrt(-2*sigma*sigma * math.log(x1)) * math.cos(2*math.pi * x2) + x0
|
|
||||||
|
|
||||||
i=i+1
|
|
||||||
if (r>=xmin and r<=xmax) or i>100 then
|
|
||||||
gotit=true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return r
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Place markers of the waypoints. Note we assume a very specific number and type of waypoints here.
|
--- Place markers of the waypoints. Note we assume a very specific number and type of waypoints here.
|
||||||
-- @param #RAT self
|
-- @param #RAT self
|
||||||
|
|||||||
@@ -140,11 +140,16 @@ WAREHOUSE = {
|
|||||||
--- Item of the warehouse pending queue table.
|
--- Item of the warehouse pending queue table.
|
||||||
-- @type WAREHOUSE.Pendingitem
|
-- @type WAREHOUSE.Pendingitem
|
||||||
-- @extends #WAREHOUSE.Queueitem
|
-- @extends #WAREHOUSE.Queueitem
|
||||||
-- @field #table assetlist Table of assets to be delivered. Each element of the table is a @{#WAREHOUSE.Stockitem}.
|
-- @field #table cargoassets Table of assets to be delivered. Each element of the table is a @{#WAREHOUSE.Stockitem}.
|
||||||
-- @field #number ndelivered Number of groups delivered to destination. Is managed automatically.
|
-- @field Core.Set#SET_GROUP cargogroupset Set of cargo groups do be delivered.
|
||||||
-- @field #number ntransporthome Number of transports back home. Is managed automatically.
|
-- @field #number ndelivered Number of groups delivered to destination.
|
||||||
-- @field Core.Set#SET_GROUP cargogroupset Set of cargo groups do be delivered. Is managed automatically.
|
-- @field #number cargoattribute Attribute of cargo assets of type @{#WAREHOUSE.Attribute}.
|
||||||
-- @field Core.Set#SET_GROUP transportgroupset Set of cargo transport groups. Is managed automatically.
|
-- @field #number cargocategory Category of cargo assets of type @{#WAREHOUSE.Category}.
|
||||||
|
-- @field #table transportassets Table of assets to be delivered. Each element of the table is a @{#WAREHOUSE.Stockitem}.
|
||||||
|
-- @field Core.Set#SET_GROUP transportgroupset Set of cargo transport groups.
|
||||||
|
-- @field #number transportattribute Attribute of transport assets of type @{#WAREHOUSE.Attribute}.
|
||||||
|
-- @field #number transportcategory Category of transport assets of type @{#WAREHOUSE.Category}.
|
||||||
|
-- @field #number ntransporthome Number of transports back home. transportattribute
|
||||||
|
|
||||||
--- Descriptors enumerator describing the type of the asset in stock.
|
--- Descriptors enumerator describing the type of the asset in stock.
|
||||||
-- @type WAREHOUSE.Descriptor
|
-- @type WAREHOUSE.Descriptor
|
||||||
@@ -191,7 +196,7 @@ WAREHOUSE.TransportType = {
|
|||||||
|
|
||||||
--- Warehouse class version.
|
--- Warehouse class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
WAREHOUSE.version="0.1.9"
|
WAREHOUSE.version="0.1.9w"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO: Warehouse todo list.
|
-- TODO: Warehouse todo list.
|
||||||
@@ -272,24 +277,25 @@ function WAREHOUSE:New(warehouse, alias)
|
|||||||
self:SetStartState("Stopped")
|
self:SetStartState("Stopped")
|
||||||
|
|
||||||
-- Add FSM transitions.
|
-- Add FSM transitions.
|
||||||
self:AddTransition("Stopped", "Load", "Stopped") -- TODO Load the warehouse state. No sure if it should be in stopped state.
|
self:AddTransition("Stopped", "Load", "Stopped") -- TODO Load the warehouse state. No sure if it should be in stopped state.
|
||||||
self:AddTransition("Stopped", "Start", "Running") -- Start the warehouse.
|
self:AddTransition("Stopped", "Start", "Running") -- Start the warehouse.
|
||||||
self:AddTransition("Running", "Status", "*") -- Status update in running mode. Requests are processed.
|
self:AddTransition("Running", "Status", "*") -- Status update in running mode. Requests are processed.
|
||||||
self:AddTransition("Paused", "Status", "*") -- TODO Status update in paused mode. Requests are not processed.
|
self:AddTransition("Paused", "Status", "*") -- TODO Status update in paused mode. Requests are not processed.
|
||||||
self:AddTransition("*", "AddAsset", "*") -- Add asset to warehouse stock.
|
self:AddTransition("*", "AddAsset", "*") -- Add asset to warehouse stock.
|
||||||
self:AddTransition("*", "AddRequest", "*") -- New request from other warehouse.
|
self:AddTransition("*", "AddRequest", "*") -- New request from other warehouse.
|
||||||
self:AddTransition("Running", "Request", "*") -- Process a request. Only in running mode.
|
self:AddTransition("Running", "Request", "*") -- Process a request. Only in running mode.
|
||||||
self:AddTransition("*", "Unloaded", "*") -- Cargo has been unloaded from the carrier.
|
self:AddTransition("*", "Unloaded", "*") -- Cargo has been unloaded from the carrier.
|
||||||
self:AddTransition("*", "Arrived", "*") -- Cargo group has arrived at destination.
|
self:AddTransition("*", "Arrived", "*") -- Cargo group has arrived at destination.
|
||||||
self:AddTransition("*", "Delivered", "*") -- All cargo groups of a request have been delivered to the requesting warehouse.
|
self:AddTransition("*", "Delivered", "*") -- All cargo groups of a request have been delivered to the requesting warehouse.
|
||||||
self:AddTransition("Running", "SelfRequest", "*") -- Request to warehouse itself. Requested assets are only spawned but not delivered anywhere.
|
self:AddTransition("Running", "SelfRequest", "*") -- Request to warehouse itself. Requested assets are only spawned but not delivered anywhere.
|
||||||
self:AddTransition("Running", "Pause", "Paused") -- TODO Pause the processing of new requests. Still possible to add assets and requests.
|
self:AddTransition("Running", "Pause", "Paused") -- TODO Pause the processing of new requests. Still possible to add assets and requests.
|
||||||
self:AddTransition("Paused", "Unpause", "Running") -- TODO Unpause the warehouse. Queued requests are processed again.
|
self:AddTransition("Paused", "Unpause", "Running") -- TODO Unpause the warehouse. Queued requests are processed again.
|
||||||
self:AddTransition("*", "Stop", "Stopped") -- TODO Stop the warehouse.
|
self:AddTransition("*", "Stop", "Stopped") -- TODO Stop the warehouse.
|
||||||
self:AddTransition("*", "Save", "*") -- TODO Save the warehouse state to disk.
|
self:AddTransition("*", "Save", "*") -- TODO Save the warehouse state to disk.
|
||||||
self:AddTransition("*", "Attacked", "*") -- TODO Warehouse is under attack by enemy coalitin.
|
self:AddTransition("*", "Attacked", "Attacked") -- TODO Warehouse is under attack by enemy coalition.
|
||||||
self:AddTransition("*", "Captured", "*") -- TODO Warehouse was captured by another coalition.
|
self:AddTransition("Attacked", "Defeated", "Running") -- TODO Attack by other coalition was defeated!
|
||||||
self:AddTransition("*", "Destroyed", "*") -- TODO Warehouse was destoryed. All assets are gone and warehouse is stopped.
|
self:AddTransition("Attacked", "Captured", "Running") -- TODO Warehouse was captured by another coalition. It must have been attacked first.
|
||||||
|
self:AddTransition("*", "Destroyed", "*") -- TODO Warehouse was destoryed. All assets in stock are gone and warehouse is stopped.
|
||||||
|
|
||||||
|
|
||||||
-- Pseudo Functions
|
-- Pseudo Functions
|
||||||
@@ -495,6 +501,13 @@ function WAREHOUSE:IsPaused()
|
|||||||
return self:is("Paused")
|
return self:is("Paused")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if the warehouse is under attack by another coalition.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @return #boolean If true, the warehouse is attacked.
|
||||||
|
function WAREHOUSE:IsAttacked()
|
||||||
|
return self:is("Attacked")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- FSM states
|
-- FSM states
|
||||||
@@ -1492,8 +1505,21 @@ end
|
|||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
function WAREHOUSE:onafterAttacked(From, Event, To)
|
-- @param DCS#coalition.side Coalition which is attacking the warehouse.
|
||||||
|
-- @param DCS#country.id Country which is attacking the warehouse.
|
||||||
|
function WAREHOUSE:onafterAttacked(From, Event, To, Coalition, Country)
|
||||||
self:E(self.wid..string.format("Out warehouse is under attack!"))
|
self:E(self.wid..string.format("Out warehouse is under attack!"))
|
||||||
|
--TODO: Spawn all ground units in the spawnzone?
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after "Defeated" event. Warehouse defeated an attack by another coalition.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
function WAREHOUSE:onafterDefeated(From, Event, To)
|
||||||
|
self:E(self.wid..string.format("Attack was defeated!"))
|
||||||
|
--TODO Put all ground assets back in stock? How to remember which? Request id. Don't delete from pending?
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "Captured" event. Warehouse has been captured by another coalition.
|
--- On after "Captured" event. Warehouse has been captured by another coalition.
|
||||||
@@ -1502,25 +1528,17 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param DCS#coalition.side Coalition which captured the warehouse.
|
-- @param DCS#coalition.side Coalition which captured the warehouse.
|
||||||
function WAREHOUSE:onafterCaptured(From, Event, To, Coalition)
|
-- @param DCS#country.id Country which has captured the warehouse.
|
||||||
|
function WAREHOUSE:onafterCaptured(From, Event, To, Coalition, Country)
|
||||||
self:E(self.wid..string.format("Our warehouse was captured by coalition %d!", Coalition))
|
self:E(self.wid..string.format("Our warehouse was captured by coalition %d!", Coalition))
|
||||||
|
|
||||||
--TODO: Need to get a way to get the correct country.
|
|
||||||
local Country
|
|
||||||
if Coalition==coalition.side.BLUE then
|
|
||||||
Country=country.id.USA
|
|
||||||
elseif Coalition==coalition.side.RED then
|
|
||||||
Country=country.id.USSR
|
|
||||||
else
|
|
||||||
Country=country.id.SWITZERLAND
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Respawn warehouse with new coalition/country.
|
-- Respawn warehouse with new coalition/country.
|
||||||
self.warehouse:ReSpawn(Country)
|
self.warehouse:ReSpawn(Country)
|
||||||
self.coalition=Coalition
|
self.coalition=Coalition
|
||||||
self.country=Country
|
self.country=Country
|
||||||
self.airbase=nil
|
self.airbase=nil
|
||||||
self.category=-1
|
self.category=-1
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -1540,6 +1558,8 @@ function WAREHOUSE:_RouteGround(Group, Coordinate, Speed)
|
|||||||
local _speed=Speed or Group:GetSpeedMax()*0.6
|
local _speed=Speed or Group:GetSpeedMax()*0.6
|
||||||
|
|
||||||
-- Create task.
|
-- Create task.
|
||||||
|
-- TODO: It might be necessary to ALWAYS route the group to the road connection first.
|
||||||
|
-- At the moment, the random spawn point might give another first road point which could also be a dead end like in Kobuliti(?).
|
||||||
local Waypoints, canroad = Group:TaskGroundOnRoad(Coordinate, _speed, "Off Road", true)
|
local Waypoints, canroad = Group:TaskGroundOnRoad(Coordinate, _speed, "Off Road", true)
|
||||||
|
|
||||||
-- Task function triggering the arrived event.
|
-- Task function triggering the arrived event.
|
||||||
@@ -1630,6 +1650,9 @@ function WAREHOUSE:_RouteAir(Aircraft, ToAirbase, Speed)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local Waypoints,Coordinates=self:_GetFlightplan(Aircraft,self.airbase,ToAirbase)
|
||||||
|
|
||||||
|
--[[
|
||||||
-- Waypoints of the route.
|
-- Waypoints of the route.
|
||||||
local Points={}
|
local Points={}
|
||||||
|
|
||||||
@@ -1660,7 +1683,11 @@ function WAREHOUSE:_RouteAir(Aircraft, ToAirbase, Speed)
|
|||||||
|
|
||||||
-- Second point of the route. First point is done in RespawnAtCurrentAirbase() routine.
|
-- Second point of the route. First point is done in RespawnAtCurrentAirbase() routine.
|
||||||
Template.route.points[2] = ToWaypoint
|
Template.route.points[2] = ToWaypoint
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- Set waypoints.
|
||||||
|
Template.route.points=Waypoints
|
||||||
|
|
||||||
-- Respawn group at the current airbase.
|
-- Respawn group at the current airbase.
|
||||||
env.info("FF Respawn at current airbase group = "..Aircraft:GetName().." name before")
|
env.info("FF Respawn at current airbase group = "..Aircraft:GetName().." name before")
|
||||||
local newAC=Aircraft:RespawnAtCurrentAirbase(Template, Takeoff, false)
|
local newAC=Aircraft:RespawnAtCurrentAirbase(Template, Takeoff, false)
|
||||||
@@ -1881,8 +1908,100 @@ end
|
|||||||
-- Helper functions
|
-- Helper functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Checks if the warehouse zone was conquered by antoher coalition.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
function WAREHOUSE:_CheckConquered()
|
||||||
|
|
||||||
|
local coord=self.zone:GetCoordinate()
|
||||||
|
local radius=self.zone:GetRadius()
|
||||||
|
|
||||||
|
-- Scan units in zone.
|
||||||
|
--TODO: need to check if scan radius does what it should!
|
||||||
|
local gotunits,_,_,units,_,_=coord:ScanObjects(radius, true, false, false)
|
||||||
|
|
||||||
|
local Nblue=0
|
||||||
|
local Nred=0
|
||||||
|
local Nneutral=0
|
||||||
|
|
||||||
|
local CountryBlue=nil
|
||||||
|
local CountryRed=nil
|
||||||
|
local CountryNeutral=nil
|
||||||
|
|
||||||
|
if gotunits then
|
||||||
|
-- Loop over all units.
|
||||||
|
for _,_unit in pairs(units) do
|
||||||
|
local unit=_unit --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
-- Get coalition and country.
|
||||||
|
local _coalition=unit:GetCoalition()
|
||||||
|
local _country=unit:GetCountry()
|
||||||
|
|
||||||
|
if _coalition==coalition.side.BLUE then
|
||||||
|
Nblue=Nblue+1
|
||||||
|
CountryBlue=_country
|
||||||
|
elseif _coalition==coalition.side.RED then
|
||||||
|
Nred=Nred+1
|
||||||
|
CountryRed=_country
|
||||||
|
else
|
||||||
|
Nneutral=Nneutral+1
|
||||||
|
CountryNeutral=_country
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Figure out the new coalition if any.
|
||||||
|
-- Condition is that only units of one coalition are within the zone.
|
||||||
|
local newcoalition=self.coalition
|
||||||
|
local newcountry=self.country
|
||||||
|
if Nblue>0 and Nred==0 and Nneutral==0 then
|
||||||
|
-- Only blue units in zone ==> Zone goes to blue.
|
||||||
|
newcoalition=coalition.side.BLUE
|
||||||
|
newcountry=CountryBlue
|
||||||
|
elseif Nblue==0 and Nred>0 and Nneutral==0 then
|
||||||
|
-- Only red units in zone ==> Zone goes to red.
|
||||||
|
newcoalition=coalition.side.RED
|
||||||
|
newcountry=CountryRed
|
||||||
|
elseif Nblue==0 and Nred==0 and Nneutral>0 then
|
||||||
|
-- Only neutral units in zone but neutrals do not attack or even capture!
|
||||||
|
--newcoalition=coalition.side.NEUTRAL
|
||||||
|
newcountry=CountryNeutral
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Coalition has changed ==> warehouse was captured!
|
||||||
|
if self:IsAttacked() and newcoalition ~= self.coalition then
|
||||||
|
self:Captured(newcoalition, newcountry)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Before a warehouse can be captured, it has to be attacked.
|
||||||
|
-- That is, even if only enemy units are present it is not immediately captured in order to spawn all ground assets for defence.
|
||||||
|
if self.coalition==coalition.side.BLUE then
|
||||||
|
-- Blue warehouse is running and we have red units in the zone.
|
||||||
|
if self:IsRunning() and Nred>0 then
|
||||||
|
self:__Attacked(coalition.side.RED, CountryRed)
|
||||||
|
end
|
||||||
|
-- Blue warehouse was under attack by blue but no more blue units in zone.
|
||||||
|
if self:IsAttacked() and Nred==0 then
|
||||||
|
self:Defeated()
|
||||||
|
end
|
||||||
|
elseif self.coalition==coalition.side.RED then
|
||||||
|
-- Red Warehouse is running and we have blue units in the zone.
|
||||||
|
if self:IsRunning() and Nblue>0 then
|
||||||
|
self:__Attacked(coalition.side.BLUE, CountryBlue)
|
||||||
|
end
|
||||||
|
-- Red warehouse was under attack by blue but no more blue units in zone.
|
||||||
|
if self:IsAttacked() and Nblue==0 then
|
||||||
|
self:Defeated()
|
||||||
|
end
|
||||||
|
elseif self.coalition==coalition.side.NEUTRAL then
|
||||||
|
-- Neutrals dont attack!
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Checks if the request can be fulfilled in general. If not, it is removed from the queue.
|
--- Checks if the request can be fulfilled in general. If not, it is removed from the queue.
|
||||||
-- Check if departure and destination bases are of the right type.
|
-- Check if departure and destination bases are of the right type.
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @param #table queue The queue which is holding the requests to check.
|
-- @param #table queue The queue which is holding the requests to check.
|
||||||
-- @return #boolean If true, request can be executed. If false, something is not right.
|
-- @return #boolean If true, request can be executed. If false, something is not right.
|
||||||
@@ -2655,6 +2774,249 @@ function WAREHOUSE:_PrintQueue(queue, name)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- Make a flight plan from a departure to a destination airport.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param Wrapper.Group#GROUP group
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE _departure Departure airbase.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE _destination Destination airbase.
|
||||||
|
-- @return #table Table of flightplan waypoints.
|
||||||
|
-- @return #table Table of flightplan coordinates.
|
||||||
|
function WAREHOUSE:_GetFlightplan(group,_departure,_destination)
|
||||||
|
|
||||||
|
-- Group parameters.
|
||||||
|
local Vmax=group:GetSpeedMax()/3.6
|
||||||
|
local Range=group:GetRange()
|
||||||
|
local _category=group:GetCategory()
|
||||||
|
local DCSDesc=group:GetDCSDesc()
|
||||||
|
local ceiling=DCSDesc.Hmax
|
||||||
|
local Vymax=DCSDesc.VyMax
|
||||||
|
|
||||||
|
-- Max cruise speed 90% of max speed.
|
||||||
|
local VxCruiseMax=0.90*Vmax
|
||||||
|
|
||||||
|
-- Min cruise speed 70% of max cruise or 600 km/h whichever is lower.
|
||||||
|
local VxCruiseMin = math.min(VxCruiseMax*0.70, 166)
|
||||||
|
|
||||||
|
-- Cruise speed (randomized). Expectation value at midpoint between min and max.
|
||||||
|
local VxCruise = UTILS.RandomGaussian((VxCruiseMax-VxCruiseMin)/2+VxCruiseMin, (VxCruiseMax-VxCruiseMax)/4, VxCruiseMin, VxCruiseMax)
|
||||||
|
|
||||||
|
-- Climb speed 90% ov Vmax but max 720 km/h.
|
||||||
|
local VxClimb = math.min(Vmax*0.90, 200)
|
||||||
|
|
||||||
|
-- Descent speed 60% of Vmax but max 500 km/h.
|
||||||
|
local VxDescent = math.min(Vmax*0.60, 140)
|
||||||
|
|
||||||
|
-- Holding speed is 90% of descent speed.
|
||||||
|
local VxHolding = VxDescent*0.9
|
||||||
|
|
||||||
|
-- Final leg is 90% of holding speed.
|
||||||
|
local VxFinal = VxHolding*0.9
|
||||||
|
|
||||||
|
-- Reasonably civil climb speed Vy=1500 ft/min = 7.6 m/s but max aircraft specific climb rate.
|
||||||
|
local VyClimb=math.min(7.6, Vymax)
|
||||||
|
|
||||||
|
-- Climb angle in rad.
|
||||||
|
local AlphaClimb=math.asin(VyClimb/VxClimb)
|
||||||
|
|
||||||
|
-- Descent angle in rad. Moderate 4 degrees.
|
||||||
|
local AlphaDescent=math.rad(4)
|
||||||
|
|
||||||
|
-- Expected cruise level (peak of Gaussian distribution)
|
||||||
|
local FLcruise_expect=200*RAT.unit.FL2m
|
||||||
|
|
||||||
|
--- DEPARTURE AIRPORT
|
||||||
|
|
||||||
|
-- Coordinates of departure point.
|
||||||
|
local Pdeparture=_departure:GetCoordinate()
|
||||||
|
|
||||||
|
-- Height ASL of departure point.
|
||||||
|
local H_departure=Pdeparture.y
|
||||||
|
|
||||||
|
--- DESTINATION AIRPORT
|
||||||
|
|
||||||
|
-- Position of destination airport.
|
||||||
|
local Pdestination=_destination:GetCoordinate()
|
||||||
|
|
||||||
|
-- Height ASL of destination airport/zone.
|
||||||
|
local H_destination=Pdestination.y
|
||||||
|
|
||||||
|
--- DESCENT/HOLDING POINT
|
||||||
|
|
||||||
|
-- Get a random point between 5 and 20 km away from the destination.
|
||||||
|
local Rhmin=8000
|
||||||
|
local Rhmax=20000
|
||||||
|
if _category==Group.Category.HELICOPTER then
|
||||||
|
-- For helos we set a distance between 500 to 1000 m.
|
||||||
|
Rhmin=500
|
||||||
|
Rhmax=1000
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Coordinates of the holding point. y is the land height at that point.
|
||||||
|
local Vholding=Pdestination:GetRandomVec2InRadius(Rhmax, Rhmin)
|
||||||
|
local Pholding=COORDINATE:NewFromVec2(Vholding)
|
||||||
|
|
||||||
|
-- AGL height of holding point.
|
||||||
|
local H_holding=Pholding.y
|
||||||
|
|
||||||
|
-- Holding point altitude. For planes between 1600 and 2400 m AGL. For helos 160 to 240 m AGL.
|
||||||
|
local h_holding=1200
|
||||||
|
if _category==Group.Category.HELICOPTER then
|
||||||
|
h_holding=150
|
||||||
|
end
|
||||||
|
h_holding=UTILS.Randomize(h_holding, 0.2)
|
||||||
|
|
||||||
|
-- This is the actual height ASL of the holding point we want to fly to
|
||||||
|
local Hh_holding=H_holding+h_holding
|
||||||
|
|
||||||
|
-- Distance from holding point to final destination.
|
||||||
|
local d_holding=Pholding:Get2DDistance(Pdestination)
|
||||||
|
|
||||||
|
-- GENERAL
|
||||||
|
local heading=Pdeparture:HeadingTo(Pdestination)
|
||||||
|
local d_total=Pdeparture:Get2DDistance(Pholding)
|
||||||
|
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
-- Height difference between departure and destination.
|
||||||
|
local deltaH=math.abs(H_departure-Hh_holding)
|
||||||
|
|
||||||
|
-- Slope between departure and destination.
|
||||||
|
local phi = math.atan(deltaH/d_total)
|
||||||
|
|
||||||
|
-- Adjusted climb/descent angles.
|
||||||
|
local phi_climb
|
||||||
|
local phi_descent
|
||||||
|
if (H_departure > Hh_holding) then
|
||||||
|
phi_climb=AlphaClimb+phi
|
||||||
|
phi_descent=AlphaDescent-phi
|
||||||
|
else
|
||||||
|
phi_climb=AlphaClimb-phi
|
||||||
|
phi_descent=AlphaDescent+phi
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Total distance including slope.
|
||||||
|
local D_total=math.sqrt(deltaH*deltaH+d_total*d_total)
|
||||||
|
|
||||||
|
-- SSA triangle for sloped case.
|
||||||
|
local gamma=math.rad(180)-phi_climb-phi_descent
|
||||||
|
local a = D_total*math.sin(phi_climb)/math.sin(gamma)
|
||||||
|
local b = D_total*math.sin(phi_descent)/math.sin(gamma)
|
||||||
|
local hphi_max = b*math.sin(phi_climb)
|
||||||
|
local hphi_max2 = a*math.sin(phi_descent)
|
||||||
|
|
||||||
|
-- Height of triangle.
|
||||||
|
local h_max1 = b*math.sin(AlphaClimb)
|
||||||
|
local h_max2 = a*math.sin(AlphaDescent)
|
||||||
|
|
||||||
|
-- Max height relative to departure or destination.
|
||||||
|
local h_max
|
||||||
|
if (H_departure > Hh_holding) then
|
||||||
|
h_max=math.min(h_max1, h_max2)
|
||||||
|
else
|
||||||
|
h_max=math.max(h_max1, h_max2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Max flight level aircraft can reach for given angles and distance.
|
||||||
|
local FLmax = h_max+H_departure
|
||||||
|
|
||||||
|
--CRUISE
|
||||||
|
-- Min cruise alt is just above holding point at destination or departure height, whatever is larger.
|
||||||
|
local FLmin=math.max(H_departure, Hh_holding)
|
||||||
|
|
||||||
|
-- For helicopters we take cruise alt between 50 to 1000 meters above ground. Default cruise alt is ~150 m.
|
||||||
|
if _category==Group.Category.HELICOPTER then
|
||||||
|
FLmin=math.max(H_departure, H_destination)+50
|
||||||
|
FLmax=math.max(H_departure, H_destination)+1000
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure that FLmax not above its service ceiling.
|
||||||
|
FLmax=math.min(FLmax, ceiling)
|
||||||
|
|
||||||
|
-- If the route is very short we set FLmin a bit lower than FLmax.
|
||||||
|
if FLmin>FLmax then
|
||||||
|
FLmin=FLmax
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Expected cruise altitude - peak of gaussian distribution.
|
||||||
|
if FLcruise_expect<FLmin then
|
||||||
|
FLcruise_expect=FLmin
|
||||||
|
end
|
||||||
|
if FLcruise_expect>FLmax then
|
||||||
|
FLcruise_expect=FLmax
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set cruise altitude. Selected from Gaussian distribution but limited to FLmin and FLmax.
|
||||||
|
local FLcruise=UTILS.RandomGaussian(FLcruise_expect, math.abs(FLmax-FLmin)/4, FLmin, FLmax)
|
||||||
|
|
||||||
|
-- Climb and descent heights.
|
||||||
|
local h_climb = FLcruise - H_departure
|
||||||
|
local h_descent = FLcruise - Hh_holding
|
||||||
|
|
||||||
|
-- Distances.
|
||||||
|
local d_climb = h_climb/math.tan(AlphaClimb)
|
||||||
|
local d_descent = h_descent/math.tan(AlphaDescent)
|
||||||
|
local d_cruise = d_total-d_climb-d_descent
|
||||||
|
|
||||||
|
-- Ensure that cruise distance is positve. Can be slightly negative in special cases. And we don't want to turn back.
|
||||||
|
if d_cruise<0 then
|
||||||
|
d_cruise=100
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Waypoints and coordinates
|
||||||
|
local wp={}
|
||||||
|
local c={}
|
||||||
|
|
||||||
|
--- Departure/Take-off
|
||||||
|
c[#c+1]=Pdeparture
|
||||||
|
wp[#wp+1]=Pdeparture:WaypointAir("RADIO", COORDINATE.WaypointType.TakeOffParking, COORDINATE.WaypointAction.FromParkingArea, VxClimb, true,_departure, nil, "Departure")
|
||||||
|
--wp[#wp+1]=self:_Waypoint(#wp+1, "Departure", takeoff, c[#wp+1], VxClimb, H_departure, departure)
|
||||||
|
|
||||||
|
--- Climb
|
||||||
|
local Pclimb=Pdeparture:Translate(d_climb/2, heading)
|
||||||
|
Pclimb.y=H_departure+(FLcruise-H_departure)/2
|
||||||
|
c[#c+1]=Pclimb
|
||||||
|
wp[#wp+1]=Pclimb:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxClimb, true, nil, nil, "Climb")
|
||||||
|
--wp[#wp+1]=self:_Waypoint(#wp+1, "Climb", RAT.wp.climb, c[#wp+1], VxClimb, )
|
||||||
|
|
||||||
|
--- Begin of Cruise
|
||||||
|
local Pcruise1=Pclimb:Translate(d_climb/2, heading)
|
||||||
|
Pcruise1.y=FLcruise
|
||||||
|
c[#c+1]=Pcruise1
|
||||||
|
wp[#wp+1]=Pcruise1:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxCruise, true, nil, nil, "Begin of Cruise")
|
||||||
|
--wp[#wp+1]=self:_Waypoint(#wp+1, "Begin of Cruise", RAT.wp.cruise, c[#wp+1], VxCruise, FLcruise)
|
||||||
|
|
||||||
|
--- End of Cruise
|
||||||
|
local Pcruise2=Pcruise1:Translate(d_cruise, heading)
|
||||||
|
Pcruise2.y=FLcruise
|
||||||
|
c[#c+1]=Pcruise2
|
||||||
|
wp[#wp+1]=Pcruise2:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxCruise, true, nil, nil, "End of Cruise")
|
||||||
|
--wp[#wp+1]=self:_Waypoint(#wp+1, "End of Cruise", RAT.wp.cruise, c[#wp+1], VxCruise, FLcruise)
|
||||||
|
|
||||||
|
--- Descent
|
||||||
|
local Pdescent=Pcruise2:Translate(d_descent/2, heading)
|
||||||
|
Pdescent.y=FLcruise-(FLcruise-(h_holding+H_holding))/2
|
||||||
|
c[#c+1]=Pdescent
|
||||||
|
wp[#wp+1]=Pcruise2:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxDescent, true, nil, nil, "Descent")
|
||||||
|
--wp[#wp+1]=self:_Waypoint(#wp+1, "Descent", RAT.wp.descent, c[#wp+1], VxDescent, FLcruise-(FLcruise-(h_holding+H_holding))/2)
|
||||||
|
|
||||||
|
--- Holding point
|
||||||
|
Pholding.y=H_holding+h_holding
|
||||||
|
c[#c+1]=Pholding
|
||||||
|
wp[#wp+1]=Pholding:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, VxHolding, true, nil, nil, "Holding")
|
||||||
|
--wp[#wp+1]=self:_Waypoint(#wp+1, "Holding Point", RAT.wp.holding, c[#wp+1], VxHolding, H_holding+h_holding)
|
||||||
|
|
||||||
|
--- Final destination.
|
||||||
|
c[#c+1]=Pdestination
|
||||||
|
wp[#wp+1]=Pcruise2:WaypointAir("BARO", COORDINATE.WaypointType.Land, COORDINATE.WaypointAction.Landing, VxFinal, true, nil, nil, "Final Destination")
|
||||||
|
--wp[#wp+1]=self:_Waypoint(#wp+1, "Final Destination", landing, c[#wp+1], VxFinal, H_destination, destination)
|
||||||
|
|
||||||
|
return wp,c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -591,4 +591,71 @@ function UTILS.DisplayMissionTime(duration)
|
|||||||
local local_time=UTILS.SecondsToClock(Tnow)
|
local local_time=UTILS.SecondsToClock(Tnow)
|
||||||
local text=string.format("Time: %s - %02d:%02d", local_time, mission_time_minutes, mission_time_seconds)
|
local text=string.format("Time: %s - %02d:%02d", local_time, mission_time_minutes, mission_time_seconds)
|
||||||
MESSAGE:New(text, duration):ToAll()
|
MESSAGE:New(text, duration):ToAll()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Generate a Gaussian pseudo-random number.
|
||||||
|
-- @param #number x0 Expectation value of distribution.
|
||||||
|
-- @param #number sigma (Optional) Standard deviation. Default 10.
|
||||||
|
-- @param #number xmin (Optional) Lower cut-off value.
|
||||||
|
-- @param #number xmax (Optional) Upper cut-off value.
|
||||||
|
-- @param #number imax (Optional) Max number of tries to get a value between xmin and xmax (if specified). Default 100.
|
||||||
|
-- @return #number Gaussian random number.
|
||||||
|
function UTILS.RandomGaussian(x0, sigma, xmin, xmax, imax)
|
||||||
|
|
||||||
|
-- Standard deviation. Default 10 if not given.
|
||||||
|
sigma=sigma or 10
|
||||||
|
|
||||||
|
-- Max attempts.
|
||||||
|
imax=imax or 100
|
||||||
|
|
||||||
|
local r
|
||||||
|
local gotit=false
|
||||||
|
local i=0
|
||||||
|
while not gotit do
|
||||||
|
|
||||||
|
-- Uniform numbers in [0,1). We need two.
|
||||||
|
local x1=math.random()
|
||||||
|
local x2=math.random()
|
||||||
|
|
||||||
|
-- Transform to Gaussian exp(-(x-x0)²/(2*sigma²).
|
||||||
|
r = math.sqrt(-2*sigma*sigma * math.log(x1)) * math.cos(2*math.pi * x2) + x0
|
||||||
|
|
||||||
|
i=i+1
|
||||||
|
if (r>=xmin and r<=xmax) or i>imax then
|
||||||
|
gotit=true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Randomize a value by a certain amount.
|
||||||
|
-- @param #number value The value which should be randomized
|
||||||
|
-- @param #number fac Randomization factor.
|
||||||
|
-- @param #number lower (Optional) Lower limit of the returned value.
|
||||||
|
-- @param #number upper (Optional) Upper limit of the returned value.
|
||||||
|
-- @return #number Randomized value.
|
||||||
|
-- @usage UTILS.Randomize(100, 0.1) returns a value between 90 and 110, i.e. a plus/minus ten percent variation.
|
||||||
|
-- @usage UTILS.Randomize(100, 0.5, nil, 120) returns a value between 50 and 120, i.e. a plus/minus fivty percent variation with upper bound 120.
|
||||||
|
function UTILS.Randomize(value, fac, lower, upper)
|
||||||
|
local min
|
||||||
|
if lower then
|
||||||
|
min=math.max(value-value*fac, lower)
|
||||||
|
else
|
||||||
|
min=value-value*fac
|
||||||
|
end
|
||||||
|
local max
|
||||||
|
if upper then
|
||||||
|
max=math.min(value+value*fac, upper)
|
||||||
|
else
|
||||||
|
max=value+value*fac
|
||||||
|
end
|
||||||
|
|
||||||
|
local r=math.random(min, max)
|
||||||
|
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1620,6 +1620,23 @@ function GROUP:InAir()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the DCS descriptor table of the nth unit of the group.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @param #number n (Optional) The number of the unit for which the dscriptor is returned.
|
||||||
|
-- @return DCS#Object.Desc The descriptor of the first unit of the group or #nil if the group does not exist any more.
|
||||||
|
function GROUP:GetDCSDesc(n)
|
||||||
|
-- Default.
|
||||||
|
n=n or 1
|
||||||
|
|
||||||
|
local unit=self:GetUnit(n)
|
||||||
|
if unit and unit:IsAlive()~=nil then
|
||||||
|
local desc=unit:GetDesc()
|
||||||
|
return desc
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
do -- Route methods
|
do -- Route methods
|
||||||
|
|
||||||
--- (AIR) Return the Group to an @{Wrapper.Airbase#AIRBASE}.
|
--- (AIR) Return the Group to an @{Wrapper.Airbase#AIRBASE}.
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ function UNIT:GetRange()
|
|||||||
local Desc = self:GetDesc()
|
local Desc = self:GetDesc()
|
||||||
|
|
||||||
if Desc then
|
if Desc then
|
||||||
local Range = Desc.range --This is in nautical miles for some reason.
|
local Range = Desc.range --This is in nautical miles for some reason. But should check again!
|
||||||
if Range then
|
if Range then
|
||||||
Range=UTILS.NMToMeters(Range)
|
Range=UTILS.NMToMeters(Range)
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user