205 lines
10 KiB
Lua
205 lines
10 KiB
Lua
-- =======================================================
|
|
-- SCRIPT: LASTE Wind/Temp Correction
|
|
-- VERSION: 14-06-2026 (ver. 1.6)
|
|
-- SCRIPTED BY: CaptMike
|
|
-- =======================================================
|
|
-- DESCRIPTION:
|
|
-- In an A-10 Thunderbolt II, LASTE stands for Low Altitude Safety
|
|
-- and Targeting Enhancement.
|
|
--
|
|
-- This script provides an in-cockpit weather data service
|
|
-- for the A-10C and A-10C II modules via the F10 Radio Menu.
|
|
-- It dynamically probes localized weather and pressure data
|
|
-- directly below the aircraft's current coordinate vector.
|
|
--
|
|
-- The output formats data matching the 4 physical CDU entry
|
|
-- altitude tiers (00, 02, 08, 26). Wind parameters are
|
|
-- packed into a raw 5-digit string (e.g., 08001) with no
|
|
-- slashes, allowing direct entry into the CDU scratchpad.
|
|
-- Negative temperatures are prefixed with a minus sign (-).
|
|
--
|
|
-- Displays data via native DCS group text blocks for 5
|
|
-- minutes, with an on-demand option to clear the layout.
|
|
-- Uses the MOOSE framework engine to handle weather tracking.
|
|
-- MOOSE Framework: https://github.com/FlightControl-Master/MOOSE
|
|
--
|
|
--
|
|
-- =======================================================
|
|
-- MISSION EDITOR SETUP INSTRUCTIONS:
|
|
-- =======================================================
|
|
-- 1. Create a trigger to load the MOOSE framework:
|
|
-- - TYPE: 4 MISSION START
|
|
-- - NAME: Load MOOSE
|
|
-- - ACTION: DO SCRIPT FILE -> Select your "Moose.lua" file.
|
|
--
|
|
-- 2. Create a delayed trigger to load this script file:
|
|
-- - TYPE: 1 ONCE
|
|
-- - NAME: Load LASTE Script
|
|
-- - CONDITION: TIME MORE (5)
|
|
-- (This 5-second delay ensures MOOSE initializes first)
|
|
-- - ACTION: DO SCRIPT FILE -> Select this saved script file.
|
|
--
|
|
-- 3. In-Game Usage:
|
|
-- - Hop into any A-10C or A-10C II aircraft slot.
|
|
-- - Press your Communication Menu key (\) -> F10 Other.
|
|
-- - Select "LASTE" -> Opens the custom tool suite.
|
|
-- - Click "Request LASTE Winds" to view or "Clear LASTE Data" to close.
|
|
-- =======================================================
|
|
|
|
-- Print confirmation message directly to the dcs.log file upon execution
|
|
env.info("=== LASTE WIND/TEMP CORRECTION SYSTEM LOADED SUCCESSFULLY ===")
|
|
|
|
-- Global tracking table to manage F10 items natively across network slots
|
|
if not _G.LasteMultiplayerTrack then
|
|
_G.LasteMultiplayerTrack = {
|
|
Menus = {}
|
|
}
|
|
end
|
|
|
|
-- Helper function to fetch and format magnetic variation via MOOSE
|
|
-- UTILS.GetMagneticDeclination() returns degrees (positive=East, negative=West)
|
|
local function GetMagneticVariationString()
|
|
local ok, magVarDeg = pcall(function()
|
|
return UTILS.GetMagneticDeclination()
|
|
end)
|
|
|
|
if not ok or magVarDeg == nil then return "N/A" end
|
|
|
|
local sign = magVarDeg >= 0 and "+" or "-"
|
|
return string.format("%s%.1f deg", sign, math.abs(magVarDeg))
|
|
end
|
|
|
|
-- Function to fetch and display weather safely using native Group environment
|
|
local function ShowLasteToGroup(GroupName)
|
|
local dcsGroup = Group.getByName(GroupName)
|
|
|
|
if dcsGroup and dcsGroup:isExist() then
|
|
local dcsUnits = dcsGroup:getUnits()
|
|
local dcsUnit = dcsUnits[1]
|
|
|
|
if dcsUnit and dcsUnit:isExist() and dcsUnit:getLife() > 0 then
|
|
local unitPos = dcsUnit:getPosition().p
|
|
local PlayerPos = COORDINATE:NewFromVec3(unitPos)
|
|
|
|
-- The 5 valid distinct physical CDU entry tiers
|
|
local AltitudesFeet = {0, 1000, 2000, 8000, 26000}
|
|
|
|
-- Fetch local sea-level barometric pressure (QNH) via native DCS atmosphere engine
|
|
local sampleCoord = { x = unitPos.x, y = 0, z = unitPos.z }
|
|
local _, rawPressurePascal = atmosphere.getTemperatureAndPressure(sampleCoord)
|
|
|
|
-- Convert Pascals to inches of Mercury (inHg)
|
|
local qnhInHg = rawPressurePascal * 0.000295300
|
|
|
|
-- Fetch magnetic variation via MOOSE UTILS (map-wide constant)
|
|
local magVarStr = GetMagneticVariationString()
|
|
|
|
-- Clean, bold header style
|
|
local Message = "===========================================\n"
|
|
Message = Message .. " LASTE WIND/TEMP CORRECTION DATA \n"
|
|
Message = Message .. "===========================================\n"
|
|
Message = Message .. string.format("Location: %s\n", PlayerPos:ToStringMGRS())
|
|
Message = Message .. string.format("Local Magnetic Variation: %s\n", magVarStr)
|
|
Message = Message .. string.format("Current Ground QNH: A%.2f\n\n", qnhInHg)
|
|
|
|
-- Master-aligned headers calibrated to baseline tracking
|
|
Message = Message .. "ALT LAYER ALT WIND TEMP\n"
|
|
Message = Message .. "---------------------------------------------------------\n"
|
|
|
|
-- Loop through altitudes, extract weather, and format
|
|
for _, AltFeet in ipairs(AltitudesFeet) do
|
|
local AltMeters = AltFeet * 0.3048
|
|
local WindDir, WindSpeedms = PlayerPos:GetWind(AltMeters)
|
|
local TempC = math.floor(PlayerPos:GetTemperature(AltMeters))
|
|
local WindKnots = math.floor(WindSpeedms * 1.94384)
|
|
local WindHeading = math.floor(WindDir)
|
|
|
|
-- Format temperature for the CDU with consistent fixed-width alignment
|
|
-- Positive temps padded to 3 chars (e.g. " 20"), negatives keep minus sign (e.g. "-32")
|
|
local TempStr
|
|
if TempC < 0 then
|
|
TempStr = string.format("-%d", math.abs(TempC))
|
|
else
|
|
TempStr = string.format("%3d", TempC)
|
|
end
|
|
|
|
-- Format Wind Data string WITHOUT the slash (e.g., 08001)
|
|
local WindString = string.format("%03d%02d", WindHeading, WindKnots)
|
|
|
|
-- Calibrated space layouts tailored to offset proportional text drift perfectly
|
|
if AltFeet == 0 then
|
|
Message = Message .. string.format("0000 ft 00 %s %s\n", WindString, TempStr)
|
|
elseif AltFeet == 1000 then
|
|
Message = Message .. string.format("1000 ft 01 %s %s\n", WindString, TempStr)
|
|
elseif AltFeet == 2000 then
|
|
Message = Message .. string.format("2000 ft 02 %s %s\n", WindString, TempStr)
|
|
elseif AltFeet == 8000 then
|
|
Message = Message .. string.format("8000 ft 08 %s %s\n", WindString, TempStr)
|
|
elseif AltFeet == 26000 then
|
|
Message = Message .. string.format("26000 ft 26 %s %s\n", WindString, TempStr)
|
|
end
|
|
end
|
|
|
|
Message = Message .. "---------------------------------------------------------\n\n"
|
|
Message = Message .. "=== MANUAL DATA ENTRY STEPS ===\n"
|
|
Message = Message .. "1. Turn Altimeter Pressure knob to match Ground QNH.\n"
|
|
Message = Message .. "2. Press [SYS] on CDU -> OSB 06 [LASTE] -> OSB 07 [WIND].\n"
|
|
Message = Message .. "3. Select/Create Altitude Layer First:\n"
|
|
Message = Message .. " Type ALT value into scratchpad -> Press target ALT OSB.\n"
|
|
Message = Message .. "4. Enter Layer Editing Mode:\n"
|
|
Message = Message .. " Press OSB 07 [WNDEDIT] to open data fields for that altitude.\n"
|
|
Message = Message .. "5. Input Target Data:\n"
|
|
Message = Message .. " Type Wind Entry (e.g. 08001) -> Press OSB 02 [WIND].\n"
|
|
Message = Message .. " Type Temp Entry (e.g. 19 or -32) -> Press OSB 03 [TEMP].\n"
|
|
Message = Message .. "6. Press [WP] on the UFC to return to Steerpoint page."
|
|
|
|
local groupID = dcsGroup:getID()
|
|
trigger.action.outTextForGroup(groupID, "", 1, true)
|
|
trigger.action.outTextForGroup(groupID, Message, 300, true)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Function called by the F10 menu item to clear the display instantly
|
|
local function ClearLasteDisplay(GroupName)
|
|
local dcsGroup = Group.getByName(GroupName)
|
|
if dcsGroup then
|
|
local groupID = dcsGroup:getID()
|
|
trigger.action.outTextForGroup(groupID, "", 1, true)
|
|
end
|
|
end
|
|
|
|
-- Dedicated Multiplayer Safe Loop Scheduler Engine
|
|
local LastePlayerFilter = SET_CLIENT:New():FilterCoalitions("blue"):FilterStart()
|
|
|
|
SCHEDULER:New(nil, function()
|
|
-- Scan all active blue client slots via MOOSE tracking filters
|
|
LastePlayerFilter:ForEachClient(function(ClientUnit)
|
|
if ClientUnit and ClientUnit:IsAlive() then
|
|
local airframeType = ClientUnit:GetTypeName()
|
|
|
|
if airframeType == "A-10C" or airframeType == "A-10C_2" then
|
|
local ClientGroup = ClientUnit:GetGroup()
|
|
|
|
if ClientGroup and ClientGroup:IsAlive() then
|
|
local groupName = ClientGroup:GetName()
|
|
local dcsGroup = Group.getByName(groupName)
|
|
|
|
if dcsGroup then
|
|
local groupID = dcsGroup:getID()
|
|
|
|
-- If this group ID doesn't have an active F10 menu record, construct it natively
|
|
if not _G.LasteMultiplayerTrack.Menus[groupID] then
|
|
-- Insert menus directly into the DCS mission commands network array passing the raw GroupName string
|
|
local rootMenu = missionCommands.addSubMenuForGroup(groupID, "LASTE")
|
|
missionCommands.addCommandForGroup(groupID, "Request LASTE Winds", rootMenu, ShowLasteToGroup, groupName)
|
|
missionCommands.addCommandForGroup(groupID, "Clear LASTE Data", rootMenu, ClearLasteDisplay, groupName)
|
|
_G.LasteMultiplayerTrack.Menus[groupID] = rootMenu
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
end, {}, 1, 2)
|