mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge pull request #1224 from FlightControl-Master/FF/Develop
RANGE v2.2.0
This commit is contained in:
commit
e67b819df9
@ -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.
|
-- [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.
|
-- * 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.
|
-- * 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.
|
-- * Results of all bombing and strafing runs are stored and top 10 results can be displayed.
|
||||||
-- * Range targets can be marked by smoke.
|
-- * 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.
|
-- * Bomb, rocket and missile impact points can be marked by smoke.
|
||||||
-- * Direct hits on targets can trigger flares.
|
-- * Direct hits on targets can trigger flares.
|
||||||
-- * Smoke and flare colors can be adjusted for each player via radio menu.
|
-- * 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.
|
-- * Range information and weather report at the range can be reported via radio menu.
|
||||||
--
|
-- * Persistence: Bombing range results can be saved to disk and loaded the next time the mission is started.
|
||||||
-- More information and examples can be found below.
|
-- * Range control voice overs (>40) for hit assessment.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg)
|
-- ## Youtube Videos:
|
||||||
-- ### [MOOSE - On the Range - Demonstration Video](https://www.youtube.com/watch?v=kIXcxNB9_3M)
|
--
|
||||||
|
-- * [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 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 defaultsmokebomb If true, initialize player settings to smoke bomb.
|
||||||
-- @field #boolean autosave If true, automatically save results every X seconds.
|
-- @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.
|
--- *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 parameter "rangename" defines the name of the range. It has to be unique since this is also the name displayed in the radio menu.
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- # 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.
|
-- 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.
|
-- 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,
|
-- 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.
|
-- 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.
|
-- 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.
|
-- 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
|
-- 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.
|
-- 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.
|
-- 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.
|
-- * 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.
|
-- * 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.
|
-- 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
|
-- 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.
|
-- 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:
|
-- 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.
|
-- * @{#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.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.
|
-- * @{#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.
|
-- 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:
|
-- The range menu contains the following submenues:
|
||||||
|
--
|
||||||
|
-- 
|
||||||
--
|
--
|
||||||
-- * "F1. Mark Targets": Various ways to mark targets.
|
-- * "F1. Statistics...": Range results of all players and personal stats.
|
||||||
-- * "F2. My Settings": Player specific settings.
|
-- * "F2. Mark Targets": Mark range targets by smoke or flares.
|
||||||
-- * "F3. Stats" Player: statistics and scores.
|
-- * "F3. My Settings" Personal settings.
|
||||||
-- * "Range Information": Information about the range, such as bearing and range. Also range and player specific settings are displayed.
|
-- * "F4. Range Info": Information about the range, such as bearing and range.
|
||||||
-- * "Weather Report": Temperature, wind and QFE pressure information is provided.
|
--
|
||||||
|
-- ## 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).
|
-- 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.
|
-- 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.
|
-- 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
|
-- 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
|
-- C:\Users\<yourname>\Saved Games\DCS\Logs\dcs.log
|
||||||
@ -213,44 +285,49 @@
|
|||||||
--
|
--
|
||||||
-- @field #RANGE
|
-- @field #RANGE
|
||||||
RANGE={
|
RANGE={
|
||||||
ClassName = "RANGE",
|
ClassName = "RANGE",
|
||||||
Debug=false,
|
Debug = false,
|
||||||
id=nil,
|
id = nil,
|
||||||
rangename=nil,
|
rangename = nil,
|
||||||
location=nil,
|
location = nil,
|
||||||
messages=true,
|
messages = true,
|
||||||
rangeradius=5000,
|
rangeradius = 5000,
|
||||||
rangezone=nil,
|
rangezone = nil,
|
||||||
strafeTargets={},
|
strafeTargets = {},
|
||||||
bombingTargets={},
|
bombingTargets = {},
|
||||||
nbombtargets=0,
|
nbombtargets = 0,
|
||||||
nstrafetargets=0,
|
nstrafetargets = 0,
|
||||||
MenuAddedTo = {},
|
MenuAddedTo = {},
|
||||||
planes = {},
|
planes = {},
|
||||||
strafeStatus = {},
|
strafeStatus = {},
|
||||||
strafePlayerResults = {},
|
strafePlayerResults = {},
|
||||||
bombPlayerResults = {},
|
bombPlayerResults = {},
|
||||||
PlayerSettings = {},
|
PlayerSettings = {},
|
||||||
dtBombtrack=0.005,
|
dtBombtrack = 0.005,
|
||||||
BombtrackThreshold=25000,
|
BombtrackThreshold = 25000,
|
||||||
Tmsg=30,
|
Tmsg = 30,
|
||||||
examinergroupname=nil,
|
examinergroupname = nil,
|
||||||
examinerexclusive=nil,
|
examinerexclusive = nil,
|
||||||
strafemaxalt=914,
|
strafemaxalt = 914,
|
||||||
ndisplayresult=10,
|
ndisplayresult = 10,
|
||||||
BombSmokeColor=SMOKECOLOR.Red,
|
BombSmokeColor = SMOKECOLOR.Red,
|
||||||
StrafeSmokeColor=SMOKECOLOR.Green,
|
StrafeSmokeColor = SMOKECOLOR.Green,
|
||||||
StrafePitSmokeColor=SMOKECOLOR.White,
|
StrafePitSmokeColor = SMOKECOLOR.White,
|
||||||
illuminationminalt=500,
|
illuminationminalt = 500,
|
||||||
illuminationmaxalt=1000,
|
illuminationmaxalt = 1000,
|
||||||
scorebombdistance=1000,
|
scorebombdistance = 1000,
|
||||||
TdelaySmoke=3.0,
|
TdelaySmoke = 3.0,
|
||||||
eventmoose=true,
|
eventmoose = true,
|
||||||
trackbombs=true,
|
trackbombs = true,
|
||||||
trackrockets=true,
|
trackrockets = true,
|
||||||
trackmissiles=true,
|
trackmissiles = true,
|
||||||
defaultsmokebomb=true,
|
defaultsmokebomb = true,
|
||||||
autosave=false,
|
autosave = false,
|
||||||
|
instructorfreq = nil,
|
||||||
|
instructor = nil,
|
||||||
|
rangecontrolfreq = nil,
|
||||||
|
rangecontrol = nil,
|
||||||
|
soundpath = "Range Soundfiles/"
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Default range parameters.
|
--- Default range parameters.
|
||||||
@ -325,6 +402,105 @@ RANGE.TargetType={
|
|||||||
-- @field #string player Player name.
|
-- @field #string player Player name.
|
||||||
-- @field #string airframe Aircraft type of player.
|
-- @field #string airframe Aircraft type of player.
|
||||||
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
|
-- @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.
|
--- Global list of all defined range names.
|
||||||
-- @field #table Names
|
-- @field #table Names
|
||||||
@ -340,7 +516,7 @@ RANGE.MenuF10Root=nil
|
|||||||
|
|
||||||
--- Range script version.
|
--- Range script version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
RANGE.version="2.1.2"
|
RANGE.version="2.2.0"
|
||||||
|
|
||||||
--TODO list:
|
--TODO list:
|
||||||
--TODO: Verbosity level for messages.
|
--TODO: Verbosity level for messages.
|
||||||
@ -431,14 +607,14 @@ function RANGE:New(rangename)
|
|||||||
-- @function [parent=#RANGE] Impact
|
-- @function [parent=#RANGE] Impact
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #RANGE.BombResult result Data of bombing run.
|
-- @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".
|
--- Triggers the FSM delayed event "Impact".
|
||||||
-- @function [parent=#RANGE] __Impact
|
-- @function [parent=#RANGE] __Impact
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number delay Delay in seconds before the function is called.
|
-- @param #number delay Delay in seconds before the function is called.
|
||||||
-- @param #RANGE.BombResult result Data of the bombing run.
|
-- @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.
|
--- On after "Impact" event user function. Called when a bomb/rocket/missile impacted.
|
||||||
-- @function [parent=#RANGE] OnAfterImpact
|
-- @function [parent=#RANGE] OnAfterImpact
|
||||||
@ -447,18 +623,18 @@ function RANGE:New(rangename)
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #RANGE.BombResult result Data of the bombing run.
|
-- @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".
|
--- Triggers the FSM event "EnterRange".
|
||||||
-- @function [parent=#RANGE] EnterRange
|
-- @function [parent=#RANGE] EnterRange
|
||||||
-- @param #RANGE self
|
-- @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".
|
--- Triggers the FSM delayed event "EnterRange".
|
||||||
-- @function [parent=#RANGE] __EnterRange
|
-- @function [parent=#RANGE] __EnterRange
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number delay Delay in seconds before the function is called.
|
-- @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.
|
--- On after "EnterRange" event user function. Called when a player enters the range zone.
|
||||||
-- @function [parent=#RANGE] OnAfterEnterRange
|
-- @function [parent=#RANGE] OnAfterEnterRange
|
||||||
@ -466,18 +642,18 @@ function RANGE:New(rangename)
|
|||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||||
|
|
||||||
--- Triggers the FSM event "ExitRange".
|
--- Triggers the FSM event "ExitRange".
|
||||||
-- @function [parent=#RANGE] ExitRange
|
-- @function [parent=#RANGE] ExitRange
|
||||||
-- @param #RANGE self
|
-- @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".
|
--- Triggers the FSM delayed event "ExitRange".
|
||||||
-- @function [parent=#RANGE] __ExitRange
|
-- @function [parent=#RANGE] __ExitRange
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number delay Delay in seconds before the function is called.
|
-- @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.
|
--- On after "ExitRange" event user function. Called when a player leaves the range zone.
|
||||||
-- @function [parent=#RANGE] OnAfterExitRange
|
-- @function [parent=#RANGE] OnAfterExitRange
|
||||||
@ -485,7 +661,7 @@ function RANGE:New(rangename)
|
|||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #RANGE.Playerdata player Data of player settings etc.
|
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||||
|
|
||||||
-- Return object.
|
-- Return object.
|
||||||
return self
|
return self
|
||||||
@ -573,6 +749,63 @@ function RANGE:onafterStart()
|
|||||||
end
|
end
|
||||||
|
|
||||||
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.
|
-- Debug mode: smoke all targets and range zone.
|
||||||
if self.Debug then
|
if self.Debug then
|
||||||
@ -831,6 +1064,34 @@ function RANGE:TrackMissilesOFF()
|
|||||||
end
|
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.
|
--- 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.
|
-- 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.
|
-- 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
|
if _distance == nil or _temp < _distance then
|
||||||
_distance = _temp
|
_distance = _temp
|
||||||
_closetTarget = _bombtarget
|
_closetTarget = _bombtarget
|
||||||
_closeCoord=targetcoord
|
_closeCoord=targetcoord
|
||||||
if _distance <= 0.5*_bombtarget.goodhitrange then
|
if _distance <= 0.5*_bombtarget.goodhitrange then
|
||||||
_hitquality = "EXCELLENT"
|
_hitquality = "EXCELLENT"
|
||||||
elseif _distance <= _bombtarget.goodhitrange then
|
elseif _distance <= _bombtarget.goodhitrange then
|
||||||
@ -1609,8 +1870,12 @@ function RANGE:OnEventShot(EventData)
|
|||||||
elseif insidezone then
|
elseif insidezone then
|
||||||
|
|
||||||
-- Send message.
|
-- 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)
|
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
|
else
|
||||||
self:T(self.id.."Weapon impacted outside range zone.")
|
self:T(self.id.."Weapon impacted outside range zone.")
|
||||||
@ -1649,15 +1914,49 @@ function RANGE:onafterStatus(From, Event, To)
|
|||||||
-- Check player status.
|
-- Check player status.
|
||||||
self:_CheckPlayers()
|
self:_CheckPlayers()
|
||||||
|
|
||||||
-- Save results.
|
|
||||||
if self.autosave then
|
|
||||||
self:Save()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check back in ~10 seconds.
|
-- Check back in ~10 seconds.
|
||||||
self:__Status(-10)
|
self:__Status(-10)
|
||||||
end
|
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.
|
--- Function called after bomb impact on range.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
@ -1665,7 +1964,7 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #RANGE.BombResult result Result of bomb impact.
|
-- @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)
|
function RANGE:onafterImpact(From, Event, To, result, player)
|
||||||
|
|
||||||
-- Only display target name if there is more than one bomb target.
|
-- 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.."."
|
text=text.."."
|
||||||
end
|
end
|
||||||
text=text..string.format(" %s hit.", result.quality)
|
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.
|
-- Unit.
|
||||||
local unit=UNIT:FindByName(player.unitname)
|
local unit=UNIT:FindByName(player.unitname)
|
||||||
@ -1689,6 +2007,11 @@ function RANGE:onafterImpact(From, Event, To, result, player)
|
|||||||
-- Send message.
|
-- Send message.
|
||||||
self:_DisplayMessageToGroup(unit, text, nil, true)
|
self:_DisplayMessageToGroup(unit, text, nil, true)
|
||||||
self:T(self.id..text)
|
self:T(self.id..text)
|
||||||
|
|
||||||
|
-- Save results.
|
||||||
|
if self.autosave then
|
||||||
|
self:Save()
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1746,7 +2069,11 @@ function RANGE:onafterSave(From, Event, To)
|
|||||||
local quality=result.quality
|
local quality=result.quality
|
||||||
local time=UTILS.SecondsToClock(result.time)
|
local time=UTILS.SecondsToClock(result.time)
|
||||||
local airframe=result.airframe
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1783,7 +2110,7 @@ function RANGE:onafterLoad(From, Event, To)
|
|||||||
f:close()
|
f:close()
|
||||||
return data
|
return data
|
||||||
else
|
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
|
return nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1833,6 +2160,7 @@ function RANGE:onafterLoad(From, Event, To)
|
|||||||
result.weapon=tostring(resultdata[7])
|
result.weapon=tostring(resultdata[7])
|
||||||
result.airframe=tostring(resultdata[8])
|
result.airframe=tostring(resultdata[8])
|
||||||
result.time=UTILS.ClockToSeconds(resultdata[9] or "00:00:00")
|
result.time=UTILS.ClockToSeconds(resultdata[9] or "00:00:00")
|
||||||
|
result.date=resultdata[10] or "n/a"
|
||||||
|
|
||||||
-- Create player array if necessary.
|
-- Create player array if necessary.
|
||||||
self.bombPlayerResults[playername]=self.bombPlayerResults[playername] or {}
|
self.bombPlayerResults[playername]=self.bombPlayerResults[playername] or {}
|
||||||
@ -2106,6 +2434,7 @@ function RANGE:_DisplayRangeInfo(_unitname)
|
|||||||
local position=self.location --Core.Point#COORDINATE
|
local position=self.location --Core.Point#COORDINATE
|
||||||
local bulls=position:ToStringBULLS(unit:GetCoalition(), settings)
|
local bulls=position:ToStringBULLS(unit:GetCoalition(), settings)
|
||||||
local lldms=position:ToStringLLDMS(settings)
|
local lldms=position:ToStringLLDMS(settings)
|
||||||
|
local llddm=position:ToStringLLDDM(settings)
|
||||||
local rangealt=position:GetLandHeight()
|
local rangealt=position:GetLandHeight()
|
||||||
local vec3=coord:GetDirectionVec3(position)
|
local vec3=coord:GetDirectionVec3(position)
|
||||||
local angle=coord:GetAngleDegrees(vec3)
|
local angle=coord:GetAngleDegrees(vec3)
|
||||||
@ -2149,6 +2478,7 @@ function RANGE:_DisplayRangeInfo(_unitname)
|
|||||||
text=text..string.format("Bearing %s, Range %s\n", Bs, trange)
|
text=text..string.format("Bearing %s, Range %s\n", Bs, trange)
|
||||||
text=text..string.format("%s\n", bulls)
|
text=text..string.format("%s\n", bulls)
|
||||||
text=text..string.format("%s\n", lldms)
|
text=text..string.format("%s\n", lldms)
|
||||||
|
text=text..string.format("%s\n", llddm)
|
||||||
text=text..string.format("Altitude ASL: %s\n", trangealt)
|
text=text..string.format("Altitude ASL: %s\n", trangealt)
|
||||||
text=text..string.format("Max strafing alt AGL: %s\n", tstrafemaxalt)
|
text=text..string.format("Max strafing alt AGL: %s\n", tstrafemaxalt)
|
||||||
text=text..string.format("# of strafe targets: %d\n", self.nstrafetargets)
|
text=text..string.format("# of strafe targets: %d\n", self.nstrafetargets)
|
||||||
@ -2192,13 +2522,13 @@ function RANGE:_DisplayBombTargets(_unitname)
|
|||||||
|
|
||||||
if coord then
|
if coord then
|
||||||
|
|
||||||
local ca2g=coord:ToStringA2G(_unit, _settings)
|
local ca2g=coord:ToStringA2G(_unit,_settings)
|
||||||
local lldms=coord:ToStringLLDMS()
|
--local lldms=coord:ToStringLLDMS(_settings)
|
||||||
_text=_text..string.format("\n- %s: %s %s", bombtarget.name or "unknown", ca2g, lldms)
|
_text=_text..string.format("\n- %s:\n%s", bombtarget.name or "unknown", ca2g)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_DisplayMessageToGroup(_unit,_text, nil, true, true)
|
self:_DisplayMessageToGroup(_unit,_text, 60, true, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -2235,7 +2565,7 @@ function RANGE:_DisplayStrafePits(_unitname)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local mycoord=coord:ToStringA2G(_unit, _settings)
|
local mycoord=coord:ToStringA2G(_unit, _settings)
|
||||||
_text=_text..string.format("\n- %s: %s - heading %03d°",_strafepit.name, mycoord, heading)
|
_text=_text..string.format("\n- %s: heading %03d°\n%s",_strafepit.name, heading, mycoord)
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_DisplayMessageToGroup(_unit,_text, nil, true, true)
|
self:_DisplayMessageToGroup(_unit,_text, nil, true, true)
|
||||||
@ -2283,7 +2613,7 @@ function RANGE:_DisplayRangeWeather(_unitname)
|
|||||||
local tW=string.format("%.1f m/s", Ws)
|
local tW=string.format("%.1f m/s", Ws)
|
||||||
local tP=string.format("%.1f mmHg", P*hPa2mmHg)
|
local tP=string.format("%.1f mmHg", P*hPa2mmHg)
|
||||||
if settings:IsImperial() then
|
if settings:IsImperial() then
|
||||||
tT=string.format("%d°F", UTILS.CelciusToFarenheit(T))
|
--tT=string.format("%d°F", UTILS.CelciusToFarenheit(T))
|
||||||
tW=string.format("%.1f knots", UTILS.MpsToKnots(Ws))
|
tW=string.format("%.1f knots", UTILS.MpsToKnots(Ws))
|
||||||
tP=string.format("%.2f inHg", P*hPa2inHg)
|
tP=string.format("%.2f inHg", P*hPa2inHg)
|
||||||
end
|
end
|
||||||
@ -2332,8 +2662,8 @@ function RANGE:_CheckPlayers()
|
|||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
if not playersettings.inzone then
|
if not playersettings.inzone then
|
||||||
self:EnterRange(playersettings)
|
|
||||||
playersettings.inzone=true
|
playersettings.inzone=true
|
||||||
|
self:EnterRange(playersettings)
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -2343,8 +2673,8 @@ function RANGE:_CheckPlayers()
|
|||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
if playersettings.inzone==true then
|
if playersettings.inzone==true then
|
||||||
self:ExitRange(playersettings)
|
|
||||||
playersettings.inzone=false
|
playersettings.inzone=false
|
||||||
|
self:ExitRange(playersettings)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -2409,6 +2739,10 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
self:_DisplayMessageToGroup(_unit, _msg, nil, true)
|
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
|
else
|
||||||
|
|
||||||
@ -2417,16 +2751,21 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
|
|
||||||
-- Result.
|
-- Result.
|
||||||
local _result = self.strafeStatus[_unitID]
|
local _result = self.strafeStatus[_unitID]
|
||||||
|
local _sound = nil --#RANGE.Soundfile
|
||||||
|
|
||||||
-- Judge this pass. Text is displayed on summary.
|
-- Judge this pass. Text is displayed on summary.
|
||||||
if _result.hits >= _result.zone.goodPass*2 then
|
if _result.hits >= _result.zone.goodPass*2 then
|
||||||
_result.text = "EXCELLENT PASS"
|
_result.text = "EXCELLENT PASS"
|
||||||
|
_sound=RANGE.Sound.RCExcellentPass
|
||||||
elseif _result.hits >= _result.zone.goodPass then
|
elseif _result.hits >= _result.zone.goodPass then
|
||||||
_result.text = "GOOD PASS"
|
_result.text = "GOOD PASS"
|
||||||
|
_sound=RANGE.Sound.RCGoodPass
|
||||||
elseif _result.hits >= _result.zone.goodPass/2 then
|
elseif _result.hits >= _result.zone.goodPass/2 then
|
||||||
_result.text = "INEFFECTIVE PASS"
|
_result.text = "INEFFECTIVE PASS"
|
||||||
|
_sound=RANGE.Sound.RCIneffectivePass
|
||||||
else
|
else
|
||||||
_result.text = "POOR PASS"
|
_result.text = "POOR PASS"
|
||||||
|
_sound=RANGE.Sound.RCPoorPass
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Calculate accuracy of run. Number of hits wrt number of rounds fired.
|
-- Calculate accuracy of run. Number of hits wrt number of rounds fired.
|
||||||
@ -2437,13 +2776,28 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Message text.
|
-- 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
|
if shots and accur then
|
||||||
_text=_text..string.format("\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur)
|
_text=_text..string.format("\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur)
|
||||||
end
|
end
|
||||||
|
_text=_text..string.format("\n%s", _result.text)
|
||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
self:_DisplayMessageToGroup(_unit, _text)
|
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.
|
-- Set strafe status to nil.
|
||||||
self.strafeStatus[_unitID] = nil
|
self.strafeStatus[_unitID] = nil
|
||||||
@ -2490,6 +2844,10 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
|
|
||||||
-- Rolling in!
|
-- Rolling in!
|
||||||
local _msg=string.format("%s, rolling in on strafe pit %s.", self:_myname(_unitName), _targetZone.name)
|
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.
|
-- Send message.
|
||||||
self:_DisplayMessageToGroup(_unit, _msg, 10, true)
|
self:_DisplayMessageToGroup(_unit, _msg, 10, true)
|
||||||
@ -2996,7 +3354,7 @@ function RANGE:_SmokeStrafeTargetBoxes(unitname)
|
|||||||
|
|
||||||
for _,_target in pairs(self.strafeTargets) do
|
for _,_target in pairs(self.strafeTargets) do
|
||||||
local zone=_target.polygon --Core.Zone#ZONE
|
local zone=_target.polygon --Core.Zone#ZONE
|
||||||
zone:SmokeZone(self.StrafePitSmokeColor)
|
zone:SmokeZone(self.StrafePitSmokeColor, 4)
|
||||||
for _,_point in pairs(_target.smokepoints) do
|
for _,_point in pairs(_target.smokepoints) do
|
||||||
_point:SmokeOrange() --Corners are smoked orange.
|
_point:SmokeOrange() --Corners are smoked orange.
|
||||||
end
|
end
|
||||||
@ -3189,7 +3547,8 @@ function RANGE:_myname(unitname)
|
|||||||
local pname=unit:GetPlayerName()
|
local pname=unit:GetPlayerName()
|
||||||
local csign=unit:GetCallsign()
|
local csign=unit:GetCallsign()
|
||||||
|
|
||||||
return string.format("%s (%s)", csign, pname)
|
--return string.format("%s (%s)", csign, pname)
|
||||||
|
return string.format("%s", pname)
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user