Graal Forums  

Go Back   Graal Forums > Development Forums > NPC Scripting
FAQ Members List Calendar Today's Posts

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old 11-15-2006, 09:25 AM
jake13jake jake13jake is offline
Former Classic Staff
jake13jake's Avatar
Join Date: Dec 2002
Location: Northwest Vermont
Posts: 1,452
jake13jake will become famous soon enough
Bitflag Tutorial

Why use a bitflag?
  • They require less memory.
  • Bitwise operations take much less execution time than other operations.
  • With the small amount of space they require, you can greatly reduce server traffic.

What is a bitflag? A bitflag is an integer that represents multiple cases of true and false.

In order to understand this, you might take a look at an integer in binary. First of all, how do you read a binary value?

0000 is 0
0001 is 1
0010 is 2
0011 is 2+1
0100 is 4
0101 is 4+1
0111 is 4+2+1

Do you see a pattern of the powers of two emerging? If you don't, I suggest you go get a catscan.

Each value in a binary number on computers is a bit. The bit is either on (1) or off (0).

Amazingly, we have operators to manipulate numbers at the bit level.
& (bitwise and), &= (bitwise and assignment)
| (bitwise or), |= (bitwise or assignment)
xor (bitwise exclusive or), unfortunately gscript lacks xor assignment
<< (left bitshift), <<= (left bitshift assignment)
>> (signed right bitshift), >>= (signed right bitshift assignment)
unfortunately, gscript lacks unsigned right bitshift/assignment.

What can we do with these operators

Let's look at different cases (pretending we're working in 8 bits):

~4
00000100 (4 in binary)
11111011 (~4)
The inversion operator makes all the 0s into 1s and all the 1s into 0s.

4 & 5
00000100 (4 in binary)
00000101 (5 in binary)
00000100 (4 & 5)
If the bits are both on, then the bit in the outcome is on.

4 | 5
00000100
00000101
00000101 (4 | 5)
If either of the bits are on, then the bit in the outcome is on.

4 xor 5
00000100
00000101
00000001 (4 xor 5)
If the bit is one or the other but not both, the bit is on in the outcome.

4 << 1
00000100
00001000 (4 << 1)
What does this do? It shifts all the bits left one and fills in with 0. This is also identical to multiplying by a power of 2, the right operand being the power.

4 >> 1
00000100
00000010 (4 >> 1)
This shifts all the bits right one, and fills in the last bit with a copy of the previous last bit (which in this case would be 0). Other than the last bit, this would be identical to integer division by a power of 2.

This is because the last bit is the SIGN bit.
11111111 would be -1.
11111110 would be -2, and so on.
If you right shifted either of these examples by more than one, the outcome would be -1. If you wanted to fill in the last bit with a 0, you'd need to use an unsigned bit, which gscript lacks.

PHP Code:
//Okay, let's say you want to make constants for a bit flag.
INFECTED = (<< 0); //player has a virus (1)
IMMUNE = (<< 1); //player is immune to the virus (2)
SICK = (<< 2); //player is sick due to the virus (4)
FATAL = (<< 3); //the virus is fatal to the player (8)
//and so on...

//This makes it so that each constant represents a particular bit. 
//You could also make a constant represent all of the bits. 
ALLBITS = -1;

//So now that we have our constants sorted out, we will initialize a bitflag.
player.clientr.flag 0;

//how do we put different values in the flag?
player.clientr.flag |= INFECTED//(sets a bit, or leaves it set)
player.clientr.flag &= ~INFECTED//(unsets a bit or leaves it unset)
player.clientr.flag player.clientr.flag xor INFECTED//(using the xor operator will toggle the bit)

//The player should be infected. 
//How do we check to see if the player is infected?
if (player.clientr.flag INFECTED == INFECTED)
  
doInfectionStuff();

//You can also check for multiple bits at once.
temp.mask INFECTED SICK;
if (
player.clientr.flag temp.mask == temp.mask)
  
doMaskStuff();

//What if you just need one of the bits your checking in the mask to be true?
if (player.clientr.flag temp.maks != 0)
  
