Compare commits

..

21 Commits

Author SHA1 Message Date
Applevangelist cf824b912d #Controllable
* Added Aerobtics tasks
2023-08-22 10:24:40 +02:00
Thomas 8d2e291deb Update Enums.lua
Error in ENUM
2023-08-21 11:35:01 +02:00
Applevangelist 3a432782b2 Storages Enum 2023-08-20 15:22:49 +02:00
Applevangelist bda1fac923 #ENUMS
* Added enumerator for ENUMS.Storage.weapons
2023-08-20 15:12:47 +02:00
Thomas ef40b1c524 Range fix for #1984 (#1992)
Range fix for #1984
2023-08-20 13:41:20 +02:00
Applevangelist 045c49679d #ATIS
* Fix explicitly set RWY not reported via SRS
2023-08-20 11:18:58 +02:00
Applevangelist f40442d309 #POSITIONABLE
* Make cargo weights an enumerator
2023-08-18 11:07:43 +02:00
Frank fe7acecdd3 Merge pull request #1991 from FlightControl-Master/FF/MasterDevel
STORAGE - DCS Warehouse
2023-08-17 19:11:01 +02:00
Frank 4471ec9b96 DCS Warehouse 2023-08-17 18:46:09 +02:00
Frank 32e1d4f8fa DCS Warehouse 2023-08-16 23:58:32 +02:00
Frank 747e5d801a Merge pull request #1986 from FlightControl-Master/FF/MasterDevel
COORDINATE
2023-08-13 18:19:16 +02:00
Frank 29ed630536 COORDINATE
- Generalized MarkupToAllFreeForm

