AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Code Snippets/Tutorials (https://forums.alliedmods.net/forumdisplay.php?f=83)
-   -   [TUT] Enumerations (enum) (https://forums.alliedmods.net/showthread.php?t=140103)

Exolent[jNr] 10-08-2010 22:22

[TUT] Enumerations (enum)
 
Introduction:
Enumerations are basically data structures.
They allow you to:
  • create a block of data and set different values into it.
  • create your own constants with automatic incrementing.
  • create your own tags for variables.


Basic Syntax:
The basic syntax for enumerations is as follows:
Code:

enum [[_:]TagName] [(IncrementType)]
{
    [TagForConstant:]Constant1 [= Value1],
    [TagForConstant:]Constant2 [= Value2],
    ...
    [TagForConstant:]ConstantN [= ValueN]
}

Let's analyze each piece of the syntax:
  • First, the data encapsulated in square brackets [] are optional for syntax.
  • [_:]TagName
    This is the name of the tag that you would be creating.
    The tag name has a value that is the size of the enumeration, which is the last constant value + 1.
    If you put the optional _: before the tag name, it means that it is no longer a tag.
  • (IncrementType)
    This is the method used to give each constant a value in the enumeration.
    The syntax for this is: operator= value
    The default for this is (+= 1) so that each constant is 1 more than the constant before it.
  • [TagForConstant:]Constant1 [= Value1]
    This is the name of the constant that is being created and also optionally giving it a value.
    The first constant is 0 if it is not given a value.
    Remember, the last constant being listed does not have a comma after it!


Creating Tags:
Creating your own tags is easy.
Here is an example of the bool tag:
Code:

enum bool
{
    false,
    true
}

It creates the bool tag, and creates 2 constants.
false is equal to bool:0 because the first constant starts at 0.
true is equal to bool:1 because the default increment is the constant before it + 1.
bool is also a constant that equals bool:2, because true is the last constant and is bool:1.

Creating tags for handles is done with an enumeration to create the tag and a constant defined for a handle.
Example:
Code:

enum Array
{
    Invalid_Array = 0
}

This creates the Array tag for cellarrays and also a constant Invalid_Array that is equal to an invalid array handle.


Using Tags on Variables:
Using tags is simple. If you've worked with bools or Floats in AMXX before, then you have used tags before.
You can create variables that are tagged with a specific tag:
Code:

new myInteger = 1
new bool:myBoolean = true
new Float:myFloat = 1.0

Remember that variables that use tags that have defined constants are not limited to those constants.
Example:
Code:

new bool:myBoolean = bool:2
The problem with doing so is that true and false are only 1 and 0 respectively, so if you checked that variable to true, it would say it is not equal to true.


Constants:
Enumerations can be useful to create a list of constants without having to define each one.
Example:
Code:

#define CONSTANT1 0
#define CONSTANT2 1
#define CONSTANT3 2
#define CONSTANT_SIZE 3

This could be annoying to try to add/edit/delete constants because you may have to edit more than one line.
Here is how an enumeration would look for this:
Code:

enum _:CONSTANT_SIZE
{
    CONSTANT1,
    CONSTANT2,
    CONSTANT3
}

You can do something like this to create a list of constants that represent bits:
Code:

enum (<<= 1) // each value is the value before it shifted left once
{
    BIT1 = 1, // start with 1 because that is the first bit
    BIT2,    // 1 << 1 = 2
    BIT3,    // 2 << 1 = 4
    BIT4      // 4 << 1 = 8
}

If you have constants defined for player tasks so that you can have different tasks for each player at a time, you may have this:
Code:

#define TASK_ID_1 1000
#define TASK_ID_2 2000
#define TASK_ID_3 3000

// ...

set_task(1.0, "TaskHandler", id + TASK_ID_1)

// ...

public TaskHandler(taskid)
{
    new id = taskid - TASK_ID_1
}

Well you may have different constant values for your task ids, so you can do this easily to copy that style shown above:
Code:

enum (+= 1000) // task ids are 1000 apart
{
    TASK_ID_1 = 1000, // start with 1000
    TASK_ID_2,
    TASK_ID_3
}



Data structures:
Data structures allow you to put different types of data in an array.
Here is an example code that could use a data structure:
Code:

new g_iKills[ 33 ]
new g_iDeaths[ 33 ]
new Float:g_flSpeed[ 33 ];

// g_iKills[ id ] = kills for id
// g_iDeaths[ id ] = deaths for id
// g_flSpeed[ id ] = run speed for id

To put this into a data structure, you could do this:
Code:

enum _:PlayerData
{
    Player_Kills,
    Player_Deaths,
    Float:Player_Speed
}

new g_ePlayerData[ 33 ][ PlayerData ]

// g_ePlayerData[ id ][ Player_Kills ] = kills for id
// g_ePlayerData[ id ][ Player_Deaths ] = deaths for id
// g_ePlayerData[ id ][ Player_Speed ] = run speed for id

When using tags for structure constants that are used as an array index (ie. Player_Speed), you may need to tag the array itself when setting/getting a value.
Example:
Code:

g_ePlayerData[ id ][ Player_Speed ] = 250.0
// If the above code gives a tag mismatch warning, you can change it to this:
g_ePlayerData[ id ][ Player_Speed ] = _:250.0

// ...

if( g_ePlayerData[ id ][ Player_Speed ] == 250.0 )
// If the above code gives a tag mismatch warning, you can change it to this:
if( Float:g_ePlayerData[ id ][ Player_Speed ] == 250.0 )

With data structures, you can even create arrays and strings.
Example:
Code:

new g_szName[ 33 ][ 32 ];
new g_szAuthID[ 33 ][ 32 ];
new g_iUserID[ 33 ];

// can be changed to

enum _:PlayerInfo
{
    Player_Name[ 32 ],
    Player_AuthID[ 35 ],
    Player_UserID
}

new g_ePlayerData[ 33 ][ PlayerInfo ]

When using arrays and strings inside data structures, there are a few rules:
Code:

sizeof( Player_Name )
charsmax( Player_Name )

Those 2 lines are invalid because Player_Name is not a variable that has a size.
The constant Player_Name just reserves indexes 0-31 for the data structure, and Player_AuthID starts are 32 and stops at 66.
To get the size of those arrays/strings from a data structure, there are 2 ways:

Method #1:
Code:

Player_AuthID // sizeof( Player_Name )
Player_AuthID - 1 // charsmax( Player_Name )
// ...
Player_UserID - Player_AuthID // sizeof( Player_AuthID )
Player_UserID - Player_AuthID - 1 // charsmax( Player_AuthID )

Method #2:
Code:

new eTempData[ PlayerData ]
// ...
sizeof( eTempData[ Player_Name ] )
charsmax( eTempData[ Player_Name ] )
// ...
sizeof( eTempData[ Player_AuthID ] )
charsmax( eTempData[ Player_AuthID ] )

Method #2 is the best way because it ensures proper sizes in the event that an enum is modified.
Also, it would be the most practical way since the only reason you're using a data structure is to create an array that uses it.
So you should use the variable that uses the data structure for readability.

When using variable arrays that are sized by a data structure in functions, the data structure cannot have a tag.
Example:
Code:

enum PlayerData // PlayerData is a tag
{
    Player_Kills,
    Player_Deaths,
    Float:Player_Speed
}

// ...

new ePlayerData[ PlayerData ]
ePlayerData[ Player_Kills ] = 0
ePlayerData[ Player_Deaths ] = 0
ePlayerData[ Player_Speed ] = 250.0

// this line will throw an error
// because it does not accept arrays from data structures that are tagged
set_task( 1.0, "TaskSetPlayerData", id, ePlayerData, PlayerData )

To fix that, you just need to untag the data structure:
Code:

enum _:PlayerData // PlayerData is no longer a tag
{
    Player_Kills,
    Player_Deaths,
    Float:Player_Speed
}

// ...

new ePlayerData[ PlayerData ]
ePlayerData[ Player_Kills ] = 0
ePlayerData[ Player_Deaths ] = 0
ePlayerData[ Player_Speed ] = 250.0

// this line will work properly
set_task( 1.0, "TaskSetPlayerData", id, ePlayerData, PlayerData )

I think this tutorial is complete.
If I confused any information or left anything out, please let me know.
Feedback and suggestions are welcome.

wrecked_ 10-08-2010 22:35

Re: [TUT] Enumerations (enum)
 
Good job, Exolent. I feel like a lot of people don't fully understand how much is capable with enum and this should definitely help.

However, whenever I get a question about enumerations I like to show them the CsTeams enum to show them how it would be set up and used, since many people are familiar with the functionality of the CsTeams tagging and constants. Perhaps you could show that as an example, some might understand its practical capabilities this way.

shuttle_wave 10-08-2010 22:39

Re: [TUT] Enumerations (enum)
 
gj. Nice Tut Exolent

lazarev 10-09-2010 02:13

Re: [TUT] Enumerations (enum)
 
thanks for sharing! :)

abdul-rehman 10-09-2010 02:44

Re: [TUT] Enumerations (enum)
 
Thnx Again X-0lent !

PS: Atleast make the tutorial a little colorful like bugsy's bits tutorial

Arkshine 10-09-2010 04:46

Re: [TUT] Enumerations (enum)
 
That's not complete and there are few things to say :

- You don't talk about weak (lower case letter) and strong tag (upper case letter). The weak tag can be dropped implicitly in some situations. Check the pawn language guide to get more informations.
- Stop to cast the tags in your examples. At least the 3 first, there is no reason to cast.
- I would like to see an example with tagName + IncrementType.
- Don't say random things like "If the above code gives a tag mismatch warning[...]" ; When you set a value, which is important is the tag of the var (g_ePlayerData). When you get a value which is important is the tag of the item (Player_Speed). g_ePlayerData is untag, so if you try to set a value with a strong tag, you will get an error. If the tag was weak or if the the var (g_ePlayerData) was tagged with the same tag as the value you want to set, you won't get errors. In the next example when you get the value, since Player_Speed is a fload and since 250.0 too, the tag is the same, no error and no need to specify Float:.
- I don't see the point to show "Method #1:". Explaining the size it's ok, but showing an example is really a bad idea. It's confusing and you should avoid to show weird ways.
- ePlayerData[ Player_Speed ] = 250.0 ; should be casted.
- There is no example with custom tags.
- There is no example with structure inside a structure.
- In your last example, the problem can be simply solved by using a weak tag. The tag will be dropped automatically.

Here an old thread you may find some ideas

hleV 10-09-2010 07:22

Re: [TUT] Enumerations (enum)
 
If I go with HN, shouldn't members of enumeration be prefixed with m_?
PHP Code:

enum EData
{
        
m_iItem1,
        
m_iItem2,
        
m_iItem3
};
 
new 
g_eData[EData]; 

PHP Code:

enum SData
{
        
m_iInteger,
        
Float:m_fFloat,
        
m_szString[32]
};
 
new 
g_sData[SData]; 


Arkshine 10-09-2010 07:24

Re: [TUT] Enumerations (enum)
 
It doesn't matter, and it's up to the coders.

hleV 10-09-2010 07:27

Re: [TUT] Enumerations (enum)
 
But how would it be done in, let's say C[++] by a hardcore HN coder?

Arkshine 10-09-2010 07:33

Re: [TUT] Enumerations (enum)
 
That's not related to the subject. I don't see the point to talk about that. See yourself in the HLSDK or whatever. Coders are free to choose the style they want to their plugins.


All times are GMT -4. The time now is 12:39.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.