doOtherStuff();

//What if you want to know what the first set or first unset bit are?
this.firstset & (~1); // can also be written c & -c;
this.firstunset = ~& (1); 
That pretty much covers the whole concept. Also, keep in mind that you have 32 whole bits you can use for one flag in gscript, not just 4 or 8.

Here are some other neat tricks that you should only use for integers.

var * 2^n;
is equivalent to
var << n;

var / 2^n;
is equivalent to
var >> n; (integer division, 3>>1 returns 1, not 1.5)


var % (2^n);
is equivalent to
var & (2^n - 1);

-var is equivalent to (~var + 1)... though this isn't so useful.

var = var xor var;
is equivalent to and for some computers even faster than
var = 0;

Here's a useful one though. Swapping two numbers without a temp value.
PHP Code:
if (var1 != var2) {
  
var1 var1 xor var2;
  
var2 var2 xor var1;
  
var1 var1 xor var2;

The body without the if branch would work for all values, except for when you're trying to swap a number with itself. This would mean, in essence that var1 is the same variable as var2. The example of this that is most often encountered is by swapping arr[i] and arr[j], when i==j.

I hope you join me in my protest for an unsigned bitshift operator (>>>) and a xor assignment operator, and that you can all use bitflags after reading this.
Reply With Quote
  #2  
Old 11-15-2006, 11:41 AM
Rick Rick is offline
PipBoy Extraordinaire!
Rick's Avatar
Join Date: Jul 2004
Location: Long Beach, California.
Posts: 831
Rick is on a distinguished road
Quote:
Originally Posted by jake13jake View Post
0000 is 0
0001 is 1
0010 is 2
0011 is 2+1
0100 is 4
0101 is 4+1
0111 is 4+2+1
Fixed.
NPC Code:
0000 is 0
0001 is 1
0010 is 2
0011 is 2 | 1
0100 is 4
0101 is 4 | 1
0111 is 4 | 2 | 1

Reply With Quote
  #3  
Old 11-15-2006, 06:11 PM
jake13jake jake13jake is offline
Former Classic Staff
jake13jake's Avatar
Join Date: Dec 2002
Location: Northwest Vermont
Posts: 1,452
jake13jake will become famous soon enough
Quote:
Originally Posted by Rick View Post
Fixed.
NPC Code:
0000 is 0
0001 is 1
0010 is 2
0011 is 2 | 1
0100 is 4
0101 is 4 | 1
0111 is 4 | 2 | 1

They evaluate to the same result, though bitwise or is probably faster. The purpose of that section was just to demonstrate how integers are represented in bits.
Reply With Quote
  #4  
Old 11-15-2006, 11:47 PM
Chompy Chompy is offline
¯\(º_o)/¯
Chompy's Avatar
Join Date: Sep 2006
Location: Norway
Posts: 2,815
Chompy is just really niceChompy is just really niceChompy is just really nice
Send a message via MSN to Chompy
Nice Tutorial!
__________________
Reply With Quote
  #5  
Old 11-15-2006, 11:54 PM
Skyld Skyld is offline
Script-fu
Skyld's Avatar
Join Date: Jan 2002
Location: United Kingdom
Posts: 3,914
Skyld has much to be proud ofSkyld has much to be proud ofSkyld has much to be proud ofSkyld has much to be proud ofSkyld has much to be proud ofSkyld has much to be proud of
Send a message via AIM to Skyld
Indeed a nice tutorial, should perhaps be put on the wiki if not done so already?
__________________
Skyld
Reply With Quote
  #6  
Old 11-16-2006, 02:12 AM
jake13jake jake13jake is offline
Former Classic Staff
jake13jake's Avatar
Join Date: Dec 2002
Location: Northwest Vermont
Posts: 1,452
jake13jake will become famous soon enough
Of course I don't think saying (4 | 1) against (4 + 1) would really matter anyways because I do believe Graal compiles using constant folding. You can put it on the Wiki if you want. I don't even think Wikipedia has a decent bitflag page.
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 02:09 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Copyright (C) 1998-2019 Toonslab All Rights Reserved.