Lua Scripting


Contents
Related Links

Overview

In addition to the legacy Reverse Polish Notation (RPN) script, Prepar3D offers the capability to embed Lua scripts into xml gauges. Prepar3D currently uses Lua 5.1. For specific information on Lua 5.1 visit their documentation found here.

In addition to embedding Lua scripts into XML gauges, scenarios can now use Script Actions and Script Triggers which can be scripted in Lua.

Syntax

The first line of the embedded Lua script must precede with !lua. The script itself can span across several lines. A comparison between getting the time in seconds for the second hand of a clock in standard gauge XML and Lua XML is shown below:

Standard XML syntax:

<Value>(P:Local time,seconds) flr 60 %</Value>

Lua XML Syntax

<Value>!lua return flr(varget("P:Local time", "seconds")) % 60 </Value>

Be aware that since the Lua code is embedded in XML escape characters are required instead of standard Lua syntax for the following characters:


Functions

In addition to the standard operations provided by Lua these commands are also available. The following table provides the Lua commands that are available.

Lua Function Description Example
lg(x) log10(x) <value>!lua return lg(1000)</value>
pi 3.141592653589793238462643 <value>!lua return pi()</value>
tg(x) tan(x) (in radians) <value>!lua return tg(45)</value>
abs(x) abs(x) <value>!lua return abs(-1)</value>
atg(x) atan(x) (in radians) <value>!lua return atg(1)</value>
cos(x) cos(x) (in radians) <value>!lua return cos(60)</value>
ctg(x) cot(x) (in radians) <value>!lua return ctg(45)</value>
eps(x,y,z) epsilon (floating point equality within value z) <value>!lua return eps(1.234, 1.234, 0.00001)</value>
exp(x) ex <value>!lua return exp(2)</value>
flr(x) floor(x) <value>!lua return flr(1.2)</value>
int(x) int cast <value>!lua x = int(true)</value>
bool(x) bool cast <value>!lua x = bool(0)</value>
log(x,y) logy(x) <value>!lua return log(10,2)</value>
max(x,y) max(x,y) <value>!lua return max(10,15)</value>
min(x,y) min(x,y) <value>!lua return min(10,15)</value>
pow(x,y) xy <value>!lua return pow(2,3)</value>
sin(x) sin(x) (in radians) <value>!lua return sin(30)</value>
sqr(x) x2 <value>!lua return sqr(3)</value>
acos(x) acos(x) (in radians) <value>!lua return acos(0)</value>
asin(x) asin(x) (in radians) <value>!lua return asin(1)</value>
atg2(x,y) atan2(x,y) (in radians) <value>!lua return atan2(1,0)</value>
ceil(x) ceil(x) (in radians) <value>!lua return ceil(1.2)</value>
d360(x) Normalize between 0 - 360 and rounds to nearest integer value <value>!lua return d360(540.7)</value>
dgrd(x) Convert degrees to radians <value>!lua return d360(90)</value>
dnor(x) Normalize between 0 - 360 <value>!lua return dnor(540)</value>
near(x) Returns x+0.5 if x>0 else returns x-0.5 <value>!lua return near(10.5)</value>
rddg(x) Radian to degrees <value>!lua return rddg(pi)</value>
rnor(x) Normalize between 0 - 2pi <value>!lua return rnor(4 * pi())</value>
sqrt(x) sqrt(x) <value>!lua return sqrt(9)</value>
scmp(x,y) String comparison (strcmp) <value>!lua return scmp("equal", "Equal")</Value>
scmi(x,y) String comparison ignoring case (stricmp) <value>!lua return scmi("equal", "Equal")</Value>
varget Gets value of a sim variable <value>!lua return varget("P:Local time", "hours")</value>
varset Sets value of a sim variable <value>!lua return varset("K:PARKING_BRAKES", "1")</value>
varswitch Switch statement. First variable is the control variable, subsequent variables are each case. <value>!lua return varswitch(num_engines, 0, 50, 110, 250)</value>


Examples

This is a simple clock example:

<Gauge Name="lua_clock" Version="1.0">
    <Image Name="clock_background.bmp"/>
    <!-- ========================= Seconds Hand ==================== -->
    <Element>
        <Position X="53.8" Y="95.4" />
        <Image Name="clock_second_hand.bmp" PointsTo="North">
            <Axis X="3.8" Y="40.4" />
        </Image>
        <Rotate>
            <Value>!lua
                return flr(varget("P:Local time", "seconds")) % 60
           </Value>
            <Nonlinearity>
                <Item Value="0" Degrees="-90" />
                <Item Value="15" Degrees="0" />
                <Item Value="30" Degrees="90" />
                <Item Value="45" Degrees="180" />
                <Item Value="60" Degrees="270" />
            </Nonlinearity>
        </Rotate>
    </Element>
    <!-- ========================= Hour Hand ====================== -->
    <Element>
        <Position X="53.6" Y="95.4" />
        <Image Name="clock_hour_needle.bmp" PointsTo="West">
            <Axis X="29.6" Y="3.39999" />
        </Image>
        <Rotate>
            <Value>!lua
                return varget("P:Local time", "hours")
           </Value>
            <Nonlinearity>
                <Item Value="0" Degrees="-90" />
                <Item Value="3" Degrees="0" />
                <Item Value="6" Degrees="90" />
                <Item Value="9" Degrees="180" />
                <Item Value="12" Degrees="270" />
            </Nonlinearity>
        </Rotate>
    </Element>
    <!-- ========================= Minute Hand ====================== -->
    <Element>
        <Position X="53.8" Y="95.4" />
        <Image Name="clock_minute_needle.bmp" PointsTo="North">
            <Axis X="4.8" Y="41.4" />
        </Image>
        <Rotate>
            <Value>!lua
                return flr(varget("P:Local time", "minutes"))
           </Value>
            <Nonlinearity>
                <Item Value="0" Degrees="-90" />
                <Item Value="15" Degrees="0" />
                <Item Value="30" Degrees="90" />
                <Item Value="45" Degrees="180" />
                <Item Value="60" Degrees="270" />
            </Nonlinearity>
        </Rotate>
    </Element>
    <Mouse>
        <Help ID="HELPID_GAUGE_CLOCK_WITH_TIME" />
        <Tooltip ID="TOOLTIPTEXT_CLOCK" />
    </Mouse>
</Gauge>

For a more advanced example of the power of lua script, here is a script used in Prepar3D's example radar gauge which is used for panning and zooming the radar map using the mouse. When the radar map is not zoomed in, this script will set the cursor to the position the user clicks on. When the map is zoomed in, the mouse is used to pan around using a click and drag. At high visual zoom levels, the data zoom level is set to match which sharpens the radar image. Finally the scroll wheel can be used to zoom in and out. For more information on the Prepar3D radar service and how to use is via XML, refer to the this article.

Note that "--" indicates a comment in Lua.


<Script>!lua 
        event = varget("M:Event","String")
        cursorSet = 0
        -- Handle Cursor set or scroll
        if event == "LeftSingle" or event == "LeftDrag" or event == "LeftRelease" then
            x = varget("M:X","Number") / 255.0
            y = varget("M:Y","Number") / 255.0
            -- Zoomed in center cursor on view and pan around on drag
            z = varget("C:P3DRadar:VisualZoom","Number")
            if z > 1 then
                if event == "LeftDrag" then
                   lx = varget("L:P3DRadarLastCursorPositionX","Number")
                   ly = varget("L:P3DRadarLastCursorPositionY","Number")
                   cx = varget("C:P3DRadar:CursorPositionX","Number")
                   cy = varget("C:P3DRadar:CursorPositionY","Number")
                   finalx = cx - ( x - lx ) / z 
                   finaly = cy - ( y - ly ) / z 
                   varset("C:P3DRadar:CursorPositionX",finalx)
                   varset("C:P3DRadar:CursorPositionY",finaly)
                   cursorSet = 1
                elseif event == "LeftRelease" then
                    -- set freesze mode back to previous value
                    varset("C:P3DRadar:FreezeEnabled",varget("L:P3DRadarFreezeEnabled","Number"));
                else
                    -- freeze image while panning because data texture
                    -- Will get remapped if data zoom is used
                    varset("C:P3DRadar:FreezeEnabled",1);
                end
                -- store last cursor position to compare against for dragging
                varset("L:P3DRadarLastCursorPositionX",x)
                varset("L:P3DRadarLastCursorPositionY",y)
            else
                -- not zoomed so just set cursor position directly
                varset("C:P3DRadar:CursorPositionX",x)
                varset("C:P3DRadar:CursorPositionY",y)
                cursorSet = 1
            end
            -- if either case above was hit where cursor got set and tracking is enabled
            -- then request the lat and lon of the cursor because the radar system doesn't
            -- keep the lat lon around.  This will get set in the update script
            if cursorSet == 1 and varget("L:P3DRadarTrackEnabled","Number") == 1 then
                varset("L:P3DRadarTrackLat","Number", varget("C:P3DRadar:CursorPositionLat","Number"))
                varset("L:P3DRadarTrackLon","Number", varget("C:P3DRadar:CursorPositionLon","Number"))
            end

        elseif event == "WheelUp" then
            -- zoom in 0.25 when mouse wheel scrolls up
            z = varget("C:P3DRadar:VisualZoom","Number")
            if z < 10 then
                z = z + 0.25
                if z > 3 then
                    varset("C:P3DRadar:DataZoom",z)
                else
                    varset("C:P3DRadar:DataZoom",1)
                end
                varset("C:P3DRadar:VisualZoom",z)
            end                            
        elseif event == "WheelDown" then
            -- zoom out 0.25 when mouse wheel scrolls down
            z = varget("C:P3DRadar:VisualZoom","Number")
            if z > 1 then
                z = z - 0.25
                if z > 3 then
                    varset("C:P3DRadar:DataZoom",z)
                else
                    varset("C:P3DRadar:DataZoom",1)
                end
                varset("C:P3DRadar:VisualZoom",z)
            end                        
        end

</Script>