| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
hpl2:amnesia:script_language_reference_and_guide:constants_and_enumerations [2013/01/11 21:20] thegreatcthulhu [Enumerations] |
hpl2:amnesia:script_language_reference_and_guide:constants_and_enumerations [2015/10/06 21:06] (current) thegreatcthulhu [At a Glance] |
||
|---|---|---|---|
| Line 6: | Line 6: | ||
| ===== At a Glance ===== | ===== At a Glance ===== | ||
| + | Constants and enumerations allow you to define names which refer to values that should never change during the execution of a script. | ||
| - | <code c++> | + | **Constants** |
| - | // Constants and enumerations allow you to define names which refer to values which | + | <code c++>// Some math constants: |
| - | // should never change during the execution of the script. If you accidentally attempt | + | const float PI = 3.1415926f; |
| - | // to change them, you'll get a compiler error. They are also useful as a more meaningful | + | const float E = 2.7182818f; |
| - | // and readable replacement for "magic numbers" - numerical values accepted as parameters | + | |
| - | // by some functions, which have special meanings for those functions. | + | |
| - | // Integer constants: | + | // Integer constants: |
| // The constants in this example define when should collision events take place; | // The constants in this example define when should collision events take place; | ||
| // intended to be used with the AddEntityCollideCallback() engine function | // intended to be used with the AddEntityCollideCallback() engine function | ||
| Line 24: | Line 23: | ||
| // Usage: | // Usage: | ||
| AddEntityCollideCallback("Player", "Area_Example", "ExampleCallback", false, COLLIDE_ON_BOTH); | AddEntityCollideCallback("Player", "Area_Example", "ExampleCallback", false, COLLIDE_ON_BOTH); | ||
| + | </code> | ||
| - | + | **Enumerated Constants (Enumerations)** | |
| - | // Some math constants: | + | <code c++>enum Color // Note: Enums are based on the int type. |
| - | const float PI = 3.1415926f; | + | |
| - | const float E = 2.7182818f; | + | |
| - | + | ||
| - | + | ||
| - | + | ||
| - | // Enumerated constants (enumerations) - often used as parameters to functions | + | |
| - | enum Color // Note: Enums are based on the int type. | + | |
| { | { | ||
| Red, // has the default value of: 0 | Red, // has the default value of: 0 | ||
| Line 39: | Line 32: | ||
| Blue // value: (previous + 1) = 2, etc, if more added... | Blue // value: (previous + 1) = 2, etc, if more added... | ||
| } | } | ||
| - | |||
| // Usage: | // Usage: | ||
| Line 48: | Line 40: | ||
| // Assigning an integer value is not possible without an explicit conversion: | // Assigning an integer value is not possible without an explicit conversion: | ||
| - | Color col = 2; // Causes compilation error! | + | Color col = 2; // Causes compilation error! |
| - | // Converting from integers - should generally be avoided: | + | // Converting from integers - should generally be avoided: |
| Color col = Color(2); // Assigns Blue to col, since 2 corresponds to Color::Blue | Color col = Color(2); // Assigns Blue to col, since 2 corresponds to Color::Blue | ||
| Line 58: | Line 50: | ||
| // This is allowed: | // This is allowed: | ||
| int colValue = col; // so, enums can be passed to functions expecting ints --> see example below | int colValue = col; // so, enums can be passed to functions expecting ints --> see example below | ||
| - | |||
| - | |||
| // Enumerations - choosing your own values | // Enumerations - choosing your own values | ||
| Line 69: | Line 59: | ||
| } | } | ||
| - | // Usage: | + | // Used as parameters to a function: |
| AddEntityCollideCallback("Player", "Area_Example", "ExampleCallback", false, CollisionState::Both); | AddEntityCollideCallback("Player", "Area_Example", "ExampleCallback", false, CollisionState::Both); | ||
| - | + | // You can define all or some of the values; those left undefined will be | |
| - | // You can define all or some of the values; those left undefined will be | + | |
| // assigned the value of previous_constant + 1 | // assigned the value of previous_constant + 1 | ||
| enum Ending | enum Ending | ||
| - | { | + | { |
| Good = 1, // = 1 | Good = 1, // = 1 | ||
| ReallyGood, // = 2 (previous + 1) | ReallyGood, // = 2 (previous + 1) | ||
| Line 91: | Line 80: | ||
| FoundNote2 = 0x02, // HEX for 2, which is in binary: 0000 0010 | FoundNote2 = 0x02, // HEX for 2, which is in binary: 0000 0010 | ||
| FoundItem = 0x04, // HEX for 4, which is in binary: 0000 0100 | FoundItem = 0x04, // HEX for 4, which is in binary: 0000 0100 | ||
| - | FoundPassage = 0x08 // HEX for 8, which is in binary: 0000 1000 | + | FoundPassage = 0x08, // HEX for 8, which is in binary: 0000 1000 |
| FoundAll = 0x0F // HEX for 15, which is in binary: 0000 1111 | FoundAll = 0x0F // HEX for 15, which is in binary: 0000 1111 | ||
| } | } | ||
| Line 279: | Line 268: | ||
| enum BodyArmor | enum BodyArmor | ||
| { | { | ||
| - | Small = 50, | + | Weak = 50, |
| - | Large = 100 | + | Strong = 100 |
| } | } | ||
| // Later on: | // Later on: | ||
| HealingPotion vial = HealingPotion::Small; | HealingPotion vial = HealingPotion::Small; | ||
| - | HealingPotion leatherArmor = BodyArmor::Small; | + | HealingPotion leatherArmor = BodyArmor::Weak; |
| Line 292: | Line 281: | ||
| // Use: | // Use: | ||
| - | GivePlayerItems(HealingPotion::Small, BodyArmor::Small); | + | GivePlayerItems(HealingPotion::Small, BodyArmor::Weak); |
| // Rather than: | // Rather than: | ||
| - | GivePlayerItems(Small, Small); // which is which? | + | GivePlayerItems(Small, Weak); // which is which? |
| // Alternatively: | // Alternatively: | ||
| GivePlayerItems(vial, leatherArmor); | GivePlayerItems(vial, leatherArmor); | ||
| </code> | </code> | ||
| + | |||
| + | |||
| + | <note important>Although enumerated constants are grouped together under a single name, and can be accessed through that name using the scope resolution operator (''::''), they actually have a global (script-level) scope, so two constants in two different enums cannot share a name. For example, this is not allowed by the language: | ||
| + | <code c++> | ||
| + | enum HealingPotion | ||
| + | { | ||
| + | Small = 10, | ||
| + | Medium = 30, | ||
| + | Large = 60, | ||
| + | Mega = 100 | ||
| + | } | ||
| + | |||
| + | enum BodyArmor | ||
| + | { | ||
| + | Small = 50, // compiler error | ||
| + | Large = 100 // compiler error | ||
| + | } | ||
| + | </code> | ||
| + | </note> | ||
| Line 363: | Line 371: | ||
| {{ http://farm9.staticflickr.com/8513/8371352462_ccf55f1631.jpg }} | {{ http://farm9.staticflickr.com/8513/8371352462_ccf55f1631.jpg }} | ||
| - | In this example, knowing what is represented by each of the bit, you can read the value 0011 1010 to mean: | + | In this example, knowing what is represented by each of the bits, you can read the value 0011 1010 to mean: |
| * 0 - (not used) | * 0 - (not used) | ||
| * 0 - (not used) | * 0 - (not used) | ||
| Line 371: | Line 379: | ||
| * 0 - the note was not found | * 0 - the note was not found | ||
| * 1 - the switch is in the "on" state | * 1 - the switch is in the "on" state | ||
| - | * 0 - the lock is unlocked | + | * 0 - the lock is left unlocked |
| - | All of that information is encoded in //a single byte//. This is one of the reasons to use flags - it saves on memory. The other reason is that flags can be (and usually are) passed as parameters to functions, whereby several indicators of simple binary state are passed to the function simultaneously, through one variable. Flags often encode "settings"-like data, but should not be overused, as they can affect code readability. | + | All of that information is encoded in //a single byte//. This is one of the reasons to use flags - using them saves memory (a single byte vs several state variables). The other reason is that flags can be (and usually are) passed as parameters to functions, whereby several indicators of simple binary states are passed to the function simultaneously, through one variable. Flags often encode "settings"-like data, but should be used with care, as they can affect code readability and clarity. |
| - | How to manipulate individual bits then? Well, by assigning integer numbers to variables, and by using binary logical operators, described below. However, manipulating bits while working with numbers in the decimal system is not very convenient. This is why programmers often use //hexadecimal// (HEX) numbers for such tasks. The reason is: there's a direct correspondence between HEX and binary numbers, as the table below shows, which makes it easy to deal with binary representations. | + | //How to manipulate individual bits then?// Well, by assigning integer numbers to variables, and by using binary logical operators, described below. However, manipulating bits while working with numbers in the decimal system is not very convenient. This is why programmers often use //hexadecimal// (HEX) numbers for such tasks. The reason is: there's a direct correspondence between HEX and binary numbers, as the table below shows, which makes it easy to deal with binary representations. |
| {{ http://farm9.staticflickr.com/8365/8371351734_f2f2795a54.jpg }} | {{ http://farm9.staticflickr.com/8365/8371351734_f2f2795a54.jpg }} | ||
| - | As you can see, unlike the decimal number system, which represents all numbers using 10 different symbols (0-9), the HEX number system represents those same numbers using 16 different symbols (0-F). It just so happens that each of the HEX digits perfectly corresponds with every possible 4-bit combinations. Any one byte can thus be represented by 2 HEX digits - all you need to do is to refer to the table above, pick two hexadecimal digits, and write them together. To get the corresponding binary number, just replace the HEX digit with its binary equivalent from the table. | + | As you can see, unlike the decimal number system, which represents all numbers using 10 different symbols (0-9), the HEX number system represents those same numbers using 16 different symbols (0-F). It just so happens that each of the HEX digits perfectly corresponds to one of all possible 4-bit combinations. Any one byte can thus be represented by 2 HEX digits - all you need to do is to refer to the table above, pick two hexadecimal digits, and write them together. To get the corresponding binary number, just replace the HEX digit with its binary equivalent from the table. |
| - | Representing bytes using HEX system - some examples: | ||
| <code> | <code> | ||
| + | Representing bytes using HEX system - some examples: | ||
| + | |||
| + | ---------------------- | ||
| HEX binary | HEX binary | ||
| ---------------------- | ---------------------- | ||
| Line 391: | Line 401: | ||
| 3A 0011 1010 | 3A 0011 1010 | ||
| FC 1111 1100 | FC 1111 1100 | ||
| + | ---------------------- | ||
| </code> | </code> | ||
| + | |||
| + | Note that to be able to do this, you //don't have to// understand the internal workings of the decimal, binary and hexadecimal number systems (although I encourage you to learn more on the web), nor do you have to know how to convert binary and HEX representations to and from decimal; all you need to know is which HEX digit corresponds to which binary sequence (and you can get that from the table). | ||
| Since HEX digits include both numerals and characters, the script language needs a way to distinguish HEX numerical literals from other numbers and variable names. So, the language provides the ''0x'' prefix - when you want to express a number in the HEX format, start by typing ''0x'' and then immediately (with no spaces in between) follow with your hex digits: | Since HEX digits include both numerals and characters, the script language needs a way to distinguish HEX numerical literals from other numbers and variable names. So, the language provides the ''0x'' prefix - when you want to express a number in the HEX format, start by typing ''0x'' and then immediately (with no spaces in between) follow with your hex digits: | ||
| Line 409: | Line 422: | ||
| - | On the [[hpl2:amnesia:script_language_reference_and_guide:types|Types]] page, it was said that the ''int'' type takes up 4 bytes of memory. This means that a single integer can be used to represent 32 different binary states, of "flags", simultaneously. As with a single byte before, you don't have to use all of them. Also, since a 2-digit HEX number represents one byte, an 8-digit can be used to represent any 4-byte integer. You don't have to use all of the 8 digits, though -- if you use less than 8, the compiler will assume that the missing digits are all 0. | + | On the [[hpl2:amnesia:script_language_reference_and_guide:types|Types]] page, it was said that the ''int'' type takes up 4 bytes of memory. This means that a single integer can be used to represent 32 different binary states, of "flags", simultaneously. As with a single byte before, you don't have to use all of them. Also, since a 2-digit HEX number represents one byte, an 8-digit HEX number can be used to represent any 4-byte integer. You don't have to use all of the 8 digits, either -- if you use less than 8, the compiler will assume that the missing digits are all 0. |
| Line 460: | Line 473: | ||
| - | If you are familiar with the boolean logical operators, you'll be pleased to learn that the binary logical operators work pretty much the same way, only on individual bits. They take two numbers as input, and produce a third number based on the bits of the inputs provided. | + | If you are familiar with the [[hpl2:amnesia:script_language_reference_and_guide:control_flow_-_conditional_statements#using_logical_operators|boolean logical operators]], you'll be pleased to learn that the binary logical operators work pretty much the same way, only on individual bits. They take two numbers as input, and produce a third number based on the bits of the inputs provided. |
| **The binary OR operator** (''|'') sets a bit to ''1'' in the output if //any// of the corresponding bits in the inputs is ''1''. This is why it can be used to combine flags.\\ | **The binary OR operator** (''|'') sets a bit to ''1'' in the output if //any// of the corresponding bits in the inputs is ''1''. This is why it can be used to combine flags.\\ | ||
| Line 537: | Line 550: | ||
| </code> | </code> | ||
| + | |||
| + | <note important>Do not confuse binary logical operators (''|'', ''&'', and ''^''), which return a //number// as a result, with their boolean equivalents (''||'', ''&&'', and ''^^''), which return a //boolean value// (either ''true'' or ''false'').</note> | ||