Merge branch 'FF/OpsDev' of https://github.com/FlightControl-Master/MOOSE into FF/OpsDev

This commit is contained in:
Frank
2023-08-30 15:53:49 +02:00
21 changed files with 3791 additions and 427 deletions

View File

@@ -157,6 +157,8 @@ ASTAR = {
-- @field #number surfacetype Surface type. -- @field #number surfacetype Surface type.
-- @field #table valid Cached valid/invalid nodes. -- @field #table valid Cached valid/invalid nodes.
-- @field #table cost Cached cost. -- @field #table cost Cached cost.
-- @field Core.Pathline#PATHLINE pathline Pathline that node is part of.
-- @field Core.Pathline#PATHLINE.Point pathpoint Pathline point.
--- ASTAR infinity. --- ASTAR infinity.
-- @field #number INF -- @field #number INF
@@ -262,6 +264,33 @@ function ASTAR:AddNodeFromCoordinate(Coordinate)
return node return node
end end
--- Adds nodes to the table of grid nodes from a PATHLINE.
-- @param #ASTAR self
-- @param Core.Pathline#PATHLINE Pathline Pathline or name of pathline. Has to exist.
-- @return #ASTAR self
function ASTAR:AddNodeFromPathlineName(Pathline)
if type(Pathline)=="string" then
Pathline=PATHLINE:FindByName(Pathline)
end
if Pathline then
for i,_point in pairs(Pathline.points) do
local point=_point --Core.Pathline#PATHLINE.Point
local coord=COORDINATE:NewFromVec3(point.vec3)
local node=self:AddNodeFromCoordinate(coord)
node.pathline=Pathline
node.pathpoint=point
end
else
env.error("FF error pathline")
end
return self
end
--- Check if the coordinate of a node has is at a valid surface type. --- Check if the coordinate of a node has is at a valid surface type.
-- @param #ASTAR self -- @param #ASTAR self
-- @param #ASTAR.Node Node The node to be added. -- @param #ASTAR.Node Node The node to be added.
@@ -340,6 +369,18 @@ function ASTAR:SetValidNeighbourRoad(MaxDistance)
return self return self
end end
--- Set valid neighbours to be on the same pathline or not further apart than 10 meters.
-- @param #ASTAR self
-- @param #number MaxDistance Max distance between nodes in meters. Default is 2000 m.
-- @return #ASTAR self
function ASTAR:SetValidNeighbourPathline(MaxDistance)
self:SetValidNeighbourFunction(ASTAR.Pathline, MaxDistance)
return self
end
--- Set the function which calculates the "cost" to go from one to another node. --- Set the function which calculates the "cost" to go from one to another node.
-- The first to arguments of this function are always the two nodes under consideration. But you can add optional arguments. -- The first to arguments of this function are always the two nodes under consideration. But you can add optional arguments.
-- Very often the distance between nodes is a good measure for the cost. -- Very often the distance between nodes is a good measure for the cost.
@@ -384,7 +425,7 @@ end
-- @return #ASTAR self -- @return #ASTAR self
function ASTAR:SetCostRoad() function ASTAR:SetCostRoad()
self:SetCostFunction(ASTAR) self:SetCostFunction(ASTAR.Road)
return self return self
end end
@@ -544,6 +585,37 @@ function ASTAR.Road(nodeA, nodeB)
end end
--- Function to check if two nodes are on the same pathline or if nodes are less than 10 meters apart.
-- @param #ASTAR.Node nodeA First node.
-- @param #ASTAR.Node nodeB Other node.
-- @param #number distmax Max distance in meters. Default is 10 m.
-- @return #boolean If true, two nodes are connected.
function ASTAR.Pathline(nodeA, nodeB, distmax)
distmax=distmax or 10
if nodeA.pathpoint.name==nodeB.pathpoint.name then
local pathline=nodeA.pathline
local idxA=pathline:_GetPointIndex(nodeA.pathpoint)
local idxB=pathline:_GetPointIndex(nodeB.pathpoint)
if math.abs(idxA-idxB)<=1 then
return true
end
else
local dist=nodeA.coordinate:Get2DDistance(nodeB.coordinate)
if dist<distmax then
return true
end
end
return false
end
--- Function to check if distance between two nodes is less than a threshold distance. --- Function to check if distance between two nodes is less than a threshold distance.
-- @param #ASTAR.Node nodeA First node. -- @param #ASTAR.Node nodeA First node.
-- @param #ASTAR.Node nodeB Other node. -- @param #ASTAR.Node nodeB Other node.
@@ -567,7 +639,7 @@ end
-- @param #ASTAR.Node nodeB Other node. -- @param #ASTAR.Node nodeB Other node.
-- @return #number Distance between the two nodes. -- @return #number Distance between the two nodes.
function ASTAR.Dist2D(nodeA, nodeB) function ASTAR.Dist2D(nodeA, nodeB)
local dist=nodeA.coordinate:Get2DDistance(nodeB) local dist=nodeA.coordinate:Get2DDistance(nodeB.coordinate)
return dist return dist
end end
@@ -720,6 +792,9 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
-- Get current node. -- Get current node.
local current=self:_LowestFscore(openset, f_score) local current=self:_LowestFscore(openset, f_score)
self:I(current)
self:I(goal)
-- Check if we are at the end node. -- Check if we are at the end node.
if current.id==goal.id then if current.id==goal.id then
@@ -793,6 +868,32 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
return nil -- no valid path return nil -- no valid path
end end
--- A* pathfinding function. This seaches the path along nodes between start and end nodes/coordinates.
-- @param #ASTAR self
-- @param #boolean ExcludeStartNode If *true*, do not include start node in found path. Default is to include it.
-- @param #boolean ExcludeEndNode If *true*, do not include end node in found path. Default is to include it.
-- @return Core.Pathline#PATHLINE Pathline
function ASTAR:GetPathline(ExcludeStartNode, ExcludeEndNode)
local nodes=self:GetPath(ExcludeStartNode, ExcludeEndNode)
local pathline=nil --Core.Pathline#PATHLINE
if nodes then
pathline=PATHLINE:New("Astar")
for _,_note in pairs(nodes) do
local note=_note --#ASTAR.Node
pathline:AddPointFromVec3(note.coordinate)
end
end
return pathline
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- A* pathfinding helper functions -- A* pathfinding helper functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -821,6 +922,8 @@ function ASTAR:_HeuristicCost(nodeA, nodeB)
cost=self:_DistNodes(nodeA, nodeB) cost=self:_DistNodes(nodeA, nodeB)
end end
self:T(self.lid..string.format("Cost nodeA=%d --> nodeB=%d = %.1f", nodeA.id, nodeB.id, cost))
nodeA.cost[nodeB.id]=cost nodeA.cost[nodeB.id]=cost
nodeB.cost[nodeA.id]=cost -- Symmetric problem. nodeB.cost[nodeA.id]=cost -- Symmetric problem.

View File

@@ -32,10 +32,12 @@
-- @image Core_Database.JPG -- @image Core_Database.JPG
--- @type DATABASE --- DATABASE class.
-- @type DATABASE
-- @field #string ClassName Name of the class. -- @field #string ClassName Name of the class.
-- @field #table Templates Templates: Units, Groups, Statics, ClientsByName, ClientsByID. -- @field #table Templates Templates: Units, Groups, Statics, ClientsByName, ClientsByID.
-- @field #table CLIENTS Clients. -- @field #table CLIENTS Clients.
-- @field #table STORAGES DCS warehouse storages.
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator. --- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
@@ -50,6 +52,7 @@
-- * PLAYERSJOINED -- * PLAYERSJOINED
-- * PLAYERS -- * PLAYERS
-- * CARGOS -- * CARGOS
-- * STORAGES (DCS warehouses)
-- --
-- On top, for internal MOOSE administration purposes, the DATABASE administers the Unit and Group TEMPLATES as defined within the Mission Editor. -- On top, for internal MOOSE administration purposes, the DATABASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
-- --
@@ -90,6 +93,7 @@ DATABASE = {
FLIGHTCONTROLS = {}, FLIGHTCONTROLS = {},
OPSZONES = {}, OPSZONES = {},
PATHLINES = {}, PATHLINES = {},
STORAGES = {},
} }
local _DATABASECoalition = local _DATABASECoalition =
@@ -246,6 +250,38 @@ function DATABASE:FindAirbase( AirbaseName )
end end
--- Adds a STORAGE (DCS warehouse wrapper) based on the Airbase Name to the DATABASE.
-- @param #DATABASE self
-- @param #string AirbaseName The name of the airbase.
-- @return Wrapper.Storage#STORAGE Storage object.
function DATABASE:AddStorage( AirbaseName )
if not self.STORAGES[AirbaseName] then
self.STORAGES[AirbaseName] = STORAGE:New( AirbaseName )
end
return self.STORAGES[AirbaseName]
end
--- Deletes a STORAGE from the DATABASE based on the name of the associated airbase.
-- @param #DATABASE self
-- @param #string AirbaseName The name of the airbase.
function DATABASE:DeleteStorage( AirbaseName )
self.STORAGES[AirbaseName] = nil
end
--- Finds an STORAGE based on the name of the associated airbase.
-- @param #DATABASE self
-- @param #string AirbaseName Name of the airbase.
-- @return Wrapper.Storage#STORAGE The found STORAGE.
function DATABASE:FindStorage( AirbaseName )
local storage = self.STORAGES[AirbaseName]
return storage
end
do -- Zones and Pathlines do -- Zones and Pathlines
--- Finds a @{Core.Zone} based on the zone name. --- Finds a @{Core.Zone} based on the zone name.

View File

