The following Guide was written by modder KanKrusha on RelicNews Forums (now defunct), however it is one of the more comprehensive guides currently available.
[HOW TO] Common Lua and SCAR errors: Identification and Prevention
Target audience: beginners wanting to start Scar editing
This little guide is born of me attempting to learn Lua programming and SCAR scripting over the past 8 months. It is a list of mistakes I have made and that I have seen other people make on this and other forums. Most of this is documented in other forums on this site but seeing as we have a few people starting out with Scar on DOW2 I thought I would pull some of this information together.
Lua and Scar
SCAR (Scripting At Relic) is the scripting language used by Relic for their games. Scar (going to drop the caps now) is used to set up the enities (buildings etc) and squads on a map. It is also used to control entity and squad behaviour through the AI programming. Scar is based on the Lua language. In order to script Scar you need to be able to understand some of the way Lua language is structured:
a well written Lua manual - http://www.lua.org/manual/5.1/manual.html#2.4.3
a learning guide - http://www.lua.org/pil/contents.html#P1
additional tutorials - http://lua-users.org/wiki/TutorialDirectory
You cannot program Lua using Microsoft Word, it adds formatting that prevents the program running. Most of us will be modding using Cope's toolbox which has an open-as-text option but other options are Notepad++ or Textpad
Lua is very sensitive to typos and errors. I check all my script by pasting it into a program called ScIte. It is a bit fussy to use but will identify syntax problems before I try the code out in game
https://www.ebswift.com/scite-text-editor-installer.html We've corrected the link to ScIte, however a modern code writing program may be just as good.
COMMON LUA ERRORS
*These errors are generally syntax errors and will cause a fatal error. Look in this section first if you are experiencing a fatal error*
Failing to comment code
The 2 dashes “–” in the above example indicate a comment in the code. Comment your code liberally! You will come back to read your code many many times and it is helpful to know what it is supposed to be doing
To make your code easily searchable to for any temporary changes made for testing you can comment your code with “qqq”. Then you can search for qqq using notepad++
I also always commented any changes in values or lines I insert with kk (eg – kk new line inserted here). I use kk because I am “KanKrusha” but also it is easily searchable
Code:
arms = 1000 -- qqq temporary test value to see if function working
You can also disable chunks of code by commenting it out with square brackets
Code:
--[[ putting 2 hyphens and 2 square brackets here comments out the following code function thisfunctiondoesnothingnow(squad) killsquad(squad) end ]] -- the last 2 square brackets ends the commenting
Prevention: Liberally use comments
Failing to indent code
This seems weird when you start out but you absolutely must indent your code for readability, especially if you are going to ask others for help. This is especially important for multiple if chunks
Code:
-**- compare these 2** function NotIndentexample() if count = 1 then if alphabet = 26 then if language = "English" then print ("25 to go") end end -- which if does this end belong to? end -- is this the end of the function? have I enough ends? function Indentexample() if count = 1 then if alphabet = 26 then if language = "English" then print ("25 to go") end end -- so easy to see which if this end belongs to! end end -- end of function
And yes, there is a missing end in the not indented example
Prevention: Get in the habit of indenting your code right from the start. Make it second nature. When you go back hunting bugs you will thank yourself.
if not If
Lua is case sensitive so adding incorrect capitals will cause the program to halt. Double check all your if statements are “if” not “If”. Likewise “and” not “And” or “AND”
Fix: go back and check all the if statements
Failing to close if chunks with end
Lua works in “chunks” of several lines of text which are closed with an “end”
You need to close each if chunk with an end as well as each function. For example
Code:
function Check_SoldierHasTwoArms(soldier) if arms = 2 then print ("yes") end -- end of if chunk end -- end of function. (I always put this comment here so I know I have closed the function properly)
Fix: go back and check each if for an end and then each function for an end (see indenting below). Document the ends that close a function
Too many or too few brackets
This is an easy mistake to make and well worth preventively counting your brackets as you write the code. Double check after each chunk. Count by adding +1 for each opening bracket “(” and subtract -1 foreach closing bracket “)”. You should end up at zero
Code:
if (Squad_IsShooting(squad) and (Squad_IsInMeleeStance(squad) or Squad_IsUnderMeleeAttack(squad))then Cmd_Retreat(squad.sgroup) end -- same code with bracket counting if (**+1**Squad_IsShooting(**+2**squad)**+1** and (**+2**Squad_IsInMeleeStance(**+3**squad)**+2** or Squad_IsUnderMeleeAttack(**+3**squad)**+2**)**+1** then -- **we did not get to zero, omg a bracket is missing** Cmd_Retreat(squad.sgroup) end
Using = instead of == when making comparisons
This is a common typo. Lua has syntax that when you are checking if a variable equals a value you use 2 equal signs.
If I want to make a variable equal something I use one equal sign
apple = “fruit”
BUT if I want to ask the question does a variable equal a value then I use 2 equal signs
if apple == “fruit” then
Fix: Go back through your code checking each if statement with a comparison uses double equal signs
Missing commas in tables
In a table each entry must be separated by a comma, leaving out a comma by mistake will result in a fatal error. Also be aware of not adding commas if you are not working in a table!
Code:
mynewtable ={ Scout, -- make sure you format tables like this so you can easily see your errors Tac -- oops a missing comma Devastator, -- it is a good idea to add a comma to the last entry so you can come back and add more entries later } mynewtable.Scout = 3 mynewtable.Tac = 5, -- oops, now I am not working within the table and this comma is an error --
Mucking it up by cutting and pasting
Several times I have fixed the typos in my code and then thought of a way to simplify it by moving chunks around. It is easy to cut brackets or halves of words and turn your functional code into a fatal scar error
Prevention/Fix: After moving any chunks double check your code carefully, preferably with Scite
COMMON SCAR PROBLEMS
*These errors generally involve mistyping a variable or function name. The code will appear to run but won't do anything. Look for these errors if your code runs but doesn't give the results you want*
Scar is documented in scar docs which were released by Relic but are no longer available from them. Fortunately some modders have hosted versions.
This is a good place to start reading and learning
You can download a version of scar docs from here
[http://www.moddb.com/games/dawn-of-w...s/dow2-toolkit](http://www.moddb.com/games/dawn-of-war-2/downloads/dow2-toolkit)
This is an online version for COH which I use a lot. NOTE many functions have been dropped for DOW2 but at least the syntax is documented
http://www.europeinruins.com/ScarDoc/scar_doc.htm
Trying to run a function using a Squad instead of SGroup
Most Scar functions run specifically on an Entity, a Squad or a SGroup
– An Entity is a single model (soldier), building, turret or other object. Generally entity commands are not used to manipulate soldiers
– A Squad is a group of enitities (soldier) that work together as a single object
– A SGroup is a group of one or more squads
– An EGroup is a group of one or more entities
Fortunately most functions are clearly named:
Squad_GetHealth won't work on a SGroup and SGroup_GetAvgHealth wont work if you try to use a squad (solution: create a SGroup from that squad first)
Other functions are not clearly named and some are confusingly named, so check the scar doc to make sure you are entering the right information.
Check them and check again, there will be multiple times you get this wrong (or you will if you are like me)
Failing to match case
Lua and scar are case sensitive. It is easy to mistype a function without the right number of capitals. Likewise for variable names
Code:
Squad_GetHealth(squad) -- this is correct squad_Gethealth(squad) -- this is a typo and will return a nil value so will seem to do nothing function Squad_NewHealthchecker(squad) return Squad_GetHealth(sQuad) -- this is a typo and will return a nil value so will seem to do nothing end
Prevention: I tend to copy and paste names of functions and variables rather than retyping them to prevent this issue
Entering the wrong number of parameters in a function
Each function requires a certain number of arguments or parameters, if you enter too many or too few the function will not work.
For example SGroup_Add requires the SGroup and the squad to be entered
Code:
SGroup_Add(sgroup1) -- this won't work SGroup_Add(sgroup1, squad2) -- this will work
Prevention/Fix: Check the scar doc for the right number of parameters for the function
Failure to initialize or call the functions
Quite commonly beginners will painstakingly correct code that is causing fatal erros, only to find that once corrected it doesn't run.
This is because Scar checks all the code as it loads it but only runs it if:
i) the function is called from another function (this is the simplest way) or
ii) the code is called from an initialization function
(note that the .ai files are lua and they will run commands during loading eg InitializeAI() in the default.ai file)
All my coding has involved getting my functions called from functions that I know are already running
Code:
function This_IsMyNewFunction(squad) -- this function will only run if called from another function print("Eldar are OP") end function ThisIsA_FunctionYThatIKnowIsRunning(squad) -- this function is already being called by Relic coding -- original code that does stuff if Squad_IsInCombat(squad) then This_IsMyNewFunction(squad) -- now this function calls my new function end end
The alternative is to call your code on initialisation using the Scar_AddInit() command. Once the simulation is loaded then Scar will run the initialisation commands (Scar_AddInit() does NOT work in .ai files)
Code:
function This_IsMyNewFunction() -- code that does stuff end end function MyOnInit3() define_globalvariable1 = 3 define_globalvariable2 = 30 Rule_AddInterval(This_IsMyNewFunction, 3) -- note that Rules cannot be called with parameters (a workaround using local functions is available) end Scar_AddInit(MyOnInit3) -- make sure you give the oninit function a unique name different from all the other oninits to avoid conflict
Related to this is forgetting to import your code. If you keep your code tidy by writing your functions in a separate file then you need to remember to add an import statement to one of the scar (or .ai) files
Prevention: Make sure you think about how your functions will be called or initialised before you start writing them
Failing to understand that entities and groups are objects
The way that relic write their code using sgroupID and squadID it is easy to fall into the trap of thinking that sgroups and squads are numbers. They are not, they are objects. For non-programmers think of them as tables. So a squad actually consists of something like this:
squadID = {number, function, value, function, value, value}
Not like this:
squadID =120458
Why is this important? It means that the following code won't work because you can't use a squad or group as a key or like a number :
Code:
function CeaseFireIfCitrus(squad) fruit_table = {"apple", "pear", "orange"} if fruit_table[squad] == "orange" then -- this won't work Squad_CeaseFire(squad) end end function FruitCounter(squad) for i=1, squad do -- this won't work either -- code that counts fruit end end **Failing to understand that the .ai and .scar sytems are separate**
The artificial intelligence for the game is split between the AI files (end in .ai) and the scar files (end in .scar). They are separates as if by a wall and do not talk to each other except through a specific function (AI_DoString)
The AI files tend to handle budgets and strategy while squad commands are housed in the scar files.
~~ SUMMARY ~~
Use the preventive measures above, you will spend much longer reading and checking code than you will writing it so these measures will save you time
If you have a fatal error - first check for a Lua-type syntax error, then check for a scar-type error
If your code seems to run but doesn't do anything - first check for a Scar-type error: a misused argument or variable (eg squad instead of sgroup) or mistyped function, then check for a Lua-type error