UTILS
- Added some functions from MIST
2023-08-13 17:40:28 +02:00
Applevangelist c5757ffd22 #CONTROLLABLE
* Added EnRouteTaskCAP()
2023-08-02 18:02:34 +02:00
Applevangelist 9cc08cb088 # 2023-08-01 16:26:29 +02:00
Applevangelist 2771e7f856 #SCENERY, SET_SCENERY
* Reworked COORDINATE scan as this doesn't seem to work
* Added SET_SCENERY Filters, and FilterOnce() to apply them
2023-08-01 16:18:23 +02:00
Thomas 7c4dd8160d Update Set.lua (#1982)
Intellisense updates
2023-08-01 11:53:00 +02:00
Thomas 1fdc50b0da Update Scenery.lua (#1980)
_id might be nil in :FindByZoneName()
2023-08-01 10:00:42 +02:00
Thomas f87a676e4b Update Scoring.lua (#1976)
Add report Spaces
2023-07-29 16:45:00 +02:00
Frank 8bf56b8b1a Update Airboss.lua
- Fixed AI handling (got lost in some merge with develop branch and was using FLIGHTGROUPS)
2023-07-26 16:36:44 +02:00
Applevangelist f31741f934 #AI_ESCORT
* Improve documentation
2023-07-25 12:01:18 +02:00
Applevangelist 46258492bd #AIRBASE, #ATIS
* Additions
2023-07-23 12:37:57 +02:00
63 changed files with 3337 additions and 76478 deletions
-7
View File
@@ -28,13 +28,6 @@ local.properties
.buildpath .buildpath
#####################
## Visual Studio Code
#####################
*.code-workspace
.vscode/
################# #################
## Visual Studio ## Visual Studio
################# #################
+67 -55
View File
@@ -147,8 +147,8 @@
-- @image Escorting.JPG -- @image Escorting.JPG
---
--- @type AI_ESCORT -- @type AI_ESCORT
-- @extends AI.AI_Formation#AI_FORMATION -- @extends AI.AI_Formation#AI_FORMATION
@@ -168,10 +168,13 @@
-- --
-- -- First find the GROUP object and the CLIENT object. -- -- First find the GROUP object and the CLIENT object.
-- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. -- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. -- local EscortGroup = SET_GROUP:New():FilterPrefixes("Escort"):FilterOnce() -- The the group name of the escorts contains "Escort".
-- --
-- -- Now use these 2 objects to construct the new EscortPlanes object. -- -- Now use these 2 objects to construct the new EscortPlanes object.
-- EscortPlanes = AI_ESCORT:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) -- EscortPlanes = AI_ESCORT:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
-- EscortPlanes:MenusAirplanes() -- create menus for airplanes
-- EscortPlanes:__Start(2)
--
-- --
-- @field #AI_ESCORT -- @field #AI_ESCORT
AI_ESCORT = { AI_ESCORT = {
@@ -189,7 +192,7 @@ AI_ESCORT = {
TaskPoints = {} TaskPoints = {}
} }
--- @field Functional.Detection#DETECTION_AREAS -- @field Functional.Detection#DETECTION_AREAS
AI_ESCORT.Detection = nil AI_ESCORT.Detection = nil
--- MENUPARAM type --- MENUPARAM type
@@ -211,10 +214,14 @@ AI_ESCORT.Detection = nil
-- --
-- -- First find the GROUP object and the CLIENT object. -- -- First find the GROUP object and the CLIENT object.
-- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor. -- local EscortUnit = CLIENT:FindByName( "Unit Name" ) -- The Unit Name is the name of the unit flagged with the skill Client in the mission editor.
-- local EscortGroup = GROUP:FindByName( "Group Name" ) -- The Group Name is the name of the group that will escort the Escort Client. -- local EscortGroup = SET_GROUP:New():FilterPrefixes("Escort"):FilterOnce() -- The the group name of the escorts contains "Escort".
-- --
-- -- Now use these 2 objects to construct the new EscortPlanes object. -- -- Now use these 2 objects to construct the new EscortPlanes object.
-- EscortPlanes = AI_ESCORT:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." ) -- EscortPlanes = AI_ESCORT:New( EscortUnit, EscortGroup, "Desert", "Welcome to the mission. You are escorted by a plane with code name 'Desert', which can be instructed through the F10 radio menu." )
-- EscortPlanes:MenusAirplanes() -- create menus for airplanes
-- EscortPlanes:__Start(2)
--
--
function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
local self = BASE:Inherit( self, AI_FORMATION:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) ) -- #AI_ESCORT local self = BASE:Inherit( self, AI_FORMATION:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing ) ) -- #AI_ESCORT
@@ -231,6 +238,13 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
self.EscortBriefing = EscortBriefing self.EscortBriefing = EscortBriefing
self.Menu = {} self.Menu = {}
self.Menu.HoldAtEscortPosition = self.Menu.HoldAtEscortPosition or {}
self.Menu.HoldAtLeaderPosition = self.Menu.HoldAtLeaderPosition or {}
self.Menu.Flare = self.Menu.Flare or {}
self.Menu.Smoke = self.Menu.Smoke or {}
self.Menu.Targets = self.Menu.Targets or {}
self.Menu.ROE = self.Menu.ROE or {}
self.Menu.ROT = self.Menu.ROT or {}
-- if not EscortBriefing then -- if not EscortBriefing then
-- EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " .. -- EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " ..
@@ -250,7 +264,7 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
EscortGroupSet:ForEachGroup( EscortGroupSet:ForEachGroup(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
-- Set EscortGroup known at EscortUnit. -- Set EscortGroup known at EscortUnit.
if not self.PlayerUnit._EscortGroups then if not self.PlayerUnit._EscortGroups then
@@ -325,14 +339,14 @@ function AI_ESCORT:_InitEscortRoute( EscortGroup )
end end
--- @param #AI_ESCORT self -- @param #AI_ESCORT self
-- @param Core.Set#SET_GROUP EscortGroupSet -- @param Core.Set#SET_GROUP EscortGroupSet
function AI_ESCORT:onafterStart( EscortGroupSet ) function AI_ESCORT:onafterStart( EscortGroupSet )
self:F() self:F()
EscortGroupSet:ForEachGroup( EscortGroupSet:ForEachGroup(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
EscortGroup:WayPointInitialize() EscortGroup:WayPointInitialize()
@@ -370,7 +384,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
self:_InitFlightMenus() self:_InitFlightMenus()
self.EscortGroupSet:ForSomeGroupAlive( self.EscortGroupSet:ForSomeGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
self:_InitEscortMenus( EscortGroup ) self:_InitEscortMenus( EscortGroup )
@@ -378,7 +392,7 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
self:SetFlightModeFormation( EscortGroup ) self:SetFlightModeFormation( EscortGroup )
--- @param #AI_ESCORT self -- @param #AI_ESCORT self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function EscortGroup:OnEventDeadOrCrash( EventData ) function EscortGroup:OnEventDeadOrCrash( EventData )
self:F( { "EventDead", EventData } ) self:F( { "EventDead", EventData } )
@@ -394,14 +408,14 @@ function AI_ESCORT:onafterStart( EscortGroupSet )
end end
--- @param #AI_ESCORT self -- @param #AI_ESCORT self
-- @param Core.Set#SET_GROUP EscortGroupSet -- @param Core.Set#SET_GROUP EscortGroupSet
function AI_ESCORT:onafterStop( EscortGroupSet ) function AI_ESCORT:onafterStop( EscortGroupSet )
self:F() self:F()
EscortGroupSet:ForEachGroup( EscortGroupSet:ForEachGroup(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
EscortGroup:WayPointInitialize() EscortGroup:WayPointInitialize()
@@ -550,7 +564,7 @@ function AI_ESCORT:SetFlightMenuFormation( Formation )
local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation, local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation,
function ( self, Formation, ... ) function ( self, Formation, ... )
self.EscortGroupSet:ForSomeGroupAlive( self.EscortGroupSet:ForSomeGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup, self, Formation, Arguments ) function( EscortGroup, self, Formation, Arguments )
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
self:E({FormationID=FormationID}) self:E({FormationID=FormationID})
@@ -764,7 +778,7 @@ end
function AI_ESCORT:SetFlightMenuHoldAtEscortPosition() function AI_ESCORT:SetFlightMenuHoldAtEscortPosition()
for _, MenuHoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do for _, MenuHoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition or {} ) do
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
local FlightMenuHoldPosition = MENU_GROUP_COMMAND local FlightMenuHoldPosition = MENU_GROUP_COMMAND
@@ -785,7 +799,7 @@ end
function AI_ESCORT:SetEscortMenuHoldAtEscortPosition( EscortGroup ) function AI_ESCORT:SetEscortMenuHoldAtEscortPosition( EscortGroup )
for _, HoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do for _, HoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition or {}) do
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName() local EscortGroupName = EscortGroup:GetName()
local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu ) local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortGroup.EscortMenu )
@@ -853,7 +867,7 @@ end
function AI_ESCORT:SetFlightMenuHoldAtLeaderPosition() function AI_ESCORT:SetFlightMenuHoldAtLeaderPosition()
for _, MenuHoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition ) do for _, MenuHoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition or {}) do
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
local FlightMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND local FlightMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND
@@ -874,7 +888,7 @@ end
function AI_ESCORT:SetEscortMenuHoldAtLeaderPosition( EscortGroup ) function AI_ESCORT:SetEscortMenuHoldAtLeaderPosition( EscortGroup )
for _, HoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition ) do for _, HoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition or {}) do
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName() local EscortGroupName = EscortGroup:GetName()
@@ -999,7 +1013,7 @@ end
function AI_ESCORT:SetFlightMenuFlare() function AI_ESCORT:SetFlightMenuFlare()
for _, MenuFlare in pairs( self.Menu.Flare) do for _, MenuFlare in pairs( self.Menu.Flare or {}) do
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
local FlightMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuFlare.MenuText, FlightMenuReportNavigation ) local FlightMenuFlare = MENU_GROUP:New( self.PlayerGroup, MenuFlare.MenuText, FlightMenuReportNavigation )
@@ -1014,7 +1028,7 @@ end
function AI_ESCORT:SetEscortMenuFlare( EscortGroup ) function AI_ESCORT:SetEscortMenuFlare( EscortGroup )
for _, MenuFlare in pairs( self.Menu.Flare) do for _, MenuFlare in pairs( self.Menu.Flare or {}) do
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName() local EscortGroupName = EscortGroup:GetName()
@@ -1059,7 +1073,7 @@ end
function AI_ESCORT:SetFlightMenuSmoke() function AI_ESCORT:SetFlightMenuSmoke()
for _, MenuSmoke in pairs( self.Menu.Smoke) do for _, MenuSmoke in pairs( self.Menu.Smoke or {}) do
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu ) local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
local FlightMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuSmoke.MenuText, FlightMenuReportNavigation ) local FlightMenuSmoke = MENU_GROUP:New( self.PlayerGroup, MenuSmoke.MenuText, FlightMenuReportNavigation )
@@ -1076,7 +1090,7 @@ end
function AI_ESCORT:SetEscortMenuSmoke( EscortGroup ) function AI_ESCORT:SetEscortMenuSmoke( EscortGroup )
for _, MenuSmoke in pairs( self.Menu.Smoke) do for _, MenuSmoke in pairs( self.Menu.Smoke or {}) do
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName() local EscortGroupName = EscortGroup:GetName()
@@ -1169,7 +1183,7 @@ function AI_ESCORT:SetFlightMenuTargets()
local FlightMenuAttackNearbyAir = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Attack nearest airborne targets", self.FlightMenuAttack, AI_ESCORT._FlightAttackNearestTarget, self, self.__Enum.ReportType.Air ):SetTag( "Attack" ) local FlightMenuAttackNearbyAir = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Attack nearest airborne targets", self.FlightMenuAttack, AI_ESCORT._FlightAttackNearestTarget, self, self.__Enum.ReportType.Air ):SetTag( "Attack" )
local FlightMenuAttackNearbyGround = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Attack nearest ground targets", self.FlightMenuAttack, AI_ESCORT._FlightAttackNearestTarget, self, self.__Enum.ReportType.Ground ):SetTag( "Attack" ) local FlightMenuAttackNearbyGround = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Attack nearest ground targets", self.FlightMenuAttack, AI_ESCORT._FlightAttackNearestTarget, self, self.__Enum.ReportType.Ground ):SetTag( "Attack" )
for _, MenuTargets in pairs( self.Menu.Targets) do for _, MenuTargets in pairs( self.Menu.Targets or {}) do
MenuTargets.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, MenuTargets.Interval, MenuTargets.Interval ) MenuTargets.FlightReportTargetsScheduler = SCHEDULER:New( self, self._FlightReportTargetsScheduler, {}, MenuTargets.Interval, MenuTargets.Interval )
end end
@@ -1179,7 +1193,7 @@ end
function AI_ESCORT:SetEscortMenuTargets( EscortGroup ) function AI_ESCORT:SetEscortMenuTargets( EscortGroup )
for _, MenuTargets in pairs( self.Menu.Targets) do for _, MenuTargets in pairs( self.Menu.Targets or {} or {}) do
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName() local EscortGroupName = EscortGroup:GetName()
--local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu ) --local EscortMenuReportTargets = MENU_GROUP:New( self.PlayerGroup, "Report targets", EscortGroup.EscortMenu )
@@ -1231,7 +1245,7 @@ function AI_ESCORT:MenuAssistedAttack()
self:F() self:F()
self.EscortGroupSet:ForSomeGroupAlive( self.EscortGroupSet:ForSomeGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
if not EscortGroup:IsAir() then if not EscortGroup:IsAir() then
-- Request assistance from other escorts. -- Request assistance from other escorts.
@@ -1246,7 +1260,7 @@ end
function AI_ESCORT:SetFlightMenuROE() function AI_ESCORT:SetFlightMenuROE()
for _, MenuROE in pairs( self.Menu.ROE) do for _, MenuROE in pairs( self.Menu.ROE or {}) do
local FlightMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", self.FlightMenu ) local FlightMenuROE = MENU_GROUP:New( self.PlayerGroup, "Rule Of Engagement", self.FlightMenu )
local FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", FlightMenuROE, AI_ESCORT._FlightROEHoldFire, self, "Holding weapons!" ) local FlightMenuROEHoldFire = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Hold fire", FlightMenuROE, AI_ESCORT._FlightROEHoldFire, self, "Holding weapons!" )
@@ -1261,7 +1275,7 @@ end
function AI_ESCORT:SetEscortMenuROE( EscortGroup ) function AI_ESCORT:SetEscortMenuROE( EscortGroup )
for _, MenuROE in pairs( self.Menu.ROE) do for _, MenuROE in pairs( self.Menu.ROE or {}) do
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName() local EscortGroupName = EscortGroup:GetName()
@@ -1302,7 +1316,7 @@ end
function AI_ESCORT:SetFlightMenuROT() function AI_ESCORT:SetFlightMenuROT()
for _, MenuROT in pairs( self.Menu.ROT) do for _, MenuROT in pairs( self.Menu.ROT or {}) do
local FlightMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", self.FlightMenu ) local FlightMenuROT = MENU_GROUP:New( self.PlayerGroup, "Reaction On Threat", self.FlightMenu )
local FlightMenuROTNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", FlightMenuROT, AI_ESCORT._FlightROTNoReaction, self, "Fighting until death!" ) local FlightMenuROTNoReaction = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Fight until death", FlightMenuROT, AI_ESCORT._FlightROTNoReaction, self, "Fighting until death!" )
@@ -1317,7 +1331,7 @@ end
function AI_ESCORT:SetEscortMenuROT( EscortGroup ) function AI_ESCORT:SetEscortMenuROT( EscortGroup )
for _, MenuROT in pairs( self.Menu.ROT) do for _, MenuROT in pairs( self.Menu.ROT or {}) do
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
local EscortGroupName = EscortGroup:GetName() local EscortGroupName = EscortGroup:GetName()
@@ -1375,7 +1389,7 @@ function AI_ESCORT:SetEscortMenuResumeMission( EscortGroup )
end end
--- @param #AI_ESCORT self -- @param #AI_ESCORT self
-- @param Wrapper.Group#GROUP OrbitGroup -- @param Wrapper.Group#GROUP OrbitGroup
-- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
-- @param #number OrbitHeight -- @param #number OrbitHeight
@@ -1419,7 +1433,7 @@ function AI_ESCORT:_HoldPosition( OrbitGroup, EscortGroup, OrbitHeight, OrbitSec
end end
--- @param #AI_ESCORT self -- @param #AI_ESCORT self
-- @param Wrapper.Group#GROUP OrbitGroup -- @param Wrapper.Group#GROUP OrbitGroup
-- @param #number OrbitHeight -- @param #number OrbitHeight
-- @param #number OrbitSeconds -- @param #number OrbitSeconds
@@ -1428,7 +1442,7 @@ function AI_ESCORT:_FlightHoldPosition( OrbitGroup, OrbitHeight, OrbitSeconds )
local EscortUnit = self.PlayerUnit local EscortUnit = self.PlayerUnit
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup, OrbitGroup ) function( EscortGroup, OrbitGroup )
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
if OrbitGroup == nil then if OrbitGroup == nil then
@@ -1456,7 +1470,7 @@ end
function AI_ESCORT:_FlightJoinUp() function AI_ESCORT:_FlightJoinUp()
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
self:_JoinUp( EscortGroup ) self:_JoinUp( EscortGroup )
@@ -1483,7 +1497,7 @@ end
function AI_ESCORT:_FlightFormationTrail( XStart, XSpace, YStart ) function AI_ESCORT:_FlightFormationTrail( XStart, XSpace, YStart )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
self:_EscortFormationTrail( EscortGroup, XStart, XSpace, YStart ) self:_EscortFormationTrail( EscortGroup, XStart, XSpace, YStart )
@@ -1510,7 +1524,7 @@ end
function AI_ESCORT:_FlightFormationStack( XStart, XSpace, YStart, YSpace ) function AI_ESCORT:_FlightFormationStack( XStart, XSpace, YStart, YSpace )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
self:_EscortFormationStack( EscortGroup, XStart, XSpace, YStart, YSpace ) self:_EscortFormationStack( EscortGroup, XStart, XSpace, YStart, YSpace )
@@ -1533,7 +1547,7 @@ end
function AI_ESCORT:_FlightFlare( Color, Message ) function AI_ESCORT:_FlightFlare( Color, Message )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
self:_Flare( EscortGroup, Color, Message ) self:_Flare( EscortGroup, Color, Message )
@@ -1556,7 +1570,7 @@ end
function AI_ESCORT:_FlightSmoke( Color, Message ) function AI_ESCORT:_FlightSmoke( Color, Message )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
self:_Smoke( EscortGroup, Color, Message ) self:_Smoke( EscortGroup, Color, Message )
@@ -1587,7 +1601,7 @@ end
function AI_ESCORT:_FlightSwitchReportNearbyTargets( ReportTargets ) function AI_ESCORT:_FlightSwitchReportNearbyTargets( ReportTargets )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
self:_EscortSwitchReportNearbyTargets( EscortGroup, ReportTargets ) self:_EscortSwitchReportNearbyTargets( EscortGroup, ReportTargets )
@@ -1679,7 +1693,7 @@ function AI_ESCORT:_ScanTargets( ScanDuration )
end end
--- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
-- @param #AI_ESCORT self -- @param #AI_ESCORT self
function AI_ESCORT.___Resume( EscortGroup, self ) function AI_ESCORT.___Resume( EscortGroup, self )
@@ -1701,7 +1715,7 @@ function AI_ESCORT.___Resume( EscortGroup, self )
end end
--- @param #AI_ESCORT self -- @param #AI_ESCORT self
-- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
-- @param #number WayPoint -- @param #number WayPoint
function AI_ESCORT:_ResumeMission( EscortGroup, WayPoint ) function AI_ESCORT:_ResumeMission( EscortGroup, WayPoint )
@@ -1723,7 +1737,7 @@ function AI_ESCORT:_ResumeMission( EscortGroup, WayPoint )
end end
--- @param #AI_ESCORT self -- @param #AI_ESCORT self
-- @param Wrapper.Group#GROUP EscortGroup The escort group that will attack the detected item. -- @param Wrapper.Group#GROUP EscortGroup The escort group that will attack the detected item.
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem ) function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem )
@@ -1743,7 +1757,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem )
local AttackUnitTasks = {} local AttackUnitTasks = {}
DetectedSet:ForEachUnit( DetectedSet:ForEachUnit(
--- @param Wrapper.Unit#UNIT DetectedUnit -- @param Wrapper.Unit#UNIT DetectedUnit
function( DetectedUnit, Tasks ) function( DetectedUnit, Tasks )
if DetectedUnit:IsAlive() then if DetectedUnit:IsAlive() then
AttackUnitTasks[#AttackUnitTasks+1] = EscortGroup:TaskAttackUnit( DetectedUnit ) AttackUnitTasks[#AttackUnitTasks+1] = EscortGroup:TaskAttackUnit( DetectedUnit )
@@ -1767,7 +1781,7 @@ function AI_ESCORT:_AttackTarget( EscortGroup, DetectedItem )
local Tasks = {} local Tasks = {}
DetectedSet:ForEachUnit( DetectedSet:ForEachUnit(
--- @param Wrapper.Unit#UNIT DetectedUnit -- @param Wrapper.Unit#UNIT DetectedUnit
function( DetectedUnit, Tasks ) function( DetectedUnit, Tasks )
if DetectedUnit:IsAlive() then if DetectedUnit:IsAlive() then
Tasks[#Tasks+1] = EscortGroup:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 ) Tasks[#Tasks+1] = EscortGroup:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 )
@@ -1795,7 +1809,7 @@ end
function AI_ESCORT:_FlightAttackTarget( DetectedItem ) function AI_ESCORT:_FlightAttackTarget( DetectedItem )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Core.Group#GROUP EscortGroup -- @param Core.Group#GROUP EscortGroup
function( EscortGroup, DetectedItem ) function( EscortGroup, DetectedItem )
if EscortGroup:IsAir() then if EscortGroup:IsAir() then
self:_AttackTarget( EscortGroup, DetectedItem ) self:_AttackTarget( EscortGroup, DetectedItem )
@@ -1842,7 +1856,7 @@ end
--- ---
--- @param #AI_ESCORT self -- @param #AI_ESCORT self
-- @param Wrapper.Group#GROUP EscortGroup The escort group that will attack the detected item. -- @param Wrapper.Group#GROUP EscortGroup The escort group that will attack the detected item.
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem ) function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem )
@@ -1854,7 +1868,7 @@ function AI_ESCORT:_AssistTarget( EscortGroup, DetectedItem )
local Tasks = {} local Tasks = {}
DetectedSet:ForEachUnit( DetectedSet:ForEachUnit(
--- @param Wrapper.Unit#UNIT DetectedUnit -- @param Wrapper.Unit#UNIT DetectedUnit
function( DetectedUnit, Tasks ) function( DetectedUnit, Tasks )
if DetectedUnit:IsAlive() then if DetectedUnit:IsAlive() then
Tasks[#Tasks+1] = EscortGroup:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 ) Tasks[#Tasks+1] = EscortGroup:TaskFireAtPoint( DetectedUnit:GetVec2(), 50 )
@@ -1881,7 +1895,7 @@ end
function AI_ESCORT:_FlightROEHoldFire( EscortROEMessage ) function AI_ESCORT:_FlightROEHoldFire( EscortROEMessage )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
self:_ROE( EscortGroup, EscortGroup.OptionROEHoldFire, EscortROEMessage ) self:_ROE( EscortGroup, EscortGroup.OptionROEHoldFire, EscortROEMessage )
end end
@@ -1890,7 +1904,7 @@ end
function AI_ESCORT:_FlightROEOpenFire( EscortROEMessage ) function AI_ESCORT:_FlightROEOpenFire( EscortROEMessage )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
self:_ROE( EscortGroup, EscortGroup.OptionROEOpenFire, EscortROEMessage ) self:_ROE( EscortGroup, EscortGroup.OptionROEOpenFire, EscortROEMessage )
end end
@@ -1899,7 +1913,7 @@ end
function AI_ESCORT:_FlightROEReturnFire( EscortROEMessage ) function AI_ESCORT:_FlightROEReturnFire( EscortROEMessage )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
self:_ROE( EscortGroup, EscortGroup.OptionROEReturnFire, EscortROEMessage ) self:_ROE( EscortGroup, EscortGroup.OptionROEReturnFire, EscortROEMessage )
end end
@@ -1908,7 +1922,7 @@ end
function AI_ESCORT:_FlightROEWeaponFree( EscortROEMessage ) function AI_ESCORT:_FlightROEWeaponFree( EscortROEMessage )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
self:_ROE( EscortGroup, EscortGroup.OptionROEWeaponFree, EscortROEMessage ) self:_ROE( EscortGroup, EscortGroup.OptionROEWeaponFree, EscortROEMessage )
end end
@@ -1924,7 +1938,7 @@ end
function AI_ESCORT:_FlightROTNoReaction( EscortROTMessage ) function AI_ESCORT:_FlightROTNoReaction( EscortROTMessage )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
self:_ROT( EscortGroup, EscortGroup.OptionROTNoReaction, EscortROTMessage ) self:_ROT( EscortGroup, EscortGroup.OptionROTNoReaction, EscortROTMessage )
end end
@@ -1933,7 +1947,7 @@ end
function AI_ESCORT:_FlightROTPassiveDefense( EscortROTMessage ) function AI_ESCORT:_FlightROTPassiveDefense( EscortROTMessage )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
self:_ROT( EscortGroup, EscortGroup.OptionROTPassiveDefense, EscortROTMessage ) self:_ROT( EscortGroup, EscortGroup.OptionROTPassiveDefense, EscortROTMessage )
end end
@@ -1942,7 +1956,7 @@ end
function AI_ESCORT:_FlightROTEvadeFire( EscortROTMessage ) function AI_ESCORT:_FlightROTEvadeFire( EscortROTMessage )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
self:_ROT( EscortGroup, EscortGroup.OptionROTEvadeFire, EscortROTMessage ) self:_ROT( EscortGroup, EscortGroup.OptionROTEvadeFire, EscortROTMessage )
end end
@@ -1951,7 +1965,7 @@ end
function AI_ESCORT:_FlightROTVertical( EscortROTMessage ) function AI_ESCORT:_FlightROTVertical( EscortROTMessage )
self.EscortGroupSet:ForEachGroupAlive( self.EscortGroupSet:ForEachGroupAlive(
--- @param Wrapper.Group#GROUP EscortGroup -- @param Wrapper.Group#GROUP EscortGroup
function( EscortGroup ) function( EscortGroup )
self:_ROT( EscortGroup, EscortGroup.OptionROTVertical, EscortROTMessage ) self:_ROT( EscortGroup, EscortGroup.OptionROTVertical, EscortROTMessage )
end end
@@ -2178,5 +2192,3 @@ function AI_ESCORT:_FlightReportTargetsScheduler()
return false return false
end end
-785
View File
@@ -1,785 +0,0 @@
--- **Core** - Client Menu Management.
--
-- **Main Features:**
--
-- * For complex, non-static menu structures
-- * Lightweigt implementation as alternative to MENU
-- * Separation of menu tree creation from menu on the clients's side
-- * Works with a SET_CLIENT set of clients
-- * Allow manipulation of the shadow tree in various ways
-- * Push to all or only one client
-- * Change entries' menu text
-- * Option to make an entry usable once only across all clients
-- * Auto appends GROUP and CLIENT objects to menu calls
--
-- ===
--
-- ### Author: **applevangelist**
--
-- ===
--
-- @module Core.ClientMenu
-- @image Core_Menu.JPG
-- last change: July 2023
-- TODO
----------------------------------------------------------------------------------------------------------------
--
-- CLIENTMENU
--
----------------------------------------------------------------------------------------------------------------
---
-- @type CLIENTMENU
-- @field #string ClassName Class Name
-- @field #string lid Lid for log entries
-- @field #string version Version string
-- @field #string name Name
-- @field #table path
-- @field #table parentpath
-- @field #CLIENTMENU Parent
-- @field Wrapper.Client#CLIENT client
-- @field #number GroupID Group ID
-- @field #number ID Entry ID
-- @field Wrapper.Group#GROUP group
-- @field #string UUID Unique ID based on path+name
-- @field #string Function
-- @field #table Functionargs
-- @field #table Children
-- @field #boolean Once
-- @field #boolean Generic
-- @field #boolean debug
-- @field #CLIENTMENUMANAGER Controller
-- @extends Core.Base#BASE
---
-- @field #CLIENTMENU
CLIENTMENU = {
ClassName = "CLIENTMENUE",
lid = "",
version = "0.1.0",
name = nil,
path = nil,
group = nil,
client = nil,
GroupID = nil,
Children = {},
Once = false,
Generic = false,
debug = false,
Controller = nil,
}
---
-- @field #CLIENTMENU_ID
CLIENTMENU_ID = 0
--- Create an new CLIENTMENU object.
-- @param #CLIENTMENU self
-- @param Wrapper.Client#CLIENT Client The client for whom this entry is.
-- @param #string Text Text of the F10 menu entry.
-- @param #CLIENTMENU Parent The parent menu entry.
-- @param #string Function (optional) Function to call when the entry is used.
-- @param ... (optional) Arguments for the Function, comma separated
-- @return #CLIENTMENU self
function CLIENTMENU:NewEntry(Client,Text,Parent,Function,...)
-- Inherit everything from BASE class.
local self=BASE:Inherit(self, BASE:New()) -- #CLIENTMENU
CLIENTMENU_ID = CLIENTMENU_ID + 1
self.ID = CLIENTMENU_ID
if Client then
self.group = Client:GetGroup()
self.client = Client
self.GroupID = self.group:GetID()
else
self.Generic = true
end
self.name = Text or "unknown entry"
if Parent then
if Parent:IsInstanceOf("MENU_BASE") then
self.parentpath = Parent.MenuPath
else
self.parentpath = Parent:GetPath()
Parent:AddChild(self)
end
end
self.Parent = Parent
self.Function = Function
self.Functionargs = arg or {}
table.insert(self.Functionargs,self.group)
table.insert(self.Functionargs,self.client)
if self.Functionargs and self.debug then
self:T({"Functionargs",self.Functionargs})
end
if not self.Generic then
if Function ~= nil then
local ErrorHandler = function( errmsg )
env.info( "MOOSE Error in CLIENTMENU COMMAND function: " .. errmsg )
if BASE.Debug ~= nil then
env.info( BASE.Debug.traceback() )
end
return errmsg
end
self.CallHandler = function()
local function MenuFunction()
return self.Function( unpack( self.Functionargs ) )
end
local Status, Result = xpcall( MenuFunction, ErrorHandler)
if self.Once == true then
self:Clear()
end
end
self.path = missionCommands.addCommandForGroup(self.GroupID,Text,self.parentpath, self.CallHandler)
else
self.path = missionCommands.addSubMenuForGroup(self.GroupID,Text,self.parentpath)
end
else
if self.parentpath then
self.path = UTILS.DeepCopy(self.parentpath)
else
self.path = {}
end
self.path[#self.path+1] = Text
end
self.UUID = table.concat(self.path,";")
self:T({self.UUID})
self.Once = false
-- Log id.
self.lid=string.format("CLIENTMENU %s | %s | ", self.ID, self.name)
self:T(self.lid.."Created")
return self
end
--- Create a UUID
-- @param #CLIENTMENU self
-- @param #CLIENTMENU Parent The parent object if any
-- @param #string Text The menu entry text
-- @return #string UUID
function CLIENTMENU:CreateUUID(Parent,Text)
local path = {}
if Parent and Parent.path then
path = Parent.path
end
path[#path+1] = Text
local UUID = table.concat(path,";")
return UUID
end
--- Set the CLIENTMENUMANAGER for this entry.
-- @param #CLIENTMENU self
-- @param #CLIENTMENUMANAGER Controller The controlling object.
-- @return #CLIENTMENU self
function CLIENTMENU:SetController(Controller)
self.Controller = Controller
return self
end
--- The entry will be deleted after being used used - for menu entries with functions only.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self
function CLIENTMENU:SetOnce()
self:T(self.lid.."SetOnce")
self.Once = true
return self
end
--- Remove the entry from the F10 menu.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self
function CLIENTMENU:RemoveF10()
self:T(self.lid.."RemoveF10")
if self.GroupID then
--self:I(self.lid.."Removing "..table.concat(self.path,";"))
missionCommands.removeItemForGroup(self.GroupID , self.path )
end
return self
end
--- Get the menu path table.
-- @param #CLIENTMENU self
-- @return #table Path
function CLIENTMENU:GetPath()
self:T(self.lid.."GetPath")
return self.path
end
--- Get the UUID.
-- @param #CLIENTMENU self
-- @return #string UUID
function CLIENTMENU:GetUUID()
self:T(self.lid.."GetUUID")
return self.UUID
end
--- Link a child entry.
-- @param #CLIENTMENU self
-- @param #CLIENTMENU Child The entry to link as a child.
-- @return #CLIENTMENU self
function CLIENTMENU:AddChild(Child)
self:T(self.lid.."AddChild "..Child.ID)
table.insert(self.Children,Child.ID,Child)
return self
end
--- Remove a child entry.
-- @param #CLIENTMENU self
-- @param #CLIENTMENU Child The entry to remove from the children.
-- @return #CLIENTMENU self
function CLIENTMENU:RemoveChild(Child)
self:T(self.lid.."RemoveChild "..Child.ID)
table.remove(self.Children,Child.ID)
return self
end
--- Remove all subentries (children) from this entry.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self
function CLIENTMENU:RemoveSubEntries()
self:T(self.lid.."RemoveSubEntries")
self:T({self.Children})
for _id,_entry in pairs(self.Children) do
self:T("Removing ".._id)
if _entry then
_entry:RemoveSubEntries()
_entry:RemoveF10()
if _entry.Parent then
_entry.Parent:RemoveChild(self)
end
--if self.Controller then
--self.Controller:_RemoveByID(_entry.ID)
--end
--_entry = nil
end
end
return self
end
--- Remove this entry and all subentries (children) from this entry.
-- @param #CLIENTMENU self
-- @return #CLIENTMENU self
function CLIENTMENU:Clear()
self:T(self.lid.."Clear")
for _id,_entry in pairs(self.Children) do
if _entry then
_entry:RemoveSubEntries()
_entry = nil
end
end
self:RemoveF10()
if self.Parent then
self.Parent:RemoveChild(self)
end
--if self.Controller then
--self.Controller:_RemoveByID(self.ID)
--end
return self
end
-- TODO
----------------------------------------------------------------------------------------------------------------
--
-- CLIENTMENUMANAGER
--
----------------------------------------------------------------------------------------------------------------
--- Class CLIENTMENUMANAGER
-- @type CLIENTMENUMANAGER
-- @field #string ClassName Class Name
-- @field #string lid Lid for log entries
-- @field #string version Version string
-- @field #string name Name
-- @field Core.Set#SET_CLIENT clientset The set of clients this menu manager is for
-- @field #table flattree
-- @field #table rootentries
-- @field #table menutree
-- @field #number entrycount
-- @field #boolean debug
-- @extends Core.Base#BASE
--- *As a child my family's menu consisted of two choices: take it, or leave it.*
--
-- ===
--
-- ## CLIENTMENU and CLIENTMENUMANAGER
--
-- Manage menu structures for a SET_CLIENT of clients.
--
-- ## Concept
--
-- Separate creation of a menu tree structure from pushing it to each client. Create a shadow "reference" menu structure tree for your client pilot's in a mission.
-- This can then be propagated to all clients. Manipulate the entries in the structure with removing, clearing or changing single entries, create replacement sub-structures
-- for entries etc, push to one or all clients.
--
-- Many functions can either change the tree for one client or for all clients.
--
-- ## Create a base reference tree and send to all clients
--
-- local clientset = SET_CLIENT:New():FilterStart()
--
-- local menumgr = CLIENTMENUMANAGER:New(clientset,"Dayshift")
-- local mymenu = menumgr:NewEntry("Top")
-- local mymenu_lv1a = menumgr:NewEntry("Level 1 a",mymenu)
-- local mymenu_lv1b = menumgr:NewEntry("Level 1 b",mymenu)
-- -- next one is a command menu entry, which can only be used once
-- local mymenu_lv1c = menumgr:NewEntry("Action Level 1 c",mymenu, testfunction, "testtext"):SetOnce()
--
-- local mymenu_lv2a = menumgr:NewEntry("Go here",mymenu_lv1a)
-- local mymenu_lv2b = menumgr:NewEntry("Level 2 ab",mymenu_lv1a)
-- local mymenu_lv2c = menumgr:NewEntry("Level 2 ac",mymenu_lv1a)
--
-- local mymenu_lv2ba = menumgr:NewEntry("Level 2 ba",mymenu_lv1b)
-- local mymenu_lv2bb = menumgr:NewEntry("Level 2 bb",mymenu_lv1b)
-- local mymenu_lv2bc = menumgr:NewEntry("Level 2 bc",mymenu_lv1b)
--
-- local mymenu_lv3a = menumgr:NewEntry("Level 3 aaa",mymenu_lv2a)
-- local mymenu_lv3b = menumgr:NewEntry("Level 3 aab",mymenu_lv2a)
-- local mymenu_lv3c = menumgr:NewEntry("Level 3 aac",mymenu_lv2a)
--
-- menumgr:Propagate()
--
-- ## Remove a single entry's subtree
--
-- menumgr:RemoveSubEntries(mymenu_lv3a)
--
-- ## Remove a single entry and also it's subtree
--
-- menumgr:DeleteEntry(mymenu_lv3a)
--
-- ## Add a single entry
--
-- local baimenu = menumgr:NewEntry("BAI",mymenu_lv1b)
--
-- menumgr:AddEntry(baimenu)
--
-- ## Add an entry with a function
--
-- local baimenu = menumgr:NewEntry("Task Action", mymenu_lv1b, TestFunction, Argument1, Argument1)
--
-- Now, the class will **automatically append the call with GROUP and CLIENT objects**, as this is can only be done when pushing the entry to the clients. So, the actual function implementation needs to look like this:
--
-- function TestFunction( Argument1, Argument2, Group, Client)
--
-- **Caveat is**, that you need to ensure your arguments are not **nil** or **false**, as LUA will optimize those away. You would end up having Group and Client in wrong places in the function call. Hence,
-- if you need/ want to send **nil** or **false**, send a place holder instead and ensure your function can handle this, e.g.
--
-- local baimenu = menumgr:NewEntry("Task Action", mymenu_lv1b, TestFunction, "nil", Argument1)
--
-- ## Change the text of a leaf entry in the menu tree
--
-- menumgr:ChangeEntryTextForAll(mymenu_lv1b,"Attack")
--
-- ## Reset a single clients menu tree
--
-- menumgr:ResetMenu(client)
--
-- ## Reset all and clear the reference tree
--
-- menumgr:ResetMenuComplete()
--
-- @field #CLIENTMENUMANAGER
CLIENTMENUMANAGER = {
ClassName = "CLIENTMENUMANAGER",
lid = "",
version = "0.1.0",
name = nil,
clientset = nil,
menutree = {},
flattree = {},
playertree = {},
entrycount = 0,
rootentries = {},
debug = true,
}
--- Create a new ClientManager instance.
-- @param #CLIENTMENUMANAGER self
-- @param Core.Set#SET_CLIENT ClientSet The set of clients to manage.
-- @param #string Alias The name of this manager.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:New(ClientSet, Alias)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, BASE:New()) -- #CLIENTMENUMANAGER
self.clientset = ClientSet
self.name = Alias or "Nightshift"
-- Log id.
self.lid=string.format("CLIENTMENUMANAGER %s | %s | ", self.version, self.name)
if self.debug then
self:T(self.lid.."Created")
end
return self
end
--- Create a new entry in the generic structure.
-- @param #CLIENTMENUMANAGER self
-- @param #string Text Text of the F10 menu entry.
-- @param #CLIENTMENU Parent The parent menu entry.
-- @param #string Function (optional) Function to call when the entry is used.
-- @param ... (optional) Arguments for the Function, comma separated.
-- @return #CLIENTMENU Entry
function CLIENTMENUMANAGER:NewEntry(Text,Parent,Function,...)
self:T(self.lid.."NewEntry "..Text or "None")
self.entrycount = self.entrycount + 1
local entry = CLIENTMENU:NewEntry(nil,Text,Parent,Function,unpack(arg))
if not Parent then
self.rootentries[self.entrycount] = entry
end
local depth = #entry.path
if not self.menutree[depth] then self.menutree[depth] = {} end
table.insert(self.menutree[depth],entry.UUID)
self.flattree[entry.UUID] = entry
return entry
end
--- Check matching entry in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #string UUID UUID of the menu entry.
-- @return #boolean Exists
function CLIENTMENUMANAGER:EntryUUIDExists(UUID)
local exists = self.flattree[UUID] and true or false
return exists
end
--- Find matching entry in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #string UUID UUID of the menu entry.
-- @return #CLIENTMENU Entry The #CLIENTMENU object found or nil.
function CLIENTMENUMANAGER:FindEntryByUUID(UUID)
self:T(self.lid.."FindEntryByUUID "..UUID or "None")
local entry = nil
for _gid,_entry in pairs(self.flattree) do
local Entry = _entry -- #CLIENTMENU
if Entry and Entry.UUID == UUID then
entry = Entry
end
end
return entry
end
--- Find matching entries by text in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #string Text Text or partial text of the menu entry to find.
-- @param #CLIENTMENU Parent (Optional) Only find entries under this parent entry.
-- @return #table Table of matching UUIDs of #CLIENTMENU objects
-- @return #table Table of matching #CLIENTMENU objects
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindUUIDsByText(Text,Parent)
self:T(self.lid.."FindUUIDsByText "..Text or "None")
local matches = {}
local entries = {}
local n = 0
for _uuid,_entry in pairs(self.flattree) do
local Entry = _entry -- #CLIENTMENU
if Parent then
if Entry and string.find(Entry.name,Text) and string.find(Entry.UUID,Parent.UUID) then
table.insert(matches,_uuid)
table.insert(entries,Entry )
n=n+1
end
else
if Entry and string.find(Entry.name,Text) then
table.insert(matches,_uuid)
table.insert(entries,Entry )
n=n+1
end
end
end
return matches, entries, n
end
--- Find matching entries in the generic structure by the menu text.
-- @param #CLIENTMENUMANAGER self
-- @param #string Text Text or partial text of the F10 menu entry.
-- @param #CLIENTMENU Parent (Optional) Only find entries under this parent entry.
-- @return #table Table of matching #CLIENTMENU objects.
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindEntriesByText(Text,Parent)
self:T(self.lid.."FindEntriesByText "..Text or "None")
local matches, objects, number = self:FindUUIDsByText(Text, Parent)
return objects, number
end
--- Find matching entries under a parent in the generic structure by UUID.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Parent Find entries under this parent entry.
-- @return #table Table of matching UUIDs of #CLIENTMENU objects
-- @return #table Table of matching #CLIENTMENU objects
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindUUIDsByParent(Parent)
self:T(self.lid.."FindUUIDsByParent")
local matches = {}
local entries = {}
local n = 0
for _uuid,_entry in pairs(self.flattree) do
local Entry = _entry -- #CLIENTMENU
if Parent then
if Entry and string.find(Entry.UUID,Parent.UUID) then
table.insert(matches,_uuid)
table.insert(entries,Entry )
n=n+1
end
end
end
return matches, entries, n
end
--- Find matching entries in the generic structure under a parent.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Parent Find entries under this parent entry.
-- @return #table Table of matching #CLIENTMENU objects.
-- @return #number Number of matches
function CLIENTMENUMANAGER:FindEntriesByParent(Parent)
self:T(self.lid.."FindEntriesByParent")
local matches, objects, number = self:FindUUIDsByParent(Parent)
return objects, number
end
--- Alter the text of a leaf entry in the generic structure and push to one specific client's F10 menu.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The menu entry.
-- @param #string Text New Text of the F10 menu entry.
-- @param Wrapper.Client#CLIENT Client (optional) The client for whom to alter the entry, if nil done for all clients.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:ChangeEntryText(Entry, Text, Client)
self:T(self.lid.."ChangeEntryText "..Text or "None")
local newentry = CLIENTMENU:NewEntry(nil,Text,Entry.Parent,Entry.Function,unpack(Entry.Functionargs))
self:DeleteF10Entry(Entry,Client)
self:DeleteGenericEntry(Entry)
if not Entry.Parent then
self.rootentries[self.entrycount] = newentry
end
local depth = #newentry.path
if not self.menutree[depth] then self.menutree[depth] = {} end
table.insert(self.menutree[depth],newentry.UUID)
self.flattree[newentry.UUID] = newentry
self:AddEntry(newentry,Client)
return self
end
--- Push the complete menu structure to each of the clients in the set - refresh the menu tree of the clients.
-- @param #CLIENTMENUMANAGER self
-- @param Wrapper.Client#CLIENT Client (optional) If given, propagate only for this client.
-- @return #CLIENTMENU Entry
function CLIENTMENUMANAGER:Propagate(Client)
self:T(self.lid.."Propagate")
self:T(Client)
local Set = self.clientset.Set
if Client then
Set = {Client}
end
self:ResetMenu(Client)
for _,_client in pairs(Set) do
local client = _client -- Wrapper.Client#CLIENT
if client and client:IsAlive() then
local playername = client:GetPlayerName()
if not self.playertree[playername] then
self.playertree[playername] = {}
end
for level,branch in pairs (self.menutree) do
self:T("Building branch:" .. level)
for _,leaf in pairs(branch) do
self:T("Building leaf:" .. leaf)
local entry = self:FindEntryByUUID(leaf)
if entry then
self:T("Found generic entry:" .. entry.UUID)
local parent = nil
if entry.Parent and entry.Parent.UUID then
parent = self.playertree[playername][entry.Parent.UUID] or self:FindEntryByUUID(entry.Parent.UUID)
end
self.playertree[playername][entry.UUID] = CLIENTMENU:NewEntry(client,entry.name,parent,entry.Function,unpack(entry.Functionargs))
self.playertree[playername][entry.UUID].Once = entry.Once
else
self:T("NO generic entry for:" .. leaf)
end
end
end
end
end
return self
end
--- Push a single previously created entry into the menu structure of all clients.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry to add.
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:AddEntry(Entry,Client)
self:T(self.lid.."AddEntry")
local Set = self.clientset.Set
if Client then
Set = {Client}
end
for _,_client in pairs(Set) do
local client = _client -- Wrapper.Client#CLIENT
if client and client:IsAlive() then
local playername = client:GetPlayerName()
if Entry then
self:T("Adding generic entry:" .. Entry.UUID)
local parent = nil
if not self.playertree[playername] then
self.playertree[playername] = {}
end
if Entry.Parent and Entry.Parent.UUID then
parent = self.playertree[playername][Entry.Parent.UUID] or self:FindEntryByUUID(Entry.Parent.UUID)
end
self.playertree[playername][Entry.UUID] = CLIENTMENU:NewEntry(client,Entry.name,parent,Entry.Function,unpack(Entry.Functionargs))
self.playertree[playername][Entry.UUID].Once = Entry.Once
else
self:T("NO generic entry given")
end
end
end
return self
end
--- Blank out the menu - remove **all root entries** and all entries below from the client's F10 menus, leaving the generic structure untouched.
-- @param #CLIENTMENUMANAGER self
-- @param Wrapper.Client#CLIENT Client (optional) If given, remove only for this client.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:ResetMenu(Client)
self:T(self.lid.."ResetMenu")
for _,_entry in pairs(self.rootentries) do
--local RootEntry = self.structure.generic[_entry]
if _entry then
self:DeleteF10Entry(_entry,Client)
end
end
return self
end
--- Blank out the menu - remove **all root entries** and all entries below from all clients' F10 menus, and **delete** the generic structure.
-- @param #CLIENTMENUMANAGER self
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:ResetMenuComplete()
self:T(self.lid.."ResetMenuComplete")
for _,_entry in pairs(self.rootentries) do
--local RootEntry = self.structure.generic[_entry]
if _entry then
self:DeleteF10Entry(_entry)
end
end
self.playertree = nil
self.playertree = {}
self.rootentries = nil
self.rootentries = {}
self.menutree = nil
self.menutree = {}
return self
end
--- Remove the entry and all entries below the given entry from the client's F10 menus.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry to remove
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client. In this case the generic structure will not be touched.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:DeleteF10Entry(Entry,Client)
self:T(self.lid.."DeleteF10Entry")
local Set = self.clientset.Set
if Client then
Set = {Client}
end
for _,_client in pairs(Set) do
if _client and _client:IsAlive() then
local playername = _client:GetPlayerName()
if self.playertree[playername] then
local centry = self.playertree[playername][Entry.UUID] -- #CLIENTMENU
if centry then
--self:I("Match for "..Entry.UUID)
centry:Clear()
end
end
end
end
return self
end
--- Remove the entry and all entries below the given entry from the generic tree.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry to remove
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:DeleteGenericEntry(Entry)
self:T(self.lid.."DeleteGenericEntry")
if Entry.Children and #Entry.Children > 0 then
self:RemoveGenericSubEntries(Entry)
end
local depth = #Entry.path
local uuid = Entry.UUID
local tbl = UTILS.DeepCopy(self.menutree)
if tbl[depth] then
for i=depth,#tbl do
--self:I("Level = "..i)
for _id,_uuid in pairs(tbl[i]) do
self:T(_uuid)
if string.find(_uuid,uuid) or _uuid == uuid then
--self:I("Match for ".._uuid)
self.menutree[i][_id] = nil
self.flattree[_uuid] = nil
end
end
end
end
return self
end
--- Remove all entries below the given entry from the generic tree.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry where to start. This entry stays.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:RemoveGenericSubEntries(Entry)
self:T(self.lid.."RemoveGenericSubEntries")
local depth = #Entry.path + 1
local uuid = Entry.UUID
local tbl = UTILS.DeepCopy(self.menutree)
if tbl[depth] then
for i=depth,#tbl do
self:T("Level = "..i)
for _id,_uuid in pairs(tbl[i]) do
self:T(_uuid)
if string.find(_uuid,uuid) then
self:T("Match for ".._uuid)
self.menutree[i][_id] = nil
self.flattree[_uuid] = nil
end
end
end
end
return self
end
--- Remove all entries below the given entry from the client's F10 menus.
-- @param #CLIENTMENUMANAGER self
-- @param #CLIENTMENU Entry The entry where to start. This entry stays.
-- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client. In this case the generic structure will not be touched.
-- @return #CLIENTMENUMANAGER self
function CLIENTMENUMANAGER:RemoveF10SubEntries(Entry,Client)
self:T(self.lid.."RemoveSubEntries")
local Set = self.clientset.Set
if Client then
Set = {Client}
end
for _,_client in pairs(Set) do
if _client and _client:IsAlive() then
local playername = _client:GetPlayerName()
if self.playertree[playername] then
local centry = self.playertree[playername][Entry.UUID] -- #CLIENTMENU
centry:RemoveSubEntries()
end
end
end
return self
end
----------------------------------------------------------------------------------------------------------------
--
-- End ClientMenu
--
----------------------------------------------------------------------------------------------------------------
+37 -1
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.
+23 -3
View File
@@ -2389,7 +2389,6 @@ do -- COORDINATE
end end
--- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified. --- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified.
-- **NOTE**: A free form polygon must have **at least three points** in total and currently only **up to 15 points** in total are supported.
-- @param #COORDINATE self -- @param #COORDINATE self
-- @param #table Coordinates Table of coordinates of the remaining points of the shape. -- @param #table Coordinates Table of coordinates of the remaining points of the shape.
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All. -- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
@@ -2463,9 +2462,30 @@ do -- COORDINATE
vecs[11], vecs[12], vecs[13], vecs[14], vecs[15], vecs[11], vecs[12], vecs[13], vecs[14], vecs[15],
Color, FillColor, LineType, ReadOnly, Text or "") Color, FillColor, LineType, ReadOnly, Text or "")
else else
self:E("ERROR: Currently a free form polygon can only have 15 points in total!")
-- Unfortunately, unpack(vecs) does not work! So no idea how to generalize this :( -- Unfortunately, unpack(vecs) does not work! So no idea how to generalize this :(
trigger.action.markupToAll(7, Coalition, MarkID, unpack(vecs), Color, FillColor, LineType, ReadOnly, Text or "") --trigger.action.markupToAll(7, Coalition, MarkID, unpack(vecs), Color, FillColor, LineType, ReadOnly, Text or "")
-- Write command as string and execute that. Idea by Grimes https://forum.dcs.world/topic/324201-mark-to-all-function/#comment-5273793
local s=string.format("trigger.action.markupToAll(7, %d, %d,", Coalition, MarkID)
for _,vec in pairs(vecs) do
s=s..string.format("%s,", UTILS._OneLineSerialize(vec))
end
s=s..string.format("%s, %s, %s, %s", UTILS._OneLineSerialize(Color), UTILS._OneLineSerialize(FillColor), tostring(LineType), tostring(ReadOnly))
if Text and Text~="" then
s=s..string.format(", \"%s\"", Text)
end
s=s..")"
-- Execute string command
local success=UTILS.DoString(s)
if not success then
self:E("ERROR: Could not draw polygon")
env.info(s)
end
end end
return MarkID return MarkID
+192 -89
View File
@@ -47,7 +47,8 @@
do -- SET_BASE do -- SET_BASE
--- @type SET_BASE ---
-- @type SET_BASE
-- @field #table Filter Table of filters. -- @field #table Filter Table of filters.
-- @field #table Set Table of objects. -- @field #table Set Table of objects.
-- @field #table Index Table of indices. -- @field #table Index Table of indices.
@@ -242,7 +243,7 @@ do -- SET_BASE
function SET_BASE:Add( ObjectName, Object ) function SET_BASE:Add( ObjectName, Object )
-- Debug info. -- Debug info.
self:T( { ObjectName = ObjectName, Object = Object } ) self:T2( { ObjectName = ObjectName, Object = Object } )
-- Ensure that the existing element is removed from the Set before a new one is inserted to the Set -- Ensure that the existing element is removed from the Set before a new one is inserted to the Set
if self.Set[ObjectName] then if self.Set[ObjectName] then
@@ -257,6 +258,8 @@ do -- SET_BASE
-- Trigger Added event. -- Trigger Added event.
self:Added( ObjectName, Object ) self:Added( ObjectName, Object )
return self
end end
--- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using the Object Name as the index. --- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using the Object Name as the index.
@@ -578,8 +581,8 @@ do -- SET_BASE
end end
----- Private method that registers all alive players in the mission. ----- Private method that registers all alive players in the mission.
---- @param #SET_BASE self -- @param #SET_BASE self
---- @return #SET_BASE self -- @return #SET_BASE self
-- function SET_BASE:_RegisterPlayers() -- function SET_BASE:_RegisterPlayers()
-- --
-- local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } -- local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) }
@@ -796,8 +799,8 @@ do -- SET_BASE
----- Iterate the SET_BASE and call an iterator function for each **alive** unit, providing the Unit and optional parameters. ----- Iterate the SET_BASE and call an iterator function for each **alive** unit, providing the Unit and optional parameters.
---- @param #SET_BASE self -- @param #SET_BASE self
---- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET_BASE. The function needs to accept a UNIT parameter. -- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET_BASE. The function needs to accept a UNIT parameter.
---- @return #SET_BASE self ---- @return #SET_BASE self
-- function SET_BASE:ForEachDCSUnitAlive( IteratorFunction, ... ) -- function SET_BASE:ForEachDCSUnitAlive( IteratorFunction, ... )
-- self:F3( arg ) -- self:F3( arg )
@@ -808,8 +811,8 @@ do -- SET_BASE
-- end -- end
-- --
----- Iterate the SET_BASE and call an iterator function for each **alive** player, providing the Unit of the player and optional parameters. ----- Iterate the SET_BASE and call an iterator function for each **alive** player, providing the Unit of the player and optional parameters.
---- @param #SET_BASE self -- @param #SET_BASE self
---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a UNIT parameter. -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a UNIT parameter.
---- @return #SET_BASE self ---- @return #SET_BASE self
-- function SET_BASE:ForEachPlayer( IteratorFunction, ... ) -- function SET_BASE:ForEachPlayer( IteratorFunction, ... )
-- self:F3( arg ) -- self:F3( arg )
@@ -821,8 +824,8 @@ do -- SET_BASE
-- --
-- --
----- Iterate the SET_BASE and call an iterator function for each client, providing the Client to the function and optional parameters. ----- Iterate the SET_BASE and call an iterator function for each client, providing the Client to the function and optional parameters.
---- @param #SET_BASE self -- @param #SET_BASE self
---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a CLIENT parameter. -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_BASE. The function needs to accept a CLIENT parameter.
---- @return #SET_BASE self ---- @return #SET_BASE self
-- function SET_BASE:ForEachClient( IteratorFunction, ... ) -- function SET_BASE:ForEachClient( IteratorFunction, ... )
-- self:F3( arg ) -- self:F3( arg )
@@ -901,9 +904,12 @@ do -- SET_BASE
end end
do -- SET_GROUP do
--- @type SET_GROUP #SET_GROUP -- SET_GROUP
---
-- @type SET_GROUP #SET_GROUP
-- @field Core.Timer#TIMER ZoneTimer -- @field Core.Timer#TIMER ZoneTimer
-- @field #number ZoneTimerInterval -- @field #number ZoneTimerInterval
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
@@ -1568,7 +1574,7 @@ do -- SET_GROUP
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Group#GROUP GroupObject -- @param Wrapper.Group#GROUP GroupObject
function( ZoneObject, GroupObject ) function( ZoneObject, GroupObject )
if GroupObject:IsCompletelyInZone( ZoneObject ) then if GroupObject:IsCompletelyInZone( ZoneObject ) then
@@ -1590,7 +1596,7 @@ do -- SET_GROUP
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Group#GROUP GroupObject -- @param Wrapper.Group#GROUP GroupObject
function( ZoneObject, GroupObject ) function( ZoneObject, GroupObject )
if GroupObject:IsPartlyInZone( ZoneObject ) then if GroupObject:IsPartlyInZone( ZoneObject ) then
@@ -1612,7 +1618,7 @@ do -- SET_GROUP
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Group#GROUP GroupObject -- @param Wrapper.Group#GROUP GroupObject
function( ZoneObject, GroupObject ) function( ZoneObject, GroupObject )
if GroupObject:IsNotInZone( ZoneObject ) then if GroupObject:IsNotInZone( ZoneObject ) then
@@ -1659,7 +1665,7 @@ do -- SET_GROUP
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Group#GROUP GroupObject -- @param Wrapper.Group#GROUP GroupObject
function( ZoneObject, GroupObject ) function( ZoneObject, GroupObject )
if GroupObject:IsAnyInZone( ZoneObject ) then if GroupObject:IsAnyInZone( ZoneObject ) then
@@ -1857,8 +1863,8 @@ do -- SET_GROUP
end end
----- Iterate the SET_GROUP and call an iterator function for each **alive** player, providing the Group of the player and optional parameters. ----- Iterate the SET_GROUP and call an iterator function for each **alive** player, providing the Group of the player and optional parameters.
---- @param #SET_GROUP self -- @param #SET_GROUP self
---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a GROUP parameter. -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a GROUP parameter.
---- @return #SET_GROUP self ---- @return #SET_GROUP self
-- function SET_GROUP:ForEachPlayer( IteratorFunction, ... ) -- function SET_GROUP:ForEachPlayer( IteratorFunction, ... )
-- self:F2( arg ) -- self:F2( arg )
@@ -1870,8 +1876,8 @@ do -- SET_GROUP
-- --
-- --
----- Iterate the SET_GROUP and call an iterator function for each client, providing the Client to the function and optional parameters. ----- Iterate the SET_GROUP and call an iterator function for each client, providing the Client to the function and optional parameters.
---- @param #SET_GROUP self -- @param #SET_GROUP self
---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a CLIENT parameter. -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_GROUP. The function needs to accept a CLIENT parameter.
---- @return #SET_GROUP self ---- @return #SET_GROUP self
-- function SET_GROUP:ForEachClient( IteratorFunction, ... ) -- function SET_GROUP:ForEachClient( IteratorFunction, ... )
-- self:F2( arg ) -- self:F2( arg )
@@ -1945,7 +1951,7 @@ do -- SET_GROUP
if self.Filter.Zones then if self.Filter.Zones then
local MGroupZone = false local MGroupZone = false
for ZoneName, Zone in pairs( self.Filter.Zones ) do for ZoneName, Zone in pairs( self.Filter.Zones ) do
--self:I( "Zone:", ZoneName ) --self:T( "Zone:", ZoneName )
if MGroup:IsInZone(Zone) then if MGroup:IsInZone(Zone) then
MGroupZone = true MGroupZone = true
end end
@@ -2012,7 +2018,8 @@ end
do -- SET_UNIT do -- SET_UNIT
--- @type SET_UNIT ---
-- @type SET_UNIT
-- @field Core.Timer#TIMER ZoneTimer -- @field Core.Timer#TIMER ZoneTimer
-- @field #number ZoneTimerInterval -- @field #number ZoneTimerInterval
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
@@ -2672,7 +2679,7 @@ do -- SET_UNIT
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Unit#UNIT UnitObject -- @param Wrapper.Unit#UNIT UnitObject
function( ZoneObject, UnitObject ) function( ZoneObject, UnitObject )
if UnitObject:IsInZone( ZoneObject ) then if UnitObject:IsInZone( ZoneObject ) then
@@ -2694,7 +2701,7 @@ do -- SET_UNIT
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Unit#UNIT UnitObject -- @param Wrapper.Unit#UNIT UnitObject
function( ZoneObject, UnitObject ) function( ZoneObject, UnitObject )
if UnitObject:IsNotInZone( ZoneObject ) then if UnitObject:IsNotInZone( ZoneObject ) then
@@ -3011,8 +3018,8 @@ do -- SET_UNIT
----- Iterate the SET_UNIT and call an iterator function for each **alive** player, providing the Unit of the player and optional parameters. ----- Iterate the SET_UNIT and call an iterator function for each **alive** player, providing the Unit of the player and optional parameters.
---- @param #SET_UNIT self -- @param #SET_UNIT self
---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter. -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter.
---- @return #SET_UNIT self ---- @return #SET_UNIT self
-- function SET_UNIT:ForEachPlayer( IteratorFunction, ... ) -- function SET_UNIT:ForEachPlayer( IteratorFunction, ... )
-- self:F2( arg ) -- self:F2( arg )
@@ -3024,8 +3031,8 @@ do -- SET_UNIT
-- --
-- --
----- Iterate the SET_UNIT and call an iterator function for each client, providing the Client to the function and optional parameters. ----- Iterate the SET_UNIT and call an iterator function for each client, providing the Client to the function and optional parameters.
---- @param #SET_UNIT self -- @param #SET_UNIT self
---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a CLIENT parameter. -- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a CLIENT parameter.
---- @return #SET_UNIT self ---- @return #SET_UNIT self
-- function SET_UNIT:ForEachClient( IteratorFunction, ... ) -- function SET_UNIT:ForEachClient( IteratorFunction, ... )
-- self:F2( arg ) -- self:F2( arg )
@@ -3040,7 +3047,7 @@ do -- SET_UNIT
-- @param Wrapper.Unit#UNIT MUnit -- @param Wrapper.Unit#UNIT MUnit
-- @return #SET_UNIT self -- @return #SET_UNIT self
function SET_UNIT:IsIncludeObject( MUnit ) function SET_UNIT:IsIncludeObject( MUnit )
self:F2( MUnit ) self:F2( {MUnit} )
local MUnitInclude = false local MUnitInclude = false
@@ -3192,7 +3199,8 @@ end
do -- SET_STATIC do -- SET_STATIC
--- @type SET_STATIC ---
-- @type SET_STATIC
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
--- Mission designers can use the SET_STATIC class to build sets of Statics belonging to certain: --- Mission designers can use the SET_STATIC class to build sets of Statics belonging to certain:
@@ -3612,7 +3620,7 @@ do -- SET_STATIC
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Static#STATIC StaticObject -- @param Wrapper.Static#STATIC StaticObject
function( ZoneObject, StaticObject ) function( ZoneObject, StaticObject )
if StaticObject:IsInZone( ZoneObject ) then if StaticObject:IsInZone( ZoneObject ) then
@@ -3634,7 +3642,7 @@ do -- SET_STATIC
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Static#STATIC StaticObject -- @param Wrapper.Static#STATIC StaticObject
function( ZoneObject, StaticObject ) function( ZoneObject, StaticObject )
if StaticObject:IsNotInZone( ZoneObject ) then if StaticObject:IsNotInZone( ZoneObject ) then
@@ -3946,7 +3954,8 @@ end
do -- SET_CLIENT do -- SET_CLIENT
--- @type SET_CLIENT ---
-- @type SET_CLIENT
-- @field Core.Timer#TIMER ZoneTimer -- @field Core.Timer#TIMER ZoneTimer
-- @field #number ZoneTimerInterval -- @field #number ZoneTimerInterval
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
@@ -4008,8 +4017,8 @@ do -- SET_CLIENT
Countries = nil, Countries = nil,
ClientPrefixes = nil, ClientPrefixes = nil,
Zones = nil, Zones = nil,
Playernames = nil, Playernames = nil,
Callsigns = nil, Callsigns = nil,
}, },
FilterMeta = { FilterMeta = {
Coalitions = { Coalitions = {
@@ -4059,7 +4068,7 @@ do -- SET_CLIENT
--- Remove CLIENT(s) from SET_CLIENT. --- Remove CLIENT(s) from SET_CLIENT.
-- @param Core.Set#SET_CLIENT self -- @param Core.Set#SET_CLIENT self
-- @param Wrapper.Client#CLIENT RemoveClientNames A single name or an array of CLIENT names. -- @param Wrapper.Client#CLIENT RemoveClientNames A single object or an array of CLIENT objects.
-- @return self -- @return self
function SET_CLIENT:RemoveClientsByName( RemoveClientNames ) function SET_CLIENT:RemoveClientsByName( RemoveClientNames )
@@ -4369,7 +4378,7 @@ do -- SET_CLIENT
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Client#CLIENT ClientObject -- @param Wrapper.Client#CLIENT ClientObject
function( ZoneObject, ClientObject ) function( ZoneObject, ClientObject )
if ClientObject:IsInZone( ZoneObject ) then if ClientObject:IsInZone( ZoneObject ) then
@@ -4391,7 +4400,7 @@ do -- SET_CLIENT
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Client#CLIENT ClientObject -- @param Wrapper.Client#CLIENT ClientObject
function( ZoneObject, ClientObject ) function( ZoneObject, ClientObject )
if ClientObject:IsNotInZone( ZoneObject ) then if ClientObject:IsNotInZone( ZoneObject ) then
@@ -4459,7 +4468,7 @@ do -- SET_CLIENT
if self.Filter.Active == false or (self.Filter.Active == true and MClient:IsActive() == true and MClient:IsAlive() == true) then if self.Filter.Active == false or (self.Filter.Active == true and MClient:IsActive() == true and MClient:IsAlive() == true) then
MClientActive = true MClientActive = true
end end
--self:I( { "Evaluated Active", MClientActive } ) --self:T( { "Evaluated Active", MClientActive } )
MClientInclude = MClientInclude and MClientActive MClientInclude = MClientInclude and MClientActive
end end
@@ -4526,45 +4535,45 @@ do -- SET_CLIENT
MClientInclude = MClientInclude and MClientPrefix MClientInclude = MClientInclude and MClientPrefix
end end
if self.Filter.Zones then if self.Filter.Zones then
local MClientZone = false local MClientZone = false
for ZoneName, Zone in pairs( self.Filter.Zones ) do for ZoneName, Zone in pairs( self.Filter.Zones ) do
self:T3( "Zone:", ZoneName ) self:T3( "Zone:", ZoneName )
local unit = MClient:GetClientGroupUnit() local unit = MClient:GetClientGroupUnit()
if unit and unit:IsInZone(Zone) then if unit and unit:IsInZone(Zone) then
MClientZone = true MClientZone = true
end end
end end
MClientInclude = MClientInclude and MClientZone MClientInclude = MClientInclude and MClientZone
end end
if self.Filter.Playernames then if self.Filter.Playernames then
local MClientPlayername = false local MClientPlayername = false
local playername = MClient:GetPlayerName() or "Unknown" local playername = MClient:GetPlayerName() or "Unknown"
--self:I(playername) --self:T(playername)
for _,_Playername in pairs(self.Filter.Playernames) do for _,_Playername in pairs(self.Filter.Playernames) do
if playername and string.find(playername,_Playername) then if playername and string.find(playername,_Playername) then
MClientPlayername = true MClientPlayername = true
end end
end end
self:T( { "Evaluated Playername", MClientPlayername } ) self:T( { "Evaluated Playername", MClientPlayername } )
MClientInclude = MClientInclude and MClientPlayername MClientInclude = MClientInclude and MClientPlayername
end end
if self.Filter.Callsigns then if self.Filter.Callsigns then
local MClientCallsigns = false local MClientCallsigns = false
local callsign = MClient:GetCallsign() local callsign = MClient:GetCallsign()
--self:I(callsign) --self:T(callsign)
for _,_Callsign in pairs(self.Filter.Callsigns) do for _,_Callsign in pairs(self.Filter.Callsigns) do
if callsign and string.find(callsign,_Callsign) then if callsign and string.find(callsign,_Callsign) then
MClientCallsigns = true MClientCallsigns = true
end end
end end
self:T( { "Evaluated Callsign", MClientCallsigns } ) self:T( { "Evaluated Callsign", MClientCallsigns } )
MClientInclude = MClientInclude and MClientCallsigns MClientInclude = MClientInclude and MClientCallsigns
end end
end end
self:T2( MClientInclude ) self:T2( MClientInclude )
return MClientInclude return MClientInclude
end end
@@ -4573,7 +4582,8 @@ end
do -- SET_PLAYER do -- SET_PLAYER
--- @type SET_PLAYER ---
-- @type SET_PLAYER
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_PLAYER} class to build sets of units belonging to alive players: --- Mission designers can use the @{Core.Set#SET_PLAYER} class to build sets of units belonging to alive players:
@@ -4868,7 +4878,7 @@ do -- SET_PLAYER
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Client#CLIENT ClientObject -- @param Wrapper.Client#CLIENT ClientObject
function( ZoneObject, ClientObject ) function( ZoneObject, ClientObject )
if ClientObject:IsInZone( ZoneObject ) then if ClientObject:IsInZone( ZoneObject ) then
@@ -4890,7 +4900,7 @@ do -- SET_PLAYER
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet(), self:ForEach( IteratorFunction, arg, self:GetSet(),
--- @param Core.Zone#ZONE_BASE ZoneObject -- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Client#CLIENT ClientObject -- @param Wrapper.Client#CLIENT ClientObject
function( ZoneObject, ClientObject ) function( ZoneObject, ClientObject )
if ClientObject:IsNotInZone( ZoneObject ) then if ClientObject:IsNotInZone( ZoneObject ) then
@@ -4999,7 +5009,8 @@ end
do -- SET_AIRBASE do -- SET_AIRBASE
--- @type SET_AIRBASE ---
-- @type SET_AIRBASE
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_AIRBASE} class to build sets of airbases optionally belonging to certain: --- Mission designers can use the @{Core.Set#SET_AIRBASE} class to build sets of airbases optionally belonging to certain:
@@ -5342,7 +5353,8 @@ end
do -- SET_CARGO do -- SET_CARGO
--- @type SET_CARGO ---
-- @type SET_CARGO
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_CARGO} class to build sets of cargos optionally belonging to certain: --- Mission designers can use the @{Core.Set#SET_CARGO} class to build sets of cargos optionally belonging to certain:
@@ -5768,7 +5780,8 @@ end
do -- SET_ZONE do -- SET_ZONE
--- @type SET_ZONE ---
-- @type SET_ZONE
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_ZONE} class to build sets of zones of various types. --- Mission designers can use the @{Core.Set#SET_ZONE} class to build sets of zones of various types.
@@ -6136,7 +6149,8 @@ end
do -- SET_ZONE_GOAL do -- SET_ZONE_GOAL
--- @type SET_ZONE_GOAL ---
-- @type SET_ZONE_GOAL
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_ZONE_GOAL} class to build sets of zones of various types. --- Mission designers can use the @{Core.Set#SET_ZONE_GOAL} class to build sets of zones of various types.
@@ -6447,7 +6461,8 @@ end
do -- SET_OPSZONE do -- SET_OPSZONE
--- @type SET_OPSZONE ---
-- @type SET_OPSZONE
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_OPSZONE} class to build sets of zones of various types. --- Mission designers can use the @{Core.Set#SET_OPSZONE} class to build sets of zones of various types.
@@ -6904,7 +6919,8 @@ end
do -- SET_OPSGROUP do -- SET_OPSGROUP
--- @type SET_OPSGROUP ---
-- @type SET_OPSGROUP
-- @extends Core.Set#SET_BASE -- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_OPSGROUP} class to build sets of OPS groups belonging to certain: --- Mission designers can use the @{Core.Set#SET_OPSGROUP} class to build sets of OPS groups belonging to certain:
@@ -7571,6 +7587,7 @@ do -- SET_SCENERY
Scenerys = {}, Scenerys = {},
Filter = { Filter = {
SceneryPrefixes = nil, SceneryPrefixes = nil,
SceneryRoles = nil,
Zones = nil, Zones = nil,
}, },
} }
@@ -7593,7 +7610,7 @@ do -- SET_SCENERY
if ZoneSet then if ZoneSet then
for _,_zone in pairs(ZoneSet.Set) do for _,_zone in pairs(ZoneSet.Set) do
self:T("Zone type handed: "..tostring(_zone.ClassName)) self:T("Zone type handed: "..tostring(_zone.ClassName))
table.insert(zonenames,_zone:GetName()) table.insert(zonenames,_zone:GetName())
end end
self:AddSceneryByName(zonenames) self:AddSceneryByName(zonenames)
@@ -7617,7 +7634,7 @@ do -- SET_SCENERY
--- Add SCENERY(s) to SET_SCENERY. --- Add SCENERY(s) to SET_SCENERY.
-- @param #SET_SCENERY self -- @param #SET_SCENERY self
-- @param #string AddScenery A single SCENERY. -- @param Wrapper.Scenery#SCENERY AddScenery A single SCENERY object.
-- @return #SET_SCENERY self -- @return #SET_SCENERY self
function SET_SCENERY:AddScenery( AddScenery ) function SET_SCENERY:AddScenery( AddScenery )
self:F2( AddScenery:GetName() ) self:F2( AddScenery:GetName() )
@@ -7687,6 +7704,7 @@ do -- SET_SCENERY
end end
for _,Zone in pairs( zones ) do for _,Zone in pairs( zones ) do
local zonename = Zone:GetName() local zonename = Zone:GetName()
self:T(zonename)
self.Filter.Zones[zonename] = Zone self.Filter.Zones[zonename] = Zone
end end
return self return self
@@ -7705,11 +7723,30 @@ do -- SET_SCENERY
Prefixes = { Prefixes } Prefixes = { Prefixes }
end end
for PrefixID, Prefix in pairs( Prefixes ) do for PrefixID, Prefix in pairs( Prefixes ) do
--self:T(Prefix)
self.Filter.SceneryPrefixes[Prefix] = Prefix self.Filter.SceneryPrefixes[Prefix] = Prefix
end end
return self return self
end end
--- Builds a set of SCENERYs that **contain** an exact match of the "ROLE" property.
-- @param #SET_SCENERY self
-- @param #string Role The string pattern(s) that needs to exactly match the scenery "ROLE" property from the ME quad-zone properties. Can also be passed as a `#table` of strings.
-- @return #SET_SCENERY self
function SET_SCENERY:FilterRoles( Role )
if not self.Filter.SceneryRoles then
self.Filter.SceneryRoles = {}
end
if type( Role ) ~= "table" then
Role = { Role }
end
for PrefixID, Prefix in pairs( Role ) do
--self:T(Prefix)
self.Filter.SceneryRoles[Prefix] = Prefix
end
return self
end
--- Iterate the SET_SCENERY and count how many SCENERYSs are alive. --- Iterate the SET_SCENERY and count how many SCENERYSs are alive.
-- @param #SET_SCENERY self -- @param #SET_SCENERY self
-- @return #number The number of SCENERYSs alive. -- @return #number The number of SCENERYSs alive.
@@ -7802,10 +7839,76 @@ do -- SET_SCENERY
-- @param Wrapper.Scenery#SCENERY MScenery -- @param Wrapper.Scenery#SCENERY MScenery
-- @return #SET_SCENERY self -- @return #SET_SCENERY self
function SET_SCENERY:IsIncludeObject( MScenery ) function SET_SCENERY:IsIncludeObject( MScenery )
self:F2( MScenery ) self:T( MScenery.SceneryName )
return true
local MSceneryInclude = true
if MScenery then
local MSceneryName = MScenery:GetName()
-- Filter Prefixes
if self.Filter.Prefixes then
local MSceneryPrefix = false
for ZonePrefixId, ZonePrefix in pairs( self.Filter.Prefixes ) do
self:T( { "Prefix:", string.find( MSceneryName, ZonePrefix, 1 ), ZonePrefix } )
if string.find( MSceneryName, ZonePrefix, 1 ) then
MSceneryPrefix = true
end
end
self:T( { "Evaluated Prefix", MSceneryPrefix } )
MSceneryInclude = MSceneryInclude and MSceneryPrefix
end
if self.Filter.Zones then
local MSceneryZone = false
for ZoneName, Zone in pairs( self.Filter.Zones ) do
--self:T( "Zone:", ZoneName )
local coord = MScenery:GetCoordinate()
if coord and Zone:IsCoordinateInZone(coord) then
MSceneryZone = true
end
self:T( { "Evaluated Zone", MSceneryZone } )
end
MSceneryInclude = MSceneryInclude and MSceneryZone
end
-- Filter Roles
if self.Filter.SceneryRoles then
local MSceneryRole = false
local Role = MScenery:GetProperty("ROLE") or "none"
for ZoneRoleId, ZoneRole in pairs( self.Filter.SceneryRoles ) do
self:T( { "Role:", ZoneRole, Role } )
if ZoneRole == Role then
MSceneryRole = true
end
end
self:T( { "Evaluated Role ", MSceneryRole } )
MSceneryInclude = MSceneryInclude and MSceneryRole
end
end
self:T2( MSceneryInclude )
return MSceneryInclude
end end
--- Filters for the defined collection.
-- @param #SET_SCENERY self
-- @return #SET_SCENERY self
function SET_SCENERY:FilterOnce()
for ObjectName, Object in pairs( self:GetSet() ) do
self:T(ObjectName)
if self:IsIncludeObject( Object ) then
self:Add( ObjectName, Object )
else
self:Remove(ObjectName, true)
end
end
return self --FilteredSet
end
--- Count overall initial (Life0) lifepoints of the SET objects. --- Count overall initial (Life0) lifepoints of the SET objects.
-- @param #SET_SCENERY self -- @param #SET_SCENERY self
-- @return #number LIfe0Points -- @return #number LIfe0Points
@@ -7843,7 +7946,7 @@ do -- SET_SCENERY
function SET_SCENERY:GetRelativeLife() function SET_SCENERY:GetRelativeLife()
local life = self:GetLife() local life = self:GetLife()
local life0 = self:GetLife0() local life0 = self:GetLife0()
self:T3(string.format("Set Lifepoints: %d life0 | %d life",life0,life)) self:T2(string.format("Set Lifepoints: %d life0 | %d life",life0,life))
local rlife = math.floor((life / life0) * 100) local rlife = math.floor((life / life0) * 100)
return rlife return rlife
end end
+2 -4
View File
@@ -1616,11 +1616,7 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius, Offset)
if (Offset.dx or Offset.dy) and (Offset.rho or Offset.theta) then if (Offset.dx or Offset.dy) and (Offset.rho or Offset.theta) then
error("Cannot use (dx, dy) with (rho, theta)") error("Cannot use (dx, dy) with (rho, theta)")
end end
end
local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneUNIT:GetVec2(), Radius, true ) )
if Offset then
self.dy = Offset.dy or 0.0 self.dy = Offset.dy or 0.0
self.dx = Offset.dx or 0.0 self.dx = Offset.dx or 0.0
self.rho = Offset.rho or 0.0 self.rho = Offset.rho or 0.0
@@ -1628,6 +1624,8 @@ function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius, Offset)
self.relative_to_unit = Offset.relative_to_unit or false self.relative_to_unit = Offset.relative_to_unit or false
end end
local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneUNIT:GetVec2(), Radius, true ) )
self:F( { ZoneName, ZoneUNIT:GetVec2(), Radius } ) self:F( { ZoneName, ZoneUNIT:GetVec2(), Radius } )
self.ZoneUNIT = ZoneUNIT self.ZoneUNIT = ZoneUNIT
+101
View File
@@ -794,10 +794,111 @@ 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
--- 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)
File diff suppressed because it is too large Load Diff
@@ -1,806 +0,0 @@
--- **Functional** -- Send a truck to supply artillery groups.
--
-- ===
--
-- **AMMOTRUCK** - Send a truck to supply artillery groups.
--
-- ===
--
-- ## Missions:
--
-- ### [AmmoTruck](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/AMT%20-%20AmmoTruck/AmmoTruck%20100%20-%20NTTR%20-%20Basic)
--
-- ===
--
-- ### Author : **applevangelist**
--
-- @module Functional.AmmoTruck
-- @image Artillery.JPG
--
-- Last update: July 2023
-------------------------------------------------------------------------
--- **AMMOTRUCK** class, extends Core.FSM#FSM
-- @type AMMOTRUCK
-- @field #string ClassName Class Name
-- @field #string lid Lid for log entries
-- @field #string version Version string
-- @field #string alias Alias name
-- @field #boolean debug Debug flag
-- @field #table trucklist List of (alive) #AMMOTRUCK.data trucks
-- @field #table targetlist List of (alive) #AMMOTRUCK.data artillery
-- @field #number coalition Coalition this is for
-- @field Core.Set#SET_GROUP truckset SET of trucks
-- @field Core.Set#SET_GROUP targetset SET of artillery
-- @field #table remunitionqueue List of (alive) #AMMOTRUCK.data artillery to be reloaded
-- @field #table waitingtargets List of (alive) #AMMOTRUCK.data artillery waiting
-- @field #number ammothreshold Threshold (min) ammo before sending a truck
-- @field #number remunidist Max distance trucks will go
-- @field #number monitor Monitor interval in seconds
-- @field #number unloadtime Unload time in seconds
-- @field #number waitingtime Max waiting time in seconds
-- @field #boolean routeonroad Route truck on road if true (default)
-- @field #number reloads Number of reloads a single truck can do before he must return home
-- @extends Core.FSM#FSM
--- *Amateurs talk about tactics, but professionals study logistics.* - General Robert H Barrow, USMC
--
-- Simple Class to re-arm your artillery with trucks.
--
-- #AMMOTRUCK
--
-- * Controls a SET\_GROUP of trucks which will re-arm a SET\_GROUP of artillery groups when they run out of ammunition.
--
-- ## 1 The AMMOTRUCK concept
--
-- A SET\_GROUP of trucks which will re-arm a SET\_GROUP of artillery groups when they run out of ammunition. They will be based on a
-- homebase and drive from there to the artillery groups and then back home.
-- Trucks are the **only known in-game mechanic** to re-arm artillery and other units in DCS. Working units are e.g.: M-939 (blue), Ural-375 and ZIL-135 (both red).
--
-- ## 2 Set-up
--
-- Define a set of trucks and a set of artillery:
--
-- local truckset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Ammo Truck"):FilterStart()
-- local ariset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Artillery"):FilterStart()
--
-- Create an AMMOTRUCK object to take care of the artillery using the trucks, with a homezone:
--
-- local ammotruck = AMMOTRUCK:New(truckset,ariset,coalition.side.BLUE,"Logistics",ZONE:FindByName("HomeZone")
--
-- ## 2 Options and their default values
--
-- ammotruck.ammothreshold = 5 -- send a truck when down to this many rounds
-- ammotruck.remunidist = 20000 -- 20km - send trucks max this far from home
-- ammotruck.unloadtime = 600 -- 10 minutes - min time to unload ammunition
-- ammotruck.waitingtime = 1800 -- 30 mintes - wait max this long until remunition is done
-- ammotruck.monitor = -60 -- 1 minute - AMMOTRUCK checks run every one minute
-- ammotruck.routeonroad = true -- Trucks will **try** to drive on roads
-- ammotruck.usearmygroup = false -- If true, will make use of ARMYGROUP in the background (if used in DEV branch)
-- ammotruck.reloads = 5 -- Maxn re-arms a truck can do before he needs to go home and restock. Set to -1 for unlimited
--
-- ## 3 FSM Events to shape mission
--
-- Truck has been sent off:
--
-- function ammotruck:OnAfterRouteTruck(From, Event, To, Truckdata, Aridata)
-- ...
-- end
--
-- Truck has arrived:
--
-- function ammotruck:OnAfterTruckArrived(From, Event, To, Truckdata)
-- ...
-- end
--
-- Truck is unloading:
--
-- function ammotruck:OnAfterTruckUnloading(From, Event, To, Truckdata)
-- ...
-- end
--
-- Truck is returning home:
--
-- function ammotruck:OnAfterTruckReturning(From, Event, To, Truckdata)
-- ...
-- end
--
-- Truck is arrived at home:
--
-- function ammotruck:OnAfterTruckHome(From, Event, To, Truckdata)
-- ...
-- end
--
-- @field #AMMOTRUCK
AMMOTRUCK = {
ClassName = "AMMOTRUCK",
lid = "",
version = "0.0.12",
alias = "",
debug = false,
trucklist = {},
targetlist = {},
coalition = nil,
truckset = nil,
targetset = nil,
remunitionqueue = {},
waitingtargets = {},
ammothreshold = 5,
remunidist = 20000,
monitor = -60,
unloadtime = 600,
waitingtime = 1800,
routeonroad = true,
reloads = 5,
}
---
-- @type AMMOTRUCK.State
AMMOTRUCK.State = {
IDLE = "idle",
DRIVING = "driving",
ARRIVED = "arrived",
UNLOADING = "unloading",
RETURNING = "returning",
WAITING = "waiting",
RELOADING = "reloading",
OUTOFAMMO = "outofammo",
REQUESTED = "requested",
}
---
--@type AMMOTRUCK.data
--@field Wrapper.Group#GROUP group
--@field #string name
--@field #AMMOTRUCK.State statusquo
--@field #number timestamp
--@field #number ammo
--@field Core.Point#COORDINATE coordinate
--@field #string targetname
--@field Wrapper.Group#GROUP targetgroup
--@field Core.Point#COORDINATE targetcoordinate
--@field #number reloads
---
-- @param #AMMOTRUCK self
-- @param Core.Set#SET_GROUP Truckset Set of truck groups
-- @param Core.Set#SET_GROUP Targetset Set of artillery groups
-- @param #number Coalition Coalition
-- @param #string Alias Alias Name
-- @param Core.Zone#ZONE Homezone Home, return zone for trucks
-- @return #AMMOTRUCK self
-- @usage
-- Define a set of trucks and a set of artillery:
-- local truckset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Ammo Truck"):FilterStart()
-- local ariset = SET_GROUP:New():FilterCoalitions("blue"):FilterActive(true):FilterCategoryGround():FilterPrefixes("Artillery"):FilterStart()
--
-- Create an AMMOTRUCK object to take care of the artillery using the trucks, with a homezone:
-- local ammotruck = AMMOTRUCK:New(truckset,ariset,coalition.side.BLUE,"Logistics",ZONE:FindByName("HomeZone")
function AMMOTRUCK:New(Truckset,Targetset,Coalition,Alias,Homezone)
-- Inherit everything from BASE class.
local self=BASE:Inherit(self, FSM:New()) -- #AMMOTRUCK
self.truckset = Truckset -- Core.Set#SET_GROUP
self.targetset = Targetset -- Core.Set#SET_GROUP
self.coalition = Coalition -- #number
self.alias = Alias -- #string
self.debug = false
self.remunitionqueue = {}
self.trucklist = {}
self.targetlist = {}
self.ammothreshold = 5
self.remunidist = 20000
self.homezone = Homezone -- Core.Zone#ZONE
self.waitingtime = 1800
self.usearmygroup = false
self.hasarmygroup = false
-- Log id.
self.lid=string.format("AMMOTRUCK %s | %s | ", self.version, self.alias)
self:SetStartState("Stopped")
self:AddTransition("Stopped", "Start", "Running")
self:AddTransition("*", "Monitor", "*")
self:AddTransition("*", "RouteTruck", "*")
self:AddTransition("*", "TruckArrived", "*")
self:AddTransition("*", "TruckUnloading", "*")
self:AddTransition("*", "TruckReturning", "*")
self:AddTransition("*", "TruckHome", "*")
self:AddTransition("*", "Stop", "Stopped")
self:__Start(math.random(5,10))
self:I(self.lid .. "Started")
------------------------
--- Pseudo Functions ---
------------------------
--- Triggers the FSM event "Stop". Stops the AMMOTRUCK and all its event handlers.
-- @function [parent=#AMMOTRUCK] Stop
-- @param #AMMOTRUCK self
--- Triggers the FSM event "Stop" after a delay. Stops the AMMOTRUCK and all its event handlers.
-- @function [parent=#AMMOTRUCK] __Stop
-- @param #AMMOTRUCK self
-- @param #number delay Delay in seconds.
--- On after "RouteTruck" event.
-- @function [parent=#AMMOTRUCK] OnAfterRouteTruck
-- @param #AMMOTRUCK self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AMMOTRUCK.data Truck
-- @param #AMMOTRUCK.data Artillery
--- On after "TruckUnloading" event.
-- @function [parent=#AMMOTRUCK] OnAfterTruckUnloading
-- @param #AMMOTRUCK self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AMMOTRUCK.data Truck
--- On after "TruckReturning" event.
-- @function [parent=#AMMOTRUCK] OnAfterTruckReturning
-- @param #AMMOTRUCK self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AMMOTRUCK.data Truck
--- On after "RouteTruck" event.
-- @function [parent=#AMMOTRUCK] OnAfterRouteTruck
-- @param #AMMOTRUCK self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AMMOTRUCK.data Truck
--- On after "TruckHome" event.
-- @function [parent=#AMMOTRUCK] OnAfterTruckHome
-- @param #AMMOTRUCK self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #AMMOTRUCK.data Truck
return self
end
---
-- @param #AMMOTRUCK self
-- @param #table dataset table of #AMMOTRUCK.data entries
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckDrivingTrucks(dataset)
self:T(self.lid .. " CheckDrivingTrucks")
local data = dataset
for _,_data in pairs (data) do
local truck = _data -- #AMMOTRUCK.data
-- see if we arrived at destination
local coord = truck.group:GetCoordinate()
local tgtcoord = truck.targetcoordinate
local dist = coord:Get2DDistance(tgtcoord)
if dist <= 150 then
-- arrived
truck.statusquo = AMMOTRUCK.State.ARRIVED
truck.timestamp = timer.getAbsTime()
truck.coordinate = coord
self:__TruckArrived(1,truck)
end
-- still driving?
local Tnow = timer.getAbsTime()
if Tnow - truck.timestamp > 30 then
local group = truck.group
if self.usearmygroup then
group = truck.group:GetGroup()
end
local currspeed = group:GetVelocityKMH()
if truck.lastspeed then
if truck.lastspeed == 0 and currspeed == 0 then
self:T(truck.group:GetName().." Is not moving!")
-- try and move it
truck.timestamp = timer.getAbsTime()
if self.routeonroad then
group:RouteGroundOnRoad(truck.targetcoordinate,30,2,"Vee")
else
group:RouteGroundTo(truck.targetcoordinate,30,"Vee",2)
end
end
truck.lastspeed = currspeed
else
truck.lastspeed = currspeed
truck.timestamp = timer.getAbsTime()
end
self:I({truck=truck.group:GetName(),currspeed=currspeed,lastspeed=truck.lastspeed})
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param Wrapper.Group#GROUP Group
-- @return #AMMOTRUCK self
function AMMOTRUCK:GetAmmoStatus(Group)
local ammotot, shells, rockets, bombs, missiles, narti = Group:GetAmmunition()
return rockets+missiles+narti
end
---
-- @param #AMMOTRUCK self
-- @param #table dataset table of #AMMOTRUCK.data entries
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckWaitingTargets(dataset)
self:T(self.lid .. " CheckWaitingTargets")
local data = dataset
for _,_data in pairs (data) do
local truck = _data -- #AMMOTRUCK.data
-- see how long we're waiting - maybe ammo truck is dead?
local Tnow = timer.getAbsTime()
local Tdiff = Tnow - truck.timestamp
if Tdiff > self.waitingtime then
local hasammo = self:GetAmmoStatus(truck.group)
if hasammo <= self.ammothreshold then
truck.statusquo = AMMOTRUCK.State.OUTOFAMMO
else
truck.statusquo = AMMOTRUCK.State.IDLE
end
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #table dataset table of #AMMOTRUCK.data entries
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckReturningTrucks(dataset)
self:T(self.lid .. " CheckReturningTrucks")
local data = dataset
local tgtcoord = self.homezone:GetCoordinate()
local radius = self.homezone:GetRadius()
for _,_data in pairs (data) do
local truck = _data -- #AMMOTRUCK.data
-- see if we arrived at destination
local coord = truck.group:GetCoordinate()
local dist = coord:Get2DDistance(tgtcoord)
self:T({name=truck.name,radius=radius,distance=dist})
if dist <= radius then
-- arrived
truck.statusquo = AMMOTRUCK.State.IDLE
truck.timestamp = timer.getAbsTime()
truck.coordinate = coord
truck.reloads = self.reloads or 5
self:__TruckHome(1,truck)
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string name Artillery group name to find
-- @return #AMMOTRUCK.data Data
function AMMOTRUCK:FindTarget(name)
self:T(self.lid .. " FindTarget")
local data = nil
local dataset = self.targetlist
for _,_entry in pairs(dataset) do
local entry = _entry -- #AMMOTRUCK.data
if entry.name == name then
data = entry
break
end
end
return data
end
---
-- @param #AMMOTRUCK self
-- @param #string name Truck group name to find
-- @return #AMMOTRUCK.data Data
function AMMOTRUCK:FindTruck(name)
self:T(self.lid .. " FindTruck")
local data = nil
local dataset = self.trucklist
for _,_entry in pairs(dataset) do
local entry = _entry -- #AMMOTRUCK.data
if entry.name == name then
data = entry
break
end
end
return data
end
---
-- @param #AMMOTRUCK self
-- @param #table dataset table of #AMMOTRUCK.data entries
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckArrivedTrucks(dataset)
self:T(self.lid .. " CheckArrivedTrucks")
local data = dataset
for _,_data in pairs (data) do
-- set to unloading
local truck = _data -- #AMMOTRUCK.data
truck.statusquo = AMMOTRUCK.State.UNLOADING
truck.timestamp = timer.getAbsTime()
self:__TruckUnloading(2,truck)
-- set target to reloading
local aridata = self:FindTarget(truck.targetname) -- #AMMOTRUCK.data
if aridata then
aridata.statusquo = AMMOTRUCK.State.RELOADING
aridata.timestamp = timer.getAbsTime()
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #table dataset table of #AMMOTRUCK.data entries
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckUnloadingTrucks(dataset)
self:T(self.lid .. " CheckUnloadingTrucks")
local data = dataset
for _,_data in pairs (data) do
-- check timestamp
local truck = _data -- #AMMOTRUCK.data
local Tnow = timer.getAbsTime()
local Tpassed = Tnow - truck.timestamp
local hasammo = self:GetAmmoStatus(truck.targetgroup)
if Tpassed > self.unloadtime and hasammo > self.ammothreshold then
truck.statusquo = AMMOTRUCK.State.RETURNING
truck.timestamp = timer.getAbsTime()
self:__TruckReturning(2,truck)
-- set target to reloaded
local aridata = self:FindTarget(truck.targetname) -- #AMMOTRUCK.data
if aridata then
aridata.statusquo = AMMOTRUCK.State.IDLE
aridata.timestamp = timer.getAbsTime()
end
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckTargetsAlive()
self:T(self.lid .. " CheckTargetsAlive")
local arilist = self.targetlist
for _,_ari in pairs(arilist) do
local ari = _ari -- #AMMOTRUCK.data
if ari.group and ari.group:IsAlive() then
-- everything fine
else
-- ari dead
self.targetlist[ari.name] = nil
end
end
-- new arrivals?
local aritable = self.targetset:GetSetObjects() --#table
for _,_ari in pairs(aritable) do
local ari = _ari -- Wrapper.Group#GROUP
if ari and ari:IsAlive() and not self.targetlist[ari:GetName()] then
local name = ari:GetName()
local newari = {} -- #AMMOTRUCK.data
newari.name = name
newari.group = ari
newari.statusquo = AMMOTRUCK.State.IDLE
newari.timestamp = timer.getAbsTime()
newari.coordinate = ari:GetCoordinate()
local hasammo = self:GetAmmoStatus(ari)
--newari.ammo = ari:GetAmmunition()
newari.ammo = hasammo
self.targetlist[name] = newari
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @return #AMMOTRUCK self
function AMMOTRUCK:CheckTrucksAlive()
self:T(self.lid .. " CheckTrucksAlive")
local trucklist = self.trucklist
for _,_truck in pairs(trucklist) do
local truck = _truck -- #AMMOTRUCK.data
if truck.group and truck.group:IsAlive() then
-- everything fine
else
-- truck dead
local tgtname = truck.targetname
local targetdata = self:FindTarget(tgtname) -- #AMMOTRUCK.data
if targetdata then
if targetdata.statusquo ~= AMMOTRUCK.State.IDLE then
targetdata.statusquo = AMMOTRUCK.State.IDLE
end
end
self.trucklist[truck.name] = nil
end
end
-- new arrivals?
local trucktable = self.truckset:GetSetObjects() --#table
for _,_truck in pairs(trucktable) do
local truck = _truck -- Wrapper.Group#GROUP
if truck and truck:IsAlive() and not self.trucklist[truck:GetName()] then
local name = truck:GetName()
local newtruck = {} -- #AMMOTRUCK.data
newtruck.name = name
newtruck.group = truck
if self.hasarmygroup then
-- is (not) already ARMYGROUP?
if truck.ClassName and truck.ClassName == "GROUP" then
local trucker = ARMYGROUP:New(truck)
trucker:Activate()
newtruck.group = trucker
end
end
newtruck.statusquo = AMMOTRUCK.State.IDLE
newtruck.timestamp = timer.getAbsTime()
newtruck.coordinate = truck:GetCoordinate()
newtruck.reloads = self.reloads or 5
self.trucklist[name] = newtruck
end
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterStart(From, Event, To)
self:T({From, Event, To})
if ARMYGROUP and self.usearmygroup then
self.hasarmygroup = true
else
self.hasarmygroup = false
end
if self.debug then
BASE:TraceOn()
BASE:TraceClass("AMMOTRUCK")
end
self:CheckTargetsAlive()
self:CheckTrucksAlive()
self:__Monitor(-30)
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterMonitor(From, Event, To)
self:T({From, Event, To})
self:CheckTargetsAlive()
self:CheckTrucksAlive()
-- update ammo state
local remunition = false
local remunitionqueue = {}
local waitingtargets = {}
for _,_ari in pairs(self.targetlist) do
local data = _ari -- #AMMOTRUCK.data
if data.group and data.group:IsAlive() then
data.ammo = self:GetAmmoStatus(data.group)
data.timestamp = timer.getAbsTime()
local text = string.format("Ari %s | Ammo %d | State %s",data.name,data.ammo,data.statusquo)
self:T(text)
if data.ammo <= self.ammothreshold and (data.statusquo == AMMOTRUCK.State.IDLE or data.statusquo == AMMOTRUCK.State.OUTOFAMMO) then
-- add to remu queue
data.statusquo = AMMOTRUCK.State.OUTOFAMMO
remunitionqueue[#remunitionqueue+1] = data
remunition = true
elseif data.statusquo == AMMOTRUCK.State.WAITING then
waitingtargets[#waitingtargets+1] = data
end
else
self.targetlist[data.name] = nil
end
end
-- sort trucks in buckets
local idletrucks = {}
local drivingtrucks = {}
local unloadingtrucks = {}
local arrivedtrucks = {}
local returningtrucks = {}
local found = false
for _,_truckdata in pairs(self.trucklist) do
local data = _truckdata -- #AMMOTRUCK.data
if data.group and data.group:IsAlive() then
-- check state
local text = string.format("Truck %s | State %s",data.name,data.statusquo)
self:T(text)
if data.statusquo == AMMOTRUCK.State.IDLE then
idletrucks[#idletrucks+1] = data
found = true
elseif data.statusquo == AMMOTRUCK.State.DRIVING then
drivingtrucks[#drivingtrucks+1] = data
elseif data.statusquo == AMMOTRUCK.State.ARRIVED then
arrivedtrucks[#arrivedtrucks+1] = data
elseif data.statusquo == AMMOTRUCK.State.UNLOADING then
unloadingtrucks[#unloadingtrucks+1] = data
elseif data.statusquo == AMMOTRUCK.State.RETURNING then
returningtrucks[#returningtrucks+1] = data
if data.reloads > 0 or data.reloads == -1 then
idletrucks[#idletrucks+1] = data
found = true
end
end
else
self.truckset[data.name] = nil
end
end
-- see if we can/need route one
local n=0
if found and remunition then
-- match
--local match = false
for _,_truckdata in pairs(idletrucks) do
local truckdata = _truckdata -- #AMMOTRUCK.data
local truckcoord = truckdata.group:GetCoordinate() -- Core.Point#COORDINATE
for _,_aridata in pairs(remunitionqueue) do
local aridata = _aridata -- #AMMOTRUCK.data
local aricoord = aridata.coordinate
local distance = truckcoord:Get2DDistance(aricoord)
if distance <= self.remunidist and aridata.statusquo == AMMOTRUCK.State.OUTOFAMMO and n <= #idletrucks then
n = n + 1
aridata.statusquo = AMMOTRUCK.State.REQUESTED
self:__RouteTruck(n*5,truckdata,aridata)
break
end
end
end
end
-- check driving trucks
if #drivingtrucks > 0 then
self:CheckDrivingTrucks(drivingtrucks)
end
-- check arrived trucks
if #arrivedtrucks > 0 then
self:CheckArrivedTrucks(arrivedtrucks)
end
-- check unloading trucks
if #unloadingtrucks > 0 then
self:CheckUnloadingTrucks(unloadingtrucks)
end
-- check returningtrucks trucks
if #returningtrucks > 0 then
self:CheckReturningTrucks(returningtrucks)
end
-- check waiting targets
if #waitingtargets > 0 then
self:CheckWaitingTargets(waitingtargets)
end
self:__Monitor(self.monitor)
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param #AMMOTRUCK.data Truckdata
-- @param #AMMOTRUCK.data Aridata
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterRouteTruck(From, Event, To, Truckdata, Aridata)
self:T({From, Event, To, Truckdata.name, Aridata.name})
local truckdata = Truckdata -- #AMMOTRUCK.data
local aridata = Aridata -- #AMMOTRUCK.data
local tgtgrp = aridata.group
local tgtzone = ZONE_GROUP:New(aridata.name,tgtgrp,30)
local tgtcoord = tgtzone:GetRandomCoordinate(15)
if self.hasarmygroup then
local mission = AUFTRAG:NewONGUARD(tgtcoord)
local oldmission = truckdata.group:GetMissionCurrent()
if oldmission then oldmission:Cancel() end
mission:SetTime(5)
mission:SetTeleport(false)
truckdata.group:AddMission(mission)
elseif self.routeonroad then
truckdata.group:RouteGroundOnRoad(tgtcoord,30)
else
truckdata.group:RouteGroundTo(tgtcoord,30)
end
truckdata.statusquo = AMMOTRUCK.State.DRIVING
truckdata.targetgroup = tgtgrp
truckdata.targetname = aridata.name
truckdata.targetcoordinate = tgtcoord
aridata.statusquo = AMMOTRUCK.State.WAITING
aridata.timestamp = timer.getAbsTime()
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param #AMMOTRUCK.data Truckdata
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterTruckUnloading(From, Event, To, Truckdata)
local m = MESSAGE:New("Truck "..Truckdata.name.." unloading!",15,"AmmoTruck"):ToCoalitionIf(self.coalition,self.debug)
local truck = Truckdata -- Functional.AmmoTruck#AMMOTRUCK.data
local coord = truck.group:GetCoordinate()
local heading = truck.group:GetHeading()
heading = heading < 180 and (360-heading) or (heading - 180)
local cid = self.coalition == coalition.side.BLUE and country.id.USA or country.id.RUSSIA
cid = self.coalition == coalition.side.NEUTRAL and country.id.UN_PEACEKEEPERS or cid
local ammo = {}
for i=1,5 do
ammo[i] = SPAWNSTATIC:NewFromType("ammo_cargo","Cargos",cid)
:InitCoordinate(coord:Translate((15+((i-1)*4)),heading))
:Spawn(0,"AmmoCrate-"..math.random(1,10000))
end
local function destroyammo(ammo)
for _,_crate in pairs(ammo) do
_crate:Destroy(false)
end
end
local scheduler = SCHEDULER:New(nil,destroyammo,{ammo},self.waitingtime)
-- one reload less
if truck.reloads ~= -1 then
truck.reloads = truck.reloads - 1
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param #AMMOTRUCK.data Truck
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterTruckReturning(From, Event, To, Truck)
self:T({From, Event, To, Truck.name})
-- route home
local truckdata = Truck -- #AMMOTRUCK.data
local tgtzone = self.homezone
local tgtcoord = tgtzone:GetRandomCoordinate()
if self.hasarmygroup then
local mission = AUFTRAG:NewONGUARD(tgtcoord)
local oldmission = truckdata.group:GetMissionCurrent()
if oldmission then oldmission:Cancel() end
mission:SetTime(5)
mission:SetTeleport(false)
truckdata.group:AddMission(mission)
elseif self.routeonroad then
truckdata.group:RouteGroundOnRoad(tgtcoord,30,1,"Cone")
else
truckdata.group:RouteGroundTo(tgtcoord,30,"Cone",1)
end
return self
end
---
-- @param #AMMOTRUCK self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @return #AMMOTRUCK self
function AMMOTRUCK:onafterStop(From, Event, To)
self:T({From, Event, To})
return self
end
@@ -3547,6 +3547,8 @@ end
function ARTY:onafterRespawn(Controllable, From, Event, To) function ARTY:onafterRespawn(Controllable, From, Event, To)
self:_EventFromTo("onafterRespawn", Event, From, To) self:_EventFromTo("onafterRespawn", Event, From, To)
env.info("FF Respawning arty group")
local group=self.Controllable --Wrapper.Group#GROUP local group=self.Controllable --Wrapper.Group#GROUP
-- Respawn group. -- Respawn group.
File diff suppressed because it is too large Load Diff
+2 -1
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.
@@ -1420,7 +1420,7 @@ function SCORING:ReportDetailedPlayerHits( PlayerName )
Penalty = Penalty + UnitData.Penalty Penalty = Penalty + UnitData.Penalty
PenaltyHit = UnitData.PenaltyHit PenaltyHit = UnitData.PenaltyHit
end end
local ScoreMessageHit = string.format( "%s:%d ", CategoryName, Score - Penalty ) local ScoreMessageHit = string.format( "%s: %d ", CategoryName, Score - Penalty )
self:T( ScoreMessageHit ) self:T( ScoreMessageHit )
ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit
PlayerScore = PlayerScore + Score PlayerScore = PlayerScore + Score
@@ -1476,7 +1476,7 @@ function SCORING:ReportDetailedPlayerDestroys( PlayerName )
end end
end end
local ScoreMessageDestroy = string.format( " %s:%d ", CategoryName, Score - Penalty ) local ScoreMessageDestroy = string.format( " %s: %d ", CategoryName, Score - Penalty )
self:T( ScoreMessageDestroy ) self:T( ScoreMessageDestroy )
ScoreMessageDestroys = ScoreMessageDestroys .. ScoreMessageDestroy ScoreMessageDestroys = ScoreMessageDestroys .. ScoreMessageDestroy
@@ -6671,13 +6671,7 @@ function WAREHOUSE:_OnEventCrashOrDead(EventData)
self:Destroyed() self:Destroyed()
end end
if self.airbase and self.airbasename and self.airbasename==EventData.IniUnitName then if self.airbase and self.airbasename and self.airbasename==EventData.IniUnitName then
if self:IsRunwayOperational() then self:RunwayDestroyed()
-- Trigger RunwayDestroyed event (only if it is not destroyed already)
self:RunwayDestroyed()
else
-- Reset the time stamp.
self.runwaydestroyed=timer.getAbsTime()
end
end end
end end
@@ -1,4 +1,4 @@
--- **Functional (WIP)** - Base class modeling processes to achieve goals involving coalition zones. --- **Functional** - Base class that models processes to achieve goals involving a Zone for a Coalition.
-- --
-- === -- ===
-- --
+51 -84
View File
@@ -1,55 +1,54 @@
__Moose.Include( 'Scripts/Moose/Utilities/Enums.lua' ) __Moose.Include( 'Scripts/Moose/Utilities/Enums.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/FiFo.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/Profiler.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/Routines.lua' ) __Moose.Include( 'Scripts/Moose/Utilities/Routines.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/Socket.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/STTS.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/Templates.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/Utils.lua' ) __Moose.Include( 'Scripts/Moose/Utilities/Utils.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/Profiler.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/Templates.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/STTS.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/FiFo.lua' )
__Moose.Include( 'Scripts/Moose/Utilities/Socket.lua' )
__Moose.Include( 'Scripts/Moose/Core/Base.lua' ) __Moose.Include( 'Scripts/Moose/Core/Base.lua' )
__Moose.Include( 'Scripts/Moose/Core/Astar.lua' ) __Moose.Include( 'Scripts/Moose/Core/Astar.lua' )
__Moose.Include( 'Scripts/Moose/Core/Beacon.lua' ) __Moose.Include( 'Scripts/Moose/Core/Beacon.lua' )
__Moose.Include( 'Scripts/Moose/Core/Condition.lua' ) __Moose.Include( 'Scripts/Moose/Core/Condition.lua' )
__Moose.Include( 'Scripts/Moose/Core/ClientMenu.lua') __Moose.Include( 'Scripts/Moose/Core/UserFlag.lua' )
__Moose.Include( 'Scripts/Moose/Core/Database.lua' )
__Moose.Include( 'Scripts/Moose/Core/Event.lua' )
__Moose.Include( 'Scripts/Moose/Core/Fsm.lua' )
__Moose.Include( 'Scripts/Moose/Core/Goal.lua' )
__Moose.Include( 'Scripts/Moose/Core/MarkerOps_Base.lua' )
__Moose.Include( 'Scripts/Moose/Core/Menu.lua' )
__Moose.Include( 'Scripts/Moose/Core/Message.lua' )
__Moose.Include( 'Scripts/Moose/Core/Point.lua' )
__Moose.Include( 'Scripts/Moose/Core/Report.lua' ) __Moose.Include( 'Scripts/Moose/Core/Report.lua' )
__Moose.Include( 'Scripts/Moose/Core/ScheduleDispatcher.lua' )
__Moose.Include( 'Scripts/Moose/Core/Scheduler.lua' ) __Moose.Include( 'Scripts/Moose/Core/Scheduler.lua' )
__Moose.Include( 'Scripts/Moose/Core/Set.lua' ) __Moose.Include( 'Scripts/Moose/Core/ScheduleDispatcher.lua' )
__Moose.Include( 'Scripts/Moose/Core/Event.lua' )
__Moose.Include( 'Scripts/Moose/Core/Settings.lua' ) __Moose.Include( 'Scripts/Moose/Core/Settings.lua' )
__Moose.Include( 'Scripts/Moose/Core/Menu.lua' )
__Moose.Include( 'Scripts/Moose/Core/Zone.lua' )
__Moose.Include( 'Scripts/Moose/Core/Zone_Detection.lua' )
__Moose.Include( 'Scripts/Moose/Core/Database.lua' )
__Moose.Include( 'Scripts/Moose/Core/Set.lua' )
__Moose.Include( 'Scripts/Moose/Core/Point.lua' )
__Moose.Include( 'Scripts/Moose/Core/Velocity.lua' )
__Moose.Include( 'Scripts/Moose/Core/Message.lua' )
__Moose.Include( 'Scripts/Moose/Core/Fsm.lua' )
__Moose.Include( 'Scripts/Moose/Core/Spawn.lua' ) __Moose.Include( 'Scripts/Moose/Core/Spawn.lua' )
__Moose.Include( 'Scripts/Moose/Core/SpawnStatic.lua' ) __Moose.Include( 'Scripts/Moose/Core/SpawnStatic.lua' )
__Moose.Include( 'Scripts/Moose/Core/Spot.lua' )
__Moose.Include( 'Scripts/Moose/Core/TextAndSound.lua' )
__Moose.Include( 'Scripts/Moose/Core/Timer.lua' ) __Moose.Include( 'Scripts/Moose/Core/Timer.lua' )
__Moose.Include( 'Scripts/Moose/Core/UserFlag.lua' ) __Moose.Include( 'Scripts/Moose/Core/Goal.lua' )
__Moose.Include( 'Scripts/Moose/Core/Velocity.lua' ) __Moose.Include( 'Scripts/Moose/Core/Spot.lua' )
__Moose.Include( 'Scripts/Moose/Core/Zone_Detection.lua' ) __Moose.Include( 'Scripts/Moose/Core/MarkerOps_Base.lua' )
__Moose.Include( 'Scripts/Moose/Core/Zone.lua' ) __Moose.Include( 'Scripts/Moose/Core/TextAndSound.lua' )
__Moose.Include( 'Scripts/Moose/Core/Pathline.lua' ) __Moose.Include( 'Scripts/Moose/Core/Pathline.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Airbase.lua' ) __Moose.Include( 'Scripts/Moose/Wrapper/Object.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Client.lua' ) __Moose.Include( 'Scripts/Moose/Wrapper/Identifiable.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Positionable.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Controllable.lua' ) __Moose.Include( 'Scripts/Moose/Wrapper/Controllable.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Group.lua' ) __Moose.Include( 'Scripts/Moose/Wrapper/Group.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Identifiable.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Marker.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Object.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Positionable.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Scenery.lua' )
__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/Client.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Static.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Airbase.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Scenery.lua' )
__Moose.Include( 'Scripts/Moose/Wrapper/Marker.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' )
@@ -57,67 +56,35 @@ __Moose.Include( 'Scripts/Moose/Cargo/CargoSlingload.lua' )
__Moose.Include( 'Scripts/Moose/Cargo/CargoCrate.lua' ) __Moose.Include( 'Scripts/Moose/Cargo/CargoCrate.lua' )
__Moose.Include( 'Scripts/Moose/Cargo/CargoGroup.lua' ) __Moose.Include( 'Scripts/Moose/Cargo/CargoGroup.lua' )
__Moose.Include( 'Scripts/Moose/Functional/AICSAR.lua' ) __Moose.Include( 'Scripts/Moose/Functional/Scoring.lua' )
__Moose.Include( 'Scripts/Moose/Functional/AmmoTruck.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Artillery.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ATC_Ground.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Autolase.lua' )
__Moose.Include( 'Scripts/Moose/Functional/CleanUp.lua' ) __Moose.Include( 'Scripts/Moose/Functional/CleanUp.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Designate.lua' ) __Moose.Include( 'Scripts/Moose/Functional/Movement.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Sead.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Escort.lua' )
__Moose.Include( 'Scripts/Moose/Functional/MissileTrainer.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ATC_Ground.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Detection.lua' ) __Moose.Include( 'Scripts/Moose/Functional/Detection.lua' )
__Moose.Include( 'Scripts/Moose/Functional/DetectionZones.lua' ) __Moose.Include( 'Scripts/Moose/Functional/DetectionZones.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Escort.lua' ) __Moose.Include( 'Scripts/Moose/Functional/Designate.lua' )
__Moose.Include( 'Scripts/Moose/Functional/RAT.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Range.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ZoneGoal.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ZoneGoalCoalition.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ZoneCaptureCoalition.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Artillery.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Suppression.lua' )
__Moose.Include( 'Scripts/Moose/Functional/PseudoATC.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Warehouse.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Fox.lua' ) __Moose.Include( 'Scripts/Moose/Functional/Fox.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Mantis.lua' ) __Moose.Include( 'Scripts/Moose/Functional/Mantis.lua' )
__Moose.Include( 'Scripts/Moose/Functional/MissileTrainer.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Movement.lua' )
__Moose.Include( 'Scripts/Moose/Functional/PseudoATC.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Range.lua' )
__Moose.Include( 'Scripts/Moose/Functional/RAT.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Scoring.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Sead.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Shorad.lua' ) __Moose.Include( 'Scripts/Moose/Functional/Shorad.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Suppression.lua' )
__Moose.Include( 'Scripts/Moose/Functional/Warehouse.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ZoneCaptureCoalition.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ZoneGoal.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ZoneGoalCargo.lua' )
__Moose.Include( 'Scripts/Moose/Functional/ZoneGoalCoalition.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Airboss.lua' ) __Moose.Include( 'Scripts/Moose/Ops/Airboss.lua' )
__Moose.Include( 'Scripts/Moose/Ops/AirWing.lua' )
__Moose.Include( 'Scripts/Moose/Ops/ArmyGroup.lua' )
__Moose.Include( 'Scripts/Moose/Ops/ATIS.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Auftrag.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Awacs.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Brigade.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Chief.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Cohort.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Commander.lua' )
__Moose.Include( 'Scripts/Moose/Ops/CSAR.lua' )
__Moose.Include( 'Scripts/Moose/Ops/CTLD.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Fleet.lua' )
__Moose.Include( 'Scripts/Moose/Ops/FlightControl.lua' )
__Moose.Include( 'Scripts/Moose/Ops/FlightGroup.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Flotilla.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Intelligence.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Legion.lua' )
__Moose.Include( 'Scripts/Moose/Ops/NavyGroup.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Operation.lua' )
__Moose.Include( 'Scripts/Moose/Ops/OpsGroup.lua' )
__Moose.Include( 'Scripts/Moose/Ops/OpsTransport.lua' )
__Moose.Include( 'Scripts/Moose/Ops/OpsZone.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Platoon.lua' )
__Moose.Include( 'Scripts/Moose/Ops/PlayerTask.lua' )
__Moose.Include( 'Scripts/Moose/Ops/PlayerRecce.lua' )
__Moose.Include( 'Scripts/Moose/Ops/RecoveryTanker.lua' ) __Moose.Include( 'Scripts/Moose/Ops/RecoveryTanker.lua' )
__Moose.Include( 'Scripts/Moose/Ops/RescueHelo.lua' ) __Moose.Include( 'Scripts/Moose/Ops/RescueHelo.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Squadron.lua' ) __Moose.Include( 'Scripts/Moose/Ops/ATIS.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Target.lua' ) __Moose.Include( 'Scripts/Moose/Ops/CTLD.lua' )
__Moose.Include( 'Scripts/Moose/Ops/CSAR.lua' )
__Moose.Include( 'Scripts/Moose/Navigation/Navaid.lua' )
__Moose.Include( 'Scripts/Moose/Navigation/NavFix.lua' )
__Moose.Include( 'Scripts/Moose/Navigation/FlightPlan.lua' )
__Moose.Include( 'Scripts/Moose/AI/AI_Balancer.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Balancer.lua' )
__Moose.Include( 'Scripts/Moose/AI/AI_Air.lua' ) __Moose.Include( 'Scripts/Moose/AI/AI_Air.lua' )
@@ -156,12 +123,12 @@ __Moose.Include( 'Scripts/Moose/Actions/Act_Route.lua' )
__Moose.Include( 'Scripts/Moose/Actions/Act_Account.lua' ) __Moose.Include( 'Scripts/Moose/Actions/Act_Account.lua' )
__Moose.Include( 'Scripts/Moose/Actions/Act_Assist.lua' ) __Moose.Include( 'Scripts/Moose/Actions/Act_Assist.lua' )
__Moose.Include( 'Scripts/Moose/Sound/UserSound.lua' )
__Moose.Include( 'Scripts/Moose/Sound/SoundOutput.lua' )
__Moose.Include( 'Scripts/Moose/Sound/Radio.lua' ) __Moose.Include( 'Scripts/Moose/Sound/Radio.lua' )
__Moose.Include( 'Scripts/Moose/Sound/RadioQueue.lua' ) __Moose.Include( 'Scripts/Moose/Sound/RadioQueue.lua' )
__Moose.Include( 'Scripts/Moose/Sound/RadioSpeech.lua' ) __Moose.Include( 'Scripts/Moose/Sound/RadioSpeech.lua' )
__Moose.Include( 'Scripts/Moose/Sound/SoundOutput.lua' )
__Moose.Include( 'Scripts/Moose/Sound/SRS.lua' ) __Moose.Include( 'Scripts/Moose/Sound/SRS.lua' )
__Moose.Include( 'Scripts/Moose/Sound/UserSound.lua' )
__Moose.Include( 'Scripts/Moose/Tasking/CommandCenter.lua' ) __Moose.Include( 'Scripts/Moose/Tasking/CommandCenter.lua' )
__Moose.Include( 'Scripts/Moose/Tasking/Mission.lua' ) __Moose.Include( 'Scripts/Moose/Tasking/Mission.lua' )
@@ -1,203 +0,0 @@
--- **NAVIGATION** - Flight Plan.
--
-- **Main Features:**
--
-- * Manage navigation aids
-- * VOR, NDB
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Ops%20-%20FlightPlan).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Navigation.FlightPlan
-- @image NAVIGATION_FlightPlan.png
--- FLIGHTPLAN class.
-- @type FLIGHTPLAN
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @field #table fixes Navigation fixes.
-- @field Wrapper.Airbase#AIRBASE departureAirbase Departure airbase.
-- @field Wrapper.Airbase#AIRBASE destinationAirbase Destination airbase.
-- @field #number altitudeCruiseMin Minimum cruise altitude in feet MSL.
-- @field #number altitudeCruiseMax Maximum cruise altitude in feet MSL.
-- @extends Core.Base#BASE
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
--
-- ===
--
-- # The FLIGHTPLAN Concept
--
-- A FLIGHTPLAN consists of one or multiple FLOTILLAs. These flotillas "live" in a WAREHOUSE that has a phyiscal struction (STATIC or UNIT) and can be captured or destroyed.
--
-- # Basic Setup
--
-- A new `FLIGHTPLAN` object can be created with the @{#FLIGHTPLAN.New}(`WarehouseName`, `FleetName`) function, where `WarehouseName` is the name of the static or unit object hosting the fleet
-- and `FleetName` is the name you want to give the fleet. This must be *unique*!
--
-- myFlightplan=FLIGHTPLAN:New("Plan A")
-- myFleet:SetPortZone(ZonePort1stFleet)
-- myFleet:Start()
--
-- A fleet needs a *port zone*, which is set via the @{#FLIGHTPLAN.SetPortZone}(`PortZone`) function. This is the zone where the naval assets are spawned and return to.
--
-- Finally, the fleet needs to be started using the @{#FLIGHTPLAN.Start}() function. If the fleet is not started, it will not process any requests.
--
-- @field #FLIGHTPLAN
FLIGHTPLAN = {
ClassName = "FLIGHTPLAN",
verbose = 0,
fixes = {}
}
--- Type of navaid
-- @type FLIGHTPLAN.Type
-- @field #string VOR VOR
-- @field #string NDB NDB
FLIGHTPLAN.TYPE={
VOR="VOR",
NDB="NDB",
}
--- FLIGHTPLAN class version.
-- @field #string version
FLIGHTPLAN.version="0.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot...
-- TODO: How to handle the FLIGHTGROUP:_LandAtAirBase
-- TODO: Do we always need a holding pattern? https://www.faa.gov/air_traffic/publications/atpubs/aip_html/part2_enr_section_1.5.html#:~:text=If%20no%20holding%20pattern%20is,than%20that%20desired%20by%20ATC.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new FLIGHTPLAN instance.
-- @param #FLIGHTPLAN self
-- @param #string Name Name of this flight plan.
-- @return #FLIGHTPLAN self
function FLIGHTPLAN:New(Name)
-- Inherit everything from SCENERY class.
self=BASE:Inherit(self, BASE:New()) -- #FLIGHTPLAN
-- Set alias.
self.alias=tostring(Name)
-- Set some string id for output to DCS.log file.
self.lid=string.format("FLIGHTPLAN %s | ", self.alias)
-- Debug info.
self:I(self.lid..string.format("Created FLIGHTPLAN!"))
return self
end
--- Create a new FLIGHTPLAN instance from another FLIGHTPLAN acting as blue print.
-- The newly created flight plan is deep copied from the given one.
-- @param #FLIGHTPLAN self
-- @param #FLIGHTPLAN FlightPlan Blue print of the flight plan to copy.
-- @return #FLIGHTPLAN self
function FLIGHTPLAN:NewFromFlightPlan(FlightPlan)
self=UTILS.DeepCopy(FlightPlan)
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add navigation fix to the flight plan.
-- @param #FLIGHTPLAN self
-- @param Navigation.NavFix#NAVFIX NavFix The nav fix.
-- @return #FLIGHTPLAN self
function FLIGHTPLAN:AddNavFix(NavFix)
table.insert(self.fixes, NavFix)
return self
end
--- Set depature airbase.
-- @param #FLIGHTPLAN self
-- @param #string AirbaseName Name of the airbase or AIRBASE object.
-- @return #FLIGHTPLAN self
function FLIGHTPLAN:SetDepartureAirbase(AirbaseName)
self.departureAirbase=AIRBASE:FindByName(AirbaseName)
return self
end
--- Set destination airbase.
-- @param #FLIGHTPLAN self
-- @param #string AirbaseName Name of the airbase or AIRBASE object.
-- @return #FLIGHTPLAN self
function FLIGHTPLAN:SetDestinationAirbase(AirbaseName)
self.destinationAirbase=AIRBASE:FindByName(AirbaseName)
return self
end
--- Set cruise altitude.
-- @param #FLIGHTPLAN self
-- @param #number AltMin Minimum altitude in feet MSL.
-- @param #number AltMax Maximum altitude in feet MSL. Default is `AltMin`.
-- @return #FLIGHTPLAN self
function FLIGHTPLAN:SetCruiseAltitude(AltMin, AltMax)
self.altitudeCruiseMin=AltMin
self.altitudeCruiseMax=AltMax or self.altitudeCruiseMin
return self
end
--- Get the name of this flight plan.
-- @param #FLIGHTPLAN self
-- @return #string The name.
function FLIGHTPLAN:GetName()
return self.alias
end
--- Get cruise altitude. This returns a random altitude between the set min/max cruise altitudes.
-- @param #FLIGHTPLAN self
-- @return #number Cruise altitude in feet MSL.
function FLIGHTPLAN:GetCruiseAltitude()
local alt=10000
if self.altitudeCruiseMin and self.altitudeCruiseMax then
alt=math.random(self.altitudeCruiseMin, self.altitudeCruiseMax)
elseif self.altitudeCruiseMin then
alt=self.altitudeCruiseMin
elseif self.altitudeCruiseMax then
alt=self.altitudeCruiseMax
end
return alt
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Private Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1,212 +0,0 @@
--- **NAVIGATION** - Navigation Airspace Fix.
--
-- **Main Features:**
--
-- * Stuff
-- * More Stuff
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20NavFix).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Navigation.NavFix
-- @image NAVIGATION_NavFix.png
--- NAVFIX class.
-- @type NAVFIX
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @field #string name Name of the fix.
-- @field Core.Point#COORDINATE coordinate Coordinate of the fix.
-- @field Wrapper.Marker#MARKER marker Marker of fix on F10 map.
-- @field #boolean isCompulsory Is this a compulsory fix.
-- @field #boolean isFlyover Is this a fly over fix.
-- @field #boolean isIAF Is initial approach fix (IAF).
-- @field #boolean isIF Is intermediate fix (IF).
--
-- @extends Core.Base#BASE
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
--
-- ===
--
-- # The NAVFIX Concept
--
-- The NAVFIX class has a great concept!
--
-- # Basic Setup
--
-- A new `NAVFIX` object can be created with the @{#NAVFIX.New}() function.
--
-- myTemplate=NAVFIX:New()
-- myTemplate:SetXYZ(X, Y, Z)
--
-- This is how it works.
--
-- @field #NAVFIX
NAVFIX = {
ClassName = "NAVFIX",
verbose = 0,
}
--- Type of navaid
-- @type NAVFIX.Type
-- @field #string VOR VOR
-- @field #string NDB NDB
NAVFIX.Type={
VOR="VOR",
NDB="NDB",
}
--- NAVFIX class version.
-- @field #string version
NAVFIX.version="0.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot...
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new NAVFIX class instance.
-- @param #NAVFIX self
-- @return #NAVFIX self
function NAVFIX:New(Coordinate, Name)
-- Inherit everything from SCENERY class.
self=BASE:Inherit(self, BASE:New()) -- #NAVFIX
self.coordinate=Coordinate
self.name=Name
self.marker=MARKER:New(Coordinate, self:_GetMarkerText())
self.marker:ToAll()
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Set minimum altitude.
-- @param #NAVFIX self
-- @param #number Altitude Min altitude in feet.
-- @return #NAVFIX self
function NAVFIX:SetAltMin(Altitude)
self.altMin=Altitude
return self
end
--- Set maximum altitude.
-- @param #NAVFIX self
-- @param #number Altitude Max altitude in feet.
-- @return #NAVFIX self
function NAVFIX:SetAltMax(Altitude)
self.altMax=Altitude
return self
end
--- Set whether this fix is compulsory.
-- @param #NAVFIX self
-- @param #boolean Compulsory If `true`, this is a compusory fix. If `false` or nil, it is non-compulsory.
-- @return #NAVFIX self
function NAVFIX:SetCompulsory(Compulsory)
self.isCompulsory=Compulsory
return self
end
--- Set whether this fix is compulsory.
-- @param #NAVFIX self
-- @param #boolean FlyOver If `true`, this is a fly over fix. If `false` or nil, it is not.
-- @return #NAVFIX self
function NAVFIX:SetFlyOver(FlyOver)
self.isFlyover=FlyOver
return self
end
--- Set whether this is the intermediate fix.
-- @param #NAVFIX self
-- @param #boolean IntermediateFix If `true`, this is an intermediate fix.
-- @return #NAVFIX self
function NAVFIX:SetIntermediateFix(IntermediateFix)
self.isIF=IntermediateFix
return self
end
--- Set whether this is an initial approach fix (IAF).
-- @param #NAVFIX self
-- @param #boolean IntermediateFix If `true`, this is an intermediate fix.
-- @return #NAVFIX self
function NAVFIX:SetInitialApproachFix(IntermediateFix)
self.isIAF=IntermediateFix
return self
end
--- Get the altitude in feet MSL.
-- @param #NAVFIX self
-- @return #number Altitude in feet MSL. Can be `#nil`
function NAVFIX:GetAltitude()
local alt=nil
if self.altMin and self.altMax then
alt=math.random(self.altMin, self.altMax)
elseif self.altMin then
alt=self.altMin
elseif self.altMax then
alt=self.altMax
end
return alt
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Private Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Get text displayed in the F10 marker.
-- @param #NAVFIX self
-- @return #string Marker text.
function NAVFIX:_GetMarkerText()
local altmin=self.altMin and tostring(self.altMin) or ""
local altmax=self.altMax and tostring(self.altMax) or ""
local speedmin=self.speedMin and tostring(self.speedMin) or ""
local speedmax=self.speedMax and tostring(self.speedMax) or ""
local text=string.format("NAVFIX %s", self.name)
if self.isIAF then
text=text..string.format(" (IAF)")
end
if self.isIF then
text=text..string.format(" (IF)")
end
text=text..string.format("\nAltitude: %s - %s", altmin, altmax)
text=text..string.format("\nSpeed: %s - %s", speedmin, speedmax)
text=text..string.format("\nCompulsory: %s", tostring(self.isCompulsory))
text=text..string.format("\nFly Over: %s", tostring(self.isFlyover))
return text
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1,172 +0,0 @@
--- **Navigation** - Navigation aid.
--
-- **Main Features:**
--
-- * Manage navigation aids
-- * VOR, NDB
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Navaid).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Navigation.Navaid
-- @image Navigation_Navaid.png
--- NAVAID class.
-- @type NAVAID
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @extends Core.Base#BASE
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
--
-- ===
--
-- # The NAVAID Concept
--
-- A NAVAID consists of one or multiple FLOTILLAs. These flotillas "live" in a WAREHOUSE that has a phyiscal struction (STATIC or UNIT) and can be captured or destroyed.
--
-- # Basic Setup
--
-- A new `NAVAID` object can be created with the @{#NAVAID.New}(`WarehouseName`, `FleetName`) function, where `WarehouseName` is the name of the static or unit object hosting the fleet
-- and `FleetName` is the name you want to give the fleet. This must be *unique*!
--
-- myFleet=NAVAID:New("myWarehouseName", "1st Fleet")
-- myFleet:SetPortZone(ZonePort1stFleet)
-- myFleet:Start()
--
-- A fleet needs a *port zone*, which is set via the @{#NAVAID.SetPortZone}(`PortZone`) function. This is the zone where the naval assets are spawned and return to.
--
-- Finally, the fleet needs to be started using the @{#NAVAID.Start}() function. If the fleet is not started, it will not process any requests.
--
-- @field #NAVAID
NAVAID = {
ClassName = "NAVAID",
verbose = 0,
}
--- Type of navaid
-- @type NAVAID.Type
-- @field #string VOR VOR
-- @field #string NDB NDB
NAVAID.TYPE={
VOR="VOR",
NDB="NDB",
}
--- NAVAID class version.
-- @field #string version
NAVAID.version="0.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot...
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new NAVAID class instance.
-- @param #NAVAID self
-- @param #string ZoneName Name of the zone to scan the scenery.
-- @param #string SceneryName Name of the scenery object.
-- @param #string Type Type of Navaid.
-- @return #NAVAID self
function NAVAID:New(ZoneName, SceneryName, Type)
-- Inherit everything from SCENERY class.
self=BASE:Inherit(self, BASE:New()) -- #NAVAID
self.zone=ZONE:FindByName(ZoneName)
self.coordinate=self.zone:GetCoordinate()
if SceneryName then
self.scenery=SCENERY:FindByNameInZone(SceneryName, ZoneName)
if not self.scenery then
self:E("ERROR: Could not find scenery object %s in zone %s", SceneryName, ZoneName)
end
end
self.alias=string.format("%s %s %s", tostring(ZoneName), tostring(SceneryName), tostring(Type))
-- Set some string id for output to DCS.log file.
self.lid=string.format("NAVAID %s | ", self.alias)
self:I(self.lid..string.format("Created NAVAID!"))
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Set frequency.
-- @param #NAVAID self
-- @param #number Frequency Frequency in Hz.
-- @return #NAVAID self
function NAVAID:SetFrequency(Frequency)
self.frequency=Frequency
return self
end
--- Set channel.
-- @param #NAVAID self
-- @param #number Channel
-- @param #string Band
-- @return #NAVAID self
function NAVAID:SetChannel(Channel, Band)
self.channel=Channel
self.band=Band
return self
end
--- Add marker the NAVAID on the F10 map.
-- @param #NAVAID self
-- @return #NAVAID self
function NAVAID:AddMarker()
local text=string.format("I am a NAVAID!")
self.markID=self.coordinate:MarkToAll(text, true)
return self
end
--- Remove marker of the NAVAID from the F10 map.
-- @param #NAVAID self
-- @return #NAVAID self
function NAVAID:DelMarker()
if self.markID then
UTILS.RemoveMark(self.markID)
end
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Private Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1,108 +0,0 @@
--- **NAVIGATION** - Template.
--
-- **Main Features:**
--
-- * Stuff
-- * More Stuff
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Template).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Navigation.Template
-- @image NAVIGATION_Template.png
--- TEMPLATE class.
-- @type TEMPLATE
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @extends Core.Base#BASE
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
--
-- ===
--
-- # The TEMPLATE Concept
--
-- The TEMPLATE class has a great concept!
--
-- # Basic Setup
--
-- A new `TEMPLATE` object can be created with the @{#TEMPLATE.New}() function.
--
-- myTemplate=TEMPLATE:New()
-- myTemplate:SetXYZ(X, Y, Z)
--
-- This is how it works.
--
-- @field #TEMPLATE
TEMPLATE = {
ClassName = "TEMPLATE",
verbose = 0,
}
--- Type of navaid
-- @type TEMPLATE.Type
-- @field #string VOR VOR
-- @field #string NDB NDB
TEMPLATE.TYPE={
VOR="VOR",
NDB="NDB",
}
--- TEMPLATE class version.
-- @field #string version
TEMPLATE.version="0.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot...
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new TEMPLATE class instance.
-- @param #TEMPLATE self
-- @return #TEMPLATE self
function TEMPLATE:New()
-- Inherit everything from SCENERY class.
self=BASE:Inherit(self, BASE:New()) -- #TEMPLATE
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Set frequency.
-- @param #TEMPLATE self
-- @param #number Frequency Frequency in Hz.
-- @return #TEMPLATE self
function TEMPLATE:SetFrequency(Frequency)
self.frequency=Frequency
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Private Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+34 -19
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
@@ -419,6 +420,8 @@ ATIS.RunwayM2T = {
TheChannel = -10, TheChannel = -10,
Syria = 5, Syria = 5,
MarianaIslands = 2, MarianaIslands = 2,
Falklands = 12,
Sinai = 5,
} }
--- Whether ICAO phraseology is used for ATIS broadcasts. --- Whether ICAO phraseology is used for ATIS broadcasts.
@@ -430,6 +433,8 @@ ATIS.RunwayM2T = {
-- @field #boolean TheChannel true. -- @field #boolean TheChannel true.
-- @field #boolean Syria true. -- @field #boolean Syria true.
-- @field #boolean MarianaIslands true. -- @field #boolean MarianaIslands true.
-- @field #boolean Falklands true.
-- @field #boolean Sinai true.
ATIS.ICAOPhraseology = { ATIS.ICAOPhraseology = {
Caucasus = true, Caucasus = true,
Nevada = false, Nevada = false,
@@ -437,7 +442,9 @@ ATIS.ICAOPhraseology = {
PersianGulf = true, PersianGulf = true,
TheChannel = true, TheChannel = true,
Syria = true, Syria = true,
MarianaIslands = true MarianaIslands = true,
Falklands = true,
Sinai = true,
} }
--- Nav point data. --- Nav point data.
@@ -609,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
@@ -1272,6 +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: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
@@ -1333,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()
@@ -1355,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
@@ -1369,25 +1378,26 @@ 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()
else
if #self.radioqueue.queue == 0 then
self:T( self.lid .. string.format( "Radio queue empty. Repeating message." ) )
self:Broadcast() self:Broadcast()
else else
self:T2( self.lid .. string.format( "Radio queue %d transmissions queued.", #self.radioqueue.queue ) )
if #self.radioqueue.queue == 0 then
self:T( self.lid .. string.format( "Radio queue empty. Repeating message." ) )
self:Broadcast()
else
self:T2( self.lid .. string.format( "Radio queue %d transmissions queued.", #self.radioqueue.queue ) )
end
end 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
@@ -1397,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()
@@ -1823,7 +1833,10 @@ function ATIS:onafterBroadcast( From, Event, To )
-- Airbase name -- Airbase name
subtitle = string.format( "%s", self.airbasename ) subtitle = string.format( "%s", self.airbasename )
if (not self.ATISforFARPs) and self.airbasename:find( "AFB" ) == nil and self.airbasename:find( "Airport" ) == nil and self.airbasename:find( "Airstrip" ) == nil and self.airbasename:find( "airfield" ) == nil and self.airbasename:find( "AB" ) == nil then if (not self.ATISforFARPs) and self.airbasename:find( "AFB" ) == nil and self.airbasename:find( "Airport" ) == nil
and self.airbasename:find( "Airstrip" ) == nil and self.airbasename:find( "airfield" ) == nil and self.airbasename:find( "AB" ) == nil
and self.airbasename:find( "Field" ) == nil
then
subtitle = subtitle .. " Airport" subtitle = subtitle .. " Airport"
end end
if not self.useSRS then if not self.useSRS then
@@ -2146,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
@@ -2407,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
File diff suppressed because it is too large Load Diff
+143 -404
View File
@@ -152,16 +152,12 @@
-- @field #boolean ICLSon Automatic ICLS is activated. -- @field #boolean ICLSon Automatic ICLS is activated.
-- @field #number ICLSchannel ICLS channel. -- @field #number ICLSchannel ICLS channel.
-- @field #string ICLSmorse ICLS morse code, e.g. "STN". -- @field #string ICLSmorse ICLS morse code, e.g. "STN".
-- @field #AIRBOSS.Radio PilotRadio Radio for Pilot calls.
-- @field #AIRBOSS.Radio LSORadio Radio for LSO calls. -- @field #AIRBOSS.Radio LSORadio Radio for LSO calls.
-- @field #number LSOFreq LSO radio frequency in MHz. -- @field #number LSOFreq LSO radio frequency in MHz.
-- @field #string LSOModu LSO radio modulation "AM" or "FM". -- @field #string LSOModu LSO radio modulation "AM" or "FM".
-- @field #AIRBOSS.Radio MarshalRadio Radio for carrier calls. -- @field #AIRBOSS.Radio MarshalRadio Radio for carrier calls.
-- @field #number MarshalFreq Marshal radio frequency in MHz. -- @field #number MarshalFreq Marshal radio frequency in MHz.
-- @field #string MarshalModu Marshal radio modulation "AM" or "FM". -- @field #string MarshalModu Marshal radio modulation "AM" or "FM".
-- @field #AIRBOSS.Radio AirbossRadio Radio for carrier calls.
-- @field #number AirbossFreq Airboss radio frequency in MHz.
-- @field #string AirbossModu Airboss radio modulation "AM" or "FM".
-- @field #number TowerFreq Tower radio frequency in MHz. -- @field #number TowerFreq Tower radio frequency in MHz.
-- @field Core.Scheduler#SCHEDULER radiotimer Radio queue scheduler. -- @field Core.Scheduler#SCHEDULER radiotimer Radio queue scheduler.
-- @field Core.Zone#ZONE_UNIT zoneCCA Carrier controlled area (CCA), i.e. a zone of 50 NM radius around the carrier. -- @field Core.Zone#ZONE_UNIT zoneCCA Carrier controlled area (CCA), i.e. a zone of 50 NM radius around the carrier.
@@ -1735,10 +1731,6 @@ AIRBOSS.Difficulty = {
-- @field #table trapsheet Groove data table recorded every 0.5 seconds. -- @field #table trapsheet Groove data table recorded every 0.5 seconds.
-- @field #boolean trapon If true, save trap sheets. -- @field #boolean trapon If true, save trap sheets.
-- @field #string debriefschedulerID Debrief scheduler ID. -- @field #string debriefschedulerID Debrief scheduler ID.
--
-- @field Sound.SRS#MSRS SRS
-- @field Sound.SRS#MSRSQUEUE SRSQ
--
-- @extends #AIRBOSS.FlightGroup -- @extends #AIRBOSS.FlightGroup
--- Main group level radio menu: F10 Other/Airboss. --- Main group level radio menu: F10 Other/Airboss.
@@ -1751,7 +1743,7 @@ AIRBOSS.MenuF10Root = nil
--- Airboss class version. --- Airboss class version.
-- @field #string version -- @field #string version
AIRBOSS.version = "1.3.2" AIRBOSS.version = "1.3.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1884,7 +1876,6 @@ function AIRBOSS:New( carriername, alias )
-- Set up Airboss radio. -- Set up Airboss radio.
self:SetMarshalRadio() self:SetMarshalRadio()
self:SetAirbossRadio()
-- Set up LSO radio. -- Set up LSO radio.
self:SetLSORadio() self:SetLSORadio()
@@ -3052,56 +3043,12 @@ function AIRBOSS:SetBeaconRefresh( TimeInterval )
return self return self
end end
--- Set up SRS for usage without sound files
-- @param #AIRBOSS self
-- @param #string PathToSRS Path to SRS folder, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone".
-- @param #number Port Port of the SRS server, defaults to 5002.
-- @param #string Culture (Optional, Airboss Culture) Culture, defaults to "en-US".
-- @param #string Gender (Optional, Airboss Gender) Gender, e.g. "male" or "female". Defaults to "male".
-- @param #string Voice (Optional, Airboss Voice) Set to use a specific voice. Will **override gender and culture** settings.
-- @param #string GoogleCreds (Optional) Path to Google credentials, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourgooglekey.json".
-- @param #number Volume (Optional) E.g. 0.75. Defaults to 1.0 (loudest).
-- @param #table AltBackend (Optional) See MSRS for details.
-- @return #AIRBOSS self
function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volume,AltBackend)
-- SRS
local Frequency = self.AirbossRadio.frequency
local Modulation = self.AirbossRadio.modulation
self.SRS = MSRS:New(PathToSRS,Frequency,Modulation,Volume,AltBackend)
self.SRS:SetCoalition(self:GetCoalition())
self.SRS:SetCoordinate(self:GetCoordinate())
self.SRS:SetCulture(Culture or "en-US")
--self.SRS:SetFrequencies(Frequencies)
self.SRS:SetGender(Gender or "male")
self.SRS:SetPath(PathToSRS)
self.SRS:SetPort(Port or 5002)
self.SRS:SetLabel(self.AirbossRadio.alias or "AIRBOSS")
--self.SRS:SetModulations(Modulations)
if GoogleCreds then
self.SRS:SetGoogle(GoogleCreds)
end
if Voice then
self.SRS:SetVoice(Voice)
end
self.SRS:SetVolume(Volume or 1.0)
-- SRSQUEUE
self.SRSQ = MSRSQUEUE:New("AIRBOSS")
self.SRSQ:SetTransmitOnlyWithPlayers(true)
if not self.PilotRadio then
self:SetSRSPilotVoice()
end
return self
end
--- Set LSO radio frequency and modulation. Default frequency is 264 MHz AM. --- Set LSO radio frequency and modulation. Default frequency is 264 MHz AM.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param #number Frequency (Optional) Frequency in MHz. Default 264 MHz. -- @param #number Frequency (Optional) Frequency in MHz. Default 264 MHz.
-- @param #string Modulation (Optional) Modulation, "AM" or "FM". Default "AM". -- @param #string Modulation (Optional) Modulation, "AM" or "FM". Default "AM".
-- @param #string Voice (Optional) SRS specific voice
-- @param #string Gender (Optional) SRS specific gender
-- @param #string Culture (Optional) SRS specific culture
-- @return #AIRBOSS self -- @return #AIRBOSS self
function AIRBOSS:SetLSORadio( Frequency, Modulation, Voice, Gender, Culture ) function AIRBOSS:SetLSORadio( Frequency, Modulation )
self.LSOFreq = (Frequency or 264) self.LSOFreq = (Frequency or 264)
Modulation = Modulation or "AM" Modulation = Modulation or "AM"
@@ -3116,62 +3063,16 @@ function AIRBOSS:SetLSORadio( Frequency, Modulation, Voice, Gender, Culture )
self.LSORadio.frequency = self.LSOFreq self.LSORadio.frequency = self.LSOFreq
self.LSORadio.modulation = self.LSOModu self.LSORadio.modulation = self.LSOModu
self.LSORadio.alias = "LSO" self.LSORadio.alias = "LSO"
self.LSORadio.voice = Voice
self.LSORadio.gender = Gender or "male"
self.LSORadio.culture = Culture or "en-US"
return self return self
end end
--- Set Airboss radio frequency and modulation. Default frequency is Tower frequency. --- Set carrier radio frequency and modulation. Default frequency is 305 MHz AM.
-- @param #AIRBOSS self
-- @param #number Frequency (Optional) Frequency in MHz. Default frequency is Tower frequency.
-- @param #string Modulation (Optional) Modulation, "AM" or "FM". Default "AM".
-- @param #string Voice (Optional) SRS specific voice
-- @param #string Gender (Optional) SRS specific gender
-- @param #string Culture (Optional) SRS specific culture
-- @return #AIRBOSS self
-- @usage
-- -- Set single frequency
-- myairboss:SetAirbossRadio(127.5,"AM",MSRS.Voices.Google.Standard.en_GB_Standard_F)
--
-- -- Set multiple frequencies, note you **need** to pass one modulation per frequency given!
-- myairboss:SetAirbossRadio({127.5,243},{radio.modulation.AM,radio.modulation.AM},MSRS.Voices.Google.Standard.en_GB_Standard_F)
function AIRBOSS:SetAirbossRadio( Frequency, Modulation, Voice, Gender, Culture )
self.AirbossFreq = Frequency or self:_GetTowerFrequency() or 127.5
Modulation = Modulation or "AM"
if type(Modulation) == "table" then
self.AirbossModu = Modulation
else
if Modulation == "FM" then
self.AirbossModu = radio.modulation.FM
else
self.AirbossModu = radio.modulation.AM
end
end
self.AirbossRadio = {} -- #AIRBOSS.Radio
self.AirbossRadio.frequency = self.AirbossFreq
self.AirbossRadio.modulation = self.AirbossModu
self.AirbossRadio.alias = "AIRBOSS"
self.AirbossRadio.voice = Voice
self.AirbossRadio.gender = Gender or "male"
self.AirbossRadio.culture = Culture or "en-US"
return self
end
--- Set Marshal radio frequency and modulation. Default frequency is 305 MHz AM.
-- @param #AIRBOSS self -- @param #AIRBOSS self
-- @param #number Frequency (Optional) Frequency in MHz. Default 305 MHz. -- @param #number Frequency (Optional) Frequency in MHz. Default 305 MHz.
-- @param #string Modulation (Optional) Modulation, "AM" or "FM". Default "AM". -- @param #string Modulation (Optional) Modulation, "AM" or "FM". Default "AM".
-- @param #string Voice (Optional) SRS specific voice
-- @param #string Gender (Optional) SRS specific gender
-- @param #string Culture (Optional) SRS specific culture
-- @return #AIRBOSS self -- @return #AIRBOSS self
function AIRBOSS:SetMarshalRadio( Frequency, Modulation, Voice, Gender, Culture ) function AIRBOSS:SetMarshalRadio( Frequency, Modulation )
self.MarshalFreq = Frequency or 305 self.MarshalFreq = Frequency or 305
Modulation = Modulation or "AM" Modulation = Modulation or "AM"
@@ -3186,9 +3087,6 @@ function AIRBOSS:SetMarshalRadio( Frequency, Modulation, Voice, Gender, Culture
self.MarshalRadio.frequency = self.MarshalFreq self.MarshalRadio.frequency = self.MarshalFreq
self.MarshalRadio.modulation = self.MarshalModu self.MarshalRadio.modulation = self.MarshalModu
self.MarshalRadio.alias = "MARSHAL" self.MarshalRadio.alias = "MARSHAL"
self.MarshalRadio.voice = Voice
self.MarshalRadio.gender = Gender or "male"
self.MarshalRadio.culture = Culture or "en-US"
return self return self
end end
@@ -5924,27 +5822,64 @@ function AIRBOSS:_ScanCarrierZone()
-- Get aircraft type name. -- Get aircraft type name.
local actype = group:GetTypeName() local actype = group:GetTypeName()
-- Create a new flight group
if knownflight then if knownflight then
-- Debug output.
self:T2(self.lid..string.format("Known flight group %s of type %s in CCA.", groupname, actype))
-- Check if flight is AI and if we want to handle it at all. -- Check if flight is AI and if we want to handle it at all.
if knownflight.ai and knownflight.flag == -100 and self.handleai then if knownflight.ai and self.handleai then
local putintomarshal = false -- Defines if AI group should be handled by the airboss.
local iscarriersquad=true
-- Get flight group. -- Check if AI group is part of the group set if a set was defined.
local flight = _DATABASE:GetOpsGroup( groupname ) if self.squadsetAI then
local group=self.squadsetAI:FindGroup(groupname)
if flight and flight:IsInbound() and flight.destbase:GetName() == self.carrier:GetName() then if group then
if flight.ishelo then iscarriersquad=true
else else
putintomarshal = true iscarriersquad=false
end end
flight.airboss = self
end end
-- Send AI flight to marshal stack. -- Check if group was explicitly excluded.
if putintomarshal then if self.excludesetAI then
local group=self.excludesetAI:FindGroup(groupname)
if group then
iscarriersquad=false
end
end
-- Get distance to carrier.
local dist=knownflight.group:GetCoordinate():Get2DDistance(self:GetCoordinate())
-- Close in distance. Is >0 if AC comes closer wrt to first detected distance d0.
local closein=knownflight.dist0-dist
-- Debug info.
self:T3(self.lid..string.format("Known AI flight group %s closed in by %.1f NM", knownflight.groupname, UTILS.MetersToNM(closein)))
-- Is this group the tanker?
local istanker=self.tanker and self.tanker.tanker:GetName()==groupname
-- Is this group the AWACS?
local isawacs=self.awacs and self.awacs.tanker:GetName()==groupname
-- Send tanker to marshal stack?
local tanker2marshal = istanker and self.tanker:IsReturning() and self.tanker.airbase:GetName()==self.airbase:GetName() and knownflight.flag==-100 and self.tanker.recovery==true
-- Send AWACS to marhsal stack?
local awacs2marshal = isawacs and self.awacs:IsReturning() and self.awacs.airbase:GetName()==self.airbase:GetName() and knownflight.flag==-100 and self.awacs.recovery==true
-- Put flight into Marshal.
local putintomarshal=closein>UTILS.NMToMeters(5) and knownflight.flag==-100 and iscarriersquad and istanker==false and isawacs==false
-- Send AI flight to marshal stack if group closes in more than 5 and has initial flag value.
if putintomarshal or tanker2marshal or awacs2marshal then
-- Get the next free stack for current recovery case. -- Get the next free stack for current recovery case.
local stack = self:_GetFreeStack( knownflight.ai ) local stack = self:_GetFreeStack( knownflight.ai )
@@ -10266,7 +10201,7 @@ function AIRBOSS:_GetSternCoord()
elseif case==2 or case==1 then elseif case==2 or case==1 then
-- V/Stol: Translate 8 meters port. -- V/Stol: Translate 8 meters port.
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8, FB-90, true, true) self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8, FB-90, true, true)
end end
elseif self.carriertype==AIRBOSS.CarrierType.STENNIS then elseif self.carriertype==AIRBOSS.CarrierType.STENNIS then
-- Stennis: translate 7 meters starboard wrt Final bearing. -- Stennis: translate 7 meters starboard wrt Final bearing.
self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 7, FB + 90, true, true ) self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 7, FB + 90, true, true )
@@ -11550,49 +11485,9 @@ end
-- @return #number Carrier heading in degrees. -- @return #number Carrier heading in degrees.
function AIRBOSS:GetHeadingIntoWind( magnetic, coord ) function AIRBOSS:GetHeadingIntoWind( magnetic, coord )
local function adjustDegreesForWindSpeed(windSpeed)
local degreesAdjustment = 0
-- the windspeeds are in m/s
-- +0 degrees at 15m/s = 37kts
-- +0 degrees at 14m/s = 35kts
-- +0 degrees at 13m/s = 33kts
-- +4 degrees at 12m/s = 31kts
-- +4 degrees at 11m/s = 29kts
-- +4 degrees at 10m/s = 27kts
-- +4 degrees at 9m/s = 27kts
-- +4 degrees at 8m/s = 27kts
-- +8 degrees at 7m/s = 27kts
-- +8 degrees at 6m/s = 27kts
-- +8 degrees at 5m/s = 26kts
-- +20 degrees at 4m/s = 26kts
-- +20 degrees at 3m/s = 26kts
-- +30 degrees at 2m/s = 26kts 1s
if windSpeed > 0 and windSpeed < 3 then
degreesAdjustment = 30
elseif windSpeed >= 3 and windSpeed < 5 then
degreesAdjustment = 20
elseif windSpeed >= 5 and windSpeed < 8 then
degreesAdjustment = 8
elseif windSpeed >= 8 and windSpeed < 13 then
degreesAdjustment = 4
elseif windSpeed >= 13 then
degreesAdjustment = 0
end
return degreesAdjustment
end
-- Get direction the wind is blowing from. This is where we want to go. -- Get direction the wind is blowing from. This is where we want to go.
local windfrom, vwind = self:GetWind( nil, nil, coord ) local windfrom, vwind = self:GetWind( nil, nil, coord )
--self:I("windfrom="..windfrom.." vwind="..vwind)
vwind = vwind + adjustDegreesForWindSpeed(vwind)
--self:I("windfrom="..windfrom.." (c)vwind="..vwind)
-- Actually, we want the runway in the wind. -- Actually, we want the runway in the wind.
local intowind = windfrom - self.carrierparam.rwyangle local intowind = windfrom - self.carrierparam.rwyangle
@@ -13526,8 +13421,8 @@ function AIRBOSS:CarrierTurnIntoWind( time, vdeck, uturn )
-- Wind speed. -- Wind speed.
local _, vwind = self:GetWind() local _, vwind = self:GetWind()
-- Speed of carrier in m/s but at least 4 knots. -- Speed of carrier in m/s but at least 2 knots.
local vtot = math.max( vdeck - vwind, UTILS.KnotsToMps( 4 ) ) local vtot = math.max( vdeck - vwind, UTILS.KnotsToMps( 2 ) )
-- Distance to travel -- Distance to travel
local dist = vtot * time local dist = vtot * time
@@ -14731,139 +14626,58 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p
return return
end end
if not self.SRS then -- Create a new radio transmission item.
local transmission = {} -- #AIRBOSS.Radioitem
-- Create a new radio transmission item. transmission.radio = radio
local transmission = {} -- #AIRBOSS.Radioitem transmission.call = call
transmission.Tplay = timer.getAbsTime() + (delay or 0)
transmission.interval = interval
transmission.isplaying = false
transmission.Tstarted = nil
transmission.loud = loud and call.loud
transmission.radio = radio -- Player onboard number if sender has one.
transmission.call = call if self:_IsOnboard( call.modexsender ) then
transmission.Tplay = timer.getAbsTime() + (delay or 0) self:_Number2Radio( radio, call.modexsender, delay, 0.3, pilotcall )
transmission.interval = interval
transmission.isplaying = false
transmission.Tstarted = nil
transmission.loud = loud and call.loud
-- Player onboard number if sender has one.
if self:_IsOnboard( call.modexsender ) then
self:_Number2Radio( radio, call.modexsender, delay, 0.3, pilotcall )
end
-- Play onboard number if receiver has one.
if self:_IsOnboard( call.modexreceiver ) then
self:_Number2Radio( radio, call.modexreceiver, delay, 0.3, pilotcall )
end
-- Add transmission to the right queue.
local caller = ""
if radio.alias == "LSO" then
table.insert( self.RQLSO, transmission )
caller = "LSOCall"
-- Schedule radio queue checks.
if not self.RQLid then
self:T( self.lid .. string.format( "Starting LSO radio queue." ) )
self.RQLid = self.radiotimer:Schedule( nil, AIRBOSS._CheckRadioQueue, { self, self.RQLSO, "LSO" }, 0.02, 0.05 )
end
elseif radio.alias == "MARSHAL" then
table.insert( self.RQMarshal, transmission )
caller = "MarshalCall"
if not self.RQMid then
self:T( self.lid .. string.format( "Starting Marhal radio queue." ) )
self.RQMid = self.radiotimer:Schedule( nil, AIRBOSS._CheckRadioQueue, { self, self.RQMarshal, "MARSHAL" }, 0.02, 0.05 )
end
end
-- Append radio click sound at the end of the transmission.
if click then
self:RadioTransmission( radio, self[caller].CLICK, false, delay )
end
else
-- SRS transmission
local frequency = self.MarshalRadio.frequency
local modulation = self.MarshalRadio.modulation
local voice = nil
local gender = nil
local culture = nil
if radio.alias == "AIRBOSS" then
frequency = self.AirbossRadio.frequency
modulation = self.AirbossRadio.modulation
voice = self.AirbossRadio.voice
gender = self.AirbossRadio.gender
culture = self.AirbossRadio.culture
end
if radio.alias == "MARSHAL" then
voice = self.MarshalRadio.voice
gender = self.MarshalRadio.gender
culture = self.MarshalRadio.culture
end
if radio.alias == "LSO" then
frequency = self.LSORadio.frequency
modulation = self.LSORadio.modulation
voice = self.LSORadio.voice
gender = self.LSORadio.gender
culture = self.LSORadio.culture
end
if pilotcall then
voice = self.PilotRadio.voice
gender = self.PilotRadio.gender
culture = self.PilotRadio.culture
radio.alias = "PILOT"
end
if not radio.alias then
-- TODO - what freq to use here?
frequency = self.AirbossRadio.frequency
modulation = self.AirbossRadio.modulation
radio.alias = "AIRBOSS"
end
local volume = nil
if loud then
volume = 1.0
end
--local text = tostring(call.modexreceiver).."; "..radio.alias.."; "..call.subtitle
local text = call.subtitle
self:I(self.lid..text)
local srstext = self:_GetNiceSRSText(text)
self.SRSQ:NewTransmission(srstext, call.duration, self.SRS, tstart, 0.1, subgroups, call.subtitle, call.subduration, frequency, modulation, gender, culture, voice, volume, radio.alias)
end
end
--- Set SRS voice for the pilot calls.
-- @param #AIRBOSS self
-- @param #string Voice (Optional) SRS specific voice
-- @param #string Gender (Optional) SRS specific gender
-- @param #string Culture (Optional) SRS specific culture
-- @return #AIRBOSS self
function AIRBOSS:SetSRSPilotVoice( Voice, Gender, Culture )
self.PilotRadio = {} -- #AIRBOSS.Radio
self.PilotRadio.alias = "PILOT"
self.PilotRadio.voice = Voice or MSRS.Voices.Microsoft.David
self.PilotRadio.gender = Gender or "male"
self.PilotRadio.culture = Culture or "en-US"
if (not Voice) and self.SRS and self.SRS.google then
self.PilotRadio.voice = MSRS.Voices.Google.Standard.en_US_Standard_J
end end
return self -- Play onboard number if receiver has one.
if self:_IsOnboard( call.modexreceiver ) then
self:_Number2Radio( radio, call.modexreceiver, delay, 0.3, pilotcall )
end
-- Add transmission to the right queue.
local caller = ""
if radio.alias == "LSO" then
table.insert( self.RQLSO, transmission )
caller = "LSOCall"
-- Schedule radio queue checks.
if not self.RQLid then
self:T( self.lid .. string.format( "Starting LSO radio queue." ) )
self.RQLid = self.radiotimer:Schedule( nil, AIRBOSS._CheckRadioQueue, { self, self.RQLSO, "LSO" }, 0.02, 0.05 )
end
elseif radio.alias == "MARSHAL" then
table.insert( self.RQMarshal, transmission )
caller = "MarshalCall"
if not self.RQMid then
self:T( self.lid .. string.format( "Starting Marhal radio queue." ) )
self.RQMid = self.radiotimer:Schedule( nil, AIRBOSS._CheckRadioQueue, { self, self.RQMarshal, "MARSHAL" }, 0.02, 0.05 )
end
end
-- Append radio click sound at the end of the transmission.
if click then
self:RadioTransmission( radio, self[caller].CLICK, false, delay )
end
end end
--- Check if a call needs a subtitle because the complete voice overs are not available. --- Check if a call needs a subtitle because the complete voice overs are not available.
@@ -15109,39 +14923,6 @@ function AIRBOSS:_RadioFilename( call, loud, channel )
return filename return filename
end end
--- Format text into SRS friendly string
-- @param #AIRBOSS self
-- @param #string text
-- @return #string text
function AIRBOSS:_GetNiceSRSText(text)
text = string.gsub(text,"================================\n","")
text = string.gsub(text,"||","parallel")
text = string.gsub(text,"==","perpendicular")
text = string.gsub(text,"BRC","Base recovery")
--text = string.gsub(text,"#","Number")
text = string.gsub(text,"%((%a+)%)","Morse %1")
text = string.gsub(text,"°C","° Celsius")
text = string.gsub(text,"°"," degrees")
text = string.gsub(text," FB "," Final bearing ")
text = string.gsub(text," ops"," operations ")
text = string.gsub(text," kts"," knots")
text = string.gsub(text,"TACAN","Tackan")
text = string.gsub(text,"ICLS","I.C.L.S.")
text = string.gsub(text,"LSO","L.S.O.")
text = string.gsub(text,"inHg","inches of Mercury")
text = string.gsub(text,"QFE","Q.F.E.")
text = string.gsub(text,"hPa","hecto pascal")
text = string.gsub(text," NM"," nautical miles")
text = string.gsub(text," ft"," feet")
text = string.gsub(text,"A/C","aircraft")
text = string.gsub(text,"(#[%a%d%p%s]+)\n","")
text = string.gsub(text,"%.000"," dot zero")
text = string.gsub(text,"00"," double zero")
text = string.gsub(text," 0 "," zero " )
text = string.gsub(text,"\n","; ")
return text
end
--- Send text message to player client. --- Send text message to player client.
-- Message format will be "SENDER: RECCEIVER, MESSAGE". -- Message format will be "SENDER: RECCEIVER, MESSAGE".
-- @param #AIRBOSS self -- @param #AIRBOSS self
@@ -15153,7 +14934,7 @@ end
-- @param #boolean clear If true, clear screen from previous messages. -- @param #boolean clear If true, clear screen from previous messages.
-- @param #number delay Delay in seconds, before the message is displayed. -- @param #number delay Delay in seconds, before the message is displayed.
function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duration, clear, delay ) function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duration, clear, delay )
self:I({sender,receiver,message})
if playerData and message and message ~= "" then if playerData and message and message ~= "" then
-- Default duration. -- Default duration.
@@ -15177,90 +14958,48 @@ function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duratio
self:ScheduleOnce( delay, self.MessageToPlayer, self, playerData, message, sender, receiver, duration, clear ) self:ScheduleOnce( delay, self.MessageToPlayer, self, playerData, message, sender, receiver, duration, clear )
else else
if not self.SRS then -- Wait until previous sound finished.
-- Wait until previous sound finished. local wait = 0
local wait = 0
-- Onboard number to get the attention. -- Onboard number to get the attention.
if receiver == playerData.onboard then if receiver == playerData.onboard then
-- Which voice over number to use. -- Which voice over number to use.
if sender and (sender == "LSO" or sender == "MARSHAL" or sender == "AIRBOSS") then if sender and (sender == "LSO" or sender == "MARSHAL" or sender == "AIRBOSS") then
-- User sound of board number. -- User sound of board number.
wait = wait + self:_Number2Sound( playerData, sender, receiver ) wait = wait + self:_Number2Sound( playerData, sender, receiver )
end
end end
-- Negative.
if string.find( text:lower(), "negative" ) then
local filename = self:_RadioFilename( self.MarshalCall.NEGATIVE, false, "MARSHAL" )
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
wait = wait + self.MarshalCall.NEGATIVE.duration
end
-- Affirm.
if string.find( text:lower(), "affirm" ) then
local filename = self:_RadioFilename( self.MarshalCall.AFFIRMATIVE, false, "MARSHAL" )
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
wait = wait + self.MarshalCall.AFFIRMATIVE.duration
end
-- Roger.
if string.find( text:lower(), "roger" ) then
local filename = self:_RadioFilename( self.MarshalCall.ROGER, false, "MARSHAL" )
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
wait = wait + self.MarshalCall.ROGER.duration
end
-- Play click sound to end message.
if wait > 0 then
local filename = self:_RadioFilename( self.MarshalCall.CLICK )
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
end
else
-- SRS transmission
local frequency = self.MarshalRadio.frequency
local modulation = self.MarshalRadio.modulation
local voice = self.MarshalRadio.voice
local gender = self.MarshalRadio.gender
local culture = self.MarshalRadio.culture
if not sender then sender = "AIRBOSS" end
if string.find(sender,"AIRBOSS" ) then
frequency = self.AirbossRadio.frequency
modulation = self.AirbossRadio.modulation
voice = self.AirbossRadio.voice
gender = self.AirbossRadio.gender
culture = self.AirbossRadio.culture
end
--if sender == "MARSHAL" then
--voice = self.MarshalRadio.voice
--gender = self.MarshalRadio.gender
--culture = self.MarshalRadio.culture
--end
if sender == "LSO" then
frequency = self.LSORadio.frequency
modulation = self.LSORadio.modulation
voice = self.LSORadio.voice
gender = self.LSORadio.gender
culture = self.LSORadio.culture
--elseif not sender then
-- TODO - what freq to use here?
--frequency = self.AirbossRadio.frequency
--modulation = self.AirbossRadio.modulation
--sender = "AIRBOSS"
end
self:I(self.lid..text)
self:I({sender,frequency,modulation,voice})
local srstext = self:_GetNiceSRSText(text)
self.SRSQ:NewTransmission(srstext,duration,self.SRS,tstart,0.1,subgroups,subtitle,subduration,frequency,modulation,gender,culture,voice,volume,sender)
end end
-- Negative.
if string.find( text:lower(), "negative" ) then
local filename = self:_RadioFilename( self.MarshalCall.NEGATIVE, false, "MARSHAL" )
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
wait = wait + self.MarshalCall.NEGATIVE.duration
end
-- Affirm.
if string.find( text:lower(), "affirm" ) then
local filename = self:_RadioFilename( self.MarshalCall.AFFIRMATIVE, false, "MARSHAL" )
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
wait = wait + self.MarshalCall.AFFIRMATIVE.duration
end
-- Roger.
if string.find( text:lower(), "roger" ) then
local filename = self:_RadioFilename( self.MarshalCall.ROGER, false, "MARSHAL" )
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
wait = wait + self.MarshalCall.ROGER.duration
end
-- Play click sound to end message.
if wait > 0 then
local filename = self:_RadioFilename( self.MarshalCall.CLICK )
USERSOUND:New( filename ):ToGroup( playerData.group, wait )
end
-- Text message to player client. -- Text message to player client.
if playerData.client then if playerData.client then
MESSAGE:New( text, duration, sender, clear ):ToClient( playerData.client ) MESSAGE:New( text, duration, sender, clear ):ToClient( playerData.client )
@@ -16599,7 +16338,7 @@ function AIRBOSS:_RequestSpinning( _unitName )
-- Some advice. -- Some advice.
if playerData.difficulty == AIRBOSS.Difficulty.EASY then if playerData.difficulty == AIRBOSS.Difficulty.EASY then
local text = "Climb to 1200 feet and proceed to the initial again." local text = "Climb to 1200 feet and proceed to the initial again."
self:MessageToPlayer( playerData, text, "AIRBOSS", "" ) self:MessageToPlayer( playerData, text, "INSTRUCTOR", "" )
end end
return return
@@ -17354,7 +17093,7 @@ function AIRBOSS:_DisplayCarrierInfo( _unitname )
state = "Deck closed" state = "Deck closed"
end end
if self.turning then if self.turning then
state = state .. " (currently turning)" state = state .. " (turning currently)"
end end
-- Message text. -- Message text.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-621
View File
@@ -1,621 +0,0 @@
--- **Ops** - Brigade Warehouse.
--
-- **Main Features:**
--
-- * Manage platoons
-- * Carry out ARTY and PATROLZONE missions (AUFTRAG)
-- * Define rearming zones
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Brigade).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Ops.Brigade
-- @image OPS_Brigade_.png
--- BRIGADE class.
-- @type BRIGADE
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @field #table rearmingZones Rearming zones. Each element is of type `#BRIGADE.SupplyZone`.
-- @field #table refuellingZones Refuelling zones. Each element is of type `#BRIGADE.SupplyZone`.
-- @field Core.Set#SET_ZONE retreatZones Retreat zone set.
-- @extends Ops.Legion#LEGION
--- *I am not afraid of an Army of lions lead by a sheep; I am afraid of sheep lead by a lion* -- Alexander the Great
--
-- ===
--
-- # The BRIGADE Concept
--
-- A BRIGADE consists of one or multiple PLATOONs. These platoons "live" in a WAREHOUSE that has a phyiscal struction (STATIC or UNIT) and can be captured or destroyed.
--
--
-- @field #BRIGADE
BRIGADE = {
ClassName = "BRIGADE",
verbose = 0,
rearmingZones = {},
refuellingZones = {},
}
--- Supply Zone.
-- @type BRIGADE.SupplyZone
-- @field Core.Zone#ZONE zone The zone.
-- @field Ops.Auftrag#AUFTRAG mission Mission assigned to supply ammo or fuel.
-- @field #boolean markerOn If `true`, marker is on.
-- @field Wrapper.Marker#MARKER marker F10 marker.
--- BRIGADE class version.
-- @field #string version
BRIGADE.version="0.1.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Spawn when hosting warehouse is a ship or oil rig or gas platform.
-- TODO: Rearming zones.
-- TODO: Retreat zones.
-- DONE: Add weapon range.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new BRIGADE class object.
-- @param #BRIGADE self
-- @param #string WarehouseName Name of the warehouse STATIC or UNIT object representing the warehouse.
-- @param #string BrigadeName Name of the brigade.
-- @return #BRIGADE self
function BRIGADE:New(WarehouseName, BrigadeName)
-- Inherit everything from LEGION class.
local self=BASE:Inherit(self, LEGION:New(WarehouseName, BrigadeName)) -- #BRIGADE
-- Nil check.
if not self then
BASE:E(string.format("ERROR: Could not find warehouse %s!", WarehouseName))
return nil
end
-- Set some string id for output to DCS.log file.
self.lid=string.format("BRIGADE %s | ", self.alias)
-- Defaults
self:SetRetreatZones()
-- Turn ship into NAVYGROUP.
if self:IsShip() then
local wh=self.warehouse --Wrapper.Unit#UNIT
local group=wh:GetGroup()
self.warehouseOpsGroup=NAVYGROUP:New(group) --Ops.NavyGroup#NAVYGROUP
self.warehouseOpsElement=self.warehouseOpsGroup:GetElementByName(wh:GetName())
end
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("*", "ArmyOnMission", "*") -- An ARMYGROUP was send on a Mission (AUFTRAG).
------------------------
--- Pseudo Functions ---
------------------------
--- Triggers the FSM event "Start". Starts the BRIGADE. Initializes parameters and starts event handlers.
-- @function [parent=#BRIGADE] Start
-- @param #BRIGADE self
--- Triggers the FSM event "Start" after a delay. Starts the BRIGADE. Initializes parameters and starts event handlers.
-- @function [parent=#BRIGADE] __Start
-- @param #BRIGADE self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Stop". Stops the BRIGADE and all its event handlers.
-- @param #BRIGADE self
--- Triggers the FSM event "Stop" after a delay. Stops the BRIGADE and all its event handlers.
-- @function [parent=#BRIGADE] __Stop
-- @param #BRIGADE self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "ArmyOnMission".
-- @function [parent=#BRIGADE] ArmyOnMission
-- @param #BRIGADE self
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup The ARMYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
--- Triggers the FSM event "ArmyOnMission" after a delay.
-- @function [parent=#BRIGADE] __ArmyOnMission
-- @param #BRIGADE self
-- @param #number delay Delay in seconds.
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup The ARMYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
--- On after "ArmyOnMission" event.
-- @function [parent=#BRIGADE] OnAfterArmyOnMission
-- @param #BRIGADE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup The ARMYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add a platoon to the brigade.
-- @param #BRIGADE self
-- @param Ops.Platoon#PLATOON Platoon The platoon object.
-- @return #BRIGADE self
function BRIGADE:AddPlatoon(Platoon)
-- Add platoon to brigade.
table.insert(self.cohorts, Platoon)
-- Add assets to platoon.
self:AddAssetToPlatoon(Platoon, Platoon.Ngroups)
-- Set brigade of platoon.
Platoon:SetBrigade(self)
-- Start platoon.
if Platoon:IsStopped() then
Platoon:Start()
end
return self
end
--- Add asset group(s) to platoon.
-- @param #BRIGADE self
-- @param Ops.Platoon#PLATOON Platoon The platoon object.
-- @param #number Nassets Number of asset groups to add.
-- @return #BRIGADE self
function BRIGADE:AddAssetToPlatoon(Platoon, Nassets)
if Platoon then
-- Get the template group of the platoon.
local Group=GROUP:FindByName(Platoon.templatename)
if Group then
-- Debug text.
local text=string.format("Adding asset %s to platoon %s", Group:GetName(), Platoon.name)
self:T(self.lid..text)
-- Add assets to airwing warehouse.
self:AddAsset(Group, Nassets, nil, nil, nil, nil, Platoon.skill, Platoon.livery, Platoon.name)
else
self:E(self.lid.."ERROR: Group does not exist!")
end
else
self:E(self.lid.."ERROR: Platoon does not exit!")
end
return self
end
--- Define a set of retreat zones.
-- @param #BRIGADE self
-- @param Core.Set#SET_ZONE RetreatZoneSet Set of retreat zones.
-- @return #BRIGADE self
function BRIGADE:SetRetreatZones(RetreatZoneSet)
self.retreatZones=RetreatZoneSet or SET_ZONE:New()
return self
end
--- Add a retreat zone.
-- @param #BRIGADE self
-- @param Core.Zone#ZONE RetreatZone Retreat zone.
-- @return #BRIGADE self
function BRIGADE:AddRetreatZone(RetreatZone)
self.retreatZones:AddZone(RetreatZone)
return self
end
--- Get retreat zones.
-- @param #BRIGADE self
-- @return Core.Set#SET_ZONE Set of retreat zones.
function BRIGADE:GetRetreatZones()
return self.retreatZones
end
--- Add a rearming zone.
-- @param #BRIGADE self
-- @param Core.Zone#ZONE RearmingZone Rearming zone.
-- @return #BRIGADE.SupplyZone The rearming zone data.
function BRIGADE:AddRearmingZone(RearmingZone)
local rearmingzone={} --#BRIGADE.SupplyZone
rearmingzone.zone=RearmingZone
rearmingzone.mission=nil
rearmingzone.marker=MARKER:New(rearmingzone.zone:GetCoordinate(), "Rearming Zone"):ToCoalition(self:GetCoalition())
table.insert(self.rearmingZones, rearmingzone)
return rearmingzone
end
--- Add a refuelling zone.
-- @param #BRIGADE self
-- @param Core.Zone#ZONE RefuellingZone Refuelling zone.
-- @return #BRIGADE.SupplyZone The refuelling zone data.
function BRIGADE:AddRefuellingZone(RefuellingZone)
local supplyzone={} --#BRIGADE.SupplyZone
supplyzone.zone=RefuellingZone
supplyzone.mission=nil
supplyzone.marker=MARKER:New(supplyzone.zone:GetCoordinate(), "Refuelling Zone"):ToCoalition(self:GetCoalition())
table.insert(self.refuellingZones, supplyzone)
return supplyzone
end
--- Get platoon by name.
-- @param #BRIGADE self
-- @param #string PlatoonName Name of the platoon.
-- @return Ops.Platoon#PLATOON The Platoon object.
function BRIGADE:GetPlatoon(PlatoonName)
local platoon=self:_GetCohort(PlatoonName)
return platoon
end
--- Get platoon of an asset.
-- @param #BRIGADE self
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The platoon asset.
-- @return Ops.Platoon#PLATOON The platoon object.
function BRIGADE:GetPlatoonOfAsset(Asset)
local platoon=self:GetPlatoon(Asset.squadname)
return platoon
end
--- Remove asset from platoon.
-- @param #BRIGADE self
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The platoon asset.
function BRIGADE:RemoveAssetFromPlatoon(Asset)
local platoon=self:GetPlatoonOfAsset(Asset)
if platoon then
platoon:DelAsset(Asset)
end
end
--- [ GROUND ] Function to load back an asset in the field that has been filed before.
-- @param #BRIGADE self
-- @param #string Templatename e.g."1 PzDv LogRg I\_AID-976" - that's the alias (name) of an platoon spawned as `"platoon - alias"_AID-"asset-ID"`
-- @param Core.Point#COORDINATE Position where to spawn the platoon
-- @return #BRIGADE self
-- @usage
-- Prerequisites:
-- Save the assets spawned by BRIGADE/CHIEF regularly (~every 5 mins) into a file, e.g. like this:
--
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
-- local BlueSaveOps = SET_GROUP:New():FilterCoalitions("blue"):FilterPrefixes("AID"):FilterCategoryGround():FilterOnce()
-- UTILS.SaveSetOfGroups(BlueSaveOps,Path,BlueOpsFilename)
--
-- where Path and Filename are strings, as chosen by you.
-- You can then load back the assets at the start of your next mission run. Be aware that it takes a couple of seconds for the
-- platoon data to arrive in brigade, so make this an action after ~20 seconds, e.g. like so:
--
-- function LoadBackAssets()
-- local Path = FilePath or "C:\\Users\\<yourname>\\Saved Games\\DCS\\Missions\\" -- example path
-- local BlueOpsFilename = BlueFileName or "ExamplePlatoonSave.csv" -- example filename
-- if UTILS.CheckFileExists(Path,BlueOpsFilename) then
-- local loadback = UTILS.LoadSetOfGroups(Path,BlueOpsFilename,false)
-- for _,_platoondata in pairs (loadback) do
-- local groupname = _platoondata.groupname -- #string
-- local coordinate = _platoondata.coordinate -- Core.Point#COORDINATE
-- Your_Brigade:LoadBackAssetInPosition(groupname,coordinate)
-- end
-- end
-- end
--
-- local AssetLoader = TIMER:New(LoadBackAssets)
-- AssetLoader:Start(20)
--
-- The assets loaded back into the mission will be considered for AUFTRAG type missions from CHIEF and BRIGADE.
function BRIGADE:LoadBackAssetInPosition(Templatename,Position)
self:T(self.lid .. "LoadBackAssetInPosition: " .. tostring(Templatename))
-- get Platoon alias from Templatename
local nametbl = UTILS.Split(Templatename,"_")
local name = nametbl[1]
self:T(string.format("*** Target Platoon = %s ***",name))
-- find a matching asset table from BRIGADE
local cohorts = self.cohorts or {}
local thisasset = nil --Functional.Warehouse#WAREHOUSE.Assetitem
local found = false
for _,_cohort in pairs(cohorts) do
local asset = _cohort:GetName()
self:T(string.format("*** Looking at Platoon = %s ***",asset))
if asset == name then
self:T("**** Found Platoon ****")
local cohassets = _cohort.assets or {}
for _,_zug in pairs (cohassets) do
local zug = _zug -- Functional.Warehouse#WAREHOUSE.Assetitem
if zug.assignment == name and zug.requested == false then
self:T("**** Found Asset ****")
found = true
thisasset = zug --Functional.Warehouse#WAREHOUSE.Assetitem
break
end
end
end
end
if found then
-- prep asset
thisasset.rid = thisasset.uid
thisasset.requested = false
thisasset.score=100
thisasset.missionTask="CAS"
thisasset.spawned = true
local template = thisasset.templatename
local alias = thisasset.spawngroupname
-- Spawn group
local spawnasset = SPAWN:NewWithAlias(template,alias)
:InitDelayOff()
:SpawnFromCoordinate(Position)
-- build a new self request
local request = {} --Functional.Warehouse#WAREHOUSE.Pendingitem
request.assignment = name
request.warehouse = self
request.assets = {thisasset}
request.ntransporthome = 0
request.ndelivered = 0
request.ntransport = 0
request.cargoattribute = thisasset.attribute
request.category = thisasset.category
request.cargoassets = {thisasset}
request.assetdesc = WAREHOUSE.Descriptor.ASSETLIST
request.cargocategory = thisasset.category
request.toself = true
request.transporttype = WAREHOUSE.TransportType.SELFPROPELLED
request.assetproblem = {}
request.born = true
request.prio = 50
request.uid = thisasset.uid
request.airbase = nil
request.timestamp = timer.getAbsTime()
request.assetdescval = {thisasset}
request.nasset = 1
request.cargogroupset = SET_GROUP:New()
request.cargogroupset:AddGroup(spawnasset)
request.iscargo = true
-- Call Brigade self
self:__AssetSpawned(2, spawnasset, thisasset, request)
end
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Start BRIGADE FSM.
-- @param #BRIGADE self
function BRIGADE:onafterStart(From, Event, To)
-- Start parent Warehouse.
self:GetParent(self, BRIGADE).onafterStart(self, From, Event, To)
-- Info.
self:I(self.lid..string.format("Starting BRIGADE v%s", BRIGADE.version))
end
--- Update status.
-- @param #BRIGADE self
function BRIGADE:onafterStatus(From, Event, To)
-- Status of parent Warehouse.
self:GetParent(self).onafterStatus(self, From, Event, To)
-- FSM state.
local fsmstate=self:GetState()
----------------
-- Transport ---
----------------
self:CheckTransportQueue()
--------------
-- Mission ---
--------------
-- Check if any missions should be cancelled.
self:CheckMissionQueue()
---------------------
-- Rearming Zones ---
---------------------
for _,_rearmingzone in pairs(self.rearmingZones) do
local rearmingzone=_rearmingzone --#BRIGADE.SupplyZone
if (not rearmingzone.mission) or rearmingzone.mission:IsOver() then
rearmingzone.mission=AUFTRAG:NewAMMOSUPPLY(rearmingzone.zone)
self:AddMission(rearmingzone.mission)
end
end
-----------------------
-- Refuelling Zones ---
-----------------------
-- Check refuelling zones.
for _,_supplyzone in pairs(self.refuellingZones) do
local supplyzone=_supplyzone --#BRIGADE.SupplyZone
-- Check if mission is nil or over.
if (not supplyzone.mission) or supplyzone.mission:IsOver() then
supplyzone.mission=AUFTRAG:NewFUELSUPPLY(supplyzone.zone)
self:AddMission(supplyzone.mission)
end
end
-----------
-- Info ---
-----------
-- General info:
if self.verbose>=1 then
-- Count missions not over yet.
local Nmissions=self:CountMissionsInQueue()
-- Asset count.
local Npq, Np, Nq=self:CountAssetsOnMission()
-- Asset string.
local assets=string.format("%d [OnMission: Total=%d, Active=%d, Queued=%d]", self:CountAssets(), Npq, Np, Nq)
-- Output.
local text=string.format("%s: Missions=%d, Platoons=%d, Assets=%s", fsmstate, Nmissions, #self.cohorts, assets)
self:I(self.lid..text)
end
------------------
-- Mission Info --
------------------
if self.verbose>=2 then
local text=string.format("Missions Total=%d:", #self.missionqueue)
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
local prio=string.format("%d/%s", mission.prio, tostring(mission.importance)) ; if mission.urgent then prio=prio.." (!)" end
local assets=string.format("%d/%d", mission:CountOpsGroups(), mission.Nassets or 0)
local target=string.format("%d/%d Damage=%.1f", mission:CountMissionTargets(), mission:GetTargetInitialNumber(), mission:GetTargetDamage())
text=text..string.format("\n[%d] %s %s: Status=%s, Prio=%s, Assets=%s, Targets=%s", i, mission.name, mission.type, mission.status, prio, assets, target)
end
self:I(self.lid..text)
end
--------------------
-- Transport Info --
--------------------
if self.verbose>=2 then
local text=string.format("Transports Total=%d:", #self.transportqueue)
for i,_transport in pairs(self.transportqueue) do
local transport=_transport --Ops.OpsTransport#OPSTRANSPORT
local prio=string.format("%d/%s", transport.prio, tostring(transport.importance)) ; if transport.urgent then prio=prio.." (!)" end
local carriers=string.format("Ncargo=%d/%d, Ncarriers=%d", transport.Ncargo, transport.Ndelivered, transport.Ncarrier)
text=text..string.format("\n[%d] UID=%d: Status=%s, Prio=%s, Cargo: %s", i, transport.uid, transport:GetState(), prio, carriers)
end
self:I(self.lid..text)
end
-------------------
-- Platoon Info --
-------------------
if self.verbose>=3 then
local text="Platoons:"
for i,_platoon in pairs(self.cohorts) do
local platoon=_platoon --Ops.Platoon#PLATOON
local callsign=platoon.callsignName and UTILS.GetCallsignName(platoon.callsignName) or "N/A"
local modex=platoon.modex and platoon.modex or -1
local skill=platoon.skill and tostring(platoon.skill) or "N/A"
-- Platoon text.
text=text..string.format("\n* %s %s: %s*%d/%d, Callsign=%s, Modex=%d, Skill=%s", platoon.name, platoon:GetState(), platoon.aircrafttype, platoon:CountAssets(true), #platoon.assets, callsign, modex, skill)
end
self:I(self.lid..text)
end
-------------------
-- Rearming Info --
-------------------
if self.verbose>=4 then
local text="Rearming Zones:"
for i,_rearmingzone in pairs(self.rearmingZones) do
local rearmingzone=_rearmingzone --#BRIGADE.SupplyZone
-- Info text.
text=text..string.format("\n* %s: Mission status=%s, suppliers=%d", rearmingzone.zone:GetName(), rearmingzone.mission:GetState(), rearmingzone.mission:CountOpsGroups())
end
self:I(self.lid..text)
end
---------------------
-- Refuelling Info --
---------------------
if self.verbose>=4 then
local text="Refuelling Zones:"
for i,_refuellingzone in pairs(self.refuellingZones) do
local refuellingzone=_refuellingzone --#BRIGADE.SupplyZone
-- Info text.
text=text..string.format("\n* %s: Mission status=%s, suppliers=%d", refuellingzone.zone:GetName(), refuellingzone.mission:GetState(), refuellingzone.mission:CountOpsGroups())
end
self:I(self.lid..text)
end
----------------
-- Asset Info --
----------------
if self.verbose>=5 then
local text="Assets in stock:"
for i,_asset in pairs(self.stock) do
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
-- Info text.
text=text..string.format("\n* %s: spawned=%s", asset.spawngroupname, tostring(asset.spawned))
end
self:I(self.lid..text)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after "ArmyOnMission".
-- @param #BRIGADE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup Ops army group on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The requested mission.
function BRIGADE:onafterArmyOnMission(From, Event, To, ArmyGroup, Mission)
-- Debug info.
self:T(self.lid..string.format("Group %s on %s mission %s", ArmyGroup:GetName(), Mission:GetType(), Mission:GetName()))
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-425
View File
@@ -1,425 +0,0 @@
--- **Ops** - Fleet Warehouse.
--
-- **Main Features:**
--
-- * Manage flotillas
-- * Carry out ARTY and PATROLZONE missions (AUFTRAG)
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Fleet).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Ops.Fleet
-- @image OPS_Fleet.png
--- FLEET class.
-- @type FLEET
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @field Core.Set#SET_ZONE retreatZones Retreat zone set.
-- @field #boolean pathfinding Set pathfinding on for all spawned navy groups.
-- @extends Ops.Legion#LEGION
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
--
-- ===
--
-- # The FLEET Concept
--
-- A FLEET consists of one or multiple FLOTILLAs. These flotillas "live" in a WAREHOUSE that has a phyiscal struction (STATIC or UNIT) and can be captured or destroyed.
--
-- # Basic Setup
--
-- A new `FLEET` object can be created with the @{#FLEET.New}(`WarehouseName`, `FleetName`) function, where `WarehouseName` is the name of the static or unit object hosting the fleet
-- and `FleetName` is the name you want to give the fleet. This must be *unique*!
--
-- myFleet=FLEET:New("myWarehouseName", "1st Fleet")
-- myFleet:SetPortZone(ZonePort1stFleet)
-- myFleet:Start()
--
-- A fleet needs a *port zone*, which is set via the @{#FLEET.SetPortZone}(`PortZone`) function. This is the zone where the naval assets are spawned and return to.
--
-- Finally, the fleet needs to be started using the @{#FLEET.Start}() function. If the fleet is not started, it will not process any requests.
--
-- ## Adding Flotillas
--
-- Flotillas can be added via the @{#FLEET.AddFlotilla}(`Flotilla`) function. See @{Ops.Flotilla#FLOTILLA} for how to create a flotilla.
--
-- myFleet:AddFlotilla(FlotillaTiconderoga)
-- myFleet:AddFlotilla(FlotillaPerry)
--
--
--
-- @field #FLEET
FLEET = {
ClassName = "FLEET",
verbose = 0,
pathfinding = false,
}
--- Supply Zone.
-- @type FLEET.SupplyZone
-- @field Core.Zone#ZONE zone The zone.
-- @field Ops.Auftrag#AUFTRAG mission Mission assigned to supply ammo or fuel.
-- @field #boolean markerOn If `true`, marker is on.
-- @field Wrapper.Marker#MARKER marker F10 marker.
--- FLEET class version.
-- @field #string version
FLEET.version="0.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Add routes?
-- DONE: Add weapon range.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new FLEET class object.
-- @param #FLEET self
-- @param #string WarehouseName Name of the warehouse STATIC or UNIT object representing the warehouse.
-- @param #string FleetName Name of the fleet.
-- @return #FLEET self
function FLEET:New(WarehouseName, FleetName)
-- Inherit everything from LEGION class.
local self=BASE:Inherit(self, LEGION:New(WarehouseName, FleetName)) -- #FLEET
-- Nil check.
if not self then
BASE:E(string.format("ERROR: Could not find warehouse %s!", WarehouseName))
return nil
end
-- Set some string id for output to DCS.log file.
self.lid=string.format("FLEET %s | ", self.alias)
-- Defaults
self:SetRetreatZones()
-- Turn ship into NAVYGROUP.
if self:IsShip() then
local wh=self.warehouse --Wrapper.Unit#UNIT
local group=wh:GetGroup()
self.warehouseOpsGroup=NAVYGROUP:New(group) --Ops.NavyGroup#NAVYGROUP
self.warehouseOpsElement=self.warehouseOpsGroup:GetElementByName(wh:GetName())
end
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("*", "NavyOnMission", "*") -- An NAVYGROUP was send on a Mission (AUFTRAG).
------------------------
--- Pseudo Functions ---
------------------------
--- Triggers the FSM event "Start". Starts the FLEET. Initializes parameters and starts event handlers.
-- @function [parent=#FLEET] Start
-- @param #FLEET self
--- Triggers the FSM event "Start" after a delay. Starts the FLEET. Initializes parameters and starts event handlers.
-- @function [parent=#FLEET] __Start
-- @param #FLEET self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "Stop". Stops the FLEET and all its event handlers.
-- @param #FLEET self
--- Triggers the FSM event "Stop" after a delay. Stops the FLEET and all its event handlers.
-- @function [parent=#FLEET] __Stop
-- @param #FLEET self
-- @param #number delay Delay in seconds.
--- Triggers the FSM event "NavyOnMission".
-- @function [parent=#FLEET] NavyOnMission
-- @param #FLEET self
-- @param Ops.NavyGroup#NAVYGROUP ArmyGroup The NAVYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
--- Triggers the FSM event "NavyOnMission" after a delay.
-- @function [parent=#FLEET] __NavyOnMission
-- @param #FLEET self
-- @param #number delay Delay in seconds.
-- @param Ops.NavyGroup#NAVYGROUP ArmyGroup The NAVYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
--- On after "NavyOnMission" event.
-- @function [parent=#FLEET] OnAfterNavyOnMission
-- @param #FLEET self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.NavyGroup#NAVYGROUP NavyGroup The NAVYGROUP on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Add a flotilla to the fleet.
-- @param #FLEET self
-- @param Ops.Flotilla#FLOTILLA Flotilla The flotilla object.
-- @return #FLEET self
function FLEET:AddFlotilla(Flotilla)
-- Add flotilla to fleet.
table.insert(self.cohorts, Flotilla)
-- Add assets to flotilla.
self:AddAssetToFlotilla(Flotilla, Flotilla.Ngroups)
-- Set fleet of flotilla.
Flotilla:SetFleet(self)
-- Start flotilla.
if Flotilla:IsStopped() then
Flotilla:Start()
end
return self
end
--- Add asset group(s) to flotilla.
-- @param #FLEET self
-- @param Ops.Flotilla#FLOTILLA Flotilla The flotilla object.
-- @param #number Nassets Number of asset groups to add.
-- @return #FLEET self
function FLEET:AddAssetToFlotilla(Flotilla, Nassets)
if Flotilla then
-- Get the template group of the flotilla.
local Group=GROUP:FindByName(Flotilla.templatename)
if Group then
-- Debug text.
local text=string.format("Adding asset %s to flotilla %s", Group:GetName(), Flotilla.name)
self:T(self.lid..text)
-- Add assets to airwing warehouse.
self:AddAsset(Group, Nassets, nil, nil, nil, nil, Flotilla.skill, Flotilla.livery, Flotilla.name)
else
self:E(self.lid.."ERROR: Group does not exist!")
end
else
self:E(self.lid.."ERROR: Flotilla does not exit!")
end
return self
end
--- Set pathfinding for all spawned naval groups.
-- @param #FLEET self
-- @param #boolean Switch If `true`, pathfinding is used.
-- @return #FLEET self
function FLEET:SetPathfinding(Switch)
self.pathfinding=Switch
return self
end
--- Define a set of retreat zones.
-- @param #FLEET self
-- @param Core.Set#SET_ZONE RetreatZoneSet Set of retreat zones.
-- @return #FLEET self
function FLEET:SetRetreatZones(RetreatZoneSet)
self.retreatZones=RetreatZoneSet or SET_ZONE:New()
return self
end
--- Add a retreat zone.
-- @param #FLEET self
-- @param Core.Zone#ZONE RetreatZone Retreat zone.
-- @return #FLEET self
function FLEET:AddRetreatZone(RetreatZone)
self.retreatZones:AddZone(RetreatZone)
return self
end
--- Get retreat zones.
-- @param #FLEET self
-- @return Core.Set#SET_ZONE Set of retreat zones.
function FLEET:GetRetreatZones()
return self.retreatZones
end
--- Get flotilla by name.
-- @param #FLEET self
-- @param #string FlotillaName Name of the flotilla.
-- @return Ops.Flotilla#FLOTILLA The Flotilla object.
function FLEET:GetFlotilla(FlotillaName)
local flotilla=self:_GetCohort(FlotillaName)
return flotilla
end
--- Get flotilla of an asset.
-- @param #FLEET self
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The flotilla asset.
-- @return Ops.Flotilla#FLOTILLA The flotilla object.
function FLEET:GetFlotillaOfAsset(Asset)
local flotilla=self:GetFlotilla(Asset.squadname)
return flotilla
end
--- Remove asset from flotilla.
-- @param #FLEET self
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The flotilla asset.
function FLEET:RemoveAssetFromFlotilla(Asset)
local flotilla=self:GetFlotillaOfAsset(Asset)
if flotilla then
flotilla:DelAsset(Asset)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Start FLEET FSM.
-- @param #FLEET self
function FLEET:onafterStart(From, Event, To)
-- Start parent Warehouse.
self:GetParent(self, FLEET).onafterStart(self, From, Event, To)
-- Info.
self:I(self.lid..string.format("Starting FLEET v%s", FLEET.version))
end
--- Update status.
-- @param #FLEET self
function FLEET:onafterStatus(From, Event, To)
-- Status of parent Warehouse.
self:GetParent(self).onafterStatus(self, From, Event, To)
-- FSM state.
local fsmstate=self:GetState()
----------------
-- Transport ---
----------------
self:CheckTransportQueue()
--------------
-- Mission ---
--------------
-- Check if any missions should be cancelled.
self:CheckMissionQueue()
-----------
-- Info ---
-----------
-- General info:
if self.verbose>=1 then
-- Count missions not over yet.
local Nmissions=self:CountMissionsInQueue()
-- Asset count.
local Npq, Np, Nq=self:CountAssetsOnMission()
-- Asset string.
local assets=string.format("%d [OnMission: Total=%d, Active=%d, Queued=%d]", self:CountAssets(), Npq, Np, Nq)
-- Output.
local text=string.format("%s: Missions=%d, Flotillas=%d, Assets=%s", fsmstate, Nmissions, #self.cohorts, assets)
self:I(self.lid..text)
end
------------------
-- Mission Info --
------------------
if self.verbose>=2 then
local text=string.format("Missions Total=%d:", #self.missionqueue)
for i,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
local prio=string.format("%d/%s", mission.prio, tostring(mission.importance)) ; if mission.urgent then prio=prio.." (!)" end
local assets=string.format("%d/%d", mission:CountOpsGroups(), mission.Nassets or 0)
local target=string.format("%d/%d Damage=%.1f", mission:CountMissionTargets(), mission:GetTargetInitialNumber(), mission:GetTargetDamage())
text=text..string.format("\n[%d] %s %s: Status=%s, Prio=%s, Assets=%s, Targets=%s", i, mission.name, mission.type, mission.status, prio, assets, target)
end
self:I(self.lid..text)
end
--------------------
-- Transport Info --
--------------------
if self.verbose>=2 then
local text=string.format("Transports Total=%d:", #self.transportqueue)
for i,_transport in pairs(self.transportqueue) do
local transport=_transport --Ops.OpsTransport#OPSTRANSPORT
local prio=string.format("%d/%s", transport.prio, tostring(transport.importance)) ; if transport.urgent then prio=prio.." (!)" end
local carriers=string.format("Ncargo=%d/%d, Ncarriers=%d", transport.Ncargo, transport.Ndelivered, transport.Ncarrier)
text=text..string.format("\n[%d] UID=%d: Status=%s, Prio=%s, Cargo: %s", i, transport.uid, transport:GetState(), prio, carriers)
end
self:I(self.lid..text)
end
-------------------
-- Flotilla Info --
-------------------
if self.verbose>=3 then
local text="Flotillas:"
for i,_flotilla in pairs(self.cohorts) do
local flotilla=_flotilla --Ops.Flotilla#FLOTILLA
local callsign=flotilla.callsignName and UTILS.GetCallsignName(flotilla.callsignName) or "N/A"
local modex=flotilla.modex and flotilla.modex or -1
local skill=flotilla.skill and tostring(flotilla.skill) or "N/A"
-- Flotilla text.
text=text..string.format("\n* %s %s: %s*%d/%d, Callsign=%s, Modex=%d, Skill=%s", flotilla.name, flotilla:GetState(), flotilla.aircrafttype, flotilla:CountAssets(true), #flotilla.assets, callsign, modex, skill)
end
self:I(self.lid..text)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after "NavyOnMission".
-- @param #FLEET self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup Ops army group on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The requested mission.
function FLEET:onafterNavyOnMission(From, Event, To, NavyGroup, Mission)
-- Debug info.
self:T(self.lid..string.format("Group %s on %s mission %s", NavyGroup:GetName(), Mission:GetType(), Mission:GetName()))
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-175
View File
@@ -1,175 +0,0 @@
--- **Ops** - Flotilla is a small naval group belonging to a fleet.
--
-- **Main Features:**
--
-- * Set parameters like livery, skill valid for all flotilla members.
-- * Define mission types, this flotilla can perform (see Ops.Auftrag#AUFTRAG).
-- * Pause/unpause flotilla operations.
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ===
-- @module Ops.Flotilla
-- @image OPS_Flotilla.png
--- FLOTILLA class.
-- @type FLOTILLA
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity level.
-- @field Ops.OpsGroup#OPSGROUP.WeaponData weaponData Weapon data table with key=BitType.
-- @extends Ops.Cohort#COHORT
--- *No captain can do very wrong if he places his ship alongside that of an enemy.* -- Horation Nelson
--
-- ===
--
-- # The FLOTILLA Concept
--
-- A FLOTILLA is an essential part of a FLEET.
--
--
--
-- @field #FLOTILLA
FLOTILLA = {
ClassName = "FLOTILLA",
verbose = 0,
weaponData = {},
}
--- FLOTILLA class version.
-- @field #string version
FLOTILLA.version="0.1.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new FLOTILLA object and start the FSM.
-- @param #FLOTILLA self
-- @param #string TemplateGroupName Name of the template group.
-- @param #number Ngroups Number of asset groups of this flotilla. Default 3.
-- @param #string FlotillaName Name of the flotilla. Must be **unique**!
-- @return #FLOTILLA self
function FLOTILLA:New(TemplateGroupName, Ngroups, FlotillaName)
-- Inherit everything from COHORT class.
local self=BASE:Inherit(self, COHORT:New(TemplateGroupName, Ngroups, FlotillaName)) -- #FLOTILLA
-- All flotillas get mission type Nothing.
self:AddMissionCapability(AUFTRAG.Type.NOTHING, 50)
-- Is naval.
self.isNaval=true
-- Get initial ammo.
self.ammo=self:_CheckAmmo()
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Flotilla specific user functions.
--- Set fleet of this flotilla.
-- @param #FLOTILLA self
-- @param Ops.Fleet#FLEET Fleet The fleet.
-- @return #FLOTILLA self
function FLOTILLA:SetFleet(Fleet)
self.legion=Fleet
return self
end
--- Get fleet of this flotilla.
-- @param #FLOTILLA self
-- @return Ops.Fleet#FLEET The fleet.
function FLOTILLA:GetFleet()
return self.legion
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after Start event. Starts the FLIGHTGROUP FSM and event handlers.
-- @param #FLOTILLA self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function FLOTILLA:onafterStart(From, Event, To)
-- Short info.
local text=string.format("Starting %s v%s %s", self.ClassName, self.version, self.name)
self:I(self.lid..text)
-- Start the status monitoring.
self:__Status(-1)
end
--- On after "Status" event.
-- @param #FLOTILLA self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function FLOTILLA:onafterStatus(From, Event, To)
if self.verbose>=1 then
-- FSM state.
local fsmstate=self:GetState()
local callsign=self.callsignName and UTILS.GetCallsignName(self.callsignName) or "N/A"
local skill=self.skill and tostring(self.skill) or "N/A"
local NassetsTot=#self.assets
local NassetsInS=self:CountAssets(true)
local NassetsQP=0 ; local NassetsP=0 ; local NassetsQ=0
if self.legion then
NassetsQP, NassetsP, NassetsQ=self.legion:CountAssetsOnMission(nil, self)
end
-- Short info.
local text=string.format("%s [Type=%s, Call=%s, Skill=%s]: Assets Total=%d, Stock=%d, Mission=%d [Active=%d, Queue=%d]",
fsmstate, self.aircrafttype, callsign, skill, NassetsTot, NassetsInS, NassetsQP, NassetsP, NassetsQ)
self:T(self.lid..text)
-- Weapon data info.
if self.verbose>=3 and self.weaponData then
local text="Weapon Data:"
for bit,_weapondata in pairs(self.weaponData) do
local weapondata=_weapondata --Ops.OpsGroup#OPSGROUP.WeaponData
text=text..string.format("\n- Bit=%s: Rmin=%.1f km, Rmax=%.1f km", bit, weapondata.RangeMin/1000, weapondata.RangeMax/1000)
end
self:I(self.lid..text)
end
-- Check if group has detected any units.
self:_CheckAssetStatus()
end
if not self:IsStopped() then
self:__Status(-60)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-175
View File
@@ -1,175 +0,0 @@
--- **Ops** - Brigade Platoon.
--
-- **Main Features:**
--
-- * Set parameters like livery, skill valid for all platoon members.
-- * Define modex and callsigns.
-- * Define mission types, this platoon can perform (see Ops.Auftrag#AUFTRAG).
-- * Pause/unpause platoon operations.
--
-- ===
--
-- ### Author: **funkyfranky**
-- @module Ops.Platoon
-- @image OPS_Platoon.png
--- PLATOON class.
-- @type PLATOON
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity level.
-- @field Ops.OpsGroup#OPSGROUP.WeaponData weaponData Weapon data table with key=BitType.
-- @extends Ops.Cohort#COHORT
--- *Some cool cohort quote* -- Known Author
--
-- ===
--
-- # The PLATOON Concept
--
-- A PLATOON is essential part of an BRIGADE.
--
--
--
-- @field #PLATOON
PLATOON = {
ClassName = "PLATOON",
verbose = 0,
weaponData = {},
}
--- PLATOON class version.
-- @field #string version
PLATOON.version="0.1.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new PLATOON object and start the FSM.
-- @param #PLATOON self
-- @param #string TemplateGroupName Name of the template group.
-- @param #number Ngroups Number of asset groups of this platoon. Default 3.
-- @param #string PlatoonName Name of the platoon. Must be **unique**!
-- @return #PLATOON self
function PLATOON:New(TemplateGroupName, Ngroups, PlatoonName)
-- Inherit everything from COHORT class.
local self=BASE:Inherit(self, COHORT:New(TemplateGroupName, Ngroups, PlatoonName)) -- #PLATOON
-- All platoons get mission type Nothing.
self:AddMissionCapability(AUFTRAG.Type.NOTHING, 50)
-- Is ground.
self.isGround=true
-- Get ammo.
self.ammo=self:_CheckAmmo()
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Platoon specific user functions.
--- Set brigade of this platoon.
-- @param #PLATOON self
-- @param Ops.Brigade#BRIGADE Brigade The brigade.
-- @return #PLATOON self
function PLATOON:SetBrigade(Brigade)
self.legion=Brigade
return self
end
--- Get brigade of this platoon.
-- @param #PLATOON self
-- @return Ops.Brigade#BRIGADE The brigade.
function PLATOON:GetBrigade()
return self.legion
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--[[
--- On after Start event. Starts the FLIGHTGROUP FSM and event handlers.
-- @param #PLATOON self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function PLATOON:onafterStart(From, Event, To)
-- Short info.
local text=string.format("Starting %s v%s %s", self.ClassName, self.version, self.name)
self:I(self.lid..text)
-- Start the status monitoring.
self:__Status(-1)
end
]]
--- On after "Status" event.
-- @param #PLATOON self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function PLATOON:onafterStatus(From, Event, To)
if self.verbose>=1 then
-- FSM state.
local fsmstate=self:GetState()
local callsign=self.callsignName and UTILS.GetCallsignName(self.callsignName) or "N/A"
local skill=self.skill and tostring(self.skill) or "N/A"
local NassetsTot=#self.assets
local NassetsInS=self:CountAssets(true)
local NassetsQP=0 ; local NassetsP=0 ; local NassetsQ=0
if self.legion then
NassetsQP, NassetsP, NassetsQ=self.legion:CountAssetsOnMission(nil, self)
end
-- Short info.
local text=string.format("%s [Type=%s, Call=%s, Skill=%s]: Assets Total=%d, Stock=%d, Mission=%d [Active=%d, Queue=%d]",
fsmstate, self.aircrafttype, callsign, skill, NassetsTot, NassetsInS, NassetsQP, NassetsP, NassetsQ)
self:T(self.lid..text)
-- Weapon data info.
if self.verbose>=3 and self.weaponData then
local text="Weapon Data:"
for bit,_weapondata in pairs(self.weaponData) do
local weapondata=_weapondata --Ops.OpsGroup#OPSGROUP.WeaponData
text=text..string.format("\n- Bit=%s: Rmin=%.1f km, Rmax=%.1f km", bit, weapondata.RangeMin/1000, weapondata.RangeMax/1000)
end
self:I(self.lid..text)
end
-- Check if group has detected any units.
self:_CheckAssetStatus()
end
if not self:IsStopped() then
self:__Status(-60)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Misc functions.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-324
View File
@@ -1,324 +0,0 @@
--- **Ops** - Airwing Squadron.
--
-- **Main Features:**
--
-- * Set parameters like livery, skill valid for all squadron members.
-- * Define modex and callsigns.
-- * Define mission types, this squadron can perform (see Ops.Auftrag#AUFTRAG).
-- * Pause/unpause squadron operations.
--
-- ===
--
-- ### Author: **funkyfranky**
-- @module Ops.Squadron
-- @image OPS_Squadron.png
--- SQUADRON class.
-- @type SQUADRON
-- @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 #string name Name of the squadron.
-- @field #string templatename Name of the template group.
-- @field #string aircrafttype Type of the airframe the squadron is using.
-- @field Wrapper.Group#GROUP templategroup Template group.
-- @field #number ngrouping User defined number of units in the asset group.
-- @field #table assets Squadron assets.
-- @field #table missiontypes Capabilities (mission types and performances) of the squadron.
-- @field #number fuellow Low fuel threshold.
-- @field #boolean fuellowRefuel If `true`, flight tries to refuel at the nearest tanker.
-- @field #number maintenancetime Time in seconds needed for maintenance of a returned flight.
-- @field #number repairtime Time in seconds for each
-- @field #string livery Livery of the squadron.
-- @field #number skill Skill of squadron members.
-- @field #number modex Modex.
-- @field #number modexcounter Counter to incease modex number for assets.
-- @field #string callsignName Callsign name.
-- @field #number callsigncounter Counter to increase callsign names for new assets.
-- @field #number Ngroups Number of asset flight groups this squadron has.
-- @field #number engageRange Mission range in meters.
-- @field #string attribute Generalized attribute of the squadron template group.
-- @field #number tankerSystem For tanker squads, the refuel system used (boom=0 or probpe=1). Default nil.
-- @field #number refuelSystem For refuelable squads, the refuel system used (boom=0 or probe=1). Default nil.
-- @field #table tacanChannel List of TACAN channels available to the squadron.
-- @field #number radioFreq Radio frequency in MHz the squad uses.
-- @field #number radioModu Radio modulation the squad uses.
-- @field #string takeoffType Take of type.
-- @field #table parkingIDs Parking IDs for this squadron.
-- @field #boolean despawnAfterLanding Aircraft are despawned after landing.
-- @field #boolean despawnAfterHolding Aircraft are despawned after holding.
-- @extends Ops.Cohort#COHORT
--- *It is unbelievable what a squadron of twelve aircraft did to tip the balance* -- Adolf Galland
--
-- ===
--
-- # The SQUADRON Concept
--
-- A SQUADRON is essential part of an @{Ops.Airwing#AIRWING} and consists of **one** type of aircraft.
--
--
--
-- @field #SQUADRON
SQUADRON = {
ClassName = "SQUADRON",
verbose = 0,
modex = nil,
modexcounter = 0,
callsignName = nil,
callsigncounter= 11,
tankerSystem = nil,
refuelSystem = nil,
}
--- SQUADRON class version.
-- @field #string version
SQUADRON.version="0.8.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- DONE: Parking spots for squadrons?
-- DONE: Engage radius.
-- DONE: Modex.
-- DONE: Call signs.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new SQUADRON object and start the FSM.
-- @param #SQUADRON self
-- @param #string TemplateGroupName Name of the template group.
-- @param #number Ngroups Number of asset groups of this squadron. Default 3.
-- @param #string SquadronName Name of the squadron, e.g. "VFA-37". Must be **unique**!
-- @return #SQUADRON self
function SQUADRON:New(TemplateGroupName, Ngroups, SquadronName)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, COHORT:New(TemplateGroupName, Ngroups, SquadronName)) -- #SQUADRON
-- Everyone can ORBIT.
self:AddMissionCapability(AUFTRAG.Type.ORBIT)
-- Is air.
self.isAir=true
-- Refueling system.
self.refuelSystem=select(2, self.templategroup:GetUnit(1):IsRefuelable())
self.tankerSystem=select(2, self.templategroup:GetUnit(1):IsTanker())
------------------------
--- Pseudo Functions ---
------------------------
-- See COHORT class
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Set number of units in groups.
-- @param #SQUADRON self
-- @param #number nunits Number of units. Must be >=1 and <=4. Default 2.
-- @return #SQUADRON self
function SQUADRON:SetGrouping(nunits)
self.ngrouping=nunits or 2
if self.ngrouping<1 then self.ngrouping=1 end
if self.ngrouping>4 then self.ngrouping=4 end
return self
end
--- Set valid parking spot IDs. Assets of this squad are only allowed to be spawned at these parking spots. **Note** that the IDs are different from the ones displayed in the mission editor!
-- @param #SQUADRON self
-- @param #table ParkingIDs Table of parking ID numbers or a single `#number`.
-- @return #SQUADRON self
function SQUADRON:SetParkingIDs(ParkingIDs)
if type(ParkingIDs)~="table" then
ParkingIDs={ParkingIDs}
end
self.parkingIDs=ParkingIDs
return self
end
--- Set takeoff type. All assets of this squadron will be spawned with cold (default) or hot engines.
-- Spawning on runways is not supported.
-- @param #SQUADRON self
-- @param #string TakeoffType Take off type: "Cold" (default) or "Hot" with engines on or "Air" for spawning in air.
-- @return #SQUADRON self
function SQUADRON:SetTakeoffType(TakeoffType)
TakeoffType=TakeoffType or "Cold"
if TakeoffType:lower()=="hot" then
self.takeoffType=COORDINATE.WaypointType.TakeOffParkingHot
elseif TakeoffType:lower()=="cold" then
self.takeoffType=COORDINATE.WaypointType.TakeOffParking
elseif TakeoffType:lower()=="air" then
self.takeoffType=COORDINATE.WaypointType.TurningPoint
else
self.takeoffType=COORDINATE.WaypointType.TakeOffParking
end
return self
end
--- Set takeoff type cold (default). All assets of this squadron will be spawned with engines off (cold).
-- @param #SQUADRON self
-- @return #SQUADRON self
function SQUADRON:SetTakeoffCold()
self:SetTakeoffType("Cold")
return self
end
--- Set takeoff type hot. All assets of this squadron will be spawned with engines on (hot).
-- @param #SQUADRON self
-- @return #SQUADRON self
function SQUADRON:SetTakeoffHot()
self:SetTakeoffType("Hot")
return self
end
--- Set takeoff type air. All assets of this squadron will be spawned in air above the airbase.
-- @param #SQUADRON self
-- @return #SQUADRON self
function SQUADRON:SetTakeoffAir()
self:SetTakeoffType("Air")
return self
end
--- Set despawn after landing. Aircraft will be despawned after the landing event.
-- Can help to avoid DCS AI taxiing issues.
-- @param #SQUADRON self
-- @param #boolean Switch If `true` (default), activate despawn after landing.
-- @return #SQUADRON self
function SQUADRON:SetDespawnAfterLanding(Switch)
if Switch then
self.despawnAfterLanding=Switch
else
self.despawnAfterLanding=true
end
return self
end
--- Set despawn after holding. Aircraft will be despawned when they arrive at their holding position at the airbase.
-- Can help to avoid DCS AI taxiing issues.
-- @param #SQUADRON self
-- @param #boolean Switch If `true` (default), activate despawn after holding.
-- @return #SQUADRON self
function SQUADRON:SetDespawnAfterHolding(Switch)
if Switch then
self.despawnAfterHolding=Switch
else
self.despawnAfterHolding=true
end
return self
end
--- Set low fuel threshold.
-- @param #SQUADRON self
-- @param #number LowFuel Low fuel threshold in percent. Default 25.
-- @return #SQUADRON self
function SQUADRON:SetFuelLowThreshold(LowFuel)
self.fuellow=LowFuel or 25
return self
end
--- Set if low fuel threshold is reached, flight tries to refuel at the neares tanker.
-- @param #SQUADRON self
-- @param #boolean switch If true or nil, flight goes for refuelling. If false, turn this off.
-- @return #SQUADRON self
function SQUADRON:SetFuelLowRefuel(switch)
if switch==false then
self.fuellowRefuel=false
else
self.fuellowRefuel=true
end
return self
end
--- Set airwing.
-- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING Airwing The airwing.
-- @return #SQUADRON self
function SQUADRON:SetAirwing(Airwing)
self.legion=Airwing
return self
end
--- Get airwing.
-- @param #SQUADRON self
-- @return Ops.AirWing#AIRWING The airwing.
function SQUADRON:GetAirwing(Airwing)
return self.legion
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after Start event. Starts the FLIGHTGROUP FSM and event handlers.
-- @param #SQUADRON self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function SQUADRON:onafterStart(From, Event, To)
-- Short info.
local text=string.format("Starting SQUADRON", self.name)
self:T(self.lid..text)
-- Start the status monitoring.
self:__Status(-1)
end
--- On after "Status" event.
-- @param #SQUADRON self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function SQUADRON:onafterStatus(From, Event, To)
if self.verbose>=1 then
-- FSM state.
local fsmstate=self:GetState()
local callsign=self.callsignName and UTILS.GetCallsignName(self.callsignName) or "N/A"
local modex=self.modex and self.modex or -1
local skill=self.skill and tostring(self.skill) or "N/A"
local NassetsTot=#self.assets
local NassetsInS=self:CountAssets(true)
local NassetsQP=0 ; local NassetsP=0 ; local NassetsQ=0
if self.legion then
NassetsQP, NassetsP, NassetsQ=self.legion:CountAssetsOnMission(nil, self)
end
-- Short info.
local text=string.format("%s [Type=%s, Call=%s, Modex=%d, Skill=%s]: Assets Total=%d, Stock=%d, Mission=%d [Active=%d, Queue=%d]",
fsmstate, self.aircrafttype, callsign, modex, skill, NassetsTot, NassetsInS, NassetsQP, NassetsP, NassetsQ)
self:I(self.lid..text)
-- Check if group has detected any units.
self:_CheckAssetStatus()
end
if not self:IsStopped() then
self:__Status(-60)
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
+6 -463
View File
@@ -46,7 +46,6 @@
-- @field #string path Path to the SRS exe. This includes the final slash "/". -- @field #string path Path to the SRS exe. This includes the final slash "/".
-- @field #string google Full path google credentials JSON file, e.g. "C:\Users\username\Downloads\service-account-file.json". -- @field #string google Full path google credentials JSON file, e.g. "C:\Users\username\Downloads\service-account-file.json".
-- @field #string Label Label showing up on the SRS radio overlay. Default is "ROBOT". No spaces allowed. -- @field #string Label Label showing up on the SRS radio overlay. Default is "ROBOT". No spaces allowed.
-- @field #table AltBackend Table containing functions and variables to enable an alternate backend to transmit to SRS.
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde --- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
@@ -124,50 +123,6 @@
-- --
-- Use @{#MSRS.SetVolume} to define the SRS volume. Defaults to 1.0. Allowed values are between 0.0 and 1.0, from silent to loudest. -- Use @{#MSRS.SetVolume} to define the SRS volume. Defaults to 1.0. Allowed values are between 0.0 and 1.0, from silent to loudest.
-- --
-- ## Set DCS-gRPC as an alternative to 'DCS-SR-ExternalAudio.exe' for TTS
--
-- Use @{#MSRS.SetDefaultBackendGRPC} to enable [DCS-gRPC](https://github.com/DCS-gRPC/rust-server) as an alternate backend for transmitting text-to-speech over SRS.
-- This can be useful if 'DCS-SR-ExternalAudio.exe' cannot be used in the environment, or to use Azure or AWS clouds for TTS. Note that DCS-gRPC does not (yet?) support
-- all of the features and options available with 'DCS-SR-ExternalAudio.exe'. Of note, only text-to-speech is supported and it it cannot be used to transmit audio files.
--
-- DCS-gRPC must be installed and configured per the [DCS-gRPC documentation](https://github.com/DCS-gRPC/rust-server) and already running via either the 'autostart' mechanism
-- or a Lua call to 'GRPC.load()' prior to use of the alternate DCS-gRPC backend. If a cloud TTS provider is being used, the API key must be set via the 'Config\dcs-grpc.lua'
-- configuration file prior DCS-gRPC being started. DCS-gRPC can be used both with DCS dedicated server and regular DCS installations.
--
-- To use the default local Windows TTS with DCS-gRPC, Windows 2019 Server (or newer) or Windows 10/11 are required. Voices for non-local languages and dialects may need to
-- be explicitly installed.
--
-- To set the MSRS class to use the DCS-gRPC backend for all future instances, call the function `MSRS.SetDefaultBackendGRPC()`.
--
-- **Note** - When using other classes that use MSRS with the alternate DCS-gRPC backend, pass them strings instead of nil values for non-applicable fields with filesystem paths,
-- such as the SRS path or Google credential path. This will help maximize compatibility with other classes that were written for the default backend.
--
-- Basic Play Text-To-Speech example using alternate DCS-gRPC backend (DCS-gRPC not previously started):
--
-- -- Start DCS-gRPC
-- GRPC.load()
-- -- Select the alternate DCS-gRPC backend for new MSRS instances
-- MSRS.SetDefaultBackendGRPC()
-- -- Create a SOUNDTEXT object.
-- local text=SOUNDTEXT:New("All Enemies destroyed")
-- -- MOOSE SRS
-- local msrs=MSRS:New('', 305.0)
-- -- Text-to speech with default voice after 30 seconds.
-- msrs:PlaySoundText(text, 30)
--
-- Basic example of using another class (ATIS) with SRS and the DCS-gRPC backend (DCS-gRPC not previously started):
--
-- -- Start DCS-gRPC
-- GRPC.load()
-- -- Select the alternate DCS-gRPC backend for new MSRS instances
-- MSRS.SetDefaultBackendGRPC()
-- -- Create new ATIS as usual
-- atis=ATIS:New("Nellis", 251, radio.modulation.AM)
-- -- ATIS:SetSRS() expects a string for the SRS path even though it is not needed with DCS-gRPC
-- atis:SetSRS('')
-- -- Start ATIS
-- atis:Start()
--
-- @field #MSRS -- @field #MSRS
MSRS = { MSRS = {
ClassName = "MSRS", ClassName = "MSRS",
@@ -184,12 +139,11 @@ MSRS = {
speed = 1, speed = 1,
coordinate = nil, coordinate = nil,
Label = "ROBOT", Label = "ROBOT",
AltBackend = nil,
} }
--- MSRS class version. --- MSRS class version.
-- @field #string version -- @field #string version
MSRS.version="0.1.2" MSRS.version="0.1.1"
--- Voices --- Voices
-- @type Voices -- @type Voices
@@ -310,35 +264,16 @@ MSRS.Voices = {
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. Can also be given as a #table of multiple frequencies. -- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. Can also be given as a #table of multiple frequencies.
-- @param #number Modulation Radio modulation: 0=AM (default), 1=FM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators. Can also be given as a #table of multiple modulations. -- @param #number Modulation Radio modulation: 0=AM (default), 1=FM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators. Can also be given as a #table of multiple modulations.
-- @param #number Volume Volume - 1.0 is max, 0.0 is silence -- @param #number Volume Volume - 1.0 is max, 0.0 is silence
-- @param #table AltBackend Optional table containing tables 'Functions' and 'Vars' which add/replace functions and variables for the MSRS instance to allow alternate backends for transmitting to SRS.
-- @return #MSRS self -- @return #MSRS self
function MSRS:New(PathToSRS, Frequency, Modulation, Volume, AltBackend) function MSRS:New(PathToSRS, Frequency, Modulation, Volume)
-- Defaults. -- Defaults.
Frequency = Frequency or 143 Frequency =Frequency or 143
Modulation = Modulation or radio.modulation.AM Modulation= Modulation or radio.modulation.AM
-- Inherit everything from FSM class. -- Inherit everything from FSM class.
local self=BASE:Inherit(self, BASE:New()) -- #MSRS local self=BASE:Inherit(self, BASE:New()) -- #MSRS
-- If AltBackend is supplied, initialize it, which will add/replace functions and variables in this MSRS instance.
if type( AltBackend ) == "table" or type( self.AltBackend ) == "table" then
local Backend = UTILS.DeepCopy(AltBackend) or UTILS.DeepCopy(self.AltBackend)
-- Add parameters to vars so alternate backends can use them if applicable
Backend.Vars = Backend.Vars or {}
Backend.Vars.PathToSRS = UTILS.DeepCopy(PathToSRS) -- DeepCopy probably unecessary
Backend.Vars.Frequency = UTILS.DeepCopy(Frequency)
Backend.Vars.Modulation = UTILS.DeepCopy(Modulation)
Backend.Vars.Volume = UTILS.DeepCopy(Volume) -- DeepCopy probably unecessary
Backend.Functions = Backend.Functions or {}
return self:_NewAltBackend(Backend)
end
-- If no AltBackend table, the proceed with default initialization
self:SetPath(PathToSRS) self:SetPath(PathToSRS)
self:SetPort() self:SetPort()
self:SetFrequencies(Frequency) self:SetFrequencies(Frequency)
@@ -633,32 +568,6 @@ function MSRS:Help()
return self return self
end end
--- Sets an alternate SRS backend to be used by MSRS to transmit over SRS for all new MSRS class instances.
-- @param #table A table containing a table `Functions` with new/replacement class functions and `Vars` with new/replacement variables.
-- @return #boolean Returns 'true' on success.
function MSRS.SetDefaultBackend(Backend)
if type(Backend) == "table" then
MSRS.AltBackend = UTILS.DeepCopy(Backend)
else
return false
end
return true
end
--- Restores default SRS backend (DCS-SR-ExternalAudio.exe) to be used by all new MSRS class instances to transmit over SRS.
-- @return #boolean Returns 'true' on success.
function MSRS.ResetDefaultBackend()
MSRS.AltBackend = nil
return true
end
--- Sets DCS-gRPC as the default SRS backend for all new MSRS class instances.
-- @return #boolean Returns 'true' on success.
function MSRS.SetDefaultBackendGRPC()
return MSRS.SetDefaultBackend(MSRS_BACKEND_DCSGRPC)
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Transmission Functions -- Transmission Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -827,35 +736,6 @@ end
-- Misc Functions -- Misc Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Adds or replaces functions and variables in the current MSRS class instance to enable an alternate backends for transmitting to SRS.
-- @param #MSRS self
-- @param #table A table containing a table `Functions` with new/replacement class functions and `Vars` with new/replacement variables.
-- @return #MSRS self
function MSRS:_NewAltBackend(Backend)
BASE:T('Entering MSRS:_NewAltBackend()')
-- Add/replace class instance functions with those defined in the alternate backend in Functions table
for funcName,funcDef in pairs(Backend.Functions) do
if type(funcDef) == 'function' then
BASE:T('MSRS (re-)defining function MSRS:' .. funcName )
self[funcName] = funcDef
end
end
-- Add/replace class instance variables with those defined in the alternate backend in Vars table
for varName,varVal in pairs(Backend.Vars) do
BASE:T('MSRS setting self.' .. varName)
self[varName] = UTILS.DeepCopy(varVal)
end
-- If _MSRSbackendInit() is defined in the backend, then run it (it should return self)
if self._MSRSbackendInit and type(self._MSRSbackendInit) == 'function' then
return self:_MSRSbackendInit()
end
return self
end
--- Execute SRS command to play sound using the `DCS-SR-ExternalAudio.exe`. --- Execute SRS command to play sound using the `DCS-SR-ExternalAudio.exe`.
-- @param #MSRS self -- @param #MSRS self
-- @param #string command Command to executer -- @param #string command Command to executer
@@ -900,23 +780,6 @@ function MSRS:_ExecCommand(command)
timer.scheduleFunction(os.remove, filename, timer.getTime()+1) timer.scheduleFunction(os.remove, filename, timer.getTime()+1)
timer.scheduleFunction(os.remove, filenvbs, timer.getTime()+1) timer.scheduleFunction(os.remove, filenvbs, timer.getTime()+1)
elseif false then
-- Create a tmp file.
local filenvbs = os.getenv('TMP') .. "\\MSRS-"..STTS.uuid()..".vbs"
-- VBS script
local script = io.open(filenvbs, "w+")
script:write(string.format('Set oShell = CreateObject ("Wscript.Shell")\n'))
script:write(string.format('Dim strArgs\n'))
script:write(string.format('strArgs = "cmd /c %s"\n', filename))
script:write(string.format('oShell.Run strArgs, 0, false'))
script:close()
local runvbs=string.format('cscript.exe //Nologo //B "%s"', filenvbs)
-- Play file in 0.01 seconds
res=os.execute(runvbs)
else else
@@ -1016,311 +879,6 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
return command return command
end end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- MSRS DCS-gRPC alternate backend
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Alternate backend for MSRS to enable text-to-speech via DCS-gRPC.
-- ### Author: **dogjutsu**
-- A table containing functions and variables for MSRS to use DCS-gRPC [DCS-gRPC](https://github.com/DCS-gRPC/rust-server) 0.7.0 or newer as a backend to transmit over SRS.
-- This is not a standalone class. Instead, variables and functions under the `Vars` and `Functions` tables get added to or replace MSRS variables/functions when activated.
--
-- @type MSRS_BACKEND_DCSGRPC
-- @field #number version Version number of this alternate backend.
-- @field #table Functions A table of functions that will add or replace the default MSRS class functions.
-- @field #table Vars A table of variables that will add or replace the default MSRS class variables.
MSRS_BACKEND_DCSGRPC = {}
MSRS_BACKEND_DCSGRPC.version = 0.1
MSRS_BACKEND_DCSGRPC.Functions = {}
MSRS_BACKEND_DCSGRPC.Vars = { provider = 'win' }
--- Called by @{#MSRS._NewAltBackend} (if present) immediately after an alternate backend functions and variables for MSRS are added/replaced.
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions._MSRSbackendInit = function (self)
BASE:I('Loaded MSRS DCS-gRPC alternate backend version ' .. self.AltBackend.version or 'unspecified')
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- MSRS DCS-gRPC alternate backend User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- No-op replacement function for @{#MSRS.SetPath} (Not Applicable)
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.SetPath = function (self)
return self
end
--- No-op replacement function for @{#MSRS.GetPath} (Not Applicable)
-- @param #MSRS self
-- @return #string Empty string
MSRS_BACKEND_DCSGRPC.Functions.GetPath = function (self)
return ''
end
--- No-op replacement function for @{#MSRS.SetVolume} (Not Applicable)
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.SetVolume = function (self)
BASE:I('NOTE: MSRS:SetVolume() not used with DCS-gRPC backend.')
return self
end
--- No-op replacement function for @{#MSRS.GetVolume} (Not Applicable)
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.GetVolume = function (self)
BASE:I('NOTE: MSRS:GetVolume() not used with DCS-gRPC backend.')
return 1
end
--- No-op replacement function for @{#MSRS.SetGender} (Not Applicable)
-- @param #MSRS self
-- #string Gender Gender: "male" or "female"
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.SetGender = function (self, Gender)
-- Use DCS-gRPC default if not specified
if Gender then
self.gender=Gender:lower()
end
-- Debug output.
self:T("Setting gender to "..tostring(self.gender))
return self
end
--- Replacement function for @{#MSRS.SetGoogle} to use google text-to-speech. (API key set as part of DCS-gRPC configuration)
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.SetGoogle = function (self)
self.provider = 'gcloud'
return self
end
--- MSRS:SetAWS() Use AWS text-to-speech. (API key set as part of DCS-gRPC configuration)
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.SetAWS = function (self)
self.provider = 'aws'
return self
end
--- MSRS:SetAzure() Use Azure text-to-speech. (API key set as part of DCS-gRPC configuration)
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.SetAzure = function (self)
self.provider = 'azure'
return self
end
--- MSRS:SetWin() Use local Windows OS text-to-speech (Windows Server 2019 / Windows 11 / Windows 10? or newer). (Default)
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.SetWin = function (self)
self.provider = 'win'
return self
end
--- Replacement function for @{#MSRS.Help} to display help.
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.Help = function (self)
env.info('For DCS-gRPC help, please see: https://github.com/DCS-gRPC/rust-server')
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- MSRS DCS-gRPC alternate backend Transmission Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- No-op replacement function for @{#MSRS.PlaySoundFile} (Not Applicable)
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.PlaySoundFile = function (self)
BASE:E("ERROR: MSRS:PlaySoundFile() is not supported by the DCS-gRPC backend.")
return self
end
--- Replacement function for @{#MSRS.PlaySoundText}
-- @param #MSRS self
-- @param Sound.SoundFile#SOUNDTEXT SoundText Sound text.
-- @param #number Delay Delay in seconds, before the sound file is played.
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.PlaySoundText = function (self, SoundText, Delay)
if Delay and Delay>0 then
self:ScheduleOnce(Delay, self.PlaySoundText, self, SoundText, 0)
else
self:_DCSgRPCtts(tostring(SoundText.text))
end
return self
end
--- Replacement function for @{#MSRS.PlayText}
-- @param #MSRS self
-- @param #string Text Text message.
-- @param #number Delay Delay in seconds, before the message is played.
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.PlayText = function (self, Text, Delay)
if Delay and Delay>0 then
self:ScheduleOnce(Delay, self.PlayText, self, Text, 0)
else
self:_DCSgRPCtts(tostring(Text))
end
return self
end
--- Replacement function for @{#MSRS.PlayText}
-- @param #MSRS self
-- @param #string Text Text message.
-- @param #number Delay Delay in seconds, before the message is played.
-- @param #table Frequencies Radio frequencies.
-- @param #table Modulations Radio modulations. (Non-functional, DCS-gRPC sets automatically)
-- @param #string Gender Gender. (Non-functional, only 'Voice' supported)
-- @param #string Culture Culture. (Non-functional, only 'Voice' supported)
-- @param #string Voice Voice.
-- @param #number Volume Volume. (Non-functional, all transmissions full volume with DCS-gRPC)
-- @param #string Label Label.
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.PlayTextExt = function (self, Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
if Delay and Delay>0 then
self:ScheduleOnce(Delay, self.PlayTextExt, self, Text, 0, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
else
self:_DCSgRPCtts(tostring(Text, nil, Frequencies, Voice, Label))
end
return self
end
--- No-op replacement function for @{#MSRS.PlayTextFile} (Not Applicable)
-- @param #MSRS self
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions.PlayTextFile = function (self, TextFile, Delay)
BASE:E("ERROR: MSRS:PlayTextFile() is not supported by the DCS-gRPC backend.")
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- MSRS DCS-gRPC alternate backend Misc Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- DCS-gRPC v0.70 TTS API call:
-- GRPC.tts(ssml, frequency[, options]) - Synthesize text (ssml; SSML tags supported) to speech and transmit it over SRS on the frequency with the following optional options (and their defaults):
-- {
-- -- The plain text without any transformations made to it for the purpose of getting it spoken out
-- -- as desired (no SSML tags, no FOUR NINER instead of 49, ...). Even though this field is
-- -- optional, please consider providing it as it can be used to display the spoken text to players
-- -- with hearing impairments.
-- plaintext = null, -- e.g. `= "Hello Pilot"`
-- -- Name of the SRS client.
-- srsClientName = "DCS-gRPC",
-- -- The origin of the transmission. Relevant if the SRS server has "Line of
-- -- Sight" and/or "Distance Limit" enabled.
-- position = {
-- lat = 0.0,
-- lon = 0.0,
-- alt = 0.0, -- in meters
-- },
-- -- The coalition of the transmission. Relevant if the SRS server has "Secure
-- -- Coalition Radios" enabled. Supported values are: `blue` and `red`. Defaults
-- -- to being spectator if not specified.
-- coalition = null,
-- -- TTS provider to be use. Defaults to the one configured in your config or to Windows'
-- -- built-in TTS. Examples:
-- -- `= { aws = {} }` / `= { aws = { voice = "..." } }` enable AWS TTS
-- -- `= { azure = {} }` / `= { azure = { voice = "..." } }` enable Azure TTS
-- -- `= { gcloud = {} }` / `= { gcloud = { voice = "..." } }` enable Google Cloud TTS
-- -- `= { win = {} }` / `= { win = { voice = "..." } }` enable Windows TTS
-- provider = null,
-- }
--- Make DCS-gRPC API call to transmit text-to-speech over SRS.
-- @param #MSRS self
-- @param #string Text Text of message to transmit (can also be SSML).
-- @param #string Optional plaintext version of message (for accessiblity)
-- @param #table Frequencies Radio frequencies to transmit on. Can also accept a number in MHz.
-- @param #string Voice Voice for the TTS provider to user.
-- @param #string Label Label (SRS diplays as name of the transmitter).
-- @return #MSRS self
MSRS_BACKEND_DCSGRPC.Functions._DCSgRPCtts = function (self, Text, Plaintext, Frequencies, Voice, Label)
BASE:T("MSRS_BACKEND_DCSGRPC:_DCSgRPCtts()")
BASE:T({Text, Plaintext, Frequencies, Voice, Label})
local options = {}
local ssml = Text or ''
local XmitFrequencies = Frequencies or self.Frequency
if type(XmitFrequencies)~="table" then
XmitFrequencies={XmitFrequencies}
end
options.plaintext = Plaintext
options.srsClientName = Label or self.Label
options.position = {}
if self.coordinate then
options.position.lat, options.position.lat, options.position.alt = self:_GetLatLongAlt(self.coordinate)
end
options.position.lat = options.position.lat or 0.0
options.position.lon = options.position.lon or 0.0
options.position.alt = options.position.alt or 0.0
if UTILS.GetCoalitionName(self.coalition) == 'Blue' then
options.coalition = 'blue'
elseif UTILS.GetCoalitionName(self.coalition) == 'Red' then
options.coalition = 'red'
end
options.provider = {}
options.provider[self.provider] = {}
if self.voice then
options.provider[self.provider].voice = Voice or self.voice
elseif ssml then
-- DCS-gRPC doesn't directly support language/gender, but can use SSML
-- Only use if a voice isn't explicitly set
local preTag, genderProp, langProp, postTag = '', '', '', ''
if self.gender then
genderProp = ' gender=\"' .. self.gender .. '\"'
end
if self.culture then
langProp = ' language=\"' .. self.culture .. '\"'
end
if self.culture or self.gender then
preTag = '<voice' .. langProp .. genderProp .. '>'
postTag = '</voice>'
ssml = preTag .. Text .. postTag
end
end
for _,_freq in ipairs(XmitFrequencies) do
local freq = _freq*1000000
BASE:T("GRPC.tts")
BASE:T(ssml)
BASE:T(freq)
BASE:T(options)
GRPC.tts(ssml, freq, options)
end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Manages radio transmissions. --- Manages radio transmissions.
@@ -1364,11 +922,6 @@ MSRSQUEUE = {
-- @field #number interval Interval in seconds before next transmission. -- @field #number interval Interval in seconds before next transmission.
-- @field #boolean TransmitOnlyWithPlayers If true, only transmit if there are alive Players. -- @field #boolean TransmitOnlyWithPlayers If true, only transmit if there are alive Players.
-- @field Core.Set#SET_CLIENT PlayerSet PlayerSet created when TransmitOnlyWithPlayers == true -- @field Core.Set#SET_CLIENT PlayerSet PlayerSet created when TransmitOnlyWithPlayers == true
-- @field #string gender Voice gender
-- @field #string culture Voice culture
-- @field #string voice Voice if any
-- @field #number volume Volume
-- @field #string label Label to be used
--- Create a new MSRSQUEUE object for a given radio frequency/modulation. --- Create a new MSRSQUEUE object for a given radio frequency/modulation.
-- @param #MSRSQUEUE self -- @param #MSRSQUEUE self
@@ -1448,13 +1001,8 @@ end
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec. -- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
-- @param #number frequency Radio frequency if other than MSRS default. -- @param #number frequency Radio frequency if other than MSRS default.
-- @param #number modulation Radio modulation if other then MSRS default. -- @param #number modulation Radio modulation if other then MSRS default.
-- @param #string gender Gender of the voice
-- @param #string culture Culture of the voice
-- @param #string voice Specific voice
-- @param #number volume Volume setting
-- @param #string label Label to be used
-- @return #MSRSQUEUE.Transmission Radio transmission table. -- @return #MSRSQUEUE.Transmission Radio transmission table.
function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgroups, subtitle, subduration, frequency, modulation, gender, culture, voice, volume, label) function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgroups, subtitle, subduration, frequency, modulation)
if self.TransmitOnlyWithPlayers then if self.TransmitOnlyWithPlayers then
if self.PlayerSet and self.PlayerSet:CountAlive() == 0 then if self.PlayerSet and self.PlayerSet:CountAlive() == 0 then
@@ -1489,11 +1037,6 @@ function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgr
else else
transmission.subduration=0 --nil transmission.subduration=0 --nil
end end
transmission.gender = gender
transmission.culture = culture
transmission.voice = voice
transmission.gender = volume
transmission.label = label
-- Add transmission to queue. -- Add transmission to queue.
self:AddTransmission(transmission) self:AddTransmission(transmission)
@@ -1507,7 +1050,7 @@ end
function MSRSQUEUE:Broadcast(transmission) function MSRSQUEUE:Broadcast(transmission)
if transmission.frequency then if transmission.frequency then
transmission.msrs:PlayTextExt(transmission.text, nil, transmission.frequency, transmission.modulation, transmission.gender, transmission.culture, transmission.voice, transmission.volume, transmission.label) transmission.msrs:PlayTextExt(transmission.text, nil, transmission.frequency, transmission.modulation, Gender, Culture, Voice, Volume, Label)
else else
transmission.msrs:PlayText(transmission.text) transmission.msrs:PlayText(transmission.text)
end end
+575
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"
+158 -14
View File
@@ -295,8 +295,9 @@ UTILS.DeepCopy = function(object)
end end
--- Porting in Slmod's serialize_slmod2. --- Serialize a given table.
-- @param #table tbl Input table. -- @param #table tbl Input table.
-- @return #string Table as a string.
UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
local lookup_table = {} local lookup_table = {}
@@ -373,7 +374,54 @@ local lookup_table = {}
return objectreturn return objectreturn
end end
--porting in Slmod's "safestring" basic serialize --- Serialize a table to a single line string.
-- @param #table tbl table to serialize.
-- @return #string string containing serialized table.
function UTILS._OneLineSerialize(tbl)
if type(tbl) == 'table' then --function only works for tables!
local tbl_str = {}
tbl_str[#tbl_str + 1] = '{ '
for ind,val in pairs(tbl) do -- serialize its fields
if type(ind) == "number" then
tbl_str[#tbl_str + 1] = '['
tbl_str[#tbl_str + 1] = tostring(ind)
tbl_str[#tbl_str + 1] = '] = '
else --must be a string
tbl_str[#tbl_str + 1] = '['
tbl_str[#tbl_str + 1] = UTILS.BasicSerialize(ind)
tbl_str[#tbl_str + 1] = '] = '
end
if ((type(val) == 'number') or (type(val) == 'boolean')) then
tbl_str[#tbl_str + 1] = tostring(val)
tbl_str[#tbl_str + 1] = ', '
elseif type(val) == 'string' then
tbl_str[#tbl_str + 1] = UTILS.BasicSerialize(val)
tbl_str[#tbl_str + 1] = ', '
elseif type(val) == 'nil' then -- won't ever happen, right?
tbl_str[#tbl_str + 1] = 'nil, '
elseif type(val) == 'table' then
tbl_str[#tbl_str + 1] = UTILS._OneLineSerialize(val)
tbl_str[#tbl_str + 1] = ', ' --I think this is right, I just added it
else
--log:warn('Unable to serialize value type $1 at index $2', mist.utils.basicSerialize(type(val)), tostring(ind))
end
end
tbl_str[#tbl_str + 1] = '}'
return table.concat(tbl_str)
else
return UTILS.BasicSerialize(tbl)
end
end
--- Basic serialize (porting in Slmod's "safestring" basic serialize).
-- @param #string s Table to serialize.
UTILS.BasicSerialize = function(s) UTILS.BasicSerialize = function(s)
if s == nil then if s == nil then
return "\"\"" return "\"\""
@@ -404,6 +452,114 @@ function UTILS.PrintTableToLog(table, indent)
end end
end end
--- Returns table in a easy readable string representation.
-- @param tbl table to show
-- @param loc
-- @param indent
-- @param tableshow_tbls
-- @return Human readable string representation of given table.
function UTILS.TableShow(tbl, loc, indent, tableshow_tbls)
tableshow_tbls = tableshow_tbls or {} --create table of tables
loc = loc or ""
indent = indent or ""
if type(tbl) == 'table' then --function only works for tables!
tableshow_tbls[tbl] = loc
local tbl_str = {}
tbl_str[#tbl_str + 1] = indent .. '{\n'
for ind,val in pairs(tbl) do -- serialize its fields
if type(ind) == "number" then
tbl_str[#tbl_str + 1] = indent
tbl_str[#tbl_str + 1] = loc .. '['
tbl_str[#tbl_str + 1] = tostring(ind)
tbl_str[#tbl_str + 1] = '] = '
else
tbl_str[#tbl_str + 1] = indent
tbl_str[#tbl_str + 1] = loc .. '['
tbl_str[#tbl_str + 1] = UTILS.BasicSerialize(ind)
tbl_str[#tbl_str + 1] = '] = '
end
if ((type(val) == 'number') or (type(val) == 'boolean')) then
tbl_str[#tbl_str + 1] = tostring(val)
tbl_str[#tbl_str + 1] = ',\n'
elseif type(val) == 'string' then
tbl_str[#tbl_str + 1] = UTILS.BasicSerialize(val)
tbl_str[#tbl_str + 1] = ',\n'
elseif type(val) == 'nil' then -- won't ever happen, right?
tbl_str[#tbl_str + 1] = 'nil,\n'
elseif type(val) == 'table' then
if tableshow_tbls[val] then
tbl_str[#tbl_str + 1] = tostring(val) .. ' already defined: ' .. tableshow_tbls[val] .. ',\n'
else
tableshow_tbls[val] = loc .. '[' .. UTILS.BasicSerialize(ind) .. ']'
tbl_str[#tbl_str + 1] = tostring(val) .. ' '
tbl_str[#tbl_str + 1] = UTILS.TableShow(val, loc .. '[' .. UTILS.BasicSerialize(ind).. ']', indent .. ' ', tableshow_tbls)
tbl_str[#tbl_str + 1] = ',\n'
end
elseif type(val) == 'function' then
if debug and debug.getinfo then
local fcnname = tostring(val)
local info = debug.getinfo(val, "S")
if info.what == "C" then
tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', C function') .. ',\n'
else
if (string.sub(info.source, 1, 2) == [[./]]) then
tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')' .. info.source) ..',\n'
else
tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')') ..',\n'
end
end
else
tbl_str[#tbl_str + 1] = 'a function,\n'
end
else
tbl_str[#tbl_str + 1] = 'unable to serialize value type ' .. UTILS.BasicSerialize(type(val)) .. ' at index ' .. tostring(ind)
end
end
tbl_str[#tbl_str + 1] = indent .. '}'
return table.concat(tbl_str)
end
end
--- Dumps the global table _G.
-- This dumps the global table _G to a file in the DCS\Logs directory.
-- This function requires you to disable script sanitization in $DCS_ROOT\Scripts\MissionScripting.lua to access lfs and io libraries.
-- @param #string fname File name.
function UTILS.Gdump(fname)
if lfs and io then
local fdir = lfs.writedir() .. [[Logs\]] .. fname
local f = io.open(fdir, 'w')
f:write(UTILS.TableShow(_G))
f:close()
env.info(string.format('Wrote debug data to $1', fdir))
else
env.error("WARNING: lfs and/or io not de-sanitized - cannot dump _G!")
end
end
--- Executes the given string.
-- borrowed from Slmod
-- @param #string s string containing LUA code.
-- @return #boolean `true` if successfully executed, `false` otherwise.
function UTILS.DoString(s)
local f, err = loadstring(s)
if f then
return true, f()
else
return false, err
end
end
UTILS.ToDegree = function(angle) UTILS.ToDegree = function(angle)
return angle*180/math.pi return angle*180/math.pi
@@ -555,18 +711,6 @@ UTILS.kg2lbs = function( kg )
return kg * 2.20462 return kg * 2.20462
end end
--- Convert latitude or longitude from degrees, minutes, seconds (DMS) to decimal degrees (DD).
-- @param #number Degrees Degrees in grad.
-- @param #number Minutes Minutes.
-- @param #number Seconds Seconds.
-- @return #number Latitude or Longitude in decimal degrees.
UTILS.LLDMSToDD = function(Degrees, Minutes, Seconds)
local dd=(Degrees or 0) + (Minutes or 0)/60 + (Seconds or 0)/3600
return dd
end
--[[acc: --[[acc:
in DM: decimal point of minutes. in DM: decimal point of minutes.
In DMS: decimal point of seconds. In DMS: decimal point of seconds.
+96 -1
View File
@@ -11,7 +11,7 @@
-- @module Wrapper.Airbase -- @module Wrapper.Airbase
-- @image Wrapper_Airbase.JPG -- @image Wrapper_Airbase.JPG
---
-- @type AIRBASE -- @type AIRBASE
-- @field #string ClassName Name of the class, i.e. "AIRBASE". -- @field #string ClassName Name of the class, i.e. "AIRBASE".
-- @field #table CategoryName Names of airbase categories. -- @field #table CategoryName Names of airbase categories.
@@ -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:
@@ -548,6 +549,8 @@ AIRBASE.Syria={
-- * AIRBASE.MarianaIslands.Saipan_Intl -- * AIRBASE.MarianaIslands.Saipan_Intl
-- * AIRBASE.MarianaIslands.Tinian_Intl -- * AIRBASE.MarianaIslands.Tinian_Intl
-- * AIRBASE.MarianaIslands.Olf_Orote -- * AIRBASE.MarianaIslands.Olf_Orote
-- * AIRBASE.MarianaIslands.Pagan_Airstrip
-- * AIRBASE.MarianaIslands.North_West_Field
-- --
-- @field MarianaIslands -- @field MarianaIslands
AIRBASE.MarianaIslands = { AIRBASE.MarianaIslands = {
@@ -557,6 +560,8 @@ AIRBASE.MarianaIslands = {
["Saipan_Intl"] = "Saipan Intl", ["Saipan_Intl"] = "Saipan Intl",
["Tinian_Intl"] = "Tinian Intl", ["Tinian_Intl"] = "Tinian Intl",
["Olf_Orote"] = "Olf Orote", ["Olf_Orote"] = "Olf Orote",
["Pagan_Airstrip"] = "Pagan Airstrip",
["North_West_Field"] = "North West Field",
} }
--- Airbases of the South Atlantic map: --- Airbases of the South Atlantic map:
@@ -788,6 +793,12 @@ function AIRBASE:Register(AirbaseName)
-- Category. -- Category.
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
-- H2 is bugged
--if self.AirbaseName == "H4" and self.descriptors == nil then
--self:E("***** H4 on Syria map is currently bugged!")
--return nil
--end
-- Set category. -- Set category.
if self.category==Airbase.Category.AIRDROME then if self.category==Airbase.Category.AIRDROME then
self.isAirdrome=true self.isAirdrome=true
@@ -823,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)
@@ -909,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
+9 -13
View File
@@ -35,7 +35,6 @@ do
-- @field #number id -- @field #number id
-- @field #number side -- @field #number side
-- @field #number slot -- @field #number slot
-- @field #numner timestamp
--- Encapsules multiplayer environment scripting functions from [net](https://wiki.hoggitworld.com/view/DCS_singleton_net) --- Encapsules multiplayer environment scripting functions from [net](https://wiki.hoggitworld.com/view/DCS_singleton_net)
-- with some added FSM functions and options to block/unblock players in MP environments. -- with some added FSM functions and options to block/unblock players in MP environments.
@@ -206,7 +205,7 @@ function NET:_EventHandler(EventData)
-- Joining -- Joining
if data.id == EVENTS.PlayerEnterUnit or data.id == EVENTS.PlayerEnterAircraft then if data.id == EVENTS.PlayerEnterUnit or data.id == EVENTS.PlayerEnterAircraft then
self:T(self.lid.."Pilot Joining: "..name.." | UCID: "..ucid.." | Event ID: "..data.id) self:T(self.lid.."Pilot Joining: "..name.." | UCID: "..ucid)
-- Check for blockages -- Check for blockages
local blocked = self:IsAnyBlocked(ucid,name,PlayerID,PlayerSide,PlayerSlot) local blocked = self:IsAnyBlocked(ucid,name,PlayerID,PlayerSide,PlayerSlot)
@@ -214,18 +213,15 @@ function NET:_EventHandler(EventData)
-- block pilot -- block pilot
local outcome = net.force_player_slot(tonumber(PlayerID), 0, '' ) local outcome = net.force_player_slot(tonumber(PlayerID), 0, '' )
else else
self.KnownPilots[name] = {
name = name,
ucid = ucid,
id = PlayerID,
side = PlayerSide,
slot = PlayerSlot,
}
local client = CLIENT:FindByPlayerName(name) or data.IniUnit local client = CLIENT:FindByPlayerName(name) or data.IniUnit
if not self.KnownPilots[name] or (self.KnownPilots[name] and TNow-self.KnownPilots[name].timestamp > 3) then self:__PlayerJoined(1,client,name)
self:__PlayerJoined(1,client,name)
self.KnownPilots[name] = {
name = name,
ucid = ucid,
id = PlayerID,
side = PlayerSide,
slot = PlayerSlot,
timestamp = TNow,
}
end
return self return self
end end
end end
@@ -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
+62 -27
View File
@@ -18,6 +18,7 @@
-- @field #string SceneryName Name of the scenery object. -- @field #string SceneryName Name of the scenery object.
-- @field DCS#Object SceneryObject DCS scenery object. -- @field DCS#Object SceneryObject DCS scenery object.
-- @field #number Life0 Initial life points. -- @field #number Life0 Initial life points.
-- @field #table Properties
-- @extends Wrapper.Positionable#POSITIONABLE -- @extends Wrapper.Positionable#POSITIONABLE
@@ -43,7 +44,7 @@ function SCENERY:Register( SceneryName, SceneryObject )
local self = BASE:Inherit( self, POSITIONABLE:New( SceneryName ) ) local self = BASE:Inherit( self, POSITIONABLE:New( SceneryName ) )
self.SceneryName = SceneryName self.SceneryName = tostring(SceneryName)
self.SceneryObject = SceneryObject self.SceneryObject = SceneryObject
@@ -52,9 +53,43 @@ function SCENERY:Register( SceneryName, SceneryObject )
else else
self.Life0 = 0 self.Life0 = 0
end end
self.Properties = {}
return self return self
end end
--- Returns the Value of the zone with the given PropertyName, or nil if no matching property exists.
-- @param #SCENERY self
-- @param #string PropertyName The name of a the QuadZone Property from the scenery assignment to be retrieved.
-- @return #string The Value of the QuadZone Property from the scenery assignment with the given PropertyName, or nil if absent.
function SCENERY:GetProperty(PropertyName)
return self.Properties[PropertyName]
end
--- Returns the scenery Properties table.
-- @param #SCENERY self
-- @return #table The Key:Value table of QuadZone properties of the zone from the scenery assignment .
function SCENERY:GetAllProperties()
return self.Properties
end
--- Set a scenery property
-- @param #SCENERY self
-- @param #string PropertyName
-- @param #string PropertyValue
-- @return #SCENERY self
function SCENERY:SetProperty(PropertyName, PropertyValue)
self.Properties[PropertyName] = PropertyValue
return self
end
--- Obtain object name.
--@param #SCENERY self
--@return #string Name
function SCENERY:GetName()
return self.SceneryName
end
--- Obtain DCS Object from the SCENERY Object. --- Obtain DCS Object from the SCENERY Object.
--@param #SCENERY self --@param #SCENERY self
--@return DCS#Object DCS scenery object. --@return DCS#Object DCS scenery object.
@@ -115,26 +150,28 @@ end
--@param Core.Point#COORDINATE Coordinate Where to find the scenery object --@param Core.Point#COORDINATE Coordinate Where to find the scenery object
--@param #number Radius (optional) Search radius around coordinate, defaults to 100 --@param #number Radius (optional) Search radius around coordinate, defaults to 100
--@return #SCENERY Scenery Object or `nil` if it cannot be found --@return #SCENERY Scenery Object or `nil` if it cannot be found
function SCENERY:FindByName(Name, Coordinate, Radius) function SCENERY:FindByName(Name, Coordinate, Radius, Role)
local radius = Radius or 100 local radius = Radius or 100
local name = Name or "unknown" local name = Name or "unknown"
local scenery = nil local scenery = nil
BASE:T({name, radius, Coordinate:GetVec2()})
--- ---
-- @param Core.Point#COORDINATE coordinate -- @param Core.Point#COORDINATE coordinate
-- @param #number radius -- @param #number radius
-- @param #string name -- @param #string name
local function SceneryScan(coordinate, radius, name) local function SceneryScan(scoordinate, sradius, sname)
if coordinate ~= nil then if scoordinate ~= nil then
local scenerylist = coordinate:ScanScenery(radius) local Vec2 = scoordinate:GetVec2()
local rscenery = nil local scanzone = ZONE_RADIUS:New("Zone-"..sname,Vec2,sradius,true)
for _,_scenery in pairs(scenerylist) do scanzone:Scan({Object.Category.SCENERY})
local scanned = scanzone:GetScannedSceneryObjects()
local rscenery = nil -- Wrapper.Scenery#SCENERY
for _,_scenery in pairs(scanned) do
local scenery = _scenery -- Wrapper.Scenery#SCENERY local scenery = _scenery -- Wrapper.Scenery#SCENERY
if tostring(scenery.SceneryName) == tostring(name) then if tostring(scenery.SceneryName) == tostring(sname) then
rscenery = scenery rscenery = scenery
if Role then rscenery:SetProperty("ROLE",Role) end
break break
end end
end end
@@ -144,6 +181,7 @@ function SCENERY:FindByName(Name, Coordinate, Radius)
end end
if Coordinate then if Coordinate then
--BASE:I("Coordinate Scenery Scan")
scenery = SceneryScan(Coordinate, radius, name) scenery = SceneryScan(Coordinate, radius, name)
end end
@@ -154,7 +192,7 @@ end
-- to find the correct object. -- to find the correct object.
--@param #SCENERY self --@param #SCENERY self
--@param #string Name The name or id of the scenery object as taken from the ME. Ex. '595785449' --@param #string Name The name or id of the scenery object as taken from the ME. Ex. '595785449'
--@param Core.Zone#ZONE Zone Where to find the scenery object. Can be handed as zone name. --@param Core.Zone#ZONE_BASE Zone Where to find the scenery object. Can be handed as zone name.
--@param #number Radius (optional) Search radius around coordinate, defaults to 100 --@param #number Radius (optional) Search radius around coordinate, defaults to 100
--@return #SCENERY Scenery Object or `nil` if it cannot be found --@return #SCENERY Scenery Object or `nil` if it cannot be found
function SCENERY:FindByNameInZone(Name, Zone, Radius) function SCENERY:FindByNameInZone(Name, Zone, Radius)
@@ -164,7 +202,7 @@ function SCENERY:FindByNameInZone(Name, Zone, Radius)
Zone = ZONE:FindByName(Zone) Zone = ZONE:FindByName(Zone)
end end
local coordinate = Zone:GetCoordinate() local coordinate = Zone:GetCoordinate()
return self:FindByName(Name,coordinate,Radius) return self:FindByName(Name,coordinate,Radius,Zone:GetProperty("ROLE"))
end end
--- Find a SCENERY object from its zone name. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first --- Find a SCENERY object from its zone name. Since SCENERY isn't registered in the Moose database (just too many objects per map), we need to do a scan first
@@ -173,38 +211,34 @@ end
--@param #string ZoneName The name of the scenery zone as created with a right-click on the map in the mission editor and select "assigned to...". Can be handed over as ZONE object. --@param #string ZoneName The name of the scenery zone as created with a right-click on the map in the mission editor and select "assigned to...". Can be handed over as ZONE object.
--@return #SCENERY First found Scenery Object or `nil` if it cannot be found --@return #SCENERY First found Scenery Object or `nil` if it cannot be found
function SCENERY:FindByZoneName( ZoneName ) function SCENERY:FindByZoneName( ZoneName )
local zone = ZoneName -- Core.Zone#ZONE local zone = ZoneName -- Core.Zone#ZONE_BASE
if type(ZoneName) == "string" then if type(ZoneName) == "string" then
zone = ZONE:FindByName(ZoneName) zone = ZONE:FindByName(ZoneName) -- Core.Zone#ZONE_POLYGON
end end
local _id = zone:GetProperty('OBJECT ID') local _id = zone:GetProperty('OBJECT ID')
BASE:T("Object ID ".._id) --local properties = zone:GetAllProperties() or {}
--BASE:I(string.format("Object ID is: %s",_id or "none"))
--BASE:T("Object ID ".._id)
if not _id then if not _id then
-- this zone has no object ID -- this zone has no object ID
BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName)) BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName))
if string.find(zone.ClassName,"POLYGON") then if string.find(zone.ClassName,"POLYGON") then
zone:Scan({Object.Category.SCENERY}) zone:Scan({Object.Category.SCENERY})
local scanned = zone:GetScannedScenery() local scanned = zone:GetScannedSceneryObjects()
for _,_scenery in (scanned) do for _,_scenery in (scanned) do
local scenery = _scenery -- Wrapper.Scenery#SCENERY local scenery = _scenery -- Wrapper.Scenery#SCENERY
if scenery:IsAlive() then if scenery:IsAlive() then
local role = zone:GetProperty("ROLE")
if role then scenery:SetProperty("ROLE",role) end
return scenery return scenery
end end
end end
return nil return nil
else else
local coordinate = zone:GetCoordinate() return self:FindByName(_id, zone:GetCoordinate(),nil,zone:GetProperty("ROLE"))
local scanned = coordinate:ScanScenery()
for _,_scenery in (scanned) do
local scenery = _scenery -- Wrapper.Scenery#SCENERY
if scenery:IsAlive() then
return scenery
end
end
return nil
end end
else else
return self:FindByName(_id, zone:GetCoordinate()) return self:FindByName(_id, zone:GetCoordinate(),nil,zone:GetProperty("ROLE"))
end end
end end
@@ -219,6 +253,7 @@ function SCENERY:FindAllByZoneName( ZoneName )
zone = ZONE:FindByName(ZoneName) zone = ZONE:FindByName(ZoneName)
end end
local _id = zone:GetProperty('OBJECT ID') local _id = zone:GetProperty('OBJECT ID')
--local properties = zone:GetAllProperties() or {}
if not _id then if not _id then
-- this zone has no object ID -- this zone has no object ID
--BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName)) --BASE:E("**** Zone without object ID: "..ZoneName.." | Type: "..tostring(zone.ClassName))
@@ -230,7 +265,7 @@ function SCENERY:FindAllByZoneName( ZoneName )
return nil return nil
end end
else else
local obj = self:FindByName(_id, zone:GetCoordinate()) local obj = self:FindByName(_id, zone:GetCoordinate(),nil,zone:GetProperty("ROLE"))
if obj then if obj then
return {obj} return {obj}
else else
+359
View File
@@ -0,0 +1,359 @@
--- **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
--- 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
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+3 -3
View File
@@ -179,9 +179,9 @@ function UNIT:GetDCSObject()
return DCSUnit return DCSUnit
end end
--if self.DCSUnit then if self.DCSUnit then
--return self.DCSUnit return self.DCSUnit
--end end
return nil return nil
end end
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType"> <launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/lua54/lua54.exe}"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="C:\ProgramData\chocolatey\lib\lua51\tools\lua5.1.exe"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="&quot;Moose Setup/Moose_Create.lua&quot; &quot;D&quot; &quot;LOCAL&quot; &quot;${workspace_loc:/Moose_Framework/Moose Development/Moose}&quot; &quot;${workspace_loc:/Moose_Framework/Moose Setup}&quot;&#13;&#10;&quot;${workspace_loc:/Moose_Framework/MOOSE_INCLUDE\Moose_Include_Dynamic}&quot; 1"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="&quot;Moose Setup\Moose_Create.lua&quot; &quot;D&quot; &quot;LOCAL&quot; &quot;${resource_loc:/MOOSE/Moose Development/Moose}&quot; &quot;${resource_loc:/MOOSE/Moose Setup}&quot;&#13;&#10;${resource_loc:/MOOSE_INCLUDE/Moose_Include_Dynamic}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework}"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/MOOSE}"/>
</launchConfiguration> </launchConfiguration>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType"> <launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/Moose_Framework/lua54/lua54.exe}"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="C:\ProgramData\chocolatey\lib\lua51\tools\lua5.1.exe"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="&quot;Moose Setup\Moose_Create.lua&quot; &quot;S&quot; &quot;LOCAL&quot; &quot;${workspace_loc:/Moose_Framework/Moose Development/Moose}&quot; &quot;${workspace_loc:/Moose_Framework/Moose Setup}&quot;&#13;&#10;&quot;${workspace_loc:/Moose_Framework/MOOSE_INCLUDE\Moose_Include_Static}&quot; 1"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="&quot;Moose Setup\Moose_Create.lua&quot; &quot;S&quot; &quot;LOCAL&quot; &quot;${resource_loc:/MOOSE/Moose Development/Moose}&quot; &quot;${resource_loc:/MOOSE/Moose Setup}&quot;&#13;&#10;${resource_loc:/MOOSE_INCLUDE/Moose_Include_Static}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Moose_Framework}"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/MOOSE}"/>
</launchConfiguration> </launchConfiguration>
+6 -29
View File
@@ -6,6 +6,7 @@ Utilities/Profiler.lua
Utilities/Templates.lua Utilities/Templates.lua
Utilities/STTS.lua Utilities/STTS.lua
Utilities/FiFo.lua Utilities/FiFo.lua
Utilities/Socket.lua
Core/Base.lua Core/Base.lua
Core/Beacon.lua Core/Beacon.lua
@@ -29,10 +30,11 @@ Core/SpawnStatic.lua
Core/Timer.lua Core/Timer.lua
Core/Goal.lua Core/Goal.lua
Core/Spot.lua Core/Spot.lua
Core/TextAndSound.lua Core/MarkerOps_Base.lua
Core/Astar.lua
Core/Condition.lua Core/Condition.lua
Core/TextAndSound.lua
Core/Pathline.lua Core/Pathline.lua
Core/ClientMenu.lua
Wrapper/Object.lua Wrapper/Object.lua
Wrapper/Identifiable.lua Wrapper/Identifiable.lua
@@ -47,6 +49,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
@@ -76,39 +79,13 @@ Functional/Warehouse.lua
Functional/Fox.lua Functional/Fox.lua
Functional/Mantis.lua Functional/Mantis.lua
Functional/Shorad.lua Functional/Shorad.lua
Functional/Autolase.lua
Functional/AICSAR.lua
Functional/AmmoTruck.lua
Ops/Airboss.lua Ops/Airboss.lua
Ops/RecoveryTanker.lua Ops/RecoveryTanker.lua
Ops/RescueHelo.lua Ops/RescueHelo.lua
Ops/ATIS.lua Ops/ATIS.lua
Ops/Auftrag.lua
Ops/OpsGroup.lua
Ops/FlightGroup.lua
Ops/NavyGroup.lua
Ops/Cohort.lua
Ops/Squadron.lua
Ops/Platoon.lua
Ops/Flotilla.lua
Ops/Legion.lua
Ops/AirWing.lua
Ops/Brigade.lua
Ops/Fleet.lua
Ops/Intelligence.lua
Ops/Commander.lua
Ops/Chief.lua
Ops/CSAR.lua
Ops/CTLD.lua Ops/CTLD.lua
Ops/Awacs.lua Ops/CSAR.lua
Ops/Operation.lua
Ops/FlightControl.lua
Ops/PlayerTask.lua
Ops/PlayerRecce.lua
Navigation/Navaid.lua
Navigation/FlightPlan.lua
AI/AI_Balancer.lua AI/AI_Balancer.lua
AI/AI_Air.lua AI/AI_Air.lua
+5 -24
View File
@@ -5,32 +5,19 @@ local MooseCommitHash = arg[2]
local MooseDevelopmentPath = arg[3] local MooseDevelopmentPath = arg[3]
local MooseSetupPath = arg[4] local MooseSetupPath = arg[4]
local MooseTargetPath = arg[5] local MooseTargetPath = arg[5]
local isWindows = arg[6]
if not isWindows then
isWindows = 0
end
print( "Moose (D)ynamic (S)tatic : " .. MooseDynamicStatic ) print( "Moose (D)ynamic (S)tatic : " .. MooseDynamicStatic )
print( "Commit Hash ID : " .. MooseCommitHash ) print( "Commit Hash ID : " .. MooseCommitHash )
print( "Moose development path : " .. MooseDevelopmentPath ) print( "Moose development path : " .. MooseDevelopmentPath )
print( "Moose setup path : " .. MooseSetupPath ) print( "Moose setup path : " .. MooseSetupPath )
print( "Moose target path : " .. MooseTargetPath ) print( "Moose target path : " .. MooseTargetPath )
print( "isWindows : " .. isWindows)
function PathConvert(splatnixPath)
if isWindows == 0 then
return splatnixPath
end
return splatnixPath:gsub("/", "\\")
end
local MooseModulesFilePath = MooseDevelopmentPath .. "/Modules.lua" local MooseModulesFilePath = MooseDevelopmentPath .. "/Modules.lua"
local LoaderFilePath = MooseTargetPath .. "/Moose.lua" local LoaderFilePath = MooseTargetPath .. "/Moose.lua"
print( "Reading Moose source list : " .. MooseModulesFilePath ) print( "Reading Moose source list : " .. MooseModulesFilePath )
print("Opening Loaderfile " .. PathConvert(LoaderFilePath))
local LoaderFile = assert(io.open( PathConvert(LoaderFilePath), "w+" )) local LoaderFile = io.open( LoaderFilePath, "w" )
if MooseDynamicStatic == "S" then if MooseDynamicStatic == "S" then
LoaderFile:write( "env.info( '*** MOOSE GITHUB Commit Hash ID: " .. MooseCommitHash .. " ***' )\n" ) LoaderFile:write( "env.info( '*** MOOSE GITHUB Commit Hash ID: " .. MooseCommitHash .. " ***' )\n" )
@@ -44,14 +31,13 @@ if MooseDynamicStatic == "S" then
MooseLoaderPath = MooseSetupPath .. "/Moose Templates/Moose_Static_Loader.lua" MooseLoaderPath = MooseSetupPath .. "/Moose Templates/Moose_Static_Loader.lua"
end end
local MooseLoader = io.open( MooseLoaderPath, "r" )
local MooseLoader = assert(io.open( PathConvert(MooseLoaderPath), "r" ))
local MooseLoaderText = MooseLoader:read( "*a" ) local MooseLoaderText = MooseLoader:read( "*a" )
MooseLoader:close() MooseLoader:close()
LoaderFile:write( MooseLoaderText ) LoaderFile:write( MooseLoaderText )
local MooseSourcesFile = assert(io.open( PathConvert(MooseModulesFilePath), "r" )) local MooseSourcesFile = io.open( MooseModulesFilePath, "r" )
local MooseSource = MooseSourcesFile:read("*l") local MooseSource = MooseSourcesFile:read("*l")
while( MooseSource ) do while( MooseSource ) do
@@ -64,7 +50,7 @@ while( MooseSource ) do
end end
if MooseDynamicStatic == "S" then if MooseDynamicStatic == "S" then
print( "Load static: " .. MooseFilePath ) print( "Load static: " .. MooseFilePath )
local MooseSourceFile = assert(io.open( PathConvert(MooseFilePath), "r" )) local MooseSourceFile = io.open( MooseFilePath, "r" )
local MooseSourceFileText = MooseSourceFile:read( "*a" ) local MooseSourceFileText = MooseSourceFile:read( "*a" )
MooseSourceFile:close() MooseSourceFile:close()
@@ -86,8 +72,3 @@ LoaderFile:write( "env.info( '*** MOOSE INCLUDE END *** ' )\n" )
MooseSourcesFile:close() MooseSourcesFile:close()
LoaderFile:close() LoaderFile:close()
print("Moose include generation complete.")
if MooseDynamicStatic == "D" then
print("To enable dynamic moose loading, add a soft or hard link from \"<YOUR_DCS_INSTALL_DIRECTORY>\\Scripts\\Moose\" to the \"Moose Development\\Moose\" subdirectory of the Moose_Framework repository.")
end
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.