Help fill the CMANO Entries! See the 2018 Contest for more details. More edits. More quality. More chances to win Steam gift cards.

Lua Beginners Tutorial 1

From Weapons Release Wiki
Jump to: navigation, search

Introduction[edit]

Below is a quick intro to Lua in Command for the Lua beginner with absolutely zero programming experience.

Some great (free) references for what I'm about to describe are:

Lua Programming Wikibook: https://en.wikibooks.org/wiki/Lua_Programming
Lua reference manual: https://www.lua.org/manual/5.3/
Command Lua Documentation: https://commandlua.github.io/index.html

Tutorial[edit]

Input Types[edit]

The absolute first thing you need to know about Lua is input types. For the purposes of this quick guide, you only need to know two:

A string is a alphanumeric grouping of characters, and is enclosed in either single or double quotation marks (I am lazy and tend to use single quotations, there are some situations where this creates extra work so then I use double quotation marks - they are fully interchangable, just make sure to start and end a string with the same type) example: 'Hello, world'

A number is just that, a number. You can perform math functions on numbers, and they are simply written as numbers (no need for quotation marks). example: 5 example: 2 + 3

Functions[edit]

Now with that out of the way let's look at the entry for the GetWeather and SetWeather functions in the Command Lua Documentation.

https://commandlua.github.io/index.html#ScenEdit_GetWeather

   ScenEdit_GetWeather ()
   Get the current weather conditions.
   Returns:
       table Table of weather parameters [temp (average), rainfall, undercloud, seastate] 
   Usage:
       ScenEdit_GetWeather()


So what does this mean? First of all, ScenEdit_GetWeather() is a function, which is like a precompiled set of instructions (in this case a precompiled set of instructions to return the weather data from a Command scenario).

To use an analogy of making a coffee, we could describe it as grind coffee, boil water, place coffee in press, add water to press, wait 4 minutes, press plunger, pour coffee. That works, but if you're constantly asking your assistant to make a coffee, it's much easier to teach them once and after that just say 'make a coffee'. A function in Lua is the equivalent of writing down those instructions and then referring your assistant to those instructions rather than repeating them every time.

In the standard Command Lua Library, functions are preceded by the prefix ScenEdit_. This is a naming convention, and each programmer (or group of programmers in a project) will have their own preferences for this. The brackets at the end of the function name are telling the console to 'execute this function now'.

So let's test this out, open up Command, bring up the Lua console (Editor > Lua Script Console). We can either type in ScenEdit_GetWeather() or click the drop down box, select the appropriate entry and click Insert. Now click Run and... Nothing happens. The function is called and executed without an error, but nothing really seems to happen.

This is because the function returns the current weather conditions. That means that when the function is called, it gathers the weather data and presents it. But without anyone to present it to, the data is never used for anything. Not very useful.

Variables[edit]

So instead, lets try assigning a variable to the function--which is kind of like giving the piece of information it returns a name--and then using the print command to see what the data is.

In the console, input the following:

1 ourVariable = ScenEdit_GetWeather()
2 print (ourVariable)

This should return the following:

  { seastate = 0, rainfall = 0, undercloud = 0, temp = 15 }


Now we're getting somewhere. How did that work? Essentially once we gave the data returned by ScenEdit_GetWeather a name (variable), we could then make use of it, in this case using the print command.

Note that adding a variable to the data returned by this function is not strictly necessary, but it's a good habit to get into when you're starting out with Lua, as it will help you visualise what's going on when you can assign meaningful names to pieces of data. You can get exactly the same output by simply putting the function directly into the print command. Give it a try:

1 print (ScenEdit_GetWeather())

Tables[edit]

So we've got an output, which probably doesn't make much sense to a Lua beginner in its raw form. First, what's the deal with the curly brackets? When you see these curly brackets { and }, that means that you are dealing with a table. A table is a collection of data that has some sort of relationship or common theme. Once you become more familiar with Lua you will be using tables a lot to store information and cut down on repetitive coding, but for now we're going to focus on how tables relate to the GetWeather and SetWeather functions we're discussing.

The table we have here, which is also assigned to the variable ourVariable (unless you closed Command and re-opened it, in which case follow the code steps above to catch up). In the spirit of relating pieces of data to variables with meaningful names, let's assign that weather data table to the variable scenarioWeather. Input the following into the console:

1 scenarioWeather = ourVariable

Q: How else could you assign the scenario weather data to the variable scenarioWeather? A: scenarioWeather = ScenEdit_GetWeather()

Now we have the data assigned to a meaningful name, lets pick apart what a table is and how to access and use the data contained within. As described above, tables are collections of data that are somehow related. There are two types of tables in Lua, arrays and dictionaries.

Arrays[edit]

Type the following example of an array into your console:

1 Letters = {'A','B','C','D','E'}

An array is basically a list of values. They can be strings, numbers, nested tables or even functions. To access the data in an array, we use the variable assigned to the array and then square brackets [ and ] around the sequential number of the value we're referring to. So, to print 'C', the 3rd value, we could use the following command:

1 print (Letters[3])

This would print the third value of the Letters table to the console, in this case C. Arrays are useful for short, simple lists but the numbering can get confusing if you need to refer to a specific value in a large or nested list. That's where dictionaries come in.

Dictionaries[edit]

A dictionary follows the basic format of an array with one key (ugh) difference. In a dictionary, we have keys and values. Type the following example of a dictionary into your console:

1 Car = {colour = 'Silver', make = 'DeLorean', model = 'DMC-12', year = 1982, registration = 'OUTTATIME'}

