Jan 14, 2016, 11:51 AM | |
Complementary scripting tutorials
I get the vibe that many JJ2+ script writers learned AngelScript by reading others' scripts, experimenting with their own, and referring to the scripting API when necessary. Learning through practice is a good, easy method, but it leaves many educational lacks that may slow down your coding, limit your possibilities, decrease your code's clarity, or make it difficult to expand. In this thread I intend to post short, bite-sized tutorials, each aimed to extend your knowledge about a certain scripting topic. The tutorials are generally meant be independent from each other so you can start reading from any of them you want, and if they require prior knowledge of other subjects I'll make that clear at the beginning of the tutorial in question. Notice however that these tutorials are certainly not aimed to be read by complete beginners: you are expected to possess basic scripting skills that just need some expansion and polishing. If you had never written a script of your own, you will probably not benefit from reading these. Finally, I encourage you to leave feedback, either by posting in this thread or by any other means you can reach me. Feel free to suggest topics you'd like me to cover or just say you found a post useful. If I don't feel like anybody benefits from this thread, I won't bother to continue posting in it.
Tutorials available so far: Strings Enums
__________________
I am an official JJ2+ programmer and this has been an official JJ2+ statement. Last edited by Sir Ementaler; Feb 9, 2016 at 05:05 AM. |
Jan 14, 2016, 11:52 AM | |
Strings
Escape sequences
You probably not only encountered, but also already used strings in your own scripts. They're a basic built-in object class designed for storing text. String literals1 begin and end with either single quotation marks ( ' ) or double quotation marks (" ). No surprise so far. However, did you ever consider what you'd have to do if you wanted to use a string that contained both of those characters inside it? If the text is surrounded by double quotation marks, you can't simply place another double quotation mark inside it, because the compiler would treat it as the end of the string and the intended result wouldn't be achieved. Instead, you should make use of what's called "escape sequences".Escape sequences are character sequences of special meaning that the compiler replaces with a specified character. In AngelScript, escape sequences are created by typing backslash ( \ ) followed by a certain character or characters. The sequence \" will be replaced by a double quotation mark and the sequence \' will be replaced by a single quotation mark, but that's not all escape sequences there are: \t is replaced by a single tab character, \n is replaced by a new line feed character, which you may find useful for drawing multi-line text on screen, \r becomes a carriage return character, which you probably won't ever need unless you decide to work with text files, and \0 is a null character (not to be mistaken with the numerical character '0' ; null is a type of a control character2). Granted, these aren't something you use commonly in AngelScript, but it's worth knowing they exist.Now if you've been reading carefully, you should be wondering how you include the backslash character in a string if the compiler expects it to start an escape sequence, and the answer is more escape sequences: \\ is an escape sequence that produces a single backslash. This is very important to know if you happen to write a string that's meant to remind a Windows file path. Consider a naively written string "C:\Games\" . When the compiler reaches it, it will see a double quotation mark and realize it's dealing with a string. It will parse the first two characters and then reach \G . That's not an escape sequence it knows, so it will ignore that bit and throw a warning that will be displayed by the chatlogger. Then it reads further and finds \" . It understands it as an instruction to insert a double quotation mark into the string, and then continues parsing all following code as a string. Eventually it reaches the end of the script file, and because the string should have been closed but wasn't, it submits an error to the chatlogger. Thus, backslashes in strings must always be escaped and the valid form of that string would've been "C:\\Games\\" .Finally, there are some universal escape sequences that allow you to insert any ASCII or Unicode character into a string as long as you know its hexadecimal code point. Or well, not really, since JJ2+ doesn't actually support Unicode strings, but the sequences can still come in useful. Those are \xFFFF , \uFFFF , and \UFFFFFFFF , where F's should be replaced by hexadecimal (base 16) digits. The number of digits must exactly match the number of F's given here, except for \x , which accepts anywhere between 1 and 4 digits. One case when this is particularly worth remembering is when you need to insert a section sign character (§ ) to modify spacing between letters. Simply type \xA7 or \u00A7 and it's there.Heredoc strings Escape sequences can be useful, but there are times when they simply make your string look really terrible. Or on other occasions you have a really big chunk of multi-line text and it would be inconvenient to replace characters with their corresponding escape sequences. AngelScript offers a solution to that, named heredoc strings. Heredoc strings are placed between two sets of triple double quotation marks ( """ ) and can safely contain backslashes, quotation marks, and new line characters. What should you do if you want your heredoc string to also contain triple double quotation marks? AngelScript doesn't tell, which is most unfortunate because most programming languages that have heredoc strings offer solutions to this kind of problems, but luckily the necessity to ever do that is unlikely enough to happen to you.Methods and supporting functions Strings come with some functions and methods that are listed but not explained on the AngelScript website, and not mentioned at all within the JJ2+ scripting API, but definitely worth knowing as they can save a lot of time. Here they are: Methods:
Functions:
In formatInt and formatFloat , options should be a string that's a combination of the following characters:
A recent update of AngelScript also added formatUInt , analogous to formatInt but operating on unsigned integers, however this function is not available in JJ2+ yet (and only comes in useful if you work with really big numbers, we're speaking 18-19 digits).Operators Finally, strings support a number of operators, some obvious and some less. It's very useful to know them as it can save you a lot of redundant code. Naturally, strings can be assigned ( = ) and tested for equality (== and != ). It's less common knowledge that they can also be compared using other relational operators (< , > , <= , >= ). Such comparison is performed according to character codes, i.e. for most common uses, ASCII. It's useful to notice, for example, that if both compared strings are lowercase English words, the one that will be considered "smaller" is the one that precedes the other alphabetically. This has the advantage of allowing to quickly sort an array of words according to alphabet with use of the array method sortAsc (which may be discussed in another tutorial).However, in ASCII, uppercase letters will always be considered "less than" lowercase ones (take a look at an ASCII table). This is quite unfortunate for the purpose of sorting alphabetically in case our words happen to contain mixed lowercase and uppercase characters. Luckily, ASCII is actually a fairly well designed system, in which the difference between an uppercase letter and its lowercase equivalent is always exactly 32. This is essential information, because it means that we can switch the case of a letter as long as we know its character code. Most programming languages provide a way to convert between charcters and character codes. AngelScript does too, but it makes it particularly bothersome and doesn't really document it. You do it using the index operator ( [] ). For example, by typing text[0] , we obtain the character code of the first character of text. Like most functionalities, it's available even for string literals, so "A"[0] is a valid expression that has the value of the character code of the letter A (65). That means you don't have to look up the ASCII code of a specific character when you need it in your script (useful in connection with jjKey , as keyboard codes of digits 0-9 and letters A-Z are the same as their ASCII codes, and jjKey["A"[0]] , even if not pretty, will be easier to understand than jjKey[65] ).The index operator can be used not only to read, but also to set a character code at the selected position, e.g. text[0] = "!"[0] ; will set the first character of text to an exclamation mark. In either case, like when working with arrays, keep in mind that the index has to be valid, i.e. non-negative and less than the string length, otherwise a run-time "index out of bounds" error will occur.With this information, you should be able to understand the following function that converts a string to lowercase: Code:
string lowercase(string text) { for (uint i = 0; i < text.length(); i++) { // for each character if (text[i] >= "A"[0] && text[i] <= "Z"[0]) // if the character is an uppercase letter text[i] += 32; // convert it to its lowercase equivalent } return text; } The last pair of operators supported by strings are concatenation operators + and += , which you probably already encountered. Although they are represented by the same characters as arithmetic addition operators (such as in the expression 1 + 1), they serve a completely different purpose and have different properties. Concatenation joins two strings together, simply appending one at the end of the other. As obvious as it may sound, you should notice that in contrast to arithmetic summation, the order of operands in concatenation does matter: "A" + "B" is not the same as "B" + "A" ; one equals "AB" and the other "BA" .AngelScript simplifies syntax by allowing one of the operands of the concatenation operator to not be a string but another data type, such as a Boolean, integer, or float. Booleans will be appropriately converted to strings that say either "true" or "false" , while integers and floats will be formatted with use of respectively formatInt and formatFloat implicitly called with default parameters. This can shorten your code, but remember to get the order of operations right: the expression "two: " + 1 + 1 will result in a string saying "two: 11" and to achieve "two: 2" instead, you should write "two: " + (1 + 1) . The expression "zero: " + 1 - 1 won't compile at all, because the concatenation will occur first, and an attempt to compile the operation "zero: 1" - 1 will cause an error as the minus sign doesn't have a meaning in strings.Summary Hopefully that's all you could ever want to know about strings. To sum it up, strings are a data type for storing text, string literals can contain escape sequences for representing characters you can't otherwise include in them, and a special syntax called heredoc strings exists for when you don't want escape sequences to be interpreted or want to include long multi-line text. Strings have many useful methods and supporting functions, among them ways to obtain and modify length, search for desired terms, split into an array and join it back into a string, and convert between strings and arithmetic data types. They also support several operators, in particular ones that allow lexicographical comparison according to their internal ASCII code representation, obtaining and modifying character codes at selected position, and concatenation. Useful links: AngelScript documentation of strings ASCII chart
__________________
I am an official JJ2+ programmer and this has been an official JJ2+ statement. Last edited by Sir Ementaler; Jan 16, 2016 at 07:28 AM. |
Jan 14, 2016, 02:18 PM | |
Thanks for letting me know. If you have a solid idea where to insert them, by all means feel free to edit the post yourself, I won't mind. Otherwise I'll give it a go in the near future.
__________________
I am an official JJ2+ programmer and this has been an official JJ2+ statement. |
Jan 14, 2016, 09:20 PM | |
I agree with Stijn—also, lists! [LIST] if you want to use BBCode for everything. I also would have liked more sample code, in particular for the "!ban 5 60m airboard bug abuse" part, and some more work tying general string mechanics into stuff people might want specifically for JJ2+ purposes.
|
Feb 9, 2016, 05:04 AM | |
Enums
Introduction
There are certain problems in scripting that simply shouldn't be solved with use of data types already offered by AngelScript. Consider, for example, the following scenario: you're trying to write a script in which players can keep a single pet animal at their home. They have a choice between 3 available pets: a dog, cat, or gold fish. Thus, the script must somehow keep track of what pet the player chose. You probably have some idea for a variable that could accomplish that, but in this tutorial I hope to show you that the superior way to do that is by using enums. First, let's see the flaws of the three solutions that might've come to your mind if you don't normally use enums or classes. Perhaps you thought declaring an integer variable would be a good solution: Code:
int pet; pet . This obviously won't be detected as an error by the compiler because 4 is still a valid integer, but your code probably won't know how to handle it and it certainly won't know where the erroneous assignment occurred, and you'll have to debug it manually.Another naive solution would be to declare pet as a string. This seems a bit more intuitive:Code:
string pet; Finally, you may have considered Booleans. Of course one Boolean won't do, so you declare three: Code:
bool dog; bool cat; bool fish; As we found, all of the presented solutions have some flaws. In particular, none of them will report an error if we attempt to assign a value that we don't consider valid. Enums Enumerated types, enumerations, or enums for short, are a construct designed specifically to solve this sort of issues. By registering an enum, you create a new, special data type. Variables of this type will be only allowed to take values defined by the enum. Specifically, to address our pet animal problem, we could define the following enum: Code:
enum pet_type {dog, cat, fish} dog , cat , and fish . It's important to understand that by writing this line, we haven't actually defined any variable. That line is only a definition of a type. To define a variable, we would write the following:Code:
pet_type pet; int pet; is that now the type is one you made yourself. In fact, after pet_type was defined as an enum, it became a type as any other, and can now be used in any other expression where built-in types such as int could be used, for example as a return type or argument in function definitions:Code:
pet_type getPetOtherThan(pet_type animal) { // ... } pet = cat; ), we can compare it to other values (e.g. pet == fish ), and we can very neatly use it in switch-case statements:Code:
switch (pet) { case dog: // do something with dog break; case cat: // do something with cat break; case fish: // do something with fish break; } pet = 1; to cause an error, because, let's face it, numbers are not pets, and if we wrote that, we must've screwed up. Code such as pet += 2; simply makes no sense, and thus it's completely reasonable that it won't compile (as opposed to what would happen if we used an int instead). Really, all it makes sense to do with a variable like this is set it and read it, and it's not a limitation of the type that this is all that's allowed, it's what we truly expected from it.Conversions It may interest you how enum type variables are stored internally. After all, you were taught that it's all ones and zeroes inside your computer and now suddenly you are allowed to assign a cat to your variable. In fact, on the inside, variables declared as enum types are the same as integers, and possible values, such as dog , cat , and fish , are simply integer constants for 0, 1, and 2.Now, I know what you're thinking, at the beginning of this tutorial I told you that using an int would be bad and registering int constants would be tiresome, and now we're doing exactly that except in a more complicated way, and you're right that there would be no difference in the effect perceived by a person running our script. The reason we use enums is that we are humans. We make errors in our code, and enums let us know about them immediately. We can read organized code more easily, and enums provide organization. We have second thoughts, and enums let us quickly expand or modify code. Enums will not extend what you can do with scripts, but they make your life as a script writer easier. Why is knowing the internal form of enums useful? Well, turns out it's not entirely internal and you can actually do some operations involving both enums and integers. For example, I told you that the expression pet += 2; is invalid. However, pet + 2 would in fact be a valid integer. In this expression, the variable pet is first converted to an integer, for example cat would be converted to 1, and then it is added to 2, giving 3 in the result. This value cannot be assigned back to pet , because it is an integer, but it can be assigned to an integer variable. It may seem strange that this conversion is allowed, but it finds use in some instances. Indeed, enums can be defined in such a way that specific identifiers are given specific integer values. For example:Code:
enum Quantity {one = 1, two, dozen = 12, lots = 128} two in our example, the value used is the value of the previous term plus 1. If no value is given to the initial term, it is given the value of 0, as happened to dog in our first enum.This feature is sometimes used to simply define a large number of related integer constants in a row, but this can be considered abuse of the enum keyword, because if you don't need the additional functionality provided by enums; you could just use a bunch of const int definitions. As for valid use cases, it mostly comes in useful if you intend to serialize1 enum types, that is, save them into a file or send over the network. The latter is unlikely to ever be an issue in JJ2+ because the game ensures that the client and the server are running the same version of the script, however files are a completely realistic concern. Consider for example that you had saved a file that stores information about a player's pet. Then you worked on the script further and extended it so that different dog and cat breeds are available. You updated the pet_type enum accordinglyCode:
enum pet_type { golden_retriever, german_shepherd, corgi, scottish_fold, maine_coon, ragdoll, gold_fish } Code:
enum pet_type { golden_retriever = 0, german_shepherd = 3, corgi = 4, scottish_fold = 1, maine_coon = 5, ragdoll = 6, gold_fish = 2 } Code:
enum pet_type { dog = 0, cat = 1, fish = 2 } Code:
pet = pet_type(2); Summary Enums are a language feature designed to make code more organized and readable, and errors easier to detect. Enums should be used wherever a variable can have several possible states that can't be reasonably described with numbers (5 is not an animal, 12 is not a piece of furniture). Variables of enum type support assignment, comparison for equality, and usage in switch-case statements. They can also be implicitly converted to integers, and integers can be explicitly converted back, however the latter operation is unsafe. When variables of enum type are to be converted to integers or back, it's best to assign the used constants the desired value in the enum definition. Useful link: AngelScript documentation of enums
__________________
I am an official JJ2+ programmer and this has been an official JJ2+ statement. Last edited by Sir Ementaler; Jun 6, 2016 at 10:03 AM. |
![]() |
Tags |
angelscript, code |
«
Previous Thread
|
Next Thread
»
Thread Tools | |
|
|
All times are GMT -8. The time now is 02:36 PM.
Jazz2Online © 1999-INFINITY (Site Credits). Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats. Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Original site design by Ovi Demetrian. DrJones is the puppet master. Eat your lima beans, Johnny.