-- P-51D-25-NA Export -- https://github.com/asherao/DCS-ExportScripts local base = _G -- game information local os = base.os -- time local Terrain = require('terrain') -- map info ExportScript.FoundDCSModule = true ExportScript.Version.P51D25NA = "1.2.1" ExportScript.ConfigEveryFrameArguments = { --[[ every frames arguments based of "mainpanel_init.lua" Example (http://www.lua.org/manual/5.1/manual.html#pdf-string.format) [DeviceID] = "Format" [4] = "%.4f", <- floating-point number with 4 digits after point [19] = "%0.1f", <- floating-point number with 1 digit after point [129] = "%1d", <- decimal number [5] = "%.f", <- floating point number rounded to a decimal number ]] -- Flight Instruments [11] = "%.4f", -- AirspeedNeedle {0,50,100,150,200,250,300,350,400,450,500,550,600,650,700} {0.0,0.05,0.10,0.15,0.2,0.25,0.3,0.35,0.4,0.45,0.5,0.55,0.6,0.65,0.7} [29] = "%.4f", -- Variometer {-6000,-4000,-2000,2000,4000,6000} {-0.6,-0.4,-0.2,0.2,0.4,0.6} -- Altimeter [97] = "%.4f", -- Altimeter_Pressure {28.1, 31.0}{0.0, 1.0} [96] = "%.4f", -- Altimeter_10000_footPtr {0.0, 100000.0}{0.0, 1.0} [24] = "%.4f", -- Altimeter_1000_footPtr {0.0, 10000.0}{0.0, 1.0} [25] = "%.4f", -- Altimeter_100_footPtr{0.0, 1000.0}{0.0, 1.0} -- Artificial horizon [15] = "%.4f", -- AHorizon_Pitch {1.0, -1.0} [14] = "%.4f", -- AHorizon_Bank {1.0, -1.0} [16] = "%.1f", -- AHorizon_PitchShift {-1.0, 1.0} [20] = "%.1f", -- AHorizon_Caged {0.0, 1.0} -- directional gyro [12] = "%.4f", -- GyroHeading -- turn indicator [27] = "%.4f", -- TurnNeedle {-1.0, 1.0} [28] = "%.4f", -- Slipball {-1.0, 1.0} -- oxygen pressure indicator [34] = "%.4f", -- Oxygen_Pressure {0.0, 500.0} {0.0, 1.0} [33] = "%.4f", -- Oxygen_Flow_Blinker -- fuel system [155] = "%.4f", -- Fuel_Tank_Left {0.0,5.0,15.0,30.0,45.0,60.0,75.0,92.0} {0.0,0.2,0.36,0.52,0.65,0.77,0.92,1.0} [156] = "%.4f", -- Fuel_Tank_Right {0.0,5.0,15.0,30.0,45.0,60.0,75.0,92.0} {0.0,0.2,0.36,0.52,0.65,0.77,0.92,1.0} [160] = "%.4f", -- Fuel_Tank_Fuselage {0.0,10.0,20.0,30.0,40.0,50.0,60.0,70.0,80.0,85.0} {0.0,0.12,0.28,0.40,0.51,0.62,0.72,0.83,0.96,1.0} [32] = "%.4f", -- Fuel_Pressure {0.0, 25.0} {0.0, 1.0} -- A-11 clock [4] = "%.4f", -- CLOCK_currtime_hours {0.0, 12.0}{0.0, 1.0} [5] = "%.4f", -- CLOCK_currtime_minutes {0.0, 60.0}{0.0, 1.0} [6] = "%.4f", -- CLOCK_currtime_seconds {0.0, 60.0}{0.0, 1.0} -- AN5730 remote compass [1] = "%.4f", -- CompassHeading [2] = "%.4f", -- CommandedCourse [3] = "%.4f", -- CommandedCourseKnob -- TailRadarWarning [161] = "%.f", -- Lamp TailRadarWarning -- SCR-522A Control panel [122] = "%.f", -- A_channel_light [123] = "%.f", -- B_channel_light [124] = "%.f", -- C_channel_light [125] = "%.f", -- D_channel_light [126] = "%.f", -- Transmit_light -- hydraulic pressure [78] = "%.4f", -- Hydraulic_Pressure {0.0, 2000.0} {0.0, 1.0} -- Landing gears handle [150] = "%.4f", -- Landing_Gear_Handle [151] = "%.4f", -- Landing_Gear_Handle_Indoor [80] = "%.f", -- LandingGearGreenLight [82] = "%.f", -- LandingGearRedLight -- gauges [10] = "%.4f", -- Manifold_Pressure {10.0, 75.0} {0.0, 1.0} [23] = "%.4f", -- Engine_RPM {0.0, 4500.0} {0.0, 1.0} [9] = "%.4f", -- Vacuum_Suction {0.0, 10.0} {0.0, 1.0} [21] = "%.4f", -- Carb_Temperature {-80, 150} {-0, 1} [22] = "%.4f", -- Coolant_Temperature {-80, 150} {-0, 1} [30] = "%.4f", -- Oil_Temperature {0.0, 100.0} {0, 1.0} [31] = "%.4f", -- Oil_Pressure {0.0, 200.0} {0, 1.0} [164] = "%.1f", -- Left_Fluor_Light [165] = "%.1f", -- Right_Fluor_Light [59] = "%.f", -- Hight_Blower_Lamp -- Trimmer [170] = "%.4f", -- Aileron_Trimmer {-1.0, 1.0} [172] = "%.4f", -- Rudder_Trimmer {-1.0, 1.0} [171] = "%.4f", -- Elevator_Trimmer {-1.0, 1.0} [174] = "%.4f", -- Control_Lock_Bracket [175] = "%.4f", -- Accelerometer_main {-5.0, 12.0} {0.0, 1.0} [177] = "%.4f", -- Accelerometer_min {-5.0, 12.0} {0.0, 1.0} [178] = "%.4f", -- Accelerometer_max {-5.0, 12.0} {0.0, 1.0} [101] = "%.4f", -- Ammeter {0.0, 150.0} {0.0, 1.0} -- light [185] = "%.1f", -- Left_cockpit_light [186] = "%.1f", -- Right_cockpit_light [190] = "%.4f", -- warEmergencyPowerLimWire ------------- --[181] = "%.4f", -- Panel_Shake_Z --[180] = "%.4f", -- Panel_Shake_Y --[189] = "%.4f", -- Panel_Rot_X --[162] = "%.1f", -- Canopy_Trucks --[163] = "%.1f", -- Canopy_Visibility -- Stick --[50] = "%.4f", -- StickPitch --[51] = "%.4f", -- StickBank -- RudderPedals --[54] = "%.4f", -- RudderPedals --[55] = "%.4f", -- Left_Wheel_Brake --[56] = "%.4f", -- Right_Wheel_Brake -- K-14 gunsight [36] = "%.4f", -- sightRange --[188] = "%.4f", -- K_14_Shake_Z --[187] = "%.4f", -- K_14_Shake_Y ------------- --[45] = "%.4f", -- ThrottleTwistGrip ------------- [77] = "%.4f", -- Rocket_Counter ------------- --[413] = "%.1f", -- WindShieldDamages --[412] = "%.1f", -- WindShieldOil } ExportScript.ConfigArguments = { --[[ arguments for export in low tick interval based on "clickabledata.lua" ]] -- Right Swich Panel [102] = "%d", -- Generator Connect/Disconnect [103] = "%d", -- Battery Connect/Disconnect [104] = "%d", -- Gun Heating ON/OFF [105] = "%d", -- Pitot Heating ON/OFF [106] = "%d", -- Wing Position Lights Bright/Off/Dim [107] = "%d", -- Tail Position Lights Bright/Off/Dim [108] = "%d", -- Red Recognition Light Key/Off/Steady [109] = "%d", -- Green Recognition Light Key/Off/Steady [110] = "%d", -- Amber Recognition Light Key/Off/Steady [111] = "%d", -- Recognition Lights Key [112] = "%d", -- Circuit Protectors Reset [100] = "%.4f", -- Right Fluorescent Light (rotary) [90] = "%.4f", -- Left Fluorescent Light (rotary) -- Flight Instrument panel [3] = "%.4f", -- Course Set (rotary) [13] = "%.4f", -- Heading Set/Cage (rotary) [179] = "%d", -- Heading Set/Cage Button [17] = "%.4f", -- Pitch Adjustment (rotary) [18] = "%.4f", -- Cage (rotary) [19] = "%d", -- Cage Button [8] = "%d", -- Winding/Adjustment Clock Button [7] = "%.4f", -- Winding/Adjustment Clock (rotary) [26] = "%.4f", -- Set Pressure (rotary) -- SCR-522A Control panel [117] = "%d", -- Radio ON/OFF [118] = "%d", -- A Channel Activate [119] = "%d", -- B Channel Activate [120] = "%d", -- C Channel Activate [121] = "%d", -- D Channel Activate [127] = "%.4f", -- Radio Lights Dimmer (rotary) [116] = "%.4f", -- Radio Audio Volume (rotary) [44] = "%d", -- Microphone On [200] = "%d", -- Arm rest [129] = "%d", -- Switch Locking Lever [128] = "%d", -- Radio Mode Transmit/Receive/Remote ------------- [71] = "%.4f", -- Cockpit Lights (rotary) [66] = "%0.1f", -- Ignition Off/Right/Left/Both [67] = "%d", -- Gun control Gun And Camera On/Gun And Camera OFF/Camera On [72] = "%d", -- Silence Landing Gear Warning Horn Cut Off -- Bomb Arm/Chemical [69] = "%d", -- Left Bomb Arm/Chemical [70] = "%d", -- Right Bomb Arm/Chemical -- Release Mode [68] = "%0.1f", -- Release Mode, Bombs and Rockets Safe/Bombs Train Release/Bombs Both Release/Rockets Arm [73] = "%0.1f", -- Rockets Release Mode Off/Single/Auto [74] = "%d", -- Rockets Delay Switch Delay/Int [75] = "%0.4f", -- Rockets Counter Control -- Engine Control Panel [58] = "%d", -- Supercharger Switch Cover [57] = "%0.1f", -- Supercharger AUTO/LOW/HIGH [60] = "%d", -- High Blower Lamp Test [61] = "%d", -- Fuel Booster On/Off [62] = "%d", -- Oil Dilute Activate [63] = "%d", -- Starter Activate [64] = "%d", -- Starter Switch Cover [65] = "%d", -- Primer Activate -- Oxygen Regulator [131] = "%d", -- Auto-Mix On-Off [130] = "%0.4f", -- Oxygen Emergency By-pass -- Fuel system [85] = "%0.1f", -- Fuel Selector Valve, Select Right Combat Tank/Select Left Main Tank/Select Fuselage Tank/Select Right Main Tank/Select Left Combat Tank [86] = "%d", -- Fuel Shut-Off Valve ON/OFF -- AN/APS-13 [114] = "%d", -- ail Warning Radar Power ON/OFF [115] = "%d", -- Tail Warning Radar Test [113] = "%.4f", -- Tail Warning Radar Light Control (rotary) ------------- [79] = "%d", -- Hydraulic Release Knob [94] = "%.4f", -- Flaps Control Handle (rotary) [84] = "%d", -- Parking Brake Handle [81] = "%d", -- Safe Landing Gear Light Test [83] = "%d", -- Unsafe Landing Gear Light Test -- Detrola receiver [137] = "%.4f", -- Detrola Frequency Selector (rotary) [138] = "%.4f", -- Detrola Volume (rotary) -- canopy [147] = "%.4f", -- Canopy Hand Crank (rotary) [149] = "%d", -- Canopy Emergency Release Handle -- AN/ARA-8 --[152] = "%0.1f", -- Homing Adapter Mode TRANSMIT/COMM./HOMING --[153] = "%d", -- Homing Adapter Power On/Off --[154] = "%d", -- Homing Adapter's Circuit Breaker -- SCR-695 --[139] = "%0.1f", -- IFF Code Selector Code 1/2/3/4/5/6 --[140] = "%d", -- IFF Power On/Off --[141] = "%d", -- IFF TIME/OFF/ON --[142] = "%d", -- IFF Detonator Circuit On/Off --[143] = "%d", -- IFF Distress Signal On/Off --[145] = "%d", -- IFF Detonator Left --[146] = "%d", -- IFF Detonator Right -- Trimmers [91] = "%.4f", -- Aileron Trim (rotary) [92] = "%.4f", -- Elevator Trim (rotary) [93] = "%.4f", -- Rudder Trim (rotary) ------------- [157] = "%.4f", -- Defroster (rotary) [158] = "%.4f", -- Cold Air (rotary) [159] = "%.4f", -- Hot Air (rotary) ------------- [89] = "%d", -- Landing Light On/Off [168] = "%d", -- Coolant Control Cover [87] = "%0.1f", -- Close Coolant Control/Automatic Coolant Control/Open Coolant Control [169] = "%d", -- Oil Control Cover [88] = "%0.1f", -- Close Oil Control/Automatic Oil Control/Open Oil Control [134] = "%0.1f", -- Carburetor Cold Air Control (rotary) [135] = "%0.1f", -- Carburetor Warm Air Control (rotary) [47] = "%0.1f", -- Mixture Control Select IDLE CUT OFF/RUN/EMERGENCY FULL RICH [43] = "%.4f", -- Throttle (rotary) [46] = "%.4f", -- Propeller RPM (rotary) [173] = "%d", -- Surface Control Lock Plunger. Left Button - Lock Stick in the Forward Position', Right Button - Lock Stick in the Neutral Position [48] = "%.4f", -- Lock Throttle (rotary) [49] = "%.4f", -- Lock Propeller & Mixture (rotary) [176] = "%d", -- G-meter reset [183] = "%d", -- Mirror } ----------------------------- -- HIGH IMPORTANCE EXPORTS -- -- done every export event -- ----------------------------- -- Pointed to by ProcessIkarusDCSHighImportance function ExportScript.ProcessIkarusDCSConfigHighImportance(mainPanelDevice) --[[ every frame export to Ikarus Example from A-10C Get Radio Frequencies get data from device local lUHFRadio = GetDevice(54) ExportScript.Tools.SendData("ExportID", "Format") ExportScript.Tools.SendData(2000, string.format("%7.3f", lUHFRadio:get_frequency()/1000000)) -- <- special function for get frequency data ExportScript.Tools.SendData(2000, ExportScript.Tools.RoundFreqeuncy((UHF_RADIO:get_frequency()/1000000))) -- ExportScript.Tools.RoundFreqeuncy(frequency (MHz|KHz), format ("7.3"), PrefixZeros (false), LeastValue (0.025)) ]] end function ExportScript.ProcessDACConfigHighImportance(mainPanelDevice) --[[ every frame export to DAC Example from A-10C Get Radio Frequencies get data from device local UHF_RADIO = GetDevice(54) ExportScript.Tools.SendDataDAC("ExportID", "Format") ExportScript.Tools.SendDataDAC("ExportID", "Format", HardwareConfigID) ExportScript.Tools.SendDataDAC("2000", string.format("%7.3f", UHF_RADIO:get_frequency()/1000000)) ExportScript.Tools.SendDataDAC("2000", ExportScript.Tools.RoundFreqeuncy((UHF_RADIO:get_frequency()/1000000))) -- ExportScript.Tools.RoundFreqeuncy(frequency (MHz|KHz), format ("7.3"), PrefixZeros (false), LeastValue (0.025)) ]] end ----------------------------------------------------- -- LOW IMPORTANCE EXPORTS -- -- done every gExportLowTickInterval export events -- ----------------------------------------------------- -- Pointed to by ExportScript.ProcessIkarusDCSConfigLowImportance function ExportScript.ProcessIkarusDCSConfigLowImportance(mainPanelDevice) if LoIsObjectExportAllowed() then -- returns true if world objects data is available if LoIsOwnshipExportAllowed() then -- returns true if ownship data is available ExportScript.LoAircraftInfo(mainPanelDevice) -- Provides a lot of aircraft properties ExportScript.AirportInfo(mainPanelDevice) -- Provides info on the two closest airports ExportScript.WindsAloft(mainPanelDevice) -- Gets winds at the aircraft ExportScript.GroundRadar(mainPanelDevice) -- Reports 2 closest friendlies and 2 enemies (Use in Single Player) ExportScript.AirRadar(mainPanelDevice) -- Reports 2 closest friendlies and 2 enemies (Use in Single Player) ExportScript.IglaHunter(mainPanelDevice) -- Locates closest Igla (Use in Single Player) end end end function ExportScript.ProcessDACConfigLowImportance(mainPanelDevice) --[[ every frame export to hardware Example from A-10C Get Radio Frequencies get data from device local UHF_RADIO = GetDevice(54) ExportScript.Tools.SendDataDAC("ExportID", "Format") ExportScript.Tools.SendDataDAC("ExportID", "Format", HardwareConfigID) ExportScript.Tools.SendDataDAC("2000", string.format("%7.3f", UHF_RADIO:get_frequency()/1000000)) ExportScript.Tools.SendDataDAC("2000", ExportScript.Tools.RoundFreqeuncy((UHF_RADIO:get_frequency()/1000000))) -- ExportScript.Tools.RoundFreqeuncy(frequency (MHz|KHz), format ("7.3"), PrefixZeros (false), LeastValue (0.025)) ]] --===================================================================================== --[[ ExportScript.Tools.WriteToLog('list_cockpit_params(): '..ExportScript.Tools.dump(list_cockpit_params())) ExportScript.Tools.WriteToLog('CMSP: '..ExportScript.Tools.dump(list_indication(7))) -- list_indication get tehe value of cockpit displays local ltmp1 = 0 for ltmp2 = 0, 20, 1 do ltmp1 = list_indication(ltmp2) ExportScript.Tools.WriteToLog(ltmp2..': '..ExportScript.Tools.dump(ltmp1)) end ]] --[[ -- getmetatable get function name from devices local ltmp1 = 0 for ltmp2 = 1, 70, 1 do ltmp1 = GetDevice(ltmp2) ExportScript.Tools.WriteToLog(ltmp2..': '..ExportScript.Tools.dump(ltmp1)) ExportScript.Tools.WriteToLog(ltmp2..' (metatable): '..ExportScript.Tools.dump(getmetatable(ltmp1))) end ]] end ----------------------------- -- Custom functions -- ----------------------------- function ExportScript.LoAircraftInfo(mainPanelDevice) -- General local aircraftName = LoGetSelfData().Name -- DCS Name of the aircraft eg "F-5E-3" local pilotName = LoGetPilotName() -- Logbook Pilot name -- Times DCS times are default in seconds local dcsModelTime = LoGetModelTime() -- time since aircraft spawn local missionStartTime = LoGetMissionStartTime() -- second after midnight that the mission started local dcsTimeLocal = formatTime(LoGetMissionStartTime() + LoGetModelTime()) -- up-to-date time in dcs local utcOffset = -1 * Terrain.GetTerrainConfig('SummerTimeDelta') * 3600 -- eg -1 * 4 * 3600 (for seconds to get hours) local dcsTimeUtc = formatTime(dcsModelTime + LoGetMissionStartTime() + utcOffset) -- dcs zulu time local realTimeLocal = os.date("%H-%M-%S") -- real life time local realTimeUtc = os.date("!%H-%M-%S") -- real life zulu time --local playTime = formatTime(DCS.getRealTime()) -- does not work, export environment no access -- Player Aircraft Properties local altMsl_meters = LoGetAltitudeAboveSeaLevel() local altMsl_feet = meters2feet(altMsl_meters) local altAgl_meters = LoGetAltitudeAboveGroundLevel() local altAgl_feet = meters2feet(altAgl_meters) local verticalVelocity_metric = LoGetVerticalVelocity() local verticalVelocity_imperial = metersPerSecond2feetPerMinute(LoGetVerticalVelocity()) local ias_metric = LoGetIndicatedAirSpeed() local ias_knots = metersPerSecond2knots(LoGetIndicatedAirSpeed()) local ias_mph = metersPerSecond2milesPerHour(LoGetIndicatedAirSpeed()) local tas_metric = LoGetTrueAirSpeed() local tas_knots = metersPerSecond2knots(LoGetTrueAirSpeed()) local tas_mph = metersPerSecond2milesPerHour(LoGetTrueAirSpeed()) local speed_mach = LoGetMachNumber() local accel_g = LoGetAccelerationUnits().y local aoa = LoGetAngleOfAttack() --local atmosphericPressure_mmhg = LoGetBasicAtmospherePressure() -- does not seem to work local aircraftPitch, aircraftBank, aircraftYawTrue = LoGetADIPitchBankYaw() aircraftPitch = aircraftPitch * 57.3 aircraftBank = aircraftBank * 57.3 aircraftYawTrue = aircraftYawTrue * 57.3 -- true heading local aircraftYawMagnetic = LoGetMagneticYaw() * 57.3 -- magnetic heading local aircraftHeading = aircraftYawMagnetic -- this cound be negative if aircraftHeading < 0 then aircraftHeading = aircraftHeading + 360 end -- removes the negative local magneticVariance = aircraftYawTrue - aircraftYawMagnetic -- works for all maps local selfData = LoGetSelfData() -- relative the the player local lLatitude = selfData.LatLongAlt.Lat local lLongitude = selfData.LatLongAlt.Long local mgrs = Terrain.GetMGRScoordinates(LoGetSelfData().Position.x, LoGetSelfData().Position.z) local mgrsTable = mgrsTableize(mgrs) -- format is mgrsTable[1][1], mgrsTable[1][2], mgrsTable[1][3], mgrsTable[1][4] local aircraftHeadingTrue = selfData.Heading * 57.3 -- true yeading (same as trueYaw for fixed wing aircraft) -- Engine Info local engineInfo = LoGetEngineInfo() local lEngineRPMleft = engineInfo.RPM.left -- ENG1 RPM % local lEngineRPMright = engineInfo.RPM.right -- ENG2 RPM % local lEngineFuelInternal = engineInfo.fuel_internal -- 1 = full. 0 = empty. Includes external tanks for FF aircraft local lEngineFuelExternal = engineInfo.fuel_external -- TANK2 (EXT) (KG) -- does not seem to work for FF modules local lEngineFuelTotal = lEngineFuelInternal + lEngineFuelExternal local lEngineTempLeft = engineInfo.Temperature.left -- ENG1 EGT ºC. May get odd numbers local lEngineTempRight = engineInfo.Temperature.right -- ENG2 EGT ºC. May get odd numbers local lFuelConsumptionLeft = engineInfo.FuelConsumption.left -- {left ,right},kg per sec local lFuelConsumptionRight = engineInfo.FuelConsumption.right -- {left ,right},kg per sec local lFuelConsumptionTotal = lFuelConsumptionLeft + lFuelConsumptionRight -- total,kg per sec local lHydraulicPressureLeft = engineInfo.HydraulicPressure.left -- {left ,right},kg per square centimeter local lHydraulicPressureRight = engineInfo.HydraulicPressure.right -- {left ,right},kg per square centimeter ExportScript.Tools.SendData(8000, aircraftName) ExportScript.Tools.SendData(8001, pilotName) ExportScript.Tools.SendData(8002, 'Real Time\n'.. realTimeLocal .. '\nDCS Time\n' .. dcsTimeLocal) -- clocks ExportScript.Tools.SendData(8003, 'HDG ' .. prefixZerosFixedLength(round(aircraftHeading,0),3) .. 'º' .. '\nALT ' .. format_int(round(altMsl_feet,-1)) .. ' ft' .. '\nIAS ' .. round(ias_knots,0) .. ' kts' .. '\nV/S ' .. format_int(round(verticalVelocity_imperial,-2)) .. ' ft/min' ) -- Aircraft Instrument panel (western) ExportScript.Tools.SendData(8004, 'HDG ' .. prefixZerosFixedLength(round(aircraftHeading,0),3) .. 'º' .. '\nALT ' .. format_int(round(altMsl_meters,-1)) .. ' m' .. '\nIAS ' .. round(ias_metric,0) .. ' km/h' .. '\nV/S ' .. format_int(round(verticalVelocity_metric,0)) .. ' m/s' ) -- Aircraft Instrument panel (eastern) ExportScript.Tools.SendData(8005, 'HDG ' .. prefixZerosFixedLength(round(aircraftHeading,0),3) .. 'º' .. '\nALT ' .. format_int(round(altMsl_feet,-1)) .. ' ft' .. '\nIAS ' .. round(ias_mph,0) .. ' mph' .. '\nV/S ' .. format_int(round(verticalVelocity_imperial,-2)) .. ' ft/min' ) -- Aircraft Instrument panel (western ww2) ExportScript.Tools.SendData(8006, "Lat-Long-DMS\n" .. formatCoord("DMS",true, lLatitude) .. "\n" .. formatCoord("DMS",false, lLongitude) ) -- Player coordinates in DMS ExportScript.Tools.SendData(8007, "Lat-Long-DDM\n" .. formatCoord("DDM",true, lLatitude) .. "\n" .. formatCoord("DDM",false, lLongitude) ) -- Player coordinates in DDM ExportScript.Tools.SendData(8008, 'MGRS\n'.. mgrsTable[1][1] .. ' ' .. mgrsTable[1][2] .. '\n' .. mgrsTable[1][3] .. ' ' .. mgrsTable[1][4] ) -- Player coordinates in MGRS on 2 rows + title ExportScript.Tools.SendData(8009, 'Mag Var\n' .. format_int(round(magneticVariance, 2))) -- also called magnetic deviation -- Example for using the Lo Data. Feel free to make your own! ExportScript.Tools.SendData(8010, format_int(round(kgPerSecond2poundPerHour(lFuelConsumptionLeft), -1))) -- fuel use in pph end function ExportScript.AirportInfo(mainPanelDevice) local airdromes = LoGetWorldObjects("airdromes") -- returns a list of runways and their popperties local airportInfo = {} -- contains generated table of important properties -- the table will be sorted by nearest airport first -- for this table: -- airportInfo[1] is the first element -- airportInfo[1][1] is the airport name of the first element/airport -- airportInfo[1][2] is the distance to the airport of the first element/airport -- airportInfo[1][3] is the bearing to the airport of the first element/airport -- airportInfo[1][4] is the extimated time en route -- airportInfo[1][5] is the direction of the wind -- airportInfo[1][6] is the windStrength of the wind -- airportInfo[1][7] is the main runway heading -- airportInfo[1][8] is the reverse of the main runway -- airportInfo[1][9] is the prefered runway based on winds for key,value in pairs(airdromes) do -- remove the woRunWay entries so that only named runways are in the list if value.Name ~= 'woRunWay' then -- get the distance from the player to the runway local distance = getdistance(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, "nm") -- get the direction from the player to the runway local bearing = getBearing(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, true) -- estimate the runway heading based on the reported values local runwayHeading = round(value.Heading * 57.3,-1) / 10 if runwayHeading < 0 then runwayHeading = 36 + runwayHeading end -- Reverse it for the reciprocal runway local runwayHeadingReciprocal if runwayHeading > 18 then runwayHeadingReciprocal = runwayHeading-18 else runwayHeadingReciprocal = runwayHeading+18 end local ete = distance / metersPerSecond2knots(LoGetTrueAirSpeed()) * (60 * 60) --based on tas bc dcs is flat... -- if ete is more than 24hrs, make it 24 hrs, which shows up as 00-00-00 -- this case is for choppers and aircraft that arent moving if ete > 86400 then ete = 86400 end ete = formatTime(ete) -- wind at airport calculations. Each airport has slighty different winds -- https://forum.dcs.world/topic/165136-logetwindatpoint-in-exportlua/#comment-3294428 -- LoGetWindAtPoint(x,y,z,is_radio_alt), 2 meters off the ground for the "wind sensor" local vx,_vy,vz,_absolute_height = LoGetWindAtPoint(value.Position.x,2,value.Position.y,true) local windDirectionInRadians = math.atan2(vz,vx) local windDirection = windDirectionInRadians * 57.3 local windStrength = math.sqrt((vx)^2 + (vz)^2) if windDirection < 0 then windDirection = 360 + windDirection end -- Convert to direction to from direction if windDirection > 180 then windDirection = windDirection - 180 else windDirection = windDirection + 180 end -- Calculate the prefered runway for landing -- if the rounded runway is within +- 9 of the rounded wind, then it is prefered local windRounded = round(windDirection, -1) if windRounded >= runwayHeading - 9 and windRounded <= runwayHeading + 9 then runwayHeadingPrefered = runwayHeading else runwayHeadingPrefered = runwayHeadingReciprocal end -- Populate the table with the important info for each airport table.insert(airportInfo, -- the table name {value.Name, -- airport name [1] distance, bearing, ete, --[2][3][4] windDirection,windStrength, --wind direction [5], wind Strength [6] runwayHeading, runwayHeadingReciprocal,runwayHeadingPrefered}) -- [7][8][9] end -- end of woRunWay end -- end of FOR loop -- sort the table based on the second value, which is distance -- https://stackoverflow.com/questions/51276613/how-to-sort-table-by-value-and-then-print-index-in-order -- https://www.tutorialspoint.com/sort-function-in-lua-programming table.sort(airportInfo, function(a,b) return a[2] < b[2] end) -- Primary Airport (closest) ExportScript.Tools.SendData(8101, airportInfo[1][1] .. '\n' -- name of airport --[[.. 'BRG ']] .. format_int(addZeros3(round(airportInfo[1][3],0))) .. 'º ' -- bearing --[[.. 'DIST ']] .. format_int(round(airportInfo[1][2], 0)) .. 'nm\n' -- distance .. 'ETE ' .. airportInfo[1][4] .. '\n' -- estimated time in route .. '' .. prefixZerosFixedLength(round(airportInfo[1][5], 0),3) .. 'º ' -- wind bearing .. round(metersPerSecond2knots(airportInfo[1][6]),0) .. 'kts' -- wing strength .. '\n' .. prefixZerosFixedLength(airportInfo[1][7],2) -- runway 1 .. '-' .. prefixZerosFixedLength(airportInfo[1][8],2) -- runway 2 .. ' (' .. prefixZerosFixedLength(airportInfo[1][9],2) .. ')') -- prefered runway based on wind in parens -- Secondary Airport (second closest) ExportScript.Tools.SendData(8102, airportInfo[2][1] .. '\n' -- name of airport --[[.. 'BRG ']] .. format_int(addZeros3(round(airportInfo[2][3],0))) .. 'º ' -- bearing --[[.. 'DIST ']] .. format_int(round(airportInfo[2][2], 0)) .. 'nm\n' -- distance .. 'ETE ' .. airportInfo[2][4] .. '\n' -- estimated time in route .. '' .. prefixZerosFixedLength(round(airportInfo[2][5], 0),3) .. 'º ' -- wind bearing .. round(metersPerSecond2knots(airportInfo[2][6]),0) .. 'kts' -- wing strength .. '\n' .. prefixZerosFixedLength(airportInfo[2][7],2) -- runway 1 .. '-' .. prefixZerosFixedLength(airportInfo[2][8],2) -- runway 2 .. ' (' .. prefixZerosFixedLength(airportInfo[2][9],2) .. ')') -- prefered runway based on wind in parens end function ExportScript.WindsAloft(mainPanelDevice) -- Winds relative to the aircraft, aka, winds aloft local windAloft = LoGetVectorWindVelocity() local windStrengthAloft = math.sqrt((windAloft.x)^2 + (windAloft.z)^2) local windDirectionAloft = math.deg(math.atan2(windAloft.z, windAloft.x)) if windDirectionAloft < 0 then windDirectionAloft = 360 + windDirectionAloft end -- Convert to direction to from direction if windDirectionAloft > 180 then windDirectionAloft = windDirectionAloft - 180 else windDirectionAloft = windDirectionAloft + 180 end ExportScript.Tools.SendData(8100, 'Wind Aloft\n' .. addZeros3(round(windDirectionAloft,0)) .. 'º ' .. round(metersPerSecond2knots(windStrengthAloft,0)) .. 'kts' ) -- winds at the aircraft end function ExportScript.GroundRadar(mainPanelDevice) -- may return some odd things local tableOfUnits = LoGetWorldObjects('units') local tableOfGround = {} -- relative to the player... local tableOfGround_friendly = {} local tableOfGround_friendlyReports = {} local tableOfGround_enemy = {} local tableOfGround_enemyReports = {} for key,value in pairs(tableOfUnits) do if value.Type.level1 == 2 then table.insert(tableOfGround, value) end end local selfData = LoGetSelfData() local selfCoalitionID = selfData.CoalitionID for key,value in pairs(tableOfGround) do if value.CoalitionID == selfCoalitionID then table.insert(tableOfGround_friendly, value) else table.insert(tableOfGround_enemy, value) end end -- TODO: only do enemy reports if there is an awacs unit(?) for key,value in pairs(tableOfGround_enemy) do local distance = getdistance(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, "nm") local bearing = getBearing(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, true) table.insert(tableOfGround_enemyReports, -- the table name {value.Name, distance, bearing}) --[1][2][3] end table.sort(tableOfGround_enemyReports, function(a,b) return a[2] < b[2] end) -- sort based on the second value, which is distance for key,value in pairs(tableOfGround_friendly) do local distance = getdistance(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, "nm") local bearing = getBearing(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, true) table.insert(tableOfGround_friendlyReports, -- the table name {value.Name, distance, bearing}) --[1][2][3] end table.sort(tableOfGround_friendlyReports, function(a,b) return a[2] < b[2] end) -- sort based on the second value, which is distance local string_8200 = 'No Ground\nEnemy\nDetected' if tableOfGround_enemyReports[1] ~= nill then string_8200 = 'Enemy Ground\n' .. tableOfGround_enemyReports[1][1] .. '\n ' .. prefixZerosFixedLength(tableOfGround_enemyReports[1][3],3) -- bearing .. 'º ' .. round(tableOfGround_enemyReports[1][2],0) .. 'nm'--distance end local string_8201 = 'No Ground\nEnemy\nDetected' if tableOfGround_enemyReports[2] ~= nill then string_8201 = 'Enemy Ground\n'.. tableOfGround_enemyReports[2][1] .. '\n ' .. prefixZerosFixedLength(tableOfGround_enemyReports[2][3],3) -- bearing .. 'º ' .. round(tableOfGround_enemyReports[2][2],0) .. 'nm'--distance end local string_8202 = 'No Ground\nFriend\nDetected' if tableOfGround_friendlyReports[1] ~= nill then string_8202 = 'Friend Ground\n' .. tableOfGround_friendlyReports[1][1] .. '\n ' .. prefixZerosFixedLength(tableOfGround_friendlyReports[1][3],3) -- bearing .. 'º ' .. round(tableOfGround_friendlyReports[1][2],0) .. 'nm'--distance end local string_8203 = 'No Ground\nFriend\nDetected' if tableOfGround_friendlyReports[2] ~= nill then string_8203 = 'Friend Ground\n' .. tableOfGround_friendlyReports[2][1] .. '\n ' .. prefixZerosFixedLength(tableOfGround_friendlyReports[2][3],3) -- bearing .. 'º ' .. round(tableOfGround_friendlyReports[2][2],0) .. 'nm'--distance end ExportScript.Tools.SendData(8200, string_8200) ExportScript.Tools.SendData(8201, string_8201) ExportScript.Tools.SendData(8202, string_8202) ExportScript.Tools.SendData(8203, string_8203) end function ExportScript.AirRadar(mainPanelDevice) local tableOfUnits = LoGetWorldObjects('units') local tableOfAircraft = {} -- relative to the player... local tableOfAircraft_friendly = {} local tableOfAircraft_friendlyReports = {} local tableOfAircraft_enemy = {} local tableOfAircraft_enemyReports = {} for key,value in pairs(tableOfUnits) do if value.Type.level1 == 1 then table.insert(tableOfAircraft, value) end end local selfData = LoGetSelfData() local selfCoalitionID = selfData.CoalitionID for key,value in pairs(tableOfAircraft) do if value.CoalitionID == selfCoalitionID then table.insert(tableOfAircraft_friendly, value) else table.insert(tableOfAircraft_enemy, value) end end -- TODO: only do enemy reports if there is a awacs unit for key,value in pairs(tableOfAircraft_enemy) do local distance = getdistance(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, "nm") local bearing = getBearing(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, true) table.insert(tableOfAircraft_enemyReports, -- the table name {value.Name, distance, bearing}) --[1][2][3] -- https://stackoverflow.com/questions/51276613/how-to-sort-table-by-value-and-then-print-index-in-order -- https://www.tutorialspoint.com/sort-function-in-lua-programming end table.sort(tableOfAircraft_enemyReports, function(a,b) return a[2] < b[2] end) -- sort based on the second value, which is distance for key,value in pairs(tableOfAircraft_friendly) do -- [1] will always be the player local distance = getdistance(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, "nm") local bearing = getBearing(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, true) table.insert(tableOfAircraft_friendlyReports, -- the table name {value.Name, distance, bearing}) --[1][2][3] end table.sort(tableOfAircraft_friendlyReports, function(a,b) return a[2] < b[2] end) -- sort based on the second value, which is distance local string_8210 = 'No Air\nEnemy\nDetected' if tableOfAircraft_enemyReports[1] ~= nill then string_8210 = 'Enemy Air\n' .. tableOfAircraft_enemyReports[1][1] .. '\n ' .. prefixZerosFixedLength(tableOfAircraft_enemyReports[1][3],3) -- bearing .. 'º ' .. round(tableOfAircraft_enemyReports[1][2],0) .. 'nm'--distance end local string_8211 = 'No Air\nEnemy\nDetected' if tableOfAircraft_enemyReports[2] ~= nill then string_8211 = 'Enemy Air\n' .. tableOfAircraft_enemyReports[2][1] .. '\n ' .. prefixZerosFixedLength(tableOfAircraft_enemyReports[2][3],3) -- bearing .. 'º ' .. round(tableOfAircraft_enemyReports[2][2],0) .. 'nm'--distance end local string_8212 = 'No Air\nFriend\nDetected' if tableOfAircraft_friendlyReports[2] ~= nill then string_8212 = 'Friend Air\n' .. tableOfAircraft_friendlyReports[2][1] .. '\n ' .. prefixZerosFixedLength(tableOfAircraft_friendlyReports[2][3],3) -- bearing .. 'º ' .. round(tableOfAircraft_friendlyReports[2][2],0) .. 'nm'--distance end local string_8213 = 'No Air\nFriend\nDetected' if tableOfAircraft_friendlyReports[3] ~= nill then string_8213 = 'Friend Air\n' .. tableOfAircraft_friendlyReports[3][1] .. '\n ' .. prefixZerosFixedLength(tableOfAircraft_friendlyReports[3][3],3) -- bearing .. 'º ' .. round(tableOfAircraft_friendlyReports[3][2],0) .. 'nm'--distance end ExportScript.Tools.SendData(8210,string_8210) ExportScript.Tools.SendData(8211, string_8211) ExportScript.Tools.SendData(8212, string_8212) ExportScript.Tools.SendData(8213, string_8213) end function ExportScript.IglaHunter(mainPanelDevice) -- Locates the nearest Igla local tableOfUnits = LoGetWorldObjects('units') local selfData = LoGetSelfData() local selfCoalitionID = selfData.CoalitionID local tableOfIgla = {} local tableOfIgla_report = {} --TODO: Might have to refine this. for key,value in pairs(tableOfUnits) do if value.CoalitionID ~= selfCoalitionID then if value.Type.level3 == 27 then if value.Type.level2 == 16 then if value.Type.level1 == 2 then if value.Type.level4 == 55 or 54 or 53 or 52 or 62 then table.insert(tableOfIgla, value) end end end end end end --if tableOfIgla ~= null then for key,value in pairs(tableOfIgla) do local distance = getdistance(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, "nm") local bearing = getBearing(LoGetSelfData().LatLongAlt.Lat, value.LatLongAlt.Lat, LoGetSelfData().LatLongAlt.Long, value.LatLongAlt.Long, true) table.insert(tableOfIgla_report, -- the table name {value.Name, distance, bearing}) --[1][2][3] --end end table.sort(tableOfIgla_report, function(a,b) return a[2] < b[2] end) -- sort based on the second value, which is distance local string_8666 = 'Igla Hunter\nSearching...' if tableOfIgla_report[1] ~= nill then string_8666 = 'Igla Detected\n' .. tableOfIgla_report[1][1] .. '\n ' .. prefixZerosFixedLength(tableOfIgla_report[1][3],3) -- bearing .. 'º ' .. round(tableOfIgla_report[1][2],0) .. ' nm'--distance end ExportScript.Tools.SendData(8666, string_8666) end ---------------------- -- Helper Functions -- ---------------------- function ExportScript.Linearize(current_value, raw_tab, final_tab) -- (c) scoobie if current_value <= raw_tab[1] then return final_tab[1] end for index, value in pairs(raw_tab) do if current_value <= value then local ft = final_tab[index] local rt = raw_tab[index] return (current_value - rt) * (ft - final_tab[index - 1]) / (rt - raw_tab[index - 1]) + ft end end -- we shouldn't be here, so something went wrong - return arbitrary max. final value, maybe the user will notice the problem: return final_tab[#final_tab] end function trim(s) --http://lua-users.org/wiki/CommonFunctions -- from PiL2 20.4 return (s:gsub("^%s*(.-)%s*$", "%1")) end function formatTime(time) local seconds = math.floor(time) % 60 local minutes = math.floor(time / 60) % 60 local hours = math.floor(time / (60 * 60)) % 24 return string.format("%02d", hours) .. "-" .. string.format("%02d", minutes) .. "-" .. string.format("%02d", seconds) end function meters2feet(meters) local feet = meters * 3.281 return feet end function feet2meters(feet) local meters = feet / 3.281 return feet end function metersPerSecond2milesPerHour(metersPerSecond) local milesPerHour = metersPerSecond * 2.237 return milesPerHour end function metersPerSecond2knots(metersPerSecond) local knots = metersPerSecond * 1.944 return knots end function kgPerSecond2poundPerHour(kgPerSecond) poundPerHour = kgPerSecond * 7937 return poundPerHour end function metersPerSecond2feetPerMinute(metersPerSecond) local feetPerMinute = metersPerSecond * 197 return feetPerMinute end function round(num, numDecimalPlaces) --http://lua-users.org/wiki/SimpleRound local mult = 10^(numDecimalPlaces or 0) return math.floor(num * mult + 0.5) / mult end function format_int(number) --https://stackoverflow.com/questions/10989788/format-integer-in-lua local i, j, minus, int, fraction = tostring(number):find('([-]?)(%d+)([.]?%d*)') -- reverse the int-string and append a comma to all blocks of 3 digits int = int:reverse():gsub("(%d%d%d)", "%1,") -- reverse the int-string back remove an optional comma and put the -- optional minus and fractional part back return minus .. int:reverse():gsub("^,", "") .. fraction end function formatCoord(type, isLat, d) local h if isLat then if d < 0 then h = 'S' d = -d else h = 'N' end else if d < 0 then h = 'W' d = -d else h = 'E' end end local g = math.floor(d) local m = math.floor(d * 60 - g * 60) local s = d * 3600 - g * 3600 - m * 60 if type == "DMS" then -- Degree Minutes Seconds s = math.floor(s * 100) / 100 return string.format('%s %2d°%.2d\'%05.2f"', h, g, m, s) elseif type == "DDM" then -- Degree Decimal Minutes s = math.floor(s / 60 * 1000) return string.format('%s %2d°%02d.%3.3d\'', h, g, m, s) else -- Decimal Degrees return string.format('%f',d) end end function getdistance(lat1,lat2,lon1,lon2,unit) -- https://www.geeksforgeeks.org/program-distance-two-points-earth/ --Example Locations --lat1 = 42.1578 -- POTI --lat2 = 42.3269 -- HONI --lon1 = 41.6777 --lon2 = 42.4122 local lon1 = toRadians(lon1) local lon2 = toRadians(lon2) local lat1 = toRadians(lat1) local lat2 = toRadians(lat2) -- Haversine formula local dlon = lon2 - lon1 local dlat = lat2 - lat1 local a = math.pow(math.sin(dlat / 2), 2) + math.cos(lat1) * math.cos(lat2) * math.pow(math.sin(dlon / 2),2) local c = 2 * math.asin(math.sqrt(a)) local r -- Radius of earth in X. if unit == 'nm' then r = 6371 / 1.852 -- times 1.852 because I could not find a good NM source elseif unit == 'km' then r = 6371 -- Use 6371 for kilometers elseif unit == 'miles' then r = 3956 -- Use 3956 for miles elseif unit == 'meters' then r = 6371 * 1000 end -- calculate the result return (c * r) end function toRadians(angleIn10thofaDegree) return (angleIn10thofaDegree * math.pi) / 180 end function getBearing(lat1,lat2,lon1,lon2, magnetic) local bearing_rad = math.atan2(lon2 - lon1, lat2 - lat1) if bearing_rad < 0 then bearing_rad = bearing_rad + (2 * math.pi) end bearing = math.deg(bearing_rad) -- start calculation for getting the magnetic bar local _aircraftPitch, _aircraftBank, aircraftYawTrue = LoGetADIPitchBankYaw() aircraftYawTrue = aircraftYawTrue * 57.3 -- actually heading local aircraftYawMagnetic = LoGetMagneticYaw() * 57.3 local magneticVariance = aircraftYawTrue - aircraftYawMagnetic if magnetic == true then bearing = bearing - magneticVariance end -- correction for bearings less than 0 due to the calculation above if bearing < 0 then bearing = bearing + 360 end return bearing end function addZeros3(number) number = string.format("%.1d" , number) if #number == 2 then number = "0" .. number elseif #number == 1 then number = "00" .. number end return number end function prefixZerosFixedLength(number, digitLength) -- prefixZerosFixedLength(99, 3) --> 099 number = string.format("%.1d" , number) -- make the number a string local zerosToAdd = digitLength - #number s = '' for i = 1, zerosToAdd do s = s .. 0 end return s .. number end function mgrsTableize(mgrsString) -- Reference: https://upload.wikimedia.org/wikipedia/commons/b/b7/Universal_Transverse_Mercator_zones.svg -- example: 38 T LM 12345 54321 -- (\d+\s\w)\s(\w+)\s(.+)\s(.+) --c# version of regex -- UTMZone = string, -- MGRSDigraph = string, -- Easting = number, -- Northing = number local UTMZone , MGRSDigraph, Easting, Northing = mgrsString:match('(%d+%s%w)%s(%w+)%s(.+)%s(.+)') local mgrsTbl = {} table.insert(mgrsTbl, {UTMZone,MGRSDigraph,Easting,Northing}) return mgrsTbl end