Page 1 of 1

Plugins Guide. Part 1: Writing the Code

PostPosted: July 5th, 2009, 9:48 am
by BroodKiller
A basic guide to writing SC plugins (by BroodKiller)

Part 1. Writing the Code

So, you're here wondering what all this fuzz about the plugins is about, right? You are probably looking for the answers to either or both of the following questions: what can I do with plugins? How hard it is to learn to make my own plugins?

The answer for the first question is: A LOT. And I mean it, the possibilities are really vast, once you realize them. Want to recreate SC2 abilities like Explosive Charges, Black Hole or Planet Cracker? No problem. Want to create new special effects? Auras, infections, resource stealing? Sure you can. Of course, it requiries a bit of work to accomplish, but no restrictions stop you from doing any of it, and much much more!
As for the second question, which is probably the main issue: truth be told, learning to make plugins might be discouraging at first, mostly due to the whole 'coding'-part of it. Plugins are effectively just small custom programs that are executed at the right moments when StarCraft is running, so "learn to make plugins" means pretty much "learn to write programs". Don't be afraid though. It is with this that I intend to help you out. It is not as tough an adventure as it seems at a first glance. If you concentrate only on the most relevant parts, you don't need to become a C++ expert in order to create fantastic effects via plugins. Once we get past this point, things become pretty much a walk in the park :)

Please, take this tutorial as a "Writing C++ code for SC modders" type of book. It is by no means a complete nor even proper tutorial to C++, it only covers some of its aspects that are relevant to pluginmaking, which means that it also has to hide certain things from you. Sometimes I will skip certain information on purpose, because it will not be relevant at the moment, so just try to take things as they are. This small tutorial can serve as a very basic introduction to writing your own, non-plugin C++ code later on, should you wish to educate yourself more. So, without further ado, let's get it on. This first part will deal with the necessary basic of writing C++ code.

Since, as a matter of fact, plugins are all about writing custom C++ code, there are a few basic concepts that you have to know and understand. They cover the basic logics of the C++ program code and how it works. The C++ code is mainly composed of commands and loops. Commands are, duh, commands to be executed by the computer. They can be anything: assigning numerical values to variables, mathematical operations, sorting, anything. Loops, on the other hand, control HOW the commands are executed. They let you mark segments of code to be run only under specific conditions or run certain commands repeatedly a specific number of times. There is a number of different loop types, and virtually anything that is not a loop, is a commmand. Commands and loops are grouped together in functions. Functions are individually named, separate blocks of code that can be called to execute at any point in the code. More on the functions in the 2nd part of the guide.

The 2 most important loops that are useful in writing plugin code are the IF and the FOR loop. The IF loop lets you specify a particular condition (or a set of conditions) that must be fulfilled so that the code inside the loop can be executed. It looks like this:
  Code:
   if (unit->energy < 50) {
      unit->energy = unit->energy + 10;
   }

This loop will raise the unit's energy level by 10 IF AND ONLY IF the unit's energy is less than 50. Pretty straighforward, isn't it? If this condition is not met, nothing will happen. However, if we actually want something to happen in this case, the IF loop can be extended with a special ELSE clause. If the condition specified within the IF statement is not met, the commands inside the ELSE clause is run. For example:
  Code:
   if (unit->energy < 50) {
      unit->energy = unit->energy + 10;
   }
   else {
      unit->energy = unit->energy - 1;
   }

This code means that if a unit's energy is less than 50 it will be raised by 10, but if it is not - 1 point will be taken from it. If you want to create multiple different specific cases, there is no problem in combining several IF and ELSE statements, for example:
  Code:
   if (unit->energy < 50) {
      unit->energy = unit->energy + 10;
   }
   else if (unit->energy < 100) {
      unit->energy = unit->energy - 1;
   }
   else {
      unit->energy = unit->energy - 2;
   }

The code above will increase the unit's energy level by 10 if it is below 50, diminish it by 1 if it is below 100, or diminish it by 2 if it is of any other value.

The second most important loop is the FOR loop, which allows you to repeat some commands a certain amount of times. It has a particular structure:
  Code:
   for (int i=0; i<50; i++) {
      unit->energy = 50 + i;
   }

The FOR loop specifies 3 elements separated by the semi-colon (";"): a counter initializer ("int i=0"), a condition ("i<50"), and a counter increment("i++"). The counter is the handy value (variable) that we will use to count how many cycles we have already done. Usually, it is initialized to 0, which means that we will start counting from 0. The condition is a checkpoint that must be passed every cycle or else the code inside the FOR loop will not be run and the loop will exit. In the above case, the condition is a check if the value of our counter is less than 50. Finally, the increment tells us by how much do we increase our counter after each cycle. Normally we just increase it by 1, which is exactly what the "i++" formula does. We can use any values in the increment, however.

