scar_coding
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | |||
scar_coding [2025/01/10 11:27] – removed - external edit (Unknown date) 127.0.0.1 | scar_coding [2025/01/10 11:27] (current) – old revision restored (2024/01/21 14:49) admin | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ===== 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:// | ||
+ | |||
+ | a learning guide - http:// | ||
+ | |||
+ | additional tutorials - http:// | ||
+ | |||
+ | 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:// | ||
+ | |||
+ | **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 " | ||
+ | |||
+ | To make your code easily searchable to for any temporary changes made for testing you can comment your code with " | ||
+ | |||
+ | 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 " | ||
+ | |||
+ | 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, | ||
+ | |||
+ | Code: | ||
+ | < | ||
+ | -**- compare these 2** | ||
+ | |||
+ | function NotIndentexample() | ||
+ | |||
+ | if count = 1 then | ||
+ | |||
+ | if alphabet = 26 then | ||
+ | |||
+ | if language = " | ||
+ | |||
+ | 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 = " | ||
+ | |||
+ | 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 " | ||
+ | |||
+ | Fix: go back and check all the if statements | ||
+ | |||
+ | **Failing to close if chunks with end** | ||
+ | |||
+ | Lua works in " | ||
+ | |||
+ | 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 (" | ||
+ | |||
+ | 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 " | ||
+ | |||
+ | 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 = " | ||
+ | |||
+ | BUT if I want to ask the question does a variable equal a value then I use 2 equal signs | ||
+ | |||
+ | if apple == " | ||
+ | |||
+ | 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/ | ||
+ | |||
+ | **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' | ||
+ | |||
+ | 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:// | ||
+ | |||
+ | You can download a version of scar docs from here | ||
+ | |||
+ | [http:// | ||
+ | |||
+ | 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:// | ||
+ | |||
+ | **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, | ||
+ | </ | ||
+ | Prevention/ | ||
+ | |||
+ | **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' | ||
+ | |||
+ | 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(" | ||
+ | |||
+ | 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, | ||
+ | |||
+ | 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 = {" | ||
+ | |||
+ | if fruit_table[squad] == " | ||
+ | |||
+ | 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' | ||
+ | |||
+ | ========================================================================================================== | ||
+ | |||
+ | Reference: https:// |