14.02.2012, 17:00
(
Last edited by iPLEOMAX; 15/02/2012 at 09:04 AM.
)
Enumerators
There is something about enums that many scripters aren't aware of.There are many of you using enums in your script for storing Player/Vehicle/House Data etc. (Especially user info)
A typical (or very common) example:
pawn Code:
enum
e_PlayerInfo
{
SCORE,
MONEY,
KILLS,
DEATHS
};
new pInfo[MAX_PLAYERS][e_PlayerInfo];
pawn Code:
public OnPlayerDeath(playerid, killerid, reason)
{
pInfo[playerid][DEATHS]++;
if(IsPlayerConnected(killerid) && killerid != playerid)
pInfo[killerid][KILLS]++;
return 1;
}
Now:
pawn Code:
enum
e_PlayerInfo
{
SCORE,
MONEY = 9,
KILLS = 5,
DEATHS = 56
};
new pInfo[MAX_PLAYERS][e_PlayerInfo];
printf("%i | %i | %i | %i", pInfo[0][SCORE], pInfo[0][MONEY], pInfo[0][KILLS], pInfo[0][DEATHS]);
If you think "yeah"..
Wrong, because it will give: "0 | 0 | 0 | 0", you might think that enums are the ones that store data.
When I did "MONEY = 9" in the enum, then used "pInfo[0][MONEY]" in the printf, it considered it as pInfo[0][9] not ePlayerInfo:MONEY. Which means I used "MONEY" as an index for my pInfo variable.
So, enums are NOT variables at all! They are actually "constants", they only help you in assigning a particular name to your variable index.
Ok, Let's get a bit deeper and hopefully you'll understand more..
Example:
pawn Code:
const e_CAR1 = 0;
const e_CAR2 = 1;
const e_CAR3 = 2;
new MyCars[3];
main()
{
MyCars[e_CAR1] = 520;
MyCars[e_CAR2] = 458;
MyCars[e_CAR3] = 411;
}
pawn Code:
enum
e_TEST
{
e_CAR1,
e_CAR2,
e_CAR3
};
new MyCars[e_TEST];
main()
{
MyCars[e_CAR1] = 520;
MyCars[e_CAR2] = 458;
MyCars[e_CAR3] = 411;
}
Yes, only in how you create the code.
This piece of code I showed you, tells you that enums do the same things as constants.
But there are few differences which makes us use enums rather than constants or definitions (const e_CAR1 = 0; or #define e_CAR1 0) We'll talk about the differences later.
First you should understand how enums are structured:
pawn Code:
enum TEST
{
Abc,
Def,
Ghi,
};
Def is a const of value 1 (const Def = 1; or #define Def 1)
And Ghi is a const of value 2 (const Ghi = 2; or #define Ghi 2)
The pre-compiler automatically sets the values of these constants starting from 0 to .. n
Whereas in making constants, you are the one who has to assign it. But in enum, it's automatically structured.
Example:
pawn Code:
enum TEST
{
e_ONE, //This will automatically get "0"
e_TWO, //this: "1"
e_THREE, // "2"
e_FOUR = 12, // Now, here's a difference, since you assigned "12" to it, instead of being "3", it'll become 12..
e_FIVE, //This will be 13 because it's upper enumerator had "12"
e_SIX //This will be 14. It's upper: "13"
}
Some more explanations:
pawn Code:
enum
DATA
{
INT, //This will get "0" (Remember, starting value)
STRING[10], //(This will get 1 but since it's a string, just one block isn't sufficient!)
//^ So, the correct numbers will be: 1,2,3,4,5,6,7,8,9,10! Because length of the string is 10!
INT2, //This will get the number 11, it comes after STRING[10] which had the last number of 10..
STRING2[10] //And this will start with 12 and end to 22 because it requires 10 spaces.
};
pawn Code:
printf("%i", _:DATA);
Because the size of the whole enum is 22.
INT, STRING, INT2, STRING2
1+ 10+ 1+ 10 = 22
Now, you might think why I used "1" to show INT and not "0"?
The thing is, I'm showing you "HOW MANY" blocks are being used by INT, not "WHICH ONE".
If it was "which one", then it would be "0", block 0 is occupied by INT.
For a block of size 22, these are the indexes "0..1..2 till 19..20..21" < You have 22 numbers here.
Using
pawn Code:
printf("%i", _:STRING);
because the first block was occupied by INT which is "0"
And therefore, STRING started from block "1"
If I show the usage of blocks by each enumerator, it will look like:
INT : block 0
STRING : blocks 1,2,3,4,5,6,7,8,9,10
INT2 : block 11
STRING2 : blocks 12,13,14,15,16,17,18,19,20,21
Using
pawn Code:
new Array[DATA];
printf("%i", sizeof Array);
Finally, we see that Array is actually:
Array[INT + STRING + INT2 + STRING2];
(will not compile, just visualize it)
Therefore, whenever you use enums, you use the actual variable & enumerators as indexes.
A diagrammatic example:
Another Example:
pawn Code:
enum
TEST
{
SomeInteger = 124,
SomeString[12],
Float:SomeFloat
};
public OnFilterScriptInit()
{
new var_TEST[TEST];
var_TEST[SomeInteger] = 1337;
printf("1) Stored in var: %i, Constant: %i", var_TEST[SomeInteger], _:SomeInteger); //1
format(var_TEST[SomeString], 12, "Hey!");
printf("2) Stored in var: %s, Constant: %i", var_TEST[SomeString], _:SomeString); //2
var_TEST[SomeFloat] = 2054.124;
printf("3) Stored in var: %f, Constant: %i", var_TEST[SomeFloat], _:SomeFloat); //3
return true;
}
1) "Stored in var: 1337, Constant: 124"
As you've seen, I assigned var_TEST[SomeInteger] with 1337.
And in the enumerations, SomeInteger has a constant value of 124.
2) "Stored in var: Hey!, Constant: 125"
Here, I assigned var_TEST[SomeString] with "Hey!".
And in the enumerations, SomeString has a size of 12, but it printed 125
because, 125 is the starting block of the string, it ends to 125 + 12.
3) "Stored in var: 2054.124023, Constant: 137"
Floating point printed out normally, but SomeFloat printed out to be "137"!
It's supposed to be 126 right? Because it was created after SomeString which had the value of 125..
But, since SomeString[12] is an Array (String), it ate up 12 more spaces. Which made SomeFloat to get the value of 137
(Note that 125 + 12 = 137)
Some more important information:
Enums can also be used as tags:
pawn Code:
enum E_EG
{
E_FIRST = 4,
E_SECOND = 2
}
Now, I can do:
pawn Code:
new E_EG:SomeVar;
pawn Code:
new E_EG:MyVariable = E_FIRST; // No warnings despite using "E_FIRST".
//Because E_FIRST is already a part of the E_EG enumerator
//Since we tagged MyVariable with E_EG, it's all fine with E_FIRST.
pawn Code:
new data[E_EG];
data[E_FIRST] = 7; // Compiler error - index out of bounds
//Because, the value of E_EG is 3 and E_FIRST is 4 (the index doesn't exist)
pawn Code:
enum //<< We didn't give it a name.
{
E_TEST[10] = 32,
E_VAR
};
main()
{
new data[E_TEST]; //E_TEST = 32 not 10.
//Note that we also didn't use any tag _:E_TEST
}
pawn Code:
enum
E_STRONG //< Since the name starts with a capital letter, the tag is considered "Strong"
{
E_VAR = 64
};
main()
{
new Test = E_STRONG:E_VAR;
//Will give you a warning: "tag mismatch" because "Test" doesn't have E_STRONG tag
#pragma unused Test
}
pawn Code:
enum
e_WEAK //< And here it starts with small letter, so the enum creates a weak tag.
{
E_VAR = 64
};
main()
{
new Test = e_WEAK:E_VAR;
//No warning...
#pragma unused Test
}
* Thanks to Y_Less for his explanations.