In the above example, the keys are colour, make, model, year and registration and the values are 'Silver', 'DeLorean', 'DMC-12', 1982 and 'OUTTATIME'. To reference a value within a table, we use the variable name for the table followed by a fullstop/period . and then the desired key. Lets use this dictionary to print the colour of the car:

1 print (Car.colour)

This should print Silver to the console. As you can see, the key and value system makes dealing with large quantities of data much easier for human eyes.

Now that we know what an array and a dictionary is and how they differ, we can easily see that our weather data is in the form of a dictionary.

Q: Knowing what you do now, how would you print the temp value from scenarioWeather? A: print(scenarioWeather.temp) or print(ScenEdit_GetWeather().temp)

Now that we understand the output of GetWeather, let's put it to some meaningful use. First, we'll take a look at the documentation for SetWeather.

   ScenEdit_SetWeather (temperature, rainfall, undercloud, seastate)
   Set the current weather conditions.
   This function takes four numbers that describe the desired weather conditions. These conditions are applied globally.
   Parameters:
       temperature number The current baseline temperature (in deg C). Varies by latitude.
       rainfall number The rainfall rate, 0-50.
       undercloud number The amount of sky that is covered in cloud, 0.0-1.0
       seastate number The current sea state 0-9.
   Returns:
       boolean True/False for Successful/Failure 


This tells us that the function ScenEdit_SetWeather requires some parameters, which are listed in the brackets. These parameters are all numbers (as opposed to strings, tables or boolean inputs). There is also a description of the accepted parameters.

So with this in mind, lets make some changes to the weather. Type the following into your console and click 'Run':

1 ScenEdit_SetWeather(0,25,0.8,5)

This changes the weather to a pretty nasty storm. How do we know it worked? The quickest method is to simply move your mouse over anywhere on the map and the databox will list the weather conditions. This is nice, but lets say you come back to this in two weeks time... It would be nice to have some meaningful variable names to look at rather than a bunch of numbers. Lets reset the weather to its initial state, this time using the dictionary table we generated earlier with the GetWeather command. Type the following into your console and click Run:

1 ScenEdit_SetWeather(scenarioWeather.temp,scenarioWeather.rainfall,scenarioWeather.undercloud,scenarioWeather.seastate)

Move your mouse over the map to see that the weather is reset back to the default. As you can see, while the function requires a number, we can use a variable or a table reference that points to a number. This is incredibly useful as you get more comfortable with Lua and begin to make more complex scripts.

Exercise[edit]

So now we know how to retrieve the current weather data with GetWeather, create variables, reference a table, and alter the weather with SetWeather. Let's do something that is actually useful in scenario design and make a simple script to randomise the weather. To do this, we're going to make use of the native Lua functions math.randomseed(), os.time() and math.random(). Type the following into your console:

1 math.randomseed(os.time())
2 currentWeather = ScenEdit_GetWeather()
3 newTemp = currentWeather.temp + math.random(-5,5)
4 newRainfall = math.random(0,50)
5 newUndercloud = math.random(0,10)/10
6 newSeastate = math.random(0,10)
7 ScenEdit_SetWeather(newTemp, newRainfall, newUndercloud, newSeastate)

Now, I know we introduced some new things here. So let's go through it step by step (or line by line, as it were)

  math.randomseed(os.time())

This calls the math.randomseed function, and uses os.time as a parameter. Great, what does that mean? math.randomseed is a native Lua function (i.e. it is part of Lua, not part of the Command Lua framework that is overlaid onto Lua) that sets the seed number used for random calculations. If we were to use the random seed 1, every 'random' result afterwards would be the same 'random' result for each time we ran the script. To avoid that, we use the the os.time function, which returns the operating system time as a number that represents the number of seconds elapsed since January 1, 1970. This is obviously a large number, and will be different every time the script is called, so it's perfect to ensure 'randomly random' results, not 'predictably random' results like we'd get without specifying a new random seed.

  currentWeather = ScenEdit_GetWeather()

This should be obvious for you now, we're assigning the weather data from GetWeather into a variable called currentWeather

  newTemp = currentWeather.temp + math.random(-5,5)

Here we're assigning the value from the temp key in our variable currentWeather to a variable named newTemp. Then, we're adding a random number to it, between -5 and 5. This is done by using the Lua native function math.random, which requires two parameters: the minimum value (-5 in this case) and the maximum value (5 in this case). When a negative number is used as the minimum, 0 is included in the range (i.e. in our example the possible results are: -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5

Primary school math teaches us that adding a negative number is the same as subtracting, so the actual effect of this line is to take our current temperature, randomly add or subtract up to 5 degrees from it--or add 0 and leave it unchanged--and then store that result as a variable named newTemp for future use.

  newRainfall = math.random(0,50)

This simply assigns a random number between 0 and 50 for rainfall and stores it as the variable newRainfall

  newUndercloud = math.random(0,10)/10

Remember how in the Command Lua Documentation undercloud was specified as a decimal number between 0 and 1.0? math.random can produce very large random decimals, but for our purposes we just want one decimal place. An easy way to do that is to generate a random number between 0 and 10 (meaning 0 is a possible result) and divide by 10. This will give us possible results of: 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0

  newSeastate = math.random(0,10)

Another simple random number, this time between 0 and 10.

  ScenEdit_SetWeather(newTemp, newRainfall, newUndercloud, newSeastate)

Now we're going to take all of those variables and put them into the SetWeather function and run it.

Et voila, you have now written your first random weather script!

Experiment with different values and math operators for your variables, and explore some of the other functions using the knowledge you've developed here in conjunction with the Command Lua Documentation.