___________________________________________ -- Cortex Command Lua Scripting Tutorial -- ___________________________________________ Author - Ken "CaveCricket48" Do Change Log: 8-29-2010: -Small typo fix -Added missile example 4-27-2010: -Small typo fix 3-14-2010: -Small typo fix 3-5-2010: -Small typo fix 2-27-2010: -Put in pointers to devices and particles 2-26-2010: -Initial Release Introduction A tutorial to teach you how to use Lua in Cortex Command. This is written for people who have limited to no knowledge of programming whatsoever, so I'm not going to use complicated words that you may see in other tutorials. It is advised that you know basic CC ini modding before trying scripting. Contents: 1.0 - Starting Off -> 1.1 Making a Lua file -> 1.2 Attaching a script to an object 2.0 - Lua scripting basics -> 2.1 Comments -> 2.2 Data types -> 2.3 Variables -> 2.4 Statements -> 2.5 Tables -> 2.6 For loop 3.0 - Cortex Command Lua stuff -> 3.1 Script phases -> 3.2 Self variable -> 3.3 Functions -> 3.4 Pointers 4.0 - Functions and properties in the wiki 5.0 - Example scripts -> 5.5 Mine -> 5.2 Missile ________________________ ----- 1.0 - Starting Off ----- ________________________ In Cortex Command, Lua allows objects to do things that they normally wouldn't be able to do or to create special effects. - 1.1 Making a Lua file - The way Lua scripts work in Cortex Command is that scripts are attached to objects created with ini coding. To make a Lua file with plain Notepad on windows, just make a new text file, go to "File", "Save As...", change "Save as type:" to all files, and change the ".txt" extension of the file name to ".lua". If there is no extension, just add ".lua" to the end of the file name. Then press "Save" and you've made a Lua file. - 1.2 Attaching a script to an object - To attach a Lua script to an "ini" coded object, simply put "ScriptPath = " in the object's code block with appropriate tabbing. ________________________ ----- 2.0 - Lua scripting basics ----- ________________________ --- 2.1 Comments --- Comments in Lua scripting are lines of text that are not read by the game/program, and are mostly used to annotate the script. To annotate, make 2 hyphens and anything after them on the same line is a comment. [code] -- This is a comment [/code] --- 2.2 Data types --- Data types are types of data that are used for variables and properties. There are 5 main ones in CC: numerical (numbers), text, boolean, Vector, and nil. The first 2 are self-explanitory. A boolean is (true) or (false). A Vector in CC is a coordinate (X,Y). numerical data is used by just typing numbers. Test is used by having a pair of quotation marks (") with text in-between them. A vector is used by having the word "Vector" followed by 2 numbers seperated by a comma in a pair of parenthesis. Nil is nothing (not to be confused with the number zero). [code] 1234 "text" true false Vector(1,1) Vector(5,2) Vector(-7,6) nil [/code] --- 2.3 Variables --- Variables are things in Lua that you can give a value to. They are used for storing information so you can recall it later. A variable consists of its name, a single equal sign, and a value. [code] X = 5 [/code] To change a variable, simply type the same thing again with a new value: [code] X = 2 [/code] You can also make a variable have the same value as another variable by setting its value to the other variable's name: [code] A = 5 X = A [/code] That would make variable "X" equal to 5. There are 2 types of variables in CC: global and local. Global variables can be changed by any object's script re-stating the value and only one variable with that name can exist. Global variables look like the ones above in the examples. Local variables are variables that can have multiple copies, each tied to the object with the script that created them. To make a local variable, type "local" before the variable name followed by a space. Setting a local variable to another local variable works in a similar way as global variables. [code] local varA = 5 local varB = varA [/code] This would make variable "varB" equal to 5. Note how the word "local" was not used after the (=) when recalling the variable "varA". Another useful thing about variables is that you can use variables to set a certain property to an object, and store an object to a variable. When storing an object to a variable, it is easier to interact with and is called a pointer. To use to variables to change the property of an object, you'll need the variable that is a defined pointer to the object (we'll get to this later), followed by a period, the property name, and equal sign, and value. [code] thing.GetsHitByMOs = false [/code] "thing" is a pointer to the object, "GetsHitByMOs" is an ini coded property, and "false" is the value. A commonly used pointer that is already defined is "self". The pointer always refers to the object that the script is attached to. [code] self.GetsHitByMOs = false [/code] --- 2.4 Statements --- The way Lua works (and programming in general) is by checking statements to see if they are true and doing stuff if so (or if not so). Let's look at the code below. [code] if X == 1 then end [/code] What this is doing is checking to see if the variable "X" is equal to "1", and will "do stuff" ("" not an actual action, just a place-holder for other things we'll get to later) if the statement is true. Note the "end" at the bottom of the code block, that says that the "" part of that statement is over. If you don't put an "end" after a statement (the end of a statement is after its too) then you will get an error. Also note how there are 2 equal signs in the "if" line. "==" is for checking congruency and "=" is for setting variables/properties. Checking sybmols are: [code] -- Is equal to == -- Is not equal to ~= -- Is less than < -- Is greater than > -- Is less than or equal to <= -- Is greater than or equal to >= [/code] Statements can also have "else" checks inside of them. Else checks do stuff if the main "if" line is not equal to the value that it is checking for. [code] if X == 1 then else end [/code] Elseif checks are like secondary "if" statements and work in a similar way: [code] if X == 1 then elseif X == 2 then end [/code] You can have more than one "elseif" check in a statement, but only one "else". --- 2.5 Tables --- Lists (also called tables and arrays) are like variables that can have mutiple values. To make a list, make the list name followed by an equal sign and a pair of brackets. [code] thelist = {} [/code] Adding a value to a list is similar to making/changing a variable's value. You need to type the list's name followed by a pair of square brackets with the desired list number, and equal sign, and then a value. [code] thelist[1] = 1234 thelist[2] = 37065 [/code] The number symbol with a list's name in front of it tells the number of items in a list. [code] numbercheck = #thelist [/code] If the list is the same list as the one in the above examples, then this would make the variable "numbercheck" equal to 2. To clear all values from a list, type the list's name followed by an equal sign and an empty pair of brackets. To clear a single value, set the value to nil. [code] -- Clearing the whole list thelist = {} -- Clearing a single item thelist[1] = nil [/code] Lists can be global and local like variables. [code] thelist = {} local thesecondlist = {} [/code] --- 2.6 For Loop --- For Loops are used to do multiple repetitive things in one short chunk of script. "For" loop format below. for = , do An example of a standard "for" statement below. [code] for i = 1, 5 do end [/code] Let's look at each individual part of this: for - The starting keyword i = 1 - The "i" is a temporary variable that the "for" statement uses to store how many times it did the action (including the one it's on). The "i" can be changed to any name like a variable. The "1" there is where to start the count. 5 - The number of times to "". To stop a for loop, have "break" inside an "if" statement that checks for the right conditions. [code] for i = 1, 5 do if i == 3 then break end end [/code] ________________________ ----- 3.0 - Cortex Command Lua stuff ----- ________________________ --- 3.1 Script Phases --- These are technically called "funtions," but that would be confusing, considering what the next topic topic is called. Script phases are parts of the script that are run only when the object has been created, while it exists, or when destroyed. Script phases also require "end"s like if statements. [code] -- Anything in between the the "function Create(self) and its end will only run when the object is created. (only happens once) function Create(self) end -- Anything in between the the "function Update(self) and its end will only run when the object is existing. function Update(self) end -- Anything in between the the "function Destroy(self) and its end will only run when the object is destroyed. (only happens once) function Destroy(self) end [/code] --- 3.2 "self" variable --- In Cortex Command Lua, scripts can set a "self" variable when inside a script phase. These variables are pretty much work the same as local variables. [code] self.varA = 12 self.varB = self.varA [/code] Note how the "self" bit sticks to the variable name where ever the variable is used. --- 3.3 Functions --- Functions are the part of Lua that are pre-set into the game (or program) and interact with stuff. Function format is the funtion's group name followed by colons, the function's name, and its arguments (required data for it to work) seperated by commas in parenthesis. Many Cortex Command function group names can be replaced by a pointer to something that they can interact with. An actual function below: [code] anactor:AddImpulseForce(Vector(0,-10),Vector(0,0)) [/code] The function information from the Cortex Command Lua wiki: [code] AddImpulseForce Adds impulse force (or instant momentum) to this MovableObject for the next time Update() is called. Arguments: - An Vector with the impulse force vector that will directly be added to this MovableObject's momentum next Update(). In kg * m/s. - A Vector with the offset, in METERS, of where the impulse is being applied relative to the center of this MovableObject. Return value: None. [/code] "anactor" is a pointer to an actor, "AddImpulseForce" is the name of the function, and the stuff in the parenthesis are data required for the function to work. In the part of the function info that says "Return value" is what the function spits out when it runs. For example, if the retrun function was the target object's mass, then making a variable's value the function would make it the object's mass. Most functions in Cortex Command can be found in the wiki, so be sure to check it out. --- 3.4 Pointers --- Alright, we finally got to pointers! In Cortex Command, pointers are variables that "store" an object to them. Or you can imagine it as a giant arrow directed towards the object. Whatever property you set on a pointer or use a function on it, will effect the thing that they're "pointing" at. There are several ways to make pointers. A common one is to use a special "for" statement that goes through a all of the objects of a certain type and have a statement that checks if the object is the one you want. The script chunk below is attached to a object that looks for the actor is named "Dummy" and then sets a pointer to it called "local pointer". [code] function Update(self) for actor in MovableMan.Actors do if actor.PresetName == "Dummy" then local pointer = actor break end end end [/code] What the above script chunck does is go through all actors in-game untill it finds an actor with "PresetName" as "'Dummy'". Then it sets a pointer to that actor as "local pointer" and stops the "for" statement with "break". The term "actor" is a pointer to an actor, and is transfered to "local pointer" for easier reference. There are 2 other "for" lines that get pointers on devices and particles. [code] -- Pointer to devices for item in MovableMan.Items do end [/code] [code] -- Pointer to particles for particle in MovableMan.Particles do end [/code] ________________________ ----- 4.0 - Functions and properties in the wiki ----- ________________________ This is a link to a section of the Cortex Command wiki that contains documentation for many functions and properties. http://wiki.datarealms.com/wiki/index.php/LuaDocs/Index ________________________ ----- 5.0 - Example scripts ----- ________________________ Below are some examples of complete scripts with comments that may help for reference. --- 5.1 Mine --- This script is for a basic mine that explodes when actors get within a specific distance of the scripted object. With comments: [code] -- While the object is existing... function Update(self) -- Go through all actors. for actor in MovableMan.Actors do -- Uses a function plus a vector property to store the distance between the actor and scripted object in a variable. local distcheck = SceneMan:shortestDistance(self.Pos,actor.Pos,true).Magnitude -- Statement checking if the distance check (variable "local distcheck") is less than 30. If so, then do the action... if distcheck < 30 then -- GibThis() is a function that makes the targeted object gib. Since the target is "self" then the scripted object gibs. self:GibThis() -- Stop the for loop. break -- End of the "if" statement. end -- End of the "for" statement. end -- End of the "function Update(self)". end [/code] Without comments: [code] function Update(self) for actor in MovableMan.Actors do local distcheck = SceneMan:shortestDistance(self.Pos,actor.Pos,true).Magnitude if distcheck < 30 then self:GibThis() break end end end [/code] --- 5.2 Missile --- A script designed to be attched to a "rocket" emitter shot from a gun. The script searches for actors of the enemy team and rotates the emitter to the direction of the closest one. With comments: [code] -- When the object is created... function Create(self) -- Go through all actors in-game... for actor in MovableMan.Actors do -- Check if the actor has the object named "Missile Launcher" and check the distance between the missile and the actor. If so... if actor:HasObject("Missile Launcher") and SceneMan:ShortestDistance(self.Pos,actor.Pos,true).Magnitude < 50 then -- Set the team that the missile doesn't want to lock onto into a variable self.ignoreteam = actor.Team -- Stop the "for" loop. break -- End of the "if" statement. end -- End of the "for" loop. end -- End of "function Create(self)". end -- While the object is existing... function Update(self) -- Check if the variable "self.target" is a pointer to a living actor. if MovableMan:IsActor(self.target) then -- Set the scripted object's rotation pointing at the "self.target" actor. self.RotAngle = SceneMan:ShortestDistance(self.Pos,self.target.Pos,true).AbsRadAngle -- Enable the scripted object's emission (the scripted object needs to be an emitter) self:EnableEmission() -- If the variable "self.target" is NOT a pointer to a living actor, then... else -- Create a variable that keeps track of the shortest distance between the probable target and the missile so far. Let's leave it at "-1" so we know it hasn't been used yet. self.shortestdistance = -1 -- Go through all of the actors in-game. for actor in MovableMan.Actors do -- If the actor is on the enemy team... if actor.Team ~= self.ignoreteam then -- Store a distance check of the scripted object and actor into a variable. self.curdist = SceneMan:ShortestDistance(self.Pos,actor.Pos,true).Magnitude -- Make sure the distance is no greater than 500. Then check if either the "self.shortestdistance" has been unused in order to continue, or if the "self.shortestdistance" has been used and the distance is less then the value of "self.shortestdistance". if self.curdist < 500 and (self.shortestdistance == -1 or self.shortestdistance ~= -1 and self.curdist < self.shortestdistance) then -- If everything checks out okay, make this actor the "self.target" and store the distance between them for later use. self.target = actor self.shortestdistance = self.curdist -- End of the "if" statement. end -- End of the "if" statement. end -- End of the "for" loop. end -- End of the "if" statement. end -- End of "function Update(self)" end [/code] Without comments: [code] function Create(self) for actor in MovableMan.Actors do if actor:HasObject("Missile Launcher") and SceneMan:ShortestDistance(self.Pos,actor.Pos,true).Magnitude < 50 then self.ignoreteam = actor.Team break end end end function Update(self) if MovableMan:IsActor(self.target) then self.RotAngle = SceneMan:ShortestDistance(self.Pos,self.target.Pos,true).AbsRadAngle self:EnableEmission() else self.shortestdistance = -1 for actor in MovableMan.Actors do if actor.Team ~= self.ignoreteam then self.curdist = SceneMan:ShortestDistance(self.Pos,actor.Pos,true).Magnitude if self.curdist < 500 and (self.shortestdistance == -1 or self.shortestdistance ~= -1 and self.curdist < self.shortestdistance) then self.target = actor self.shortestdistance = self.curdist end end end end end [/code]