User Tools

Site Tools


scar_coding
This version (2024/01/21 14:49) is a draft.
Approvals: 0/1

Table of Contents

SCAR Coding

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

http://scardocs.mooo.com/

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

scar_coding.txt · Last modified: 2024/01/21 14:49 by rap6tor