mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-11 03:43:38 +00:00
Ops
Airboss v1.0.9 Range v2.2.0
This commit is contained in:
@@ -252,8 +252,6 @@ do -- SETTINGS
|
||||
self:SetMessageTime( MESSAGE.Type.Overview, 60 )
|
||||
self:SetMessageTime( MESSAGE.Type.Update, 15 )
|
||||
self:SetEraModern()
|
||||
--self:SetMenutextShort(true)
|
||||
--self:SetMenuStatic(true)
|
||||
return self
|
||||
else
|
||||
local Settings = _DATABASE:GetPlayerSettings( PlayerName )
|
||||
@@ -270,14 +268,14 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @param #boolean onoff If *true* use short menu texts. If *false* long ones (default).
|
||||
function SETTINGS:SetMenutextShort(onoff)
|
||||
self.MenuShort = onoff
|
||||
_SETTINGS.MenuShort = onoff
|
||||
end
|
||||
|
||||
--- Set menu to be static.
|
||||
-- @param #SETTINGS self
|
||||
-- @param #boolean onoff If *true* menu is static. If *false* menu will be updated after changes (default).
|
||||
function SETTINGS:SetMenuStatic(onoff)
|
||||
self.MenuStatic = onoff
|
||||
_SETTINGS.MenuStatic = onoff
|
||||
end
|
||||
|
||||
--- Sets the SETTINGS metric.
|
||||
@@ -496,8 +494,8 @@ do -- SETTINGS
|
||||
-- A2G Coordinate System
|
||||
-------
|
||||
|
||||
local text="A2G Coordinate System XXX"
|
||||
if self.MenuShort then
|
||||
local text="A2G Coordinate System"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2G Coordinates"
|
||||
end
|
||||
local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
@@ -505,7 +503,7 @@ do -- SETTINGS
|
||||
-- Set LL DMS
|
||||
if not self:IsA2G_LL_DMS() then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="LL DMS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
|
||||
@@ -514,7 +512,7 @@ do -- SETTINGS
|
||||
-- Set LL DDM
|
||||
if not self:IsA2G_LL_DDM() then
|
||||
local text="Lat/Lon Degree Dec Min (LL DDM)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="LL DDM"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
|
||||
@@ -525,7 +523,7 @@ do -- SETTINGS
|
||||
local text1="LL DDM Accuracy 1"
|
||||
local text2="LL DDM Accuracy 2"
|
||||
local text3="LL DDM Accuracy 3"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text1="LL DDM"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
|
||||
@@ -536,7 +534,7 @@ do -- SETTINGS
|
||||
-- Set BR.
|
||||
if not self:IsA2G_BR() then
|
||||
local text="Bearing, Range (BR)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="BR"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text , A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
|
||||
@@ -545,7 +543,7 @@ do -- SETTINGS
|
||||
-- Set MGRS.
|
||||
if not self:IsA2G_MGRS() then
|
||||
local text="Military Grid (MGRS)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="MGRS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
|
||||
@@ -565,14 +563,14 @@ do -- SETTINGS
|
||||
-------
|
||||
|
||||
local text="A2A Coordinate System"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2A Coordinates"
|
||||
end
|
||||
local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
if not self:IsA2A_LL_DMS() then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="LL DMS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
|
||||
@@ -580,7 +578,7 @@ do -- SETTINGS
|
||||
|
||||
if not self:IsA2A_LL_DDM() then
|
||||
local text="Lat/Lon Degree Dec Min (LL DDM)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="LL DDM"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
|
||||
@@ -594,7 +592,7 @@ do -- SETTINGS
|
||||
|
||||
if not self:IsA2A_BULLS() then
|
||||
local text="Bullseye (BULLS)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Bulls"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime )
|
||||
@@ -602,7 +600,7 @@ do -- SETTINGS
|
||||
|
||||
if not self:IsA2A_BRAA() then
|
||||
local text="Bearing Range Altitude Aspect (BRAA)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="BRAA"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime )
|
||||
@@ -610,7 +608,7 @@ do -- SETTINGS
|
||||
|
||||
if not self:IsA2A_MGRS() then
|
||||
local text="Military Grid (MGRS)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="MGRS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
|
||||
@@ -625,14 +623,14 @@ do -- SETTINGS
|
||||
end
|
||||
|
||||
local text="Measures and Weights System"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Unit System"
|
||||
end
|
||||
local MetricsMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
if self:IsMetric() then
|
||||
local text="Imperial (Miles,Feet)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Imperial"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime )
|
||||
@@ -640,14 +638,14 @@ do -- SETTINGS
|
||||
|
||||
if self:IsImperial() then
|
||||
local text="Metric (Kilometers,Meters)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Metric"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
local text="Messages and Reports"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Messages & Reports"
|
||||
end
|
||||
local MessagesMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
@@ -805,7 +803,7 @@ do -- SETTINGS
|
||||
|
||||
if not self:IsA2A_LL_DMS() or _SETTINGS.MenuStatic then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
if self.MenuShort then
|
||||
if _SETTINGS.MenuShort then
|
||||
text="LL DMS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
||||
@@ -983,7 +981,7 @@ do -- SETTINGS
|
||||
BASE:E( {self, PlayerUnit:GetName(), A2GSystem} )
|
||||
self.A2GSystem = A2GSystem
|
||||
MESSAGE:New( string.format( "Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if self.MenuStatic==false then
|
||||
if _SETTINGS.MenuStatic==false then
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
@@ -993,7 +991,7 @@ do -- SETTINGS
|
||||
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
|
||||
self.A2ASystem = A2ASystem
|
||||
MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if self.MenuStatic==false then
|
||||
if _SETTINGS.MenuStatic==false then
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
@@ -1003,7 +1001,7 @@ do -- SETTINGS
|
||||
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
|
||||
self.LL_Accuracy = LL_Accuracy
|
||||
MESSAGE:New( string.format( "Settings: LL format accuracy set to %d decimal places for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if self.MenuStatic==false then
|
||||
if _SETTINGS.MenuStatic==false then
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
@@ -1013,7 +1011,7 @@ do -- SETTINGS
|
||||
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
|
||||
self.MGRS_Accuracy = MGRS_Accuracy
|
||||
MESSAGE:New( string.format( "Settings: MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if self.MenuStatic==false then
|
||||
if _SETTINGS.MenuStatic==false then
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
@@ -1023,7 +1021,7 @@ do -- SETTINGS
|
||||
function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, MW )
|
||||
self.Metric = MW
|
||||
MESSAGE:New( string.format( "Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if self.MenuStatic==false then
|
||||
if _SETTINGS.MenuStatic==false then
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
|
||||
@@ -9,24 +9,34 @@
|
||||
--
|
||||
-- [476th - Air Weapons Range Objects mod](http://www.476vfightergroup.com/downloads.php?do=file&id=287) is highly recommended for this class.
|
||||
--
|
||||
-- ## Features:
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Impact points of bombs, rockets and missiles are recorded and distance to closest range target is measured and reported to the player.
|
||||
-- * Number of hits on strafing passes are counted and reported. Also the percentage of hits w.r.t fired shots is evaluated.
|
||||
-- * Results of all bombing and strafing runs are stored and top 10 results can be displayed.
|
||||
-- * Range targets can be marked by smoke.
|
||||
-- * Range can be illuminated by illumination bombs for night practices.
|
||||
-- * Range can be illuminated by illumination bombs for night missions.
|
||||
-- * Bomb, rocket and missile impact points can be marked by smoke.
|
||||
-- * Direct hits on targets can trigger flares.
|
||||
-- * Smoke and flare colors can be adjusted for each player via radio menu.
|
||||
-- * Range information and weather report at the range can be reported via radio menu.
|
||||
--
|
||||
-- More information and examples can be found below.
|
||||
-- * Persistence: Bombing range results can be saved to disk and loaded the next time the mission is started.
|
||||
-- * Range control voice overs (>40) for hit assessment.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg)
|
||||
-- ### [MOOSE - On the Range - Demonstration Video](https://www.youtube.com/watch?v=kIXcxNB9_3M)
|
||||
-- ## Youtube Videos:
|
||||
--
|
||||
-- * [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg)
|
||||
-- * [MOOSE - On the Range - Demonstration Video](https://www.youtube.com/watch?v=kIXcxNB9_3M)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Missions: Example missions will be added later.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Sound files: Check out the pinned messages in the Moose discord *#func-range* channel.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -79,10 +89,23 @@
|
||||
-- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated.
|
||||
-- @field #boolean defaultsmokebomb If true, initialize player settings to smoke bomb.
|
||||
-- @field #boolean autosave If true, automatically save results every X seconds.
|
||||
-- @extends Core.Base#BASE
|
||||
-- @field #number instructorfreq Frequency on which the range control transmitts.
|
||||
-- @field Core.RadioQueue#RADIOQUEUE instructor Instructor radio queue.
|
||||
-- @field #number rangecontrolfreq Frequency on which the range control transmitts.
|
||||
-- @field Core.RadioQueue#RADIOQUEUE rangecontrol Range control radio queue.
|
||||
-- @field #string soundpath Path inside miz file where the sound files are located. Default is "Range Soundfiles/".
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- Enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor.
|
||||
-- The parameter "rangename" defines the name of the range. It has to be unique since this is also the name displayed in the radio menu.
|
||||
--- *Don't only practice your art, but force your way into its secrets; art deserves that, for it and knowledge can raise man to the Divine.* - Ludwig van Beethoven
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The Range Concept
|
||||
--
|
||||
-- The RANGE class enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(*rangename*) contructor.
|
||||
-- The parameter *rangename* defines the name of the range. It has to be unique since this is also the name displayed in the radio menu.
|
||||
--
|
||||
-- Generally, a range consists of strafe pits and bombing targets. For strafe pits the number of hits for each pass is counted and tabulated.
|
||||
-- For bombing targets, the distance from the impact point of the bomb, rocket or missile to the closest range target is measured and tabulated.
|
||||
@@ -97,7 +120,8 @@
|
||||
-- If that is not done, the script is not started correctly. This can be checked by looking at the radio menues. If the mission was entered correctly,
|
||||
-- there should be an "On the Range" menu items in the "F10. Other..." menu.
|
||||
--
|
||||
-- ## Strafe Pits
|
||||
-- # Strafe Pits
|
||||
--
|
||||
-- Each strafe pit can consist of multiple targets. Often one finds two or three strafe targets next to each other.
|
||||
--
|
||||
-- A strafe pit can be added to the range by the @{#RANGE.AddStrafePit}(*targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*) function.
|
||||
@@ -117,7 +141,8 @@
|
||||
-- Finally, a valid approach has to be performed below a certain maximum altitude. The default is 914 meters (3000 ft) AGL. This is a parameter valid for all
|
||||
-- strafing pits of the range and can be adjusted by the @{#RANGE.SetMaxStrafeAlt}(maxalt) function.
|
||||
--
|
||||
-- ## Bombing targets
|
||||
-- # Bombing targets
|
||||
--
|
||||
-- One ore multiple bombing targets can be added to the range by the @{#RANGE.AddBombingTargets}(targetnames, goodhitrange, randommove) function.
|
||||
--
|
||||
-- * The first parameter *targetnames* has to be a lua table, which contains the names of @{Wrapper.Unit} and/or @{Static} objects defined in the mission editor.
|
||||
@@ -126,10 +151,18 @@
|
||||
-- * If final (optional) parameter "*randommove*" can be enabled to create moving targets. If this parameter is set to true, the units of this bombing target will randomly move within the range zone.
|
||||
-- Note that there might be quirks since DCS units can get stuck in buildings etc. So it might be safer to manually define a route for the units in the mission editor if moving targets are desired.
|
||||
--
|
||||
-- ## Adding Groups
|
||||
--
|
||||
-- Another possibility to add bombing targets is the @{#RANGE.AddBombingTargetGroup}(*group, goodhitrange, randommove*) function. Here the parameter *group* is a MOOSE @{Wrapper.Group} object
|
||||
-- and **all** units in this group are defined as bombing targets.
|
||||
--
|
||||
-- ## Specifying Coordinates
|
||||
--
|
||||
-- It is also possible to specify coordinates rather than unit or static objects as bombing target locations. This has the advantage, that even when the unit/static object is dead, the specified
|
||||
-- coordinate will still be a valid impact point. This can be done via the @{#RANGE.AddBombingTargetCoordinate}(*coord*, *name*, *goodhitrange*) function.
|
||||
--
|
||||
-- ## Fine Tuning
|
||||
-- # Fine Tuning
|
||||
--
|
||||
-- Many range parameters have good default values. However, the mission designer can change these settings easily with the supplied user functions:
|
||||
--
|
||||
-- * @{#RANGE.SetMaxStrafeAlt}() sets the max altitude for valid strafing runs.
|
||||
@@ -144,22 +177,61 @@
|
||||
-- * @{#RANGE.TrackRocketsON}() or @{#RANGE.TrackRocketsOFF}() can be used to enable/disable tracking and evaluating of all rocket types a player fires.
|
||||
-- * @{#RANGE.TrackMissilesON}() or @{#RANGE.TrackMissilesOFF}() can be used to enable/disable tracking and evaluating of all missile types a player fires.
|
||||
--
|
||||
-- ## Radio Menu
|
||||
-- # Radio Menu
|
||||
--
|
||||
-- Each range gets a radio menu with various submenus where each player can adjust his individual settings or request information about the range or his scores.
|
||||
--
|
||||
-- The main range menu can be found at "F10. Other..." --> "Fxx. On the Range..." --> "F1. Your Range Name...".
|
||||
-- The main range menu can be found at "F10. Other..." --> "F*X*. On the Range..." --> "F1. <Range Name>...".
|
||||
--
|
||||
-- The range menu contains the following submenues:
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- * "F1. Mark Targets": Various ways to mark targets.
|
||||
-- * "F2. My Settings": Player specific settings.
|
||||
-- * "F3. Stats" Player: statistics and scores.
|
||||
-- * "Range Information": Information about the range, such as bearing and range. Also range and player specific settings are displayed.
|
||||
-- * "Weather Report": Temperature, wind and QFE pressure information is provided.
|
||||
-- * "F1. Statistics...": Range results of all players and personal stats.
|
||||
-- * "F2. Mark Targets": Mark range targets by smoke or flares.
|
||||
-- * "F3. My Settings" Personal settings.
|
||||
-- * "F4. Range Info": Information about the range, such as bearing and range.
|
||||
--
|
||||
-- ## F1 Statistics
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## F2 Mark Targets
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## F3 My Settings
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## F4 Range Info
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # Voice Overs
|
||||
--
|
||||
-- Voice over sound files can be downloaded from the Moose Discord. Check the pinned messages in the *#func-range* channel.
|
||||
--
|
||||
-- Instructor radio will inform players when they enter or exit the range zone and provide the radio frequency of the range control for hit assessment.
|
||||
-- This can be enabled via the @{#RANGE.SetInstructorRadio}(*frequency*) functions, where *frequency* is the AM frequency in MHz.
|
||||
--
|
||||
-- The range control can be enabled via the @{#RANGE.SetRangeControl}(*frequency*) functions, where *frequency* is the AM frequency in MHz.
|
||||
--
|
||||
-- By default, the sound files are placed in the "Range Soundfiles/" folder inside the mission (.miz) file. Another folder can be specified via the @{#RANGE.SetSoundfilesPath}(*path*) function.
|
||||
--
|
||||
-- # Persistence
|
||||
--
|
||||
-- To automatically save bombing results to disk, use the @{#RANGE.SetAutosave}() function. Bombing results will be saved as csv file in your "Saved Games\DCS.openbeta\Logs" directory.
|
||||
-- Each range has a separate file, which is named "RANGE-<*RangeName*>_BombingResults.csv".
|
||||
--
|
||||
-- The next time you start the mission, these results are also automatically loaded.
|
||||
--
|
||||
-- Strafing results are currently **not** saved.
|
||||
--
|
||||
-- ## Examples
|
||||
-- # Examples
|
||||
--
|
||||
-- ### Goldwater Range
|
||||
-- ## Goldwater Range
|
||||
--
|
||||
-- This example shows hot to set up the [Barry M. Goldwater range](https://en.wikipedia.org/wiki/Barry_M._Goldwater_Air_Force_Range).
|
||||
-- It consists of two strafe pits each has two targets plus three bombing targets.
|
||||
--
|
||||
@@ -190,7 +262,7 @@
|
||||
--
|
||||
-- The [476th - Air Weapons Range Objects mod](http://www.476vfightergroup.com/downloads.php?do=file&id=287) is (implicitly) used in this example.
|
||||
--
|
||||
-- ## Debugging
|
||||
-- # Debugging
|
||||
--
|
||||
-- In case you have problems, it is always a good idea to have a look at your DCS log file. You find it in your "Saved Games" folder, so for example in
|
||||
-- C:\Users\<yourname>\Saved Games\DCS\Logs\dcs.log
|
||||
@@ -213,44 +285,49 @@
|
||||
--
|
||||
-- @field #RANGE
|
||||
RANGE={
|
||||
ClassName = "RANGE",
|
||||
Debug=false,
|
||||
id=nil,
|
||||
rangename=nil,
|
||||
location=nil,
|
||||
messages=true,
|
||||
rangeradius=5000,
|
||||
rangezone=nil,
|
||||
strafeTargets={},
|
||||
bombingTargets={},
|
||||
nbombtargets=0,
|
||||
nstrafetargets=0,
|
||||
MenuAddedTo = {},
|
||||
planes = {},
|
||||
strafeStatus = {},
|
||||
ClassName = "RANGE",
|
||||
Debug = false,
|
||||
id = nil,
|
||||
rangename = nil,
|
||||
location = nil,
|
||||
messages = true,
|
||||
rangeradius = 5000,
|
||||
rangezone = nil,
|
||||
strafeTargets = {},
|
||||
bombingTargets = {},
|
||||
nbombtargets = 0,
|
||||
nstrafetargets = 0,
|
||||
MenuAddedTo = {},
|
||||
planes = {},
|
||||
strafeStatus = {},
|
||||
strafePlayerResults = {},
|
||||
bombPlayerResults = {},
|
||||
PlayerSettings = {},
|
||||
dtBombtrack=0.005,
|
||||
BombtrackThreshold=25000,
|
||||
Tmsg=30,
|
||||
examinergroupname=nil,
|
||||
examinerexclusive=nil,
|
||||
strafemaxalt=914,
|
||||
ndisplayresult=10,
|
||||
BombSmokeColor=SMOKECOLOR.Red,
|
||||
StrafeSmokeColor=SMOKECOLOR.Green,
|
||||
StrafePitSmokeColor=SMOKECOLOR.White,
|
||||
illuminationminalt=500,
|
||||
illuminationmaxalt=1000,
|
||||
scorebombdistance=1000,
|
||||
TdelaySmoke=3.0,
|
||||
eventmoose=true,
|
||||
trackbombs=true,
|
||||
trackrockets=true,
|
||||
trackmissiles=true,
|
||||
defaultsmokebomb=true,
|
||||
autosave=false,
|
||||
bombPlayerResults = {},
|
||||
PlayerSettings = {},
|
||||
dtBombtrack = 0.005,
|
||||
BombtrackThreshold = 25000,
|
||||
Tmsg = 30,
|
||||
examinergroupname = nil,
|
||||
examinerexclusive = nil,
|
||||
strafemaxalt = 914,
|
||||
ndisplayresult = 10,
|
||||
BombSmokeColor = SMOKECOLOR.Red,
|
||||
StrafeSmokeColor = SMOKECOLOR.Green,
|
||||
StrafePitSmokeColor = SMOKECOLOR.White,
|
||||
illuminationminalt = 500,
|
||||
illuminationmaxalt = 1000,
|
||||
scorebombdistance = 1000,
|
||||
TdelaySmoke = 3.0,
|
||||
eventmoose = true,
|
||||
trackbombs = true,
|
||||
trackrockets = true,
|
||||
trackmissiles = true,
|
||||
defaultsmokebomb = true,
|
||||
autosave = false,
|
||||
instructorfreq = nil,
|
||||
instructor = nil,
|
||||
rangecontrolfreq = nil,
|
||||
rangecontrol = nil,
|
||||
soundpath = "Range Soundfiles/"
|
||||
}
|
||||
|
||||
--- Default range parameters.
|
||||
@@ -325,6 +402,105 @@ RANGE.TargetType={
|
||||
-- @field #string player Player name.
|
||||
-- @field #string airframe Aircraft type of player.
|
||||
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
|
||||
-- @field #string date OS date.
|
||||
|
||||
--- Sound file data.
|
||||
-- @type RANGE.Soundfile
|
||||
-- @field #string filename Name of the file
|
||||
-- @field #number duration Duration in seconds.
|
||||
|
||||
--- Sound files.
|
||||
-- @type RANGE.Sound
|
||||
-- @field #RANGE.Soundfile RC0
|
||||
-- @field #RANGE.Soundfile RC1
|
||||
-- @field #RANGE.Soundfile RC2
|
||||
-- @field #RANGE.Soundfile RC3
|
||||
-- @field #RANGE.Soundfile RC4
|
||||
-- @field #RANGE.Soundfile RC5
|
||||
-- @field #RANGE.Soundfile RC6
|
||||
-- @field #RANGE.Soundfile RC7
|
||||
-- @field #RANGE.Soundfile RC8
|
||||
-- @field #RANGE.Soundfile RC9
|
||||
-- @field #RANGE.Soundfile RCAccuracy
|
||||
-- @field #RANGE.Soundfile RCDegrees
|
||||
-- @field #RANGE.Soundfile RCExcellentHit
|
||||
-- @field #RANGE.Soundfile RCExcellentPass
|
||||
-- @field #RANGE.Soundfile RCFeet
|
||||
-- @field #RANGE.Soundfile RCFor
|
||||
-- @field #RANGE.Soundfile RCGoodHit
|
||||
-- @field #RANGE.Soundfile RCGoodPass
|
||||
-- @field #RANGE.Soundfile RCHitsOnTarget
|
||||
-- @field #RANGE.Soundfile RCImpact
|
||||
-- @field #RANGE.Soundfile RCIneffectiveHit
|
||||
-- @field #RANGE.Soundfile RCIneffectivePass
|
||||
-- @field #RANGE.Soundfile RCInvalidHit
|
||||
-- @field #RANGE.Soundfile RCLeftStrafePitTooQuickly
|
||||
-- @field #RANGE.Soundfile RCPercent
|
||||
-- @field #RANGE.Soundfile RCPoorHit
|
||||
-- @field #RANGE.Soundfile RCPoorPass
|
||||
-- @field #RANGE.Soundfile RCRollingInOnStrafeTarget
|
||||
-- @field #RANGE.Soundfile RCTotalRoundsFired
|
||||
-- @field #RANGE.Soundfile RCWeaponImpactedTooFar
|
||||
-- @field #RANGE.Soundfile IR0
|
||||
-- @field #RANGE.Soundfile IR1
|
||||
-- @field #RANGE.Soundfile IR2
|
||||
-- @field #RANGE.Soundfile IR3
|
||||
-- @field #RANGE.Soundfile IR4
|
||||
-- @field #RANGE.Soundfile IR5
|
||||
-- @field #RANGE.Soundfile IR6
|
||||
-- @field #RANGE.Soundfile IR7
|
||||
-- @field #RANGE.Soundfile IR8
|
||||
-- @field #RANGE.Soundfile IR9
|
||||
-- @field #RANGE.Soundfile IRDecimal
|
||||
-- @field #RANGE.Soundfile IRMegaHertz
|
||||
-- @field #RANGE.Soundfile IREnterRange
|
||||
-- @field #RANGE.Soundfile IRExitRange
|
||||
RANGE.Sound = {
|
||||
RC0={filename="RC-0.ogg", duration=0.60},
|
||||
RC1={filename="RC-1.ogg", duration=0.47},
|
||||
RC2={filename="RC-2.ogg", duration=0.43},
|
||||
RC3={filename="RC-3.ogg", duration=0.50},
|
||||
RC4={filename="RC-4.ogg", duration=0.58},
|
||||
RC5={filename="RC-5.ogg", duration=0.54},
|
||||
RC6={filename="RC-6.ogg", duration=0.61},
|
||||
RC7={filename="RC-7.ogg", duration=0.53},
|
||||
RC8={filename="RC-8.ogg", duration=0.34},
|
||||
RC9={filename="RC-9.ogg", duration=0.54},
|
||||
RCAccuracy={filename="RC-Accuracy.ogg", duration=0.67},
|
||||
RCDegrees={filename="RC-Degrees.ogg", duration=0.59},
|
||||
RCExcellentHit={filename="RC-ExcellentHit.ogg", duration=0.76},
|
||||
RCExcellentPass={filename="RC-ExcellentPass.ogg", duration=0.89},
|
||||
RCFeet={filename="RC-Feet.ogg", duration=0.49},
|
||||
RCFor={filename="RC-For.ogg", duration=0.64},
|
||||
RCGoodHit={filename="RC-GoodHit.ogg", duration=0.52},
|
||||
RCGoodPass={filename="RC-GoodPass.ogg", duration=0.62},
|
||||
RCHitsOnTarget={filename="RC-HitsOnTarget.ogg", duration=0.88},
|
||||
RCImpact={filename="RC-Impact.ogg", duration=0.61},
|
||||
RCIneffectiveHit={filename="RC-IneffectiveHit.ogg", duration=0.86},
|
||||
RCIneffectivePass={filename="RC-IneffectivePass.ogg", duration=0.99},
|
||||
RCInvalidHit={filename="RC-InvalidHit.ogg", duration=2.97},
|
||||
RCLeftStrafePitTooQuickly={filename="RC-LeftStrafePitTooQuickly.ogg", duration=3.09},
|
||||
RCPercent={filename="RC-Percent.ogg", duration=0.56},
|
||||
RCPoorHit={filename="RC-PoorHit.ogg", duration=0.54},
|
||||
RCPoorPass={filename="RC-PoorPass.ogg", duration=0.68},
|
||||
RCRollingInOnStrafeTarget={filename="RC-RollingInOnStrafeTarget.ogg", duration=1.38},
|
||||
RCTotalRoundsFired={filename="RC-TotalRoundsFired.ogg", duration=1.22},
|
||||
RCWeaponImpactedTooFar={filename="RC-WeaponImpactedTooFar.ogg", duration=3.73},
|
||||
IR0={filename="IR-0.ogg", duration=0.55},
|
||||
IR1={filename="IR-1.ogg", duration=0.41},
|
||||
IR2={filename="IR-2.ogg", duration=0.37},
|
||||
IR3={filename="IR-3.ogg", duration=0.41},
|
||||
IR4={filename="IR-4.ogg", duration=0.37},
|
||||
IR5={filename="IR-5.ogg", duration=0.43},
|
||||
IR6={filename="IR-6.ogg", duration=0.55},
|
||||
IR7={filename="IR-7.ogg", duration=0.43},
|
||||
IR8={filename="IR-8.ogg", duration=0.38},
|
||||
IR9={filename="IR-9.ogg", duration=0.55},
|
||||
IRDecimal={filename="IR-Decimal.ogg", duration=0.54},
|
||||
IRMegaHertz={filename="IR-MegaHertz.ogg", duration=0.87},
|
||||
IREnterRange={filename="IR-EnterRange.ogg", duration=4.83},
|
||||
IRExitRange={filename="IR-ExitRange.ogg", duration=3.10},
|
||||
}
|
||||
|
||||
--- Global list of all defined range names.
|
||||
-- @field #table Names
|
||||
@@ -340,7 +516,7 @@ RANGE.MenuF10Root=nil
|
||||
|
||||
--- Range script version.
|
||||
-- @field #string version
|
||||
RANGE.version="2.1.2"
|
||||
RANGE.version="2.2.0"
|
||||
|
||||
--TODO list:
|
||||
--TODO: Verbosity level for messages.
|
||||
@@ -431,14 +607,14 @@ function RANGE:New(rangename)
|
||||
-- @function [parent=#RANGE] Impact
|
||||
-- @param #RANGE self
|
||||
-- @param #RANGE.BombResult result Data of bombing run.
|
||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
||||
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||
|
||||
--- Triggers the FSM delayed event "Impact".
|
||||
-- @function [parent=#RANGE] __Impact
|
||||
-- @param #RANGE self
|
||||
-- @param #number delay Delay in seconds before the function is called.
|
||||
-- @param #RANGE.BombResult result Data of the bombing run.
|
||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
||||
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||
|
||||
--- On after "Impact" event user function. Called when a bomb/rocket/missile impacted.
|
||||
-- @function [parent=#RANGE] OnAfterImpact
|
||||
@@ -447,18 +623,18 @@ function RANGE:New(rangename)
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #RANGE.BombResult result Data of the bombing run.
|
||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
||||
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||
|
||||
--- Triggers the FSM event "EnterRange".
|
||||
-- @function [parent=#RANGE] EnterRange
|
||||
-- @param #RANGE self
|
||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
||||
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||
|
||||
--- Triggers the FSM delayed event "EnterRange".
|
||||
-- @function [parent=#RANGE] __EnterRange
|
||||
-- @param #RANGE self
|
||||
-- @param #number delay Delay in seconds before the function is called.
|
||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
||||
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||
|
||||
--- On after "EnterRange" event user function. Called when a player enters the range zone.
|
||||
-- @function [parent=#RANGE] OnAfterEnterRange
|
||||
@@ -466,18 +642,18 @@ function RANGE:New(rangename)
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
||||
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||
|
||||
--- Triggers the FSM event "ExitRange".
|
||||
-- @function [parent=#RANGE] ExitRange
|
||||
-- @param #RANGE self
|
||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
||||
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||
|
||||
--- Triggers the FSM delayed event "ExitRange".
|
||||
-- @function [parent=#RANGE] __ExitRange
|
||||
-- @param #RANGE self
|
||||
-- @param #number delay Delay in seconds before the function is called.
|
||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
||||
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||
|
||||
--- On after "ExitRange" event user function. Called when a player leaves the range zone.
|
||||
-- @function [parent=#RANGE] OnAfterExitRange
|
||||
@@ -485,7 +661,7 @@ function RANGE:New(rangename)
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
||||
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||
|
||||
-- Return object.
|
||||
return self
|
||||
@@ -573,6 +749,63 @@ function RANGE:onafterStart()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Init range control.
|
||||
if self.rangecontrolfreq then
|
||||
|
||||
-- Radio queue.
|
||||
self.rangecontrol=RADIOQUEUE:New(self.rangecontrolfreq)
|
||||
|
||||
-- Init numbers.
|
||||
self.rangecontrol:SetDigit(0, RANGE.Sound.RC0.filename, RANGE.Sound.RC0.duration, self.soundpath)
|
||||
self.rangecontrol:SetDigit(1, RANGE.Sound.RC1.filename, RANGE.Sound.RC1.duration, self.soundpath)
|
||||
self.rangecontrol:SetDigit(2, RANGE.Sound.RC2.filename, RANGE.Sound.RC2.duration, self.soundpath)
|
||||
self.rangecontrol:SetDigit(3, RANGE.Sound.RC3.filename, RANGE.Sound.RC3.duration, self.soundpath)
|
||||
self.rangecontrol:SetDigit(4, RANGE.Sound.RC4.filename, RANGE.Sound.RC4.duration, self.soundpath)
|
||||
self.rangecontrol:SetDigit(5, RANGE.Sound.RC5.filename, RANGE.Sound.RC5.duration, self.soundpath)
|
||||
self.rangecontrol:SetDigit(6, RANGE.Sound.RC6.filename, RANGE.Sound.RC6.duration, self.soundpath)
|
||||
self.rangecontrol:SetDigit(7, RANGE.Sound.RC7.filename, RANGE.Sound.RC7.duration, self.soundpath)
|
||||
self.rangecontrol:SetDigit(8, RANGE.Sound.RC8.filename, RANGE.Sound.RC8.duration, self.soundpath)
|
||||
self.rangecontrol:SetDigit(9, RANGE.Sound.RC9.filename, RANGE.Sound.RC9.duration, self.soundpath)
|
||||
|
||||
-- Set location where the messages are transmitted from.
|
||||
self.rangecontrol:SetSenderCoordinate(self.location)
|
||||
|
||||
-- Start range control radio queue.
|
||||
self.rangecontrol:Start(1, 0.1)
|
||||
|
||||
-- Init range control.
|
||||
if self.instructorfreq then
|
||||
|
||||
-- Radio queue.
|
||||
self.instructor=RADIOQUEUE:New(self.instructorfreq)
|
||||
|
||||
-- Init numbers.
|
||||
self.instructor:SetDigit(0, RANGE.Sound.IR0.filename, RANGE.Sound.IR0.duration, self.soundpath)
|
||||
self.instructor:SetDigit(1, RANGE.Sound.IR1.filename, RANGE.Sound.IR1.duration, self.soundpath)
|
||||
self.instructor:SetDigit(2, RANGE.Sound.IR2.filename, RANGE.Sound.IR2.duration, self.soundpath)
|
||||
self.instructor:SetDigit(3, RANGE.Sound.IR3.filename, RANGE.Sound.IR3.duration, self.soundpath)
|
||||
self.instructor:SetDigit(4, RANGE.Sound.IR4.filename, RANGE.Sound.IR4.duration, self.soundpath)
|
||||
self.instructor:SetDigit(5, RANGE.Sound.IR5.filename, RANGE.Sound.IR5.duration, self.soundpath)
|
||||
self.instructor:SetDigit(6, RANGE.Sound.IR6.filename, RANGE.Sound.IR6.duration, self.soundpath)
|
||||
self.instructor:SetDigit(7, RANGE.Sound.IR7.filename, RANGE.Sound.IR7.duration, self.soundpath)
|
||||
self.instructor:SetDigit(8, RANGE.Sound.IR8.filename, RANGE.Sound.IR8.duration, self.soundpath)
|
||||
self.instructor:SetDigit(9, RANGE.Sound.IR9.filename, RANGE.Sound.IR9.duration, self.soundpath)
|
||||
|
||||
-- Set location where the messages are transmitted from.
|
||||
self.instructor:SetSenderCoordinate(self.location)
|
||||
|
||||
-- Start instructor radio queue.
|
||||
self.instructor:Start(1, 0.1)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Load prev results.
|
||||
if self.autosave then
|
||||
self:Load()
|
||||
end
|
||||
|
||||
-- Debug mode: smoke all targets and range zone.
|
||||
if self.Debug then
|
||||
@@ -831,6 +1064,34 @@ function RANGE:TrackMissilesOFF()
|
||||
end
|
||||
|
||||
|
||||
--- Enable range control and set frequency.
|
||||
-- @param #RANGE self
|
||||
-- @param #number frequency Frequency in MHz. Default 256 MHz.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetRangeControl(frequency)
|
||||
self.rangecontrolfreq=frequency or 256
|
||||
return self
|
||||
end
|
||||
|
||||
--- Enable instructor radio and set frequency.
|
||||
-- @param #RANGE self
|
||||
-- @param #number frequency Frequency in MHz. Default 305 MHz.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetInstructorRadio(frequency)
|
||||
self.instructorfreq=frequency or 305
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set sound files folder within miz file.
|
||||
-- @param #RANGE self
|
||||
-- @param #string path Path for sound files. Default "ATIS Soundfiles/". Mind the slash "/" at the end!
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetSoundfilesPath(path)
|
||||
self.soundpath=tostring(path or "Range Soundfiles/")
|
||||
self:I(self.lid..string.format("Setting sound files path to %s", self.soundpath))
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add new strafe pit. For a strafe pit, hits from guns are counted. One pit can consist of several units.
|
||||
-- Note, an approach is only valid, if the player enters via a zone in front of the pit, which defined by boxlength and boxheading.
|
||||
-- Furthermore, the player must not be too high and fly in the direction of the pit to make a valid target apporoach.
|
||||
@@ -1565,7 +1826,7 @@ function RANGE:OnEventShot(EventData)
|
||||
if _distance == nil or _temp < _distance then
|
||||
_distance = _temp
|
||||
_closetTarget = _bombtarget
|
||||
_closeCoord=targetcoord
|
||||
_closeCoord=targetcoord
|
||||
if _distance <= 0.5*_bombtarget.goodhitrange then
|
||||
_hitquality = "EXCELLENT"
|
||||
elseif _distance <= _bombtarget.goodhitrange then
|
||||
@@ -1609,8 +1870,12 @@ function RANGE:OnEventShot(EventData)
|
||||
elseif insidezone then
|
||||
|
||||
-- Send message.
|
||||
local _message=string.format("%s, weapon fell more than %.1f km away from nearest range target. No score!", _callsign, self.scorebombdistance/1000)
|
||||
local _message=string.format("%s, weapon impacted too far from nearest range target (>%.1f km). No score!", _callsign, self.scorebombdistance/1000)
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, false)
|
||||
|
||||
if self.rangecontrol then
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCWeaponImpactedTooFar.filename, RANGE.Sound.RCWeaponImpactedTooFar.duration, self.soundpath, nil, nil, _message, self.subduration)
|
||||
end
|
||||
|
||||
else
|
||||
self:T(self.id.."Weapon impacted outside range zone.")
|
||||
@@ -1649,15 +1914,49 @@ function RANGE:onafterStatus(From, Event, To)
|
||||
-- Check player status.
|
||||
self:_CheckPlayers()
|
||||
|
||||
-- Save results.
|
||||
if self.autosave then
|
||||
self:Save()
|
||||
end
|
||||
|
||||
-- Check back in ~10 seconds.
|
||||
self:__Status(-10)
|
||||
end
|
||||
|
||||
--- Function called after player enters the range zone.
|
||||
-- @param #RANGE self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #RANGE.PlayerData player Player data.
|
||||
function RANGE:onafterEnterRange(From, Event, To, player)
|
||||
|
||||
if self.instructor and self.rangecontrol then
|
||||
|
||||
-- Range control radio frequency split.
|
||||
local RF=UTILS.Split(string.format("%.3f", self.rangecontrolfreq), ".")
|
||||
|
||||
-- Radio message that player entered the range
|
||||
self.instructor:NewTransmission(RANGE.Sound.IREnterRange.filename, RANGE.Sound.IREnterRange.duration, self.soundpath)
|
||||
self.instructor:Number2Transmission(RF[1])
|
||||
if tonumber(RF[2])>0 then
|
||||
self.instructor:NewTransmission(RANGE.Sound.IRDecimal.filename, RANGE.Sound.IRDecimal.duration, self.soundpath)
|
||||
self.instructor:Number2Transmission(RF[2])
|
||||
end
|
||||
self.instructor:NewTransmission(RANGE.Sound.IRMegaHertz.filename, RANGE.Sound.IRMegaHertz.duration, self.soundpath)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Function called after player leaves the range zone.
|
||||
-- @param #RANGE self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #RANGE.PlayerData player Player data.
|
||||
function RANGE:onafterExitRange(From, Event, To, player)
|
||||
|
||||
if self.instructor then
|
||||
self.instructor:NewTransmission(RANGE.Sound.IRExitRange.filename, RANGE.Sound.IRExitRange.duration, self.soundpath)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Function called after bomb impact on range.
|
||||
-- @param #RANGE self
|
||||
@@ -1665,7 +1964,7 @@ end
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #RANGE.BombResult result Result of bomb impact.
|
||||
-- @param #RANGE.PlayerData player
|
||||
-- @param #RANGE.PlayerData player Player data table.
|
||||
function RANGE:onafterImpact(From, Event, To, result, player)
|
||||
|
||||
-- Only display target name if there is more than one bomb target.
|
||||
@@ -1682,6 +1981,25 @@ function RANGE:onafterImpact(From, Event, To, result, player)
|
||||
text=text.."."
|
||||
end
|
||||
text=text..string.format(" %s hit.", result.quality)
|
||||
|
||||
if self.rangecontrol then
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCImpact.filename, RANGE.Sound.RCImpact.duration, self.soundpath, nil, nil, text, self.subduration)
|
||||
self.rangecontrol:Number2Transmission(string.format("%03d", result.radial), nil, 0.1)
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCDegrees.filename, RANGE.Sound.RCDegrees.duration, self.soundpath)
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCFor.filename, RANGE.Sound.RCFor.duration, self.soundpath)
|
||||
self.rangecontrol:Number2Transmission(string.format("%d", UTILS.MetersToFeet(result.distance)))
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCFeet.filename, RANGE.Sound.RCFeet.duration, self.soundpath)
|
||||
if result.quality=="POOR" then
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCPoorHit.filename, RANGE.Sound.RCPoorHit.duration, self.soundpath, nil, 0.5)
|
||||
elseif result.quality=="INEFFECTIVE" then
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCIneffectiveHit.filename, RANGE.Sound.RCIneffectiveHit.duration, self.soundpath, nil, 0.5)
|
||||
elseif result.quality=="GOOD" then
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCGoodHit.filename, RANGE.Sound.RCGoodHit.duration, self.soundpath, nil, 0.5)
|
||||
elseif result.quality=="EXCELLENT" then
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCExcellentHit.filename, RANGE.Sound.RCExcellentHit.duration, self.soundpath, nil, 0.5)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Unit.
|
||||
local unit=UNIT:FindByName(player.unitname)
|
||||
@@ -1689,6 +2007,11 @@ function RANGE:onafterImpact(From, Event, To, result, player)
|
||||
-- Send message.
|
||||
self:_DisplayMessageToGroup(unit, text, nil, true)
|
||||
self:T(self.id..text)
|
||||
|
||||
-- Save results.
|
||||
if self.autosave then
|
||||
self:Save()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1746,7 +2069,11 @@ function RANGE:onafterSave(From, Event, To)
|
||||
local quality=result.quality
|
||||
local time=UTILS.SecondsToClock(result.time)
|
||||
local airframe=result.airframe
|
||||
scores=scores..string.format("\n%s,%d,%s,%.2f,%03d,%s,%s,%s,%s", playername, i, target, distance, radial, quality, weapon, airframe, time)
|
||||
local date="n/a"
|
||||
if os then
|
||||
date=os.date()
|
||||
end
|
||||
scores=scores..string.format("\n%s,%d,%s,%.2f,%03d,%s,%s,%s,%s,%s", playername, i, target, distance, radial, quality, weapon, airframe, time, date)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1783,7 +2110,7 @@ function RANGE:onafterLoad(From, Event, To)
|
||||
f:close()
|
||||
return data
|
||||
else
|
||||
self:E(self.id..string.format("ERROR: Could not load player results from file %s", tostring(filename)))
|
||||
self:E(self.id..string.format("WARNING: Could not load player results from file %s. File might not exist just yet.", tostring(filename)))
|
||||
return nil
|
||||
end
|
||||
end
|
||||
@@ -1833,6 +2160,7 @@ function RANGE:onafterLoad(From, Event, To)
|
||||
result.weapon=tostring(resultdata[7])
|
||||
result.airframe=tostring(resultdata[8])
|
||||
result.time=UTILS.ClockToSeconds(resultdata[9] or "00:00:00")
|
||||
result.date=resultdata[10] or "n/a"
|
||||
|
||||
-- Create player array if necessary.
|
||||
self.bombPlayerResults[playername]=self.bombPlayerResults[playername] or {}
|
||||
@@ -2334,8 +2662,8 @@ function RANGE:_CheckPlayers()
|
||||
------------------------------
|
||||
|
||||
if not playersettings.inzone then
|
||||
self:EnterRange(playersettings)
|
||||
playersettings.inzone=true
|
||||
self:EnterRange(playersettings)
|
||||
end
|
||||
|
||||
else
|
||||
@@ -2345,8 +2673,8 @@ function RANGE:_CheckPlayers()
|
||||
-------------------------------
|
||||
|
||||
if playersettings.inzone==true then
|
||||
self:ExitRange(playersettings)
|
||||
playersettings.inzone=false
|
||||
self:ExitRange(playersettings)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -2411,6 +2739,10 @@ function RANGE:_CheckInZone(_unitName)
|
||||
|
||||
-- Send message.
|
||||
self:_DisplayMessageToGroup(_unit, _msg, nil, true)
|
||||
|
||||
if self.rangecontrol then
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCLeftStrafePitTooQuickly.filename, RANGE.Sound.RCLeftStrafePitTooQuickly.duration, self.soundpath)
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
@@ -2419,16 +2751,21 @@ function RANGE:_CheckInZone(_unitName)
|
||||
|
||||
-- Result.
|
||||
local _result = self.strafeStatus[_unitID]
|
||||
local _sound = nil --#RANGE.Soundfile
|
||||
|
||||
-- Judge this pass. Text is displayed on summary.
|
||||
if _result.hits >= _result.zone.goodPass*2 then
|
||||
_result.text = "EXCELLENT PASS"
|
||||
_sound=RANGE.Sound.RCExcellentPass
|
||||
elseif _result.hits >= _result.zone.goodPass then
|
||||
_result.text = "GOOD PASS"
|
||||
_sound=RANGE.Sound.RCGoodPass
|
||||
elseif _result.hits >= _result.zone.goodPass/2 then
|
||||
_result.text = "INEFFECTIVE PASS"
|
||||
_sound=RANGE.Sound.RCIneffectivePass
|
||||
else
|
||||
_result.text = "POOR PASS"
|
||||
_sound=RANGE.Sound.RCPoorPass
|
||||
end
|
||||
|
||||
-- Calculate accuracy of run. Number of hits wrt number of rounds fired.
|
||||
@@ -2439,13 +2776,28 @@ function RANGE:_CheckInZone(_unitName)
|
||||
end
|
||||
|
||||
-- Message text.
|
||||
local _text=string.format("%s, %s with %d hits on target %s.", self:_myname(_unitName), _result.text, _result.hits, _result.zone.name)
|
||||
local _text=string.format("%s, hits on target %s: %d", self:_myname(_unitName), _result.zone.name, _result.hits)
|
||||
if shots and accur then
|
||||
_text=_text..string.format("\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur)
|
||||
end
|
||||
_text=_text..string.format("\n%s", _result.text)
|
||||
|
||||
-- Send message.
|
||||
self:_DisplayMessageToGroup(_unit, _text)
|
||||
|
||||
-- Voice over.
|
||||
if self.rangecontrol then
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCHitsOnTarget.filename, RANGE.Sound.RCHitsOnTarget.duration, self.soundpath)
|
||||
self.rangecontrol:Number2Transmission(string.format("%d", _result.hits))
|
||||
if shots and accur then
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCTotalRoundsFired.filename, RANGE.Sound.RCTotalRoundsFired.duration, self.soundpath, nil, 0.2)
|
||||
self.rangecontrol:Number2Transmission(string.format("%d", shots), nil, 0.2)
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCAccuracy.filename, RANGE.Sound.RCAccuracy.duration, self.soundpath, nil, 0.2)
|
||||
self.rangecontrol:Number2Transmission(string.format("%d", UTILS.Round(accur, 0)))
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCPercent.filename, RANGE.Sound.RCPercent.duration, self.soundpath)
|
||||
end
|
||||
self.rangecontrol:NewTransmission(_sound.filename, _sound.duration, self.soundpath, nil, 0.5)
|
||||
end
|
||||
|
||||
-- Set strafe status to nil.
|
||||
self.strafeStatus[_unitID] = nil
|
||||
@@ -2492,6 +2844,10 @@ function RANGE:_CheckInZone(_unitName)
|
||||
|
||||
-- Rolling in!
|
||||
local _msg=string.format("%s, rolling in on strafe pit %s.", self:_myname(_unitName), _targetZone.name)
|
||||
|
||||
if self.rangecontrol then
|
||||
self.rangecontrol:NewTransmission(RANGE.Sound.RCRollingInOnStrafeTarget.filename, RANGE.Sound.RCRollingInOnStrafeTarget.duration, self.soundpath)
|
||||
end
|
||||
|
||||
-- Send message.
|
||||
self:_DisplayMessageToGroup(_unit, _msg, 10, true)
|
||||
@@ -2998,7 +3354,7 @@ function RANGE:_SmokeStrafeTargetBoxes(unitname)
|
||||
|
||||
for _,_target in pairs(self.strafeTargets) do
|
||||
local zone=_target.polygon --Core.Zone#ZONE
|
||||
zone:SmokeZone(self.StrafePitSmokeColor)
|
||||
zone:SmokeZone(self.StrafePitSmokeColor, 4)
|
||||
for _,_point in pairs(_target.smokepoints) do
|
||||
_point:SmokeOrange() --Corners are smoked orange.
|
||||
end
|
||||
@@ -3191,7 +3547,8 @@ function RANGE:_myname(unitname)
|
||||
local pname=unit:GetPlayerName()
|
||||
local csign=unit:GetCallsign()
|
||||
|
||||
return string.format("%s (%s)", csign, pname)
|
||||
--return string.format("%s (%s)", csign, pname)
|
||||
return string.format("%s", pname)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
-- @field #boolean windtrue Report true (from) heading of wind. Default is magnetic.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- Be informed!
|
||||
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -339,10 +339,10 @@ ATIS.Alphabet = {
|
||||
|
||||
--- Runway correction for converting true to magnetic heading.
|
||||
-- @type ATIS.RunwayM2T
|
||||
-- @field #number Caucasus 0� (East).
|
||||
-- @field #number Nevada +12� (East).
|
||||
-- @field #number Normandy -10� (West).
|
||||
-- @field #number PersianGulf +2� (East).
|
||||
-- @field #number Caucasus 0° (East).
|
||||
-- @field #number Nevada +12° (East).
|
||||
-- @field #number Normandy -10° (West).
|
||||
-- @field #number PersianGulf +2° (East).
|
||||
ATIS.RunwayM2T={
|
||||
Caucasus=0,
|
||||
Nevada=12,
|
||||
@@ -523,7 +523,7 @@ ATIS.version="0.4.0"
|
||||
-- @return #ATIS self
|
||||
function ATIS:New(airbasename, frequency, modulation)
|
||||
|
||||
-- Inherit everything from WAREHOUSE class.
|
||||
-- Inherit everything from FSM class.
|
||||
local self=BASE:Inherit(self, FSM:New()) -- #ATIS
|
||||
|
||||
self.airbasename=airbasename
|
||||
@@ -650,7 +650,7 @@ end
|
||||
|
||||
--- Set magnetic runway headings as depicted on the runway, e.g. 13 for 130.
|
||||
-- @param #ATIS self
|
||||
-- @param #table headings Magnetic headings. Inverse (-180�) headings are added automatically.
|
||||
-- @param #table headings Magnetic headings. Inverse (-180°) headings are added automatically.
|
||||
-- @return #ATIS self
|
||||
function ATIS:SetRunwayHeadingsMagnetic(headings)
|
||||
if type(headings)=="table" then
|
||||
@@ -728,12 +728,12 @@ end
|
||||
--
|
||||
-- To get *true* from *magnetic* heading one has to add easterly or substract westerly variation, e.g
|
||||
--
|
||||
-- A magnetic heading of 180� corresponds to a true heading of
|
||||
-- A magnetic heading of 180° corresponds to a true heading of
|
||||
--
|
||||
-- * 186� on the Caucaus map
|
||||
-- * 192� on the Nevada map
|
||||
-- * 170� on the Normany map
|
||||
-- * 182� on the Persian Gulf map
|
||||
-- * 186° on the Caucaus map
|
||||
-- * 192° on the Nevada map
|
||||
-- * 170° on the Normany map
|
||||
-- * 182° on the Persian Gulf map
|
||||
--
|
||||
-- Likewise, to convert *magnetic* into *true* heading, one has to substract easterly and add westerly variation.
|
||||
--
|
||||
@@ -922,7 +922,7 @@ function ATIS:onafterStatus(From, Event, To)
|
||||
local text=string.format("State %s", fsmstate)
|
||||
self:I(self.lid..text)
|
||||
|
||||
self:__Status(60)
|
||||
self:__Status(-60)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -941,7 +941,7 @@ function ATIS:onafterCheckQueue(From, Event, To)
|
||||
end
|
||||
|
||||
-- Check back in 5 seconds.
|
||||
self:__CheckQueue(5)
|
||||
self:__CheckQueue(-5)
|
||||
end
|
||||
|
||||
--- Broadcast ATIS radio message.
|
||||
@@ -1070,10 +1070,10 @@ function ATIS:onafterBroadcast(From, Event, To)
|
||||
--- Temperature ---
|
||||
-------------------
|
||||
|
||||
-- Temperature in �C (or �F).
|
||||
-- Temperature in °C (or °F).
|
||||
local temperature=coord:GetTemperature(height)
|
||||
|
||||
-- Convert to �F.
|
||||
-- Convert to °F.
|
||||
if self.TDegF then
|
||||
temperature=UTILS.CelciusToFarenheit(temperature)
|
||||
end
|
||||
@@ -1553,7 +1553,7 @@ end
|
||||
--- Get runway from user supplied magnetic heading.
|
||||
-- @param #ATIS self
|
||||
-- @param #number windfrom Wind direction (from) in degrees.
|
||||
-- @return #string Runway magnetic heading divided by ten (and rounded). Eg, "13" for 130�.
|
||||
-- @return #string Runway magnetic heading divided by ten (and rounded). Eg, "13" for 130°.
|
||||
function ATIS:GetMagneticRunway(windfrom)
|
||||
|
||||
local diffmin=nil
|
||||
@@ -1588,7 +1588,7 @@ function ATIS:GetNavPoint(navpoints, runway)
|
||||
else
|
||||
local nr=tonumber(nav.runway)
|
||||
local r=tonumber(runway)
|
||||
if math.abs(nr-r)<=2 then --We allow an error of +-20� here.
|
||||
if math.abs(nr-r)<=2 then --We allow an error of +-20° here.
|
||||
return nav
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1688,7 +1688,7 @@ AIRBOSS.MenuF10Root=nil
|
||||
|
||||
--- Airboss class version.
|
||||
-- @field #string version
|
||||
AIRBOSS.version="1.0.8"
|
||||
AIRBOSS.version="1.0.9"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -1954,22 +1954,29 @@ function AIRBOSS:New(carriername, alias)
|
||||
end
|
||||
|
||||
-- Smoke zones.
|
||||
if false then
|
||||
local case=2
|
||||
if true then
|
||||
local case=3
|
||||
self.holdingoffset=30
|
||||
--[[
|
||||
self:_GetZoneGroove():SmokeZone(SMOKECOLOR.Red, 5)
|
||||
self:_GetZoneLineup():SmokeZone(SMOKECOLOR.Green, 5)
|
||||
self:_GetZoneBullseye(case):SmokeZone(SMOKECOLOR.White, 45)
|
||||
self:_GetZoneDirtyUp(case):SmokeZone(SMOKECOLOR.Orange, 45)
|
||||
]]
|
||||
self:_GetZoneArcIn(case):SmokeZone(SMOKECOLOR.Blue, 45)
|
||||
self:_GetZoneArcOut(case):SmokeZone(SMOKECOLOR.Blue, 45)
|
||||
self:_GetZonePlatform(case):SmokeZone(SMOKECOLOR.Red, 45)
|
||||
self:_GetZonePlatform(case):SmokeZone(SMOKECOLOR.Blue, 45)
|
||||
self:_GetZoneCorridor(case):SmokeZone(SMOKECOLOR.Green, 45)
|
||||
self:_GetZoneHolding(case, 1):SmokeZone(SMOKECOLOR.White, 45)
|
||||
self:_GetZoneHolding(case, 2):SmokeZone(SMOKECOLOR.White, 45)
|
||||
self:_GetZoneInitial(case):SmokeZone(SMOKECOLOR.Orange, 45)
|
||||
self:_GetZoneCommence(case):SmokeZone(SMOKECOLOR.Red, 45)
|
||||
|
||||
self:_GetZoneCommence(case, 1):SmokeZone(SMOKECOLOR.Red, 45)
|
||||
self:_GetZoneCommence(case, 2):SmokeZone(SMOKECOLOR.Red, 45)
|
||||
--[[
|
||||
self:_GetZoneAbeamLandingSpot():SmokeZone(SMOKECOLOR.Red, 5)
|
||||
self:_GetZoneLandingSpot():SmokeZone(SMOKECOLOR.Red, 5)
|
||||
]]
|
||||
end
|
||||
|
||||
-- Carrier parameter debug tests.
|
||||
@@ -5715,14 +5722,16 @@ function AIRBOSS:_GetNextMarshalFight()
|
||||
end
|
||||
|
||||
-- Check if conditions are right.
|
||||
if stack==1 and flight.holding~=nil and Tmarshal>=TmarshalMin then
|
||||
if flight.ai then
|
||||
-- Return AI flight.
|
||||
return flight
|
||||
else
|
||||
-- Check for human player if they are already commencing.
|
||||
if flight.step~=AIRBOSS.PatternStep.COMMENCING then
|
||||
if flight.holding~=nil and Tmarshal>=TmarshalMin then
|
||||
if flight.case==1 and stack==1 or flight.case>1 then
|
||||
if flight.ai then
|
||||
-- Return AI flight.
|
||||
return flight
|
||||
else
|
||||
-- Check for human player if they are already commencing.
|
||||
if flight.step~=AIRBOSS.PatternStep.COMMENCING then
|
||||
return flight
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -6863,8 +6872,8 @@ function AIRBOSS:_CollapseMarshalStack(flight, nopattern)
|
||||
for _,_flight in pairs(self.Qmarshal) do
|
||||
local mflight=_flight --#AIRBOSS.PlayerData
|
||||
|
||||
-- Only collapse stack of which the flight left. CASE II/III stack is the same.
|
||||
if (case==1 and mflight.case==1) or (case>1 and mflight.case>1) then
|
||||
-- Only collapse stack of which the flight left. CASE II/III stacks are not collapsed.
|
||||
if (case==1 and mflight.case==1) then --or (case>1 and mflight.case>1) then
|
||||
|
||||
-- Get current flag/stack value.
|
||||
local mstack=mflight.flag
|
||||
@@ -6968,6 +6977,96 @@ function AIRBOSS:_GetFreeStack(ai, case, empty)
|
||||
|
||||
-- Recovery case.
|
||||
case=case or self.case
|
||||
|
||||
if case==1 then
|
||||
return self:_GetFreeStack_Old(ai, case, empty)
|
||||
end
|
||||
|
||||
-- Max number of stacks available.
|
||||
local nmaxstacks=100
|
||||
if case==1 then
|
||||
nmaxstacks=self.Nmaxmarshal
|
||||
end
|
||||
|
||||
-- Assume up to two (human) flights per stack. All are free.
|
||||
local stack={}
|
||||
for i=1,nmaxstacks do
|
||||
stack[i]=self.NmaxStack -- Number of human flights per stack.
|
||||
end
|
||||
|
||||
local nmax=1
|
||||
|
||||
-- Loop over all flights in marshal stack.
|
||||
for _,_flight in pairs(self.Qmarshal) do
|
||||
local flight=_flight --#AIRBOSS.FlightGroup
|
||||
|
||||
-- Check that the case is right.
|
||||
if flight.case==case then
|
||||
|
||||
-- Get stack of flight.
|
||||
local n=flight.flag
|
||||
|
||||
if n>nmax then
|
||||
nmax=n
|
||||
end
|
||||
|
||||
if n>0 then
|
||||
if flight.ai or flight.case>1 then
|
||||
stack[n]=0 -- AI get one stack on their own. Also CASE II/III get one stack each.
|
||||
else
|
||||
stack[n]=stack[n]-1
|
||||
end
|
||||
else
|
||||
self:E(string.format("ERROR: Flight %s in marshal stack has stack value <= 0. Stack value is %d.", flight.groupname, n))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
local nfree=nil
|
||||
if stack[nmax]==0 then
|
||||
-- Max occupied stack is completely full!
|
||||
if case==1 then
|
||||
if nmax>=nmaxstacks then
|
||||
-- Already all Case I stacks are occupied ==> wait outside 10 NM zone.
|
||||
nfree=nil
|
||||
else
|
||||
-- Return next free stack.
|
||||
nfree=nmax+1
|
||||
end
|
||||
else
|
||||
-- Case II/III return next stack
|
||||
nfree=nmax+1
|
||||
end
|
||||
|
||||
elseif stack[nmax]==self.NmaxStack then
|
||||
-- Max occupied stack is completely empty! This should happen only when there is no other flight in the marshal queue.
|
||||
self:E(self.lid..string.format("ERROR: Max occupied stack is empty. Should not happen! Nmax=%d, stack[nmax]=%d", nmax, stack[nmax]))
|
||||
nfree=nmax
|
||||
else
|
||||
-- Max occupied stack is partly full.
|
||||
if ai or empty or case>1 then
|
||||
nfree=nmax+1
|
||||
else
|
||||
nfree=nmax
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:I(self.lid..string.format("Returning free stack %s", tostring(nfree)))
|
||||
return nfree
|
||||
end
|
||||
|
||||
--- Get next free Marshal stack. Depending on AI/human and recovery case.
|
||||
-- @param #AIRBOSS self
|
||||
-- @param #boolean ai If true, get a free stack for an AI flight group.
|
||||
-- @param #number case Recovery case. Default current (self) case in progress.
|
||||
-- @param #boolean empty Return lowest stack that is completely empty.
|
||||
-- @return #number Lowest free stack available for the given case or nil if all Case I stacks are taken.
|
||||
function AIRBOSS:_GetFreeStack_Old(ai, case, empty)
|
||||
|
||||
-- Recovery case.
|
||||
case=case or self.case
|
||||
|
||||
-- Max number of stacks available.
|
||||
local nmaxstacks=100
|
||||
@@ -9008,7 +9107,7 @@ function AIRBOSS:_Commencing(playerData, zonecheck)
|
||||
if zonecheck then
|
||||
|
||||
-- Get auto commence zone.
|
||||
local zoneCommence=self:_GetZoneCommence(playerData.case)
|
||||
local zoneCommence=self:_GetZoneCommence(playerData.case, playerData.flag)
|
||||
|
||||
-- Check if unit is in the zone.
|
||||
local inzone=playerData.unit:IsInZone(zoneCommence)
|
||||
@@ -10943,8 +11042,9 @@ end
|
||||
--- Get zone where player are automatically commence when enter.
|
||||
-- @param #AIRBOSS self
|
||||
-- @param #number case Recovery case.
|
||||
-- @param #number stack Stack for Case II/III as we commence from stack>=1.
|
||||
-- @return Core.Zone#ZONE Holding zone.
|
||||
function AIRBOSS:_GetZoneCommence(case)
|
||||
function AIRBOSS:_GetZoneCommence(case, stack)
|
||||
|
||||
-- Commence zone.
|
||||
local zone
|
||||
@@ -10981,12 +11081,11 @@ function AIRBOSS:_GetZoneCommence(case)
|
||||
|
||||
else
|
||||
-- Case II/III
|
||||
|
||||
stack=stack or 1
|
||||
|
||||
-- We simply take the corridor for now. But a bit shorter. Holding starts at 21 and add 2 NM box as commence.
|
||||
--zone=self:_GetZoneCorridor(case, 23)
|
||||
|
||||
-- Total length.
|
||||
local l=21
|
||||
-- Start point at 21 NM for stack=1.
|
||||
local l=20+stack
|
||||
|
||||
-- Offset angle
|
||||
local offset=self:GetRadial(case, false, true)
|
||||
@@ -17333,7 +17432,7 @@ function AIRBOSS:_MarkMarshalZone(_unitName, flare)
|
||||
local zoneHolding=self:_GetZoneHolding(case, stack)
|
||||
|
||||
-- Get Case I commence zone at three position.
|
||||
local zoneThree=self:_GetZoneCommence(case)
|
||||
local zoneThree=self:_GetZoneCommence(case, stack)
|
||||
|
||||
-- Pattern alitude.
|
||||
local patternalt=self:_GetMarshalAltitude(stack, case)
|
||||
|
||||
Reference in New Issue
Block a user