What no one is telling DLively, but probably should, is that the flags are just a bitfield.

Here, let me play Erklärbär once more (explaining bear... But the joke is lost in translation, so we won't talk about that).

A variable, no matter what type (aka, not to be confused with var), occupies a certain number of bits in memory. An int and a var for example occupy 32 bits, or 4 byte, whereas a double for example occupies 8 bytes. This in and off itself isn't that surprising, information has to be stored somewhere and computer use bits and bytes for that, news at 11.

What's more interesting is that you can change the bits. One way, you are already aware of, simply assigning values to it. Like the following:

Code:
int foo = 1234;
foo = 4321;



There is another way though, and that is manipulating the bits directly. You may or may not have seen the bitwise operators already, there is bitwise OR "|" and bitwise AND "&", not to be confused with their boolean counterparts "||" and "&&", there are also two more operators which I will come to in a second.

Bitwise OR takes two bit patterns and sets the output bit pattern in such a way that if either or both bits are 1, the result is 1, otherwise it's 0. Or, put differently and as a picture:
Code:
0100
1101

Both ORed together is
1101



Bitwise AND sets the resulting bit to 1 if both bits are set, example:
Code:
0100
1101

Both AND together is
0100



Now, let's look at how decimal values are actually represented in an integer. Let's stick with 4 bits, because I'm lazy and hate typing, there is no 4 bit integer in C, but screw it, we now have one!
All bits to 0 is 0 in decimal. Then, for every +1, the least significant bit is increased by one (least significant is the one on the rightmost place on x86), because a bit can either hold 0 or 1, adding 1 to a bit that is already 1 causes it to overflow to the left, and become 0. Let's count!

Code:
0000 // -> 0
0001 // -> 1
0010 // -> 2 (Note how the least significant bit spilled over to the left)
0011 // -> 3
0100 // -> 4
0101 // -> 5
0111 // -> 6
1000 // -> 7
1001 // -> 8
1010 // -> 9
1011 // -> 10
1100 // -> 11
1101 // -> 12
1110 // -> 13
1111 // -> 14
0000 // -> 0



Notice the last entry? This is why variables wrap around, they simply overflow and go back to 0.

Of course, a 4 bit integer is now fun because it has only 15 possible states, but adding just 28 more bits to make it a full blown 4byte integer, and suddenly it has 4 billion something possible states!

Okay, now we have almost everything in place to get to entity flags. Lets cover bit shifts real quick! There are two operators to shift bits to the left and to the right, they are << and >> respectively. 1 << 2 would shift the number 1 (0001) by 2 places to the left (01000).

And now, to the flags!
The flags are to be treated as a bitfield. They are a 4 byte integer, but you shouldn't treat it as such but as a bitfield instead. Ie, don't do normal integer mathematic on it(*).

The set and reset "functions" are actually just macros over the & and | bitwise operators, and they look like this:

Code:
#define set(entity, flag) entity->flags |= flag
#define reset(entity, flag) entity->flags &= ~flag



There is nothing fancy, there is no function executed or anything. It just changes bits in the bitfield. Bitfields are perfect for when you have a lot of true/false on/off states to represent, because then you don't waste memory on them. A 32 bit integer, can hold... 32 on/off states, and you toggle them individually via bitwise operators.

What the engine does is the following, whenever it executes code dependend on one of the flags, it checks if the flag is set or not using the AND operator, and then decides how to act accordingly. Pseudo code time!

Code:
void c_move(ENTITY *entity)
{
   if(entiy->flags & PASSABLE)
      return; // Screw it, we are done!

   if(entity->flags & POLYGON)
   {
      // Polygon correct check here
   }
   else
   {
     // Cheap check here
   }
}



Okay, so, last bit of wrap up!
The reset macro, you will notice the tilde in there! That's the third bitwise operator, it's bitwise NOT. It inverts the bit field. Example:
Code:
0100
1011



The flags themselves are also just macros, they look like this, except that I pulled the actual shift values out of my ass:
Code:
#define PASSABLE (1 << 0)
#define POLYGON (1 << 2)



And now for the grand finale and why things like if(flag & XYZ) actually works. Let's visualize you setting the and resetting the PASSABLE and POLYGON flags! I'll use my trusty 4bit integer because it has enough precision:

Code:
// Assume flags has the PASSABLE flag set
flags = 0001

// Now you set the POLYGON flag using flags |= POLYGON
flags = 0001 | 0100
flags = 0101

// Now you reset the PASSABLE flag
inverted = ~0001
inverted = 1110

flags = 0101 & 1110
flags = 0100



See how it works? Now, let's check if the passable flag is set!

Code:
result = 0100 & 0001
result = 0000



0 evaluates to false, so if(flags & PASSABLE) is false. But lets check the POLYGON flag!
Code:
result = 0100 & 0100
result = 0100



Everything greater 0 evaluates to true, so if(flags & POLYGON) is true!

Tada, bitwise operators and bitfields ladies and gentlemen. Useful as fuck!

Now, extra round! There is one last bitwise operator, and that is XOR, or "^". It stands for exclusive OR, and is opposed to OR which is an inclusive OR. Two patterns XORed with each other will result in a bit to be 1 if either of the bits is 1, otherwise its 0. Example:

Code:
0101 ^
1011

1110



Oh boy. Lets toggle some bits with it!
Code:
flags = PASSABLE | POLYGON
flags = 0101

flags ^= PASSABLE
flags = 0101 ^ 0001
flags = 0100

flags ^= PASSABLE
flags = 0100 ^ 0001
flags = 0101



The logical conclusion I'm trying to get at for so long already is, that it doesn't matter in which order you use set() and reset(). You just change some bits around, and the order doesn't matter, there is no engine function executed or anything which alters the result, the flags are evaluated on demand by the engine.

Now, you can do much more stuff with the operators, for example read out only certain bit ranges of an integer. But this is for another day.


(*) Technically, because single bits always represent a power of two, you can use the + and - arithmetic operators. For example, the following works as well:
Code:
flags = PASSABLE + POLYGON



However, it's not done because then it stops being clear wether or not you are working with a bitfield or a normal variable.


Shitlord by trade and passion. Graphics programmer at Laminar Research.
I write blog posts at feresignum.com