@@ -21,6 +21,7 @@
-- @field #string lid Class id string for output to DCS log file. -- @field #string lid Class id string for output to DCS log file.
-- @field #string name Name of the path line. -- @field #string name Name of the path line.
-- @field #table points List of 3D points defining the path. -- @field #table points List of 3D points defining the path.
-- @field #number counter Running number counting the point IDs.
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
--- *The shortest distance between two points is a straight line.* -- Archimedes --- *The shortest distance between two points is a straight line.* -- Archimedes
@@ -59,10 +60,13 @@ PATHLINE = {
ClassName = "PATHLINE", ClassName = "PATHLINE",
lid = nil, lid = nil,
points = {}, points = {},
counter = 0,
} }
--- Point of line. --- Point of line.
-- @type PATHLINE.Point -- @type PATHLINE.Point
-- @field #number uid Unique ID of this point.
-- @field #string name Name of the pathline this point belongs to.
-- @field DCS#Vec3 vec3 3D position. -- @field DCS#Vec3 vec3 3D position.
-- @field DCS#Vec2 vec2 2D position. -- @field DCS#Vec2 vec2 2D position.
-- @field #number surfaceType Surface type. -- @field #number surfaceType Surface type.
@@ -73,7 +77,7 @@ PATHLINE = {
--- PATHLINE class version. --- PATHLINE class version.
-- @field #string version -- @field #string version
PATHLINE.version="0.1.0" PATHLINE.version="0.2.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@@ -244,6 +248,7 @@ function PATHLINE:GetCoordinats()
for _,_point in pairs(self.points) do for _,_point in pairs(self.points) do
local point=_point --#PATHLINE.Point local point=_point --#PATHLINE.Point
local coord=COORDINATE:NewFromVec3(point.vec3) local coord=COORDINATE:NewFromVec3(point.vec3)
table.insert(vecs, coord)
end end
return vecs return vecs
@@ -311,7 +316,7 @@ function PATHLINE:MarkPoints(Switch)
if Switch==false then if Switch==false then
if point.markerID then if point.markerID then
UTILS.RemoveMark(point.markerID, Delay) UTILS.RemoveMark(point.markerID)
end end
else else
@@ -322,7 +327,7 @@ function PATHLINE:MarkPoints(Switch)
point.markerID=UTILS.GetMarkID() point.markerID=UTILS.GetMarkID()
local text=string.format("Pathline %s: Point #%d\nSurface Type=%d\nHeight=%.1f m\nDepth=%.1f m", self.name, i, point.surfaceType, point.landHeight, point.depth) local text=string.format("Pathline %s: Point #%d [UID=%d]\nSurface Type=%d\nHeight=%.1f m\nDepth=%.1f m", self.name, i, point.uid, point.surfaceType, point.landHeight, point.depth)
trigger.action.markToAll(point.markerID, text, point.vec3, "") trigger.action.markToAll(point.markerID, text, point.vec3, "")
@@ -343,6 +348,11 @@ function PATHLINE:_CreatePoint(Vec)
local point={} --#PATHLINE.Point local point={} --#PATHLINE.Point
self.counter=self.counter+1
point.uid=self.counter
point.name=self.name
if Vec.z then if Vec.z then
-- Given vec is 3D -- Given vec is 3D
point.vec3=UTILS.DeepCopy(Vec) point.vec3=UTILS.DeepCopy(Vec)
@@ -364,6 +374,23 @@ function PATHLINE:_CreatePoint(Vec)
return point return point
end end
--- Get index of point in the lua table.
-- @param #PATHLINE self
-- @param #Pathline.Point Point Given point.
-- @return #number index
function PATHLINE:_GetPointIndex(Point)
for i,_point in pairs(self.points) do
local point=_point --#Pathline.Point
if point.uid==Point.uid then
return i
end
end
return nil
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@@ -35,6 +35,13 @@
-- * Validate the presence of objects in the SET. -- * Validate the presence of objects in the SET.
-- * Trigger events when objects in the SET change a zone presence. -- * Trigger events when objects in the SET change a zone presence.
-- --
-- ## Notes on `FilterPrefixes()`:
--
-- This filter always looks for a **partial match** somewhere in the given field. LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through the following to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching).
-- For example, setting a filter like so `FilterPrefixes("Huey")` is perfectly all right, whilst `FilterPrefixes("UH-1H Al-Assad")` might not be due to the minus signs. A quick fix here is to use a dot (.)
-- in place of the special character, or escape it with a percentage sign (%), i.e. either `FilterPrefixes("UH.1H Al.Assad")` or `FilterPrefixes("UH%-1H Al%-Assad")` will give you the expected results.
--
-- === -- ===
-- --
-- ### Author: **FlightControl** -- ### Author: **FlightControl**
@@ -940,7 +947,8 @@ do
-- * @{#SET_GROUP.FilterCoalitions}: Builds the SET_GROUP with the groups belonging to the coalition(s). -- * @{#SET_GROUP.FilterCoalitions}: Builds the SET_GROUP with the groups belonging to the coalition(s).
-- * @{#SET_GROUP.FilterCategories}: Builds the SET_GROUP with the groups belonging to the category(ies). -- * @{#SET_GROUP.FilterCategories}: Builds the SET_GROUP with the groups belonging to the category(ies).
-- * @{#SET_GROUP.FilterCountries}: Builds the SET_GROUP with the groups belonging to the country(ies). -- * @{#SET_GROUP.FilterCountries}: Builds the SET_GROUP with the groups belonging to the country(ies).
-- * @{#SET_GROUP.FilterPrefixes}: Builds the SET_GROUP with the groups *containing* the given string in the group name. **Attention!** Bad naming convention, as this not really filtering *prefixes*. -- * @{#SET_GROUP.FilterPrefixes}: Builds the SET_GROUP with the groups *containing* the given string in the group name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- * @{#SET_GROUP.FilterActive}: Builds the SET_GROUP with the groups that are only active. Groups that are inactive (late activation) won't be included in the set! -- * @{#SET_GROUP.FilterActive}: Builds the SET_GROUP with the groups that are only active. Groups that are inactive (late activation) won't be included in the set!
-- --
-- For the Category Filter, extra methods have been added: -- For the Category Filter, extra methods have been added:
@@ -2052,7 +2060,8 @@ do -- SET_UNIT
-- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies). -- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies).
-- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s). -- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s).
-- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies). -- * @{#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.FilterPrefixes}: Builds the SET_UNIT with the units sharing the same string(s) in their name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- * @{#SET_UNIT.FilterActive}: Builds the SET_UNIT with the units that are only active. Units that are inactive (late activation) won't be included in the set! -- * @{#SET_UNIT.FilterActive}: Builds the SET_UNIT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
-- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Core.Zone#ZONE}. -- * @{#SET_UNIT.FilterZones}: Builds the SET_UNIT with the units within a @{Core.Zone#ZONE}.
-- --
@@ -3231,7 +3240,8 @@ do -- SET_STATIC
-- * @{#SET_STATIC.FilterCategories}: Builds the SET_STATIC with the units belonging to the category(ies). -- * @{#SET_STATIC.FilterCategories}: Builds the SET_STATIC with the units belonging to the category(ies).
-- * @{#SET_STATIC.FilterTypes}: Builds the SET_STATIC with the units belonging to the unit type(s). -- * @{#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.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.FilterPrefixes}: Builds the SET_STATIC with the units containing the same string(s) in their name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- * @{#SET_STATIC.FilterZones}: Builds the SET_STATIC with the units within a @{Core.Zone#ZONE}. -- * @{#SET_STATIC.FilterZones}: Builds the SET_STATIC with the units within a @{Core.Zone#ZONE}.
-- --
-- Once the filter criteria have been set for the SET_STATIC, you can start filtering using: -- Once the filter criteria have been set for the SET_STATIC, you can start filtering using:
@@ -3988,7 +3998,8 @@ do -- SET_CLIENT
-- * @{#SET_CLIENT.FilterCategories}: Builds the SET_CLIENT with the clients belonging to the category(ies). -- * @{#SET_CLIENT.FilterCategories}: Builds the SET_CLIENT with the clients belonging to the category(ies).
-- * @{#SET_CLIENT.FilterTypes}: Builds the SET_CLIENT with the clients belonging to the client type(s). -- * @{#SET_CLIENT.FilterTypes}: Builds the SET_CLIENT with the clients belonging to the client type(s).
-- * @{#SET_CLIENT.FilterCountries}: Builds the SET_CLIENT with the clients belonging to the country(ies). -- * @{#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.FilterPrefixes}: Builds the SET_CLIENT with the clients containing the same string(s) in their unit/pilot name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- * @{#SET_CLIENT.FilterActive}: Builds the SET_CLIENT with the units that are only active. Units that are inactive (late activation) won't be included in the set! -- * @{#SET_CLIENT.FilterActive}: Builds the SET_CLIENT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
-- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Core.Zone#ZONE}. -- * @{#SET_CLIENT.FilterZones}: Builds the SET_CLIENT with the clients within a @{Core.Zone#ZONE}.
-- --
@@ -4603,7 +4614,8 @@ do -- SET_PLAYER
-- * @{#SET_PLAYER.FilterCategories}: Builds the SET_PLAYER with the clients belonging to the category(ies). -- * @{#SET_PLAYER.FilterCategories}: Builds the SET_PLAYER with the clients belonging to the category(ies).
-- * @{#SET_PLAYER.FilterTypes}: Builds the SET_PLAYER with the clients belonging to the client type(s). -- * @{#SET_PLAYER.FilterTypes}: Builds the SET_PLAYER with the clients belonging to the client type(s).
-- * @{#SET_PLAYER.FilterCountries}: Builds the SET_PLAYER with the clients belonging to the country(ies). -- * @{#SET_PLAYER.FilterCountries}: Builds the SET_PLAYER with the clients belonging to the country(ies).
-- * @{#SET_PLAYER.FilterPrefixes}: Builds the SET_PLAYER with the clients sharing the same string(s) in their unit/pilot name. **ATTENTION** Bad naming convention as this *does not* only filter prefixes. -- * @{#SET_PLAYER.FilterPrefixes}: Builds the SET_PLAYER with the clients sharing the same string(s) in their unit/pilot name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- --
-- Once the filter criteria have been set for the SET_PLAYER, you can start filtering using: -- Once the filter criteria have been set for the SET_PLAYER, you can start filtering using:
-- --
@@ -5380,7 +5392,8 @@ do -- SET_CARGO
-- Filter criteria are defined by: -- Filter criteria are defined by:
-- --
-- * @{#SET_CARGO.FilterCoalitions}: Builds the SET_CARGO with the cargos belonging to the coalition(s). -- * @{#SET_CARGO.FilterCoalitions}: Builds the SET_CARGO with the cargos belonging to the coalition(s).
-- * @{#SET_CARGO.FilterPrefixes}: Builds the SET_CARGO with the cargos containing the same string(s). **ATTENTION** Bad naming convention as this *does not* only filter *prefixes*. -- * @{#SET_CARGO.FilterPrefixes}: Builds the SET_CARGO with the cargos containing the same string(s). **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- * @{#SET_CARGO.FilterTypes}: Builds the SET_CARGO with the cargos belonging to the cargo type(s). -- * @{#SET_CARGO.FilterTypes}: Builds the SET_CARGO with the cargos belonging to the cargo type(s).
-- * @{#SET_CARGO.FilterCountries}: Builds the SET_CARGO with the cargos belonging to the country(ies). -- * @{#SET_CARGO.FilterCountries}: Builds the SET_CARGO with the cargos belonging to the country(ies).
-- --
@@ -5802,7 +5815,8 @@ do -- SET_ZONE
-- You can set filter criteria to build the collection of zones in SET_ZONE. -- You can set filter criteria to build the collection of zones in SET_ZONE.
-- Filter criteria are defined by: -- Filter criteria are defined by:
-- --
-- * @{#SET_ZONE.FilterPrefixes}: Builds the SET_ZONE with the zones having a certain text pattern in their name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*. -- * @{#SET_ZONE.FilterPrefixes}: Builds the SET_ZONE with the zones having a certain text pattern in their name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- --
-- Once the filter criteria have been set for the SET_ZONE, you can start filtering using: -- Once the filter criteria have been set for the SET_ZONE, you can start filtering using:
-- --
@@ -6171,7 +6185,8 @@ do -- SET_ZONE_GOAL
-- You can set filter criteria to build the collection of zones in SET_ZONE_GOAL. -- You can set filter criteria to build the collection of zones in SET_ZONE_GOAL.
-- Filter criteria are defined by: -- Filter criteria are defined by:
-- --
-- * @{#SET_ZONE_GOAL.FilterPrefixes}: Builds the SET_ZONE_GOAL with the zones having a certain text pattern in their name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*. -- * @{#SET_ZONE_GOAL.FilterPrefixes}: Builds the SET_ZONE_GOAL with the zones having a certain text pattern in their name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- --
-- Once the filter criteria have been set for the SET_ZONE_GOAL, you can start filtering using: -- Once the filter criteria have been set for the SET_ZONE_GOAL, you can start filtering using:
-- --
@@ -6483,7 +6498,8 @@ do -- SET_OPSZONE
-- You can set filter criteria to build the collection of zones in SET_OPSZONE. -- You can set filter criteria to build the collection of zones in SET_OPSZONE.
-- Filter criteria are defined by: -- Filter criteria are defined by:
-- --
-- * @{#SET_OPSZONE.FilterPrefixes}: Builds the SET_OPSZONE with the zones having a certain text pattern in their name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*. -- * @{#SET_OPSZONE.FilterPrefixes}: Builds the SET_OPSZONE with the zones having a certain text pattern in their name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- --
-- Once the filter criteria have been set for the SET_OPSZONE, you can start filtering using: -- Once the filter criteria have been set for the SET_OPSZONE, you can start filtering using:
-- --
@@ -6949,7 +6965,8 @@ do -- SET_OPSGROUP
-- * @{#SET_OPSGROUP.FilterCoalitions}: Builds the SET_OPSGROUP with the groups belonging to the coalition(s). -- * @{#SET_OPSGROUP.FilterCoalitions}: Builds the SET_OPSGROUP with the groups belonging to the coalition(s).
-- * @{#SET_OPSGROUP.FilterCategories}: Builds the SET_OPSGROUP with the groups belonging to the category(ies). -- * @{#SET_OPSGROUP.FilterCategories}: Builds the SET_OPSGROUP with the groups belonging to the category(ies).
-- * @{#SET_OPSGROUP.FilterCountries}: Builds the SET_OPSGROUP with the groups belonging to the country(ies). -- * @{#SET_OPSGROUP.FilterCountries}: Builds the SET_OPSGROUP with the groups belonging to the country(ies).
-- * @{#SET_OPSGROUP.FilterPrefixes}: Builds the SET_OPSGROUP with the groups *containing* the given string in the group name. **Attention!** Bad naming convention, as this not really filtering *prefixes*. -- * @{#SET_OPSGROUP.FilterPrefixes}: Builds the SET_OPSGROUP with the groups *containing* the given string in the group name. **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results.
-- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching)
-- * @{#SET_OPSGROUP.FilterActive}: Builds the SET_OPSGROUP with the groups that are only active. Groups that are inactive (late activation) won't be included in the set! -- * @{#SET_OPSGROUP.FilterActive}: Builds the SET_OPSGROUP with the groups that are only active. Groups that are inactive (late activation) won't be included in the set!
-- --
-- For the Category Filter, extra methods have been added: -- For the Category Filter, extra methods have been added:

View File

@@ -810,10 +810,117 @@ do -- Airbase
-- @param self -- @param self
-- @return #Airbase.Desc -- @return #Airbase.Desc
--- Returns the warehouse object associated with the airbase object. Can then be used to call the warehouse class functions to modify the contents of the warehouse.
-- @function [parent=#Airbase] getWarehouse
-- @param self
-- @return #Warehouse The DCS warehouse object of this airbase.
--- Enables or disables the airbase and FARP auto capture game mechanic where ownership of a base can change based on the presence of ground forces or the
-- default setting assigned in the editor.
-- @function [parent=#Airbase] autoCapture
-- @param self
-- @param #boolean setting `true` : enables autoCapture behavior, `false` : disables autoCapture behavior
--- Returns the current autoCapture setting for the passed base.
-- @function [parent=#Airbase] autoCaptureIsOn
-- @param self
-- @return #boolean `true` if autoCapture behavior is enabled and `false` otherwise.
--- Changes the passed airbase object's coalition to the set value. Must be used with Airbase.autoCapture to disable auto capturing of the base,
-- otherwise the base can revert back to a different coalition depending on the situation and built in game capture rules.
-- @function [parent=#Airbase] setCoalition
-- @param self
-- @param #number coa The new owner coalition: 0=neutra, 1=red, 2=blue.
--- Returns the wsType of every object that exists in DCS. A wsType is a table consisting of 4 entries indexed numerically.
-- It can be used to broadly categorize object types. The table can be broken down as: {mainCategory, subCat1, subCat2, index}
-- @function [parent=#Airbase] getResourceMap
-- @param self
-- @return #table wsType of every object that exists in DCS.
Airbase = {} --#Airbase Airbase = {} --#Airbase
end -- Airbase end -- Airbase
do -- Warehouse
--- [DCS Class Warehouse](https://wiki.hoggitworld.com/view/DCS_Class_Warehouse)
-- The warehouse class gives control over warehouses that exist in airbase objects. These warehouses can limit the aircraft, munitions, and fuel available to coalition aircraft.
-- @type Warehouse
--- Get a warehouse by passing its name.
-- @function [parent=#Warehouse] getByName
-- @param #string Name Name of the warehouse.
-- @return #Warehouse The warehouse object.
--- Adds the passed amount of a given item to the warehouse.
-- itemName is the typeName associated with the item: "weapons.missiles.AIM_54C_Mk47"
-- A wsType table can also be used, however the last digit with wsTypes has been known to change. {4, 4, 7, 322}
-- @function [parent=#Warehouse] addItem
-- @param self
-- @param #string itemName Name of the item.
-- @param #number count Number of items to add.
--- Returns the number of the passed type of item currently in a warehouse object.
-- @function [parent=#Warehouse] getItemCount
-- @param self
-- @param #string itemName Name of the item.
--- Sets the passed amount of a given item to the warehouse.
-- @function [parent=#Warehouse] setItem
-- @param self
-- @param #string itemName Name of the item.
-- @param #number count Number of items to add.
--- Removes the amount of the passed item from the warehouse.
-- @function [parent=#Warehouse] removeItem
-- @param self
-- @param #string itemName Name of the item.
-- @param #number count Number of items to be removed.
--- Adds the passed amount of a liquid fuel into the warehouse inventory.
-- @function [parent=#Warehouse] addLiquid
-- @param self
-- @param #number liquidType Type of liquid to add: 0=jetfuel, 1=aviation gasoline, 2=MW50, 3=Diesel.
-- @param #number count Amount of liquid to add.
--- Returns the amount of the passed liquid type within a given warehouse.
-- @function [parent=#Warehouse] getLiquidAmount
-- @param self
-- @param #number liquidType Type of liquid to add: 0=jetfuel, 1=aviation gasoline, 2=MW50, 3=Diesel.
-- @return #number Amount of liquid.
--- Sets the passed amount of a liquid fuel into the warehouse inventory.
-- @function [parent=#Warehouse] setLiquidAmount
-- @param self
-- @param #number liquidType Type of liquid to add: 0=jetfuel, 1=aviation gasoline, 2=MW50, 3=Diesel.
-- @param #number count Amount of liquid.
--- Removes the set amount of liquid from the inventory in a warehouse.
-- @function [parent=#Warehouse] setLiquidAmount
-- @param self
-- @param #number liquidType Type of liquid to add: 0=jetfuel, 1=aviation gasoline, 2=MW50, 3=Diesel.
-- @param #number count Amount of liquid.
--- Returns the airbase object associated with the warehouse object.
-- @function [parent=#Warehouse] getOwner
-- @param self
-- @return #Airbase The airbase object owning this warehouse.
--- Returns a full itemized list of everything currently in a warehouse. If a category is set to unlimited then the table will be returned empty.
-- Aircraft and weapons are indexed by strings. Liquids are indexed by number.
-- @function [parent=#Warehouse] getInventory
-- @param self
-- @param #string itemName Name of the item.
-- @return #table Itemized list of everything currently in a warehouse
Warehouse = {} --#Warehouse
end
do -- Spot do -- Spot
--- [DCS Class Spot](https://wiki.hoggitworld.com/view/DCS_Class_Spot) --- [DCS Class Spot](https://wiki.hoggitworld.com/view/DCS_Class_Spot)

View File

@@ -591,7 +591,7 @@ RANGE.MenuF10Root = nil
--- Range script version. --- Range script version.
-- @field #string version -- @field #string version
RANGE.version = "2.7.0" RANGE.version = "2.7.1"
-- TODO list: -- TODO list:
-- TODO: Verbosity level for messages. -- TODO: Verbosity level for messages.
@@ -2044,6 +2044,7 @@ function RANGE:OnEventShot( EventData )
-- Attack parameters. -- Attack parameters.
local attackHdg=_unit:GetHeading() local attackHdg=_unit:GetHeading()
local attackAlt=_unit:GetHeight() local attackAlt=_unit:GetHeight()
attackAlt = UTILS.MetersToFeet(attackAlt)
local attackVel=_unit:GetVelocityKNOTS() local attackVel=_unit:GetVelocityKNOTS()
-- Tracking info and init of last bomb position. -- Tracking info and init of last bomb position.

View File

@@ -4101,9 +4101,9 @@ function WAREHOUSE:_RegisterAsset(group, ngroups, forceattribute, forcecargobay,
-- Get the size of an object. -- Get the size of an object.
local function _GetObjectSize(DCSdesc) local function _GetObjectSize(DCSdesc)
if DCSdesc.box then if DCSdesc.box then
local x=DCSdesc.box.max.x+math.abs(DCSdesc.box.min.x) --length local x=DCSdesc.box.max.x-DCSdesc.box.min.x --length
local y=DCSdesc.box.max.y+math.abs(DCSdesc.box.min.y) --height local y=DCSdesc.box.max.y-DCSdesc.box.min.y --height
local z=DCSdesc.box.max.z+math.abs(DCSdesc.box.min.z) --width local z=DCSdesc.box.max.z-DCSdesc.box.min.z --width
return math.max(x,z), x , y, z return math.max(x,z), x , y, z
end end
return 0,0,0,0 return 0,0,0,0

View File

@@ -50,6 +50,7 @@ __Moose.Include( 'Scripts/Moose/Wrapper/Static.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Unit.lua' ) __Moose.Include( 'Scripts/Moose/Wrapper/Unit.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Weapon.lua' ) __Moose.Include( 'Scripts/Moose/Wrapper/Weapon.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Net.lua' ) __Moose.Include( 'Scripts/Moose/Wrapper/Net.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Storage.lua' )
__Moose.Include( 'Scripts/Moose/Cargo/Cargo.lua' ) __Moose.Include( 'Scripts/Moose/Cargo/Cargo.lua' )
__Moose.Include( 'Scripts/Moose/Cargo/CargoUnit.lua' ) __Moose.Include( 'Scripts/Moose/Cargo/CargoUnit.lua' )

View File

@@ -46,6 +46,7 @@
-- === -- ===
-- --
-- ### Author: **funkyfranky** -- ### Author: **funkyfranky**
-- ### Additions for SRS and FARP: **applevangelist**
-- --
-- @module Ops.ATIS -- @module Ops.ATIS
-- @image OPS_ATIS.png -- @image OPS_ATIS.png
@@ -615,7 +616,7 @@ _ATIS = {}
--- ATIS class version. --- ATIS class version.
-- @field #string version -- @field #string version
ATIS.version = "0.9.15" ATIS.version = "0.9.16"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@@ -1278,7 +1279,8 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function ATIS:onafterStart( From, Event, To ) function ATIS:onafterStart( From, Event, To )
self:I("Airbase category is "..self.airbase:GetAirbaseCategory()) self:T({From, Event, To})
self:T("Airbase category is "..self.airbase:GetAirbaseCategory())
-- Check that this is an airdrome. -- Check that this is an airdrome.
if self.airbase:GetAirbaseCategory() == Airbase.Category.SHIP then if self.airbase:GetAirbaseCategory() == Airbase.Category.SHIP then
@@ -1340,7 +1342,7 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function ATIS:onafterStatus( From, Event, To ) function ATIS:onafterStatus( From, Event, To )
self:T({From, Event, To})
-- Get FSM state. -- Get FSM state.
local fsmstate = self:GetState() local fsmstate = self:GetState()
@@ -1362,7 +1364,7 @@ function ATIS:onafterStatus( From, Event, To )
self:T( self.lid .. text ) self:T( self.lid .. text )
if not self:Is("Stopped") then if not self:Is("Stopped") then
self:__Status( -60 ) self:__Status( 60 )
end end
end end
@@ -1376,7 +1378,8 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function ATIS:onafterCheckQueue( From, Event, To ) function ATIS:onafterCheckQueue( From, Event, To )
self:T({From, Event, To})
if not self:Is("Stopped") then
if self.useSRS then if self.useSRS then
self:Broadcast() self:Broadcast()
@@ -1392,9 +1395,9 @@ function ATIS:onafterCheckQueue( From, Event, To )
end end
if not self:Is("Stopped") then
-- Check back in 5 seconds. -- Check back in 5 seconds.
self:__CheckQueue( -math.abs( self.dTQueueCheck ) ) self:__CheckQueue( math.abs( self.dTQueueCheck ) )
end end
end end
@@ -1404,7 +1407,7 @@ end
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function ATIS:onafterBroadcast( From, Event, To ) function ATIS:onafterBroadcast( From, Event, To )
self:T({From, Event, To})
-- Get current coordinate. -- Get current coordinate.
local coord = self.airbase:GetCoordinate() local coord = self.airbase:GetCoordinate()
@@ -2156,8 +2159,9 @@ function ATIS:onafterBroadcast( From, Event, To )
if not self.ATISforFARPs then if not self.ATISforFARPs then
-- Active runway. -- Active runway.
local subtitle
if runwayLanding then if runwayLanding then
local subtitle=string.format("Active runway %s", runwayLanding) subtitle=string.format("Active runway %s", runwayLanding)
if rwyLandingLeft==true then if rwyLandingLeft==true then
subtitle=subtitle.." Left" subtitle=subtitle.." Left"
elseif rwyLandingLeft==false then elseif rwyLandingLeft==false then
@@ -2417,6 +2421,7 @@ end
-- @param #string To To state. -- @param #string To To state.
-- @param #string Text Report text. -- @param #string Text Report text.
function ATIS:onafterReport( From, Event, To, Text ) function ATIS:onafterReport( From, Event, To, Text )
self:T({From, Event, To})
self:T( self.lid .. string.format( "Report:\n%s", Text ) ) self:T( self.lid .. string.format( "Report:\n%s", Text ) )
if self.useSRS and self.msrs then if self.useSRS and self.msrs then

View File

@@ -5776,11 +5776,13 @@ function AUFTRAG:UpdateMarker()
-- Get target coordinates. Can be nil! -- Get target coordinates. Can be nil!
local targetcoord=self:GetTargetCoordinate() local targetcoord=self:GetTargetCoordinate()
if targetcoord then
if self.markerCoaliton and self.markerCoaliton>=0 then if self.markerCoaliton and self.markerCoaliton>=0 then
self.marker=MARKER:New(targetcoord, text):ReadOnly():ToCoalition(self.markerCoaliton) self.marker=MARKER:New(targetcoord, text):ReadOnly():ToCoalition(self.markerCoaliton)
else else
self.marker=MARKER:New(targetcoord, text):ReadOnly():ToAll() self.marker=MARKER:New(targetcoord, text):ReadOnly():ToAll()
end end
end
else else

View File

@@ -1807,7 +1807,7 @@ function COMMANDER:RecruitAssetsForEscort(Mission, Assets)
local Cohorts=self:_GetCohorts(Mission.escortLegions, Mission.escortCohorts, Mission.operation) local Cohorts=self:_GetCohorts(Mission.escortLegions, Mission.escortCohorts, Mission.operation)
-- Call LEGION function but provide COMMANDER as self. -- Call LEGION function but provide COMMANDER as self.
local assigned=LEGION.AssignAssetsForEscort(self, Cohorts, Assets, Mission.NescortMin, Mission.NescortMax, Mission.escortTargetTypes, Mission.escortEngageRange) local assigned=LEGION.AssignAssetsForEscort(self, Cohorts, Assets, Mission.NescortMin, Mission.NescortMax, Mission.escortMissionType, Mission.escortTargetTypes, Mission.escortEngageRange)
return assigned return assigned
end end

View File

@@ -347,6 +347,7 @@ FLIGHTCONTROL.version="0.7.3"
-- TODO: Talk me down option. -- TODO: Talk me down option.
-- TODO: Check runways and clean up. -- TODO: Check runways and clean up.
-- TODO: Add FARPS? -- TODO: Add FARPS?
-- TODO: Info on Taxi "Departing flights shall contact Tower to obtain ATC clearance before comencing taxing". On F10 menu as text and voice.
-- DONE: Improve ATC TTS messages. -- DONE: Improve ATC TTS messages.
-- DONE: ATIS option. -- DONE: ATIS option.
-- DONE: Runway destroyed. -- DONE: Runway destroyed.

View File

@@ -489,11 +489,17 @@ OPSGROUP.CargoStatus={
--- Element cargo bay data. --- Element cargo bay data.
-- @type OPSGROUP.MyCargo -- @type OPSGROUP.MyCargo
-- @field #OPSGROUP group The cargo group. -- @field #OPSGROUP group The cargo group.
-- @field #number storageType Type of storage.
-- @field #number storageAmount Amount of storage.
-- @field #number storageWeight Weight of storage item.
-- @field #boolean reserved If `true`, the cargo bay space is reserved but cargo has not actually been loaded yet. -- @field #boolean reserved If `true`, the cargo bay space is reserved but cargo has not actually been loaded yet.
--- Cargo group data. --- Cargo group data.
-- @type OPSGROUP.CargoGroup -- @type OPSGROUP.CargoGroup
-- @field #number uid Unique ID of this cargo data.
-- @field #string type Type of cargo: "OPSGROUP" or "STORAGE".
-- @field #OPSGROUP opsgroup The cargo opsgroup. -- @field #OPSGROUP opsgroup The cargo opsgroup.
-- @field Ops.OpsTransport#OPSTRANSPORT.Storage storage Storage data.
-- @field #boolean delivered If `true`, group was delivered. -- @field #boolean delivered If `true`, group was delivered.
-- @field #boolean disembarkActivation If `true`, group is activated. If `false`, group is late activated. -- @field #boolean disembarkActivation If `true`, group is activated. If `false`, group is late activated.
-- @field Core.Zone#ZONE disembarkZone Zone where this group is disembarked to. -- @field Core.Zone#ZONE disembarkZone Zone where this group is disembarked to.
@@ -2268,22 +2274,27 @@ end
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #number Delay Delay in seconds. Default now. -- @param #number Delay Delay in seconds. Default now.
-- @param #number ExplosionPower (Optional) Explosion power in kg TNT. Default 100 kg. -- @param #number ExplosionPower (Optional) Explosion power in kg TNT. Default 100 kg.
-- @param #string ElementName Name of the element that should be destroyed. Default is all elements.
-- @return #OPSGROUP self -- @return #OPSGROUP self
function OPSGROUP:SelfDestruction(Delay, ExplosionPower) function OPSGROUP:SelfDestruction(Delay, ExplosionPower, ElementName)
if Delay and Delay>0 then if Delay and Delay>0 then
self:ScheduleOnce(Delay, OPSGROUP.SelfDestruction, self, 0, ExplosionPower) self:ScheduleOnce(Delay, OPSGROUP.SelfDestruction, self, 0, ExplosionPower, ElementName)
else else
-- Loop over all elements. -- Loop over all elements.
for i,_element in pairs(self.elements) do for i,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element local element=_element --#OPSGROUP.Element
if ElementName==nil or ElementName==element.name then
local unit=element.unit local unit=element.unit
if unit and unit:IsAlive() then if unit and unit:IsAlive() then
unit:Explode(ExplosionPower or 100) unit:Explode(ExplosionPower or 100)
end end
end
end end
end end
@@ -3013,7 +3024,7 @@ function OPSGROUP:MarkWaypoints(Duration)
local waypoint=_waypoint --#OPSGROUP.Waypoint local waypoint=_waypoint --#OPSGROUP.Waypoint
local text=string.format("Waypoint ID=%d of %s", waypoint.uid, self.groupname) local text=string.format("Waypoint ID=%d of %s", waypoint.uid, self.groupname)
text=text..string.format("\nSpeed=%.1f kts, Alt=%d ft (%s)", UTILS.MpsToKnots(waypoint.speed), UTILS.MetersToFeet(waypoint.alt), "BARO") text=text..string.format("\nSpeed=%.1f kts, Alt=%d ft (%s)", UTILS.MpsToKnots(waypoint.speed), UTILS.MetersToFeet(waypoint.alt or 0), "BARO")
if waypoint.marker then if waypoint.marker then
if waypoint.marker.text~=text then if waypoint.marker.text~=text then
@@ -5452,10 +5463,10 @@ function OPSGROUP:onafterMissionExecute(From, Event, To, Mission)
if self.isFlightgroup then if self.isFlightgroup then
if Mission.prohibitABExecute == true then if Mission.prohibitABExecute == true then
self:SetProhibitAfterburner() self:SetProhibitAfterburner()
self:I("Set prohibit AB") self:T(self.lid.."Set prohibit AB")
elseif Mission.prohibitABExecute == false then elseif Mission.prohibitABExecute == false then
self:SetAllowAfterburner() self:SetAllowAfterburner()
self:T2("Set allow AB") self:T2(self.lid.."Set allow AB")
end end
end end
@@ -7446,36 +7457,55 @@ function OPSGROUP:onafterElementDead(From, Event, To, Element)
-- Clear cargo bay of element. -- Clear cargo bay of element.
for i=#Element.cargoBay,1,-1 do for i=#Element.cargoBay,1,-1 do
local cargo=Element.cargoBay[i] --#OPSGROUP.MyCargo local mycargo=Element.cargoBay[i] --#OPSGROUP.MyCargo
if mycargo.group then
-- Remove from cargo bay. -- Remove from cargo bay.
self:_DelCargobay(cargo.group) self:_DelCargobay(mycargo.group)
if cargo.group and not (cargo.group:IsDead() or cargo.group:IsStopped()) then if mycargo.group and not (mycargo.group:IsDead() or mycargo.group:IsStopped()) then
-- Remove my carrier -- Remove my carrier
cargo.group:_RemoveMyCarrier() mycargo.group:_RemoveMyCarrier()
if cargo.reserved then if mycargo.reserved then
-- This group was not loaded yet ==> Not cargo any more. -- This group was not loaded yet ==> Not cargo any more.
cargo.group:_NewCargoStatus(OPSGROUP.CargoStatus.NOTCARGO) mycargo.group:_NewCargoStatus(OPSGROUP.CargoStatus.NOTCARGO)
else else
-- Carrier dead ==> cargo dead. -- Carrier dead ==> cargo dead.
for _,cargoelement in pairs(cargo.group.elements) do for _,cargoelement in pairs(mycargo.group.elements) do
-- Debug info. -- Debug info.
self:T2(self.lid.."Cargo element dead "..cargoelement.name) self:T2(self.lid.."Cargo element dead "..cargoelement.name)
-- Trigger dead event. -- Trigger dead event.
cargo.group:ElementDead(cargoelement) mycargo.group:ElementDead(cargoelement)
end end
end end
end end
else
-- Add cargo to lost.
if self.cargoTZC then
for _,_cargo in pairs(self.cargoTZC.Cargos) do
local cargo=_cargo --#OPSGROUP.CargoGroup
if cargo.uid==mycargo.cargoUID then
cargo.storage.cargoLost=cargo.storage.cargoLost+mycargo.storageAmount
end
end
end
-- Remove cargo from cargo bay.
self:_DelCargobayElement(Element, mycargo)
end
end end
end end
@@ -7972,7 +8002,12 @@ function OPSGROUP:_CheckCargoTransport()
local element=_element --#OPSGROUP.Element local element=_element --#OPSGROUP.Element
for _,_cargo in pairs(element.cargoBay) do for _,_cargo in pairs(element.cargoBay) do
local cargo=_cargo --#OPSGROUP.MyCargo local cargo=_cargo --#OPSGROUP.MyCargo
if cargo.group then
text=text..string.format("\n- %s in carrier %s, reserved=%s", tostring(cargo.group:GetName()), tostring(element.name), tostring(cargo.reserved)) text=text..string.format("\n- %s in carrier %s, reserved=%s", tostring(cargo.group:GetName()), tostring(element.name), tostring(cargo.reserved))
else
text=text..string.format("\n- storage %s=%d kg in carrier %s [UID=%s]",
tostring(cargo.storageType), tostring(cargo.storageAmount*cargo.storageWeight), tostring(element.name), tostring(cargo.cargoUID))
end
end end
end end
if text=="" then if text=="" then
@@ -7993,6 +8028,7 @@ function OPSGROUP:_CheckCargoTransport()
text=text..string.format("\n[%d] UID=%d Status=%s: %s --> %s", i, transport.uid, transport:GetState(), pickupname, deployname) text=text..string.format("\n[%d] UID=%d Status=%s: %s --> %s", i, transport.uid, transport:GetState(), pickupname, deployname)
for j,_cargo in pairs(transport:GetCargos()) do for j,_cargo in pairs(transport:GetCargos()) do
local cargo=_cargo --#OPSGROUP.CargoGroup local cargo=_cargo --#OPSGROUP.CargoGroup
if cargo.type==OPSTRANSPORT.CargoType.OPSGROUP then
local state=cargo.opsgroup:GetState() local state=cargo.opsgroup:GetState()
local status=cargo.opsgroup.cargoStatus local status=cargo.opsgroup.cargoStatus
local name=cargo.opsgroup.groupname local name=cargo.opsgroup.groupname
@@ -8000,6 +8036,9 @@ function OPSGROUP:_CheckCargoTransport()
local carrierGroupname=carriergroup and carriergroup.groupname or "none" local carrierGroupname=carriergroup and carriergroup.groupname or "none"
local carrierElementname=carrierelement and carrierelement.name or "none" local carrierElementname=carrierelement and carrierelement.name or "none"
text=text..string.format("\n (%d) %s [%s]: %s, carrier=%s(%s), delivered=%s", j, name, state, status, carrierGroupname, carrierElementname, tostring(cargo.delivered)) text=text..string.format("\n (%d) %s [%s]: %s, carrier=%s(%s), delivered=%s", j, name, state, status, carrierGroupname, carrierElementname, tostring(cargo.delivered))
else
--TODO: STORAGE
end
end end
end end
if text~="" then if text~="" then
@@ -8074,42 +8113,51 @@ function OPSGROUP:_CheckCargoTransport()
-- Current pickup time. -- Current pickup time.
local tloading=Time-self.Tloading local tloading=Time-self.Tloading
--TODO: Check max loading time. If exceeded ==> abort transport. --TODO: Check max loading time. If exceeded ==> abort transport. Time might depend on required cargos, because we need to give them time to arrive.
-- Debug info. -- Debug info.
self:T(self.lid..string.format("Loading at %s [TZC UID=%d] for %s sec...", self.cargoTZC.PickupZone and self.cargoTZC.PickupZone:GetName() or "unknown", self.cargoTZC.uid, tloading)) self:T(self.lid..string.format("Loading at %s [TZC UID=%d] for %.1f sec...", self.cargoTZC.PickupZone and self.cargoTZC.PickupZone:GetName() or "unknown", self.cargoTZC.uid, tloading))
local boarding=false local boarding=false
local gotcargo=false local gotcargo=false
for _,_cargo in pairs(self.cargoTZC.Cargos) do for _,_cargo in pairs(self.cargoTZC.Cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if cargo.type==OPSTRANSPORT.CargoType.OPSTRANPORT then
-- Check if anyone is still boarding. -- Check if anyone is still boarding.
if cargo.opsgroup:IsBoarding(self.groupname) then if cargo.opsgroup and cargo.opsgroup:IsBoarding(self.groupname) then
boarding=true boarding=true
end end
-- Check if we have any cargo to transport. -- Check if we have any cargo to transport.
if cargo.opsgroup:IsLoaded(self.groupname) then if cargo.opsgroup and cargo.opsgroup:IsLoaded(self.groupname) then
gotcargo=true gotcargo=true
end end
else
-- Get cargo if it is in the cargo bay of any carrier element.
local mycargo=self:_GetMyCargoBayFromUID(cargo.uid)
if mycargo and mycargo.storageAmount>0 then
gotcargo=true
end
end
end end
-- Boarding finished ==> Transport cargo. -- Boarding finished ==> Transport cargo.
if gotcargo and self.cargoTransport:_CheckRequiredCargos(self.cargoTZC, self) and not boarding then if gotcargo and self.cargoTransport:_CheckRequiredCargos(self.cargoTZC, self) and not boarding then
self:T(self.lid.."Boarding finished ==> Loaded") self:T(self.lid.."Boarding/loading finished ==> Loaded")
self.Tloading=nil
self:LoadingDone() self:LoadingDone()
else else
-- No cargo and no one is boarding ==> check again if we can make anyone board. -- No cargo and no one is boarding ==> check again if we can make anyone board.
self:Loading() self:Loading()
end end
-- No cargo and no one is boarding ==> check again if we can make anyone board.
if not gotcargo and not boarding then
--self:Loading()
end
elseif self:IsTransporting() then elseif self:IsTransporting() then
-- Set time stamp. -- Set time stamp.
@@ -8136,6 +8184,8 @@ function OPSGROUP:_CheckCargoTransport()
for _,_cargo in pairs(self.cargoTZC.Cargos) do for _,_cargo in pairs(self.cargoTZC.Cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if cargo.type==OPSTRANSPORT.CargoType.OPSGROUP then
local carrierGroup=cargo.opsgroup:_GetMyCarrierGroup() local carrierGroup=cargo.opsgroup:_GetMyCarrierGroup()
-- Check that this group is -- Check that this group is
@@ -8144,6 +8194,21 @@ function OPSGROUP:_CheckCargoTransport()
break break
end end
else
---
-- STORAGE
---
-- Get cargo if it is in the cargo bay of any carrier element.
local mycargo=self:_GetMyCargoBayFromUID(cargo.uid)
if mycargo and not cargo.delivered then
delivered=false
break
end
end
end end
-- Unloading finished ==> pickup next batch or call it a day. -- Unloading finished ==> pickup next batch or call it a day.
@@ -8165,6 +8230,7 @@ function OPSGROUP:_CheckCargoTransport()
local text=string.format("Carrier [%s]: %s --> %s", self.carrierStatus, pickupname, deployname) local text=string.format("Carrier [%s]: %s --> %s", self.carrierStatus, pickupname, deployname)
for _,_cargo in pairs(self.cargoTransport:GetCargos(self.cargoTZC)) do for _,_cargo in pairs(self.cargoTransport:GetCargos(self.cargoTZC)) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if cargo.type==OPSTRANSPORT.CargoType.OPSGROUP then
local name=cargo.opsgroup:GetName() local name=cargo.opsgroup:GetName()
local gstatus=cargo.opsgroup:GetState() local gstatus=cargo.opsgroup:GetState()
local cstatus=cargo.opsgroup.cargoStatus local cstatus=cargo.opsgroup.cargoStatus
@@ -8173,6 +8239,9 @@ function OPSGROUP:_CheckCargoTransport()
local carrierGroupname=carriergroup and carriergroup.groupname or "none" local carrierGroupname=carriergroup and carriergroup.groupname or "none"
local carrierElementname=carrierelement and carrierelement.name or "none" local carrierElementname=carrierelement and carrierelement.name or "none"
text=text..string.format("\n- %s (%.1f kg) [%s]: %s, carrier=%s (%s), delivered=%s", name, weight, gstatus, cstatus, carrierElementname, carrierGroupname, tostring(cargo.delivered)) text=text..string.format("\n- %s (%.1f kg) [%s]: %s, carrier=%s (%s), delivered=%s", name, weight, gstatus, cstatus, carrierElementname, carrierGroupname, tostring(cargo.delivered))
else
--TODO: Storage
end
end end
self:I(self.lid..text) self:I(self.lid..text)
end end
@@ -8217,6 +8286,8 @@ function OPSGROUP:_AddCargobay(CargoGroup, CarrierElement, Reserved)
cargo.reserved=Reserved cargo.reserved=Reserved
else else
--cargo=self:_CreateMyCargo(CargoUID, CargoGroup)
cargo={} --#OPSGROUP.MyCargo cargo={} --#OPSGROUP.MyCargo
cargo.group=CargoGroup cargo.group=CargoGroup
cargo.reserved=Reserved cargo.reserved=Reserved
@@ -8244,6 +8315,95 @@ function OPSGROUP:_AddCargobay(CargoGroup, CarrierElement, Reserved)
return self return self
end end
--- Add warehouse storage to cargo bay of a carrier.
-- @param #OPSGROUP self
-- @param #OPSGROUP.Element CarrierElement The element of the carrier.
-- @param #number CargoUID UID of the cargo data.
-- @param #string StorageType Storage type.
-- @param #number StorageAmount Storage amount.
-- @param #number StorageWeight Weight of a single storage item in kg.
function OPSGROUP:_AddCargobayStorage(CarrierElement, CargoUID, StorageType, StorageAmount, StorageWeight)
local MyCargo=self:_CreateMyCargo(CargoUID, nil, StorageType, StorageAmount, StorageWeight)
self:_AddMyCargoBay(MyCargo, CarrierElement)
end
--- Add OPSGROUP to cargo bay of a carrier.
-- @param #OPSGROUP self
-- @param #number CargoUID UID of the cargo data.
-- @param #OPSGROUP OpsGroup Cargo group.
-- @param #string StorageType Storage type.
-- @param #number StorageAmount Storage amount.
-- @param #number StorageWeight Weight of a single storage item in kg.
-- @return #OPSGROUP.MyCargo My cargo object.
function OPSGROUP:_CreateMyCargo(CargoUID, OpsGroup, StorageType, StorageAmount, StorageWeight)
local cargo={} --#OPSGROUP.MyCargo
cargo.cargoUID=CargoUID
cargo.group=OpsGroup
cargo.storageType=StorageType
cargo.storageAmount=StorageAmount
cargo.storageWeight=StorageWeight
cargo.reserved=false
return cargo
end
--- Add storage to cargo bay of a carrier.
-- @param #OPSGROUP self
-- @param #OPSGROUP.MyCargo MyCargo My cargo.
-- @param #OPSGROUP.Element CarrierElement The element of the carrier.
function OPSGROUP:_AddMyCargoBay(MyCargo, CarrierElement)
table.insert(CarrierElement.cargoBay, MyCargo)
if not MyCargo.reserved then
-- Cargo weight.
local weight=0
if MyCargo.group then
weight=MyCargo.group:GetWeightTotal()
else
weight=MyCargo.storageAmount*MyCargo.storageWeight
end
-- Add weight to carrier.
self:AddWeightCargo(CarrierElement.name, weight)
end
end
--- Get cargo bay data from a cargo data id.
-- @param #OPSGROUP self
-- @param #number uid Unique ID of cargo data.
-- @return #OPSGROUP.MyCargo Cargo My cargo.
-- @return #OPSGROUP.Element Element that has loaded the cargo.
function OPSGROUP:_GetMyCargoBayFromUID(uid)
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
for i,_mycargo in pairs(element.cargoBay) do
local mycargo=_mycargo --#OPSGROUP.MyCargo
if mycargo.cargoUID and mycargo.cargoUID==uid then
return mycargo, element, i
end
end
end
return nil, nil, nil
end
--- Get all groups currently loaded as cargo. --- Get all groups currently loaded as cargo.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string CarrierName (Optional) Only return cargo groups loaded into a particular carrier unit. -- @param #string CarrierName (Optional) Only return cargo groups loaded into a particular carrier unit.
@@ -8291,6 +8451,51 @@ function OPSGROUP:_GetCargobay(CargoGroup)
return nil, nil, nil return nil, nil, nil
end end
--- Remove OPSGROUP from cargo bay of a carrier.
-- @param #OPSGROUP self
-- @param #OPSGROUP.Element Element Cargo group.
-- @param #number CargoUID Cargo UID.
-- @return #OPSGROUP.MyCargo MyCargo My cargo data.
function OPSGROUP:_GetCargobayElement(Element, CargoUID)
self:T3({Element=Element, CargoUID=CargoUID})
for i,_mycargo in pairs(Element.cargoBay) do
local mycargo=_mycargo --#OPSGROUP.MyCargo
if mycargo.cargoUID and mycargo.cargoUID==CargoUID then
return mycargo
end
end
return nil
end
--- Remove OPSGROUP from cargo bay of a carrier.
-- @param #OPSGROUP self
-- @param #OPSGROUP.Element Element Cargo group.
-- @param #OPSGROUP.MyCargo MyCargo My cargo data.
-- @return #boolean If `true`, cargo could be removed.
function OPSGROUP:_DelCargobayElement(Element, MyCargo)
for i,_mycargo in pairs(Element.cargoBay) do
local mycargo=_mycargo --#OPSGROUP.MyCargo
if mycargo.cargoUID and MyCargo.cargoUID and mycargo.cargoUID==MyCargo.cargoUID then
if MyCargo.group then
self:RedWeightCargo(Element.name, MyCargo.group:GetWeightTotal())
else
self:RedWeightCargo(Element.name, MyCargo.storageAmount*MyCargo.storageWeight)
end
table.remove(Element.cargoBay, i)
return true
end
end
return false
end
--- Remove OPSGROUP from cargo bay of a carrier. --- Remove OPSGROUP from cargo bay of a carrier.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #OPSGROUP CargoGroup Cargo group. -- @param #OPSGROUP CargoGroup Cargo group.
@@ -8385,11 +8590,13 @@ function OPSGROUP:_CheckDelivered(CargoTransport)
for _,_cargo in pairs(CargoTransport:GetCargos()) do for _,_cargo in pairs(CargoTransport:GetCargos()) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if self:CanCargo(cargo.opsgroup) then if self:CanCargo(cargo) then
if cargo.delivered then if cargo.delivered then
-- This one is delivered. -- This one is delivered.
elseif cargo.opsgroup==nil or cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped() then elseif cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and cargo.opsgroup==nil then
elseif cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and (cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped()) then
-- This one is dead. -- This one is dead.
else else
done=false --Someone is not done! done=false --Someone is not done!
@@ -8419,13 +8626,13 @@ function OPSGROUP:_CheckGoPickup(CargoTransport)
for _,_cargo in pairs(CargoTransport:GetCargos()) do for _,_cargo in pairs(CargoTransport:GetCargos()) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if self:CanCargo(cargo.opsgroup) then if self:CanCargo(cargo) then
if cargo.delivered then if cargo.delivered then
-- This one is delivered. -- This one is delivered.
elseif cargo.opsgroup==nil or cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped() then elseif cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and (cargo.opsgroup==nil or cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped()) then
-- This one is dead. -- This one is dead.
elseif cargo.opsgroup:IsLoaded(CargoTransport:_GetCarrierNames()) then elseif cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and (cargo.opsgroup:IsLoaded(CargoTransport:_GetCarrierNames())) then
-- This one is loaded into a(nother) carrier. -- This one is loaded into a(nother) carrier.
else else
done=false --Someone is not done! done=false --Someone is not done!
@@ -8650,8 +8857,11 @@ function OPSGROUP:GetWeightCargo(UnitName, IncludeReserved)
for _,_cargo in pairs(element.cargoBay) do for _,_cargo in pairs(element.cargoBay) do
local cargo=_cargo --#OPSGROUP.MyCargo local cargo=_cargo --#OPSGROUP.MyCargo
if (not cargo.reserved) or (cargo.reserved==true and (IncludeReserved==true or IncludeReserved==nil)) then if (not cargo.reserved) or (cargo.reserved==true and (IncludeReserved==true or IncludeReserved==nil)) then
local cargoweight=cargo.group:GetWeightTotal() if cargo.group then
gewicht=gewicht+cargoweight gewicht=gewicht+cargo.group:GetWeightTotal()
else
gewicht=gewicht+cargo.storageAmount*cargo.storageWeight
end
--self:I(self.lid..string.format("unit=%s (reserved=%s): cargo=%s weight=%d, total weight=%d", tostring(UnitName), tostring(IncludeReserved), cargo.group:GetName(), cargoweight, weight)) --self:I(self.lid..string.format("unit=%s (reserved=%s): cargo=%s weight=%d, total weight=%d", tostring(UnitName), tostring(IncludeReserved), cargo.group:GetName(), cargoweight, weight))
end end
end end
@@ -8745,16 +8955,46 @@ function OPSGROUP:RedWeightCargo(UnitName, Weight)
return self return self
end end
--- Get weight of warehouse storage to transport.
-- @param #OPSGROUP self
-- @param Ops.OpsTransport#OPSTRANSPORT.Storage Storage
-- @param #boolean Total Get total weight. Otherweise the amount left to deliver (total-loaded-lost-delivered).
-- @param #boolean Reserved Reduce weight that is reserved.
-- @param #boolean Amount Return amount not weight.
-- @return #number Weight of cargo in kg or amount in number of items, if `Amount=true`.
function OPSGROUP:_GetWeightStorage(Storage, Total, Reserved, Amount)
local weight=Storage.cargoAmount
if not Total then
weight=weight-Storage.cargoLost-Storage.cargoLoaded-Storage.cargoDelivered
end
if Reserved then
weight=weight-Storage.cargoReserved
end
if not Amount then
weight=weight*Storage.cargoWeight
end
return weight
end
--- Check if the group can *in principle* be carrier of a cargo group. This checks the max cargo capacity of the group but *not* how much cargo is already loaded (if any). --- Check if the group can *in principle* be carrier of a cargo group. This checks the max cargo capacity of the group but *not* how much cargo is already loaded (if any).
-- **Note** that the cargo group *cannot* be split into units, i.e. the largest cargo bay of any element of the group must be able to load the whole cargo group in one piece. -- **Note** that the cargo group *cannot* be split into units, i.e. the largest cargo bay of any element of the group must be able to load the whole cargo group in one piece.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #OPSGROUP CargoGroup Cargo group, which needs a carrier. -- @param Ops.OpsGroup#OPSGROUP.CargoGroup Cargo Cargo data, which needs a carrier.
-- @return #boolean If `true`, there is an element of the group that can load the whole cargo group. -- @return #boolean If `true`, there is an element of the group that can load the whole cargo group.
function OPSGROUP:CanCargo(CargoGroup) function OPSGROUP:CanCargo(Cargo)
if CargoGroup then if Cargo then
local weight=CargoGroup:GetWeightTotal() local weight=math.huge
if Cargo.type==OPSTRANSPORT.CargoType.OPSGROUP then
local weight=Cargo.opsgroup:GetWeightTotal()
for _,_element in pairs(self.elements) do for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element local element=_element --#OPSGROUP.Element
@@ -8763,31 +9003,58 @@ function OPSGROUP:CanCargo(CargoGroup)
if element and element.status~=OPSGROUP.ElementStatus.DEAD and element.weightMaxCargo>=weight then if element and element.status~=OPSGROUP.ElementStatus.DEAD and element.weightMaxCargo>=weight then
return true return true
end end
end
else
---
-- STORAGE
---
-- Since storage cargo can be devided onto multiple carriers, we take the weight of a single cargo item (even 1 kg of fuel).
weight=Cargo.storage.cargoWeight
end end
-- Calculate cargo bay space.
local bay=0
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
-- Check that element is not dead and has
if element and element.status~=OPSGROUP.ElementStatus.DEAD then
bay=bay+element.weightMaxCargo
end
end
-- Check if cargo fits into cargo bay(s) of carrier group.
if bay>=weight then
return true
end
end end
return false return false
end end
--- Add weight to the internal cargo of an element of the group. --- Find carrier for cargo by evaluating the free cargo bay storage.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #OPSGROUP CargoGroup Cargo group, which needs a carrier. -- @param #number Weight Weight of cargo in kg.
-- @return #OPSGROUP.Element Carrier able to transport the cargo. -- @return #OPSGROUP.Element Carrier able to transport the cargo.
function OPSGROUP:FindCarrierForCargo(CargoGroup) function OPSGROUP:FindCarrierForCargo(Weight)
local weight=CargoGroup:GetWeightTotal()
for _,_element in pairs(self.elements) do for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element local element=_element --#OPSGROUP.Element
local free=self:GetFreeCargobay(element.name) local free=self:GetFreeCargobay(element.name)
if free>=weight then if free>=Weight then
return element return element
else else
self:T3(self.lid..string.format("%s: Weight %d>%d free cargo bay", element.name, weight, free)) self:T3(self.lid..string.format("%s: Weight %d>%d free cargo bay", element.name, Weight, free))
end end
end end
@@ -9068,6 +9335,36 @@ function OPSGROUP:onafterPickup(From, Event, To)
end end
--- On after "Loading" event.
-- @param #OPSGROUP self
-- @param #table Cargos Table of cargos.
-- @return #table Table of sorted cargos.
function OPSGROUP:_SortCargo(Cargos)
-- Sort results table wrt descending weight.
local function _sort(a, b)
local cargoA=a --Ops.OpsGroup#OPSGROUP.CargoGroup
local cargoB=b --Ops.OpsGroup#OPSGROUP.CargoGroup
local weightA=0
local weightB=0
if cargoA.opsgroup then
weightA=cargoA.opsgroup:GetWeightTotal()
else
weightA=self:_GetWeightStorage(cargoA.storage)
end
if cargoB.opsgroup then
weightB=cargoB.opsgroup:GetWeightTotal()
else
weightB=self:_GetWeightStorage(cargoB.storage)
end
return weightA>weightB
end
table.sort(Cargos, _sort)
return Cargos
end
--- On after "Loading" event. --- On after "Loading" event.
-- @param #OPSGROUP self -- @param #OPSGROUP self
@@ -9079,32 +9376,30 @@ function OPSGROUP:onafterLoading(From, Event, To)
-- Set carrier status. -- Set carrier status.
self:_NewCarrierStatus(OPSGROUP.CarrierStatus.LOADING) self:_NewCarrierStatus(OPSGROUP.CarrierStatus.LOADING)
-- Loading time stamp.
self.Tloading=timer.getAbsTime()
-- Get valid cargos of the TZC. -- Get valid cargos of the TZC.
local cargos={} local cargos={}
for _,_cargo in pairs(self.cargoTZC.Cargos) do for _,_cargo in pairs(self.cargoTZC.Cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
-- Check if this group can carry the cargo. -- Check if this group can carry the cargo.
local canCargo=self:CanCargo(cargo.opsgroup) local canCargo=self:CanCargo(cargo)
-- Check if this group is currently acting as carrier. -- Check if this group is currently acting as carrier.
local isCarrier=cargo.opsgroup:IsPickingup() or cargo.opsgroup:IsLoading() or cargo.opsgroup:IsTransporting() or cargo.opsgroup:IsUnloading() local isCarrier=false
-- Check if cargo is not already cargo. -- Check if cargo is not already cargo.
local isNotCargo=cargo.opsgroup:IsNotCargo(true) local isNotCargo=true
-- Check if cargo is holding or loaded -- Check if cargo is holding or loaded
local isHolding=cargo.opsgroup:IsHolding() or cargo.opsgroup:IsLoaded() local isHolding=cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and (cargo.opsgroup:IsHolding() or cargo.opsgroup:IsLoaded()) or true
-- Check if cargo is in embark/pickup zone. -- Check if cargo is in embark/pickup zone.
-- Added InUtero here, if embark zone is moving (ship) and cargo has been spawned late activated and its position is not updated. Not sure if that breaks something else! -- Added InUtero here, if embark zone is moving (ship) and cargo has been spawned late activated and its position is not updated. Not sure if that breaks something else!
local inZone=cargo.opsgroup:IsInZone(self.cargoTZC.EmbarkZone) or cargo.opsgroup:IsInUtero() local inZone=cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and (cargo.opsgroup:IsInZone(self.cargoTZC.EmbarkZone) or cargo.opsgroup:IsInUtero()) or true
-- Check if cargo is currently on a mission. -- Check if cargo is currently on a mission.
local isOnMission=cargo.opsgroup:IsOnMission() local isOnMission=cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and cargo.opsgroup:IsOnMission() or false
-- Check if current mission is using this ops transport. -- Check if current mission is using this ops transport.
if isOnMission then if isOnMission then
@@ -9114,39 +9409,114 @@ function OPSGROUP:onafterLoading(From, Event, To)
end end
end end
local isAvail=true
if cargo.type==OPSTRANSPORT.CargoType.STORAGE then
local nAvail=cargo.storage.storageFrom:GetAmount(cargo.storage.cargoType)
if nAvail>0 then
isAvail=true
else
isAvail=false
end
else
isCarrier=cargo.opsgroup:IsPickingup() or cargo.opsgroup:IsLoading() or cargo.opsgroup:IsTransporting() or cargo.opsgroup:IsUnloading()
isNotCargo=cargo.opsgroup:IsNotCargo(true)
end
local isDead=cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and cargo.opsgroup:IsDead() or false
-- Debug message. -- Debug message.
self:T(self.lid..string.format("Loading: canCargo=%s, isCarrier=%s, isNotCargo=%s, isHolding=%s, isOnMission=%s", self:T(self.lid..string.format("Loading: canCargo=%s, isCarrier=%s, isNotCargo=%s, isHolding=%s, isOnMission=%s",
tostring(canCargo), tostring(isCarrier), tostring(isNotCargo), tostring(isHolding), tostring(isOnMission))) tostring(canCargo), tostring(isCarrier), tostring(isNotCargo), tostring(isHolding), tostring(isOnMission)))
-- TODO: Need a better :IsBusy() function or :IsReadyForMission() :IsReadyForBoarding() :IsReadyForTransport() -- TODO: Need a better :IsBusy() function or :IsReadyForMission() :IsReadyForBoarding() :IsReadyForTransport()
if canCargo and inZone and isNotCargo and isHolding and (not (cargo.delivered or cargo.opsgroup:IsDead() or isCarrier or isOnMission)) then if canCargo and inZone and isNotCargo and isHolding and isAvail and (not (cargo.delivered or isDead or isCarrier or isOnMission)) then
table.insert(cargos, cargo) table.insert(cargos, cargo)
end end
end end
-- Sort results table wrt descending weight. -- Sort cargos.
local function _sort(a, b) self:_SortCargo(cargos)
local cargoA=a --Ops.OpsGroup#OPSGROUP.CargoGroup
local cargoB=b --Ops.OpsGroup#OPSGROUP.CargoGroup
return cargoA.opsgroup:GetWeightTotal()>cargoB.opsgroup:GetWeightTotal()
end
table.sort(cargos, _sort)
-- Loop over all cargos. -- Loop over all cargos.
for _,_cargo in pairs(cargos) do for _,_cargo in pairs(cargos) do
local cargo=_cargo --#OPSGROUP.CargoGroup local cargo=_cargo --#OPSGROUP.CargoGroup
-- Find a carrier for this cargo. local weight=nil
local carrier=self:FindCarrierForCargo(cargo.opsgroup) if cargo.type==OPSTRANSPORT.CargoType.OPSGROUP then
if carrier then weight=cargo.opsgroup:GetWeightTotal()
-- Find a carrier for this cargo.
local carrier=self:FindCarrierForCargo(weight)
-- Order cargo group to board the carrier. -- Order cargo group to board the carrier.
if carrier then
cargo.opsgroup:Board(self, carrier) cargo.opsgroup:Board(self, carrier)
end
else
---
-- STORAGE
---
-- Get weight of cargo that needs to be transported.
weight=self:_GetWeightStorage(cargo.storage, false)
-- Get amount that the warehouse currently has.
local Amount=cargo.storage.storageFrom:GetAmount(cargo.storage.cargoType)
local Weight=Amount*cargo.storage.cargoWeight
-- Make sure, we do not take more than the warehouse can provide.
weight=math.min(weight, Weight)
-- Debug info.
self:T(self.lid..string.format("Loading storage weight=%d kg (warehouse has %d kg)!", weight, Weight))
-- Loop over all elements of the carrier group.
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
-- Get the free cargo space of the carrier.
local free=self:GetFreeCargobay(element.name)
-- Min of weight or bay.
local w=math.min(weight, free)
-- Check that weight is >0 and also greater that at least one item. We cannot transport half a missile.
if w>=cargo.storage.cargoWeight then
-- Calculate item amount.
local amount=math.floor(w/cargo.storage.cargoWeight)
-- Remove items from warehouse.
cargo.storage.storageFrom:RemoveAmount(cargo.storage.cargoType, amount)
-- Add amount to loaded cargo.
cargo.storage.cargoLoaded=cargo.storage.cargoLoaded+amount
-- Add cargo to cargo by of element.
self:_AddCargobayStorage(element, cargo.uid, cargo.storage.cargoType, amount, cargo.storage.cargoWeight)
-- Reduce weight for the next element (if any).
weight=weight-amount*cargo.storage.cargoWeight
-- Debug info.
local text=string.format("Element %s: loaded amount=%d (weight=%d) ==> left=%d kg", element.name, amount, amount*cargo.storage.cargoWeight, weight)
self:T(self.lid..text)
-- If no cargo left, break the loop.
if weight<=0 then
break
end
end
end end
end end
end
end end
--- Set (new) cargo status. --- Set (new) cargo status.
@@ -9323,6 +9693,8 @@ function OPSGROUP:onafterTransport(From, Event, To)
end end
end end
--env.info(string.format("FF Transport: Zone=%s inzone=%s, ready2deploy=%s", Zone:GetName(), tostring(inzone), tostring(ready2deploy)))
if inzone then if inzone then
-- We are already in the deploy zone ==> wait and initiate unloading. -- We are already in the deploy zone ==> wait and initiate unloading.
@@ -9480,6 +9852,8 @@ function OPSGROUP:onafterUnloading(From, Event, To)
for _,_cargo in pairs(self.cargoTZC.Cargos) do for _,_cargo in pairs(self.cargoTZC.Cargos) do
local cargo=_cargo --#OPSGROUP.CargoGroup local cargo=_cargo --#OPSGROUP.CargoGroup
if cargo.type==OPSTRANSPORT.CargoType.OPSGROUP then
-- Check that cargo is loaded into this group. -- Check that cargo is loaded into this group.
-- NOTE: Could be that the element carriing this cargo group is DEAD, which would mean that the cargo group is also DEAD. -- NOTE: Could be that the element carriing this cargo group is DEAD, which would mean that the cargo group is also DEAD.
if cargo.opsgroup:IsLoaded(self.groupname) and not cargo.opsgroup:IsDead() then if cargo.opsgroup:IsLoaded(self.groupname) and not cargo.opsgroup:IsDead() then
@@ -9617,6 +9991,67 @@ function OPSGROUP:onafterUnloading(From, Event, To)
-- Not loaded or dead -- Not loaded or dead
end end
else
---
-- STORAGE
---
-- TODO: should proabaly move this check to the top to include OPSGROUPS as well?!
if not cargo.delivered then
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
-- Get my cargo from cargo bay of element.
local mycargo=self:_GetCargobayElement(element, cargo.uid)
if mycargo then
-- Add cargo to warehouse storage.
cargo.storage.storageTo:AddAmount(mycargo.storageType, mycargo.storageAmount)
-- Add amount to delivered.
cargo.storage.cargoDelivered=cargo.storage.cargoDelivered+mycargo.storageAmount
-- Reduce loaded amount.
cargo.storage.cargoLoaded=cargo.storage.cargoLoaded-mycargo.storageAmount
-- Remove cargo from bay.
self:_DelCargobayElement(element, mycargo)
-- Debug info
self:T2(self.lid..string.format("Cargo loaded=%d, delivered=%d, lost=%d", cargo.storage.cargoLoaded, cargo.storage.cargoDelivered, cargo.storage.cargoLost))
end
end
-- Get amount that was delivered.
local amountToDeliver=self:_GetWeightStorage(cargo.storage, false, false, true)
-- Get total amount to be delivered.
local amountTotal=self:_GetWeightStorage(cargo.storage, true, false, true)
-- Debug info.
local text=string.format("Amount delivered=%d, total=%d", amountToDeliver, amountTotal)
self:T(self.lid..text)
if amountToDeliver<=0 then
-- Cargo was delivered (somehow).
cargo.delivered=true
-- Increase number of delivered cargos.
self.cargoTransport.Ndelivered=self.cargoTransport.Ndelivered+1
-- Debug info.
local text=string.format("Ndelivered=%d delivered=%s", self.cargoTransport.Ndelivered, tostring(cargo.delivered))
self:T(self.lid..text)
end
end
end
end -- loop over cargos end -- loop over cargos
end end
@@ -10047,7 +10482,7 @@ function OPSGROUP:onafterBoard(From, Event, To, CarrierGroup, Carrier)
-- Debug info. -- Debug info.
self:T(self.lid..string.format("Group is loaded currently ==> Moving directly to new carrier - No Unload(), Disembart() events triggered!")) self:T(self.lid..string.format("Group is loaded currently ==> Moving directly to new carrier - No Unload(), Disembart() events triggered!"))
-- Remove my carrier. -- Remove old/current carrier.
self:_RemoveMyCarrier() self:_RemoveMyCarrier()
-- Trigger Load event. -- Trigger Load event.

View File

@@ -1,8 +1,9 @@
--- **Ops** - Troop transport assignment for OPS groups. --- **Ops** - Transport assignment for OPS groups and storage.
-- --
-- ## Main Features: -- ## Main Features:
-- --
-- * Transport troops from A to B -- * Transport troops from A to B
-- * Transport of warehouse storage (fuel, weapons and equipment)
-- * Supports ground, naval and airborne (airplanes and helicopters) units as carriers -- * Supports ground, naval and airborne (airplanes and helicopters) units as carriers
-- * Use combined forces (ground, naval, air) to transport the troops -- * Use combined forces (ground, naval, air) to transport the troops
-- * Additional FSM events to hook into and customize your mission design -- * Additional FSM events to hook into and customize your mission design
@@ -63,6 +64,7 @@
-- @field Ops.Chief#CHIEF chief Chief of the transport. -- @field Ops.Chief#CHIEF chief Chief of the transport.
-- @field Ops.OpsZone#OPSZONE opszone OPS zone. -- @field Ops.OpsZone#OPSZONE opszone OPS zone.
-- @field #table requestID The ID of the queued warehouse request. Necessary to cancel the request if the transport was cancelled before the request is processed. -- @field #table requestID The ID of the queued warehouse request. Necessary to cancel the request if the transport was cancelled before the request is processed.
-- @field #number cargocounter Running number to generate cargo UIDs.
-- --
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
@@ -79,7 +81,7 @@
-- * Cargo groups are **not** split and distributed into different carrier *units*. That means that the whole cargo group **must fit** into one of the carrier units. -- * Cargo groups are **not** split and distributed into different carrier *units*. That means that the whole cargo group **must fit** into one of the carrier units.
-- * Cargo groups must be inside the pickup zones to be considered for loading. Groups not inside the pickup zone will not get the command to board. -- * Cargo groups must be inside the pickup zones to be considered for loading. Groups not inside the pickup zone will not get the command to board.
-- --
-- # Constructor -- # Troop Transport
-- --
-- A new cargo transport assignment is created with the @{#OPSTRANSPORT.New}() function -- A new cargo transport assignment is created with the @{#OPSTRANSPORT.New}() function
-- --
@@ -101,6 +103,30 @@
-- --
-- You can also mix carrier types. For instance, you can assign the same transport to APCs and helicopters. Or to helicopters and airplanes. -- You can also mix carrier types. For instance, you can assign the same transport to APCs and helicopters. Or to helicopters and airplanes.
-- --
-- # Storage Transport
--
-- An instance of the OPSTRANSPORT class is created similarly to the troop transport case. However, the first parameter is `nil` as not troops
-- are transported.
--
-- local storagetransport=OPSTRANSPORT:New(nil, PickupZone, DeployZone)
--
-- ## Defining Storage
--
-- The storage warehouses from which the cargo is taken and to which the cargo is delivered have to be specified
--
-- storagetransport:AddCargoStorage(berlinStorage, batumiStorage, STORAGE.Liquid.JETFUEL, 1000)
--
-- Here `berlinStorage` and `batumiStorage` are @{Wrapper.Storage#STORAGE} objects of DCS warehouses.
--
-- Furthermore, that type of cargo (liquids or weapons/equipment) and the amount has to be specified. If weapons/equipment is the cargo,
-- we also need to specify the weight per storage item as this cannot be retrieved from the DCS API and is not stored in any MOOSE database.
--
-- storagetransport:AddCargoStorage(berlinStorage, batumiStorage, ENUMS.Storage.weapons.bombs.Mk_82, 9, 230)
--
-- Finally, the transport is assigned to one or multiple groups, which carry out the transport
--
-- myopsgroup:AddOpsTransport(storagetransport)
--
-- # Examples -- # Examples
-- --
-- A carrier group is assigned to transport infantry troops from zone "Zone Kobuleti X" to zone "Zone Alpha". -- A carrier group is assigned to transport infantry troops from zone "Zone Kobuleti X" to zone "Zone Alpha".
@@ -131,6 +157,7 @@ OPSTRANSPORT = {
legions = {}, legions = {},
statusLegion = {}, statusLegion = {},
requestID = {}, requestID = {},
cargocounter = 0,
} }
--- Cargo transport status. --- Cargo transport status.
@@ -186,6 +213,27 @@ OPSTRANSPORT.Status={
-- @field #number radius Radomization radius for waypoints in meters. Default 0 m. -- @field #number radius Radomization radius for waypoints in meters. Default 0 m.
-- @field #boolean reverse If `true`, path is used in reversed order. -- @field #boolean reverse If `true`, path is used in reversed order.
--- Storage data.
-- @type OPSTRANSPORT.Storage
-- @field Wrapper.Storage#STORAGE storageFrom Storage from.
-- @field Wrapper.Storage#STORAGE storageTo Storage To.
-- @field #string cargoType Type of cargo.
-- @field #number cargoAmount Amount of cargo that should be transported.
-- @field #number cargoReserved Amount of cargo that is reserved for a carrier group.
-- @field #number cargoDelivered Amount of cargo that has been delivered.
-- @field #number cargoLost Amount of cargo that was lost.
-- @field #number cargoLoaded Amount of cargo that is loading.
-- @field #number cargoWeight Weight of one single cargo item in kg. Default 1 kg.
--- Storage data.
-- @type OPSTRANSPORT.CargoType
-- @field #string OPSGROUP Cargo is an OPSGROUP.
-- @field #string STORAGE Cargo is storage of DCS warehouse.
OPSTRANSPORT.CargoType={
OPSGROUP="OPSGROUP",
STORAGE="STORAGE",
}
--- Generic transport condition. --- Generic transport condition.
-- @type OPSTRANSPORT.Condition -- @type OPSTRANSPORT.Condition
-- @field #function func Callback function to check for a condition. Should return a #boolean. -- @field #function func Callback function to check for a condition. Should return a #boolean.
@@ -196,7 +244,7 @@ _OPSTRANSPORTID=0
--- Army Group version. --- Army Group version.
-- @field #string version -- @field #string version
OPSTRANSPORT.version="0.7.0" OPSTRANSPORT.version="0.8.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@@ -205,6 +253,7 @@ OPSTRANSPORT.version="0.7.0"
-- TODO: Trains. -- TODO: Trains.
-- TODO: Stop transport. -- TODO: Stop transport.
-- TODO: Improve pickup and transport paths. -- TODO: Improve pickup and transport paths.
-- DONE: Storage.
-- DONE: Disembark parameters per cargo group. -- DONE: Disembark parameters per cargo group.
-- DONE: Special transport cohorts/legions. Similar to mission. -- DONE: Special transport cohorts/legions. Similar to mission.
-- DONE: Cancel transport. -- DONE: Cancel transport.
@@ -576,6 +625,38 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet, TransportZoneCombo, DisembarkActi
return self return self
end end
--- Add cargo warehouse storage to be transported. This adds items such as fuel, weapons and other equipment, which is to be transported
-- from one DCS warehouse to another.
-- For weapons and equipment, the weight per item has to be specified explicitly as these cannot be retrieved by the DCS API. For liquids the
-- default value of 1 kg per item should be used as the amount of liquid is already given in kg.
-- @param #OPSTRANSPORT self
-- @param Wrapper.Storage#STORAGE StorageFrom Storage warehouse from which the cargo is taken.
-- @param Wrapper.Storage#STORAGE StorageTo Storage warehouse to which the cargo is delivered.
-- @param #string CargoType Type of cargo, *e.g.* `"weapons.bombs.Mk_84"` or liquid type as #number.
-- @param #number CargoAmount Amount of cargo. Liquids in kg.
-- @param #number CargoWeight Weight of a single cargo item in kg. Default 1 kg.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo if other than default.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:AddCargoStorage(StorageFrom, StorageTo, CargoType, CargoAmount, CargoWeight, TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
-- Cargo data.
local cargo=self:_CreateCargoStorage(StorageFrom,StorageTo, CargoType, CargoAmount, CargoWeight, TransportZoneCombo)
if cargo then
-- Add total amount of ever assigned cargos.
self.Ncargo=self.Ncargo+1
-- Add to TZC table.
table.insert(TransportZoneCombo.Cargos, cargo)
end
end
--- Set pickup zone. --- Set pickup zone.
-- @param #OPSTRANSPORT self -- @param #OPSTRANSPORT self
@@ -1063,18 +1144,37 @@ end
-- @return #table Cargo Ops groups. Can be and empty table `{}`. -- @return #table Cargo Ops groups. Can be and empty table `{}`.
function OPSTRANSPORT:GetCargoOpsGroups(Delivered, Carrier, TransportZoneCombo) function OPSTRANSPORT:GetCargoOpsGroups(Delivered, Carrier, TransportZoneCombo)
local cargos=self:GetCargos(TransportZoneCombo) local cargos=self:GetCargos(TransportZoneCombo, Carrier, Delivered)
local opsgroups={} local opsgroups={}
for _,_cargo in pairs(cargos) do for _,_cargo in pairs(cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if Delivered==nil or cargo.delivered==Delivered then if cargo.type=="OPSGROUP" then
if cargo.opsgroup and not (cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped()) then if cargo.opsgroup and not (cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped()) then
if Carrier==nil or Carrier:CanCargo(cargo.opsgroup) then
table.insert(opsgroups, cargo.opsgroup) table.insert(opsgroups, cargo.opsgroup)
end end
end end
end end
return opsgroups
end
--- Get (all) cargo @{Ops.OpsGroup#OPSGROUP}s. Optionally, only delivered or undelivered groups can be returned.
-- @param #OPSTRANSPORT self
-- @param #boolean Delivered If `true`, only delivered groups are returned. If `false` only undelivered groups are returned. If `nil`, all groups are returned.
-- @param Ops.OpsGroup#OPSGROUP Carrier (Optional) Only count cargo groups that fit into the given carrier group. Current cargo is not a factor.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #table Cargo Ops groups. Can be and empty table `{}`.
function OPSTRANSPORT:GetCargoStorages(Delivered, Carrier, TransportZoneCombo)
local cargos=self:GetCargos(TransportZoneCombo, Carrier, Delivered)
local opsgroups={}
for _,_cargo in pairs(cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if cargo.type=="STORAGE" then
table.insert(opsgroups, cargo.storage)
end
end end
return opsgroups return opsgroups
@@ -1090,22 +1190,60 @@ end
--- Get cargos. --- Get cargos.
-- @param #OPSTRANSPORT self -- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo. -- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @param Ops.OpsGroup#OPSGROUP Carrier Specific carrier.
-- @param #boolean Delivered Delivered status.
-- @return #table Cargos. -- @return #table Cargos.
function OPSTRANSPORT:GetCargos(TransportZoneCombo) function OPSTRANSPORT:GetCargos(TransportZoneCombo, Carrier, Delivered)
local tczs=self.tzCombos
if TransportZoneCombo then if TransportZoneCombo then
return TransportZoneCombo.Cargos tczs={TransportZoneCombo}
else end
local cargos={} local cargos={}
for _,_tzc in pairs(self.tzCombos) do for _,_tcz in pairs(tczs) do
local tzc=_tzc --#OPSTRANSPORT.TransportZoneCombo local tcz=_tcz --#OPSTRANSPORT.TransportZoneCombo
for _,cargo in pairs(tzc.Cargos) do for _,_cargo in pairs(tcz.Cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if Delivered==nil or cargo.delivered==Delivered then
if Carrier==nil or Carrier:CanCargo(cargo) then
table.insert(cargos, cargo) table.insert(cargos, cargo)
end end
end end
return cargos end
end end
return cargos
end
--- Get total weight.
-- @param #OPSTRANSPORT self
-- @param Ops.OpsGroup#OPSGROUP.CargoGroup Cargo Cargo data.
-- @param #boolean IncludeReserved Include reserved cargo.
-- @return #number Weight in kg.
function OPSTRANSPORT:GetCargoTotalWeight(Cargo, IncludeReserved)
local weight=0
if Cargo.type==OPSTRANSPORT.CargoType.OPSGROUP then
weight=Cargo.opsgroup:GetWeightTotal(nil, IncludeReserved)
else
if type(Cargo.storage.cargoType)=="number" then
if IncludeReserved then
return Cargo.storage.cargoAmount+Cargo.storage.cargoReserved
else
return Cargo.storage.cargoAmount
end
else
if IncludeReserved then
return Cargo.storage.cargoAmount*100 -- Assume 100 kg per item
else
return (Cargo.storage.cargoAmount+Cargo.storage.cargoReserved)*100 -- Assume 100 kg per item
end
end
end
return weight
end end
--- Set transport start and stop time. --- Set transport start and stop time.
@@ -1642,11 +1780,18 @@ function OPSTRANSPORT:onafterStatusUpdate(From, Event, To)
text=text..string.format("\nCargos:") text=text..string.format("\nCargos:")
for _,_cargo in pairs(self:GetCargos()) do for _,_cargo in pairs(self:GetCargos()) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if cargo.type==OPSTRANSPORT.CargoType.OPSGROUP then
local carrier=cargo.opsgroup:_GetMyCarrierElement() local carrier=cargo.opsgroup:_GetMyCarrierElement()
local name=carrier and carrier.name or "none" local name=carrier and carrier.name or "none"
local cstate=carrier and carrier.status or "N/A" local cstate=carrier and carrier.status or "N/A"
text=text..string.format("\n- %s: %s [%s], weight=%d kg, carrier=%s [%s], delivered=%s [UID=%s]", text=text..string.format("\n- %s: %s [%s], weight=%d kg, carrier=%s [%s], delivered=%s [UID=%s]",
cargo.opsgroup:GetName(), cargo.opsgroup.cargoStatus:upper(), cargo.opsgroup:GetState(), cargo.opsgroup:GetWeightTotal(), name, cstate, tostring(cargo.delivered), tostring(cargo.opsgroup.cargoTransportUID)) cargo.opsgroup:GetName(), cargo.opsgroup.cargoStatus:upper(), cargo.opsgroup:GetState(), cargo.opsgroup:GetWeightTotal(), name, cstate, tostring(cargo.delivered), tostring(cargo.opsgroup.cargoTransportUID))
else
--TODO: Storage
local storage=cargo.storage
text=text..string.format("\n- storage type=%s: amount: total=%d loaded=%d, lost=%d, delivered=%d, delivered=%s [UID=%s]",
storage.cargoType, storage.cargoAmount, storage.cargoLoaded, storage.cargoLost, storage.cargoDelivered, tostring(cargo.delivered), tostring(cargo.uid))
end
end end
text=text..string.format("\nCarriers:") text=text..string.format("\nCarriers:")
@@ -1923,14 +2068,14 @@ function OPSTRANSPORT:_CheckDelivered()
if cargo.delivered then if cargo.delivered then
-- This one is delivered. -- This one is delivered.
dead=false dead=false
elseif cargo.opsgroup==nil then elseif cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and cargo.opsgroup==nil then
-- This one is nil?! -- This one is nil?!
dead=false dead=false
elseif cargo.opsgroup:IsDestroyed() then elseif cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and cargo.opsgroup:IsDestroyed() then
-- This one was destroyed. -- This one was destroyed.
elseif cargo.opsgroup:IsDead() then elseif cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and cargo.opsgroup:IsDead() then
-- This one is dead. -- This one is dead.
elseif cargo.opsgroup:IsStopped() then elseif cargo.type==OPSTRANSPORT.CargoType.OPSGROUP and cargo.opsgroup:IsStopped() then
-- This one is stopped. -- This one is stopped.
dead=false dead=false
else else
@@ -2116,10 +2261,12 @@ function OPSTRANSPORT:_CreateCargoGroupData(group, TransportZoneCombo, Disembark
end end
end end
self.cargocounter=self.cargocounter+1
-- Create a new data item. -- Create a new data item.
local cargo={} --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo={} --Ops.OpsGroup#OPSGROUP.CargoGroup
cargo.uid=self.cargocounter
cargo.type="OPSGROUP"
cargo.opsgroup=opsgroup cargo.opsgroup=opsgroup
cargo.delivered=false cargo.delivered=false
cargo.status="Unknown" cargo.status="Unknown"
@@ -2133,6 +2280,45 @@ function OPSTRANSPORT:_CreateCargoGroupData(group, TransportZoneCombo, Disembark
return cargo return cargo
end end
--- Create a cargo group data structure.
-- @param #OPSTRANSPORT self
-- @param Wrapper.Storage#STORAGE StorageFrom Storage from.
-- @param Wrapper.Storage#STORAGE StorageTo Storage to.
-- @param #string CargoType Type of cargo.
-- @param #number CargoAmount Total amount of cargo that should be transported. Liquids in kg.
-- @param #number CargoWeight Weight of a single cargo item in kg. Default 1 kg.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return Ops.OpsGroup#OPSGROUP.CargoGroup Cargo group data.
function OPSTRANSPORT:_CreateCargoStorage(StorageFrom, StorageTo, CargoType, CargoAmount, CargoWeight, TransportZoneCombo)
local storage={} --#OPSTRANSPORT.Storage
storage.storageFrom=StorageFrom
storage.storageTo=StorageTo
storage.cargoType=CargoType
storage.cargoAmount=CargoAmount
storage.cargoDelivered=0
storage.cargoLost=0
storage.cargoReserved=0
storage.cargoLoaded=0
storage.cargoWeight=CargoWeight or 1
self.cargocounter=self.cargocounter+1
-- Create a new data item.
local cargo={} --Ops.OpsGroup#OPSGROUP.CargoGroup
cargo.uid=self.cargocounter
cargo.type="STORAGE"
cargo.opsgroup=nil
cargo.storage=storage
cargo.delivered=false
cargo.status="Unknown"
cargo.tzcUID=TransportZoneCombo
cargo.disembarkZone=nil
cargo.disembarkCarriers=nil
return cargo
end
--- Count how many cargo groups are inside a zone. --- Count how many cargo groups are inside a zone.
-- @param #OPSTRANSPORT self -- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE Zone The zone object. -- @param Core.Zone#ZONE Zone The zone object.
@@ -2143,7 +2329,9 @@ end
function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier, TransportZoneCombo) function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier, TransportZoneCombo)
-- Get cargo ops groups. -- Get cargo ops groups.
local cargos=self:GetCargoOpsGroups(Delivered, Carrier, TransportZoneCombo) --local cargos=self:GetCargoOpsGroups(Delivered, Carrier, TransportZoneCombo)
local cargos=self:GetCargos(TransportZoneCombo, Carrier, Delivered)
--- Function to check if carrier is supposed to be disembarked to. --- Function to check if carrier is supposed to be disembarked to.
local function iscarrier(_cargo) local function iscarrier(_cargo)
@@ -2185,22 +2373,33 @@ function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier, TransportZone
local N=0 local N=0
for _,_cargo in pairs(cargos) do for _,_cargo in pairs(cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
local isNotCargo=true
local isInZone=true
local isInUtero=true
if cargo.type==OPSTRANSPORT.CargoType.OPSGROUP then
local opsgroup=cargo.opsgroup
-- Is not cargo? -- Is not cargo?
local isNotCargo=cargo:IsNotCargo(true) isNotCargo=opsgroup:IsNotCargo(true)
if not isNotCargo then if not isNotCargo then
isNotCargo=iscarrier(cargo) isNotCargo=iscarrier(opsgroup)
end end
-- Is in zone? -- Is in zone?
local isInZone=cargo:IsInZone(Zone) isInZone=opsgroup:IsInZone(Zone)
-- Is in utero? -- Is in utero?
local isInUtero=cargo:IsInUtero() isInUtero=opsgroup:IsInUtero()
-- Debug info. -- Debug info.
self:T(self.lid..string.format("Cargo=%s: notcargo=%s, iscarrier=%s inzone=%s, inutero=%s", cargo:GetName(), tostring(cargo:IsNotCargo(true)), tostring(iscarrier(cargo)), tostring(isInZone), tostring(isInUtero))) self:T(self.lid..string.format("Cargo=%s: notcargo=%s, iscarrier=%s inzone=%s, inutero=%s", opsgroup:GetName(), tostring(opsgroup:IsNotCargo(true)), tostring(iscarrier(opsgroup)), tostring(isInZone), tostring(isInUtero)))
end
-- We look for groups that are not cargo, in the zone or in utero. -- We look for groups that are not cargo, in the zone or in utero.
if isNotCargo and (isInZone or isInUtero) then if isNotCargo and (isInZone or isInUtero) then

View File

@@ -104,7 +104,7 @@ PLAYERRECCE = {
ClassName = "PLAYERRECCE", ClassName = "PLAYERRECCE",
verbose = true, verbose = true,
lid = nil, lid = nil,
version = "0.0.17", version = "0.0.18",
ViewZone = {}, ViewZone = {},
ViewZoneVisual = {}, ViewZoneVisual = {},
ViewZoneLaser = {}, ViewZoneLaser = {},
@@ -807,6 +807,7 @@ function PLAYERRECCE:_SetClientLaserCode(client,group,playername,code)
self.ClientMenus[playername]:Remove() self.ClientMenus[playername]:Remove()
self.ClientMenus[playername]=nil self.ClientMenus[playername]=nil
end end
self:_BuildMenus()
return self return self
end end
@@ -829,6 +830,7 @@ function PLAYERRECCE:_SwitchOnStation(client,group,playername)
self.ClientMenus[playername]:Remove() self.ClientMenus[playername]:Remove()
self.ClientMenus[playername]=nil self.ClientMenus[playername]=nil
end end
self:_BuildMenus(client)
return self return self
end end
@@ -851,6 +853,7 @@ function PLAYERRECCE:_SwitchSmoke(client,group,playername)
self.ClientMenus[playername]:Remove() self.ClientMenus[playername]:Remove()
self.ClientMenus[playername]=nil self.ClientMenus[playername]=nil
end end
self:_BuildMenus(client)
return self return self
end end
@@ -873,6 +876,7 @@ function PLAYERRECCE:_SwitchLasing(client,group,playername)
self.ClientMenus[playername]:Remove() self.ClientMenus[playername]:Remove()
self.ClientMenus[playername]=nil self.ClientMenus[playername]=nil
end end
self:_BuildMenus(client)
return self return self
end end
@@ -902,6 +906,7 @@ function PLAYERRECCE:_SwitchLasingDist(client,group,playername,mindist,maxdist)
self.ClientMenus[playername]:Remove() self.ClientMenus[playername]:Remove()
self.ClientMenus[playername]=nil self.ClientMenus[playername]=nil
end end
self:_BuildMenus(client)
return self return self
end end
@@ -930,6 +935,8 @@ function PLAYERRECCE:_SmokeTargets(client,group,playername)
if cameraset:CountAlive() > 0 then if cameraset:CountAlive() > 0 then
self:__TargetsSmoked(-1,client,playername,cameraset) self:__TargetsSmoked(-1,client,playername,cameraset)
else
return self
end end
local highsmoke = self.SmokeColor.highsmoke local highsmoke = self.SmokeColor.highsmoke
@@ -1068,7 +1075,7 @@ self:T(self.lid.."_ReportLaserTargets")
if number > 0 and self.AutoLase[playername] then if number > 0 and self.AutoLase[playername] then
local Settings = ( client and _DATABASE:GetPlayerSettings( playername ) ) or _SETTINGS local Settings = ( client and _DATABASE:GetPlayerSettings( playername ) ) or _SETTINGS
local target = self:_GetHVTTarget(targetset) -- the one we're lasing local target = self:_GetHVTTarget(targetset) -- the one we're lasing
local ThreatLevel = target:GetThreatLevel() local ThreatLevel = target:GetThreatLevel() or 1
local ThreatLevelText = "high" local ThreatLevelText = "high"
if ThreatLevel > 3 and ThreatLevel < 8 then if ThreatLevel > 3 and ThreatLevel < 8 then
ThreatLevelText = "medium" ThreatLevelText = "medium"
@@ -1078,7 +1085,7 @@ self:T(self.lid.."_ReportLaserTargets")
local ThreatGraph = "[" .. string.rep( "", ThreatLevel ) .. string.rep( "", 10 - ThreatLevel ) .. "]: "..ThreatLevel local ThreatGraph = "[" .. string.rep( "", ThreatLevel ) .. string.rep( "", 10 - ThreatLevel ) .. "]: "..ThreatLevel
local report = REPORT:New("Lasing Report") local report = REPORT:New("Lasing Report")
report:Add(string.rep("-",15)) report:Add(string.rep("-",15))
report:Add("Target type: "..target:GetTypeName()) report:Add("Target type: "..target:GetTypeName() or "unknown")
report:Add("Threat Level: "..ThreatGraph.." ("..ThreatLevelText..")") report:Add("Threat Level: "..ThreatGraph.." ("..ThreatLevelText..")")
if not self.ReferencePoint then if not self.ReferencePoint then
report:Add("Location: "..client:GetCoordinate():ToStringBULLS(self.Coalition,Settings)) report:Add("Location: "..client:GetCoordinate():ToStringBULLS(self.Coalition,Settings))
@@ -1088,14 +1095,14 @@ self:T(self.lid.."_ReportLaserTargets")
report:Add("Laser Code: "..self.UnitLaserCodes[playername] or 1688) report:Add("Laser Code: "..self.UnitLaserCodes[playername] or 1688)
report:Add(string.rep("-",15)) report:Add(string.rep("-",15))
local text = report:Text() local text = report:Text()
self:__TargetReport(-1,client,targetset,target,text) self:__TargetReport(1,client,targetset,target,text)
else else
local report = REPORT:New("Lasing Report") local report = REPORT:New("Lasing Report")
report:Add(string.rep("-",15)) report:Add(string.rep("-",15))
report:Add("N O T A R G E T S") report:Add("N O T A R G E T S")
report:Add(string.rep("-",15)) report:Add(string.rep("-",15))
local text = report:Text() local text = report:Text()
self:__TargetReport(-1,client,nil,nil,text) self:__TargetReport(1,client,nil,nil,text)
end end
return self return self
end end
@@ -1130,25 +1137,27 @@ function PLAYERRECCE:_ReportVisualTargets(client,group,playername)
end end
report:Add(string.rep("-",15)) report:Add(string.rep("-",15))
local text = report:Text() local text = report:Text()
self:__TargetReport(-1,client,targetset,nil,text) self:__TargetReport(1,client,targetset,nil,text)
else else
local report = REPORT:New("Target Report") local report = REPORT:New("Target Report")
report:Add(string.rep("-",15)) report:Add(string.rep("-",15))
report:Add("N O T A R G E T S") report:Add("N O T A R G E T S")
report:Add(string.rep("-",15)) report:Add(string.rep("-",15))
local text = report:Text() local text = report:Text()
self:__TargetReport(-1,client,nil,nil,text) self:__TargetReport(1,client,nil,nil,text)
end end
return self return self
end end
--- [Internal] --- [Internal] Build Menus
-- @param #PLAYERRECCE self -- @param #PLAYERRECCE self
-- @param #PLAYERRECCE self -- @param Wrapper.Client#CLIENT Client (optional) Client object
function PLAYERRECCE:_BuildMenus() -- @return #PLAYERRECCE self
function PLAYERRECCE:_BuildMenus(Client)
self:T(self.lid.."_BuildMenus") self:T(self.lid.."_BuildMenus")
local clients = self.PlayerSet -- Core.Set#SET_CLIENT local clients = self.PlayerSet -- Core.Set#SET_CLIENT
local clientset = clients:GetSetObjects() local clientset = clients:GetSetObjects()
if Client then clientset = {Client} end
for _,_client in pairs(clientset) do for _,_client in pairs(clientset) do
local client = _client -- Wrapper.Client#CLIENT local client = _client -- Wrapper.Client#CLIENT
if client and client:IsAlive() then if client and client:IsAlive() then
@@ -1156,7 +1165,7 @@ function PLAYERRECCE:_BuildMenus()
if not self.UnitLaserCodes[playername] then if not self.UnitLaserCodes[playername] then
self:_SetClientLaserCode(nil,nil,playername,1688) self:_SetClientLaserCode(nil,nil,playername,1688)
end end
if not self.SmokeOwn[playername] then if self.SmokeOwn[playername] == nil then
self.SmokeOwn[playername] = self.smokeownposition self.SmokeOwn[playername] = self.smokeownposition
end end
local group = client:GetGroup() local group = client:GetGroup()
@@ -1919,7 +1928,7 @@ function PLAYERRECCE:onafterTargetReport(From, Event, To, Client, TargetSet, Tar
-- send message to AttackSet -- send message to AttackSet
for _,_client in pairs(self.AttackSet.Set) do for _,_client in pairs(self.AttackSet.Set) do
local client = _client -- Wrapper.Client#CLIENT local client = _client -- Wrapper.Client#CLIENT
if client and client:IsAlive() then if client and client:IsAlive() and client ~= Client then
MESSAGE:New(Text,45,self.Name or "FACA"):ToClient(client) MESSAGE:New(Text,45,self.Name or "FACA"):ToClient(client)
end end
end end

View File

@@ -562,3 +562,578 @@ ENUMS.ReportingName =
Predator = "MQ-1A", Predator = "MQ-1A",
} }
} }
--- Enums for the STORAGE class for stores - which need to be in ""
-- @type ENUMS.Storage
-- @type ENUMS.Storage.weapons
ENUMS.Storage = {
weapons = {
missiles = {}, -- Missiles
bombs = {}, -- Bombs
nurs = {}, -- Rockets and unguided
containers = {}, -- Containers
droptanks = {}, -- Droptanks
adapters = {}, -- Adapter
torpedoes = {}, -- Torpedoes
}
}
ENUMS.Storage.weapons.nurs.SNEB_TYPE253_F1B = "weapons.nurs.SNEB_TYPE253_F1B"
ENUMS.Storage.weapons.missiles.P_24T = "weapons.missiles.P_24T"
ENUMS.Storage.weapons.bombs.BLU_3B_OLD = "weapons.bombs.BLU-3B_OLD"
ENUMS.Storage.weapons.missiles.AGM_154 = "weapons.missiles.AGM_154"
ENUMS.Storage.weapons.nurs.HYDRA_70_M151_M433 = "weapons.nurs.HYDRA_70_M151_M433"
ENUMS.Storage.weapons.bombs.SAM_Avenger_M1097_Skid_7090lb = "weapons.bombs.SAM Avenger M1097 Skid [7090lb]"
ENUMS.Storage.weapons.bombs.British_GP_250LB_Bomb_Mk5 = "weapons.bombs.British_GP_250LB_Bomb_Mk5"
ENUMS.Storage.weapons.containers.OV10_SMOKE = "weapons.containers.{OV10_SMOKE}"
ENUMS.Storage.weapons.bombs.BLU_4B_OLD = "weapons.bombs.BLU-4B_OLD"
ENUMS.Storage.weapons.bombs.FAB_500M54 = "weapons.bombs.FAB-500M54"
ENUMS.Storage.weapons.bombs.GBU_38 = "weapons.bombs.GBU_38"
ENUMS.Storage.weapons.containers.F_15E_AXQ_14_DATALINK = "weapons.containers.F-15E_AXQ-14_DATALINK"
ENUMS.Storage.weapons.bombs.BEER_BOMB = "weapons.bombs.BEER_BOMB"
ENUMS.Storage.weapons.bombs.P_50T = "weapons.bombs.P-50T"
ENUMS.Storage.weapons.nurs.C_8CM_GN = "weapons.nurs.C_8CM_GN"
ENUMS.Storage.weapons.bombs.FAB_500SL = "weapons.bombs.FAB-500SL"
ENUMS.Storage.weapons.bombs.KAB_1500Kr = "weapons.bombs.KAB_1500Kr"
ENUMS.Storage.weapons.bombs.two50_2 = "weapons.bombs.250-2"
ENUMS.Storage.weapons.droptanks.Spitfire_tank_1 = "weapons.droptanks.Spitfire_tank_1"
ENUMS.Storage.weapons.missiles.AGM_65G = "weapons.missiles.AGM_65G"
ENUMS.Storage.weapons.missiles.AGM_65A = "weapons.missiles.AGM_65A"
ENUMS.Storage.weapons.containers.Hercules_JATO = "weapons.containers.Hercules_JATO"
ENUMS.Storage.weapons.nurs.HYDRA_70_M259 = "weapons.nurs.HYDRA_70_M259"
ENUMS.Storage.weapons.missiles.AGM_84E = "weapons.missiles.AGM_84E"
ENUMS.Storage.weapons.bombs.AN_M30A1 = "weapons.bombs.AN_M30A1"
ENUMS.Storage.weapons.nurs.C_25 = "weapons.nurs.C_25"
ENUMS.Storage.weapons.containers.AV8BNA_ALQ164 = "weapons.containers.AV8BNA_ALQ164"
ENUMS.Storage.weapons.containers.lav_25 = "weapons.containers.lav-25"
ENUMS.Storage.weapons.missiles.P_60 = "weapons.missiles.P_60"
ENUMS.Storage.weapons.bombs.FAB_1500 = "weapons.bombs.FAB_1500"
ENUMS.Storage.weapons.droptanks.FuelTank_350L = "weapons.droptanks.FuelTank_350L"
ENUMS.Storage.weapons.bombs.AAA_Vulcan_M163_Skid_21577lb = "weapons.bombs.AAA Vulcan M163 Skid [21577lb]"
ENUMS.Storage.weapons.missiles.Kormoran = "weapons.missiles.Kormoran"
ENUMS.Storage.weapons.droptanks.HB_F14_EXT_DROPTANK_EMPTY = "weapons.droptanks.HB_F14_EXT_DROPTANK_EMPTY"
ENUMS.Storage.weapons.droptanks.FuelTank_150L = "weapons.droptanks.FuelTank_150L"
ENUMS.Storage.weapons.missiles.Rb_15F_for_A_I = "weapons.missiles.Rb 15F (for A.I.)"
ENUMS.Storage.weapons.missiles.RB75T = "weapons.missiles.RB75T"
ENUMS.Storage.weapons.missiles.Vikhr_M = "weapons.missiles.Vikhr_M"
ENUMS.Storage.weapons.nurs.FFAR_M156_WP = "weapons.nurs.FFAR M156 WP"
ENUMS.Storage.weapons.nurs.British_HE_60LBSAPNo2_3INCHNo1 = "weapons.nurs.British_HE_60LBSAPNo2_3INCHNo1"
ENUMS.Storage.weapons.missiles.DWS39_MJ2 = "weapons.missiles.DWS39_MJ2"
ENUMS.Storage.weapons.bombs.HEBOMBD = "weapons.bombs.HEBOMBD"
ENUMS.Storage.weapons.missiles.CATM_9M = "weapons.missiles.CATM_9M"
ENUMS.Storage.weapons.bombs.Mk_81 = "weapons.bombs.Mk_81"
ENUMS.Storage.weapons.droptanks.Drop_Tank_300_Liter = "weapons.droptanks.Drop_Tank_300_Liter"
ENUMS.Storage.weapons.containers.HMMWV_M1025 = "weapons.containers.HMMWV_M1025"
ENUMS.Storage.weapons.bombs.SAM_CHAPARRAL_Air_21624lb = "weapons.bombs.SAM CHAPARRAL Air [21624lb]"
ENUMS.Storage.weapons.missiles.AGM_154A = "weapons.missiles.AGM_154A"
ENUMS.Storage.weapons.bombs.Mk_84AIR_TP = "weapons.bombs.Mk_84AIR_TP"
ENUMS.Storage.weapons.bombs.GBU_31_V_3B = "weapons.bombs.GBU_31_V_3B"
ENUMS.Storage.weapons.nurs.C_8CM_WH = "weapons.nurs.C_8CM_WH"
ENUMS.Storage.weapons.missiles.Matra_Super_530D = "weapons.missiles.Matra Super 530D"
ENUMS.Storage.weapons.nurs.ARF8M3TPSM = "weapons.nurs.ARF8M3TPSM"
ENUMS.Storage.weapons.missiles.TGM_65H = "weapons.missiles.TGM_65H"
ENUMS.Storage.weapons.nurs.M8rocket = "weapons.nurs.M8rocket"
ENUMS.Storage.weapons.bombs.GBU_27 = "weapons.bombs.GBU_27"
ENUMS.Storage.weapons.missiles.AGR_20A = "weapons.missiles.AGR_20A"
ENUMS.Storage.weapons.missiles.LS_6_250 = "weapons.missiles.LS-6-250"
ENUMS.Storage.weapons.droptanks.M2KC_RPL_522_EMPTY = "weapons.droptanks.M2KC_RPL_522_EMPTY"
ENUMS.Storage.weapons.droptanks.M2KC_02_RPL541 = "weapons.droptanks.M2KC_02_RPL541"
ENUMS.Storage.weapons.missiles.AGM_45 = "weapons.missiles.AGM_45"
ENUMS.Storage.weapons.missiles.AGM_84A = "weapons.missiles.AGM_84A"
ENUMS.Storage.weapons.bombs.APC_BTR_80_Air_23936lb = "weapons.bombs.APC BTR-80 Air [23936lb]"
ENUMS.Storage.weapons.missiles.P_33E = "weapons.missiles.P_33E"
ENUMS.Storage.weapons.missiles.Ataka_9M120 = "weapons.missiles.Ataka_9M120"
ENUMS.Storage.weapons.bombs.MK76 = "weapons.bombs.MK76"
ENUMS.Storage.weapons.bombs.AB_250_2_SD_2 = "weapons.bombs.AB_250_2_SD_2"
ENUMS.Storage.weapons.missiles.Rb_05A = "weapons.missiles.Rb 05A"
ENUMS.Storage.weapons.bombs.ART_GVOZDIKA_34720lb = "weapons.bombs.ART GVOZDIKA [34720lb]"
ENUMS.Storage.weapons.bombs.Generic_Crate_20000lb = "weapons.bombs.Generic Crate [20000lb]"
ENUMS.Storage.weapons.bombs.FAB_100SV = "weapons.bombs.FAB_100SV"
ENUMS.Storage.weapons.bombs.BetAB_500 = "weapons.bombs.BetAB_500"
ENUMS.Storage.weapons.droptanks.M2KC_02_RPL541_EMPTY = "weapons.droptanks.M2KC_02_RPL541_EMPTY"
ENUMS.Storage.weapons.droptanks.PTB600_MIG15 = "weapons.droptanks.PTB600_MIG15"
ENUMS.Storage.weapons.missiles.Rb_24J = "weapons.missiles.Rb 24J"
ENUMS.Storage.weapons.nurs.C_8CM_BU = "weapons.nurs.C_8CM_BU"
ENUMS.Storage.weapons.nurs.SNEB_TYPE259E_F1B = "weapons.nurs.SNEB_TYPE259E_F1B"
ENUMS.Storage.weapons.nurs.WGr21 = "weapons.nurs.WGr21"
ENUMS.Storage.weapons.bombs.SAMP250HD = "weapons.bombs.SAMP250HD"
ENUMS.Storage.weapons.containers.alq_184long = "weapons.containers.alq-184long"
ENUMS.Storage.weapons.nurs.SNEB_TYPE259E_H1 = "weapons.nurs.SNEB_TYPE259E_H1"
ENUMS.Storage.weapons.bombs.British_SAP_250LB_Bomb_Mk5 = "weapons.bombs.British_SAP_250LB_Bomb_Mk5"
ENUMS.Storage.weapons.bombs.Transport_UAZ_469_Air_3747lb = "weapons.bombs.Transport UAZ-469 Air [3747lb]"
ENUMS.Storage.weapons.bombs.Mk_83CT = "weapons.bombs.Mk_83CT"
ENUMS.Storage.weapons.missiles.AIM_7P = "weapons.missiles.AIM-7P"
ENUMS.Storage.weapons.missiles.AT_6 = "weapons.missiles.AT_6"
ENUMS.Storage.weapons.nurs.SNEB_TYPE254_H1_GREEN = "weapons.nurs.SNEB_TYPE254_H1_GREEN"
ENUMS.Storage.weapons.nurs.SNEB_TYPE250_F1B = "weapons.nurs.SNEB_TYPE250_F1B"
ENUMS.Storage.weapons.containers.U22A = "weapons.containers.U22A"
ENUMS.Storage.weapons.bombs.British_GP_250LB_Bomb_Mk1 = "weapons.bombs.British_GP_250LB_Bomb_Mk1"
ENUMS.Storage.weapons.bombs.CBU_105 = "weapons.bombs.CBU_105"
ENUMS.Storage.weapons.droptanks.FW_190_Fuel_Tank = "weapons.droptanks.FW-190_Fuel-Tank"
ENUMS.Storage.weapons.missiles.X_58 = "weapons.missiles.X_58"
ENUMS.Storage.weapons.missiles.BK90_MJ1_MJ2 = "weapons.missiles.BK90_MJ1_MJ2"
ENUMS.Storage.weapons.missiles.TGM_65D = "weapons.missiles.TGM_65D"
ENUMS.Storage.weapons.containers.BRD_4_250 = "weapons.containers.BRD-4-250"
ENUMS.Storage.weapons.missiles.P_73 = "weapons.missiles.P_73"
ENUMS.Storage.weapons.bombs.AN_M66 = "weapons.bombs.AN_M66"
ENUMS.Storage.weapons.bombs.APC_LAV_25_Air_22520lb = "weapons.bombs.APC LAV-25 Air [22520lb]"
ENUMS.Storage.weapons.missiles.AIM_7MH = "weapons.missiles.AIM-7MH"
ENUMS.Storage.weapons.containers.MB339_TravelPod = "weapons.containers.MB339_TravelPod"
ENUMS.Storage.weapons.bombs.GBU_12 = "weapons.bombs.GBU_12"
ENUMS.Storage.weapons.bombs.SC_250_T3_J = "weapons.bombs.SC_250_T3_J"
ENUMS.Storage.weapons.missiles.KD_20 = "weapons.missiles.KD-20"
ENUMS.Storage.weapons.missiles.AGM_86C = "weapons.missiles.AGM_86C"
ENUMS.Storage.weapons.missiles.X_35 = "weapons.missiles.X_35"
ENUMS.Storage.weapons.bombs.MK106 = "weapons.bombs.MK106"
ENUMS.Storage.weapons.bombs.BETAB_500S = "weapons.bombs.BETAB-500S"
ENUMS.Storage.weapons.nurs.C_5 = "weapons.nurs.C_5"
ENUMS.Storage.weapons.nurs.S_24B = "weapons.nurs.S-24B"
ENUMS.Storage.weapons.bombs.British_MC_500LB_Bomb_Mk2 = "weapons.bombs.British_MC_500LB_Bomb_Mk2"
ENUMS.Storage.weapons.containers.ANAWW_13 = "weapons.containers.ANAWW_13"
ENUMS.Storage.weapons.droptanks.droptank_108_gal = "weapons.droptanks.droptank_108_gal"
ENUMS.Storage.weapons.droptanks.DFT_300_GAL_A4E_LR = "weapons.droptanks.DFT_300_GAL_A4E_LR"
ENUMS.Storage.weapons.bombs.CBU_87 = "weapons.bombs.CBU_87"
ENUMS.Storage.weapons.missiles.GAR_8 = "weapons.missiles.GAR-8"
ENUMS.Storage.weapons.bombs.BELOUGA = "weapons.bombs.BELOUGA"
ENUMS.Storage.weapons.containers.EclairM_33 = "weapons.containers.{EclairM_33}"
ENUMS.Storage.weapons.bombs.ART_2S9_NONA_Air_19140lb = "weapons.bombs.ART 2S9 NONA Air [19140lb]"
ENUMS.Storage.weapons.bombs.BR_250 = "weapons.bombs.BR_250"
ENUMS.Storage.weapons.bombs.IAB_500 = "weapons.bombs.IAB-500"
ENUMS.Storage.weapons.containers.AN_ASQ_228 = "weapons.containers.AN_ASQ_228"
ENUMS.Storage.weapons.missiles.P_27P = "weapons.missiles.P_27P"
ENUMS.Storage.weapons.bombs.SD_250_Stg = "weapons.bombs.SD_250_Stg"
ENUMS.Storage.weapons.missiles.R_530F_IR = "weapons.missiles.R_530F_IR"
ENUMS.Storage.weapons.bombs.British_SAP_500LB_Bomb_Mk5 = "weapons.bombs.British_SAP_500LB_Bomb_Mk5"
ENUMS.Storage.weapons.bombs.FAB_250M54 = "weapons.bombs.FAB-250M54"
ENUMS.Storage.weapons.containers.M2KC_AAF = "weapons.containers.{M2KC_AAF}"
ENUMS.Storage.weapons.missiles.CM_802AKG_AI = "weapons.missiles.CM-802AKG_AI"
ENUMS.Storage.weapons.bombs.CBU_103 = "weapons.bombs.CBU_103"
ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_RED = "weapons.containers.{US_M10_SMOKE_TANK_RED}"
ENUMS.Storage.weapons.missiles.X_29T = "weapons.missiles.X_29T"
ENUMS.Storage.weapons.bombs.HEMTT_TFFT_34400lb = "weapons.bombs.HEMTT TFFT [34400lb]"
ENUMS.Storage.weapons.missiles.C_701IR = "weapons.missiles.C-701IR"
ENUMS.Storage.weapons.containers.fullCargoSeats = "weapons.containers.fullCargoSeats"
ENUMS.Storage.weapons.bombs.GBU_15_V_31_B = "weapons.bombs.GBU_15_V_31_B"
ENUMS.Storage.weapons.bombs.APC_M1043_HMMWV_Armament_Air_7023lb = "weapons.bombs.APC M1043 HMMWV Armament Air [7023lb]"
ENUMS.Storage.weapons.missiles.PL_5EII = "weapons.missiles.PL-5EII"
ENUMS.Storage.weapons.bombs.SC_250_T1_L2 = "weapons.bombs.SC_250_T1_L2"
ENUMS.Storage.weapons.torpedoes.mk46torp_name = "weapons.torpedoes.mk46torp_name"
ENUMS.Storage.weapons.containers.F_15E_AAQ_33_XR_ATP_SE = "weapons.containers.F-15E_AAQ-33_XR_ATP-SE"
ENUMS.Storage.weapons.missiles.AIM_7 = "weapons.missiles.AIM_7"
ENUMS.Storage.weapons.missiles.AGM_122 = "weapons.missiles.AGM_122"
ENUMS.Storage.weapons.bombs.HEBOMB = "weapons.bombs.HEBOMB"
ENUMS.Storage.weapons.bombs.CBU_97 = "weapons.bombs.CBU_97"
ENUMS.Storage.weapons.bombs.MK_81SE = "weapons.bombs.MK-81SE"
ENUMS.Storage.weapons.nurs.Zuni_127 = "weapons.nurs.Zuni_127"
ENUMS.Storage.weapons.containers.M2KC_AGF = "weapons.containers.{M2KC_AGF}"
ENUMS.Storage.weapons.droptanks.Hercules_ExtFuelTank = "weapons.droptanks.Hercules_ExtFuelTank"
ENUMS.Storage.weapons.containers.SMOKE_WHITE = "weapons.containers.{SMOKE_WHITE}"
ENUMS.Storage.weapons.droptanks.droptank_150_gal = "weapons.droptanks.droptank_150_gal"
ENUMS.Storage.weapons.nurs.HYDRA_70_WTU1B = "weapons.nurs.HYDRA_70_WTU1B"
ENUMS.Storage.weapons.missiles.GB_6_SFW = "weapons.missiles.GB-6-SFW"
ENUMS.Storage.weapons.missiles.KD_63 = "weapons.missiles.KD-63"
ENUMS.Storage.weapons.bombs.GBU_28 = "weapons.bombs.GBU_28"
ENUMS.Storage.weapons.nurs.C_8CM_YE = "weapons.nurs.C_8CM_YE"
ENUMS.Storage.weapons.droptanks.HB_F14_EXT_DROPTANK = "weapons.droptanks.HB_F14_EXT_DROPTANK"
ENUMS.Storage.weapons.missiles.Super_530F = "weapons.missiles.Super_530F"
ENUMS.Storage.weapons.missiles.Ataka_9M220 = "weapons.missiles.Ataka_9M220"
ENUMS.Storage.weapons.bombs.BDU_33 = "weapons.bombs.BDU_33"
ENUMS.Storage.weapons.bombs.British_GP_250LB_Bomb_Mk4 = "weapons.bombs.British_GP_250LB_Bomb_Mk4"
ENUMS.Storage.weapons.missiles.TOW = "weapons.missiles.TOW"
ENUMS.Storage.weapons.bombs.ATGM_M1045_HMMWV_TOW_Air_7183lb = "weapons.bombs.ATGM M1045 HMMWV TOW Air [7183lb]"
ENUMS.Storage.weapons.missiles.X_25MR = "weapons.missiles.X_25MR"
ENUMS.Storage.weapons.droptanks.fueltank230 = "weapons.droptanks.fueltank230"
ENUMS.Storage.weapons.droptanks.PTB_490C_MIG21 = "weapons.droptanks.PTB-490C-MIG21"
ENUMS.Storage.weapons.bombs.M1025_HMMWV_Air_6160lb = "weapons.bombs.M1025 HMMWV Air [6160lb]"
ENUMS.Storage.weapons.nurs.SNEB_TYPE254_F1B_GREEN = "weapons.nurs.SNEB_TYPE254_F1B_GREEN"
ENUMS.Storage.weapons.missiles.R_550 = "weapons.missiles.R_550"
ENUMS.Storage.weapons.bombs.KAB_1500LG = "weapons.bombs.KAB_1500LG"
ENUMS.Storage.weapons.missiles.AGM_84D = "weapons.missiles.AGM_84D"
ENUMS.Storage.weapons.missiles.YJ_83K = "weapons.missiles.YJ-83K"
ENUMS.Storage.weapons.missiles.AIM_54C_Mk47 = "weapons.missiles.AIM_54C_Mk47"
ENUMS.Storage.weapons.missiles.BRM_1_90MM = "weapons.missiles.BRM-1_90MM"
ENUMS.Storage.weapons.missiles.Ataka_9M120F = "weapons.missiles.Ataka_9M120F"
ENUMS.Storage.weapons.droptanks.Eleven00L_Tank = "weapons.droptanks.1100L Tank"
ENUMS.Storage.weapons.bombs.BAP_100 = "weapons.bombs.BAP_100"
ENUMS.Storage.weapons.adapters.lau_88 = "weapons.adapters.lau-88"
ENUMS.Storage.weapons.missiles.P_40T = "weapons.missiles.P_40T"
ENUMS.Storage.weapons.missiles.GB_6 = "weapons.missiles.GB-6"
ENUMS.Storage.weapons.bombs.FAB_250M54TU = "weapons.bombs.FAB-250M54TU"
ENUMS.Storage.weapons.missiles.DWS39_MJ1 = "weapons.missiles.DWS39_MJ1"
ENUMS.Storage.weapons.missiles.CM_802AKG = "weapons.missiles.CM-802AKG"
ENUMS.Storage.weapons.bombs.FAB_250 = "weapons.bombs.FAB_250"
ENUMS.Storage.weapons.missiles.C_802AK = "weapons.missiles.C_802AK"
ENUMS.Storage.weapons.bombs.SD_500_A = "weapons.bombs.SD_500_A"
ENUMS.Storage.weapons.bombs.GBU_32_V_2B = "weapons.bombs.GBU_32_V_2B"
ENUMS.Storage.weapons.containers.marder = "weapons.containers.marder"
ENUMS.Storage.weapons.missiles.ADM_141B = "weapons.missiles.ADM_141B"
ENUMS.Storage.weapons.bombs.ROCKEYE = "weapons.bombs.ROCKEYE"
ENUMS.Storage.weapons.missiles.BK90_MJ1 = "weapons.missiles.BK90_MJ1"
ENUMS.Storage.weapons.containers.BTR_80 = "weapons.containers.BTR-80"
ENUMS.Storage.weapons.bombs.SAM_ROLAND_ADS_34720lb = "weapons.bombs.SAM ROLAND ADS [34720lb]"
ENUMS.Storage.weapons.containers.wmd7 = "weapons.containers.wmd7"
ENUMS.Storage.weapons.missiles.C_701T = "weapons.missiles.C-701T"
ENUMS.Storage.weapons.missiles.AIM_7E_2 = "weapons.missiles.AIM-7E-2"
ENUMS.Storage.weapons.nurs.HVAR = "weapons.nurs.HVAR"
ENUMS.Storage.weapons.containers.HMMWV_M1043 = "weapons.containers.HMMWV_M1043"
ENUMS.Storage.weapons.droptanks.PTB_800_MIG21 = "weapons.droptanks.PTB-800-MIG21"
ENUMS.Storage.weapons.missiles.AGM_114 = "weapons.missiles.AGM_114"
ENUMS.Storage.weapons.bombs.APC_M1126_Stryker_ICV_29542lb = "weapons.bombs.APC M1126 Stryker ICV [29542lb]"
ENUMS.Storage.weapons.bombs.APC_M113_Air_21624lb = "weapons.bombs.APC M113 Air [21624lb]"
ENUMS.Storage.weapons.bombs.M_117 = "weapons.bombs.M_117"
ENUMS.Storage.weapons.missiles.AGM_65D = "weapons.missiles.AGM_65D"
ENUMS.Storage.weapons.droptanks.MB339_TT320_L = "weapons.droptanks.MB339_TT320_L"
ENUMS.Storage.weapons.missiles.AGM_86 = "weapons.missiles.AGM_86"
ENUMS.Storage.weapons.bombs.BDU_45LGB = "weapons.bombs.BDU_45LGB"
ENUMS.Storage.weapons.missiles.AGM_65H = "weapons.missiles.AGM_65H"
ENUMS.Storage.weapons.nurs.RS_82 = "weapons.nurs.RS-82"
ENUMS.Storage.weapons.nurs.SNEB_TYPE252_F1B = "weapons.nurs.SNEB_TYPE252_F1B"
ENUMS.Storage.weapons.bombs.BL_755 = "weapons.bombs.BL_755"
ENUMS.Storage.weapons.containers.F_15E_AAQ_28_LITENING = "weapons.containers.F-15E_AAQ-28_LITENING"
ENUMS.Storage.weapons.nurs.SNEB_TYPE256_F1B = "weapons.nurs.SNEB_TYPE256_F1B"
ENUMS.Storage.weapons.missiles.AGM_84H = "weapons.missiles.AGM_84H"
ENUMS.Storage.weapons.missiles.AIM_54 = "weapons.missiles.AIM_54"
ENUMS.Storage.weapons.missiles.X_31A = "weapons.missiles.X_31A"
ENUMS.Storage.weapons.bombs.KAB_500Kr = "weapons.bombs.KAB_500Kr"
ENUMS.Storage.weapons.containers.SPS_141_100 = "weapons.containers.SPS-141-100"
ENUMS.Storage.weapons.missiles.BK90_MJ2 = "weapons.missiles.BK90_MJ2"
ENUMS.Storage.weapons.missiles.Super_530D = "weapons.missiles.Super_530D"
ENUMS.Storage.weapons.bombs.CBU_52B = "weapons.bombs.CBU_52B"
ENUMS.Storage.weapons.droptanks.PTB_450 = "weapons.droptanks.PTB-450"
ENUMS.Storage.weapons.bombs.IFV_MCV_80_34720lb = "weapons.bombs.IFV MCV-80 [34720lb]"
ENUMS.Storage.weapons.containers.Two_c9 = "weapons.containers.2-c9"
ENUMS.Storage.weapons.missiles.AIM_9JULI = "weapons.missiles.AIM-9JULI"
ENUMS.Storage.weapons.droptanks.MB339_TT500_R = "weapons.droptanks.MB339_TT500_R"
ENUMS.Storage.weapons.nurs.C_8CM = "weapons.nurs.C_8CM"
ENUMS.Storage.weapons.containers.BARAX = "weapons.containers.BARAX"
ENUMS.Storage.weapons.missiles.P_40R = "weapons.missiles.P_40R"
ENUMS.Storage.weapons.missiles.YJ_12 = "weapons.missiles.YJ-12"
ENUMS.Storage.weapons.missiles.CM_802AKG = "weapons.missiles.CM_802AKG"
ENUMS.Storage.weapons.nurs.SNEB_TYPE254_H1_YELLOW = "weapons.nurs.SNEB_TYPE254_H1_YELLOW"
ENUMS.Storage.weapons.bombs.Durandal = "weapons.bombs.Durandal"
ENUMS.Storage.weapons.droptanks.i16_eft = "weapons.droptanks.i16_eft"
ENUMS.Storage.weapons.droptanks.AV8BNA_AERO1D_EMPTY = "weapons.droptanks.AV8BNA_AERO1D_EMPTY"
ENUMS.Storage.weapons.containers.Hercules_Battle_Station_TGP = "weapons.containers.Hercules_Battle_Station_TGP"
ENUMS.Storage.weapons.nurs.C_8CM_VT = "weapons.nurs.C_8CM_VT"
ENUMS.Storage.weapons.missiles.PL_12 = "weapons.missiles.PL-12"
ENUMS.Storage.weapons.missiles.R_3R = "weapons.missiles.R-3R"
ENUMS.Storage.weapons.bombs.GBU_54_V_1B = "weapons.bombs.GBU_54_V_1B"
ENUMS.Storage.weapons.droptanks.MB339_TT320_R = "weapons.droptanks.MB339_TT320_R"
ENUMS.Storage.weapons.bombs.RN_24 = "weapons.bombs.RN-24"
ENUMS.Storage.weapons.containers.Twoc6m = "weapons.containers.2c6m"
ENUMS.Storage.weapons.bombs.ARV_BRDM_2_Air_12320lb = "weapons.bombs.ARV BRDM-2 Air [12320lb]"
ENUMS.Storage.weapons.bombs.ARV_BRDM_2_Skid_12210lb = "weapons.bombs.ARV BRDM-2 Skid [12210lb]"
ENUMS.Storage.weapons.nurs.SNEB_TYPE251_F1B = "weapons.nurs.SNEB_TYPE251_F1B"
ENUMS.Storage.weapons.missiles.X_41 = "weapons.missiles.X_41"
ENUMS.Storage.weapons.containers.MIG21_SMOKE_WHITE = "weapons.containers.{MIG21_SMOKE_WHITE}"
ENUMS.Storage.weapons.bombs.MK_82AIR = "weapons.bombs.MK_82AIR"
ENUMS.Storage.weapons.missiles.R_530F_EM = "weapons.missiles.R_530F_EM"
ENUMS.Storage.weapons.bombs.SAMP400LD = "weapons.bombs.SAMP400LD"
ENUMS.Storage.weapons.bombs.FAB_50 = "weapons.bombs.FAB_50"
ENUMS.Storage.weapons.bombs.AB_250_2_SD_10A = "weapons.bombs.AB_250_2_SD_10A"
ENUMS.Storage.weapons.missiles.ADM_141A = "weapons.missiles.ADM_141A"
ENUMS.Storage.weapons.containers.KBpod = "weapons.containers.KBpod"
ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk4 = "weapons.bombs.British_GP_500LB_Bomb_Mk4"
ENUMS.Storage.weapons.missiles.AGM_65E = "weapons.missiles.AGM_65E"
ENUMS.Storage.weapons.containers.sa342_dipole_antenna = "weapons.containers.sa342_dipole_antenna"
ENUMS.Storage.weapons.bombs.OFAB_100_Jupiter = "weapons.bombs.OFAB-100 Jupiter"
ENUMS.Storage.weapons.nurs.SNEB_TYPE257_F1B = "weapons.nurs.SNEB_TYPE257_F1B"
ENUMS.Storage.weapons.missiles.Rb_04E_for_A_I = "weapons.missiles.Rb 04E (for A.I.)"
ENUMS.Storage.weapons.bombs.AN_M66A2 = "weapons.bombs.AN-M66A2"
ENUMS.Storage.weapons.missiles.P_27T = "weapons.missiles.P_27T"
ENUMS.Storage.weapons.droptanks.LNS_VIG_XTANK = "weapons.droptanks.LNS_VIG_XTANK"
ENUMS.Storage.weapons.missiles.R_55 = "weapons.missiles.R-55"
ENUMS.Storage.weapons.torpedoes.YU_6 = "weapons.torpedoes.YU-6"
ENUMS.Storage.weapons.bombs.British_MC_250LB_Bomb_Mk2 = "weapons.bombs.British_MC_250LB_Bomb_Mk2"
ENUMS.Storage.weapons.droptanks.PTB_120_F86F35 = "weapons.droptanks.PTB_120_F86F35"
ENUMS.Storage.weapons.missiles.PL_8B = "weapons.missiles.PL-8B"
ENUMS.Storage.weapons.droptanks.F_15E_Drop_Tank_Empty = "weapons.droptanks.F-15E_Drop_Tank_Empty"
ENUMS.Storage.weapons.nurs.British_HE_60LBFNo1_3INCHNo1 = "weapons.nurs.British_HE_60LBFNo1_3INCHNo1"
ENUMS.Storage.weapons.missiles.P_77 = "weapons.missiles.P_77"
ENUMS.Storage.weapons.torpedoes.LTF_5B = "weapons.torpedoes.LTF_5B"
ENUMS.Storage.weapons.missiles.R_3S = "weapons.missiles.R-3S"
ENUMS.Storage.weapons.nurs.SNEB_TYPE253_H1 = "weapons.nurs.SNEB_TYPE253_H1"
ENUMS.Storage.weapons.missiles.PL_8A = "weapons.missiles.PL-8A"
ENUMS.Storage.weapons.bombs.APC_BTR_82A_Skid_24888lb = "weapons.bombs.APC BTR-82A Skid [24888lb]"
ENUMS.Storage.weapons.containers.Sborka = "weapons.containers.Sborka"
ENUMS.Storage.weapons.missiles.AGM_65L = "weapons.missiles.AGM_65L"
ENUMS.Storage.weapons.missiles.X_28 = "weapons.missiles.X_28"
ENUMS.Storage.weapons.missiles.TGM_65G = "weapons.missiles.TGM_65G"
ENUMS.Storage.weapons.nurs.SNEB_TYPE257_H1 = "weapons.nurs.SNEB_TYPE257_H1"
ENUMS.Storage.weapons.missiles.RB75B = "weapons.missiles.RB75B"
ENUMS.Storage.weapons.missiles.X_25ML = "weapons.missiles.X_25ML"
ENUMS.Storage.weapons.droptanks.FPU_8A = "weapons.droptanks.FPU_8A"
ENUMS.Storage.weapons.bombs.BLG66 = "weapons.bombs.BLG66"
ENUMS.Storage.weapons.nurs.C_8CM_RD = "weapons.nurs.C_8CM_RD"
ENUMS.Storage.weapons.containers.EclairM_06 = "weapons.containers.{EclairM_06}"
ENUMS.Storage.weapons.bombs.RBK_500AO = "weapons.bombs.RBK_500AO"
ENUMS.Storage.weapons.missiles.AIM_9P = "weapons.missiles.AIM-9P"
ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk4_Short = "weapons.bombs.British_GP_500LB_Bomb_Mk4_Short"
ENUMS.Storage.weapons.containers.MB339_Vinten = "weapons.containers.MB339_Vinten"
ENUMS.Storage.weapons.missiles.Rb_15F = "weapons.missiles.Rb 15F"
ENUMS.Storage.weapons.nurs.ARAKM70BHE = "weapons.nurs.ARAKM70BHE"
ENUMS.Storage.weapons.bombs.AAA_Vulcan_M163_Air_21666lb = "weapons.bombs.AAA Vulcan M163 Air [21666lb]"
ENUMS.Storage.weapons.missiles.X_29L = "weapons.missiles.X_29L"
ENUMS.Storage.weapons.containers.F14_LANTIRN_TP = "weapons.containers.{F14-LANTIRN-TP}"
ENUMS.Storage.weapons.bombs.FAB_250_M62 = "weapons.bombs.FAB-250-M62"
ENUMS.Storage.weapons.missiles.AIM_120C = "weapons.missiles.AIM_120C"
ENUMS.Storage.weapons.bombs.EWR_SBORKA_Air_21624lb = "weapons.bombs.EWR SBORKA Air [21624lb]"
ENUMS.Storage.weapons.bombs.SAMP250LD = "weapons.bombs.SAMP250LD"
ENUMS.Storage.weapons.droptanks.Spitfire_slipper_tank = "weapons.droptanks.Spitfire_slipper_tank"
ENUMS.Storage.weapons.missiles.LS_6_500 = "weapons.missiles.LS-6-500"
ENUMS.Storage.weapons.bombs.GBU_31_V_4B = "weapons.bombs.GBU_31_V_4B"
ENUMS.Storage.weapons.droptanks.PTB400_MIG15 = "weapons.droptanks.PTB400_MIG15"
ENUMS.Storage.weapons.containers.m_113 = "weapons.containers.m-113"
ENUMS.Storage.weapons.bombs.SPG_M1128_Stryker_MGS_33036lb = "weapons.bombs.SPG M1128 Stryker MGS [33036lb]"
ENUMS.Storage.weapons.missiles.AIM_9L = "weapons.missiles.AIM-9L"
ENUMS.Storage.weapons.missiles.AIM_9X = "weapons.missiles.AIM_9X"
ENUMS.Storage.weapons.nurs.C_8 = "weapons.nurs.C_8"
ENUMS.Storage.weapons.bombs.SAM_CHAPARRAL_Skid_21516lb = "weapons.bombs.SAM CHAPARRAL Skid [21516lb]"
ENUMS.Storage.weapons.missiles.P_27TE = "weapons.missiles.P_27TE"
ENUMS.Storage.weapons.bombs.ODAB_500PM = "weapons.bombs.ODAB-500PM"
ENUMS.Storage.weapons.bombs.MK77mod1_WPN = "weapons.bombs.MK77mod1-WPN"
ENUMS.Storage.weapons.droptanks.PTB400_MIG19 = "weapons.droptanks.PTB400_MIG19"
ENUMS.Storage.weapons.torpedoes.Mark_46 = "weapons.torpedoes.Mark_46"
ENUMS.Storage.weapons.containers.rightSeat = "weapons.containers.rightSeat"
ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_ORANGE = "weapons.containers.{US_M10_SMOKE_TANK_ORANGE}"
ENUMS.Storage.weapons.bombs.SAB_100MN = "weapons.bombs.SAB_100MN"
ENUMS.Storage.weapons.nurs.FFAR_Mk5_HEAT = "weapons.nurs.FFAR Mk5 HEAT"
ENUMS.Storage.weapons.bombs.IFV_TPZ_FUCH_33440lb = "weapons.bombs.IFV TPZ FUCH [33440lb]"
ENUMS.Storage.weapons.bombs.IFV_M2A2_Bradley_34720lb = "weapons.bombs.IFV M2A2 Bradley [34720lb]"
ENUMS.Storage.weapons.bombs.MK77mod0_WPN = "weapons.bombs.MK77mod0-WPN"
ENUMS.Storage.weapons.containers.ASO_2 = "weapons.containers.ASO-2"
ENUMS.Storage.weapons.bombs.Mk_84AIR_GP = "weapons.bombs.Mk_84AIR_GP"
ENUMS.Storage.weapons.nurs.S_24A = "weapons.nurs.S-24A"
ENUMS.Storage.weapons.bombs.RBK_250_275_AO_1SCH = "weapons.bombs.RBK_250_275_AO_1SCH"
ENUMS.Storage.weapons.bombs.Transport_Tigr_Skid_15730lb = "weapons.bombs.Transport Tigr Skid [15730lb]"
ENUMS.Storage.weapons.missiles.AIM_7F = "weapons.missiles.AIM-7F"
ENUMS.Storage.weapons.bombs.CBU_99 = "weapons.bombs.CBU_99"
ENUMS.Storage.weapons.bombs.LUU_2B = "weapons.bombs.LUU_2B"
ENUMS.Storage.weapons.bombs.FAB_500TA = "weapons.bombs.FAB-500TA"
ENUMS.Storage.weapons.missiles.AGR_20_M282 = "weapons.missiles.AGR_20_M282"
ENUMS.Storage.weapons.droptanks.MB339_FT330 = "weapons.droptanks.MB339_FT330"
ENUMS.Storage.weapons.bombs.SAMP125LD = "weapons.bombs.SAMP125LD"
ENUMS.Storage.weapons.missiles.X_25MP = "weapons.missiles.X_25MP"
ENUMS.Storage.weapons.nurs.SNEB_TYPE252_H1 = "weapons.nurs.SNEB_TYPE252_H1"
ENUMS.Storage.weapons.missiles.AGM_65F = "weapons.missiles.AGM_65F"
ENUMS.Storage.weapons.missiles.AIM_9P5 = "weapons.missiles.AIM-9P5"
ENUMS.Storage.weapons.bombs.Transport_Tigr_Air_15900lb = "weapons.bombs.Transport Tigr Air [15900lb]"
ENUMS.Storage.weapons.nurs.SNEB_TYPE254_H1_RED = "weapons.nurs.SNEB_TYPE254_H1_RED"
ENUMS.Storage.weapons.nurs.FFAR_Mk1_HE = "weapons.nurs.FFAR Mk1 HE"
ENUMS.Storage.weapons.nurs.SPRD_99 = "weapons.nurs.SPRD-99"
ENUMS.Storage.weapons.bombs.BIN_200 = "weapons.bombs.BIN_200"
ENUMS.Storage.weapons.bombs.BLU_4B_GROUP = "weapons.bombs.BLU_4B_GROUP"
ENUMS.Storage.weapons.bombs.GBU_24 = "weapons.bombs.GBU_24"
ENUMS.Storage.weapons.missiles.Rb_04E = "weapons.missiles.Rb 04E"
ENUMS.Storage.weapons.missiles.Rb_74 = "weapons.missiles.Rb 74"
ENUMS.Storage.weapons.containers.leftSeat = "weapons.containers.leftSeat"
ENUMS.Storage.weapons.bombs.LS_6_100 = "weapons.bombs.LS-6-100"
ENUMS.Storage.weapons.bombs.Transport_URAL_375_14815lb = "weapons.bombs.Transport URAL-375 [14815lb]"
ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_GREEN = "weapons.containers.{US_M10_SMOKE_TANK_GREEN}"
ENUMS.Storage.weapons.missiles.X_22 = "weapons.missiles.X_22"
ENUMS.Storage.weapons.containers.FAS = "weapons.containers.FAS"
ENUMS.Storage.weapons.nurs.S_25_O = "weapons.nurs.S-25-O"
ENUMS.Storage.weapons.droptanks.para = "weapons.droptanks.para"
ENUMS.Storage.weapons.droptanks.F_15E_Drop_Tank = "weapons.droptanks.F-15E_Drop_Tank"
ENUMS.Storage.weapons.droptanks.M2KC_08_RPL541_EMPTY = "weapons.droptanks.M2KC_08_RPL541_EMPTY"
ENUMS.Storage.weapons.missiles.X_31P = "weapons.missiles.X_31P"
ENUMS.Storage.weapons.bombs.RBK_500U = "weapons.bombs.RBK_500U"
ENUMS.Storage.weapons.missiles.AIM_54A_Mk47 = "weapons.missiles.AIM_54A_Mk47"
ENUMS.Storage.weapons.droptanks.oiltank = "weapons.droptanks.oiltank"
ENUMS.Storage.weapons.missiles.AGM_154B = "weapons.missiles.AGM_154B"
ENUMS.Storage.weapons.containers.MB339_SMOKE_POD = "weapons.containers.MB339_SMOKE-POD"
ENUMS.Storage.weapons.containers.ECM_POD_L_175V = "weapons.containers.{ECM_POD_L_175V}"
ENUMS.Storage.weapons.droptanks.PTB_580G_F1 = "weapons.droptanks.PTB_580G_F1"
ENUMS.Storage.weapons.containers.EclairM_15 = "weapons.containers.{EclairM_15}"
ENUMS.Storage.weapons.containers.F_15E_AAQ_13_LANTIRN = "weapons.containers.F-15E_AAQ-13_LANTIRN"
ENUMS.Storage.weapons.droptanks.Eight00L_Tank_Empty = "weapons.droptanks.800L Tank Empty"
ENUMS.Storage.weapons.containers.One6c_hts_pod = "weapons.containers.16c_hts_pod"
ENUMS.Storage.weapons.bombs.AN_M81 = "weapons.bombs.AN-M81"
ENUMS.Storage.weapons.droptanks.Mosquito_Drop_Tank_100gal = "weapons.droptanks.Mosquito_Drop_Tank_100gal"
ENUMS.Storage.weapons.droptanks.Mosquito_Drop_Tank_50gal = "weapons.droptanks.Mosquito_Drop_Tank_50gal"
ENUMS.Storage.weapons.droptanks.DFT_150_GAL_A4E = "weapons.droptanks.DFT_150_GAL_A4E"
ENUMS.Storage.weapons.missiles.AIM_9 = "weapons.missiles.AIM_9"
ENUMS.Storage.weapons.bombs.IFV_BTR_D_Air_18040lb = "weapons.bombs.IFV BTR-D Air [18040lb]"
ENUMS.Storage.weapons.containers.EclairM_42 = "weapons.containers.{EclairM_42}"
ENUMS.Storage.weapons.bombs.KAB_1500T = "weapons.bombs.KAB_1500T"
ENUMS.Storage.weapons.droptanks.PTB_490_MIG21 = "weapons.droptanks.PTB-490-MIG21"
ENUMS.Storage.weapons.droptanks.PTB_200_F86F35 = "weapons.droptanks.PTB_200_F86F35"
ENUMS.Storage.weapons.droptanks.PTB760_MIG19 = "weapons.droptanks.PTB760_MIG19"
ENUMS.Storage.weapons.bombs.GBU_43_B_MOAB = "weapons.bombs.GBU-43/B(MOAB)"
ENUMS.Storage.weapons.torpedoes.G7A_T1 = "weapons.torpedoes.G7A_T1"
ENUMS.Storage.weapons.bombs.IFV_BMD_1_Air_18040lb = "weapons.bombs.IFV BMD-1 Air [18040lb]"
ENUMS.Storage.weapons.bombs.SAM_LINEBACKER_34720lb = "weapons.bombs.SAM LINEBACKER [34720lb]"
ENUMS.Storage.weapons.containers.ais_pod_t50_r = "weapons.containers.ais-pod-t50_r"
ENUMS.Storage.weapons.containers.CE2_SMOKE_WHITE = "weapons.containers.{CE2_SMOKE_WHITE}"
ENUMS.Storage.weapons.droptanks.fuel_tank_230 = "weapons.droptanks.fuel_tank_230"
ENUMS.Storage.weapons.droptanks.M2KC_RPL_522 = "weapons.droptanks.M2KC_RPL_522"
ENUMS.Storage.weapons.missiles.AGM_130 = "weapons.missiles.AGM_130"
ENUMS.Storage.weapons.droptanks.Eight00L_Tank = "weapons.droptanks.800L Tank"
ENUMS.Storage.weapons.bombs.IFV_BTR_D_Skid_17930lb = "weapons.bombs.IFV BTR-D Skid [17930lb]"
ENUMS.Storage.weapons.containers.bmp_1 = "weapons.containers.bmp-1"
ENUMS.Storage.weapons.bombs.GBU_31 = "weapons.bombs.GBU_31"
ENUMS.Storage.weapons.containers.aaq_28LEFT_litening = "weapons.containers.aaq-28LEFT litening"
ENUMS.Storage.weapons.missiles.Kh_66_Grom = "weapons.missiles.Kh-66_Grom"
ENUMS.Storage.weapons.containers.MIG21_SMOKE_RED = "weapons.containers.{MIG21_SMOKE_RED}"
ENUMS.Storage.weapons.containers.U22 = "weapons.containers.U22"
ENUMS.Storage.weapons.bombs.IFV_BMD_1_Skid_17930lb = "weapons.bombs.IFV BMD-1 Skid [17930lb]"
ENUMS.Storage.weapons.droptanks.Bidon = "weapons.droptanks.Bidon"
ENUMS.Storage.weapons.bombs.GBU_31_V_2B = "weapons.bombs.GBU_31_V_2B"
ENUMS.Storage.weapons.bombs.Mk_82Y = "weapons.bombs.Mk_82Y"
ENUMS.Storage.weapons.containers.pl5eii = "weapons.containers.pl5eii"
ENUMS.Storage.weapons.bombs.RBK_500U_OAB_2_5RT = "weapons.bombs.RBK_500U_OAB_2_5RT"
ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk5 = "weapons.bombs.British_GP_500LB_Bomb_Mk5"
ENUMS.Storage.weapons.containers.Eclair = "weapons.containers.{Eclair}"
ENUMS.Storage.weapons.nurs.S5MO_HEFRAG_FFAR = "weapons.nurs.S5MO_HEFRAG_FFAR"
ENUMS.Storage.weapons.bombs.BETAB_500M = "weapons.bombs.BETAB-500M"
ENUMS.Storage.weapons.bombs.Transport_M818_16000lb = "weapons.bombs.Transport M818 [16000lb]"
ENUMS.Storage.weapons.bombs.British_MC_250LB_Bomb_Mk1 = "weapons.bombs.British_MC_250LB_Bomb_Mk1"
ENUMS.Storage.weapons.nurs.SNEB_TYPE251_H1 = "weapons.nurs.SNEB_TYPE251_H1"
ENUMS.Storage.weapons.bombs.TYPE_200A = "weapons.bombs.TYPE-200A"
ENUMS.Storage.weapons.nurs.HYDRA_70_M151 = "weapons.nurs.HYDRA_70_M151"
ENUMS.Storage.weapons.bombs.IFV_BMP_3_32912lb = "weapons.bombs.IFV BMP-3 [32912lb]"
ENUMS.Storage.weapons.bombs.APC_MTLB_Air_26400lb = "weapons.bombs.APC MTLB Air [26400lb]"
ENUMS.Storage.weapons.nurs.HYDRA_70_M229 = "weapons.nurs.HYDRA_70_M229"
ENUMS.Storage.weapons.bombs.BDU_45 = "weapons.bombs.BDU_45"
ENUMS.Storage.weapons.bombs.OFAB_100_120TU = "weapons.bombs.OFAB-100-120TU"
ENUMS.Storage.weapons.missiles.AIM_9J = "weapons.missiles.AIM-9J"
ENUMS.Storage.weapons.nurs.ARF8M3API = "weapons.nurs.ARF8M3API"
ENUMS.Storage.weapons.bombs.BetAB_500ShP = "weapons.bombs.BetAB_500ShP"
ENUMS.Storage.weapons.nurs.C_8OFP2 = "weapons.nurs.C_8OFP2"
ENUMS.Storage.weapons.bombs.GBU_10 = "weapons.bombs.GBU_10"
ENUMS.Storage.weapons.bombs.APC_MTLB_Skid_26290lb = "weapons.bombs.APC MTLB Skid [26290lb]"
ENUMS.Storage.weapons.nurs.SNEB_TYPE254_F1B_RED = "weapons.nurs.SNEB_TYPE254_F1B_RED"
ENUMS.Storage.weapons.missiles.X_65 = "weapons.missiles.X_65"
ENUMS.Storage.weapons.missiles.R_550_M1 = "weapons.missiles.R_550_M1"
ENUMS.Storage.weapons.missiles.AGM_65K = "weapons.missiles.AGM_65K"
ENUMS.Storage.weapons.nurs.SNEB_TYPE254_F1B_YELLOW = "weapons.nurs.SNEB_TYPE254_F1B_YELLOW"
ENUMS.Storage.weapons.missiles.AGM_88 = "weapons.missiles.AGM_88"
ENUMS.Storage.weapons.nurs.C_8OM = "weapons.nurs.C_8OM"
ENUMS.Storage.weapons.bombs.SAM_ROLAND_LN_34720b = "weapons.bombs.SAM ROLAND LN [34720b]"
ENUMS.Storage.weapons.missiles.AIM_120 = "weapons.missiles.AIM_120"
ENUMS.Storage.weapons.missiles.HOT3_MBDA = "weapons.missiles.HOT3_MBDA"
ENUMS.Storage.weapons.missiles.R_13M = "weapons.missiles.R-13M"
ENUMS.Storage.weapons.missiles.AIM_54C_Mk60 = "weapons.missiles.AIM_54C_Mk60"
ENUMS.Storage.weapons.bombs.AAA_GEPARD_34720lb = "weapons.bombs.AAA GEPARD [34720lb]"
ENUMS.Storage.weapons.missiles.R_13M1 = "weapons.missiles.R-13M1"
ENUMS.Storage.weapons.bombs.APC_Cobra_Air_10912lb = "weapons.bombs.APC Cobra Air [10912lb]"
ENUMS.Storage.weapons.bombs.RBK_250 = "weapons.bombs.RBK_250"
ENUMS.Storage.weapons.bombs.SC_500_J = "weapons.bombs.SC_500_J"
ENUMS.Storage.weapons.missiles.AGM_114K = "weapons.missiles.AGM_114K"
ENUMS.Storage.weapons.missiles.ALARM = "weapons.missiles.ALARM"
ENUMS.Storage.weapons.bombs.Mk_83 = "weapons.bombs.Mk_83"
ENUMS.Storage.weapons.missiles.AGM_65B = "weapons.missiles.AGM_65B"
ENUMS.Storage.weapons.bombs.MK_82SNAKEYE = "weapons.bombs.MK_82SNAKEYE"
ENUMS.Storage.weapons.nurs.HYDRA_70_MK1 = "weapons.nurs.HYDRA_70_MK1"
ENUMS.Storage.weapons.bombs.BLG66_BELOUGA = "weapons.bombs.BLG66_BELOUGA"
ENUMS.Storage.weapons.containers.EclairM_51 = "weapons.containers.{EclairM_51}"
ENUMS.Storage.weapons.missiles.AIM_54A_Mk60 = "weapons.missiles.AIM_54A_Mk60"
ENUMS.Storage.weapons.droptanks.DFT_300_GAL_A4E = "weapons.droptanks.DFT_300_GAL_A4E"
ENUMS.Storage.weapons.bombs.ATGM_M1134_Stryker_30337lb = "weapons.bombs.ATGM M1134 Stryker [30337lb]"
ENUMS.Storage.weapons.bombs.BAT_120 = "weapons.bombs.BAT-120"
ENUMS.Storage.weapons.missiles.DWS39_MJ1_MJ2 = "weapons.missiles.DWS39_MJ1_MJ2"
ENUMS.Storage.weapons.containers.SPRD = "weapons.containers.SPRD"
ENUMS.Storage.weapons.bombs.BR_500 = "weapons.bombs.BR_500"
ENUMS.Storage.weapons.bombs.British_GP_500LB_Bomb_Mk1 = "weapons.bombs.British_GP_500LB_Bomb_Mk1"
ENUMS.Storage.weapons.bombs.BDU_50HD = "weapons.bombs.BDU_50HD"
ENUMS.Storage.weapons.missiles.RS2US = "weapons.missiles.RS2US"
ENUMS.Storage.weapons.bombs.IFV_BMP_2_25168lb = "weapons.bombs.IFV BMP-2 [25168lb]"
ENUMS.Storage.weapons.bombs.SAMP400HD = "weapons.bombs.SAMP400HD"
ENUMS.Storage.weapons.containers.Hercules_Battle_Station = "weapons.containers.Hercules_Battle_Station"
ENUMS.Storage.weapons.bombs.AN_M64 = "weapons.bombs.AN_M64"
ENUMS.Storage.weapons.containers.rearCargoSeats = "weapons.containers.rearCargoSeats"
ENUMS.Storage.weapons.bombs.Mk_82 = "weapons.bombs.Mk_82"
ENUMS.Storage.weapons.missiles.AKD_10 = "weapons.missiles.AKD-10"
ENUMS.Storage.weapons.bombs.BDU_50LGB = "weapons.bombs.BDU_50LGB"
ENUMS.Storage.weapons.missiles.SD_10 = "weapons.missiles.SD-10"
ENUMS.Storage.weapons.containers.IRDeflector = "weapons.containers.IRDeflector"
ENUMS.Storage.weapons.bombs.FAB_500 = "weapons.bombs.FAB_500"
ENUMS.Storage.weapons.bombs.KAB_500 = "weapons.bombs.KAB_500"
ENUMS.Storage.weapons.nurs.S_5M = "weapons.nurs.S-5M"
ENUMS.Storage.weapons.missiles.MICA_R = "weapons.missiles.MICA_R"
ENUMS.Storage.weapons.missiles.X_59M = "weapons.missiles.X_59M"
ENUMS.Storage.weapons.nurs.UG_90MM = "weapons.nurs.UG_90MM"
ENUMS.Storage.weapons.bombs.LYSBOMB = "weapons.bombs.LYSBOMB"
ENUMS.Storage.weapons.nurs.R4M = "weapons.nurs.R4M"
ENUMS.Storage.weapons.containers.dlpod_akg = "weapons.containers.dlpod_akg"
ENUMS.Storage.weapons.missiles.LD_10 = "weapons.missiles.LD-10"
ENUMS.Storage.weapons.bombs.SC_50 = "weapons.bombs.SC_50"
ENUMS.Storage.weapons.nurs.HYDRA_70_MK5 = "weapons.nurs.HYDRA_70_MK5"
ENUMS.Storage.weapons.bombs.FAB_100M = "weapons.bombs.FAB_100M"
ENUMS.Storage.weapons.missiles.Rb_24 = "weapons.missiles.Rb 24"
ENUMS.Storage.weapons.bombs.BDU_45B = "weapons.bombs.BDU_45B"
ENUMS.Storage.weapons.missiles.GB_6_HE = "weapons.missiles.GB-6-HE"
ENUMS.Storage.weapons.missiles.KD_63B = "weapons.missiles.KD-63B"
ENUMS.Storage.weapons.missiles.P_27PE = "weapons.missiles.P_27PE"
ENUMS.Storage.weapons.droptanks.PTB300_MIG15 = "weapons.droptanks.PTB300_MIG15"
ENUMS.Storage.weapons.bombs.Two50_3 = "weapons.bombs.250-3"
ENUMS.Storage.weapons.bombs.SC_500_L2 = "weapons.bombs.SC_500_L2"
ENUMS.Storage.weapons.containers.HMMWV_M1045 = "weapons.containers.HMMWV_M1045"
ENUMS.Storage.weapons.bombs.FAB_500M54TU = "weapons.bombs.FAB-500M54TU"
ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_YELLOW = "weapons.containers.{US_M10_SMOKE_TANK_YELLOW}"
ENUMS.Storage.weapons.containers.EclairM_60 = "weapons.containers.{EclairM_60}"
ENUMS.Storage.weapons.bombs.SAB_250_200 = "weapons.bombs.SAB_250_200"
ENUMS.Storage.weapons.bombs.FAB_100 = "weapons.bombs.FAB_100"
ENUMS.Storage.weapons.bombs.KAB_500S = "weapons.bombs.KAB_500S"
ENUMS.Storage.weapons.missiles.AGM_45A = "weapons.missiles.AGM_45A"
ENUMS.Storage.weapons.missiles.Kh25MP_PRGS1VP = "weapons.missiles.Kh25MP_PRGS1VP"
ENUMS.Storage.weapons.nurs.S5M1_HEFRAG_FFAR = "weapons.nurs.S5M1_HEFRAG_FFAR"
ENUMS.Storage.weapons.containers.kg600 = "weapons.containers.kg600"
ENUMS.Storage.weapons.bombs.AN_M65 = "weapons.bombs.AN_M65"
ENUMS.Storage.weapons.bombs.AN_M57 = "weapons.bombs.AN_M57"
ENUMS.Storage.weapons.bombs.BLU_3B_GROUP = "weapons.bombs.BLU_3B_GROUP"
ENUMS.Storage.weapons.bombs.BAP_100 = "weapons.bombs.BAP-100"
ENUMS.Storage.weapons.containers.HEMTT = "weapons.containers.HEMTT"
ENUMS.Storage.weapons.bombs.British_MC_500LB_Bomb_Mk1_Short = "weapons.bombs.British_MC_500LB_Bomb_Mk1_Short"
ENUMS.Storage.weapons.nurs.ARAKM70BAP = "weapons.nurs.ARAKM70BAP"
ENUMS.Storage.weapons.missiles.AGM_119 = "weapons.missiles.AGM_119"
ENUMS.Storage.weapons.missiles.MMagicII = "weapons.missiles.MMagicII"
ENUMS.Storage.weapons.bombs.AB_500_1_SD_10A = "weapons.bombs.AB_500_1_SD_10A"
ENUMS.Storage.weapons.nurs.HYDRA_70_M282 = "weapons.nurs.HYDRA_70_M282"
ENUMS.Storage.weapons.droptanks.DFT_400_GAL_A4E = "weapons.droptanks.DFT_400_GAL_A4E"
ENUMS.Storage.weapons.nurs.HYDRA_70_M257 = "weapons.nurs.HYDRA_70_M257"
ENUMS.Storage.weapons.droptanks.AV8BNA_AERO1D = "weapons.droptanks.AV8BNA_AERO1D"
ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_BLUE = "weapons.containers.{US_M10_SMOKE_TANK_BLUE}"
ENUMS.Storage.weapons.nurs.ARF8M3HEI = "weapons.nurs.ARF8M3HEI"
ENUMS.Storage.weapons.bombs.RN_28 = "weapons.bombs.RN-28"
ENUMS.Storage.weapons.bombs.Squad_30_x_Soldier_7950lb = "weapons.bombs.Squad 30 x Soldier [7950lb]"
ENUMS.Storage.weapons.containers.uaz_469 = "weapons.containers.uaz-469"
ENUMS.Storage.weapons.containers.Otokar_Cobra = "weapons.containers.Otokar_Cobra"
ENUMS.Storage.weapons.bombs.APC_BTR_82A_Air_24998lb = "weapons.bombs.APC BTR-82A Air [24998lb]"
ENUMS.Storage.weapons.nurs.HYDRA_70_M274 = "weapons.nurs.HYDRA_70_M274"
ENUMS.Storage.weapons.missiles.P_24R = "weapons.missiles.P_24R"
ENUMS.Storage.weapons.nurs.HYDRA_70_MK61 = "weapons.nurs.HYDRA_70_MK61"
ENUMS.Storage.weapons.missiles.Igla_1E = "weapons.missiles.Igla_1E"
ENUMS.Storage.weapons.missiles.C_802AK = "weapons.missiles.C-802AK"
ENUMS.Storage.weapons.nurs.C_24 = "weapons.nurs.C_24"
ENUMS.Storage.weapons.droptanks.M2KC_08_RPL541 = "weapons.droptanks.M2KC_08_RPL541"
ENUMS.Storage.weapons.nurs.C_13 = "weapons.nurs.C_13"
ENUMS.Storage.weapons.droptanks.droptank_110_gal = "weapons.droptanks.droptank_110_gal"
ENUMS.Storage.weapons.bombs.Mk_84 = "weapons.bombs.Mk_84"
ENUMS.Storage.weapons.missiles.Sea_Eagle = "weapons.missiles.Sea_Eagle"
ENUMS.Storage.weapons.droptanks.PTB_1200_F1 = "weapons.droptanks.PTB_1200_F1"
ENUMS.Storage.weapons.nurs.SNEB_TYPE256_H1 = "weapons.nurs.SNEB_TYPE256_H1"
ENUMS.Storage.weapons.containers.MATRA_PHIMAT = "weapons.containers.MATRA-PHIMAT"
ENUMS.Storage.weapons.containers.smoke_pod = "weapons.containers.smoke_pod"
ENUMS.Storage.weapons.containers.F_15E_AAQ_14_LANTIRN = "weapons.containers.F-15E_AAQ-14_LANTIRN"
ENUMS.Storage.weapons.containers.EclairM_24 = "weapons.containers.{EclairM_24}"
ENUMS.Storage.weapons.bombs.GBU_16 = "weapons.bombs.GBU_16"
ENUMS.Storage.weapons.nurs.HYDRA_70_M156 = "weapons.nurs.HYDRA_70_M156"
ENUMS.Storage.weapons.missiles.R_60 = "weapons.missiles.R-60"
ENUMS.Storage.weapons.containers.zsu_23_4 = "weapons.containers.zsu-23-4"
ENUMS.Storage.weapons.missiles.RB75 = "weapons.missiles.RB75"
ENUMS.Storage.weapons.missiles.Mistral = "weapons.missiles.Mistral"
ENUMS.Storage.weapons.droptanks.MB339_TT500_L = "weapons.droptanks.MB339_TT500_L"
ENUMS.Storage.weapons.bombs.SAM_SA_13_STRELA_21624lb = "weapons.bombs.SAM SA-13 STRELA [21624lb]"
ENUMS.Storage.weapons.bombs.SAM_Avenger_M1097_Air_7200lb = "weapons.bombs.SAM Avenger M1097 Air [7200lb]"
ENUMS.Storage.weapons.droptanks.Eleven00L_Tank_Empty = "weapons.droptanks.1100L Tank Empty"
ENUMS.Storage.weapons.bombs.AN_M88 = "weapons.bombs.AN-M88"
ENUMS.Storage.weapons.missiles.S_25L = "weapons.missiles.S_25L"
ENUMS.Storage.weapons.nurs.British_AP_25LBNo1_3INCHNo1 = "weapons.nurs.British_AP_25LBNo1_3INCHNo1"
ENUMS.Storage.weapons.bombs.BDU_50LD = "weapons.bombs.BDU_50LD"
ENUMS.Storage.weapons.bombs.AGM_62 = "weapons.bombs.AGM_62"
ENUMS.Storage.weapons.containers.US_M10_SMOKE_TANK_WHITE = "weapons.containers.{US_M10_SMOKE_TANK_WHITE}"
ENUMS.Storage.weapons.missiles.MICA_T = "weapons.missiles.MICA_T"
ENUMS.Storage.weapons.containers.HVAR_rocket = "weapons.containers.HVAR_rocket"

View File

@@ -30,6 +30,7 @@
-- @field #table runways Runways of airdromes. -- @field #table runways Runways of airdromes.
-- @field #AIRBASE.Runway runwayLanding Runway used for landing. -- @field #AIRBASE.Runway runwayLanding Runway used for landing.
-- @field #AIRBASE.Runway runwayTakeoff Runway used for takeoff. -- @field #AIRBASE.Runway runwayTakeoff Runway used for takeoff.
-- @field Wrapper.Storage#STORAGE storage The DCS warehouse storage.
-- @extends Wrapper.Positionable#POSITIONABLE -- @extends Wrapper.Positionable#POSITIONABLE
--- Wrapper class to handle the DCS Airbase objects: --- Wrapper class to handle the DCS Airbase objects:
@@ -833,6 +834,9 @@ function AIRBASE:Register(AirbaseName)
-- Init coordinate. -- Init coordinate.
self:GetCoordinate() self:GetCoordinate()
-- Storage.
self.storage=_DATABASE:AddStorage(AirbaseName)
if vec2 then if vec2 then
if self.isShip then if self.isShip then
local unit=UNIT:FindByName(AirbaseName) local unit=UNIT:FindByName(AirbaseName)
@@ -919,6 +923,87 @@ function AIRBASE:GetZone()
return self.AirbaseZone return self.AirbaseZone
end end
--- Get the DCS warehouse.
-- @param #AIRBASE self
-- @return DCS#Warehouse The DCS warehouse object.
function AIRBASE:GetWarehouse()
local warehouse=nil --DCS#Warehouse
local airbase=self:GetDCSObject()
if airbase then
warehouse=airbase:getWarehouse()
end
return warehouse
end
--- Get the warehouse storage of this airbase. The returned `STORAGE` object is the wrapper of the DCS warehouse.
-- This allows you to add and remove items such as aircraft, liquids, weapons and other equipment.
-- @param #AIRBASE self
-- @return Wrapper.Storage#STORAGE The storage.
function AIRBASE:GetStorage()
return self.storage
end
--- Enables or disables automatic capturing of the airbase.
-- @param #AIRBASE self
-- @param #boolean Switch If `true`, enable auto capturing. If `false`, disable it.
-- @return #AIRBASE self
function AIRBASE:SetAutoCapture(Switch)
local airbase=self:GetDCSObject()
if airbase then
airbase:autoCapture(Switch)
end
return self
end
--- Enables automatic capturing of the airbase.
-- @param #AIRBASE self
-- @return #AIRBASE self
function AIRBASE:SetAutoCaptureON()
self:SetAutoCapture(true)
return self
end
--- Disables automatic capturing of the airbase.
-- @param #AIRBASE self
-- @return #AIRBASE self
function AIRBASE:SetAutoCaptureOFF()
self:SetAutoCapture(false)
return self
end
--- Returns whether auto capturing of the airbase is on or off.
-- @param #AIRBASE self
-- @return #boolean Returns `true` if auto capturing is on, `false` if off and `nil` if the airbase object cannot be retrieved.
function AIRBASE:IsAutoCapture()
local airbase=self:GetDCSObject()
local auto=nil
if airbase then
auto=airbase:autoCaptureIsOn()
end
return auto
end
--- Sets the coalition of the airbase.
-- @param #AIRBASE self
-- @param #number Coal Coalition that the airbase should have (0=Neutral, 1=Red, 2=Blue).
-- @return #AIRBASE self
function AIRBASE:SetCoalition(Coal)
local airbase=self:GetDCSObject()
if airbase then
airbase:setCoalition(Coal)
end
return self
end
--- Get all airbases of the current map. This includes ships and FARPS. --- Get all airbases of the current map. This includes ships and FARPS.
-- @param DCS#Coalition coalition (Optional) Return only airbases belonging to the specified coalition. By default, all airbases of the map are returned. -- @param DCS#Coalition coalition (Optional) Return only airbases belonging to the specified coalition. By default, all airbases of the map are returned.
-- @param #number category (Optional) Return only airbases of a certain category, e.g. Airbase.Category.FARP -- @param #number category (Optional) Return only airbases of a certain category, e.g. Airbase.Category.FARP

File diff suppressed because it is too large Load Diff

View File

@@ -591,10 +591,10 @@ function POSITIONABLE:GetRandomVec3( Radius )
if Radius then if Radius then
local PositionableRandomVec3 = {} local PositionableRandomVec3 = {}
local angle = math.random() * math.pi * 2; local angle = math.random() * math.pi * 2
PositionableRandomVec3.x = PositionablePointVec3.x + math.cos( angle ) * math.random() * Radius; PositionableRandomVec3.x = PositionablePointVec3.x + math.cos( angle ) * math.random() * Radius
PositionableRandomVec3.y = PositionablePointVec3.y PositionableRandomVec3.y = PositionablePointVec3.y
PositionableRandomVec3.z = PositionablePointVec3.z + math.sin( angle ) * math.random() * Radius; PositionableRandomVec3.z = PositionablePointVec3.z + math.sin( angle ) * math.random() * Radius
self:T3( PositionableRandomVec3 ) self:T3( PositionableRandomVec3 )
return PositionableRandomVec3 return PositionableRandomVec3
@@ -1769,6 +1769,93 @@ do -- Cargo
return self.__.CargoBayWeightLimit - CargoWeight return self.__.CargoBayWeightLimit - CargoWeight
end end
---
-- @field DefaultInfantryWeight
-- Abstract out the "XYZ*95" calculation in the Ground POSITIONABLE case, where the table
-- holds number of infantry that the vehicle could carry, instead of actual cargo weights.
POSITIONABLE.DefaultInfantryWeight = 95
---
-- @field CargoBayCapacityValues
-- @field CargoBayCapacityValues.Air
-- @field CargoBayCapacityValues.Naval
-- @field CargoBayCapacityValues.Ground
POSITIONABLE.CargoBayCapacityValues = {
["Air"] = {
-- C-17A
-- Wiki says: max=265,352, empty=128,140, payload=77,516 (134 troops, 1 M1 Abrams tank, 2 M2 Bradley or 3 Stryker)
-- DCS says: max=265,350, empty=125,645, fuel=132,405 ==> Cargo Bay=7300 kg with a full fuel load (lot of fuel!) and 73300 with half a fuel load.
--["C-17A"] = 35000, --77519 cannot be used, because it loads way too much apcs and infantry.
-- C-130:
-- DCS says: max=79,380, empty=36,400, fuel=10,415 kg ==> Cargo Bay=32,565 kg with fuel load.
-- Wiki says: max=70,307, empty=34,382, payload=19,000 kg (92 passengers, 2-3 Humvees or 2 M113s), max takeoff weight 70,037 kg.
-- Here we say two M113s should be transported. Each one weights 11,253 kg according to DCS. So the cargo weight should be 23,000 kg with a full load of fuel.
-- This results in a max takeoff weight of 69,815 kg (23,000+10,415+36,400), which is very close to the Wiki value of 70,037 kg.
["C_130"] = 70000,
},
["Naval"] = {
["Type_071"] = 245000,
["LHA_Tarawa"] = 500000,
["Ropucha_class"] = 150000,
["Dry_cargo_ship_1"] = 70000,
["Dry_cargo_ship_2"] = 70000,
["Higgins_boat"] = 3700, -- Higgins Boat can load 3700 kg of general cargo or 36 men (source wikipedia).
["USS_Samuel_Chase"] = 25000, -- Let's say 25 tons for now. Wiki says 33 Higgins boats, which would be 264 tons (can't be right!) and/or 578 troops.
["LST_Mk2"] = 2100000, -- Can carry 2100 tons according to wiki source!
["speedboat"] = 500, -- 500 kg ~ 5 persons
["Seawise_Giant"] =261000000, -- Gross tonnage is 261,000 tonns.
},
["Ground"] = {
["AAV7"] = 25*POSITIONABLE.DefaultInfantryWeight,
["Bedford_MWD"] = 8*POSITIONABLE.DefaultInfantryWeight, -- new by kappa
["Blitz_36_6700A"] = 10*POSITIONABLE.DefaultInfantryWeight, -- new by kappa
["BMD_1"] = 9*POSITIONABLE.DefaultInfantryWeight, -- IRL should be 4 passengers
["BMP_1"] = 8*POSITIONABLE.DefaultInfantryWeight,
["BMP_2"] = 7*POSITIONABLE.DefaultInfantryWeight,
["BMP_3"] = 8*POSITIONABLE.DefaultInfantryWeight, -- IRL should be 7+2 passengers
["Boman"] = 25*POSITIONABLE.DefaultInfantryWeight,
["BTR_80"] = 9*POSITIONABLE.DefaultInfantryWeight, -- IRL should be 7 passengers
["BTR_82A"] = 9*POSITIONABLE.DefaultInfantryWeight, -- new by kappa -- IRL should be 7 passengers
["BTR_D"] = 12*POSITIONABLE.DefaultInfantryWeight, -- IRL should be 10 passengers
["Cobra"] = 8*POSITIONABLE.DefaultInfantryWeight,
["Land_Rover_101_FC"] = 11*POSITIONABLE.DefaultInfantryWeight, -- new by kappa
["Land_Rover_109_S3"] = 7*POSITIONABLE.DefaultInfantryWeight, -- new by kappa
["LAV_25"] = 6*POSITIONABLE.DefaultInfantryWeight,
["M_2_Bradley"] = 6*POSITIONABLE.DefaultInfantryWeight,
["M1043_HMMWV_Armament"] = 4*POSITIONABLE.DefaultInfantryWeight,
["M1045_HMMWV_TOW"] = 4*POSITIONABLE.DefaultInfantryWeight,
["M1126_Stryker_ICV"] = 9*POSITIONABLE.DefaultInfantryWeight,
["M1134_Stryker_ATGM"] = 9*POSITIONABLE.DefaultInfantryWeight,
["M2A1_halftrack"] = 9*POSITIONABLE.DefaultInfantryWeight,
["M_113"] = 9*POSITIONABLE.DefaultInfantryWeight, -- IRL should be 11 passengers
["Marder"] = 6*POSITIONABLE.DefaultInfantryWeight,
["MCV_80"] = 9*POSITIONABLE.DefaultInfantryWeight, -- IRL should be 7 passengers
["MLRS_FDDM"] = 4*POSITIONABLE.DefaultInfantryWeight,
["MTLB"] = 25*POSITIONABLE.DefaultInfantryWeight, -- IRL should be 11 passengers
["GAZ_66"] = 8*POSITIONABLE.DefaultInfantryWeight,
["GAZ_3307"] = 12*POSITIONABLE.DefaultInfantryWeight,
["GAZ_3308"] = 14*POSITIONABLE.DefaultInfantryWeight,
["Grad_FDDM"] = 6*POSITIONABLE.DefaultInfantryWeight, -- new by kappa
["KAMAZ_Truck"] = 12*POSITIONABLE.DefaultInfantryWeight,
["KrAZ6322"] = 12*POSITIONABLE.DefaultInfantryWeight,
["M_818"] = 12*POSITIONABLE.DefaultInfantryWeight,
["Tigr_233036"] = 6*POSITIONABLE.DefaultInfantryWeight,
["TPZ"] = 10*POSITIONABLE.DefaultInfantryWeight, -- Fuchs
["UAZ_469"] = 4*POSITIONABLE.DefaultInfantryWeight, -- new by kappa
["Ural_375"] = 12*POSITIONABLE.DefaultInfantryWeight,
["Ural_4320_31"] = 14*POSITIONABLE.DefaultInfantryWeight,
["Ural_4320_APA_5D"] = 10*POSITIONABLE.DefaultInfantryWeight,
["Ural_4320T"] = 14*POSITIONABLE.DefaultInfantryWeight,
["ZBD04A"] = 7*POSITIONABLE.DefaultInfantryWeight, -- new by kappa
["VAB_Mephisto"] = 8*POSITIONABLE.DefaultInfantryWeight, -- new by Apple
["tt_KORD"] = 6*POSITIONABLE.DefaultInfantryWeight, -- 2.7.1 HL/TT
["tt_DSHK"] = 6*POSITIONABLE.DefaultInfantryWeight,
["HL_KORD"] = 6*POSITIONABLE.DefaultInfantryWeight,
["HL_DSHK"] = 6*POSITIONABLE.DefaultInfantryWeight,
["CCKW_353"] = 16*POSITIONABLE.DefaultInfantryWeight, --GMC CCKW 2½-ton 6×6 truck, estimating 16 soldiers,
}
}
--- Set Cargo Bay Weight Limit in kg. --- Set Cargo Bay Weight Limit in kg.
-- @param #POSITIONABLE self -- @param #POSITIONABLE self
-- @param #number WeightLimit (Optional) Weight limit in kg. If not given, the value is taken from the descriptors or hard coded. -- @param #number WeightLimit (Optional) Weight limit in kg. If not given, the value is taken from the descriptors or hard coded.
@@ -1792,23 +1879,13 @@ do -- Cargo
-- Unit type name. -- Unit type name.
local TypeName=Desc.typeName or "Unknown Type" local TypeName=Desc.typeName or "Unknown Type"
TypeName = string.gsub(TypeName,"[%p%s]","_")
-- When an airplane or helicopter, we calculate the WeightLimit based on the descriptor. -- When an airplane or helicopter, we calculate the WeightLimit based on the descriptor.
if self:IsAir() then if self:IsAir() then
-- Max takeoff weight if DCS descriptors have unrealstic values. -- Max takeoff weight if DCS descriptors have unrealstic values.
local Weights = { local Weights = POSITIONABLE.CargoBayCapacityValues.Air
-- C-17A
-- Wiki says: max=265,352, empty=128,140, payload=77,516 (134 troops, 1 M1 Abrams tank, 2 M2 Bradley or 3 Stryker)
-- DCS says: max=265,350, empty=125,645, fuel=132,405 ==> Cargo Bay=7300 kg with a full fuel load (lot of fuel!) and 73300 with half a fuel load.
--["C-17A"] = 35000, --77519 cannot be used, because it loads way too much apcs and infantry.
-- C-130:
-- DCS says: max=79,380, empty=36,400, fuel=10,415 kg ==> Cargo Bay=32,565 kg with fuel load.
-- Wiki says: max=70,307, empty=34,382, payload=19,000 kg (92 passengers, 2-3 Humvees or 2 M113s), max takeoff weight 70,037 kg.
-- Here we say two M113s should be transported. Each one weights 11,253 kg according to DCS. So the cargo weight should be 23,000 kg with a full load of fuel.
-- This results in a max takeoff weight of 69,815 kg (23,000+10,415+36,400), which is very close to the Wiki value of 70,037 kg.
["C-130"] = 70000,
}
-- Max (takeoff) weight (empty+fuel+cargo weight). -- Max (takeoff) weight (empty+fuel+cargo weight).
local massMax= Desc.massMax or 0 local massMax= Desc.massMax or 0
@@ -1843,75 +1920,16 @@ do -- Cargo
elseif self:IsShip() then elseif self:IsShip() then
-- Hard coded cargo weights in kg. -- Hard coded cargo weights in kg.
local Weights = { local Weights = POSITIONABLE.CargoBayCapacityValues.Naval
["Type_071"] = 245000,
["LHA_Tarawa"] = 500000,
["Ropucha-class"] = 150000,
["Dry-cargo ship-1"] = 70000,
["Dry-cargo ship-2"] = 70000,
["Higgins_boat"] = 3700, -- Higgins Boat can load 3700 kg of general cargo or 36 men (source wikipedia).
["USS_Samuel_Chase"] = 25000, -- Let's say 25 tons for now. Wiki says 33 Higgins boats, which would be 264 tons (can't be right!) and/or 578 troops.
["LST_Mk2"] = 2100000, -- Can carry 2100 tons according to wiki source!
["speedboat"] = 500, -- 500 kg ~ 5 persons
["Seawise_Giant"] =261000000, -- Gross tonnage is 261,000 tonns.
}
self.__.CargoBayWeightLimit = ( Weights[TypeName] or 50000 ) self.__.CargoBayWeightLimit = ( Weights[TypeName] or 50000 )
else else
-- Hard coded number of soldiers. -- Hard coded number of soldiers.
local Weights = { local Weights = POSITIONABLE.CargoBayCapacityValues.Ground
["AAV7"] = 25,
["Bedford_MWD"] = 8, -- new by kappa
["Blitz_36-6700A"] = 10, -- new by kappa
["BMD-1"] = 9, -- IRL should be 4 passengers
["BMP-1"] = 8,
["BMP-2"] = 7,
["BMP-3"] = 8, -- IRL should be 7+2 passengers
["Boman"] = 25,
["BTR-80"] = 9, -- IRL should be 7 passengers
["BTR-82A"] = 9, -- new by kappa -- IRL should be 7 passengers
["BTR_D"] = 12, -- IRL should be 10 passengers
["Cobra"] = 8,
["Land_Rover_101_FC"] = 11, -- new by kappa
["Land_Rover_109_S3"] = 7, -- new by kappa
["LAV-25"] = 6,
["M-2 Bradley"] = 6,
["M1043 HMMWV Armament"] = 4,
["M1045 HMMWV TOW"] = 4,
["M1126 Stryker ICV"] = 9,
["M1134 Stryker ATGM"] = 9,
["M2A1_halftrack"] = 9,
["M-113"] = 9, -- IRL should be 11 passengers
["Marder"] = 6,
["MCV-80"] = 9, -- IRL should be 7 passengers
["MLRS FDDM"] = 4,
["MTLB"] = 25, -- IRL should be 11 passengers
["GAZ-66"] = 8,
["GAZ-3307"] = 12,
["GAZ-3308"] = 14,
["Grad_FDDM"] = 6, -- new by kappa
["KAMAZ Truck"] = 12,
["KrAZ6322"] = 12,
["M 818"] = 12,
["Tigr_233036"] = 6,
["TPZ"] = 10, -- Fuchs
["UAZ-469"] = 4, -- new by kappa
["Ural-375"] = 12,
["Ural-4320-31"] = 14,
["Ural-4320 APA-5D"] = 10,
["Ural-4320T"] = 14,
["ZBD04A"] = 7, -- new by kappa
["VAB_Mephisto"] = 8, -- new by Apple
["tt_KORD"] = 6, -- 2.7.1 HL/TT
["tt_DSHK"] = 6,
["HL_KORD"] = 6,
["HL_DSHK"] = 6,
["CCKW_353"] = 16, --GMC CCKW 2½-ton 6×6 truck, estimating 16 soldiers
}
-- Assuming that each passenger weighs 95 kg on average. -- Assuming that each passenger weighs 95 kg on average.
local CargoBayWeightLimit = ( Weights[TypeName] or 0 ) * 95 local CargoBayWeightLimit = ( Weights[TypeName] or 0 )
self.__.CargoBayWeightLimit = CargoBayWeightLimit self.__.CargoBayWeightLimit = CargoBayWeightLimit
end end

View File

@@ -0,0 +1,534 @@
--- **Wrapper** - Warehouse storage of DCS airbases.
--
-- ## Main Features:
--
-- * Convenient access to DCS API functions
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Wrapper%20-%20Storage).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Wrapper.Storage
-- @image Wrapper_Storage.png
--- STORAGE class.
-- @type STORAGE
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity level.
-- @field #string lid Class id string for output to DCS log file.
-- @field DCS#Warehouse warehouse The DCS warehouse object.
-- @field DCS#Airbase airbase The DCS airbase object.
-- @extends Core.Base#BASE
--- *The capitalist cannot store labour-power in warehouses after he has bought it, as he may do with the raw material.* -- Karl Marx
--
-- ===
--
-- # The STORAGE Concept
--
-- The STORAGE class offers an easy-to-use wrapper interface to all DCS API functions of DCS warehouses.
-- We named the class STORAGE, because the name WAREHOUSE is already taken by another MOOSE class.
--
-- This class allows you to add and remove items to a DCS warehouse, such as aircraft, liquids, weapons and other equipment.
--
-- # Constructor
--
-- A DCS warehouse is associated with an airbase. Therefore, a `STORAGE` instance is automatically created, once an airbase is registered and added to the MOOSE database.
--
-- You can get the `STORAGE` object from the
--
-- -- Create a STORAGE instance of the Batumi warehouse
-- local storage=STORAGE:FindByName("Batumi")
--
-- An other way to get the `STORAGE` object is to retrieve it from the AIRBASE function `AIRBASE:GetStorage()`
--
-- -- Get storage instance of Batumi airbase
-- local Batumi=AIRBASE:FindByName("Batumi")
-- local storage=Batumi:GetStorage()
--
-- # Aircraft, Weapons and Equipment
--
-- ## Adding Items
--
-- To add aircraft, weapons and/or othe equipment, you can use the @{#STORAGE.AddItem}() function
--
-- storage:AddItem("A-10C", 3)
-- storage:AddItem("weapons.missiles.AIM_120C", 10)
--
-- This will add three A-10Cs and ten AIM-120C missiles to the warehouse inventory.
--
-- ## Setting Items
--
-- You can also explicitly set, how many items are in the inventory with the @{#STORAGE.SetItem}() function.
--
-- ## Removing Items
--
-- Items can be removed from the inventory with the @{#STORAGE.RemoveItem}() function.
--
-- ## Getting Amount
--
-- The number of items currently in the inventory can be obtained with the @{#STORAGE.GetItemAmount}() function
--
-- local N=storage:GetItemAmount("A-10C")
-- env.info(string.format("We currently have %d A-10Cs available", N))
--
-- # Liquids
--
-- Liquids can be added and removed by slightly different functions as described below. Currently there are four types of liquids
--
-- * Jet fuel `STORAGE.Liquid.JETFUEL`
-- * Aircraft gasoline `STORAGE.Liquid.GASOLINE`
-- * MW 50 `STORAGE.Liquid.MW50`
-- * Diesel `STORAGE.Liquid.DIESEL`
--
-- ## Adding Liquids
--
-- To add a certain type of liquid, you can use the @{#STORAGE.AddItem}(Type, Amount) function
--
-- storage:AddLiquid(STORAGE.Liquid.JETFUEL, 10000)
-- storage:AddLiquid(STORAGE.Liquid.DIESEL, 20000)
--
-- This will add 10,000 kg of jet fuel and 20,000 kg of diesel to the inventory.
--
-- ## Setting Liquids
--
-- You can also explicitly set the amount of liquid with the @{#STORAGE.SetLiquid}(Type, Amount) function.
--
-- ## Removing Liquids
--
-- Liquids can be removed with @{#STORAGE.RemoveLiquid}(Type, Amount) function.
--
-- ## Getting Amount
--
-- The current amount of a certain liquid can be obtained with the @{#STORAGE.GetLiquidAmount}(Type) function
--
-- local N=storage:GetLiquidAmount(STORAGE.Liquid.DIESEL)
-- env.info(string.format("We currently have %d kg of Diesel available", N))
--
--
-- # Inventory
--
-- The current inventory of the warehouse can be obtained with the @{#STORAGE.GetInventory}() function. This returns three tables with the aircraft, liquids and weapons:
--
-- local aircraft, liquids, weapons=storage:GetInventory()
--
-- UTILS.PrintTableToLog(aircraft)
-- UTILS.PrintTableToLog(liquids)
-- UTILS.PrintTableToLog(weapons)
--
-- @field #STORAGE
STORAGE = {
ClassName = "STORAGE",
verbose = 0,
}
--- Liquid types.
-- @type STORAGE.Liquid
-- @field #number JETFUEL Jet fuel (0).
-- @field #number GASOLINE Aviation gasoline (1).
-- @field #number MW50 MW50 (2).
-- @field #number DIESEL Diesel (3).
STORAGE.Liquid = {
JETFUEL = 0,
GASOLINE = 1,
MW50 = 2,
DIESEL = 3,
}
--- STORAGE class version.
-- @field #string version
STORAGE.version="0.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot...
-- TODO: Persistence
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new STORAGE object from the DCS weapon object.
-- @param #STORAGE self
-- @param #string AirbaseName Name of the airbase.
-- @return #STORAGE self
function STORAGE:New(AirbaseName)
-- Inherit everything from BASE class.
local self=BASE:Inherit(self, BASE:New()) -- #STORAGE
self.airbase=Airbase.getByName(AirbaseName)
self.warehouse=self.airbase:getWarehouse()
self.lid = string.format("STORAGE %s", AirbaseName)
return self
end
--- Find a STORAGE in the **_DATABASE** using the name associated airbase.
-- @param #STORAGE self
-- @param #string AirbaseName The Airbase Name.
-- @return #STORAGE self
function STORAGE:FindByName( AirbaseName )
local storage = _DATABASE:FindStorage( AirbaseName )
return storage
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User API Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Set verbosity level.
-- @param #STORAGE self
-- @param #number VerbosityLevel Level of output (higher=more). Default 0.
-- @return #STORAGE self
function STORAGE:SetVerbosity(VerbosityLevel)
self.verbose=VerbosityLevel or 0
return self
end
--- Adds the passed amount of a given item to the warehouse.
-- @param #STORAGE self
-- @param #string Name Name of the item to add.
-- @param #number Amount Amount of items to add.
-- @return #STORAGE self
function STORAGE:AddItem(Name, Amount)
self:T(self.lid..string.format("Adding %d items of %s", Amount, UTILS.OneLineSerialize(Name)))
self.warehouse:addItem(Name, Amount)
return self
end
--- Sets the specified amount of a given item to the warehouse.
-- @param #STORAGE self
-- @param #string Name Name of the item.
-- @param #number Amount Amount of items.
-- @return #STORAGE self
function STORAGE:SetItem(Name, Amount)
self:T(self.lid..string.format("Setting item %s to N=%d", UTILS.OneLineSerialize(Name), Amount))
self.warehouse:setItem(Name, Amount)
return self
end
--- Gets the amount of a given item currently present the warehouse.
-- @param #STORAGE self
-- @param #string Name Name of the item.
-- @return #number Amount of items.
function STORAGE:GetItemAmount(Name)
local N=self.warehouse:getItemCount(Name)
return N
end
--- Removes the amount of the passed item from the warehouse.
-- @param #STORAGE self
-- @param #string Name Name of the item.
-- @param #number Amount Amount of items.
-- @return #STORAGE self
function STORAGE:RemoveItem(Name, Amount)
self:T(self.lid..string.format("Removing N=%d of item %s", Amount, Name))
self.warehouse:removeItem(Name, Amount)
return self
end
--- Adds the passed amount of a given liquid to the warehouse.
-- @param #STORAGE self
-- @param #number Type Type of liquid.
-- @param #number Amount Amount of liquid to add.
-- @return #STORAGE self
function STORAGE:AddLiquid(Type, Amount)
self:T(self.lid..string.format("Adding %d liquids of %s", Amount, self:GetLiquidName(Type)))
self.warehouse:addLiquid(Type, Amount)
return self
end
--- Sets the specified amount of a given liquid to the warehouse.
-- @param #STORAGE self
-- @param #number Type Type of liquid.
-- @param #number Amount Amount of liquid.
-- @return #STORAGE self
function STORAGE:SetLiquid(Type, Amount)
self:T(self.lid..string.format("Setting liquid %s to N=%d", self:GetLiquidName(Type), Amount))
self.warehouse:setLiquid(Type, Amount)
return self
end
--- Removes the amount of the given liquid type from the warehouse.
-- @param #STORAGE self
-- @param #number Type Type of liquid.
-- @param #number Amount Amount of liquid in kg to be removed.
-- @return #STORAGE self
function STORAGE:RemoveLiquid(Type, Amount)
self:T(self.lid..string.format("Removing N=%d of liquid %s", Amount, self:GetLiquidName(Type)))
self.warehouse:removeLiquid(Type, Amount)
return self
end
--- Gets the amount of a given liquid currently present the warehouse.
-- @param #STORAGE self
-- @param #number Type Type of liquid.
-- @return #number Amount of liquid in kg.
function STORAGE:GetLiquidAmount(Type)
local N=self.warehouse:getLiquidAmount(Type)
return N
end
--- Returns the name of the liquid from its numeric type.
-- @param #STORAGE self
-- @param #number Type Type of liquid.
-- @return #string Name of the liquid.
function STORAGE:GetLiquidName(Type)
local name="Unknown"
if Type==STORAGE.Liquid.JETFUEL then
name = "Jet fuel"
elseif Type==STORAGE.Liquid.GASOLINE then
name = "Aircraft gasoline"
elseif Type==STORAGE.Liquid.MW50 then
name = "MW 50"
elseif Type==STORAGE.Liquid.DIESEL then
name = "Diesel"
else
self:E(self.lid..string.format("ERROR: Unknown liquid type %s", tostring(Type)))
end
return name
end
--- Adds the amount of a given type of aircraft, liquid, weapon currently present the warehouse.
-- @param #STORAGE self
-- @param #number Type Type of liquid or name of aircraft, weapon or equipment.
-- @param #number Amount Amount of given type to add. Liquids in kg.
-- @return #STORAGE self
function STORAGE:AddAmount(Type, Amount)
if type(Type)=="number" then
self:AddLiquid(Type, Amount)
else
self:AddItem(Type, Amount)
end
return self
end
--- Removes the amount of a given type of aircraft, liquid, weapon from the warehouse.
-- @param #STORAGE self
-- @param #number Type Type of liquid or name of aircraft, weapon or equipment.
-- @param #number Amount Amount of given type to remove. Liquids in kg.
-- @return #STORAGE self
function STORAGE:RemoveAmount(Type, Amount)
if type(Type)=="number" then
self:RemoveLiquid(Type, Amount)
else
self:RemoveItem(Type, Amount)
end
return self
end
--- Sets the amount of a given type of aircraft, liquid, weapon currently present the warehouse.
-- @param #STORAGE self
-- @param #number Type Type of liquid or name of aircraft, weapon or equipment.
-- @param #number Amount of given type. Liquids in kg.
-- @return #STORAGE self
function STORAGE:SetAmount(Type, Amount)
if type(Type)=="number" then
self:SetLiquid(Type, Amount)
else
self:SetItem(Type, Amount)
end
return self
end
--- Gets the amount of a given type of aircraft, liquid, weapon currently present the warehouse.
-- @param #STORAGE self
-- @param #number Type Type of liquid or name of aircraft, weapon or equipment.
-- @return #number Amount of given type. Liquids in kg.
function STORAGE:GetAmount(Type)
local N=0
if type(Type)=="number" then
N=self:GetLiquidAmount(Type)
else
N=self:GetItemAmount(Type)
end
return N
end
--- Returns whether a given type of aircraft, liquid, weapon is set to be unlimited.
-- @param #STORAGE self
-- @param #string Type Name of aircraft, weapon or equipment or type of liquid (as `#number`).
-- @return #boolen If `true` the given type is unlimited or `false` otherwise.
function STORAGE:IsUnlimited(Type)
-- Get current amount of type.
local N=self:GetAmount(Type)
local unlimited=false
if N>0 then
-- Remove one item.
self:RemoveAmount(Type, 1)
-- Get amount.
local n=self:GetAmount(Type)
-- If amount did not change, it is unlimited.
unlimited=n==N
-- Add item back.
if not unlimited then
self:AddAmount(Type, 1)
end
-- Debug info.
self:I(self.lid..string.format("Type=%s: unlimited=%s (N=%d n=%d)", tostring(Type), tostring(unlimited), N, n))
end
return unlimited
end
--- Returns whether a given type of aircraft, liquid, weapon is set to be limited.
-- @param #STORAGE self
-- @param #number Type Type of liquid or name of aircraft, weapon or equipment.
-- @return #boolen If `true` the given type is limited or `false` otherwise.
function STORAGE:IsLimited(Type)
local limited=not self:IsUnlimited(Type)
return limited
end
--- Returns whether aircraft are unlimited.
-- @param #STORAGE self
-- @return #boolen If `true` aircraft are unlimited or `false` otherwise.
function STORAGE:IsUnlimitedAircraft()
-- We test with a specific type but if it is unlimited, than all aircraft are.
local unlimited=self:IsUnlimited("A-10C")
return unlimited
end
--- Returns whether liquids are unlimited.
-- @param #STORAGE self
-- @return #boolen If `true` liquids are unlimited or `false` otherwise.
function STORAGE:IsUnlimitedLiquids()
-- We test with a specific type but if it is unlimited, than all are.
local unlimited=self:IsUnlimited(STORAGE.Liquid.DIESEL)
return unlimited
end
--- Returns whether weapons and equipment are unlimited.
-- @param #STORAGE self
-- @return #boolen If `true` weapons and equipment are unlimited or `false` otherwise.
function STORAGE:IsUnlimitedWeapons()
-- We test with a specific type but if it is unlimited, than all are.
local unlimited=self:IsUnlimited(ENUMS.Storage.weapons.bombs.Mk_82)
return unlimited
end
--- Returns whether aircraft are limited.
-- @param #STORAGE self
-- @return #boolen If `true` aircraft are limited or `false` otherwise.
function STORAGE:IsLimitedAircraft()
-- We test with a specific type but if it is limited, than all are.
local limited=self:IsLimited("A-10C")
return limited
end
--- Returns whether liquids are limited.
-- @param #STORAGE self
-- @return #boolen If `true` liquids are limited or `false` otherwise.
function STORAGE:IsLimitedLiquids()
-- We test with a specific type but if it is limited, than all are.
local limited=self:IsLimited(STORAGE.Liquid.DIESEL)
return limited
end
--- Returns whether weapons and equipment are limited.
-- @param #STORAGE self
-- @return #boolen If `true` liquids are limited or `false` otherwise.
function STORAGE:IsLimitedWeapons()
-- We test with a specific type but if it is limited, than all are.
local limited=self:IsLimited(ENUMS.Storage.weapons.bombs.Mk_82)
return limited
end
--- Returns a full itemized list of everything currently in a warehouse. If a category is set to unlimited then the table will be returned empty.
-- @param #STORAGE self
-- @param #string Item Name of item as #string or type of liquid as #number.
-- @return #table Table of aircraft. Table is emtpy `{}` if number of aircraft is set to be unlimited.
-- @return #table Table of liquids. Table is emtpy `{}` if number of liquids is set to be unlimited.
-- @return #table Table of weapons and other equipment. Table is emtpy `{}` if number of liquids is set to be unlimited.
function STORAGE:GetInventory(Item)
local inventory=self.warehouse:getInventory(Item)
return inventory.aircraft, inventory.liquids, inventory.weapon
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Private Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@@ -47,6 +47,7 @@ Wrapper/Scenery.lua
Wrapper/Marker.lua Wrapper/Marker.lua
Wrapper/Weapon.lua Wrapper/Weapon.lua
Wrapper/Net.lua Wrapper/Net.lua
Wrapper/Storage.lua
Cargo/Cargo.lua Cargo/Cargo.lua
Cargo/CargoUnit.lua Cargo/CargoUnit.lua