Files
2026-07-15 15:03:40 +00:00

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)