mirror of
https://github.com/akaAgar/the-universal-mission-for-dcs-world.git
synced 2025-11-25 19:31:01 +00:00
Merge branch 'environment-library'
This commit is contained in:
commit
1488001442
10
README.md
10
README.md
@ -86,7 +86,7 @@ The exact content of the menu will depend on the current phase of the mission.
|
||||
- **Target count**: How many objectives will be spawned. More objectives means potentially more xp in a single sortie, so better medals, but also more work and more risk. Be aware that you can RTB to rearm/refuel at any time between objectives, but you won't accumulate as many single-sortie XP as if you complete objectives without going back to base, because XP is awarded to your profile and reset each time you land.
|
||||
- **Enemy air defense**: Amount, quality and skill of enemy surface-to-air units (AAA, MANPADS and SAM). A higher setting awards more XP.
|
||||
- **Enemy air force**: Amount, quality and skill of enemy combat air patrols. A higher setting awards more XP.
|
||||
- **Wingmen count**: **(COMING SOON!)** How many wingmen will fly by your side (from zero to three). A small XP penalty is added for each additional wingman. Wingman won't get replaced if they get shot during a mission, but they will (with full payload) each time you land and takeoff again. Only shown in single-player missions.
|
||||
- **Wingmen count**: How many wingmen will fly by your side (from zero to three). A small XP penalty is added for each additional wingman. Wingman won't get replaced if they get shot during a mission, but they will (with full payload) each time you land and takeoff again. Only shown in single-player missions.
|
||||
- **Friendly AI CAP**: Should AI fighter aicraft be spawned regularly to patrol the AO and shoot down potential threats? Disabling this option will award you more XP (only if "Enemy air force" is not set to "None") but also means you and your wingmen will be alone against the whole enemy air force.
|
||||
- **View pilot career stats**: Displays a list of your achievements, as well as your medal case. Only available when playing single-player missions and if the Lua IO module has been unsanitized (see "First setup" above)
|
||||
- **Begin mission**: Starts a mission with the current settings.
|
||||
@ -94,10 +94,11 @@ The exact content of the menu will depend on the current phase of the mission.
|
||||
#### During the mission
|
||||
|
||||
- **Mission status**: Displays a summary of the mission's status (list of objectives and progress on each objective).
|
||||
- **Objectives**: Displays a list of commands related to each of the mission's objectives.
|
||||
- **Objective coordinates**: Displays the coordinates of the objective and its BRA ("fly X for Y") relative to the player's position. Some objectives types (e.g. strike missions) are provided with exact coordinates, but must will only have approximate coordiantes, so you'll have to search for your targets in the objective area.
|
||||
- **Objectives**: Displays a list of special commands related to each of the mission's objectives. Be aware that some objectives may have no special commands associated with them.
|
||||
- **Smoke marker on target**: Asks for a friendly JTAC to pop a smoke marker on the target. Makes finding the target easier, but will cost you a small XP penalty. Only available for missions where a JTAC is available (it's pretty hard to throw a smoke grenade at an airplane or a ship in the middle of the sea).
|
||||
- **Flight**: **(COMING SOON!)** Displays a list of commands for your wingmen. Only shown in single-player missions and if wingmen are available for this mission.
|
||||
- **Navigation**: Displays a list of commands related to navigational assistance.
|
||||
- **Navigation to objective [OBJECTIVE NAME]**: Displays the coordinates of the objective, its BRA ("fly X for Y") relative to the player's position and an estimated flight time and ETA. Some objectives types (e.g. strike missions) are provided with exact coordinates, but most will only have approximate coordiantes, so you'll have to search for targets yourself once in the objective area.
|
||||
- **Flight**: Displays a list of commands for your wingmen. Only shown in single-player missions and if wingmen are available for this mission.
|
||||
- **Cover me!**: Tasks your wingmen to immediately engage any nearby air threats.
|
||||
- **Engage**: Tasks your wingmen to engage a certain type of targets. Targets must be detected by your wingmen (see "Report contacts" below), or they won't be able to engage them.
|
||||
- **Report contacts**: Asks your wingmen for a list of all detected contacts. According to range and sensors capabilities, their reports can go from perfect ID (e.g. "Su-27") to very generic descriptions (e.g. "fighter" or even "aircraft")
|
||||
@ -242,6 +243,7 @@ The core script is quite simple and small, I probably won't need too much help w
|
||||
- Increased minimum aircraft spawn altitude to avoir crashes in nearby hills
|
||||
- Infantry escaping from destroyed vehicles is now hidden on F10 map, as it should be
|
||||
- Interception objectives are now marked as complete when target is shot down
|
||||
- Moved "Request objective coordinates" radio commands to new "Navigation" submenu, which will include additional navigational assist in future versions
|
||||
- Lowered MANPADS count and skill (MANPADS are overpowered in DCS, especially SA-18)
|
||||
- "New friendly/enemy aircraft taking off" radio messages now mention their BRAA relative to the player, number of bandits taking off now displayed as a word instead of digits
|
||||
- "Rifle!" and "Missile away!" radio calls now both used for any kind of A/G missiles
|
||||
|
||||
@ -45,6 +45,28 @@ function DCSEx.string.join(table, separator)
|
||||
return joinedString
|
||||
end
|
||||
|
||||
-- TODO: description, file header
|
||||
function DCSEx.string.getTimeString(timeInSeconds, useColon)
|
||||
timeInSeconds = timeInSeconds or timer.getAbsTime()
|
||||
useColon = useColon or false
|
||||
|
||||
timeInSeconds = math.max(0, timeInSeconds) % 86400
|
||||
|
||||
local hours = math.floor(timeInSeconds / 3600)
|
||||
local minutes = math.floor(timeInSeconds / 60 - hours * 60)
|
||||
|
||||
local hoursStr = tostring(hours)
|
||||
if #hoursStr == 1 then hoursStr = "0"..hoursStr end
|
||||
|
||||
local minutesStr = tostring(minutes)
|
||||
if #minutesStr == 1 then minutesStr = "0"..minutesStr end
|
||||
|
||||
local separator = ""
|
||||
if useColon then separator = ":" end
|
||||
|
||||
return hoursStr..separator..minutesStr
|
||||
end
|
||||
|
||||
-- TODO: description, file header
|
||||
function DCSEx.string.toStringNumber(number, firstToUpper)
|
||||
firstToUpper = firstToUpper or false
|
||||
|
||||
277
Script/Library/Environment.lua
Normal file
277
Script/Library/Environment.lua
Normal file
@ -0,0 +1,277 @@
|
||||
Library.environment = {}
|
||||
|
||||
Library.environment.windAmount = {
|
||||
CALM = 1,
|
||||
LIGHT_BREEZE = 2,
|
||||
MODERATE_BREEZE = 3,
|
||||
STRONG_BREEZE = 4,
|
||||
GALE = 5,
|
||||
STORM = 6
|
||||
}
|
||||
|
||||
do
|
||||
local DAYTIME_TABLE = {
|
||||
["Afghanistan"] = {
|
||||
{ 05 * 60 + 31, 18 * 60 + 33 },
|
||||
{ 05 * 60 + 14, 19 * 60 + 00 },
|
||||
{ 04 * 60 + 40, 19 * 60 + 24 },
|
||||
{ 03 * 60 + 53, 19 * 60 + 54 },
|
||||
{ 03 * 60 + 12, 20 * 60 + 27 },
|
||||
{ 02 * 60 + 54, 20 * 60 + 53 },
|
||||
{ 03 * 60 + 09, 20 * 60 + 48 },
|
||||
{ 03 * 60 + 42, 20 * 60 + 12 },
|
||||
{ 04 * 60 + 11, 19 * 60 + 24 },
|
||||
{ 04 * 60 + 35, 18 * 60 + 42 },
|
||||
{ 04 * 60 + 59, 18 * 60 + 15 },
|
||||
{ 05 * 60 + 22, 18 * 60 + 14 },
|
||||
},
|
||||
["Caucasus"] = {
|
||||
{ 08 * 60 + 26, 17 * 60 + 57 },
|
||||
{ 07 * 60 + 49, 18 * 60 + 30 },
|
||||
{ 07 * 60 + 14, 19 * 60 + 01 },
|
||||
{ 07 * 60 + 30, 19 * 60 + 34 },
|
||||
{ 06 * 60 + 35, 20 * 60 + 06 },
|
||||
{ 05 * 60 + 33, 20 * 60 + 40 },
|
||||
{ 06 * 60 + 06, 20 * 60 + 18 },
|
||||
{ 06 * 60 + 39, 19 * 60 + 45 },
|
||||
{ 07 * 60 + 11, 19 * 60 + 13 },
|
||||
{ 08 * 60 + 02, 18 * 60 + 40 },
|
||||
{ 08 * 60 + 17, 18 * 60 + 07 },
|
||||
{ 08 * 60 + 39, 17 * 60 + 45 },
|
||||
},
|
||||
["Falklands"] = {
|
||||
{ 04 * 60 + 42, 20 * 60 + 48 },
|
||||
{ 05 * 60 + 32, 19 * 60 + 54 },
|
||||
{ 06 * 60 + 24, 18 * 60 + 43 },
|
||||
{ 07 * 60 + 18, 17 * 60 + 40 },
|
||||
{ 08 * 60 + 08, 16 * 60 + 57 },
|
||||
{ 08 * 60 + 51, 16 * 60 + 56 },
|
||||
{ 09 * 60 + 04, 17 * 60 + 31 },
|
||||
{ 08 * 60 + 33, 18 * 60 + 19 },
|
||||
{ 07 * 60 + 33, 19 * 60 + 07 },
|
||||
{ 06 * 60 + 24, 20 * 60 + 01 },
|
||||
{ 05 * 60 + 17, 20 * 60 + 53 },
|
||||
{ 04 * 60 + 36, 21 * 60 + 17 },
|
||||
},
|
||||
["GermanyCW"] = {
|
||||
{ 08 * 60 + 09, 16 * 60 + 25 },
|
||||
{ 07 * 60 + 22, 17 * 60 + 19 },
|
||||
{ 06 * 60 + 20, 18 * 60 + 11 },
|
||||
{ 06 * 60 + 08, 20 * 60 + 05 },
|
||||
{ 05 * 60 + 10, 20 * 60 + 56 },
|
||||
{ 04 * 60 + 42, 21 * 60 + 31 },
|
||||
{ 05 * 60 + 02, 21 * 60 + 22 },
|
||||
{ 05 * 60 + 49, 20 * 60 + 31 },
|
||||
{ 06 * 60 + 40, 19 * 60 + 21 },
|
||||
{ 07 * 60 + 32, 18 * 60 + 11 },
|
||||
{ 07 * 60 + 28, 16 * 60 + 13 },
|
||||
{ 08 * 60 + 11, 15 * 60 + 52 },
|
||||
},
|
||||
["Iraq"] = {
|
||||
{ 07 * 60 + 06, 17 * 60 + 33 },
|
||||
{ 06 * 60 + 58, 17 * 60 + 58 },
|
||||
{ 06 * 60 + 30, 18 * 60 + 21 },
|
||||
{ 05 * 60 + 50, 18 * 60 + 44 },
|
||||
{ 05 * 60 + 14, 19 * 60 + 06 },
|
||||
{ 04 * 60 + 53, 19 * 60 + 15 },
|
||||
{ 04 * 60 + 56, 19 * 60 + 03 },
|
||||
{ 05 * 60 + 15, 18 * 60 + 28 },
|
||||
{ 05 * 60 + 36, 17 * 60 + 48 },
|
||||
{ 05 * 60 + 56, 17 * 60 + 11 },
|
||||
{ 06 * 60 + 20, 16 * 60 + 54 },
|
||||
{ 06 * 60 + 47, 17 * 60 + 04 },
|
||||
},
|
||||
["Kola"] = {
|
||||
{ 11 * 60 + 52, 14 * 60 + 02 },
|
||||
{ 09 * 60 + 15, 16 * 60 + 50 },
|
||||
{ 07 * 60 + 07, 18 * 60 + 47 },
|
||||
{ 04 * 60 + 49, 20 * 60 + 48 },
|
||||
{ 02 * 60 + 10, 23 * 60 + 24 },
|
||||
{ 00 * 60 + 00, 23 * 60 + 59 },
|
||||
{ 00 * 60 + 00, 23 * 60 + 59 },
|
||||
{ 03 * 60 + 59, 21 * 60 + 41 },
|
||||
{ 06 * 60 + 03, 19 * 60 + 19 },
|
||||
{ 07 * 60 + 56, 17 * 60 + 08 },
|
||||
{ 10 * 60 + 16, 14 * 60 + 47 },
|
||||
{ 12 * 60 + 00, 13 * 60 + 01 },
|
||||
},
|
||||
["MarianaIslands"] = {
|
||||
{ 07 * 60 + 10, 16 * 60 + 15 },
|
||||
{ 06 * 60 + 50, 16 * 60 + 45 },
|
||||
{ 06 * 60 + 13, 17 * 60 + 11 },
|
||||
{ 05 * 60 + 31, 19 * 60 + 35 },
|
||||
{ 05 * 60 + 00, 19 * 60 + 59 },
|
||||
{ 04 * 60 + 49, 20 * 60 + 18 },
|
||||
{ 05 * 60 + 31, 20 * 60 + 17 },
|
||||
{ 05 * 60 + 24, 19 * 60 + 51 },
|
||||
{ 05 * 60 + 46, 19 * 60 + 10 },
|
||||
{ 06 * 60 + 09, 18 * 60 + 28 },
|
||||
{ 06 * 60 + 37, 15 * 60 + 58 },
|
||||
{ 07 * 60 + 03, 15 * 60 + 54 },
|
||||
},
|
||||
["MarianaIslandsWWII"] = {
|
||||
{ 07 * 60 + 10, 16 * 60 + 15 },
|
||||
{ 06 * 60 + 50, 16 * 60 + 45 },
|
||||
{ 06 * 60 + 13, 17 * 60 + 11 },
|
||||
{ 05 * 60 + 31, 19 * 60 + 35 },
|
||||
{ 05 * 60 + 00, 19 * 60 + 59 },
|
||||
{ 04 * 60 + 49, 20 * 60 + 18 },
|
||||
{ 05 * 60 + 31, 20 * 60 + 17 },
|
||||
{ 05 * 60 + 24, 19 * 60 + 51 },
|
||||
{ 05 * 60 + 46, 19 * 60 + 10 },
|
||||
{ 06 * 60 + 09, 18 * 60 + 28 },
|
||||
{ 06 * 60 + 37, 15 * 60 + 58 },
|
||||
{ 07 * 60 + 03, 15 * 60 + 54 },
|
||||
},
|
||||
["Nevada"] = {
|
||||
{ 07 * 60 + 21, 16 * 60 + 19 },
|
||||
{ 06 * 60 + 58, 16 * 60 + 51 },
|
||||
{ 06 * 60 + 21, 17 * 60 + 18 },
|
||||
{ 06 * 60 + 37, 18 * 60 + 44 },
|
||||
{ 06 * 60 + 04, 19 * 60 + 10 },
|
||||
{ 05 * 60 + 53, 19 * 60 + 29 },
|
||||
{ 06 * 60 + 05, 19 * 60 + 27 },
|
||||
{ 06 * 60 + 29, 19 * 60 + 00 },
|
||||
{ 06 * 60 + 53, 18 * 60 + 17 },
|
||||
{ 07 * 60 + 28, 17 * 60 + 34 },
|
||||
{ 06 * 60 + 47, 16 * 60 + 02 },
|
||||
{ 07 * 60 + 14, 15 * 60 + 58 },
|
||||
},
|
||||
["Normandy"] = {
|
||||
{ 09 * 60 + 23, 17 * 60 + 01 },
|
||||
{ 08 * 60 + 43, 17 * 60 + 52 },
|
||||
{ 07 * 60 + 48, 18 * 60 + 37 },
|
||||
{ 06 * 60 + 43, 19 * 60 + 24 },
|
||||
{ 05 * 60 + 50, 20 * 60 + 09 },
|
||||
{ 05 * 60 + 26, 20 * 60 + 40 },
|
||||
{ 05 * 60 + 42, 20 * 60 + 34 },
|
||||
{ 06 * 60 + 23, 19 * 60 + 51 },
|
||||
{ 07 * 60 + 08, 18 * 60 + 48 },
|
||||
{ 07 * 60 + 53, 17 * 60 + 44 },
|
||||
{ 08 * 60 + 42, 16 * 60 + 52 },
|
||||
{ 09 * 60 + 21, 16 * 60 + 34 },
|
||||
},
|
||||
["PersianGulf"] = {
|
||||
{ 07 * 60 + 34, 17 * 60 + 17 },
|
||||
{ 07 * 60 + 22, 17 * 60 + 39 },
|
||||
{ 06 * 60 + 55, 17 * 60 + 55 },
|
||||
{ 06 * 60 + 23, 18 * 60 + 09 },
|
||||
{ 06 * 60 + 01, 18 * 60 + 25 },
|
||||
{ 05 * 60 + 55, 18 * 60 + 39 },
|
||||
{ 06 * 60 + 05, 18 * 60 + 40 },
|
||||
{ 06 * 60 + 20, 18 * 60 + 21 },
|
||||
{ 06 * 60 + 32, 17 * 60 + 50 },
|
||||
{ 06 * 60 + 45, 17 * 60 + 19 },
|
||||
{ 07 * 60 + 04, 16 * 60 + 58 },
|
||||
{ 07 * 60 + 25, 16 * 60 + 58 },
|
||||
},
|
||||
["SinaiMap"] = {
|
||||
{ 07 * 60 + 10, 16 * 60 + 15 },
|
||||
{ 06 * 60 + 50, 16 * 60 + 45 },
|
||||
{ 06 * 60 + 13, 17 * 60 + 11 },
|
||||
{ 05 * 60 + 31, 19 * 60 + 35 },
|
||||
{ 05 * 60 + 00, 19 * 60 + 59 },
|
||||
{ 04 * 60 + 49, 20 * 60 + 18 },
|
||||
{ 05 * 60 + 31, 20 * 60 + 17 },
|
||||
{ 05 * 60 + 24, 19 * 60 + 51 },
|
||||
{ 05 * 60 + 46, 19 * 60 + 10 },
|
||||
{ 06 * 60 + 09, 18 * 60 + 28 },
|
||||
{ 06 * 60 + 37, 15 * 60 + 58 },
|
||||
{ 07 * 60 + 03, 15 * 60 + 54 },
|
||||
},
|
||||
["Syria"] = {
|
||||
{ 07 * 60 + 10, 16 * 60 + 15 },
|
||||
{ 06 * 60 + 50, 16 * 60 + 45 },
|
||||
{ 06 * 60 + 13, 17 * 60 + 11 },
|
||||
{ 05 * 60 + 31, 19 * 60 + 35 },
|
||||
{ 05 * 60 + 00, 19 * 60 + 59 },
|
||||
{ 04 * 60 + 49, 20 * 60 + 18 },
|
||||
{ 05 * 60 + 31, 20 * 60 + 17 },
|
||||
{ 05 * 60 + 24, 19 * 60 + 51 },
|
||||
{ 05 * 60 + 46, 19 * 60 + 10 },
|
||||
{ 06 * 60 + 09, 18 * 60 + 28 },
|
||||
{ 06 * 60 + 37, 15 * 60 + 58 },
|
||||
{ 07 * 60 + 03, 15 * 60 + 54 },
|
||||
},
|
||||
["TheChannel"] = {
|
||||
{ 09 * 60 + 23, 17 * 60 + 01 },
|
||||
{ 08 * 60 + 43, 17 * 60 + 52 },
|
||||
{ 07 * 60 + 48, 18 * 60 + 37 },
|
||||
{ 06 * 60 + 43, 19 * 60 + 24 },
|
||||
{ 05 * 60 + 50, 20 * 60 + 09 },
|
||||
{ 05 * 60 + 26, 20 * 60 + 40 },
|
||||
{ 05 * 60 + 42, 20 * 60 + 34 },
|
||||
{ 06 * 60 + 23, 19 * 60 + 51 },
|
||||
{ 07 * 60 + 08, 18 * 60 + 48 },
|
||||
{ 07 * 60 + 53, 17 * 60 + 44 },
|
||||
{ 08 * 60 + 42, 16 * 60 + 52 },
|
||||
{ 09 * 60 + 21, 16 * 60 + 34 },
|
||||
}
|
||||
}
|
||||
|
||||
function Library.environment.getDayTime(monthIndex, sunset)
|
||||
monthIndex = DCSEx.math.clamp(monthIndex or env.mission.date.Month, 1, 12)
|
||||
sunset = sunset or false
|
||||
|
||||
if not env or not env.mission or not env.mission.theatre then return 0 end
|
||||
if not DAYTIME_TABLE[env.mission.theatre] then return 0 end
|
||||
|
||||
local sunIndex = 1
|
||||
if sunset then sunIndex = 2 end
|
||||
|
||||
return DAYTIME_TABLE[env.mission.theatre][monthIndex][sunIndex] * 60
|
||||
end
|
||||
|
||||
function Library.environment.isItNightTime(timeOfDayInSeconds)
|
||||
if not env or not env.mission or not env.mission.theatre then return false end
|
||||
if not DAYTIME_TABLE[env.mission.theatre] then return false end
|
||||
|
||||
timeOfDayInSeconds = math.max(0, timeOfDayInSeconds or timer.getAbsTime())
|
||||
|
||||
if timeOfDayInSeconds > 86400 then
|
||||
while timeOfDayInSeconds > 86400 do
|
||||
timeOfDayInSeconds = timeOfDayInSeconds - 86400
|
||||
end
|
||||
end
|
||||
|
||||
local sunriseTime = Library.environment.getDayTime(nil, false)
|
||||
local sunsetTime = Library.environment.getDayTime(nil, true)
|
||||
|
||||
return timeOfDayInSeconds < sunriseTime or timeOfDayInSeconds > sunsetTime
|
||||
end
|
||||
|
||||
function Library.environment.getWindLevel()
|
||||
local windSpeed = 0
|
||||
local windSpeedValuesCount = 0
|
||||
|
||||
if not env or not env.mission or not env.mission.weather or not env.mission.weather.wind then
|
||||
return Library.environment.windAmount.CALM
|
||||
end
|
||||
|
||||
for _,v in ipairs({"at8000", "atGround", "at2000"}) do
|
||||
if env.mission.weather.wind[v] and env.mission.weather.wind[v].speed then
|
||||
windSpeed = windSpeed + env.mission.weather.wind[v].speed
|
||||
windSpeedValuesCount = windSpeedValuesCount + 1
|
||||
end
|
||||
end
|
||||
|
||||
if windSpeedValuesCount == 0 then
|
||||
return Library.environment.windAmount.CALM
|
||||
end
|
||||
|
||||
windSpeed = windSpeed / windSpeedValuesCount
|
||||
if windSpeed < 1 then
|
||||
return Library.environment.windAmount.CALM
|
||||
elseif windSpeed < 4 then
|
||||
return Library.environment.windAmount.LIGHT_BREEZE
|
||||
elseif windSpeed < 8 then
|
||||
return Library.environment.windAmount.MODERATE_BREEZE
|
||||
elseif windSpeed < 14 then
|
||||
return Library.environment.windAmount.STRONG_BREEZE
|
||||
elseif windSpeed < 21 then
|
||||
return Library.environment.windAmount.GALE
|
||||
else
|
||||
return Library.environment.windAmount.STORM
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -251,24 +251,26 @@ Library.radioMessages = {
|
||||
"All flights, objective $1 wrapped, keep on the good work.",
|
||||
"All callsigns, objective $1's done. Proceed direct to next waypoint."
|
||||
},
|
||||
commandObjectiveCoordinates = "We have no exact coordinates for objective $1.\nObjective should be located near:\n$2\n\nFly $3 to reach the objective.",
|
||||
commandObjectiveCoordinatesPrecise = "We have exact coordinates for objective $1.\nObjective coordinates are:\n$2\n\nFly $3 to reach the objective.",
|
||||
|
||||
commandObjectiveCoordinates = "Copy, navigational assist for objective $1.\n\n$2",
|
||||
commandObjectiveCoordinatesPrecise = "Copy, navigational assist for objective $1.\n\n$2",
|
||||
|
||||
commandObjectivesManyLeft = {
|
||||
"Stay focused, people. We still have work to do.\n$1",
|
||||
"Our work is not done yet, we have a lot to do.\n$1",
|
||||
"Flights, you've got a couple of tasks left, keep moving down the list.\n$1",
|
||||
"Still a few objectives outstanding, don't break until they're complete.\n$1",
|
||||
"Alright people, keep your focus, more work ahead before you can head home.\n$1",
|
||||
"All flights, maintain timeline. You've got more boxes to check before RTB.\n$1"
|
||||
"Stay focused, people. We still have work to do.\n\n$1",
|
||||
"Our work is not done yet, we have a lot to do.\n\n$1",
|
||||
"Flights, you've got a couple of tasks left, keep moving down the list.\n\n$1",
|
||||
"Still a few objectives outstanding, don't break until they're complete.\n\n$1",
|
||||
"Alright people, keep your focus, more work ahead before you can head home.\n\n$1",
|
||||
"All flights, maintain timeline. You've got more boxes to check before RTB.\n\n$1"
|
||||
},
|
||||
commandObjectivesOneLeft = {
|
||||
"All flights, you've got one last task before you're done.\n$1",
|
||||
"Flights, almost home. One objective remaining, then you're RTB.\n$1",
|
||||
"All flights, you're down to the final push. Complete this and you're done.\n$1",
|
||||
"All leads, one more on the board. Finish it and head back to base.\n$1",
|
||||
"Flights, you're not clear yet. One last objective to wrap up.\n$1",
|
||||
"Come on people, one last push and we're done.\n$1",
|
||||
"Just one objective to complete and we're done.\n$1"
|
||||
"All flights, you've got one last task before you're done.\n\n$1",
|
||||
"Flights, almost home. One objective remaining, then you're RTB.\n\n$1",
|
||||
"All flights, you're down to the final push. Complete this and you're done.\n\n$1",
|
||||
"All leads, one more on the board. Finish it and head back to base.\n\n$1",
|
||||
"Flights, you're not clear yet. One last objective to wrap up.\n\n$1",
|
||||
"Come on people, one last push and we're done.\n\n$1",
|
||||
"Just one objective to complete and we're done.\n\n$1"
|
||||
},
|
||||
|
||||
jtacSmokeOK = {
|
||||
|
||||
41
Script/The Universal Mission/ATC.lua
Normal file
41
Script/The Universal Mission/ATC.lua
Normal file
@ -0,0 +1,41 @@
|
||||
TUM.atc = {}
|
||||
|
||||
do
|
||||
function TUM.atc.requestNavAssistanceToObjective(index, delayRadioAnswer)
|
||||
local obj = TUM.objectives.getObjective(index)
|
||||
if not obj then return end
|
||||
|
||||
local msgIDSuffix = ""
|
||||
if obj.preciseCoordinates then msgIDSuffix = "Precise" end
|
||||
|
||||
local players = coalition.getPlayers(TUM.settings.getPlayerCoalition())
|
||||
for _,p in ipairs(players) do
|
||||
-- Give BRA to objective
|
||||
local navInfo = "- Fly "..DCSEx.dcs.getBRAA(obj.waypoint3, p:getPoint(), false).."\n"
|
||||
|
||||
-- Give flight time and ETA
|
||||
local velocity = p:getVelocity()
|
||||
local speed = math.max(1, math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z))
|
||||
local distance = DCSEx.math.getDistance2D(obj.waypoint2, DCSEx.math.vec3ToVec2(p:getPoint()))
|
||||
local timeInMinutes = math.max(1, math.floor(distance / (speed * 60)))
|
||||
local eta = DCSEx.string.getTimeString(timer.getAbsTime() + timeInMinutes * 60)
|
||||
if timeInMinutes > 600 then
|
||||
navInfo = navInfo.."- More than ten hours of flight time at current airspeed\n"
|
||||
elseif timeInMinutes > 120 then
|
||||
navInfo = navInfo.."- "..tostring(math.floor(timeInMinutes / 60)).." hours of flight time at current airspeed, ETA "..eta.."\n"
|
||||
else
|
||||
navInfo = navInfo.."- "..tostring(timeInMinutes).." minute(s) of flight time at current airspeed, ETA "..eta.."\n"
|
||||
end
|
||||
|
||||
-- Give objective coordinates
|
||||
if obj.preciseCoordinates then
|
||||
navInfo = navInfo.."\nExact coordinates for objective are:\n"
|
||||
else
|
||||
navInfo = navInfo.."\nNo exact coordinates for objective. Approximate coordinates are:\n"
|
||||
end
|
||||
navInfo = navInfo..DCSEx.world.getCoordinatesAsString(obj.waypoint3, false)
|
||||
|
||||
TUM.radio.playForUnit(DCSEx.dcs.getObjectIDAsNumber(p), "commandObjectiveCoordinates"..msgIDSuffix, { obj.name, navInfo }, "Command", delayRadioAnswer)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -111,12 +111,26 @@ do
|
||||
if missionStatus == TUM.mission.status.NONE then return "" end
|
||||
|
||||
local missionSummary = ""
|
||||
local validObjCount = 1
|
||||
for i=1,TUM.objectives.getCount() do
|
||||
local o = TUM.objectives.getObjective(i)
|
||||
|
||||
if o then
|
||||
if not o.completed or not onlyShowIncomplete then
|
||||
missionSummary = missionSummary.."- Objective "..o.name..": "..Library.tasks[o.taskID].description.short
|
||||
local bulletCharacter = "⬤"
|
||||
if validObjCount == 1 then bulletCharacter = "❶"
|
||||
elseif validObjCount == 2 then bulletCharacter = "❷"
|
||||
elseif validObjCount == 3 then bulletCharacter = "❸"
|
||||
elseif validObjCount == 4 then bulletCharacter = "❹"
|
||||
elseif validObjCount == 5 then bulletCharacter = "❺"
|
||||
elseif validObjCount == 6 then bulletCharacter = "❻"
|
||||
elseif validObjCount == 7 then bulletCharacter = "❼"
|
||||
elseif validObjCount == 8 then bulletCharacter = "❽"
|
||||
elseif validObjCount == 9 then bulletCharacter = "❾"
|
||||
elseif validObjCount == 10 then bulletCharacter = "❿"
|
||||
end
|
||||
|
||||
missionSummary = missionSummary..bulletCharacter.." Objective "..o.name..": "..Library.tasks[o.taskID].description.short
|
||||
if not o.completed then
|
||||
missionSummary = missionSummary.." ("..TUM.objectives.getObjectiveProgress(i, doublePercentage)..")"
|
||||
else
|
||||
@ -126,6 +140,8 @@ do
|
||||
if i < TUM.objectives.getCount() then
|
||||
missionSummary = missionSummary.."\n"
|
||||
end
|
||||
|
||||
validObjCount = validObjCount + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -19,17 +19,8 @@ do
|
||||
local obj = TUM.objectives.getObjective(index)
|
||||
if not obj then return end
|
||||
|
||||
local messageSuffix = ""
|
||||
if obj.preciseCoordinates then messageSuffix = "Precise" end
|
||||
|
||||
TUM.radio.playForCoalition(TUM.settings.getPlayerCoalition(), "playerCommandRequireObjectives", { obj.name }, "Flight", false)
|
||||
|
||||
local players = coalition.getPlayers(TUM.settings.getPlayerCoalition())
|
||||
for _,p in ipairs(players) do
|
||||
local coordinates = DCSEx.world.getCoordinatesAsString(obj.waypoint3, false)
|
||||
local braa = DCSEx.dcs.getBRAA(obj.waypoint3, p:getPoint(), false)
|
||||
TUM.radio.playForUnit(DCSEx.dcs.getObjectIDAsNumber(p), "commandObjectiveCoordinates"..messageSuffix, { obj.name, coordinates, braa }, "Command", true)
|
||||
end
|
||||
TUM.atc.requestNavAssistanceToObjective(index, true)
|
||||
end
|
||||
|
||||
function TUM.missionMenu.create()
|
||||
@ -37,15 +28,20 @@ do
|
||||
missionCommands.addCommand("☱ Mission status", nil, doCommandMissionStatus, nil)
|
||||
|
||||
local objectivesMenuRoot = missionCommands.addSubMenu("❖ Objectives")
|
||||
local navigationMenuRoot = missionCommands.addSubMenu("➽ Navigation")
|
||||
|
||||
for i=1,TUM.objectives.getCount() do
|
||||
local obj = TUM.objectives.getObjective(i)
|
||||
if obj then
|
||||
local objRoot = missionCommands.addSubMenu("Objective "..obj.name.." ("..Library.tasks[obj.taskID].description.short..")", objectivesMenuRoot)
|
||||
missionCommands.addCommand("Request objective coordinates", objRoot, doCommandObjectiveLocation, i)
|
||||
local objNameAndDescription = obj.name.." ("..Library.tasks[obj.taskID].description.short..")"
|
||||
local objRoot = missionCommands.addSubMenu("Objective "..objNameAndDescription, objectivesMenuRoot)
|
||||
TUM.supportJTAC.setupJTACOnObjective(i, objRoot)
|
||||
|
||||
missionCommands.addCommand("Navigation to objective "..objNameAndDescription, navigationMenuRoot, doCommandObjectiveLocation, i)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
TUM.wingmenMenu.create()
|
||||
TUM.supportAWACS.createMenu()
|
||||
|
||||
|
||||
@ -88,6 +88,6 @@ do
|
||||
local objectiveDB = Library.tasks[obj.taskID]
|
||||
if not DCSEx.table.contains(objectiveDB.flags, DCSEx.enums.taskFlag.ALLOW_JTAC) then return end -- No JTAC for this objective
|
||||
|
||||
missionCommands.addCommand("Require smoke marker on target ("..tostring(SMOKE_MARKER_PENALTY).."xp)", menuRoot, doCommandSmoke, index)
|
||||
missionCommands.addCommand("Smoke marker on target ("..tostring(SMOKE_MARKER_PENALTY).."xp)", menuRoot, doCommandSmoke, index)
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user