So, what exactly will the above code do? It will run 50 times and in each cycle it will add to the unit's energy the number of the current cycle. So, in the first cycle (counter = 0, since we initalized it to 0), it will add 0, in the second (counter = 1) it will add 1, etc. etc., until it eventually will reach 49. 49 is still less than 50, so the unit's energy will be raised by 49. In the next cycle though, our counter will equal 50, so will no longer satisfy our condition, which requires the counter to be less than this number, and our loop will end.

In general, the FOR loop is most often used to iterate through a series of elements, for example in search of one particular element in long list. In SC plugins, you will very often see the following code:

  Code:
UNIT* unit;
for (int i=0; i<1700; i++) {
   unit = &unitTable[i];
   ...something else...
}

What it effectively does, is that it cycles one-by-one through 1700 elements of the unitTable (which contains the units present in the game at a given moment) in search of a particular unit. It should not be hard to grasp, once you understand how the FOR loop works :)


Here are some rules necessary for proper code writing and formatting:

1) Each command has to end with a semi-colon, the ';'. For example the following code will raise a unit's energy by 50 points.
  Code:
unit->energy = unit->energy + 50; <---this will work
    unit->energy = unit->energy + 50  <-- this will cause an error


2) Each loop has a condition (or multiple conditions) that is specified within round brackets. If this condition is true, the loop will execute. If it is not, it will exit.
  Code:
if (unit->energy < 50) <---this will work
   if (unit->energy < 50  <--- this will cause an error


3) You can include multiple conditions in a loop, but they must form a logical whole. To this end, you use two operands: && and ||. The first one is the AND operand, and requires what is before and after it to be fulfilled at the same time. For example:

  Code:
if (unit->energy < 50 && unit->energy > 25) {
   ...do something...
}

This loop will only execute if the unit's energy is less than 50 AND at the same time more than 25.
The second operand is the OR operand. It is less strict and requires only 1 of its surrounding conditions to be fulfilled. For example:
  Code:
if (unit->energy < 50 || unit->energy > 125) {
   ...do something...
}

This loop will execute either if the unit's energy is less than 50 or more than 125. An important issue with the OR operand is that the conditions are evaluated IN THE ORDER they are written, so if the first condition is already fulfilled, the second one is not. So, the following code:
  Code:
if (unit->unitId == marine || unit->unitId == firebat) {
   ...do something...
}

will execute if our unit is of the Terran infantry, but it will not tell us which type of unit it is.


4) Each loop needs to be contained within brace brackets, the '{' and '}'. The first one marks the beginning of the loop code, and the second one the ending. It is the code that falls between these 2 special characters that will be executed.
  Code:
if (unit->energy == 50) {
      unit->energy = unit->energy+50;
   }                      <--- this is correct
   
   if (unit->energy == 50)
      unit->energy = unit->energy+50;
   }                            <-- this will cause error


5) All that is created inside a loop, stays in the loop. If you create something new during the execution of a loop and don't save it somewhere, it will not be available outside of the loop.
  Code:
if (unit->energy < 50) {
           UNIT* another_unit;
             another_unit = &unitTable[100];
    }
   another_unit->energy = another_unit->energy - 50; <-- trying to use "unit" will NOT work, because it was created inside the IF loop.


If you follow these few rules, you should avoid most compilation errors coming from non-compliance to the C++ language standards ;)

Another important element of the code are the operators. Operators let you compare and manipulate the values that you are working with, so they constitute a fundamental part of the code. Here's a rundown of the most important operators:

a = b - this is the assignment operator. It assigns what is on its right side to what is on its left side.
  Code:
int radius = 100;

This code assigns the value of 100 to an integer variable named 'radius'.

a == b - this operator performs the equality comparison. It is of utter importance not to confuse it with the previous one, since the compiler will often not treat using one for another as an error. It returns true (allowed the code following it to work) if both sides of it are equal.
  Code:
if (unit->unitId == 1) {
   unit->mainOrderId = Die;
}

This code compares the units ID with 1. If the unit's ID is 1, which means that it is a ghost, we will kill it. If it's ID is not 1, nothing will happen.

a != b - this is the inverse of the above. It returns true only if both sides of it have different values.
  Code:
if (unit->unitId != 1) {
   unit->mainOrderId = Die;
}

This code will kill all units whose ID IS NOT equal to 1, which means only the ghosts will stay alive.

a < b - this is the 'strictly smaller than' comparison operator. It returns true if the value on the left is smaller than the value on the right.
  Code:
if (unit->unitId < 3) {
   unit->mainOrderId = Die;
}

This code will kill any unit whose ID is less than 3, which means all marines, ghosts and vultures.

a > b - this is the 'strictly larger than' comparison operator. It returns true if the value on the left is larger than the value on the right.
  Code:
if (unit->unitId > 2) {
   unit->mainOrderId = Die;
}

This code will kill any unit whose ID is larger than 2, which means only marines, ghosts and vultures will remain.

a >= b - this is the 'larger or equal' comparison operator. Self-explanatory.
a <= b - this is the 'smaller or equal' comparison operator. Self-explanatory.

There are also some mathematical operators that are often employed in conjuction with the ones presented above. They are pretty straighforward, but let's take a quick look at them:

a + b - adds a to b.
a - b - subtracts b from a.
a*b - multiplies a times b.
a/b - divides a by b. (if b is zero, an error will occur)
a^b - raises a to the b-th power.

It is very important that you remember that these operators simply calculate something, but they do not store the result. You have to do this yourself, using the assignment operator.
  Code:
result = a + b;


There are however some operators that do not require you to store the results manually:
a++ - increases a by 1.
a-- - decreases a by 1.
a += b - add b to a, and store the result in a.
a -= b - subtract b from a, and store the result in a.

This is the first part of the doc that I am working on. I view it as a sort of 'theoretical' supplement to the plugin examples that I posted earlier. It basically just puts into words'n'rules what I try to show in the examples, but maybe not stress enough. Please share any ideas, comments or any feedback that comes to your mind regarding this guide-wannabe. Should I maybe reuse the code from the specific examples? Elaborate more/less on something?

-Uncle Broody

Re: Plugins Guide. Part I: Writing the Code

PostPosted: July 6th, 2009, 11:22 pm
by Hydrolisk
In step five, you have typed "another_unit = &unitTable[100];". Is this command arbitrary? What I mean is, this line seems rather impractical. Could you elaborate? At the moment, it appears that all it would do is affect whatever unit is taking up space 99.

I think differentiating "=" and "==" would be useful. Also, comparison symbols would be useful too. You might also want to carry a warning to differentiate ">" and "<" with ">>" and "<<", respectively. I.e. "<" creates a less than comparison, whereas "<<" is C++'s insertion operator. Likewise with "=" and "==", the first sets variable values and the second compares equivalence.
Bottom line is, review the operators.

(What is ">>'s" name? I found "overloaded operator of extraction", but is it shortened to anything normally?)

Then again, one could find some C++ tutorials over the Internet.

EDIT:
I forgot to add something -- you should mention where one's code should go. It was discouraging to not know where to put my code in, and how to run it. In fact, I'm still quite confused.

Re: Plugins Guide. Part I: Writing the Code

PostPosted: July 7th, 2009, 5:14 am
by BroodKiller
That bit of code is truly completely arbitrary. It is there just to show that you cannot break the if loop's scope, that's all. I thought about reviewing the operators, but I figured it might be a little too technical, and also because they are pretty much straighforward. I might add it though, on a second thought.
The ">>" and "<<" are also bitshift operators, if that's what you're asking for. There is no other use for them regarding SC plugins, since extraction/insertion is not a relevant topic to my mind.
As for where the code should go - this will go to part3 of the guide: Compiling and Running. This one is solely dedicated to the rules of writing the code, regardless of where it will go.

Also, this is only a first draft of the guide. I appreciate any feedback regarding it, because I sometimes skip things that appear obvious to me, but must not be to people new to plugins.

Re: Plugins Guide. Part I: Writing the Code

PostPosted: July 7th, 2009, 10:25 am
by AofST
I use bitshifts instead of multiplying and dividing by 256 -- it makes a lot more sense when I look at it that way.

Re: Plugins Guide. Part I: Writing the Code

PostPosted: July 8th, 2009, 1:24 am
by BroodKiller
It is quite probably more intuitive this way, but to my mind it somehow obscures the real type of this data, which we often want to exploit. That's why I stick to straight numbers and math.

Re: Plugins Guide. Part I: Writing the Code

PostPosted: July 8th, 2009, 10:44 am
by TassadarZeratul
I'm going to add this to the wiki for you.

Re: Plugins Guide. Part I: Writing the Code

PostPosted: July 8th, 2009, 12:16 pm
by BroodKiller
I don't know if it really belongs to the wiki, TZ, but that's ok with me. Just please don't do it until the doc is finished, ok? (which means until I make the necessary amendments and clarifications, not too far from here)

Re: Plugins Guide. Part I: Writing the Code

PostPosted: July 11th, 2009, 5:19 am
by BroodKiller
Ok, I extended the document with the description of operators, per Hydro's advice. Learn and enjoy! :)

Re: Plugins Guide. Part I: Writing the Code

PostPosted: July 12th, 2009, 1:41 am
by BroodKiller
Also added a few words about comments.

Re: Plugins Guide. Part I: Writing the Code

PostPosted: July 15th, 2009, 3:55 am
by BroodKiller
Slightly edited and included a few words about functions. I am not sure as to where to actually put it, since it is a general concept, so I spread it between part 1 and part 2. Heck, we'll see.